diff --git a/enzevalos_iphone.xcodeproj/project.pbxproj b/enzevalos_iphone.xcodeproj/project.pbxproj index 6d4376501d994f74b7523a9ba217304775feb450..f8524eab582452fcf14ec27277de8709c16b32b5 100644 --- a/enzevalos_iphone.xcodeproj/project.pbxproj +++ b/enzevalos_iphone.xcodeproj/project.pbxproj @@ -108,6 +108,15 @@ 3EC35F2E200376A1008BDF95 /* SendViewController+Invitation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3EC35F2C200376A1008BDF95 /* SendViewController+Invitation.swift */; }; 3EC35F302003838E008BDF95 /* InvitationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3EC35F2F2003838E008BDF95 /* InvitationTests.swift */; }; 45262931B4C72A96C686C533 /* Pods_enzevalos_iphoneTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C9B9CE43043CF806E1C02FCA /* Pods_enzevalos_iphoneTests.framework */; }; + 4707091E2189BC3500DF71A3 /* plainThunderbird.eml in Resources */ = {isa = PBXBuildFile; fileRef = 470709172189BC3500DF71A3 /* plainThunderbird.eml */; }; + 470709262189C73900DF71A3 /* enc+signedInlineThunderbird.eml in Resources */ = {isa = PBXBuildFile; fileRef = 470709212189C73900DF71A3 /* enc+signedInlineThunderbird.eml */; }; + 470709272189C73900DF71A3 /* encThunderbird.eml in Resources */ = {isa = PBXBuildFile; fileRef = 470709222189C73900DF71A3 /* encThunderbird.eml */; }; + 470709282189C73900DF71A3 /* encInlineThunderbird.eml in Resources */ = {isa = PBXBuildFile; fileRef = 470709232189C73900DF71A3 /* encInlineThunderbird.eml */; }; + 470709292189C73900DF71A3 /* signedInlineThunderbird.eml in Resources */ = {isa = PBXBuildFile; fileRef = 470709242189C73900DF71A3 /* signedInlineThunderbird.eml */; }; + 4707092A2189C73900DF71A3 /* signedThunderbird.eml in Resources */ = {isa = PBXBuildFile; fileRef = 470709252189C73900DF71A3 /* signedThunderbird.eml */; }; + 4707092D2189C74200DF71A3 /* bobSecret.asc in Resources */ = {isa = PBXBuildFile; fileRef = 4707092B2189C74200DF71A3 /* bobSecret.asc */; }; + 4707092E2189C74200DF71A3 /* alicePublic.asc in Resources */ = {isa = PBXBuildFile; fileRef = 4707092C2189C74200DF71A3 /* alicePublic.asc */; }; + 470709302189E1C100DF71A3 /* enc+signedThunderbird.eml in Resources */ = {isa = PBXBuildFile; fileRef = 4707092F2189E1C000DF71A3 /* enc+signedThunderbird.eml */; }; 4707096D1F8F9F4900657F41 /* ExportViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4707096C1F8F9F4900657F41 /* ExportViewController.swift */; }; 4715F637202A0248001BFFD0 /* CoreDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4715F636202A0248001BFFD0 /* CoreDataTests.swift */; }; 472276BC1FCD46B200ADA507 /* LoggingEventType.swift in Sources */ = {isa = PBXBuildFile; fileRef = A18E7D761FBDE5D9002F7CC9 /* LoggingEventType.swift */; }; @@ -134,26 +143,48 @@ 476142081E07E52B00FD5E4F /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 476142071E07E52B00FD5E4F /* Theme.swift */; }; 4761420A1E082F9C00FD5E4F /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 476142091E082F9C00FD5E4F /* Settings.bundle */; }; 476373C21E09BA88004D5EFE /* UserData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 476373C11E09BA88004D5EFE /* UserData.swift */; }; + 476801DB218436B600F7F259 /* Autocrypt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 476801DA218436B600F7F259 /* Autocrypt.swift */; }; + 476801DC218436B600F7F259 /* Autocrypt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 476801DA218436B600F7F259 /* Autocrypt.swift */; }; + 476801DE21846A5A00F7F259 /* OutgoingMail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 476801DD21846A5A00F7F259 /* OutgoingMail.swift */; }; + 476801DF21846A5A00F7F259 /* OutgoingMail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 476801DD21846A5A00F7F259 /* OutgoingMail.swift */; }; 476916A0216B86A100491527 /* PersistentMail +CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4769169F216B86A100491527 /* PersistentMail +CoreDataClass.swift */; }; 476916A2216B86CF00491527 /* EnzevalosContact+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 476916A1216B86CF00491527 /* EnzevalosContact+CoreDataClass.swift */; }; 47691A8A1ECB56D1004BCFC5 /* Mail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47691A891ECB56D1004BCFC5 /* Mail.swift */; }; 47691A8C1ECC3EC7004BCFC5 /* EphemeralMail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47691A8B1ECC3EC7004BCFC5 /* EphemeralMail.swift */; }; - 47953AA91FD7000200D4631A /* bitcoinde.asc in Resources */ = {isa = PBXBuildFile; fileRef = 47953AA81FD7000200D4631A /* bitcoinde.asc */; }; - 47953AAA1FD7000200D4631A /* bitcoinde.asc in Resources */ = {isa = PBXBuildFile; fileRef = 47953AA81FD7000200D4631A /* bitcoinde.asc */; }; + 477548DE21F5DABE000B22A8 /* MailServerConnectionError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 477548DD21F5DABE000B22A8 /* MailServerConnectionError.swift */; }; + 477548DF21F5DABE000B22A8 /* MailServerConnectionError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 477548DD21F5DABE000B22A8 /* MailServerConnectionError.swift */; }; + 477548E221F77466000B22A8 /* SecurityIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 477548E121F77466000B22A8 /* SecurityIndicator.swift */; }; + 477548E421F77BA0000B22A8 /* StudyParameterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 477548E321F77BA0000B22A8 /* StudyParameterProtocol.swift */; }; + 477548E521F77DF5000B22A8 /* StudyParameterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 477548E321F77BA0000B22A8 /* StudyParameterProtocol.swift */; }; + 477548E621F77DF7000B22A8 /* SecurityIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 477548E121F77466000B22A8 /* SecurityIndicator.swift */; }; + 478154A721FF3F0900A931EC /* Warning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 478154A621FF3F0900A931EC /* Warning.swift */; }; + 478154A921FF3FF400A931EC /* Invitation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 478154A821FF3FF400A931EC /* Invitation.swift */; }; + 478154AC21FF6A9600A931EC /* Mailbot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 478154AB21FF6A9600A931EC /* Mailbot.swift */; }; + 478154AE2200641900A931EC /* StudyTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 478154AD2200641900A931EC /* StudyTest.swift */; }; + 478AF715222FD5C600AEF69E /* IncomingMail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 478AF714222FD5C600AEF69E /* IncomingMail.swift */; }; 479B5977206914BE00B3944D /* CryptoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 479B5976206914BE00B3944D /* CryptoTests.swift */; }; 479B597820691BE400B3944D /* ObjectivePGP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 47CEF4EC2052C3E600887CDB /* ObjectivePGP.framework */; }; 479B597920691BFB00B3944D /* libbz2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 47F867E32052B49800AA832F /* libbz2.tbd */; }; 479B597A20691C0600B3944D /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 47F867E12052B48E00AA832F /* libz.tbd */; }; 479B597B20691C1A00B3944D /* ObjectivePGP.framework in Resources */ = {isa = PBXBuildFile; fileRef = 47CEF4EA2052C3C700887CDB /* ObjectivePGP.framework */; }; - 479C648921EE299C00A01071 /* attachment.eml in Resources */ = {isa = PBXBuildFile; fileRef = 479C648821EE299C00A01071 /* attachment.eml */; }; - 479C648B21EE416100A01071 /* TempAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 479C648A21EE416100A01071 /* TempAttachment.swift */; }; + 479C649621F2139B00A01071 /* support_pk.asc in Resources */ = {isa = PBXBuildFile; fileRef = 479C649521F2139B00A01071 /* support_pk.asc */; }; + 479C649721F2139B00A01071 /* support_pk.asc in Resources */ = {isa = PBXBuildFile; fileRef = 479C649521F2139B00A01071 /* support_pk.asc */; }; + 479C649A21F45DAF00A01071 /* HideShowPasswordTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 479C649821F45DAF00A01071 /* HideShowPasswordTextField.swift */; }; + 479C649B21F45DAF00A01071 /* PasswordToggleVisibilityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 479C649921F45DAF00A01071 /* PasswordToggleVisibilityView.swift */; }; 47A7975B1FCD56B7006B3BC4 /* enzevalos_iphone.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = A135267F1D955BDF00D3BFE1 /* enzevalos_iphone.xcdatamodeld */; }; + 47C22281218AFD6300BD2C2B /* AutocryptTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47C22280218AFD6300BD2C2B /* AutocryptTest.swift */; }; + 47C22283218B02C700BD2C2B /* autocryptSimpleExample1.eml in Resources */ = {isa = PBXBuildFile; fileRef = 47C22282218B02C700BD2C2B /* autocryptSimpleExample1.eml */; }; 47CD5AAA2012368D00E771A1 /* logging_pk.asc in Resources */ = {isa = PBXBuildFile; fileRef = 47CD5AA82012368D00E771A1 /* logging_pk.asc */; }; - 47CD5AAB2012368D00E771A1 /* bitcoinde.asc in Resources */ = {isa = PBXBuildFile; fileRef = 47CD5AA92012368D00E771A1 /* bitcoinde.asc */; }; - 47CD5AAD2012369400E771A1 /* support_pk.asc in Resources */ = {isa = PBXBuildFile; fileRef = 47CD5AAC2012369300E771A1 /* support_pk.asc */; }; + 47CD5AAD2012369400E771A1 /* support_pk2.asc in Resources */ = {isa = PBXBuildFile; fileRef = 47CD5AAC2012369300E771A1 /* support_pk2.asc */; }; + 47CEAC98222541B40075B7DC /* MailSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47CEAC97222541B40075B7DC /* MailSession.swift */; }; 47CEF4EB2052C3C800887CDB /* ObjectivePGP.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 47CEF4EA2052C3C700887CDB /* ObjectivePGP.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 47CEF4ED2052C3E700887CDB /* ObjectivePGP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 47CEF4EC2052C3E600887CDB /* ObjectivePGP.framework */; }; 47D1302B1F7CEE6D007B14DF /* DebugSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47D1302A1F7CEE6D007B14DF /* DebugSettings.swift */; }; + 47E7BE5B22319B6900C8EF94 /* EncMailFromMac.eml in Resources */ = {isa = PBXBuildFile; fileRef = 47E7BE5A22319B6900C8EF94 /* EncMailFromMac.eml */; }; + 47E7BE5D22319B7100C8EF94 /* SignedMailFromMac.eml in Resources */ = {isa = PBXBuildFile; fileRef = 47E7BE5C22319B7000C8EF94 /* SignedMailFromMac.eml */; }; + 47E7BE5F22319B7D00C8EF94 /* SecureMailFromMac.eml in Resources */ = {isa = PBXBuildFile; fileRef = 47E7BE5E22319B7D00C8EF94 /* SecureMailFromMac.eml */; }; + 47E7BE6122319B8F00C8EF94 /* PlainMailFromMac.eml in Resources */ = {isa = PBXBuildFile; fileRef = 47E7BE6022319B8F00C8EF94 /* PlainMailFromMac.eml */; }; + 47E7BE632232BD0A00C8EF94 /* SignedEncMailFromMac.eml in Resources */ = {isa = PBXBuildFile; fileRef = 47E7BE622232BD0A00C8EF94 /* SignedEncMailFromMac.eml */; }; 47F79240203492E3005E7DB6 /* KeyRecord+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F7923E203492E3005E7DB6 /* KeyRecord+CoreDataClass.swift */; }; 47F79241203492E3005E7DB6 /* KeyRecord+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F7923F203492E3005E7DB6 /* KeyRecord+CoreDataProperties.swift */; }; 47F867E02052B47C00AA832F /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 47F867DF2052B47C00AA832F /* Security.framework */; }; @@ -193,6 +224,9 @@ A13526861D955BDF00D3BFE1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A13526841D955BDF00D3BFE1 /* LaunchScreen.storyboard */; }; A135269C1D955BE000D3BFE1 /* enzevalos_iphoneUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A135269B1D955BE000D3BFE1 /* enzevalos_iphoneUITests.swift */; }; A142E70921E7919F000395E3 /* IntroContactViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A142E70821E7919F000395E3 /* IntroContactViewController.swift */; }; + A15D215B223BE5F4003E0CE0 /* TempAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = A15D215A223BE5F4003E0CE0 /* TempAttachment.swift */; }; + A15D215D223BE614003E0CE0 /* attachment.eml in Resources */ = {isa = PBXBuildFile; fileRef = A15D215C223BE614003E0CE0 /* attachment.eml */; }; + A15D215F223BE6E4003E0CE0 /* MailTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = A15D215E223BE6E4003E0CE0 /* MailTest.swift */; }; A16BA2121E0439B6005E29E3 /* providers.json in Resources */ = {isa = PBXBuildFile; fileRef = A16BA2111E0439B6005E29E3 /* providers.json */; }; A1735DFA205AB88500B336DB /* SendViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1735DF9205AB88500B336DB /* SendViewState.swift */; }; A182182721E5012300918A29 /* Intro.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A182182621E5012300918A29 /* Intro.storyboard */; }; @@ -306,6 +340,15 @@ 3EC35F2C200376A1008BDF95 /* SendViewController+Invitation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SendViewController+Invitation.swift"; sourceTree = "<group>"; }; 3EC35F2F2003838E008BDF95 /* InvitationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitationTests.swift; sourceTree = "<group>"; }; 411EB2B85F99B48FFD36F966 /* Pods-enzevalos_iphoneTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-enzevalos_iphoneTests.debug.xcconfig"; path = "../workspace/Pods/Target Support Files/Pods-enzevalos_iphoneTests/Pods-enzevalos_iphoneTests.debug.xcconfig"; sourceTree = "<group>"; }; + 470709172189BC3500DF71A3 /* plainThunderbird.eml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = plainThunderbird.eml; sourceTree = "<group>"; }; + 470709212189C73900DF71A3 /* enc+signedInlineThunderbird.eml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "enc+signedInlineThunderbird.eml"; sourceTree = "<group>"; }; + 470709222189C73900DF71A3 /* encThunderbird.eml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = encThunderbird.eml; sourceTree = "<group>"; }; + 470709232189C73900DF71A3 /* encInlineThunderbird.eml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = encInlineThunderbird.eml; sourceTree = "<group>"; }; + 470709242189C73900DF71A3 /* signedInlineThunderbird.eml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = signedInlineThunderbird.eml; sourceTree = "<group>"; }; + 470709252189C73900DF71A3 /* signedThunderbird.eml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = signedThunderbird.eml; sourceTree = "<group>"; }; + 4707092B2189C74200DF71A3 /* bobSecret.asc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = bobSecret.asc; sourceTree = "<group>"; }; + 4707092C2189C74200DF71A3 /* alicePublic.asc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = alicePublic.asc; sourceTree = "<group>"; }; + 4707092F2189E1C000DF71A3 /* enc+signedThunderbird.eml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "enc+signedThunderbird.eml"; sourceTree = "<group>"; }; 4707096C1F8F9F4900657F41 /* ExportViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExportViewController.swift; sourceTree = "<group>"; }; 4715F636202A0248001BFFD0 /* CoreDataTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreDataTests.swift; sourceTree = "<group>"; }; 472F396D1E14F384009260FB /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; @@ -330,21 +373,38 @@ 476142071E07E52B00FD5E4F /* Theme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = "<group>"; }; 476142091E082F9C00FD5E4F /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = "<group>"; }; 476373C11E09BA88004D5EFE /* UserData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserData.swift; sourceTree = "<group>"; }; + 476801DA218436B600F7F259 /* Autocrypt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Autocrypt.swift; sourceTree = "<group>"; }; + 476801DD21846A5A00F7F259 /* OutgoingMail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutgoingMail.swift; sourceTree = "<group>"; }; 4769169F216B86A100491527 /* PersistentMail +CoreDataClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "PersistentMail +CoreDataClass.swift"; sourceTree = "<group>"; }; 476916A1216B86CF00491527 /* EnzevalosContact+CoreDataClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "EnzevalosContact+CoreDataClass.swift"; sourceTree = "<group>"; }; 47691A891ECB56D1004BCFC5 /* Mail.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Mail.swift; sourceTree = "<group>"; }; 47691A8B1ECC3EC7004BCFC5 /* EphemeralMail.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EphemeralMail.swift; sourceTree = "<group>"; }; - 47953AA81FD7000200D4631A /* bitcoinde.asc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = bitcoinde.asc; sourceTree = "<group>"; }; + 477548DD21F5DABE000B22A8 /* MailServerConnectionError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MailServerConnectionError.swift; sourceTree = "<group>"; }; + 477548E121F77466000B22A8 /* SecurityIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecurityIndicator.swift; sourceTree = "<group>"; }; + 477548E321F77BA0000B22A8 /* StudyParameterProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StudyParameterProtocol.swift; sourceTree = "<group>"; }; + 478154A621FF3F0900A931EC /* Warning.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Warning.swift; sourceTree = "<group>"; }; + 478154A821FF3FF400A931EC /* Invitation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Invitation.swift; sourceTree = "<group>"; }; + 478154AB21FF6A9600A931EC /* Mailbot.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mailbot.swift; sourceTree = "<group>"; }; + 478154AD2200641900A931EC /* StudyTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StudyTest.swift; sourceTree = "<group>"; }; + 478AF714222FD5C600AEF69E /* IncomingMail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = IncomingMail.swift; path = mail/IncomingMail.swift; sourceTree = "<group>"; }; 479B5976206914BE00B3944D /* CryptoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CryptoTests.swift; sourceTree = "<group>"; }; - 479C648821EE299C00A01071 /* attachment.eml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = attachment.eml; sourceTree = "<group>"; }; - 479C648A21EE416100A01071 /* TempAttachment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TempAttachment.swift; sourceTree = "<group>"; }; + 479C649521F2139B00A01071 /* support_pk.asc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = support_pk.asc; sourceTree = "<group>"; }; + 479C649821F45DAF00A01071 /* HideShowPasswordTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HideShowPasswordTextField.swift; sourceTree = "<group>"; }; + 479C649921F45DAF00A01071 /* PasswordToggleVisibilityView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasswordToggleVisibilityView.swift; sourceTree = "<group>"; }; 47B2318A1F0D458100961B28 /* enzevalos_iphone 2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "enzevalos_iphone 2.xcdatamodel"; sourceTree = "<group>"; }; + 47C22280218AFD6300BD2C2B /* AutocryptTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutocryptTest.swift; sourceTree = "<group>"; }; + 47C22282218B02C700BD2C2B /* autocryptSimpleExample1.eml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = autocryptSimpleExample1.eml; sourceTree = "<group>"; }; 47CD5AA82012368D00E771A1 /* logging_pk.asc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = logging_pk.asc; path = keys/logging_pk.asc; sourceTree = "<group>"; }; - 47CD5AA92012368D00E771A1 /* bitcoinde.asc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = bitcoinde.asc; path = keys/bitcoinde.asc; sourceTree = "<group>"; }; - 47CD5AAC2012369300E771A1 /* support_pk.asc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = support_pk.asc; path = keys/support_pk.asc; sourceTree = "<group>"; }; + 47CD5AAC2012369300E771A1 /* support_pk2.asc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = support_pk2.asc; path = keys/support_pk2.asc; sourceTree = "<group>"; }; + 47CEAC97222541B40075B7DC /* MailSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MailSession.swift; sourceTree = "<group>"; }; 47CEF4EA2052C3C700887CDB /* ObjectivePGP.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = ObjectivePGP.framework; sourceTree = "<group>"; }; 47CEF4EC2052C3E600887CDB /* ObjectivePGP.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ObjectivePGP.framework; path = ../enzevalos_iphone_workspace/ObjectivePGP.framework; sourceTree = "<group>"; }; 47D1302A1F7CEE6D007B14DF /* DebugSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DebugSettings.swift; sourceTree = "<group>"; }; + 47E7BE5A22319B6900C8EF94 /* EncMailFromMac.eml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = EncMailFromMac.eml; sourceTree = "<group>"; }; + 47E7BE5C22319B7000C8EF94 /* SignedMailFromMac.eml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SignedMailFromMac.eml; sourceTree = "<group>"; }; + 47E7BE5E22319B7D00C8EF94 /* SecureMailFromMac.eml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SecureMailFromMac.eml; sourceTree = "<group>"; }; + 47E7BE6022319B8F00C8EF94 /* PlainMailFromMac.eml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = PlainMailFromMac.eml; sourceTree = "<group>"; }; + 47E7BE622232BD0A00C8EF94 /* SignedEncMailFromMac.eml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SignedEncMailFromMac.eml; sourceTree = "<group>"; }; 47F7923E203492E3005E7DB6 /* KeyRecord+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KeyRecord+CoreDataClass.swift"; sourceTree = "<group>"; }; 47F7923F203492E3005E7DB6 /* KeyRecord+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KeyRecord+CoreDataProperties.swift"; sourceTree = "<group>"; }; 47F867DF2052B47C00AA832F /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; @@ -394,6 +454,9 @@ A135269B1D955BE000D3BFE1 /* enzevalos_iphoneUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = enzevalos_iphoneUITests.swift; sourceTree = "<group>"; }; A135269D1D955BE000D3BFE1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; A142E70821E7919F000395E3 /* IntroContactViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntroContactViewController.swift; sourceTree = "<group>"; }; + A15D215A223BE5F4003E0CE0 /* TempAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TempAttachment.swift; sourceTree = "<group>"; }; + A15D215C223BE614003E0CE0 /* attachment.eml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = attachment.eml; sourceTree = "<group>"; }; + A15D215E223BE6E4003E0CE0 /* MailTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MailTest.swift; sourceTree = "<group>"; }; A15D2D0B21F4CF13007AF2F4 /* enzevalos_iphone 5.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "enzevalos_iphone 5.xcdatamodel"; sourceTree = "<group>"; }; A16BA2111E0439B6005E29E3 /* providers.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; lineEnding = 0; path = providers.json; sourceTree = "<group>"; }; A1735DF9205AB88500B336DB /* SendViewState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendViewState.swift; sourceTree = "<group>"; }; @@ -579,6 +642,36 @@ name = Invitation; sourceTree = "<group>"; }; + 470709112189BB4A00DF71A3 /* testMails */ = { + isa = PBXGroup; + children = ( + A15D215C223BE614003E0CE0 /* attachment.eml */, + 47E7BE622232BD0A00C8EF94 /* SignedEncMailFromMac.eml */, + 47E7BE5A22319B6900C8EF94 /* EncMailFromMac.eml */, + 47E7BE6022319B8F00C8EF94 /* PlainMailFromMac.eml */, + 47E7BE5E22319B7D00C8EF94 /* SecureMailFromMac.eml */, + 47E7BE5C22319B7000C8EF94 /* SignedMailFromMac.eml */, + 47C22282218B02C700BD2C2B /* autocryptSimpleExample1.eml */, + 4707092F2189E1C000DF71A3 /* enc+signedThunderbird.eml */, + 470709212189C73900DF71A3 /* enc+signedInlineThunderbird.eml */, + 470709232189C73900DF71A3 /* encInlineThunderbird.eml */, + 470709222189C73900DF71A3 /* encThunderbird.eml */, + 470709242189C73900DF71A3 /* signedInlineThunderbird.eml */, + 470709252189C73900DF71A3 /* signedThunderbird.eml */, + 470709172189BC3500DF71A3 /* plainThunderbird.eml */, + ); + path = testMails; + sourceTree = "<group>"; + }; + 470709202189C24800DF71A3 /* testKeys */ = { + isa = PBXGroup; + children = ( + 4707092C2189C74200DF71A3 /* alicePublic.asc */, + 4707092B2189C74200DF71A3 /* bobSecret.asc */, + ); + path = testKeys; + sourceTree = "<group>"; + }; 472F39921E279792009260FB /* protocols */ = { isa = PBXGroup; children = ( @@ -590,6 +683,39 @@ name = protocols; sourceTree = "<group>"; }; + 477548DC21F5DA46000B22A8 /* mail */ = { + isa = PBXGroup; + children = ( + 476801DD21846A5A00F7F259 /* OutgoingMail.swift */, + A16BA2111E0439B6005E29E3 /* providers.json */, + A1EB057B1D956838008659C1 /* MailHandler.swift */, + 477548DD21F5DABE000B22A8 /* MailServerConnectionError.swift */, + 47CEAC97222541B40075B7DC /* MailSession.swift */, + 478AF714222FD5C600AEF69E /* IncomingMail.swift */, + ); + name = mail; + sourceTree = "<group>"; + }; + 477548E021F77445000B22A8 /* study parameters */ = { + isa = PBXGroup; + children = ( + 477548E121F77466000B22A8 /* SecurityIndicator.swift */, + 478154A621FF3F0900A931EC /* Warning.swift */, + 477548E321F77BA0000B22A8 /* StudyParameterProtocol.swift */, + 478154A821FF3FF400A931EC /* Invitation.swift */, + ); + path = "study parameters"; + sourceTree = "<group>"; + }; + 478154AA21FF6A5300A931EC /* mailbot */ = { + isa = PBXGroup; + children = ( + 478154AB21FF6A9600A931EC /* Mailbot.swift */, + ); + name = mailbot; + path = "New Group"; + sourceTree = "<group>"; + }; 47B91AC01EC0C1CF000AE3EE /* coredata */ = { isa = PBXGroup; children = ( @@ -613,13 +739,13 @@ 47B91AC11EC0C1FB000AE3EE /* data */ = { isa = PBXGroup; children = ( + A15D215A223BE5F4003E0CE0 /* TempAttachment.swift */, 472F39921E279792009260FB /* protocols */, A114E4311FACB23000E40243 /* StringExtension.swift */, 47691A8B1ECC3EC7004BCFC5 /* EphemeralMail.swift */, 472F398B1E2519C8009260FB /* CNContactExtension.swift */, 472F398F1E252470009260FB /* CNMailAddressesExtension.swift */, A1EB05871D956879008659C1 /* AddressHandler.swift */, - 479C648A21EE416100A01071 /* TempAttachment.swift */, 47B91AC01EC0C1CF000AE3EE /* coredata */, ); name = data; @@ -688,14 +814,6 @@ name = Data; sourceTree = "<group>"; }; - A10DAA5521F347D2005D8BBB /* Recovered References */ = { - isa = PBXGroup; - children = ( - 479C648821EE299C00A01071 /* attachment.eml */, - ); - name = "Recovered References"; - sourceTree = "<group>"; - }; A10DE41E1EFAA140005E8189 /* folders */ = { isa = PBXGroup; children = ( @@ -719,6 +837,7 @@ isa = PBXGroup; children = ( 475B00301F7B9565006CDD41 /* SwiftPGP.swift */, + 476801DA218436B600F7F259 /* Autocrypt.swift */, 475B00311F7B9565006CDD41 /* Cryptography.swift */, 475B00321F7B9565006CDD41 /* CryptoObject.swift */, ); @@ -743,7 +862,6 @@ A13526761D955BDF00D3BFE1 /* Products */, 24472862977D71D3F0AD0D58 /* Pods */, 78280F99990BFF65543B7F0B /* Frameworks */, - A10DAA5521F347D2005D8BBB /* Recovered References */, ); sourceTree = "<group>"; }; @@ -762,6 +880,7 @@ isa = PBXGroup; children = ( A1B9999D21DE7CD2002563F6 /* Travel */, + 477548DC21F5DA46000B22A8 /* mail */, F1866C84201F703200B72453 /* OAuth */, 3EB4FA9C2012007C001D0625 /* Dialog */, 3EC35F1F2003755F008BDF95 /* Invitation */, @@ -783,8 +902,6 @@ 476142071E07E52B00FD5E4F /* Theme.swift */, A1230BD81E2F881E006642C7 /* Encryption */, 476373C11E09BA88004D5EFE /* UserData.swift */, - A16BA2111E0439B6005E29E3 /* providers.json */, - A1EB057B1D956838008659C1 /* MailHandler.swift */, A198270D1D9A8ABC0027F65C /* enzevalos_iphone-Bridging-Header.h */, A1F9922B1DA7C9100073BF1B /* Main.storyboard */, F1984D731E1E92B300804E1E /* LabelStyleKit.swift */, @@ -803,12 +920,17 @@ A135268F1D955BE000D3BFE1 /* enzevalos_iphoneTests */ = { isa = PBXGroup; children = ( + 470709202189C24800DF71A3 /* testKeys */, + 470709112189BB4A00DF71A3 /* testMails */, 4715F636202A0248001BFFD0 /* CoreDataTests.swift */, + A15D215E223BE6E4003E0CE0 /* MailTest.swift */, A13526921D955BE000D3BFE1 /* Info.plist */, F1E918D61FBDEECA00D60418 /* LoggerTests.swift */, 3EC35F2F2003838E008BDF95 /* InvitationTests.swift */, 8428A8561F4369EA007649A5 /* GamificationDataUnitTest.swift */, 479B5976206914BE00B3944D /* CryptoTests.swift */, + 47C22280218AFD6300BD2C2B /* AutocryptTest.swift */, + 478154AD2200641900A931EC /* StudyTest.swift */, ); path = enzevalos_iphoneTests; sourceTree = "<group>"; @@ -835,6 +957,8 @@ A17FDFF1202C680A00F7BA89 /* debug and study */ = { isa = PBXGroup; children = ( + 478154AA21FF6A5300A931EC /* mailbot */, + 477548E021F77445000B22A8 /* study parameters */, A17FDFF2202C685800F7BA89 /* StudySettings.swift */, 47D1302A1F7CEE6D007B14DF /* DebugSettings.swift */, A111F6AB1FA77AF80060AFDE /* Logging */, @@ -881,6 +1005,8 @@ A18C76851E8185ED00B21414 /* onboarding */ = { isa = PBXGroup; children = ( + 479C649821F45DAF00A01071 /* HideShowPasswordTextField.swift */, + 479C649921F45DAF00A01071 /* PasswordToggleVisibilityView.swift */, A1083A531E8BFEA6003666B7 /* Onboarding.swift */, A102AA891EDDB4E80024B457 /* videoOnboarding2.m4v */, A1C62E992018F716000E5273 /* OnboardingValueState.swift */, @@ -911,9 +1037,8 @@ isa = PBXGroup; children = ( A1E5960D1FCC871E003791E9 /* researchteam.asc */, - 47953AA81FD7000200D4631A /* bitcoinde.asc */, - 47CD5AA92012368D00E771A1 /* bitcoinde.asc */, - 47CD5AAC2012369300E771A1 /* support_pk.asc */, + 479C649521F2139B00A01071 /* support_pk.asc */, + 47CD5AAC2012369300E771A1 /* support_pk2.asc */, 47CD5AA82012368D00E771A1 /* logging_pk.asc */, ); name = keys; @@ -1174,11 +1299,11 @@ 3E97093B1FAC95F5005825C9 /* InboxTableViewCell.xib in Resources */, 3E97093D1FAC95F5005825C9 /* ContactCell.xib in Resources */, 3E97093E1FAC95F5005825C9 /* Inbox.storyboard in Resources */, + 479C649721F2139B00A01071 /* support_pk.asc in Resources */, 3E9709401FAC95F5005825C9 /* Settings.bundle in Resources */, 3E9709431FAC95F5005825C9 /* providers.json in Resources */, 3EB4FAA22012007C001D0625 /* Dialog.storyboard in Resources */, 3E97094C1FAC95F5005825C9 /* Localizable.strings in Resources */, - 47953AAA1FD7000200D4631A /* bitcoinde.asc in Resources */, 3E97094D1FAC95F5005825C9 /* Main.storyboard in Resources */, 3E9709501FAC95F5005825C9 /* InfoPlist.strings in Resources */, 3E9709511FAC95F5005825C9 /* Gamification.storyboard in Resources */, @@ -1196,18 +1321,17 @@ files = ( A102AA8A1EDDB4F40024B457 /* videoOnboarding2.m4v in Resources */, A1F992391DA7DD2E0073BF1B /* InboxTableViewCell.xib in Resources */, - 47CD5AAD2012369400E771A1 /* support_pk.asc in Resources */, + 47CD5AAD2012369400E771A1 /* support_pk2.asc in Resources */, A1EB058A1D956890008659C1 /* ContactCell.xib in Resources */, F1F070281FA0DF3F004A860A /* Inbox.storyboard in Resources */, 4761420A1E082F9C00FD5E4F /* Settings.bundle in Resources */, A16BA2121E0439B6005E29E3 /* providers.json in Resources */, - 47953AA91FD7000200D4631A /* bitcoinde.asc in Resources */, - 47CD5AAB2012368D00E771A1 /* bitcoinde.asc in Resources */, F12D8DBB2069422A0068788E /* About.storyboard in Resources */, A1E5960E1FCC871F003791E9 /* researchteam.asc in Resources */, A1123E6A1DA682850069551C /* Localizable.strings in Resources */, A1F992291DA7C9100073BF1B /* Main.storyboard in Resources */, F18C5E561FE025D300C3B86D /* BadgeCase.storyboard in Resources */, + 479C649621F2139B00A01071 /* support_pk.asc in Resources */, 3EB4FAA12012007C001D0625 /* Dialog.storyboard in Resources */, A1B49E5F21E54EE700ED86FC /* IntroContactView.xib in Resources */, A1BE3FF61E9664660040114B /* InfoPlist.strings in Resources */, @@ -1228,9 +1352,24 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 470709262189C73900DF71A3 /* enc+signedInlineThunderbird.eml in Resources */, + 47E7BE632232BD0A00C8EF94 /* SignedEncMailFromMac.eml in Resources */, 479B597B20691C1A00B3944D /* ObjectivePGP.framework in Resources */, + 470709282189C73900DF71A3 /* encInlineThunderbird.eml in Resources */, + 470709292189C73900DF71A3 /* signedInlineThunderbird.eml in Resources */, 8428A8841F436ACC007649A5 /* GamificationElements.xcassets in Resources */, - 479C648921EE299C00A01071 /* attachment.eml in Resources */, + 4707092D2189C74200DF71A3 /* bobSecret.asc in Resources */, + 47E7BE5B22319B6900C8EF94 /* EncMailFromMac.eml in Resources */, + 4707091E2189BC3500DF71A3 /* plainThunderbird.eml in Resources */, + 4707092E2189C74200DF71A3 /* alicePublic.asc in Resources */, + 4707092A2189C73900DF71A3 /* signedThunderbird.eml in Resources */, + A15D215D223BE614003E0CE0 /* attachment.eml in Resources */, + 47C22283218B02C700BD2C2B /* autocryptSimpleExample1.eml in Resources */, + 470709302189E1C100DF71A3 /* enc+signedThunderbird.eml in Resources */, + 47E7BE6122319B8F00C8EF94 /* PlainMailFromMac.eml in Resources */, + 470709272189C73900DF71A3 /* encThunderbird.eml in Resources */, + 47E7BE5D22319B7100C8EF94 /* SignedMailFromMac.eml in Resources */, + 47E7BE5F22319B7D00C8EF94 /* SecureMailFromMac.eml in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1418,6 +1557,7 @@ 3E9708C41FAC95F5005825C9 /* InboxCellDelegator.swift in Sources */, 3E9708C51FAC95F5005825C9 /* Badges.swift in Sources */, 3E9708C61FAC95F5005825C9 /* BadgeCaseCollectionViewCell.swift in Sources */, + 477548DF21F5DABE000B22A8 /* MailServerConnectionError.swift in Sources */, 3E9708C71FAC95F5005825C9 /* Mail_Address+CoreDataClass.swift in Sources */, 3E9708C81FAC95F5005825C9 /* CollectionDataDelegate.swift in Sources */, 3E9708C91FAC95F5005825C9 /* DebugSettings.swift in Sources */, @@ -1433,6 +1573,7 @@ 3E9708DD1FAC95F5005825C9 /* ArrowTableViewCell.swift in Sources */, 3E9708DE1FAC95F5005825C9 /* ContactViewController.swift in Sources */, 3E9708DF1FAC95F5005825C9 /* CryptoObject.swift in Sources */, + 476801DC218436B600F7F259 /* Autocrypt.swift in Sources */, 3E9708E01FAC95F5005825C9 /* VENDataDelegate.swift in Sources */, 3E9708E11FAC95F5005825C9 /* InviteFriendViewController.swift in Sources */, 3EC35F2E200376A1008BDF95 /* SendViewController+Invitation.swift in Sources */, @@ -1459,6 +1600,7 @@ 3E9709031FAC95F5005825C9 /* MessageBodyTableViewCell.swift in Sources */, 3E9709041FAC95F5005825C9 /* ReadVENDelegate.swift in Sources */, 3E9709061FAC95F5005825C9 /* PersistentKey+CoreDataClass.swift in Sources */, + 477548E621F77DF7000B22A8 /* SecurityIndicator.swift in Sources */, 3E9709081FAC95F5005825C9 /* KeyViewController.swift in Sources */, 3E9709091FAC95F5005825C9 /* ExportCells.swift in Sources */, 3E97090B1FAC95F5005825C9 /* CNMailAddressesExtension.swift in Sources */, @@ -1482,10 +1624,12 @@ 3E9709231FAC95F5005825C9 /* MailAddress.swift in Sources */, 3E9709241FAC95F5005825C9 /* MailHandlerDelegator.swift in Sources */, 3E97092A1FAC95F5005825C9 /* LabelStyleKit.swift in Sources */, + 477548E521F77DF5000B22A8 /* StudyParameterProtocol.swift in Sources */, 3E97092C1FAC95F5005825C9 /* SubBadgeTableViewCell.swift in Sources */, 3E97092D1FAC95F5005825C9 /* FrequentCell.swift in Sources */, 3E97092E1FAC95F5005825C9 /* ListViewController.swift in Sources */, 3E97092F1FAC95F5005825C9 /* FlipTransition.swift in Sources */, + 476801DF21846A5A00F7F259 /* OutgoingMail.swift in Sources */, 3EB4FAA02012007C001D0625 /* DialogViewController.swift in Sources */, 3E9709331FAC95F5005825C9 /* EnzevalosContact+CoreDataProperties.swift in Sources */, 3E9709341FAC95F5005825C9 /* BadgeCase.swift in Sources */, @@ -1497,6 +1641,7 @@ buildActionMask = 2147483647; files = ( 47691A8A1ECB56D1004BCFC5 /* Mail.swift in Sources */, + 476801DE21846A5A00F7F259 /* OutgoingMail.swift in Sources */, 472F398A1E251787009260FB /* Contact.swift in Sources */, 472F39861E1FA34E009260FB /* Record.swift in Sources */, A1C3270E1DB907D900CE2ED5 /* TextFormatter.swift in Sources */, @@ -1511,10 +1656,10 @@ 8428A85D1F436A05007649A5 /* Badges.swift in Sources */, 8428A8651F436A11007649A5 /* BadgeCaseCollectionViewCell.swift in Sources */, 472F39811E1E5347009260FB /* Mail_Address+CoreDataClass.swift in Sources */, - 479C648B21EE416100A01071 /* TempAttachment.swift in Sources */, A1EB05821D95685B008659C1 /* CollectionDataDelegate.swift in Sources */, 47D1302B1F7CEE6D007B14DF /* DebugSettings.swift in Sources */, A1EB05801D956851008659C1 /* SendViewController.swift in Sources */, + 479C649B21F45DAF00A01071 /* PasswordToggleVisibilityView.swift in Sources */, 47691A8C1ECC3EC7004BCFC5 /* EphemeralMail.swift in Sources */, A142E70921E7919F000395E3 /* IntroContactViewController.swift in Sources */, 8428A8671F436A11007649A5 /* SubBadgeHeaderTableViewCell.swift in Sources */, @@ -1533,8 +1678,10 @@ 8428A86F1F436A1E007649A5 /* InviteFriendViewController.swift in Sources */, A1735DFA205AB88500B336DB /* SendViewState.swift in Sources */, 475B00331F7B9565006CDD41 /* SwiftPGP.swift in Sources */, + 477548E421F77BA0000B22A8 /* StudyParameterProtocol.swift in Sources */, 3EB4FAA420120096001D0625 /* DialogOption.swift in Sources */, F14239C11F30A99C00998A83 /* QRCodeGenerator.swift in Sources */, + 478154A921FF3FF400A931EC /* Invitation.swift in Sources */, F1AF938F1E2D04BA00755128 /* CustomCells.swift in Sources */, 8428A8711F436A1E007649A5 /* GamificationStatusViewController.swift in Sources */, F1866C86201F707200B72453 /* EmailHelper.m in Sources */, @@ -1543,15 +1690,20 @@ 3EB4FA9F2012007C001D0625 /* DialogViewController.swift in Sources */, 476142081E07E52B00FD5E4F /* Theme.swift in Sources */, 8428A8701F436A1E007649A5 /* LinearBadgeViewController.swift in Sources */, + 476801DB218436B600F7F259 /* Autocrypt.swift in Sources */, A1EB057A1D956829008659C1 /* ContactCell.swift in Sources */, A12FC23120221A1400196008 /* ExportInfoViewController.swift in Sources */, + 477548DE21F5DABE000B22A8 /* MailServerConnectionError.swift in Sources */, 475DF47A1F0D54C9009D807F /* Folder+CoreDataProperties.swift in Sources */, 475B00431F7BB6D6006CDD41 /* PersistentKey+CoreDataProperties.swift in Sources */, + 479C649A21F45DAF00A01071 /* HideShowPasswordTextField.swift in Sources */, + 47CEAC98222541B40075B7DC /* MailSession.swift in Sources */, F119D2901E364B59001D732A /* AnimatedSendIcon.swift in Sources */, 4707096D1F8F9F4900657F41 /* ExportViewController.swift in Sources */, F12060801DA540FE00F6EF37 /* RefreshControlExtension.swift in Sources */, A13526811D955BDF00D3BFE1 /* enzevalos_iphone.xcdatamodeld in Sources */, 472F39821E1E5347009260FB /* Mail_Address+CoreDataProperties.swift in Sources */, + 477548E221F77466000B22A8 /* SecurityIndicator.swift in Sources */, 476373C21E09BA88004D5EFE /* UserData.swift in Sources */, A1EB05A01D95696C008659C1 /* MessageBodyTableViewCell.swift in Sources */, F18B44621E73286C0080C041 /* ReadVENDelegate.swift in Sources */, @@ -1579,10 +1731,12 @@ A1ECE54B1EFBE7ED0009349F /* FolderCell.swift in Sources */, 8428A85F1F436A05007649A5 /* GamificationData.swift in Sources */, 475DF4791F0D54C9009D807F /* Folder+CoreDataClass.swift in Sources */, + A15D215B223BE5F4003E0CE0 /* TempAttachment.swift in Sources */, 3EC35F2D200376A1008BDF95 /* SendViewController+Invitation.swift in Sources */, 475B00341F7B9565006CDD41 /* Cryptography.swift in Sources */, A1EB057C1D956838008659C1 /* MailHandler.swift in Sources */, A182182E21E50D8D00918A29 /* IntroButtonViewController.swift in Sources */, + 478AF715222FD5C600AEF69E /* IncomingMail.swift in Sources */, A1EB05881D956879008659C1 /* AddressHandler.swift in Sources */, 472F39701E14F75C009260FB /* DataHandler.swift in Sources */, A1C62E9A2018F716000E5273 /* OnboardingValueState.swift in Sources */, @@ -1594,11 +1748,13 @@ A18E7D771FBDE5D9002F7CC9 /* LoggingEventType.swift in Sources */, F1984D741E1E92B300804E1E /* LabelStyleKit.swift in Sources */, A1FA44A721E10E1400DB02AC /* TravelHandler.swift in Sources */, + 478154A721FF3F0900A931EC /* Warning.swift in Sources */, 8428A8681F436A11007649A5 /* SubBadgeTableViewCell.swift in Sources */, A1EB05861D956872008659C1 /* FrequentCell.swift in Sources */, F12041FB1DA3FBF7002E4940 /* ListViewController.swift in Sources */, F18B445E1E7044B70080C041 /* FlipTransition.swift in Sources */, 472F397E1E1D0B0B009260FB /* EnzevalosContact+CoreDataProperties.swift in Sources */, + 478154AC21FF6A9600A931EC /* Mailbot.swift in Sources */, 8428A86E1F436A1E007649A5 /* BadgeCase.swift in Sources */, A1B49E5D21E54CBF00ED86FC /* IntroContactTableViewController.swift in Sources */, ); @@ -1611,7 +1767,10 @@ 8428A8831F436AC9007649A5 /* GamificationDataUnitTest.swift in Sources */, 3EC35F302003838E008BDF95 /* InvitationTests.swift in Sources */, 479B5977206914BE00B3944D /* CryptoTests.swift in Sources */, + A15D215F223BE6E4003E0CE0 /* MailTest.swift in Sources */, 4715F637202A0248001BFFD0 /* CoreDataTests.swift in Sources */, + 47C22281218AFD6300BD2C2B /* AutocryptTest.swift in Sources */, + 478154AE2200641900A931EC /* StudyTest.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1929,7 +2088,7 @@ baseConfigurationReference = 91B6C9020C660BEA78FAEF28 /* Pods-enzevalos_iphone.debug.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_APPICON_NAME = Mailbox; CLANG_ENABLE_MODULES = NO; CODE_SIGN_ENTITLEMENTS = enzevalos_iphone/PLists/enzevalos_iphone.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -1989,7 +2148,7 @@ baseConfigurationReference = AA686D4FC9B86445A0C87F0F /* Pods-enzevalos_iphone.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_APPICON_NAME = Mailbox; CLANG_ENABLE_MODULES = NO; CODE_SIGN_ENTITLEMENTS = enzevalos_iphone/PLists/enzevalos_iphone.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; diff --git a/enzevalos_iphone.xcodeproj/project.xcworkspace/xcuserdata/Olli.xcuserdatad/UserInterfaceState.xcuserstate b/enzevalos_iphone.xcodeproj/project.xcworkspace/xcuserdata/Olli.xcuserdatad/UserInterfaceState.xcuserstate index c93b9ff53b8d6cc0260381a2db718b0bf37413fb..cc59415b1fd6ec353f8779ec0721d09d40ad4361 100644 Binary files a/enzevalos_iphone.xcodeproj/project.xcworkspace/xcuserdata/Olli.xcuserdatad/UserInterfaceState.xcuserstate and b/enzevalos_iphone.xcodeproj/project.xcworkspace/xcuserdata/Olli.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/enzevalos_iphone/AddressHandler.swift b/enzevalos_iphone/AddressHandler.swift index 6e92a4da15bf99e59406160b76e9e67b3f84a027..9d173ca7ade5bfb43606be0f522b9f04bd2d3e8d 100644 --- a/enzevalos_iphone/AddressHandler.swift +++ b/enzevalos_iphone/AddressHandler.swift @@ -276,7 +276,7 @@ class AddressHandler { } - static func updateCNContacts() { + static func updateCNContacts(save: Bool = true) { let enzContacts = DataHandler.handler.getContacts() for contact in enzContacts { @@ -316,6 +316,8 @@ class AddressHandler { } } - DataHandler.handler.save(during: "updateCNContacts") + if save { + DataHandler.handler.save(during: "updateCNContacts") + } } } diff --git a/enzevalos_iphone/AnimatedSendIcon.swift b/enzevalos_iphone/AnimatedSendIcon.swift index 01e31e14d7d674ad6219a72245924fd809fdfcb3..79a93830e4eccd4a59a7c43adb25663c317361ae 100644 --- a/enzevalos_iphone/AnimatedSendIcon.swift +++ b/enzevalos_iphone/AnimatedSendIcon.swift @@ -24,32 +24,41 @@ import UIKit class AnimatedSendIcon: UIView { var isPostcardOnTop = false - var square = UIImageView(image:IconsStyleKit.imageOfLetterBG) - var square2 = UIImageView(image:IconsStyleKit.imageOfPostcardBG) - let width = 100.0 - let height = 70.0 + var square = UIImageView(image: StudySettings.securityIndicator.imageOfSecureIndicator(background: true, open: false)) + var square2 = UIImageView(image: StudySettings.securityIndicator.imageOfInsecureIndicator(background: true)) + let width: Double //= 100.0 + let height: Double// = 70.0 let f = 0.8 var size = CGSize() var sizeSmall = CGSize() - let front = CGPoint(x: 30, y: 35) + let front = CGPoint(x: 30, y: 30) let back = CGPoint(x: 100, y: 15) + var scale = false + var scaleFactor = 1.0 override init(frame: CGRect) { + if let w = square.image?.size.width { + scaleFactor = min(100.0 / Double(w), 2.6) + self.width = Double(w) * scaleFactor + } + else { + self.width = 100.0 + } + if let h = square.image?.size.height { + self.height = Double(h) * scaleFactor + } + else { + self.height = 70.0 + } + + super.init(frame: frame) self.isUserInteractionEnabled = false let resizing: ResizingBehavior = .aspectFit -// let context = UIGraphicsGetCurrentContext()! -// //// Resize to Target Frame -// CGContextSaveGState(context) let resizedFrame: CGRect = resizing.apply(rect: CGRect(x: 0, y: 0, width: 200, height: 110), target: CGRect(x: 40, y: -10, width: 113, height: 48)) -// CGContextTranslateCTM(context, resizedFrame.minX, resizedFrame.minY) -// CGContextScaleCTM(context, resizedFrame.width / 200, resizedFrame.height / 110) -// -// self.view.transform = CGAffineTransformMakeScale(2, 2) - + self.transform = CGAffineTransform(scaleX: resizedFrame.width / 200, y: resizedFrame.height / 110) - // self = UIView(frame: frame) //UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 110)) self.backgroundColor = UIColor.white size = CGSize(width: width, height: height) @@ -64,8 +73,6 @@ class AnimatedSendIcon: UIView { self.addSubview(square) self.addSubview(square2) - -// CGContextRestoreGState(context) } required init?(coder aDecoder: NSCoder) { diff --git a/enzevalos_iphone/AppDelegate.swift b/enzevalos_iphone/AppDelegate.swift index d033e99416fe9fd26ad20ff6d02ee10ae7f114f2..5adfa42bcf417683d2eca8fd5e0fcafd9caf205b 100644 --- a/enzevalos_iphone/AppDelegate.swift +++ b/enzevalos_iphone/AppDelegate.swift @@ -47,7 +47,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { resetApp() StudySettings.setupStudy() - // StudySettings.firstMail() + //StudySettings.firstMail() if (!UserDefaults.standard.bool(forKey: "launchedBefore")) { // Logger.queue.async(flags: .barrier) { Logger.log(startApp: true) @@ -61,7 +61,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { self.window = UIWindow(frame: UIScreen.main.bounds) //self.window?.rootViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("onboarding") - self.window?.rootViewController = Onboarding.onboarding(self.credentialCheck) + self.window?.rootViewController = Onboarding.onboarding() self.window?.makeKeyAndVisible() @@ -75,15 +75,17 @@ class AppDelegate: UIResponder, UIApplicationDelegate { selector: #selector(addressBookDidChange), name: NSNotification.Name.CNContactStoreDidChange, object: nil) - - if #available(iOS 11.0, *) { - QAKit.Fingertips.start() - } + if #available(iOS 11.0, *) { + QAKit.Fingertips.start() + } // Set background fetching time interval to 5 min // Alternative: UIApplicationBackgroundFetchIntervalMinimum let backgroundFetchInterval : Double = 60*5 // = seconds * minutes UIApplication.shared.setMinimumBackgroundFetchInterval(backgroundFetchInterval) - + + if hasUser() { + DataHandler.handler.startToSendMore() + } return true } @@ -113,7 +115,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { if self.currentReachabilityStatus == .notReachable { let alert = UIAlertController(title: NSLocalizedString("Error.noInternet.Title", comment: ""), message: NSLocalizedString("Error.noInternet.Message", comment: ""), preferredStyle: .alert) alert.addAction(UIAlertAction(title: "On", style: .default, handler: { [weak self] _ in - let contr = (Onboarding.onboarding((self?.credentialCheck)!) as! OnboardingViewController) + let contr = (Onboarding.onboarding() as! OnboardingViewController) self?.window?.rootViewController = contr contr.gotoLastPage() })) @@ -122,7 +124,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { EmailHelper.singleton().doEmailLoginIfRequired(onVC: vc, completionBlock: { guard let userEmail = EmailHelper.singleton().authorization?.userEmail, EmailHelper.singleton().authorization?.canAuthorize() ?? false else { print("Google authetication failed") - self.credentialsFailed() + // TODO: self.credentialsFailed(error: MailServerConnectionError.AuthenticationError) return } UserManager.storeUserValue(userEmail as AnyObject, attribute: Attribute.userName) @@ -136,11 +138,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate { UserManager.storeUserValue(MCOConnectionType.startTLS.rawValue as AnyObject, attribute: Attribute.smtpConnectionType) UserManager.storeUserValue(MCOAuthType.xoAuth2.rawValue as AnyObject, attribute: Attribute.smtpAuthType) - Onboarding.checkConfig(self.credentialsFailed, work: self.credentialsWork) + Onboarding.checkIMAPConfigUI() }) } } + /* func credentialCheck() { self.window?.rootViewController = Onboarding.checkConfigView() if Onboarding.googleAuth { @@ -149,18 +152,18 @@ class AppDelegate: UIResponder, UIApplicationDelegate { return } if Onboarding.setValues() != OnboardingValueState.fine { - credentialsFailed() + credentialsFailed(error: MailServerConnectionError.NoError) return } Onboarding.checkConfig(self.credentialsFailed, work: self.credentialsWork) } - func credentialsFailed() { + func credentialsFailed(error: MailServerConnectionError) { Onboarding.credentialFails += 1 if Onboarding.credentialFails >= 2 { Onboarding.manualSet = true - self.window?.rootViewController = Onboarding.detailOnboarding(self.credentialCheck) + self.window?.rootViewController = Onboarding.detailOnboarding(self.credentialCheck, errorCode: error) } else { Onboarding.manualSet = false let contr = (Onboarding.onboarding(self.credentialCheck) as! OnboardingViewController) @@ -168,6 +171,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { contr.gotoLastPage() } } + */ func credentialsWork() { self.window?.rootViewController = Onboarding.contactView(self.requestForAccess) @@ -194,7 +198,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { self.window = UIWindow(frame: UIScreen.main.bounds) //self.window?.rootViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("onboarding") - self.window?.rootViewController = Onboarding.onboarding(self.credentialCheck) + self.window?.rootViewController = Onboarding.onboarding() self.window?.makeKeyAndVisible() UserDefaults.standard.set(false, forKey: "launchedBefore") UserDefaults.standard.set(false, forKey: "reset") @@ -202,11 +206,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } func setupKeys() { - self.window?.rootViewController = Onboarding.keyHandlingView() + DispatchQueue.main.async(execute: { + self.window?.rootViewController = Onboarding.keyHandlingView() + }) let handler = DataHandler.init() _ = handler.createNewSecretKey(adr: UserManager.loadUserValue(Attribute.userAddr) as! String) StudySettings.setupStudyKeys() - StudySettings.firstMail() + Mailbot.firstMail() DataHandler.handler.callForFolders(done: { err in for f in DataHandler.handler.allFolders { if f.flags.contains(MCOIMAPFolderFlag.drafts) { @@ -261,6 +267,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate { Logger.log(background: false) // } resetApp() + if hasUser() { + DataHandler.handler.startToSendMore() + } + } + + private func hasUser() -> Bool{ + return UserManager.loadUserValue(.userAddr) != nil } func applicationWillTerminate(_ application: UIApplication) { @@ -358,8 +371,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func hasNewMails(_ newMails: UInt32, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void){ let duration = Date().timeIntervalSince(start) Logger.log(backgroundFetch: newMails, duration: duration) - if newMails > 0 { - UIApplication.shared.applicationIconBadgeNumber = Int(newMails) + var mails = newMails - 1 + if mails > 0 { + UIApplication.shared.applicationIconBadgeNumber = Int(mails) completionHandler(.newData) } else { UIApplication.shared.applicationIconBadgeNumber = 0 @@ -419,6 +433,22 @@ extension AppDelegate { //Network check } } + func noInternetConnection(){ + let alert = UIAlertController(title: NSLocalizedString("ReceiveError", comment: "There was an error"), message: NSLocalizedString("ErrorText", comment: ""), preferredStyle: UIAlertControllerStyle.alert) + alert.addAction(UIAlertAction(title: NSLocalizedString("Done", comment: ""), style: UIAlertActionStyle.default, handler: nil)) + self.window?.rootViewController?.present(alert, animated: true, completion: nil) + if #available(iOS 10.0, *) { + Timer.scheduledTimer(withTimeInterval: TimeInterval(5), repeats: true, block: ({(t: Timer) -> () in + if self.currentReachabilityStatus != .notReachable { + t.invalidate() + DataHandler.handler.startToSendMore() + } + })) + } else { + // Fallback on earlier versions + } + } + } struct AppUtility { diff --git a/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Contents.json b/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Contents.json new file mode 100644 index 0000000000000000000000000000000000000000..82e208dd47ee11dcc81435271422dedda862c481 --- /dev/null +++ b/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Contents.json @@ -0,0 +1,62 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Mailbox_40.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Mailbox_60.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Mailbox_58.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Mailbox_87.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Mailbox_80.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Mailbox_120.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Mailbox_120-1.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Mailbox@3x.png", + "scale" : "3x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Mailbox_1024.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox@3x.png b/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..0c8903dbf9d22d5956886725d72fcd9a950a6650 Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox@3x.png differ diff --git a/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox_1024.png b/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox_1024.png new file mode 100644 index 0000000000000000000000000000000000000000..10879a629df4652725458eb1db850a6eb9079d1b Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox_1024.png differ diff --git a/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox_120-1.png b/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox_120-1.png new file mode 100644 index 0000000000000000000000000000000000000000..5f495093b013400ddab4b95c66c039e09ee038f3 Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox_120-1.png differ diff --git a/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox_120.png b/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox_120.png new file mode 100644 index 0000000000000000000000000000000000000000..5f495093b013400ddab4b95c66c039e09ee038f3 Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox_120.png differ diff --git a/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox_40.png b/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox_40.png new file mode 100644 index 0000000000000000000000000000000000000000..e5fbba77dcaa5083759effe6cdc26241f9439b0b Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox_40.png differ diff --git a/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox_58.png b/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox_58.png new file mode 100644 index 0000000000000000000000000000000000000000..de5eaba8e47bb14e4dfa7545699861b5209d94f5 Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox_58.png differ diff --git a/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox_60.png b/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox_60.png new file mode 100644 index 0000000000000000000000000000000000000000..91e692c22b22c4627235ec30af663b58051c523d Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox_60.png differ diff --git a/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox_80.png b/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox_80.png new file mode 100644 index 0000000000000000000000000000000000000000..379621419e0edc5185810cf1f5a7b26985d2df22 Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox_80.png differ diff --git a/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox_87.png b/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox_87.png new file mode 100644 index 0000000000000000000000000000000000000000..e6884e4fc3c56c7876cb536040b4bd4b32560c61 Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/Mailbox.appiconset/Mailbox_87.png differ diff --git a/enzevalos_iphone/Assets.xcassets/passwordInput/Contents.json b/enzevalos_iphone/Assets.xcassets/passwordInput/Contents.json new file mode 100644 index 0000000000000000000000000000000000000000..da4a164c918651cdd1e11dca5cc62c333f097601 --- /dev/null +++ b/enzevalos_iphone/Assets.xcassets/passwordInput/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/enzevalos_iphone/Assets.xcassets/passwordInput/ic_eye_closed.imageset/Contents.json b/enzevalos_iphone/Assets.xcassets/passwordInput/ic_eye_closed.imageset/Contents.json new file mode 100644 index 0000000000000000000000000000000000000000..1bb26ac5def09970c595f7a8c63be73007770a2d --- /dev/null +++ b/enzevalos_iphone/Assets.xcassets/passwordInput/ic_eye_closed.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_eye_closed.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "ic_eye_closed@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "ic_eye_closed@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/enzevalos_iphone/Assets.xcassets/passwordInput/ic_eye_closed.imageset/ic_eye_closed.png b/enzevalos_iphone/Assets.xcassets/passwordInput/ic_eye_closed.imageset/ic_eye_closed.png new file mode 100644 index 0000000000000000000000000000000000000000..10a89456c953256b948001ad9009ea4de285a457 Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/passwordInput/ic_eye_closed.imageset/ic_eye_closed.png differ diff --git a/enzevalos_iphone/Assets.xcassets/passwordInput/ic_eye_closed.imageset/ic_eye_closed@2x.png b/enzevalos_iphone/Assets.xcassets/passwordInput/ic_eye_closed.imageset/ic_eye_closed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..f8feed2ee39a7433e44e39b55189429d00f50c3c Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/passwordInput/ic_eye_closed.imageset/ic_eye_closed@2x.png differ diff --git a/enzevalos_iphone/Assets.xcassets/passwordInput/ic_eye_closed.imageset/ic_eye_closed@3x.png b/enzevalos_iphone/Assets.xcassets/passwordInput/ic_eye_closed.imageset/ic_eye_closed@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..798f10fd18b30cbfb052cb6a615e4c262742f411 Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/passwordInput/ic_eye_closed.imageset/ic_eye_closed@3x.png differ diff --git a/enzevalos_iphone/Assets.xcassets/passwordInput/ic_eye_open.imageset/Contents.json b/enzevalos_iphone/Assets.xcassets/passwordInput/ic_eye_open.imageset/Contents.json new file mode 100644 index 0000000000000000000000000000000000000000..63979ef42fc4258f587c9d33d2b76142b4b306bc --- /dev/null +++ b/enzevalos_iphone/Assets.xcassets/passwordInput/ic_eye_open.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_eye_open.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "ic_eye_open@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "ic_eye_open@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/enzevalos_iphone/Assets.xcassets/passwordInput/ic_eye_open.imageset/ic_eye_open.png b/enzevalos_iphone/Assets.xcassets/passwordInput/ic_eye_open.imageset/ic_eye_open.png new file mode 100644 index 0000000000000000000000000000000000000000..91faf3494467740a1e72d66042da7a5b2e162a1b Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/passwordInput/ic_eye_open.imageset/ic_eye_open.png differ diff --git a/enzevalos_iphone/Assets.xcassets/passwordInput/ic_eye_open.imageset/ic_eye_open@2x.png b/enzevalos_iphone/Assets.xcassets/passwordInput/ic_eye_open.imageset/ic_eye_open@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..050cbfae72ab4e9f007178afab75263bfb23c2d5 Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/passwordInput/ic_eye_open.imageset/ic_eye_open@2x.png differ diff --git a/enzevalos_iphone/Assets.xcassets/passwordInput/ic_eye_open.imageset/ic_eye_open@3x.png b/enzevalos_iphone/Assets.xcassets/passwordInput/ic_eye_open.imageset/ic_eye_open@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..54f3348b28895887e8e3cb039084a74ac4171a8a Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/passwordInput/ic_eye_open.imageset/ic_eye_open@3x.png differ diff --git a/enzevalos_iphone/Assets.xcassets/passwordInput/ic_password_checkmark.imageset/Contents.json b/enzevalos_iphone/Assets.xcassets/passwordInput/ic_password_checkmark.imageset/Contents.json new file mode 100644 index 0000000000000000000000000000000000000000..85a76208ad5a387b04f895ed8f01815f668fe032 --- /dev/null +++ b/enzevalos_iphone/Assets.xcassets/passwordInput/ic_password_checkmark.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_password_checkmark.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "ic_password_checkmark@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "ic_password_checkmark@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/enzevalos_iphone/Assets.xcassets/passwordInput/ic_password_checkmark.imageset/ic_password_checkmark.png b/enzevalos_iphone/Assets.xcassets/passwordInput/ic_password_checkmark.imageset/ic_password_checkmark.png new file mode 100644 index 0000000000000000000000000000000000000000..05a5bccd35783d27d8904dbf4fc9b66c0343f23d Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/passwordInput/ic_password_checkmark.imageset/ic_password_checkmark.png differ diff --git a/enzevalos_iphone/Assets.xcassets/passwordInput/ic_password_checkmark.imageset/ic_password_checkmark@2x.png b/enzevalos_iphone/Assets.xcassets/passwordInput/ic_password_checkmark.imageset/ic_password_checkmark@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4bf6c49ebebc5f5cc258567ecb6d375432087d8e Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/passwordInput/ic_password_checkmark.imageset/ic_password_checkmark@2x.png differ diff --git a/enzevalos_iphone/Assets.xcassets/passwordInput/ic_password_checkmark.imageset/ic_password_checkmark@3x.png b/enzevalos_iphone/Assets.xcassets/passwordInput/ic_password_checkmark.imageset/ic_password_checkmark@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..7740a41d8e0daf48bdc11325356cb816dead3271 Binary files /dev/null and b/enzevalos_iphone/Assets.xcassets/passwordInput/ic_password_checkmark.imageset/ic_password_checkmark@3x.png differ diff --git a/enzevalos_iphone/Autocrypt.swift b/enzevalos_iphone/Autocrypt.swift new file mode 100644 index 0000000000000000000000000000000000000000..651569507a6e104ca765907fbbb5896e284cd906 --- /dev/null +++ b/enzevalos_iphone/Autocrypt.swift @@ -0,0 +1,157 @@ + +// +// Autocrypt.swift +// enzevalos_iphone +// +// Created by Oliver Wiese on 27.10.18. +// Copyright © 2018 fu-berlin. All rights reserved. +// + +import Foundation + +// See: https://autocrypt.org/level1.html + +class Autocrypt { + static let ENFORCEENCRYPTION = true + static let AUTOCRYPTHEADER = "Autocrypt" + static let SETUPMESSAGE = "Autocrypt-Setup-Message" + static let ADDR = "addr" + static let TYPE = "type" + static let ENCRYPTION = "prefer-encrypt" + static let KEY = "keydata" + static let EXTRAHEADERS = [Autocrypt.AUTOCRYPTHEADER, Autocrypt.SETUPMESSAGE] + + var addr: String = "" + var type: CryptoScheme = .PGP + var prefer_encryption: EncState = EncState.NOAUTOCRYPT + var key: String = "" + + init(addr: String, type: String, prefer_encryption: String, key: String) { + self.addr = addr + self.key = key + setPrefer_encryption(prefer_encryption) + } + + + convenience init(header: MCOMessageHeader) { + var autocrypt = header.extraHeaderValue(forName: Autocrypt.AUTOCRYPTHEADER) + var field: [String] + var addr = "" + var type = "1" + var pref = EncState.MUTUAL.name + var key = "" + + if autocrypt != nil { + autocrypt = autocrypt?.trimmingCharacters(in: .whitespacesAndNewlines) + let autocrypt_fields = autocrypt?.components(separatedBy: ";") + for f in autocrypt_fields! { + field = f.components(separatedBy: "=") + if field.count > 1 { + let flag = field[0].trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) + var value = field[1] + if field.count > 2 { + for i in 2...(field.count - 1) { + value = value + "=" + value = value + field[i] + } + } + switch flag { + case Autocrypt.ADDR: + addr = value.trimmingCharacters(in: .whitespacesAndNewlines) + addr = addr.lowercased() + break + case Autocrypt.TYPE: + type = value.trimmingCharacters(in: .whitespacesAndNewlines) + break + case Autocrypt.ENCRYPTION: + pref = value.trimmingCharacters(in: .whitespacesAndNewlines) + break + case Autocrypt.KEY: + if value.count > 0 { + key = value + } + break + default: + break + } + } + } + } + self.init(addr: addr, type: type, prefer_encryption: pref, key: key) + } + + + func setPrefer_encryption(_ input: String){ + let pref = input.lowercased() + if pref == "yes" || pref == "mutual" || pref == EncState.MUTUAL.name { + self.prefer_encryption = EncState.MUTUAL + } else if pref == "no" || pref == EncState.NOPREFERENCE.name { + self.prefer_encryption = EncState.NOPREFERENCE + } + else { + self.prefer_encryption = EncState.NOPREFERENCE + } + } + + func toString() -> String { + return "Addr: \(addr) | type: \(type) | encryption? \(prefer_encryption) key size: \(key.count)" + } + + static func addAutocryptHeader(_ builder: MCOMessageBuilder) { + guard let prefKey = DataHandler.handler.prefSecretKey() else { + return + } + let adr = (UserManager.loadUserValue(Attribute.userAddr) as! String).lowercased() + let skID = prefKey.keyID + let encPref = EncState.MUTUAL + + let pgp = SwiftPGP() + if let id = skID { + if let key = pgp.exportKey(id: id, isSecretkey: false, autocrypt: true) { + var string = "\(ADDR)=" + adr + string = string + "; \(ENCRYPTION)=\(encPref.name)" + string = string + "; \(KEY)= \n" + key + builder.header.setExtraHeaderValue(string, forName: AUTOCRYPTHEADER) + } + } + } + + static func recommandateEncryption (receiver: MailAddress) -> (hasAutocrypt: Bool, recommandEnc: Bool){ + if receiver.hasKey, let key = receiver.primaryKey { + if key.prefer_encryption == .NOAUTOCRYPT { + return (false, ENFORCEENCRYPTION) + } + else if key.prefer_encryption == .MUTUAL { + return (true, true) + } + return (true, false) + } + else { + return (false, false) + } + } + + static func createAutocryptKeyExport(builder: MCOMessageBuilder, keyID: String, key: String) { + builder.header.setExtraHeaderValue("v1", forName: SETUPMESSAGE) + + builder.addAttachment(MCOAttachment.init(text: "This message contains a secret for reading secure mails on other devices. \n 1) Input the passcode from your smartphone to unlock the message on your other device. \n 2) Import the secret key into your pgp program on the device. \n\n For more information visit: https://userpage.fu-berlin.de/letterbox/faq.html#otherDevices \n\n")) + + if let keyAttachment = MCOAttachment.init(text: key){ + builder.addAttachment(keyAttachment) + } + + // See: https://autocrypt.org/level1.html#autocrypt-setup-message + let filename = keyID+".asc.asc" + if let keyAttachment = MCOAttachment.init(contentsOfFile: filename){ + keyAttachment.mimeType = "application/autocrypt-setup" + keyAttachment.setContentTypeParameterValue("UTF-8", forName: "charset") + keyAttachment.setContentTypeParameterValue(filename, forName: "name") + keyAttachment.filename = filename + keyAttachment.data = key.data(using: .utf8) + + builder.addAttachment(keyAttachment) + + } + } + +} diff --git a/enzevalos_iphone/Base.lproj/InboxTableViewCell.xib b/enzevalos_iphone/Base.lproj/InboxTableViewCell.xib index 3961edca658762aec6f2e1dfdc2271a05049b35b..56e4a4b31a221d5b0d35aaa1595c0f1e9c525130 100644 --- a/enzevalos_iphone/Base.lproj/InboxTableViewCell.xib +++ b/enzevalos_iphone/Base.lproj/InboxTableViewCell.xib @@ -1,11 +1,12 @@ <?xml version="1.0" encoding="UTF-8"?> -<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13196" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES"> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES"> <device id="retina4_7" orientation="portrait"> <adaptation id="fullscreen"/> </device> <dependencies> <deployment identifier="iOS"/> - <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13174"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/> + <capability name="Alignment constraints with different attributes" minToolsVersion="5.1"/> <capability name="Constraints to layout margins" minToolsVersion="6.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> </dependencies> @@ -20,9 +21,9 @@ <autoresizingMask key="autoresizingMask"/> <subviews> <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Klo-Po-J7v" userLabel="Contact Button"> - <rect key="frame" x="8" y="8" width="88" height="113"/> + <rect key="frame" x="12" y="11" width="64" height="113"/> <constraints> - <constraint firstAttribute="width" constant="88" id="WoA-3H-azl"/> + <constraint firstAttribute="width" constant="64" id="WoA-3H-azl"/> <constraint firstAttribute="height" constant="113" id="g0g-9z-hfC"/> </constraints> <connections> @@ -30,34 +31,34 @@ </connections> </button> <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="WNp-Ty-Hv1"> - <rect key="frame" x="16" y="16" width="70" height="70"/> + <rect key="frame" x="20" y="27" width="50" height="50"/> <constraints> - <constraint firstAttribute="height" constant="70" id="Bei-PK-STi"/> - <constraint firstAttribute="width" constant="70" id="Tid-sz-S35"/> + <constraint firstAttribute="height" constant="50" id="Bei-PK-STi"/> + <constraint firstAttribute="width" constant="50" id="Tid-sz-S35"/> </constraints> </imageView> <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="uDO-9h-a86" userLabel="Icon View"> - <rect key="frame" x="64" y="8" width="30" height="30"/> + <rect key="frame" x="54" y="19" width="20" height="20"/> <constraints> - <constraint firstAttribute="width" constant="30" id="Zf5-eH-DtF"/> - <constraint firstAttribute="height" constant="30" id="n7I-Eu-a0k"/> + <constraint firstAttribute="width" constant="20" id="Zf5-eH-DtF"/> + <constraint firstAttribute="height" constant="20" id="n7I-Eu-a0k"/> </constraints> </imageView> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Name" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsLetterSpacingToFitWidth="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ixt-EX-9TM"> - <rect key="frame" x="8" y="90" width="86" height="32"/> + <rect key="frame" x="20" y="87" width="50" height="32"/> <constraints> <constraint firstAttribute="height" constant="32" id="r0W-bg-uj9"/> </constraints> - <fontDescription key="fontDescription" type="system" pointSize="17"/> + <fontDescription key="fontDescription" type="system" pointSize="16"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <nil key="highlightedColor"/> </label> <button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="249" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fkg-yw-zDk" userLabel="More Button"> - <rect key="frame" x="104" y="94" width="288" height="28"/> + <rect key="frame" x="80" y="92" width="300" height="27"/> <constraints> <constraint firstAttribute="height" priority="250" constant="38" id="PkY-uX-CRO"/> </constraints> - <fontDescription key="fontDescription" type="system" pointSize="13"/> + <fontDescription key="fontDescription" type="system" pointSize="12"/> <state key="normal" title="Alle E-Mails von diesem Kontakt"> <color key="titleColor" red="0.43529411759999997" green="0.4431372549" blue="0.47450980390000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> </state> @@ -66,64 +67,64 @@ </connections> </button> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="KQh-Jo-J47" userLabel="Seperator"> - <rect key="frame" x="102" y="87" width="298" height="0.0"/> + <rect key="frame" x="84" y="87" width="304" height="0.0"/> <color key="backgroundColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <constraints> <constraint firstAttribute="height" constant="0.5" id="iGw-4L-rQm"/> </constraints> </view> <button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="249" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="d9Z-AX-rvb" userLabel="Second Row"> - <rect key="frame" x="98" y="46" width="302" height="41"/> + <rect key="frame" x="80" y="47.5" width="308" height="39.5"/> <connections> <action selector="secondButtonPressed:" destination="CFu-ns-kay" eventType="touchUpInside" id="bkj-Q4-ZwY"/> </connections> </button> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="252" horizontalCompressionResistancePriority="751" verticalCompressionResistancePriority="751" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="p7w-rZ-MsF"> - <rect key="frame" x="392" y="76" width="0.0" height="0.0"/> - <fontDescription key="fontDescription" type="system" pointSize="15"/> + <rect key="frame" x="380" y="76" width="0.0" height="0.0"/> + <fontDescription key="fontDescription" type="system" pointSize="12"/> <color key="textColor" red="0.43529411759999997" green="0.4431372549" blue="0.47450980390000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <nil key="highlightedColor"/> </label> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalCompressionResistancePriority="749" verticalCompressionResistancePriority="749" text="Keine weiteren Nachrichten..." textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5es-fE-2Ig"> - <rect key="frame" x="110" y="60" width="274" height="16"/> - <fontDescription key="fontDescription" type="system" pointSize="13"/> + <rect key="frame" x="92" y="61.5" width="280" height="14.5"/> + <fontDescription key="fontDescription" type="system" pointSize="12"/> <color key="textColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <nil key="highlightedColor"/> </label> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="aNQ-sk-gux"> - <rect key="frame" x="102" y="56" width="0.0" height="21"/> + <rect key="frame" x="84" y="57.5" width="0.0" height="19.5"/> <fontDescription key="fontDescription" type="system" pointSize="17"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <nil key="highlightedColor"/> </label> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="6Ac-fp-DaH" userLabel="Seperator"> - <rect key="frame" x="102" y="45" width="298" height="1"/> + <rect key="frame" x="84" y="46.5" width="304" height="1"/> <color key="backgroundColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <constraints> <constraint firstAttribute="height" constant="0.5" id="4mk-1j-mQw"/> </constraints> </view> <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Woe-Z6-TzX" userLabel="First Row"> - <rect key="frame" x="98" y="0.0" width="302" height="45"/> + <rect key="frame" x="80" y="3" width="308" height="43.5"/> <connections> <action selector="firstButtonPressed:" destination="CFu-ns-kay" eventType="touchUpInside" id="YFb-kT-nNt"/> </connections> </button> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="252" verticalHuggingPriority="252" horizontalCompressionResistancePriority="751" verticalCompressionResistancePriority="751" text="Datum" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Nu7-tF-hGe"> - <rect key="frame" x="346" y="16" width="46" height="18"/> - <fontDescription key="fontDescription" type="system" pointSize="15"/> + <rect key="frame" x="342.5" y="21" width="37.5" height="14.5"/> + <fontDescription key="fontDescription" type="system" pointSize="12"/> <color key="textColor" red="0.43529411759999997" green="0.4431372549" blue="0.47450980390000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <nil key="highlightedColor"/> </label> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalCompressionResistancePriority="749" verticalCompressionResistancePriority="749" text="Nachricht" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TqY-sR-0LV"> - <rect key="frame" x="163" y="18" width="175" height="16"/> - <fontDescription key="fontDescription" type="system" pointSize="13"/> + <rect key="frame" x="142" y="21" width="192.5" height="14.5"/> + <fontDescription key="fontDescription" type="system" pointSize="12"/> <color key="textColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <nil key="highlightedColor"/> </label> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Betreff" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XJ6-AX-Txg"> - <rect key="frame" x="102" y="14" width="53" height="21"/> - <fontDescription key="fontDescription" type="system" pointSize="17"/> + <rect key="frame" x="84" y="17" width="50" height="19.5"/> + <fontDescription key="fontDescription" type="system" pointSize="16"/> <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <nil key="highlightedColor"/> </label> @@ -138,24 +139,24 @@ <constraint firstItem="KQh-Jo-J47" firstAttribute="top" secondItem="aNQ-sk-gux" secondAttribute="bottom" constant="8" id="5Xa-ur-flk"/> <constraint firstItem="6Ac-fp-DaH" firstAttribute="top" secondItem="XJ6-AX-Txg" secondAttribute="bottom" constant="10" id="7Jc-Fa-yCt"/> <constraint firstItem="6Ac-fp-DaH" firstAttribute="leading" secondItem="KQh-Jo-J47" secondAttribute="leading" id="8Bu-SI-3wf"/> - <constraint firstAttribute="leadingMargin" secondItem="WNp-Ty-Hv1" secondAttribute="leading" constant="-8" id="8Qz-qU-0pQ"/> + <constraint firstAttribute="leadingMargin" secondItem="WNp-Ty-Hv1" secondAttribute="leading" id="8Qz-qU-0pQ"/> <constraint firstItem="5es-fE-2Ig" firstAttribute="centerX" secondItem="6Ac-fp-DaH" secondAttribute="centerX" id="9S7-qb-FGm"/> <constraint firstItem="Nu7-tF-hGe" firstAttribute="centerY" secondItem="XJ6-AX-Txg" secondAttribute="centerY" id="9xe-VP-4Ml"/> <constraint firstItem="ixt-EX-9TM" firstAttribute="top" secondItem="aNQ-sk-gux" secondAttribute="bottom" constant="17" id="AhO-j2-beE"/> <constraint firstItem="ixt-EX-9TM" firstAttribute="centerX" secondItem="WNp-Ty-Hv1" secondAttribute="centerX" priority="750" id="AoH-YY-Rat"/> <constraint firstAttribute="trailingMargin" secondItem="fkg-yw-zDk" secondAttribute="trailing" id="BTc-bK-iUs"/> <constraint firstAttribute="trailingMargin" secondItem="KQh-Jo-J47" secondAttribute="trailing" constant="-8" id="CUy-27-K5C"/> - <constraint firstAttribute="leadingMargin" secondItem="Klo-Po-J7v" secondAttribute="leading" id="DAX-Jt-Jy0"/> - <constraint firstItem="uDO-9h-a86" firstAttribute="leading" secondItem="WNp-Ty-Hv1" secondAttribute="trailing" constant="-22" id="Ep6-8a-mxu"/> + <constraint firstItem="WNp-Ty-Hv1" firstAttribute="leadingMargin" secondItem="Klo-Po-J7v" secondAttribute="leading" constant="16" id="DAX-Jt-Jy0"/> + <constraint firstItem="uDO-9h-a86" firstAttribute="leading" secondItem="WNp-Ty-Hv1" secondAttribute="trailing" constant="-16" id="Ep6-8a-mxu"/> <constraint firstAttribute="bottomMargin" secondItem="ixt-EX-9TM" secondAttribute="bottom" id="HJW-m3-xQf"/> <constraint firstAttribute="trailingMargin" secondItem="Nu7-tF-hGe" secondAttribute="trailing" id="Iun-11-1dU"/> - <constraint firstItem="6Ac-fp-DaH" firstAttribute="leading" secondItem="iQP-01-jFC" secondAttribute="leadingMargin" constant="94" id="JmJ-3n-YQE"/> + <constraint firstItem="6Ac-fp-DaH" firstAttribute="leading" secondItem="iQP-01-jFC" secondAttribute="leadingMargin" constant="64" id="JmJ-3n-YQE"/> <constraint firstItem="6Ac-fp-DaH" firstAttribute="leading" secondItem="XJ6-AX-Txg" secondAttribute="leading" id="K4E-pM-i1g"/> <constraint firstAttribute="topMargin" secondItem="Woe-Z6-TzX" secondAttribute="top" constant="8" id="M24-q2-8rU"/> <constraint firstItem="5es-fE-2Ig" firstAttribute="baseline" secondItem="aNQ-sk-gux" secondAttribute="baseline" priority="996" id="MIK-Lm-sHl"/> <constraint firstAttribute="trailingMargin" secondItem="p7w-rZ-MsF" secondAttribute="trailing" id="MU1-O9-owp"/> <constraint firstItem="p7w-rZ-MsF" firstAttribute="baseline" secondItem="aNQ-sk-gux" secondAttribute="baseline" id="PnO-9W-e9y"/> - <constraint firstAttribute="topMargin" secondItem="WNp-Ty-Hv1" secondAttribute="top" constant="-8" id="Ssn-ty-fGT"/> + <constraint firstAttribute="topMargin" secondItem="WNp-Ty-Hv1" secondAttribute="top" constant="-16" id="Ssn-ty-fGT"/> <constraint firstItem="fkg-yw-zDk" firstAttribute="top" secondItem="KQh-Jo-J47" secondAttribute="bottom" priority="750" id="Uja-D9-x7G"/> <constraint firstAttribute="trailingMargin" secondItem="d9Z-AX-rvb" secondAttribute="trailing" constant="-8" id="Wi7-cb-bZM"/> <constraint firstAttribute="bottomMargin" secondItem="fkg-yw-zDk" secondAttribute="bottom" priority="750" id="Wpi-eN-8Jj"/> @@ -187,9 +188,9 @@ </constraints> <variation key="default"> <mask key="constraints"> - <exclude reference="AhO-j2-beE"/> <exclude reference="1Xo-Rd-5M9"/> <exclude reference="4uw-Gk-HBI"/> + <exclude reference="AhO-j2-beE"/> <exclude reference="ide-90-fIG"/> <exclude reference="oKz-Cf-6UQ"/> <exclude reference="vYu-LF-pbM"/> diff --git a/enzevalos_iphone/Base.lproj/Main.storyboard b/enzevalos_iphone/Base.lproj/Main.storyboard index f669bd27b7804c5510a3990c36bc9d833dcc60fb..b80f6830e80e75d043f5422aaad2621752ece458 100644 --- a/enzevalos_iphone/Base.lproj/Main.storyboard +++ b/enzevalos_iphone/Base.lproj/Main.storyboard @@ -32,14 +32,15 @@ <autoresizingMask key="autoresizingMask"/> <subviews> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="zNO-Uq-ewV" customClass="VENTokenField"> - <rect key="frame" x="0.0" y="0.0" width="258" height="44"/> + <rect key="frame" x="0.0" y="0.0" width="200" height="44"/> <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <constraints> <constraint firstAttribute="height" constant="44" id="T2D-H0-pg7"/> + <constraint firstAttribute="width" constant="200" id="cHW-uV-4Zo"/> </constraints> </view> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="EB5-Z7-WoN"> - <rect key="frame" x="266" y="13" width="38" height="18"/> + <rect key="frame" x="208" y="13" width="96" height="18"/> <fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/> <color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/> <nil key="highlightedColor"/> @@ -54,9 +55,6 @@ </constraints> <edgeInsets key="layoutMargins" top="20" left="8" bottom="8" right="8"/> </tableViewCellContentView> - <accessibility key="accessibilityConfiguration"> - <accessibilityTraits key="traits" notEnabled="YES"/> - </accessibility> </tableViewCell> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="ZjK-3s-N2G"> <rect key="frame" x="0.0" y="79" width="320" height="44"/> @@ -1019,7 +1017,7 @@ <autoresizingMask key="autoresizingMask"/> <subviews> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="VTZ-4w-fot"> - <rect key="frame" x="15" y="0.0" width="270" height="43.5"/> + <rect key="frame" x="16" y="0.0" width="269" height="43.5"/> <autoresizingMask key="autoresizingMask"/> <fontDescription key="fontDescription" type="system" pointSize="17"/> <nil key="textColor"/> @@ -1858,10 +1856,16 @@ Um deine sicheren E-Mails auch auf einem anderen Gerät lesen zu können, muss d </scene> </scenes> <inferredMetricsTieBreakers> +<!--<<<<<<< HEAD--> <segue reference="hd4-SZ-DZ0"/> <segue reference="hSn-Um-hji"/> <segue reference="DcR-GX-scc"/> +<!--=======--> + <segue reference="rhW-cI-4c4"/> + <segue reference="hSn-Um-hji"/> + <segue reference="btx-4o-o0r"/> +<!-->>>>>>> master--> <segue reference="TgN-rB-esa"/> - <segue reference="6Ug-AV-lba"/> + <segue reference="ecN-Wn-7S0"/> </inferredMetricsTieBreakers> </document> diff --git a/enzevalos_iphone/ContactViewController.swift b/enzevalos_iphone/ContactViewController.swift index 71a723294c5bd344794125c7d9388e1706c94aab..ddd6b3663998d5e227d23bd4101274b139a9ff89 100644 --- a/enzevalos_iphone/ContactViewController.swift +++ b/enzevalos_iphone/ContactViewController.swift @@ -156,11 +156,11 @@ class ContactViewController: UIViewController { let frame = CGRect(x: myBounds.size.width / 2 - iconSize / 2, y: myBounds.size.height / 2 - iconSize / 2, width: iconSize, height: iconSize) if keyRecord.hasKey { - IconsStyleKit.drawLetter(frame: frame, fillBackground: true) + StudySettings.securityIndicator.drawOfSecureIndictor(frame: frame, fillbackground: true, open: false) } else if keyRecord.isVerified { - IconsStyleKit.drawLetter(frame: frame, color: UIColor.white) + StudySettings.securityIndicator.drawOfSecureIndictor(frame: frame, color: UIColor.white, fillbackground: true, open: false) } else { - IconsStyleKit.drawPostcard(frame: frame, resizing: .aspectFit, color: UIColor.white) + StudySettings.securityIndicator.drawOfInSecureIndictor(frame: frame, color: UIColor.white, open: false) } let img = UIGraphicsGetImageFromCurrentImageContext(); @@ -390,10 +390,10 @@ extension ContactViewController: UITableViewDataSource { dateFormatter.locale = Locale.current dateFormatter.dateStyle = .medium cell.dateLabel.text = dateFormatter.string(from: time as Date) - cell.iconImage.image = IconsStyleKit.imageOfLetter + cell.iconImage.image = StudySettings.securityIndicator.imageOfSecureIndicator(open: false) } else { cell.dateLabel.text = "" - cell.iconImage.image = IconsStyleKit.imageOfPostcard + cell.iconImage.image = StudySettings.securityIndicator.imageOfInsecureIndicator() } cell.label.text = r[indexPath.row].addresses.first?.mailAddress } @@ -410,11 +410,11 @@ extension ContactViewController: UITableViewDataSource { dateFormatter.locale = Locale.current dateFormatter.dateStyle = .medium cell.dateLabel.text = dateFormatter.string(from: time as Date) - cell.iconImage.image = IconsStyleKit.imageOfLetter + cell.iconImage.image = StudySettings.securityIndicator.imageOfSecureIndicator() //TODO: add insecure travel keyRecord here } else { cell.dateLabel.text = "" - cell.iconImage.image = IconsStyleKit.imageOfPostcard + cell.iconImage.image = StudySettings.securityIndicator.imageOfInsecureIndicator() } cell.label.text = r[indexPath.row].addresses.first?.mailAddress } diff --git a/enzevalos_iphone/CryptoObject.swift b/enzevalos_iphone/CryptoObject.swift index 09e18e21413bf5041f679f32ebcd4a487b4ce2bf..ebc237dc43a4466aa00b6c7335db5f535c7885df 100644 --- a/enzevalos_iphone/CryptoObject.swift +++ b/enzevalos_iphone/CryptoObject.swift @@ -7,7 +7,8 @@ // import Foundation -enum SignatureState: Int16 { + +/* enum SignatureState: Int16 { case NoSignature = 0 case NoPublicKey = -1 case InvalidSignature = -2 @@ -19,6 +20,20 @@ enum EncryptionState: Int16 { case UnableToDecrypt = -1 case ValidEncryptedWithOldKey = 1 case ValidedEncryptedWithCurrentKey = 2 +} */ + +enum SignatureState: Int16 { + case NoSignature = 0 + case NoPublicKey = 1 + case InvalidSignature = -1 + case ValidSignature = 2 +} + +enum EncryptionState: Int16 { + case NoEncryption = 0 + case UnableToDecrypt = 1 + case ValidEncryptedWithOldKey = 2 + case ValidedEncryptedWithCurrentKey = 3 } public enum CryptoScheme { @@ -69,6 +84,13 @@ public class CryptoObject { } return nil } + + var chiperString: String? { + if let data = chiphertext { + return String.init(data: data, encoding: .utf8) + } + return nil + } init(chiphertext: Data?, plaintext: String?, decryptedData: Data?, sigState: SignatureState, encState: EncryptionState, signKey: String?, encType: CryptoScheme, signedAdrs: [String]) { @@ -82,8 +104,4 @@ public class CryptoObject { self.passcode = nil self.signedAdrs = signedAdrs } - - - - } diff --git a/enzevalos_iphone/Cryptography.swift b/enzevalos_iphone/Cryptography.swift index 8d116c0c60454773117c8d199f97f33499a7b5f9..38038b60be0b84ae142cf2e125287249e1271ba6 100644 --- a/enzevalos_iphone/Cryptography.swift +++ b/enzevalos_iphone/Cryptography.swift @@ -20,7 +20,7 @@ public protocol Encryption { func deleteSecretKeys() // operations on keys - func encrypt(plaintext: String, ids: [String], myId: String) -> CryptoObject - func decrypt(data: Data, decryptionIDs: [String], verifyIds: [String], fromAdr: String?) -> CryptoObject + func encrypt(plaintext: String, ids: [String], myId: String, encryptForMyID: Bool) -> CryptoObject + func decrypt(data: Data, attachedSignature: Data?, decKeyIDs: [String], signatureIDs: [String], fromAddr: String) -> CryptoObject } diff --git a/enzevalos_iphone/DataHandler.swift b/enzevalos_iphone/DataHandler.swift index 0e5f85e983f0f70db491dc1728c968bf093aa010..188cd1056eb09a449287597cd1f8575209ac7004 100644 --- a/enzevalos_iphone/DataHandler.swift +++ b/enzevalos_iphone/DataHandler.swift @@ -59,9 +59,38 @@ typealias requestTuple = (request: String, value: Any) class DataHandler { static let handler: DataHandler = DataHandler() - private var managedObjectContext: NSManagedObjectContext - private let MaxRecords = 50 - private let MaxMailsPerRecord = 100 + private var mainMOC: NSManagedObjectContext + private var backMOC: NSManagedObjectContext + private var managedObjectContext: NSManagedObjectContext { + get { + if Thread.current.isMainThread { + return mainMOC + } + else { + return backMOC + } + } + } + + public let outgoingFolder = "OutgoingMails" + + func addOutgoingMail(mail: OutgoingMail) { + let outgoingFolder = findFolder(with: self.outgoingFolder) + let isOnlyMail = outgoingFolder.counterMails == 0 + _ = mail.store() + if isOnlyMail { + mail.send(informUser: true) + } + } + + func startToSendMore(){ + let outgoingFolder = findFolder(with: self.outgoingFolder) + if outgoingFolder.counterMails == 0 { + return + } + let m = OutgoingMail(mail: outgoingFolder.mailsOfFolder[0]) + m.send() + } var allFolders: [Folder] { get { @@ -89,7 +118,6 @@ class DataHandler { func callForFolders(done: @escaping ((_ error: Error?) -> ())) { // Maybe call back? Look for new Folder? AppDelegate.getAppDelegate().mailHandler.allFolders { (err, array) -> Void in guard err == nil else { - print("Error while fetching all folders: \(String(describing: err))") done(err) return } @@ -166,8 +194,8 @@ class DataHandler { fatalError("Error initializing mom from: \(modelURL)") } let psc = NSPersistentStoreCoordinator(managedObjectModel: mom) - self.managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType) // This is why we have trouble with concurrency: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreData/Concurrency.html - self.managedObjectContext.persistentStoreCoordinator = psc + self.mainMOC = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType) // This is why we have trouble with concurrency: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreData/Concurrency.html + self.mainMOC.persistentStoreCoordinator = psc let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) let docURL = urls[urls.endIndex - 1] @@ -182,7 +210,9 @@ class DataHandler { } catch { fatalError("Error migrating store: \(error)") } - managedObjectContext.mergePolicy = NSMergePolicy(merge: NSMergePolicyType.mergeByPropertyObjectTrumpMergePolicyType); + mainMOC.mergePolicy = NSMergePolicy(merge: NSMergePolicyType.mergeByPropertyObjectTrumpMergePolicyType); + backMOC = NSManagedObjectContext.init(concurrencyType: .privateQueueConcurrencyType) + backMOC.parent = mainMOC callForFolders(done: { _ in return }) @@ -197,6 +227,7 @@ class DataHandler { try managedObjectContext.save() } catch { print("Error during saving while: \(during)") + NSLog("Error during saving while %s", during) } } @@ -220,6 +251,12 @@ class DataHandler { self.managedObjectContext.delete(key as NSManagedObject) save(during: "delete SecretKey") } + + func delete(mail: OutgoingMail) { + if let m = mail.store() { + delete(mail: m) + } + } func deleteSecretKeys() { let keys = findSecretKeys() @@ -266,7 +303,7 @@ class DataHandler { // Save, load, search - func newSecretKey(keyID: String, addPk: Bool) -> SecretKey { + func newSecretKey(keyID: String, addPk: Bool, saveKey: Bool = true) -> SecretKey { let sk: SecretKey if let key = findSecretKey(keyID: keyID) { sk = key @@ -283,7 +320,9 @@ class DataHandler { _ = newPublicKey(keyID: keyID, cryptoType: CryptoScheme.PGP, adr: adr, autocrypt: false) } } - save(during: "new sk") + if saveKey { + save(during: "new sk") + } return sk } @@ -308,7 +347,7 @@ class DataHandler { return sk } - func newPublicKey(keyID: String, cryptoType: CryptoScheme, adr: String, autocrypt: Bool, firstMail: PersistentMail? = nil, newGenerated: Bool = false) -> PersistentKey { + func newPublicKey(keyID: String, cryptoType: CryptoScheme, adr: String, autocrypt: Bool, firstMail: PersistentMail? = nil, newGenerated: Bool = false, saveKey: Bool = true) -> PersistentKey { var date = Date.init() if let mail = firstMail { if date.compare(mail.date).rawValue > 0 { @@ -374,7 +413,9 @@ class DataHandler { found = true } } - save(during: "new pk") + if saveKey{ + save(during: "new pk") + } if Logger.logging { var importChannel = "autocrypt" if newGenerated { @@ -536,7 +577,7 @@ class DataHandler { return false } - func getKeyRecord(addr: String, keyID: String?) -> KeyRecord { + func getKeyRecord(addr: String, keyID: String?, saveRecord: Bool = true) -> KeyRecord { if let id = keyID { if let key = findKey(keyID: id) { if let record = key.keyRecord { @@ -551,7 +592,9 @@ class DataHandler { else { record.contact = getContactByAddress(addr) } - save(during: "create keyRecord with key") + if saveRecord { + save(during: "create keyRecord with key") + } return record } } @@ -572,7 +615,9 @@ class DataHandler { // create KeyRecord let record = NSEntityDescription.insertNewObject(forEntityName: "KeyRecord", into: managedObjectContext) as! KeyRecord record.contact = getContactByAddress(addr) - save(during: "create keyRecord without key") + if saveRecord { + save(during: "create keyRecord without key") + } return record } @@ -707,7 +752,7 @@ class DataHandler { // -------- Start handle to, cc, from addresses -------- - private func handleFromAddress(_ sender: MCOAddress, fromMail: PersistentMail, autocrypt: AutocryptContact?) { + private func handleFromAddress(_ sender: MCOAddress, fromMail: PersistentMail, autocrypt: Autocrypt?) { let adr: Mail_Address adr = getMailAddressByMCOAddress(sender, temporary: false) as! Mail_Address if adr.contact == nil { @@ -739,7 +784,7 @@ class DataHandler { } // -------- End handle to, cc, from addresses -------- - func createMail(_ uid: UInt64, sender: MCOAddress?, receivers: [MCOAddress], cc: [MCOAddress], time: Date, received: Bool, subject: String, body: String?, readableAttachments: Set<TempAttachment> = Set<TempAttachment>(), flags: MCOMessageFlag, record: KeyRecord?, autocrypt: AutocryptContact?, decryptedData: CryptoObject?, folderPath: String, secretKey: String?, references: [String] = [], mailagent: String? = nil, messageID: String? = nil, encryptedBody: String?, storeEncrypted: Bool = false) -> PersistentMail? { + func createMail(_ uid: UInt64, sender: MCOAddress?, receivers: [MCOAddress], cc: [MCOAddress], time: Date, received: Bool, subject: String, body: String?, readableAttachments: Set<TempAttachment> = Set<TempAttachment>(), flags: MCOMessageFlag, record: KeyRecord?, autocrypt: Autocrypt?, decryptedData: CryptoObject?, folderPath: String, secretKey: String?, references: [String] = [], mailagent: String? = nil, messageID: String? = nil, encryptedBody: String?, storeEncrypted: Bool = false) -> PersistentMail? { let myfolder = findFolder(with: folderPath) as Folder let finding = findNum("PersistentMail", type: "uid", search: uid) @@ -750,7 +795,7 @@ class DataHandler { mails = tmpMails } - if finding == nil || finding!.count == 0 || mails.filter({ $0.folder.path == folderPath && $0.uidvalidity == myfolder.uidvalidity }).count == 0 { + if finding == nil || finding!.count == 0 || mails.filter({ $0.folder.path == folderPath && $0.uidvalidity == myfolder.uidvalidity }).count == 0 || uid == 0{ // create new mail object mail = NSEntityDescription.insertNewObject(forEntityName: "PersistentMail", into: managedObjectContext) as! PersistentMail @@ -761,7 +806,7 @@ class DataHandler { mail.date = now } mail.subject = subject - if !storeEncrypted { + if !storeEncrypted, let body = body { mail.body = body } else { mail.body = nil @@ -869,7 +914,7 @@ class DataHandler { } } else { - mail.signedKey = newPublicKey(keyID: decData.signKey!, cryptoType: decData.encType, adr: decData.signedAdrs.first!, autocrypt: false, firstMail: mail, newGenerated: false) + mail.signedKey = newPublicKey(keyID: decData.signKey!, cryptoType: decData.encType, adr: decData.signedAdrs.first!, autocrypt: false, firstMail: mail, newGenerated: false, saveKey: false) } } @@ -887,9 +932,9 @@ class DataHandler { if mail.uid > myfolder.maxID { myfolder.maxID = mail.uid } - var record = getKeyRecord(addr: mail.from.mailAddress, keyID: nil) - if let signedID = mail.signedKey?.keyID { - record = getKeyRecord(addr: mail.from.mailAddress, keyID: signedID) + var record = getKeyRecord(addr: mail.from.mailAddress, keyID: nil, saveRecord: false) + if let signedID = mail.signedKey?.keyID, mail.isSecure { + record = getKeyRecord(addr: mail.from.mailAddress, keyID: signedID, saveRecord: false) } record.addToPersistentMails(mail) mail.folder.addToKeyRecords(record) diff --git a/enzevalos_iphone/Dialog/DialogOption.swift b/enzevalos_iphone/Dialog/DialogOption.swift index df4c9b4a8cbfa5370206172d9b5ff8f2012a670d..fd14977ce38f4a13b1269515c293223585b843b0 100644 --- a/enzevalos_iphone/Dialog/DialogOption.swift +++ b/enzevalos_iphone/Dialog/DialogOption.swift @@ -46,7 +46,7 @@ enum DialogOption { case .invitationCode : return nil case .invitationWelcome, .invitationHelp : switch StudySettings.invitationsmode { - case InvitationMode.Censorship: + case .Censorship: var images = [UIImage]() if let sender = UIImage(named: "bg_inviation_censor_sender"), let receiver = UIImage(named: "bg_inviation_censor_receiver") { images.append(sender) @@ -99,12 +99,12 @@ enum DialogOption { case .PasswordEnc : return NSLocalizedString("Invitation.Welcome.Message", comment: "") } case .invitationStep : - if StudySettings.invitationsmode == InvitationMode.Censorship{ + if StudySettings.invitationsmode == Inviation.Censorship{ return NSLocalizedString("Invitation.Step.Message.Censor", comment: "") } return NSLocalizedString("Invitation.Step.Message", comment: "") case .invitationCode(let code) : - if StudySettings.invitationsmode == InvitationMode.Censorship{ + if StudySettings.invitationsmode == Inviation.Censorship{ return "" } return String(format: NSLocalizedString("Invitation.Code.Message", comment: ""), code) diff --git a/enzevalos_iphone/EphemeralMail.swift b/enzevalos_iphone/EphemeralMail.swift index 568e391fa87d104399684675c8267f86c9b94883..6db9848cdf70ead045cc5dcb32f31820464a87a5 100644 --- a/enzevalos_iphone/EphemeralMail.swift +++ b/enzevalos_iphone/EphemeralMail.swift @@ -35,7 +35,12 @@ open class EphemeralMail: Mail { self.cc = cc self.bcc = bcc self.to = to - self.body = body + if let body = body { + self.body = body + } + else { + self.body = "" + } self.date = date self.subject = subject self.uid = uid diff --git a/enzevalos_iphone/ExportViewController.swift b/enzevalos_iphone/ExportViewController.swift index 89b0192df75325ecaa4f9bc53d14306e398744f7..9c26281b29d8d84a475fb92c7ec64b5ffc59861d 100644 --- a/enzevalos_iphone/ExportViewController.swift +++ b/enzevalos_iphone/ExportViewController.swift @@ -52,27 +52,22 @@ class ExportViewController: UITableViewController { // } let handler = DataHandler.handler - let ids = handler.findSecretKeys() - if ids.count > 0 { - let id = ids[0] - let pgp = SwiftPGP() - if let keyId = id.keyID { - if alreadySent { - if let message = pgp.exportKey(id: keyId, isSecretkey: true, autocrypt: true, newPasscode: true) { - passcode = pgp.loadExportPasscode(id: keyId)! - let mailHandler = AppDelegate.getAppDelegate().mailHandler - mailHandler.sendSecretKey(keyID: keyId, key: message, passcode: passcode, callback: mailSend) - } - } else { - if let message = pgp.exportKey(id: keyId, isSecretkey: true, autocrypt: true, newPasscode: false) { - passcode = pgp.loadExportPasscode(id: keyId)! - let mailHandler = AppDelegate.getAppDelegate().mailHandler - mailHandler.sendSecretKey(keyID: keyId, key: message, passcode: passcode, callback: mailSend) - } - alreadySent = true + let sk = handler.prefSecretKey() //handler.findSecretKeys() + let pgp = SwiftPGP() + if let sk = sk, let keyId = sk.keyID { + if alreadySent { + if let message = pgp.exportKey(id: keyId, isSecretkey: true, autocrypt: true, newPasscode: true) { + passcode = pgp.loadExportPasscode(id: keyId)! + let mailHandler = AppDelegate.getAppDelegate().mailHandler + mailHandler.sendSecretKey(keyID: keyId, key: message, callback: mailSend) + } + } else { + if let message = pgp.exportKey(id: keyId, isSecretkey: true, autocrypt: true, newPasscode: false) { + passcode = pgp.loadExportPasscode(id: keyId)! + let mailHandler = AppDelegate.getAppDelegate().mailHandler + mailHandler.sendSecretKey(keyID: keyId, key: message, callback: mailSend) } - //TODO: remove - //AppDelegate.getAppDelegate().mailHandler.send(["recipient@spamless.me"], ccEntrys: [], bccEntrys: [], subject: "passcode", message: passcode, sendEncryptedIfPossible: false, callback: {_ in }, loggingMail: false, htmlContent: nil, warningReact: false, inviteMail: false, textparts: 1) + alreadySent = true } } else { diff --git a/enzevalos_iphone/FolderViewController.swift b/enzevalos_iphone/FolderViewController.swift index 145cec858ff8821c669c3265ca2d299a1e02f3d6..5dfb6a2ba79dea4bba0627460cb17da1ccd5dbce 100644 --- a/enzevalos_iphone/FolderViewController.swift +++ b/enzevalos_iphone/FolderViewController.swift @@ -130,11 +130,11 @@ class FolderViewController: UITableViewController { cell.date.text = mail.timeString if mail.isSecure { - cell.secureImageView.image = IconsStyleKit.imageOfLetter + cell.secureImageView.image = StudySettings.securityIndicator.imageOfSecureIndicator() } else if mail.trouble { - cell.secureImageView.image = IconsStyleKit.imageOfLetterCorrupted + cell.secureImageView.image = StudySettings.securityIndicator.imageOfCorruptedIndicator() } else { - cell.secureImageView.image = IconsStyleKit.imageOfPostcard + cell.secureImageView.image = StudySettings.securityIndicator.imageOfInsecureIndicator() } if !mail.isRead { cell.markImageView.image = "🔵".image() diff --git a/enzevalos_iphone/GamificationStatusViewController.swift b/enzevalos_iphone/GamificationStatusViewController.swift index 396cb5cfe07e4c18337a82b5d95fda2ad20fecff..1d9eb657359efa4b559fb19af0e3dfd4daad0271 100755 --- a/enzevalos_iphone/GamificationStatusViewController.swift +++ b/enzevalos_iphone/GamificationStatusViewController.swift @@ -210,16 +210,13 @@ class GamificationStatusViewController: UIViewController, UITableViewDelegate, U // In a storyboard-based application, you will often want to do a little preparation before navigation override func prepare(for segue: UIStoryboardSegue, sender: Any?) { guard let identifier = segue.identifier else { - print("Identifier Failure") return } guard let badge = self.selected else { - print("Non achieved Selected, proceeding with no Selection") return } if identifier == "badge" { guard let destination = segue.destination as? BadgeCase else { - print("BadgeCase Failure (in: gamificationStatusView)") return } destination.selected = badge diff --git a/enzevalos_iphone/HideShowPasswordTextField.swift b/enzevalos_iphone/HideShowPasswordTextField.swift new file mode 100644 index 0000000000000000000000000000000000000000..3864480b04bd5c4704483a08a269aedbb4bf2740 --- /dev/null +++ b/enzevalos_iphone/HideShowPasswordTextField.swift @@ -0,0 +1,135 @@ +// +// HideShowPasswordTextField.swift +// Guidebook +// +// Created by Mike Sprague on 4/15/16. +// See: https://github.com/Guidebook/HideShowPasswordTextField +// +// + +import Foundation +import UIKit + +protocol HideShowPasswordTextFieldDelegate: class { + func isValidPassword(password: String) -> Bool +} + +class HideShowPasswordTextField: UITextField { + + weak var passwordDelegate: HideShowPasswordTextFieldDelegate? + var preferredFont: UIFont? { + didSet { + self.font = preferredFont + + if self.isSecureTextEntry { + self.font = nil + } + } + } + + override var isSecureTextEntry: Bool { + didSet { + if !isSecureTextEntry { + self.font = nil + self.font = preferredFont + } + if isSecureTextEntry { + passwordToggleVisibilityView.eyeState = .closed + } + } + } + private var passwordToggleVisibilityView: PasswordToggleVisibilityView! + + override init(frame: CGRect) { + super.init(frame: frame) + super.isSecureTextEntry = true + setupViews() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + setupViews() + } + + override func awakeFromNib() { + super.awakeFromNib() + setupViews() + } +} + +// MARK: UITextFieldDelegate needed calls +// Implement UITextFieldDelegate when you use this, and forward these calls to this class! +extension HideShowPasswordTextField { + func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { + // Hack to prevent text from getting cleared + // http://stackoverflow.com/a/29195723/1417922 + //Setting the new text. + let updatedString = (textField.text as NSString?)?.replacingCharacters(in: range, with: string) + textField.text = updatedString + + //Setting the cursor at the right place + let selectedRange = NSMakeRange(range.location + string.count, 0) + let from = textField.position(from: textField.beginningOfDocument, offset:selectedRange.location)! + let to = textField.position(from: from, offset:selectedRange.length)! + textField.selectedTextRange = textField.textRange(from: from, to: to) + + //Sending an action + textField.sendActions(for: .editingChanged) + + return false + } + + func textFieldDidEndEditing(textField: UITextField) { + passwordToggleVisibilityView.eyeState = PasswordToggleVisibilityView.EyeState.closed + self.isSecureTextEntry = !isSelected + } + +} + +// MARK: PasswordToggleVisibilityDelegate +extension HideShowPasswordTextField: PasswordToggleVisibilityDelegate { + func viewWasToggled(passwordToggleVisibilityView: PasswordToggleVisibilityView, isSelected selected: Bool) { + + // hack to fix a bug with padding when switching between secureTextEntry state + let hackString = self.text + self.text = " " + self.text = hackString + + // hack to save our correct font. The order here is VERY finicky + self.isSecureTextEntry = !selected + } +} + +// MARK: Control events +extension HideShowPasswordTextField { + @objc func passwordTextChanged(sender: AnyObject) { + if let password = self.text { + passwordToggleVisibilityView.checkmarkVisible = passwordDelegate?.isValidPassword(password: password) ?? false + } else { + passwordToggleVisibilityView.checkmarkVisible = false + } + } +} + +// MARK: Private helpers +extension HideShowPasswordTextField { + private func setupViews() { + let toggleFrame = CGRect(x: 0, y: 0, width: 66, height: frame.height) + passwordToggleVisibilityView = PasswordToggleVisibilityView(frame: toggleFrame) + passwordToggleVisibilityView.delegate = self + passwordToggleVisibilityView.checkmarkVisible = false + + self.keyboardType = .asciiCapable + self.rightView = passwordToggleVisibilityView + self.rightViewMode = .whileEditing + + self.font = self.preferredFont + self.addTarget(self, action: #selector(HideShowPasswordTextField.passwordTextChanged(sender:)), for: .editingChanged) + + // if we don't do this, the eye flies in on textfield focus! + self.rightView?.frame = self.rightViewRect(forBounds: self.bounds) + + // default eye state based on our initial secure text entry + passwordToggleVisibilityView.eyeState = isSecureTextEntry ? .closed : .open + } +} diff --git a/enzevalos_iphone/IconsStyleKit.swift b/enzevalos_iphone/IconsStyleKit.swift index 1e5f96586bd1d4efeec50c97402dc9f5d4dcbf06..26c2b7810bb7e41bc03709b15cecdac6981fe84a 100644 --- a/enzevalos_iphone/IconsStyleKit.swift +++ b/enzevalos_iphone/IconsStyleKit.swift @@ -2,21 +2,19 @@ // IconsStyleKit.swift // enzevalos // -// Created by Joscha on 04.01.17. -// Copyright © 2017 FU Berlin. All rights reserved. +// Created by Oliver Wiese on 22.01.19. +// Copyright © 2019 FU Berlin. All rights reserved. // // Generated by PaintCode // http://www.paintcodeapp.com // -// This code was partly generated by Trial version of PaintCode, therefore cannot be used for commercial purposes. // - - - import UIKit -open class IconsStyleKit: NSObject { - +internal class IconsStyleKit: NSObject { + + static let height = CGFloat(35) + static let width = CGFloat(50) //// Cache private struct Cache { @@ -31,6 +29,16 @@ open class IconsStyleKit: NSObject { static var postcardTargets: [AnyObject]? static var imageOfLetterOpen: UIImage? static var letterOpenTargets: [AnyObject]? + static var imageOfPadlockSecure: UIImage? + static var imageOfPadlockSecureBG: UIImage? + static var padlockSecureTargets: [AnyObject]? + static var imageOfPadlockInsecure: UIImage? + static var imageOfPadlockInsecureBG: UIImage? + static var padlockInsecureTargets: [AnyObject]? + static var imageOfPadlockError: UIImage? + static var padlockErrorTargets: [AnyObject]? + static var imageOfMailbox: UIImage? + static var mailboxTargets: [AnyObject]? } //// Colors @@ -39,15 +47,15 @@ open class IconsStyleKit: NSObject { //// Drawing Methods - @objc open dynamic class func drawLetter(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 50, height: 35), resizing: ResizingBehavior = .aspectFit, color: UIColor = IconsStyleKit.strokeColor, fillBackground: Bool = false) { + @objc open dynamic class func drawLetter(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: width, height: height), resizing: ResizingBehavior = .aspectFit, color: UIColor = IconsStyleKit.strokeColor, fillBackground: Bool = false) { //// General Declarations let context = UIGraphicsGetCurrentContext()! //// Resize to Target Frame context.saveGState() - let resizedFrame: CGRect = resizing.apply(rect: CGRect(x: 0, y: 0, width: 50, height: 35), target: targetFrame) + let resizedFrame: CGRect = resizing.apply(rect: CGRect(x: 0, y: 0, width: width, height: height), target: targetFrame) context.translateBy(x: resizedFrame.minX, y: resizedFrame.minY) - context.scaleBy(x: resizedFrame.width / 50, y: resizedFrame.height / 35) + context.scaleBy(x: resizedFrame.width / width, y: resizedFrame.height / height) //// letter Group @@ -446,6 +454,360 @@ open class IconsStyleKit: NSObject { context.restoreGState() } + @objc dynamic public class func drawPadlockSecure(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 35, height: 50), resizing: ResizingBehavior = .aspectFit, color: UIColor = strokeColor, fillBackground: Bool = false) { + //// General Declarations + let context = UIGraphicsGetCurrentContext()! + + //// Resize to Target Frame + context.saveGState() + let resizedFrame: CGRect = resizing.apply(rect: CGRect(x: 0, y: 0, width: 35, height: 50), target: targetFrame) + context.translateBy(x: resizedFrame.minX, y: resizedFrame.minY) + context.scaleBy(x: resizedFrame.width / 35, y: resizedFrame.height / 50) + color.setStroke() + + if fillBackground { + //// Rectangle Drawing + let rectanglePath = UIBezierPath(rect: CGRect(x: 11, y: 25, width: 14, height: 20)) + UIColor.white.setFill() + rectanglePath.fill() + } + + //// Bezier Drawing + context.saveGState() + context.translateBy(x: 1.3, y: 1) + context.scaleBy(x: 0.47, y: 0.47) + + let bezierPath = UIBezierPath() + bezierPath.move(to: CGPoint(x: 60.43, y: 45)) + bezierPath.addLine(to: CGPoint(x: 58.72, y: 45)) + bezierPath.addLine(to: CGPoint(x: 58.72, y: 30)) + bezierPath.addCurve(to: CGPoint(x: 34.04, y: 0), controlPoint1: CGPoint(x: 58.64, y: 10.81), controlPoint2: CGPoint(x: 47.58, y: 0)) + bezierPath.addCurve(to: CGPoint(x: 9.36, y: 30), controlPoint1: CGPoint(x: 20.51, y: 0), controlPoint2: CGPoint(x: 8.94, y: 11.3)) + bezierPath.addLine(to: CGPoint(x: 9.36, y: 45)) + bezierPath.addCurve(to: CGPoint(x: 8.51, y: 45), controlPoint1: CGPoint(x: 9.36, y: 45), controlPoint2: CGPoint(x: 9.53, y: 45)) + bezierPath.addCurve(to: CGPoint(x: -0, y: 54), controlPoint1: CGPoint(x: 7.43, y: 45), controlPoint2: CGPoint(x: -0, y: 46.54)) + bezierPath.addLine(to: CGPoint(x: -0, y: 90)) + bezierPath.addCurve(to: CGPoint(x: 8.51, y: 100), controlPoint1: CGPoint(x: -0, y: 97.96), controlPoint2: CGPoint(x: 8.32, y: 100)) + bezierPath.addLine(to: CGPoint(x: 60.43, y: 100)) + bezierPath.addCurve(to: CGPoint(x: 68.09, y: 90), controlPoint1: CGPoint(x: 60.61, y: 100), controlPoint2: CGPoint(x: 68.09, y: 98.95)) + bezierPath.addLine(to: CGPoint(x: 68.09, y: 55)) + bezierPath.addCurve(to: CGPoint(x: 60.43, y: 45), controlPoint1: CGPoint(x: 68.09, y: 46.55), controlPoint2: CGPoint(x: 60.62, y: 45)) + bezierPath.addLine(to: CGPoint(x: 60.43, y: 45)) + bezierPath.close() + bezierPath.move(to: CGPoint(x: 41.7, y: 86)) + bezierPath.addLine(to: CGPoint(x: 26.38, y: 86)) + bezierPath.addLine(to: CGPoint(x: 30.64, y: 72)) + bezierPath.addCurve(to: CGPoint(x: 27.23, y: 65), controlPoint1: CGPoint(x: 28.83, y: 70.59), controlPoint2: CGPoint(x: 27.23, y: 67.8)) + bezierPath.addCurve(to: CGPoint(x: 34.04, y: 57), controlPoint1: CGPoint(x: 27.23, y: 60.62), controlPoint2: CGPoint(x: 30.43, y: 57)) + bezierPath.addCurve(to: CGPoint(x: 40.85, y: 65), controlPoint1: CGPoint(x: 37.66, y: 57), controlPoint2: CGPoint(x: 40.85, y: 60.62)) + bezierPath.addCurve(to: CGPoint(x: 37.45, y: 72), controlPoint1: CGPoint(x: 40.85, y: 67.8), controlPoint2: CGPoint(x: 39.25, y: 70.59)) + bezierPath.addLine(to: CGPoint(x: 41.7, y: 86)) + bezierPath.addLine(to: CGPoint(x: 41.7, y: 86)) + bezierPath.close() + bezierPath.move(to: CGPoint(x: 20.43, y: 45)) + bezierPath.addLine(to: CGPoint(x: 20.43, y: 30)) + bezierPath.addCurve(to: CGPoint(x: 34.04, y: 12), controlPoint1: CGPoint(x: 20.43, y: 20.05), controlPoint2: CGPoint(x: 25.67, y: 12)) + bezierPath.addCurve(to: CGPoint(x: 47.66, y: 30), controlPoint1: CGPoint(x: 42.33, y: 12), controlPoint2: CGPoint(x: 47.66, y: 19.05)) + bezierPath.addLine(to: CGPoint(x: 47.66, y: 45)) + bezierPath.addLine(to: CGPoint(x: 20.43, y: 45)) + bezierPath.addLine(to: CGPoint(x: 20.43, y: 45)) + bezierPath.close() + IconsStyleKit.strokeColor.setStroke() + bezierPath.lineWidth = 2*1/0.47 + bezierPath.miterLimit = 4 + bezierPath.lineJoinStyle = .round + if fillBackground { + UIColor.white.setFill() + bezierPath.fill() + } + bezierPath.stroke() + + context.restoreGState() + + context.restoreGState() + + } + + @objc dynamic public class func drawPadlockInsecure(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 35, height: 50), resizing: ResizingBehavior = .aspectFit, color: UIColor = strokeColor, fillBackground: Bool = false) { + //// General Declarations + let context = UIGraphicsGetCurrentContext()! + + //// Resize to Target Frame + context.saveGState() + let resizedFrame: CGRect = resizing.apply(rect: CGRect(x: 0, y: 0, width: 35, height: 50), target: targetFrame) + context.translateBy(x: resizedFrame.minX, y: resizedFrame.minY) + context.scaleBy(x: resizedFrame.width / 35, y: resizedFrame.height / 50) + color.setStroke() + + //// lock-open + if fillBackground { + //// Rectangle Drawing + let rectanglePath = UIBezierPath(rect: CGRect(x: 11, y: 25, width: 14, height: 20)) + UIColor.white.setFill() + rectanglePath.fill() + } + context.saveGState() + context.translateBy(x: 1.3, y: 1) + context.scaleBy(x: 1.6, y: 1.6) + + + + //// Bezier Drawing + context.saveGState() + context.scaleBy(x: 0.27, y: 0.27) + + let bezierPath = UIBezierPath() + bezierPath.move(to: CGPoint(x: 66.26, y: 29.6)) + bezierPath.addCurve(to: CGPoint(x: 38.47, y: 0), controlPoint1: CGPoint(x: 66.26, y: 12.22), controlPoint2: CGPoint(x: 53.67, y: 0)) + bezierPath.addCurve(to: CGPoint(x: 10.14, y: 32.94), controlPoint1: CGPoint(x: 23.29, y: 0), controlPoint2: CGPoint(x: 9.66, y: 12.16)) + bezierPath.addLine(to: CGPoint(x: 10.12, y: 50.31)) + bezierPath.addCurve(to: CGPoint(x: 9.21, y: 50.33), controlPoint1: CGPoint(x: 10.12, y: 50.31), controlPoint2: CGPoint(x: 10.35, y: 50.33)) + bezierPath.addCurve(to: CGPoint(x: 0, y: 60.26), controlPoint1: CGPoint(x: 7.99, y: 50.33), controlPoint2: CGPoint(x: 0, y: 51.97)) + bezierPath.addLine(to: CGPoint(x: 0, y: 100.06)) + bezierPath.addCurve(to: CGPoint(x: 9.21, y: 111.11), controlPoint1: CGPoint(x: 0, y: 108.91), controlPoint2: CGPoint(x: 9, y: 111.11)) + bezierPath.addLine(to: CGPoint(x: 67.65, y: 111.11)) + bezierPath.addCurve(to: CGPoint(x: 76.39, y: 100.06), controlPoint1: CGPoint(x: 67.86, y: 111.11), controlPoint2: CGPoint(x: 76.39, y: 110.01)) + bezierPath.addLine(to: CGPoint(x: 76.39, y: 60.81)) + bezierPath.addCurve(to: CGPoint(x: 68.1, y: 50.33), controlPoint1: CGPoint(x: 76.39, y: 51.41), controlPoint2: CGPoint(x: 68.32, y: 50.33)) + bezierPath.addLine(to: CGPoint(x: 22.99, y: 50.33)) + bezierPath.addLine(to: CGPoint(x: 23, y: 33.16)) + bezierPath.addCurve(to: CGPoint(x: 38.19, y: 13.27), controlPoint1: CGPoint(x: 23, y: 22.11), controlPoint2: CGPoint(x: 28.8, y: 13.27)) + bezierPath.addCurve(to: CGPoint(x: 53.93, y: 32.59), controlPoint1: CGPoint(x: 47.49, y: 13.27), controlPoint2: CGPoint(x: 53.93, y: 20.36)) + bezierPath.addLine(to: CGPoint(x: 66.26, y: 29.6)) + bezierPath.close() + bezierPath.move(to: CGPoint(x: 46.93, y: 95.8)) + bezierPath.addLine(to: CGPoint(x: 29.48, y: 95.8)) + bezierPath.addLine(to: CGPoint(x: 34.22, y: 79.62)) + bezierPath.addCurve(to: CGPoint(x: 30.85, y: 72.21), controlPoint1: CGPoint(x: 32.2, y: 78.05), controlPoint2: CGPoint(x: 30.85, y: 75.32)) + bezierPath.addCurve(to: CGPoint(x: 38.19, y: 63.39), controlPoint1: CGPoint(x: 30.85, y: 67.34), controlPoint2: CGPoint(x: 34.14, y: 63.39)) + bezierPath.addCurve(to: CGPoint(x: 45.53, y: 72.21), controlPoint1: CGPoint(x: 42.25, y: 63.39), controlPoint2: CGPoint(x: 45.53, y: 67.34)) + bezierPath.addCurve(to: CGPoint(x: 42.17, y: 79.61), controlPoint1: CGPoint(x: 45.53, y: 75.32), controlPoint2: CGPoint(x: 44.19, y: 78.05)) + bezierPath.addLine(to: CGPoint(x: 46.93, y: 95.8)) + bezierPath.addLine(to: CGPoint(x: 46.93, y: 95.8)) + bezierPath.close() + IconsStyleKit.strokeColor.setStroke() + bezierPath.lineWidth = 2*1/0.46 + bezierPath.miterLimit = 4 + bezierPath.lineJoinStyle = .round + if fillBackground { + UIColor.white.setFill() + bezierPath.fill() + } + bezierPath.stroke() + + context.restoreGState() + + + + context.restoreGState() + + context.restoreGState() + + } + + @objc dynamic public class func drawPadlockError(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 35, height: 50), resizing: ResizingBehavior = .aspectFit, color: UIColor = strokeColor, fillBackground: Bool = false) { + //// General Declarations + let context = UIGraphicsGetCurrentContext()! + + + + //// Resize to Target Frame + context.saveGState() + let resizedFrame: CGRect = resizing.apply(rect: CGRect(x: 0, y: 0, width: 35, height: 50), target: targetFrame) + context.translateBy(x: resizedFrame.minX, y: resizedFrame.minY) + context.scaleBy(x: resizedFrame.width / 35, y: resizedFrame.height / 50) + color.setStroke() + + //// Bezier Drawing + context.saveGState() + context.translateBy(x: 1.23, y: 1.83) + context.scaleBy(x: 0.25, y: 0.25) + + if fillBackground { + //// Rectangle Drawing + let rectanglePath = UIBezierPath(rect: CGRect(x: 11, y: 25, width: 14, height: 20)) + UIColor.white.setFill() + rectanglePath.fill() + } + + let bezierPath = UIBezierPath() + bezierPath.move(to: CGPoint(x: 116.87, y: 85.13)) + bezierPath.addLine(to: CGPoint(x: 113.72, y: 85.13)) + bezierPath.addLine(to: CGPoint(x: 113.72, y: 55.51)) + bezierPath.addCurve(to: CGPoint(x: 64.07, y: 0.69), controlPoint1: CGPoint(x: 113.56, y: 19.17), controlPoint2: CGPoint(x: 90.15, y: 0.69)) + bezierPath.addCurve(to: CGPoint(x: 17.4, y: 55.51), controlPoint1: CGPoint(x: 38.01, y: 0.69), controlPoint2: CGPoint(x: 16.59, y: 20.1)) + bezierPath.addLine(to: CGPoint(x: 17.37, y: 85.09)) + bezierPath.addCurve(to: CGPoint(x: 15.8, y: 85.13), controlPoint1: CGPoint(x: 17.37, y: 85.09), controlPoint2: CGPoint(x: 17.77, y: 85.13)) + bezierPath.addCurve(to: CGPoint(x: 0, y: 102.05), controlPoint1: CGPoint(x: 13.72, y: 85.13), controlPoint2: CGPoint(x: 0, y: 87.92)) + bezierPath.addLine(to: CGPoint(x: 0, y: 169.87)) + bezierPath.addCurve(to: CGPoint(x: 15.8, y: 188.69), controlPoint1: CGPoint(x: 0, y: 184.94), controlPoint2: CGPoint(x: 15.44, y: 188.69)) + bezierPath.addLine(to: CGPoint(x: 116.09, y: 188.69)) + bezierPath.addCurve(to: CGPoint(x: 131.1, y: 169.87), controlPoint1: CGPoint(x: 116.45, y: 188.69), controlPoint2: CGPoint(x: 131.1, y: 186.81)) + bezierPath.addLine(to: CGPoint(x: 131.1, y: 102.98)) + bezierPath.addCurve(to: CGPoint(x: 116.87, y: 85.13), controlPoint1: CGPoint(x: 131.1, y: 86.98), controlPoint2: CGPoint(x: 117.24, y: 85.13)) + bezierPath.addLine(to: CGPoint(x: 116.87, y: 85.13)) + bezierPath.close() + bezierPath.move(to: CGPoint(x: 39.48, y: 55.9)) + bezierPath.addCurve(to: CGPoint(x: 65.55, y: 22), controlPoint1: CGPoint(x: 39.48, y: 37.06), controlPoint2: CGPoint(x: 49.43, y: 22)) + bezierPath.addCurve(to: CGPoint(x: 91.61, y: 55.9), controlPoint1: CGPoint(x: 81.51, y: 22), controlPoint2: CGPoint(x: 91.61, y: 35.17)) + bezierPath.addLine(to: CGPoint(x: 91.63, y: 85.13)) + bezierPath.addLine(to: CGPoint(x: 39.45, y: 85.13)) + bezierPath.addLine(to: CGPoint(x: 39.48, y: 55.9)) + bezierPath.addLine(to: CGPoint(x: 39.48, y: 55.9)) + bezierPath.close() + bezierPath.move(to: CGPoint(x: 82.37, y: 171.09)) + bezierPath.addLine(to: CGPoint(x: 64.43, y: 150.37)) + bezierPath.addLine(to: CGPoint(x: 47.67, y: 170.13)) + bezierPath.addLine(to: CGPoint(x: 36.86, y: 157.62)) + bezierPath.addLine(to: CGPoint(x: 54.8, y: 136.9)) + bezierPath.addLine(to: CGPoint(x: 38.02, y: 117.55)) + bezierPath.addLine(to: CGPoint(x: 48.53, y: 105.27)) + bezierPath.addLine(to: CGPoint(x: 66.47, y: 125.98)) + bezierPath.addLine(to: CGPoint(x: 83.55, y: 106.41)) + bezierPath.addLine(to: CGPoint(x: 94.22, y: 118.74)) + bezierPath.addLine(to: CGPoint(x: 76.28, y: 139.46)) + bezierPath.addLine(to: CGPoint(x: 93.19, y: 158.98)) + bezierPath.addLine(to: CGPoint(x: 82.37, y: 171.09)) + bezierPath.close() + IconsStyleKit.strokeColor.setStroke() + bezierPath.lineWidth = 2*1/0.46 + bezierPath.miterLimit = 4 + bezierPath.lineJoinStyle = .round + if fillBackground { + UIColor.white.setFill() + bezierPath.fill() + } + bezierPath.stroke() + + context.restoreGState() + + context.restoreGState() + + } + + + @objc dynamic public class func drawMailbox(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 60, height: 60), resizing: ResizingBehavior = .aspectFit) { + //// General Declarations + let context = UIGraphicsGetCurrentContext()! + + //// Resize to Target Frame + context.saveGState() + let resizedFrame: CGRect = resizing.apply(rect: CGRect(x: 0, y: 0, width: 60, height: 60), target: targetFrame) + context.translateBy(x: resizedFrame.minX, y: resizedFrame.minY) + context.scaleBy(x: resizedFrame.width / 60, y: resizedFrame.height / 60) + + + //// Color Declarations + let fillColor3 = UIColor(red: 0.776, green: 0.776, blue: 0.773, alpha: 1.000) + let fillColor4 = UIColor(red: 0.925, green: 0.925, blue: 0.925, alpha: 1.000) + let fillColor5 = UIColor(red: 0.851, green: 0.851, blue: 0.851, alpha: 1.000) + let red = UIColor(red: 0.910, green: 0.306, blue: 0.106, alpha: 1.000) + let fillColor7 = UIColor(red: 0.612, green: 0.608, blue: 0.608, alpha: 1.000) + + //// letterbox-09.svg Group + context.saveGState() + context.translateBy(x: -11.36, y: 0.74) + context.scaleBy(x: 0.06, y: 0.06) + + + + //// Group 4 + //// Star Drawing + context.saveGState() + context.translateBy(x: 505.36, y: 653.16) + context.rotate(by: -30 * CGFloat.pi/180) + + let starPath = UIBezierPath() + starPath.move(to: CGPoint(x: 0, y: -369.95)) + starPath.addLine(to: CGPoint(x: 213.6, y: 0)) + starPath.addLine(to: CGPoint(x: 0, y: 369.95)) + starPath.addLine(to: CGPoint(x: -213.6, y: 0)) + starPath.close() + fillColor3.setFill() + starPath.fill() + + context.restoreGState() + + + //// Bezier 137 Drawing + let bezier137Path = UIBezierPath() + bezier137Path.move(to: CGPoint(x: 690.36, y: 547.26)) + bezier137Path.addLine(to: CGPoint(x: 320.36, y: 333.66)) + bezier137Path.addLine(to: CGPoint(x: 690.36, y: 119.96)) + bezier137Path.addLine(to: CGPoint(x: 1060.36, y: 333.66)) + bezier137Path.addLine(to: CGPoint(x: 690.36, y: 547.26)) + bezier137Path.close() + fillColor4.setFill() + bezier137Path.fill() + + + //// Star 2 Drawing + context.saveGState() + context.translateBy(x: 875.36, y: 653.16) + context.rotate(by: -150 * CGFloat.pi/180) + + let star2Path = UIBezierPath() + star2Path.move(to: CGPoint(x: 0, y: -369.95)) + star2Path.addLine(to: CGPoint(x: 213.6, y: 0)) + star2Path.addLine(to: CGPoint(x: 0, y: 369.95)) + star2Path.addLine(to: CGPoint(x: -213.6, y: 0)) + star2Path.close() + fillColor5.setFill() + star2Path.fill() + + context.restoreGState() + + + //// Bezier 138 Drawing + context.saveGState() + context.translateBy(x: 791.26, y: 643.23) + + let bezier138Path = UIBezierPath() + bezier138Path.move(to: CGPoint(x: 37.5, y: -3.36)) + bezier138Path.addLine(to: CGPoint(x: 54.8, y: -13.36)) + bezier138Path.addCurve(to: CGPoint(x: 67.3, y: -35.06), controlPoint1: CGPoint(x: 62.5, y: -17.86), controlPoint2: CGPoint(x: 67.3, y: -26.06)) + bezier138Path.addLine(to: CGPoint(x: 67.3, y: -433.36)) + bezier138Path.addCurve(to: CGPoint(x: 79.8, y: -455.06), controlPoint1: CGPoint(x: 67.3, y: -442.26), controlPoint2: CGPoint(x: 72.1, y: -450.56)) + bezier138Path.addLine(to: CGPoint(x: 155.7, y: -498.86)) + bezier138Path.addCurve(to: CGPoint(x: 168.2, y: -520.56), controlPoint1: CGPoint(x: 163.4, y: -503.36), controlPoint2: CGPoint(x: 168.2, y: -511.56)) + bezier138Path.addLine(to: CGPoint(x: 168.2, y: -618.16)) + bezier138Path.addCurve(to: CGPoint(x: 130.7, y: -639.86), controlPoint1: CGPoint(x: 168.2, y: -637.36), controlPoint2: CGPoint(x: 147.4, y: -649.46)) + bezier138Path.addLine(to: CGPoint(x: 12.5, y: -571.66)) + bezier138Path.addCurve(to: CGPoint(x: 0, y: -549.96), controlPoint1: CGPoint(x: 4.8, y: -567.16), controlPoint2: CGPoint(x: 0, y: -558.96)) + bezier138Path.addLine(to: CGPoint(x: 0, y: -25.06)) + bezier138Path.addCurve(to: CGPoint(x: 37.5, y: -3.36), controlPoint1: CGPoint(x: 0, y: -5.86), controlPoint2: CGPoint(x: 20.8, y: 6.24)) + bezier138Path.close() + red.setFill() + bezier138Path.fill() + + context.restoreGState() + + + //// Bezier 139 Drawing + let bezier139Path = UIBezierPath() + bezier139Path.move(to: CGPoint(x: 590.36, y: 688.03)) + bezier139Path.addLine(to: CGPoint(x: 398.66, y: 577.33)) + bezier139Path.addCurve(to: CGPoint(x: 387.76, y: 558.43), controlPoint1: CGPoint(x: 391.86, y: 573.43), controlPoint2: CGPoint(x: 387.76, y: 566.23)) + bezier139Path.addLine(to: CGPoint(x: 387.76, y: 492.43)) + bezier139Path.addCurve(to: CGPoint(x: 420.56, y: 473.53), controlPoint1: CGPoint(x: 387.76, y: 475.63), controlPoint2: CGPoint(x: 405.96, y: 465.03)) + bezier139Path.addLine(to: CGPoint(x: 612.26, y: 584.23)) + bezier139Path.addCurve(to: CGPoint(x: 623.16, y: 603.13), controlPoint1: CGPoint(x: 619.06, y: 588.13), controlPoint2: CGPoint(x: 623.16, y: 595.33)) + bezier139Path.addLine(to: CGPoint(x: 623.16, y: 669.13)) + bezier139Path.addCurve(to: CGPoint(x: 590.36, y: 688.03), controlPoint1: CGPoint(x: 623.26, y: 685.93), controlPoint2: CGPoint(x: 604.96, y: 696.43)) + bezier139Path.close() + fillColor7.setFill() + bezier139Path.fill() + + + + + + context.restoreGState() + + context.restoreGState() + + } + //// Generated Images @objc open dynamic class var imageOfLetter: UIImage { @@ -531,6 +893,90 @@ open class IconsStyleKit: NSObject { return Cache.imageOfLetterOpen! } + + @objc dynamic public class var imageOfPadlockSecure: UIImage { + if Cache.imageOfPadlockSecure != nil { + return Cache.imageOfPadlockSecure! + } + + UIGraphicsBeginImageContextWithOptions(CGSize(width: height, height: width), false, 0) + IconsStyleKit.drawPadlockSecure(fillBackground: false) + + Cache.imageOfPadlockSecure = UIGraphicsGetImageFromCurrentImageContext()! + UIGraphicsEndImageContext() + + return Cache.imageOfPadlockSecure! + } + + @objc dynamic public class var imageOfPadlockSecureBG: UIImage { + if Cache.imageOfPadlockSecureBG != nil { + return Cache.imageOfPadlockSecureBG! + } + + UIGraphicsBeginImageContextWithOptions(CGSize(width: height, height: width), false, 0) + IconsStyleKit.drawPadlockSecure(fillBackground: true) + + Cache.imageOfPadlockSecureBG = UIGraphicsGetImageFromCurrentImageContext()! + UIGraphicsEndImageContext() + + return Cache.imageOfPadlockSecureBG! + } + + @objc dynamic public class var imageOfPadlockInsecure: UIImage { + if Cache.imageOfPadlockInsecure != nil { + return Cache.imageOfPadlockInsecure! + } + + UIGraphicsBeginImageContextWithOptions(CGSize(width: height, height: width), false, 0) + IconsStyleKit.drawPadlockInsecure(fillBackground: false) + + Cache.imageOfPadlockInsecure = UIGraphicsGetImageFromCurrentImageContext()! + UIGraphicsEndImageContext() + + return Cache.imageOfPadlockInsecure! + } + + @objc dynamic public class var imageOfPadlockInsecureBG: UIImage { + if Cache.imageOfPadlockInsecureBG != nil { + return Cache.imageOfPadlockInsecureBG! + } + + UIGraphicsBeginImageContextWithOptions(CGSize(width: height, height: width), false, 0) + IconsStyleKit.drawPadlockInsecure(fillBackground: true) + + Cache.imageOfPadlockInsecureBG = UIGraphicsGetImageFromCurrentImageContext()! + UIGraphicsEndImageContext() + return Cache.imageOfPadlockInsecureBG! + } + + @objc dynamic public class var imageOfPadlockError: UIImage { + if Cache.imageOfPadlockError != nil { + return Cache.imageOfPadlockError! + } + + UIGraphicsBeginImageContextWithOptions(CGSize(width: height, height: width), false, 0) + IconsStyleKit.drawPadlockError() + + Cache.imageOfPadlockError = UIGraphicsGetImageFromCurrentImageContext()! + UIGraphicsEndImageContext() + + return Cache.imageOfPadlockError! + } + + @objc dynamic public class var imageOfMailbox: UIImage { + if Cache.imageOfMailbox != nil { + return Cache.imageOfMailbox! + } + + UIGraphicsBeginImageContextWithOptions(CGSize(width: 60, height: 60), false, 0) + IconsStyleKit.drawMailbox() + + Cache.imageOfMailbox = UIGraphicsGetImageFromCurrentImageContext()! + UIGraphicsEndImageContext() + + return Cache.imageOfMailbox! + } + //// Customization Infrastructure @@ -573,6 +1019,36 @@ open class IconsStyleKit: NSObject { } } } + + @objc @IBOutlet dynamic var padlockSecureTargets: [AnyObject]! { + get { return Cache.padlockSecureTargets } + set { + Cache.padlockSecureTargets = newValue + for target: AnyObject in newValue { + let _ = target.perform(NSSelectorFromString("setImage:"), with: IconsStyleKit.imageOfPadlockSecure) + } + } + } + + @objc @IBOutlet dynamic var padlockInsecureTargets: [AnyObject]! { + get { return Cache.padlockInsecureTargets } + set { + Cache.padlockInsecureTargets = newValue + for target: AnyObject in newValue { + let _ = target.perform(NSSelectorFromString("setImage:"), with: IconsStyleKit.imageOfPadlockInsecure) + } + } + } + + @objc @IBOutlet dynamic var padlockErrorTargets: [AnyObject]! { + get { return Cache.padlockErrorTargets } + set { + Cache.padlockErrorTargets = newValue + for target: AnyObject in newValue { + let _ = target.perform(NSSelectorFromString("setImage:"), with: IconsStyleKit.imageOfPadlockError) + } + } + } @objc public enum ResizingBehavior: Int { @@ -613,3 +1089,61 @@ open class IconsStyleKit: NSObject { } } } +extension UIImage { + // see: https://stackoverflow.com/questions/36645060/rotate-uiimage-in-swift + func rotate(deg degrees: CGFloat) -> UIImage { + //Calculate the size of the rotated view's containing box for our drawing space + let rotatedViewBox: UIView = UIView(frame: CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height)) + let t: CGAffineTransform = CGAffineTransform(rotationAngle: degrees * CGFloat.pi / 180) + rotatedViewBox.transform = t + let rotatedSize: CGSize = rotatedViewBox.frame.size + //Create the bitmap context + UIGraphicsBeginImageContext(rotatedSize) + let bitmap: CGContext = UIGraphicsGetCurrentContext()! + //Move the origin to the middle of the image so we will rotate and scale around the center. + bitmap.translateBy(x: rotatedSize.width / 2, y: rotatedSize.height / 2) + //Rotate the image context + bitmap.rotate(by: (degrees * CGFloat.pi / 180)) + //Now, draw the rotated/scaled image into the context + bitmap.scaleBy(x: 1.0, y: -1.0) + bitmap.draw(self.cgImage!, in: CGRect(x: -self.size.width / 2, y: -self.size.height / 2, width: self.size.width, height: self.size.height)) + let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()! + UIGraphicsEndImageContext() + return newImage + } + +} +private extension UIColor { + func withHue(_ newHue: CGFloat) -> UIColor { + var saturation: CGFloat = 1, brightness: CGFloat = 1, alpha: CGFloat = 1 + self.getHue(nil, saturation: &saturation, brightness: &brightness, alpha: &alpha) + return UIColor(hue: newHue, saturation: saturation, brightness: brightness, alpha: alpha) + } + func withSaturation(_ newSaturation: CGFloat) -> UIColor { + var hue: CGFloat = 1, brightness: CGFloat = 1, alpha: CGFloat = 1 + self.getHue(&hue, saturation: nil, brightness: &brightness, alpha: &alpha) + return UIColor(hue: hue, saturation: newSaturation, brightness: brightness, alpha: alpha) + } + func withBrightness(_ newBrightness: CGFloat) -> UIColor { + var hue: CGFloat = 1, saturation: CGFloat = 1, alpha: CGFloat = 1 + self.getHue(&hue, saturation: &saturation, brightness: nil, alpha: &alpha) + return UIColor(hue: hue, saturation: saturation, brightness: newBrightness, alpha: alpha) + } + func withAlpha(_ newAlpha: CGFloat) -> UIColor { + var hue: CGFloat = 1, saturation: CGFloat = 1, brightness: CGFloat = 1 + self.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: nil) + return UIColor(hue: hue, saturation: saturation, brightness: brightness, alpha: newAlpha) + } + func highlight(withLevel highlight: CGFloat) -> UIColor { + var red: CGFloat = 1, green: CGFloat = 1, blue: CGFloat = 1, alpha: CGFloat = 1 + self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) + return UIColor(red: red * (1-highlight) + highlight, green: green * (1-highlight) + highlight, blue: blue * (1-highlight) + highlight, alpha: alpha * (1-highlight) + highlight) + } + func shadow(withLevel shadow: CGFloat) -> UIColor { + var red: CGFloat = 1, green: CGFloat = 1, blue: CGFloat = 1, alpha: CGFloat = 1 + self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) + return UIColor(red: red * (1-shadow), green: green * (1-shadow), blue: blue * (1-shadow), alpha: alpha * (1-shadow) + shadow) + } +} + + diff --git a/enzevalos_iphone/InboxTableViewCell.swift b/enzevalos_iphone/InboxTableViewCell.swift index e1d6f46ec161440f92134910d6c8b22c066b565d..0c4f76d394bcb94c8a1a5bf442b55eabf9557045 100644 --- a/enzevalos_iphone/InboxTableViewCell.swift +++ b/enzevalos_iphone/InboxTableViewCell.swift @@ -99,9 +99,9 @@ class InboxTableViewCell: UITableViewCell { secondButton.isEnabled = false } if con.isSecure { - iconView.image = IconsStyleKit.imageOfLetterBG + iconView.image = StudySettings.securityIndicator.imageOfSecureIndicator(background: true, open: false) } else { - iconView.image = IconsStyleKit.imageOfPostcardBG + iconView.image = StudySettings.securityIndicator.imageOfInsecureIndicator(background: true) } var cont: Contact diff --git a/enzevalos_iphone/InboxViewController.swift b/enzevalos_iphone/InboxViewController.swift index 167edfdd0d2dfdfe96274b2ab6a28a6f38cd1a6a..9a2c137d29582b055ea2f7865dfbee41f5c58744 100644 --- a/enzevalos_iphone/InboxViewController.swift +++ b/enzevalos_iphone/InboxViewController.swift @@ -82,8 +82,11 @@ class InboxViewController: UITableViewController, InboxCellDelegator { dateFormatter.timeStyle = .medium tableView.register(UINib(nibName: "InboxTableViewCell", bundle: nil), forCellReuseIdentifier: "inboxCell") - - AppDelegate.getAppDelegate().mailHandler.startIMAPIdleIfSupported() + do{ + try AppDelegate.getAppDelegate().mailHandler.startIMAPIdleIfSupported() + } catch { + print("ERROR: Coould not establish connection to server!") + } NotificationCenter.default.addObserver(forName: Notification.Name.NSManagedObjectContextDidSave, object: nil, queue: nil, using: { [weak self] _ in self?.tableView.reloadData() @@ -300,9 +303,7 @@ extension InboxViewController { func doneLoading(_ error: Error?) { if error != nil { lastUpdateText = NSLocalizedString("NeverUpdated", comment: "Error while loading mailscomment") - print(String(describing: error)) } - loading = false } } diff --git a/enzevalos_iphone/LabelStyleKit.swift b/enzevalos_iphone/LabelStyleKit.swift index f1757a4485a3af9ac52147ba9d69d411813aaca9..88787b5489d573fa2bb788a4112ca908429bd812 100644 --- a/enzevalos_iphone/LabelStyleKit.swift +++ b/enzevalos_iphone/LabelStyleKit.swift @@ -8,7 +8,6 @@ // Generated by PaintCode // http://www.paintcodeapp.com // -// This code was partly generated by Trial version of PaintCode, therefore cannot be used for commercial purposes. // diff --git a/enzevalos_iphone/Logger.swift b/enzevalos_iphone/Logger.swift index fd133142e74f99b2df9e13cc6248da349f2ed8c6..0907f021c4a7855eb0401dadfb854b9231435b1e 100644 --- a/enzevalos_iphone/Logger.swift +++ b/enzevalos_iphone/Logger.swift @@ -22,12 +22,12 @@ import Foundation class Logger { - static var logging = false + static var logging = StudySettings.studyMode static let queue = DispatchQueue(label: "logging", qos: .background) static let defaultFileName = "log.json" - static let loggingInterval = 21600 //60*60*6 seconds + static let loggingInterval = 21600 //60*60*6 seconds = 6 hours static let resendInterval = 5 * 60 static let logReceiver = LOGGING_MAIL_ADR @@ -35,13 +35,14 @@ class Logger { static var studyID = StudySettings.studyID //identifies the participant in the study + + static fileprivate func sendCheck() { - if nextDeadline <= Date() && AppDelegate.getAppDelegate().currentReachabilityStatus != .notReachable { + if nextDeadline <= Date() && AppDelegate.getAppDelegate().currentReachabilityStatus != .notReachable && UserManager.loadUserValue(Attribute.userName) != nil && UserDefaults.standard.bool(forKey: "launchedBefore"){ //Do not send duplicate mails let tmpNextDeadline = Date(timeIntervalSinceNow: TimeInterval(resendInterval)) nextDeadline = tmpNextDeadline UserManager.storeUserValue(nextDeadline as AnyObject?, attribute: Attribute.nextDeadline) - sendLog() } } @@ -50,6 +51,7 @@ class Logger { var fields: [String: Any] = [:] let now = Date() fields["timestamp"] = now.description + fields["lang"] = Locale.current.languageCode return fields } @@ -65,14 +67,17 @@ class Logger { } } - static func log(setupStudy studypara: [StudyParamter: Int], alreadyRegistered: Bool) { + static func log(setupStudy studypara: [StudyParameterProtocol.Type], alreadyRegistered: Bool) { if !logging { return } var event = plainLogDict() event["type"] = LoggingEventType.setupStudy.rawValue - for (para, value) in studypara { - event[para.name] = value + + //event["language"] = + + for para in studypara{ + event[para.name] = para.load().value } event["alreadyRegistered"] = alreadyRegistered saveToDisk(json: dictToJSON(fields: event)) diff --git a/enzevalos_iphone/MailAddress.swift b/enzevalos_iphone/MailAddress.swift index 1623b5d52d19b78817049f29a49ea616252a359f..45031420c691dc4a0037975c5291764a8f24a375 100644 --- a/enzevalos_iphone/MailAddress.swift +++ b/enzevalos_iphone/MailAddress.swift @@ -22,17 +22,30 @@ import Foundation import Contacts public enum EncState { - case MUTAL + case MUTUAL case GOSSIP case NOPREFERENCE case RESET case NOAUTOCRYPT + + var name: String{ + get{ + switch self { + case .MUTUAL: + return "mutual" + case .NOPREFERENCE: + return "nopreference" + default: + return "" + } + } + } static func find(i: Int) -> EncState { switch i { case 0: - return EncState.MUTAL + return EncState.MUTUAL case 1: return EncState.GOSSIP case 2: @@ -49,7 +62,7 @@ public enum EncState { func canEnc() -> Bool { switch self { - case EncState.MUTAL: + case EncState.MUTUAL: return true case EncState.GOSSIP: return true @@ -61,7 +74,7 @@ public enum EncState { } func asInt() -> Int16 { switch self { - case EncState.MUTAL: + case EncState.MUTUAL: return 0 case EncState.GOSSIP: return 1 diff --git a/enzevalos_iphone/MailHandler.swift b/enzevalos_iphone/MailHandler.swift index 1128c347509f7c99b060ecb53a0198acb24ca322..915c0095b43a0e7e960068e47bf5fc94ce5ab1e8 100644 --- a/enzevalos_iphone/MailHandler.swift +++ b/enzevalos_iphone/MailHandler.swift @@ -46,265 +46,50 @@ fileprivate func > <T : Comparable>(lhs: T?, rhs: T?) -> Bool { } } - - -let AUTOCRYPTHEADER = "Autocrypt" -let SETUPMESSAGE = "Autocrypt-Setup-Message" -let ADDR = "addr" -let TYPE = "type" -let ENCRYPTION = "prefer-encrypt" -let KEY = "keydata" - - -class AutocryptContact { - var addr: String = "" - var type: CryptoScheme = .PGP - var prefer_encryption: EncState = EncState.NOAUTOCRYPT - var key: String = "" - - init(addr: String, type: String, prefer_encryption: String, key: String) { - self.addr = addr - self.key = key - setPrefer_encryption(prefer_encryption) - } - - - convenience init(header: MCOMessageHeader) { - var autocrypt = header.extraHeaderValue(forName: AUTOCRYPTHEADER) - var field: [String] - var addr = "" - var type = "1" - var pref = "mutal" - var key = "" - - if autocrypt != nil { - autocrypt = autocrypt?.trimmingCharacters(in: .whitespacesAndNewlines) - let autocrypt_fields = autocrypt?.components(separatedBy: ";") - for f in autocrypt_fields! { - field = f.components(separatedBy: "=") - if field.count > 1 { - let flag = field[0].trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) - var value = field[1] - if field.count > 2 { - for i in 2...(field.count - 1) { - value = value + "=" - value = value + field[i] - } - } - switch flag { - case ADDR: - addr = value.trimmingCharacters(in: .whitespacesAndNewlines) - addr = addr.lowercased() - break - case TYPE: - type = value.trimmingCharacters(in: .whitespacesAndNewlines) - break - case ENCRYPTION: - pref = value.trimmingCharacters(in: .whitespacesAndNewlines) - break - case KEY: - if value.count > 0 { - key = value - } - break - default: - break - } - } - } - } - self.init(addr: addr, type: type, prefer_encryption: pref, key: key) - } - - - func setPrefer_encryption(_ input: String){ - let pref = input.lowercased() - if pref == "yes" || pref == "mutal" { - self.prefer_encryption = EncState.MUTAL - } else if pref == "no" { - self.prefer_encryption = EncState.NOPREFERENCE - } - prefer_encryption = EncState.NOPREFERENCE - } - - func toString() -> String { - return "Addr: \(addr) | type: \(type) | encryption? \(prefer_encryption) key size: \(key.count)" - } -} - class MailHandler { + private static let MAXMAILS = 25 + private static let extraHeaders = Autocrypt.EXTRAHEADERS + [TravelHandler.backupHeader] var delegate: MailHandlerDelegator? - - var INBOX: String { + static var INBOX: String { return "INBOX" } - - fileprivate static let MAXMAILS = 25 - - fileprivate let concurrentMailServer = DispatchQueue(label: "com.enzevalos.mailserverQueue", attributes: DispatchQueue.Attributes.concurrent) - private var IMAPSes: MCOIMAPSession? - - var IMAPSession: MCOIMAPSession { + var IMAPSession: MCOIMAPSession? { if IMAPSes == nil { - IMAPSes = setupIMAPSession() + do { + try IMAPSes = setupIMAPSession() + }catch{} } - return IMAPSes! + return IMAPSes } - var IMAPIdleSession: MCOIMAPSession? var IMAPIdleSupported: Bool? var shouldTryRefreshOAUTH: Bool { - return (UserManager.loadImapAuthType() == MCOAuthType.xoAuth2 || UserManager.loadSmtpAuthType() == MCOAuthType.xoAuth2) && - !(EmailHelper.singleton().authorization?.authState.isTokenFresh() ?? false) - } - - private func addAutocryptHeader(_ builder: MCOMessageBuilder) { - guard let prefKey = DataHandler.handler.prefSecretKey() else { - return - } - let adr = (UserManager.loadUserValue(Attribute.userAddr) as! String).lowercased() - let skID = prefKey.keyID - - let pgp = SwiftPGP() - if let id = skID { - let enc = "yes" - if let key = pgp.exportKey(id: id, isSecretkey: false, autocrypt: true) { - var string = "\(ADDR)=" + adr - if enc == "yes" { - string = string + "; \(ENCRYPTION)=mutal" - } - string = string + "; \(KEY)= \n" + key - builder.header.setExtraHeaderValue(string, forName: AUTOCRYPTHEADER) - } - } - } - - fileprivate func createHeader(_ builder: MCOMessageBuilder, toEntrys: [String], ccEntrys: [String], bccEntrys: [String], subject: String, autocrypt: Bool = true) { - - let username = UserManager.loadUserValue(Attribute.userName) as! String - let useraddr = (UserManager.loadUserValue(Attribute.userAddr) as! String) - - var toReady: [MCOAddress] = [] - for addr in toEntrys { - toReady.append(MCOAddress(displayName: addr, mailbox: addr)) - } - builder.header.to = toReady - - var ccReady: [MCOAddress] = [] - for addr in ccEntrys { - ccReady.append(MCOAddress(displayName: addr, mailbox: addr)) - } - builder.header.cc = ccReady - - var bccReady: [MCOAddress] = [] - for addr in bccEntrys { - bccReady.append(MCOAddress(displayName: addr, mailbox: addr)) - } - - builder.header.bcc = bccReady - builder.header.from = MCOAddress(displayName: username, mailbox: useraddr) - builder.header.subject = subject - builder.header.setExtraHeaderValue("letterbox", forName: "X-Mailer") - - if autocrypt { - addAutocryptHeader(builder) - } - } - - private func orderReceiver(receiver: [String], sendEncryptedIfPossible: Bool) -> [CryptoScheme: [MCOAddress]] { - var orderedReceiver = [CryptoScheme: [MCOAddress]]() - orderedReceiver[CryptoScheme.PGP] = [MCOAddress]() - orderedReceiver[CryptoScheme.UNKNOWN] = [MCOAddress]() - - for r in receiver { - let mco = MCOAddress(displayName: r, mailbox: r) - if let adr = DataHandler.handler.findMailAddress(adr: r), adr.hasKey, sendEncryptedIfPossible, let primaryKey = adr.primaryKey, !primaryKey.currentlyActiveKey.repealed { // TODO: include encryption preference of Autocrypt - orderedReceiver[CryptoScheme.PGP]?.append(mco!) - } else { - orderedReceiver[CryptoScheme.UNKNOWN]?.append(mco!) - } - } - return orderedReceiver - } - - private func addKeys(adrs: [MCOAddress]) -> [String] { - var ids = [String]() - for a in adrs { - if let adr = DataHandler.handler.findMailAddress(adr: a.mailbox), let key = adr.primaryKey?.keyID { - ids.append(key) - } + if let imapAuthType = UserManager.loadUserValue(.imapConnectionType) as? Int, + let smtpAuthType = UserManager.loadUserValue(.smtpAuthType) as? Int{ + return (imapAuthType == MCOAuthType.xoAuth2.rawValue || smtpAuthType == MCOAuthType.xoAuth2.rawValue) && + !(EmailHelper.singleton().authorization?.authState.isTokenFresh() ?? false) } - return ids + return false } - - func sendSecretKey(keyID: String, key: String, passcode: String, callback: @escaping (Error?) -> Void) { - let useraddr = (UserManager.loadUserValue(Attribute.userAddr) as! String) - let session = createSMTPSession() - let builder = MCOMessageBuilder() - let userID: MCOAddress = MCOAddress(displayName: useraddr, mailbox: useraddr) - - createHeader(builder, toEntrys: [useraddr], ccEntrys: [], bccEntrys: [], subject: "Autocrypt Setup Message") - builder.header.setExtraHeaderValue("v1", forName: SETUPMESSAGE) - - - builder.addAttachment(MCOAttachment.init(text: "This message contains a secret for reading secure mails on other devices. \n 1) Input the passcode from your smartphone to unlock the message on your other device. \n 2) Import the secret key into your pgp program on the device. \n\n For more information visit:https://userpage.fu-berlin.de/letterbox/faq.html#otherDevices \n\n")) - - if let keyAttachment = MCOAttachment.init(text: key){ - builder.addAttachment(keyAttachment) - } - - // See: https://autocrypt.org/level1.html#autocrypt-setup-message - let filename = keyID+".asc.asc" - if let keyAttachment = MCOAttachment.init(contentsOfFile: filename){ - keyAttachment.mimeType = "application/autocrypt-setup" - keyAttachment.setContentTypeParameterValue("UTF-8", forName: "charset") - keyAttachment.setContentTypeParameterValue(filename, forName: "name") - keyAttachment.filename = filename - keyAttachment.data = key.data(using: .utf8) - - builder.addAttachment(keyAttachment) - - } - - - - let sendOperation = session.sendOperation(with: builder.data(), from: userID, recipients: [userID]) - sendOperation?.start({ error in - guard error == nil else { - self.errorhandling(error: error, originalCall: {self.sendSecretKey(keyID: keyID, key: key, passcode: passcode, callback: callback)}, completionCallback: nil) - return - } - callback(nil) - }) + + func sendSecretKey(keyID: String, key: String, callback: @escaping (MailServerConnectionError?) -> Void) { + let mail = OutgoingMail.createSecretKeyExportMail(keyID: keyID, keyData: key) + sendSMTP(mail: mail, callback: callback) } func sendTravelRepeal(to addr: String, keyID: String, sharedSecret: String, callback: @escaping (Error?) -> Void) { - let useraddr = (UserManager.loadUserValue(Attribute.userAddr) as! String) + /*let useraddr = (UserManager.loadUserValue(Attribute.userAddr) as! String) let session = createSMTPSession() let builder = MCOMessageBuilder() - let userID: MCOAddress = MCOAddress(displayName: useraddr, mailbox: useraddr) + let userID: MCOAddress = MCOAddress(displayName: useraddr, mailbox: useraddr)*/ - createHeader(builder, toEntrys: [addr], ccEntrys: [], bccEntrys: [], subject: "Travel Message", autocrypt: true) //TODO: rename subject to 'Repeal Key Message' ? + let mail = OutgoingMail.createTravelRepeal(addr: addr, sharedSecret: sharedSecret) + //TODO: send mail - builder.addAttachment(MCOAttachment.init(text: "You are receiving this message, because the keypair it is signed with will soon be (temporary) disabled by its owner. The owner will be unable to decrypt messages encrypted with the keypair.\nTo be able to communicate securely after the keypair is disabled, you will receive a second message with a new keypair attached. To enable you to trust the new key at the same level as you do for the current key, a secret is attached in the end of this message (see SECRET). The message introducing the new keypair will have a secret attached too. ONLY if both secrets are equal AND there were no other messages introducing new keypairs in the meanwhile you can trust the new keypair!\n\nPlease do not send a message using the current keypair anymore, since it is decativated now.\n\nFor more information visit: "+TravelHandler.website+"\n\nThis Message was automatically generated by my Letterbox email client.\n\nSECRET:\n"+sharedSecret)) - - let filename = "repeal.txt" //TODO: renmae to secret.txt? - if let keyAttachment = MCOAttachment.init(contentsOfFile: filename){ - keyAttachment.mimeType = TravelHandler.callForRepealMimeType - keyAttachment.setContentTypeParameterValue("UTF-8", forName: "charset") - keyAttachment.setContentTypeParameterValue(filename, forName: "name") - keyAttachment.filename = filename - keyAttachment.data = sharedSecret.data(using: .utf8) - builder.addAttachment(keyAttachment) - } -// if let keyAttachment = MCOAttachment.init(text: sharedSecret){ -// builder.addAttachment(keyAttachment) -// } - - let data = builder.dataForEncryption() + /*let data = builder.dataForEncryption() let message = String(data: data!, encoding: .utf8)! let pgp = SwiftPGP() @@ -323,49 +108,23 @@ class MailHandler { return } callback(nil) - }) + })*/ } - + func sendTravelCallForUse(to addr: String, sharedSecret: String, pubKey: String, keyID: String, repealedKeyFingerprint: String, callback: @escaping (Error?) -> Void) { let useraddr = (UserManager.loadUserValue(Attribute.userAddr) as! String) let session = createSMTPSession() let builder = MCOMessageBuilder() let userID: MCOAddress = MCOAddress(displayName: useraddr, mailbox: useraddr) - //do not use autocrypt to be able to parse new key as related to the prevoius one - createHeader(builder, toEntrys: [addr], ccEntrys: [], bccEntrys: [], subject: "Travel Message", autocrypt: false) //TODO: rename subject to 'Call for use Key Message' ? - - builder.addAttachment(MCOAttachment.init(text: "This message introduces the senders new keypair. You can trust this key in the same level as you did with the last valid key if and ONLY IF the attached secret (see SECRET) matches with the secret attached to the previous 'Travel Message' asking to repeal the senders keypair.\n\nFor more information visit: "+TravelHandler.website+"\n\nThis Message was automatically generated by my Letterbox email client.\n\nSECRET:\n"+sharedSecret)) - - - if let keyAttachment = MCOAttachment.init(text: pubKey){ - builder.addAttachment(keyAttachment) - } - - var filename = "callForUse.txt" //TODO: rename to secret.txt? - if let keyAttachment = MCOAttachment.init(contentsOfFile: filename){ - keyAttachment.mimeType = TravelHandler.callForUseMimeType - keyAttachment.setContentTypeParameterValue("UTF-8", forName: "charset") - keyAttachment.setContentTypeParameterValue(filename, forName: "name") - keyAttachment.filename = filename - keyAttachment.data = (TravelHandler.callForUseSecretHeader+sharedSecret+"\n"+TravelHandler.callForUseFingerprintHeader+repealedKeyFingerprint).data(using: .utf8) - builder.addAttachment(keyAttachment) - } - filename = keyID+".asc.asc" //have a look at MailHandler.sendSecretKey() - if let keyAttachment = MCOAttachment.init(contentsOfFile: filename){ - keyAttachment.mimeType = "application/pgp-keys" - keyAttachment.setContentTypeParameterValue("UTF-8", forName: "charset") - keyAttachment.setContentTypeParameterValue(filename, forName: "name") - keyAttachment.filename = filename - keyAttachment.data = pubKey.data(using: .utf8) - builder.addAttachment(keyAttachment) - } + OutgoingMail.createTravelCallForUse(addr: addr, sharedSecret: sharedSecret, pubKey: pubKey, keyID: keyID, repealedKeyFingerprint: repealedKeyFingerprint) + //TODO: send - let data = builder.dataForEncryption() + /*let data = builder.dataForEncryption() let message = String(data: data!, encoding: .utf8)! let pgp = SwiftPGP() - + //since it is checked in Travel.prepare before there are objects stored, we can safly force unwrap here let adr = DataHandler.handler.findMailAddress(adr: addr)! let cryptoObject = pgp.encrypt(plaintext: message, ids: [adr.primaryKey!.keyID], myId: keyID) @@ -379,11 +138,14 @@ class MailHandler { return } callback(nil) - }) + })*/ } func sendTravelBackup(to addr: String, encryptedWith keyID: String, keyPair: String, keyPairKeyID: String, callback: @escaping (Error?) -> Void) { - let useraddr = (UserManager.loadUserValue(Attribute.userAddr) as! String) + //TODO: convert to OutgoingMail + + + /*let useraddr = (UserManager.loadUserValue(Attribute.userAddr) as! String) let session = createSMTPSession() let builder = MCOMessageBuilder() let userID: MCOAddress = MCOAddress(displayName: useraddr, mailbox: useraddr) @@ -428,386 +190,257 @@ class MailHandler { return } callback(nil) - }) } + })*/ + } - func send(_ toEntrys: [String], ccEntrys: [String], bccEntrys: [String], subject: String, message: String, sendEncryptedIfPossible: Bool = true, callback: @escaping (Error?) -> Void, loggingMail: Bool = false, htmlContent: String? = nil, warningReact: Bool = false, inviteMail: Bool = false, textparts: Int = 0) { - if let useraddr = (UserManager.loadUserValue(Attribute.userAddr) as? String) { - let session = createSMTPSession() - let builder = MCOMessageBuilder() - - createHeader(builder, toEntrys: toEntrys, ccEntrys: ccEntrys, bccEntrys: bccEntrys, subject: subject) - - var allRec: [String] = [] - allRec.append(contentsOf: toEntrys) - allRec.append(contentsOf: ccEntrys) - allRec.append(contentsOf: bccEntrys) - - let fromLogging: Mail_Address = DataHandler.handler.getMailAddress(useraddr, temporary: false) as! Mail_Address - var toLogging: [Mail_Address] = [] - var ccLogging: [Mail_Address] = [] - var bccLogging: [Mail_Address] = [] - - for entry in toEntrys { - toLogging.append(DataHandler.handler.getMailAddress(entry, temporary: false) as! Mail_Address) - } - for entry in ccEntrys { - ccLogging.append(DataHandler.handler.getMailAddress(entry, temporary: false) as! Mail_Address) - } - for entry in bccEntrys { - bccLogging.append(DataHandler.handler.getMailAddress(entry, temporary: false) as! Mail_Address) - } - - let sk = DataHandler.handler.prefSecretKey() - - var ordered: [CryptoScheme: [MCOAddress]] = [:] - if let sk = sk { - ordered = orderReceiver(receiver: allRec, sendEncryptedIfPossible: sendEncryptedIfPossible) - } else { - ordered = orderReceiver(receiver: allRec, sendEncryptedIfPossible: false) - //TODO: maybe we should send a response to the caller here! This case should only happen, when TravelHandler.instance().mode == .borderCrossing + func sendSMTP(mail: OutgoingMail, callback: ((MailServerConnectionError?) -> Void)?) { + guard AppDelegate.getAppDelegate().currentReachabilityStatus != .notReachable else { + if let call = callback { + call(MailServerConnectionError.NoInternetconnection) } - - let userID = MCOAddress(displayName: useraddr, mailbox: useraddr) -// let sk = DataHandler.handler.prefSecretKey() - - var sendData: Data - var sendOperation: MCOSMTPSendOperation - let pgp = SwiftPGP() - - if let encPGP = ordered[CryptoScheme.PGP], encPGP.count > 0, let sk = sk { - var keyIDs = addKeys(adrs: encPGP) - // added own public key here, so we can decrypt our own message to read it in sent-folder - keyIDs.append(sk.keyID!) - /* - Attach own public key - */ - var missingOwnPublic = false - for id in keyIDs { - if let key = DataHandler.handler.findKey(keyID: id) { - if !key.sentOwnPublicKey { - missingOwnPublic = true - key.sentOwnPublicKey = true - } - } - } - - var msg = message - if missingOwnPublic { - if let myPK = pgp.exportKey(id: sk.keyID!, isSecretkey: false, autocrypt: false) { - msg = msg + "\n" + myPK - } - } - - let cryptoObject = pgp.encrypt(plaintext: "\n" + msg, ids: keyIDs, myId: sk.keyID!) - if let encData = cryptoObject.chiphertext { - sendData = encData - if Logger.logging && !loggingMail { - let secureAddrsInString = encPGP.map { $0.mailbox } - var secureAddresses: [Mail_Address] = [] - for addr in toLogging+ccLogging+bccLogging { - for sec in secureAddrsInString { - if addr.address == sec { - secureAddresses.append(addr) - } - } - } - var inviteMailContent: String? = nil - if inviteMail { - inviteMailContent = textparts.description - } - Logger.log(sent: fromLogging, to: toLogging, cc: ccLogging, bcc: bccLogging, subject: subject, bodyLength: (String(data: cryptoObject.chiphertext!, encoding: String.Encoding.utf8) ?? "").count, isEncrypted: true, decryptedBodyLength: ("\n" + message).count, decryptedWithOldPrivateKey: false, isSigned: true, isCorrectlySigned: true, signingKeyID: sk.keyID!, myKeyID: sk.keyID!, secureAddresses: secureAddresses, encryptedForKeyIDs: keyIDs, inviteMailContent: inviteMailContent, invitationMail: inviteMail) - } - - sendOperation = session.sendOperation(with: builder.openPGPEncryptedMessageData(withEncryptedData: sendData), from: userID, recipients: encPGP) - sendOperation.start(callback) - if (ordered[CryptoScheme.UNKNOWN] == nil || ordered[CryptoScheme.UNKNOWN]!.count == 0) && !loggingMail { - createSendCopy(sendData: builder.openPGPEncryptedMessageData(withEncryptedData: sendData)) - } - if Logger.logging && loggingMail { - createLoggingSendCopy(sendData: builder.openPGPEncryptedMessageData(withEncryptedData: sendData)) - } - } else { - callback(NSError(domain: NSCocoaErrorDomain, code: NSPropertyListReadCorruptError, userInfo: nil)) - } - } - - if let unenc = ordered[CryptoScheme.UNKNOWN], !loggingMail { - if unenc.count > 0 { - if let html = htmlContent { - builder.htmlBody = html - } else { - builder.textBody = message - } + return + } + let session = createSMTPSession() - sendData = builder.data() - sendOperation = session.sendOperation(with: sendData, from: userID, recipients: unenc) - if unenc.count == allRec.count && !loggingMail { - var inviteMailContent: String? = nil - if inviteMail { - inviteMailContent = textparts.description - } - Logger.log(sent: fromLogging, to: toLogging, cc: ccLogging, bcc: bccLogging, subject: subject, bodyLength: ("\n" + message).count, isEncrypted: false, decryptedBodyLength: ("\n" + message).count, decryptedWithOldPrivateKey: false, isSigned: false, isCorrectlySigned: false, signingKeyID: "", myKeyID: "", secureAddresses: [], encryptedForKeyIDs: [], inviteMailContent: inviteMailContent, invitationMail: inviteMail) + var sent = false + if mail.encReceivers.count > 0 { + let data = mail.pgpData + if let sendOperation = session.sendOperation(with: data, from: mail.sender, recipients: mail.encReceivers){ + sendOperation.start({ error in + guard error == nil else { + let connerror = MailServerConnectionError.findErrorCode(error: error!) + self.errorhandling(error: connerror, originalCall: {self.sendSMTP(mail: mail, callback: callback)}, completionCallback: callback) + return } - sendOperation.start(callback) - if !loggingMail { - createSendCopy(sendData: sendData) + if let callback = callback{ + callback(nil) } - } - } - - if let encPGP = ordered[CryptoScheme.PGP], encPGP.count > 0 { - } else if let unenc = ordered[CryptoScheme.UNKNOWN], unenc.count > 0, !loggingMail { - } else { - let error = NSError.init(domain: MCOErrorDomain, code: MCOErrorCode.sendMessage.rawValue, userInfo: nil) as Error - callback(error) + }) + sent = true } - } else { - let error = NSError.init(domain: MCOErrorDomain, code: MCOErrorCode.sendMessage.rawValue, userInfo: nil) as Error - callback(error) } - } - - fileprivate func createSendCopy(sendData: Data) { - let sentFolder = UserManager.backendSentFolderPath - if !DataHandler.handler.existsFolder(with: sentFolder) { - let op = IMAPSession.createFolderOperation(sentFolder) - op?.start({ error in - guard error == nil else { - self.errorhandling(error: error, originalCall: {self.createSendCopy(sendData: sendData)}, completionCallback: nil) - return - } - let op = self.IMAPSession.appendMessageOperation(withFolder: sentFolder, messageData: sendData, flags: MCOMessageFlag.mdnSent) - op?.start({ error, _ in + if mail.plainReceivers.count > 0 { + if let sendOperation = session.sendOperation(with: mail.plainData, from: mail.sender, recipients: mail.plainReceivers) { + sendOperation.start({error in guard error == nil else { - self.errorhandling(error: error, originalCall: {self.createSendCopy(sendData: sendData)}, completionCallback: nil) + let connerror = MailServerConnectionError.findErrorCode(error: error!) + self.errorhandling(error: connerror, originalCall: {self.sendSMTP(mail: mail, callback: callback)}, completionCallback: callback) return } + if let callback = callback{ + callback(nil) + } }) - }) - } else { - let op = IMAPSession.appendMessageOperation(withFolder: sentFolder, messageData: sendData, flags: MCOMessageFlag.mdnSent) - op?.start({ error, _ in - guard error == nil else { - self.errorhandling(error: error, originalCall: {self.createSendCopy(sendData: sendData)}, completionCallback: nil) - return - } - }) + sent = true + } + } + if sent { + _ = mail.logMail() + var copyFolder = UserManager.backendSentFolderPath + if mail.loggingMail { + copyFolder = UserManager.loadUserValue(.loggingFolderPath) as! String + } + //TODO Maybe we should consider a connection error. + self.storeIMAP(mail: mail, folder: copyFolder, callback: nil) + } + else if let callback = callback{ + callback(nil) } } - - fileprivate func createLoggingSendCopy(sendData: Data) { - let sentFolder = UserManager.loadUserValue(.loggingFolderPath) as! String - if !DataHandler.handler.existsFolder(with: sentFolder) { - let op = IMAPSession.createFolderOperation(sentFolder) - op?.start({ error in - guard error == nil else { - self.errorhandling(error: error, originalCall: {self.createLoggingSendCopy(sendData: sendData)}, completionCallback: nil) - return - } - let op = self.IMAPSession.appendMessageOperation(withFolder: sentFolder, messageData: sendData, flags: MCOMessageFlag.mdnSent) - op?.start({ error, _ in + + + + + func storeIMAP(mail: OutgoingMail, folder: String, callback: ((MailServerConnectionError?) -> Void)?) { + // 1. Test if folder exists + // TODO: Does this really work? Should we test if folder exits on server and not locally? -> Ask Jakob + if !DataHandler.handler.existsFolder(with: folder) { + if let op = IMAPSession?.createFolderOperation(folder) { + op.start({ error in guard error == nil else { - self.errorhandling(error: error, originalCall: {self.createLoggingSendCopy(sendData: sendData)}, completionCallback: nil) + let connerror = MailServerConnectionError.findErrorCode(error: error!) + self.errorhandling(error: connerror, originalCall: {self.storeIMAP(mail: mail, folder: folder, callback: callback)}, completionCallback: callback) + self.IMAPSes = nil return } + // Create folder on local + _ = DataHandler.handler.findFolder(with: folder) + self.storeIMAP(mail: mail, folder: folder, callback: callback) }) - }) - } else { - let op = IMAPSession.appendMessageOperation(withFolder: sentFolder, messageData: sendData, flags: MCOMessageFlag.mdnSent) + } + } + else { + // 2. Store Mail in test + // We can always store encrypted data on the imap server because the user has a key pair and it is users imap account. + let op = self.IMAPSession?.appendMessageOperation(withFolder: folder, messageData: mail.pgpData, flags: MCOMessageFlag.mdnSent) op?.start({ error, _ in guard error == nil else { - self.errorhandling(error: error, originalCall: {self.createLoggingSendCopy(sendData: sendData)}, completionCallback: nil) + let connerror = MailServerConnectionError.findErrorCode(error: error!) + self.errorhandling(error: connerror, originalCall: {self.storeIMAP(mail: mail, folder: folder, callback: callback)}, completionCallback: callback) + self.IMAPSes = nil return } + if let callback = callback { + callback(nil) + } }) } } - - func createDraft(_ toEntrys: [String], ccEntrys: [String], bccEntrys: [String], subject: String, message: String, callback: @escaping (Error?) -> Void) { - let builder = MCOMessageBuilder() - - createHeader(builder, toEntrys: toEntrys, ccEntrys: ccEntrys, bccEntrys: bccEntrys, subject: subject) - - var allRec: [String] = [] - allRec.append(contentsOf: toEntrys) - allRec.append(contentsOf: ccEntrys) - // What about BCC?? - - var sendData: Data - - let pgp = SwiftPGP() - if allRec.reduce(true, { $0 && DataHandler.handler.hasKey(adr: $1) }), let mykey = DataHandler.handler.prefSecretKey() { - let receiverIds = [mykey.keyID] as! [String] - if Logger.logging { - var to: [Mail_Address?] = [] - for addr in toEntrys { - to.append(DataHandler.handler.findMailAddress(adr: addr)) - } - - var cc: [Mail_Address?] = [] - for addr in ccEntrys { - cc.append(DataHandler.handler.findMailAddress(adr: addr)) - } - - var bcc: [Mail_Address?] = [] - for addr in bccEntrys { - bcc.append(DataHandler.handler.findMailAddress(adr: addr)) - } - Logger.log(createDraft: to, cc: cc, bcc: bcc, subject: subject, bodyLength: message.count, isEncrypted: true, isSigned: true, myKeyID: mykey.keyID ?? "") - } - let cryptoObject = pgp.encrypt(plaintext: "\n" + message, ids: receiverIds, myId: mykey.keyID!) - if let encData = cryptoObject.chiphertext { - sendData = builder.openPGPEncryptedMessageData(withEncryptedData: encData) - - let drafts = UserManager.backendDraftFolderPath - - if !DataHandler.handler.existsFolder(with: drafts) { - let op = IMAPSession.createFolderOperation(drafts) - op?.start({ error in - guard error == nil else { - self.errorhandling(error: error, originalCall: {self.createDraft(toEntrys, ccEntrys: ccEntrys, bccEntrys: bccEntrys, subject: subject, message: message, callback: callback)}, completionCallback: nil) - return - } - self.saveDraft(data: sendData, callback: callback) }) - } else { - saveDraft(data: sendData, callback: callback) - } - } else { - callback(NSError(domain: NSCocoaErrorDomain, code: NSPropertyListReadCorruptError, userInfo: nil)) - } - } else { - if Logger.logging { - var to: [Mail_Address?] = [] - for addr in toEntrys { - to.append(DataHandler.handler.findMailAddress(adr: addr)) - } - - var cc: [Mail_Address?] = [] - for addr in ccEntrys { - cc.append(DataHandler.handler.findMailAddress(adr: addr)) - } - - var bcc: [Mail_Address?] = [] - for addr in bccEntrys { - bcc.append(DataHandler.handler.findMailAddress(adr: addr)) - } - Logger.log(createDraft: to, cc: cc, bcc: bcc, subject: subject, bodyLength: message.count, isEncrypted: false, isSigned: false, myKeyID: "") - } - builder.textBody = message - sendData = builder.data() - - let drafts = UserManager.backendDraftFolderPath - - if !DataHandler.handler.existsFolder(with: drafts) { - let op = IMAPSession.createFolderOperation(drafts) - op?.start({ error in - guard error == nil else { - self.errorhandling(error: error, originalCall: {self.createDraft(toEntrys, ccEntrys: ccEntrys, bccEntrys: bccEntrys, subject: subject, message: message, callback: callback)}, completionCallback: nil) - return - } - self.saveDraft(data: sendData, callback: callback) }) - } else { - saveDraft(data: sendData, callback: callback) - } + + func send(_ toEntrys: [String], ccEntrys: [String], bccEntrys: [String], subject: String, message: String, sendEncryptedIfPossible: Bool = true, callback: ((MailServerConnectionError?) -> Void)?, loggingMail: Bool = false, htmlContent: String? = nil, warningReact: Bool = false, inviteMail: Bool = false, textparts: Int = 0) { + let mail: OutgoingMail + if inviteMail { + mail = OutgoingMail.createInvitationMail(toEntrys: toEntrys, ccEntrys: ccEntrys, bccEntrys: bccEntrys, subject: subject, textContent: message, htmlContent: htmlContent) + } + else { + mail = OutgoingMail(toEntrys: toEntrys, ccEntrys: ccEntrys, bccEntrys: bccEntrys, subject: subject, textContent: message, htmlContent: htmlContent, textparts: textparts, sendEncryptedIfPossible: sendEncryptedIfPossible) } + DataHandler.handler.addOutgoingMail(mail: mail) } - fileprivate func saveDraft(data: Data, callback: @escaping (Error?) -> Void) { - let op = IMAPSession.appendMessageOperation(withFolder: UserManager.backendDraftFolderPath, messageData: data, flags: MCOMessageFlag.draft) - op?.start({ error, _ in - guard error == nil else { - self.errorhandling(error: error, originalCall: {self.saveDraft(data: data, callback: callback)}, completionCallback: callback) - return - } - callback(nil) - - }) + func createDraft(_ toEntrys: [String], ccEntrys: [String], bccEntrys: [String], subject: String, message: String, callback: @escaping (MailServerConnectionError?) -> Void) { + let mail = OutgoingMail.createDraft(toEntrys: toEntrys, ccEntrys: ccEntrys, bccEntrys: bccEntrys, subject: subject, textContent: message, htmlContent: nil) + let folder = UserManager.backendDraftFolderPath + self.storeIMAP(mail: mail, folder: folder, callback: callback) + _ = mail.logMail() } - - private func setupIMAPSession() -> MCOIMAPSession { + private func setupIMAPSession() throws -> MCOIMAPSession{ + var allData = true let imapsession = MCOIMAPSession() + imapsession.isCheckCertificateEnabled = true if let hostname = UserManager.loadUserValue(Attribute.imapHostname) as? String { imapsession.hostname = hostname } + else { + allData = false + } if let port = UserManager.loadUserValue(Attribute.imapPort) as? UInt32 { imapsession.port = port } + else { + allData = false + } if let username = UserManager.loadUserValue(Attribute.userAddr) as? String { imapsession.username = username } - imapsession.authType = UserManager.loadImapAuthType() + else { + allData = false + } + if let authType = UserManager.loadUserValue(.imapAuthType) as? Int { + imapsession.authType = MCOAuthType(rawValue: authType) + } + else { + allData = false + } - if UserManager.loadImapAuthType() == MCOAuthType.xoAuth2 { + if imapsession.authType == MCOAuthType.xoAuth2 { imapsession.oAuth2Token = EmailHelper.singleton().authorization?.authState.lastTokenResponse?.accessToken } else if let pw = UserManager.loadUserValue(Attribute.userPW) as? String { imapsession.password = pw } + else { + allData = false + } if let connType = UserManager.loadUserValue(Attribute.imapConnectionType) as? Int { imapsession.connectionType = MCOConnectionType(rawValue: connType) } + else { + allData = false + } + if !allData { + throw MailServerConnectionError.NoData + } return imapsession } - func startIMAPIdleIfSupported() { + func startIMAPIdleIfSupported() throws{ if let supported = IMAPIdleSupported { if supported && IMAPIdleSession == nil { - IMAPIdleSession = setupIMAPSession() - let op = IMAPIdleSession!.idleOperation(withFolder: INBOX, lastKnownUID: UInt32(DataHandler.handler.findFolder(with: INBOX).maxID)) + IMAPIdleSession = try setupIMAPSession() + + //IDLE for Inbox + let op = IMAPIdleSession!.idleOperation(withFolder: MailHandler.INBOX, lastKnownUID: UInt32(DataHandler.handler.findFolder(with: MailHandler.INBOX).maxID)) op?.start({ error in guard error == nil else { - self.errorhandling(error: error, originalCall: {self.startIMAPIdleIfSupported()}, completionCallback: nil) + let connerror = MailServerConnectionError.findErrorCode(error: error!) + self.errorhandling(error: connerror, originalCall: {do { + try self.startIMAPIdleIfSupported() + } catch{} + }, completionCallback: nil) return } self.IMAPIdleSession = nil - let folder = DataHandler.handler.findFolder(with: self.INBOX) + let folder = DataHandler.handler.findFolder(with: MailHandler.INBOX) self.updateFolder(folder: folder, completionCallback: { error in guard error == nil else { - self.errorhandling(error: error, originalCall: {self.startIMAPIdleIfSupported()}, completionCallback: nil) + self.errorhandling(error: error, originalCall: {do { + try self.startIMAPIdleIfSupported() + } catch{}}, completionCallback: nil) return } - self.startIMAPIdleIfSupported() }) + do { + try self.startIMAPIdleIfSupported() + } catch{} }) }) + + //IDLE for Travel-Keymanagement folder let op2 = IMAPIdleSession!.idleOperation(withFolder: TravelHandler.keyManagementFolder, lastKnownUID: UInt32(DataHandler.handler.findFolder(with: TravelHandler.keyManagementFolder).maxID)) op2?.start({ error in guard error == nil else { - self.errorhandling(error: error, originalCall: {self.startIMAPIdleIfSupported()}, completionCallback: nil) + let connerror = MailServerConnectionError.findErrorCode(error: error!) + self.errorhandling(error: connerror, originalCall: {do { + try self.startIMAPIdleIfSupported() + } catch{} + }, completionCallback: nil) return } self.IMAPIdleSession = nil let folder = DataHandler.handler.findFolder(with: TravelHandler.keyManagementFolder) self.updateFolder(folder: folder, completionCallback: { error in guard error == nil else { - self.errorhandling(error: error, originalCall: {self.startIMAPIdleIfSupported()}, completionCallback: nil) + self.errorhandling(error: error, originalCall: {do { + try self.startIMAPIdleIfSupported() + } catch{}}, completionCallback: nil) return } - self.startIMAPIdleIfSupported() }) + do { + try self.startIMAPIdleIfSupported() + } catch{} }) }) } } else { - checkIdleSupport() + try checkIdleSupport() } } - private func checkIdleSupport() { - let op = setupIMAPSession().capabilityOperation() + private func checkIdleSupport() throws{ + let op = try setupIMAPSession().capabilityOperation() op?.start({ (error, capabilities) in guard error == nil else { - self.errorhandling(error: error, originalCall: {self.checkIdleSupport()}, completionCallback: nil) + let connerror = MailServerConnectionError.findErrorCode(error: error!) + self.errorhandling(error: connerror, originalCall: { + do { + try self.checkIdleSupport() + }catch{}}, completionCallback: nil) return } if let c = capabilities { self.IMAPIdleSupported = c.contains(UInt64(MCOIMAPCapability.idle.rawValue)) - self.startIMAPIdleIfSupported() + do { + try self.startIMAPIdleIfSupported() + }catch{} } }) } fileprivate func createSMTPSession() -> MCOSMTPSession { let session = MCOSMTPSession() - session.authType = UserManager.loadSmtpAuthType() - if UserManager.loadSmtpAuthType() == MCOAuthType.xoAuth2 { + if let authType = UserManager.loadUserValue(.smtpAuthType) as? Int { + session.authType = MCOAuthType(rawValue: authType) + } + if session.authType == MCOAuthType.xoAuth2 { if let lastToken = EmailHelper.singleton().authorization?.authState.lastTokenResponse { session.oAuth2Token = lastToken.accessToken } @@ -817,38 +450,46 @@ class MailHandler { session.hostname = UserManager.loadUserValue(Attribute.smtpHostname) as! String session.port = UInt32(UserManager.loadUserValue(Attribute.smtpPort) as! Int) session.username = UserManager.loadUserValue(Attribute.userAddr) as! String - session.authType = UserManager.loadSmtpAuthType() session.connectionType = MCOConnectionType(rawValue: UserManager.loadUserValue(Attribute.smtpConnectionType) as! Int) return session } - func addFlag(_ uid: UInt64, flags: MCOMessageFlag, folder: String?) { - var folderName = INBOX - if let folder = folder { - folderName = folder - } + func setFlag(_ uid: UInt64, flags: MCOMessageFlag, folder: String = INBOX) { + changeFlag(uid: uid, flags: flags, kind: MCOIMAPStoreFlagsRequestKind.set, folderName: folder) + } + func removeFlag(_ uid: UInt64, flags: MCOMessageFlag, folder: String = INBOX) { + changeFlag(uid: uid, flags: flags, kind: MCOIMAPStoreFlagsRequestKind.remove, folderName: folder) + } + + private func changeFlag(uid: UInt64, flags: MCOMessageFlag, kind: MCOIMAPStoreFlagsRequestKind, folderName: String){ + guard IMAPSession != nil else { + return + } let f = DataHandler.handler.findFolder(with: folderName) - let folderstatus = IMAPSession.folderStatusOperation(folderName) + let folderstatus = IMAPSession?.folderStatusOperation(folderName) folderstatus?.start { (error, status) -> Void in guard error == nil else { - self.errorhandling(error: error, originalCall: {self.addFlag(uid, flags: flags, folder: folderName)}, completionCallback: nil) + let conerror = MailServerConnectionError.findErrorCode(error: error!) + self.errorhandling(error: conerror, originalCall: {self.changeFlag(uid: uid, flags: flags, kind: kind, folderName: folderName)}, completionCallback: nil) return } if let status = status { let uidValidity = status.uidValidity if uidValidity == f.uidvalidity { - let op = self.IMAPSession.storeFlagsOperation(withFolder: folderName, uids: MCOIndexSet.init(index: uid), kind: MCOIMAPStoreFlagsRequestKind.set, flags: flags) + let op = self.IMAPSession?.storeFlagsOperation(withFolder: folderName, uids: MCOIndexSet.init(index: uid), kind: kind, flags: flags) op?.start { error -> Void in guard error == nil else { - self.errorhandling(error: error, originalCall: {self.addFlag(uid, flags: flags, folder: folderName)}, completionCallback: nil) + let conerror = MailServerConnectionError.findErrorCode(error: error!) + self.errorhandling(error: conerror, originalCall: {self.changeFlag(uid: uid, flags: flags, kind: kind, folderName: folderName)}, completionCallback: nil) return } - if flags.contains(MCOMessageFlag.deleted) { - let operation = self.IMAPSession.expungeOperation(folderName) + if flags.contains(MCOMessageFlag.deleted) && kind == MCOIMAPStoreFlagsRequestKind.add { + let operation = self.IMAPSession?.expungeOperation(folderName) operation?.start({ err in guard err == nil else { - self.errorhandling(error: error, originalCall: {self.addFlag(uid, flags: flags, folder: folderName)}, completionCallback: nil) + let conerror = MailServerConnectionError.findErrorCode(error: error!) + self.errorhandling(error: conerror, originalCall: {self.changeFlag(uid: uid, flags: flags, kind: kind, folderName: folderName)}, completionCallback: nil) return } DataHandler.handler.deleteMail(with: uid) @@ -860,42 +501,17 @@ class MailHandler { } } - func removeFlag(_ uid: UInt64, flags: MCOMessageFlag, folder: String?) { - var folderName = INBOX - if let folder = folder { - folderName = folder - } - let f = DataHandler.handler.findFolder(with: folderName) - let folderstatus = IMAPSession.folderStatusOperation(folderName) - folderstatus?.start { (error, status) -> Void in - guard error == nil else { - self.errorhandling(error: error, originalCall: {self.removeFlag(uid, flags: flags, folder: folderName)}, completionCallback: nil) - return - } - if let status = status { - let uidValidity = status.uidValidity - if uidValidity == f.uidvalidity { - let op = self.IMAPSession.storeFlagsOperation(withFolder: folderName, uids: MCOIndexSet.init(index: uid), kind: MCOIMAPStoreFlagsRequestKind.remove, flags: flags) - - op?.start { error -> Void in - guard error == nil else { - self.errorhandling(error: error, originalCall: {self.removeFlag(uid, flags: flags, folder: folderName)}, completionCallback: nil) - return - } - } - } - } + func loadMailsForRecord(_ record: KeyRecord, folderPath: String, completionCallback: @escaping ((_ error: MailServerConnectionError?) -> ())) { + guard IMAPSession != nil else { + completionCallback(MailServerConnectionError.NoData) + return } - } - - - - func loadMailsForRecord(_ record: KeyRecord, folderPath: String, completionCallback: @escaping ((_ error: Error?) -> ())) { let folder = DataHandler.handler.findFolder(with: folderPath) - let folderstatus = IMAPSession.folderStatusOperation(folderPath) + let folderstatus = IMAPSession?.folderStatusOperation(folderPath) folderstatus?.start { (error, status) -> Void in guard error == nil else { - self.errorhandling(error: error, originalCall: {self.loadMailsForRecord(record, folderPath: folderPath, completionCallback: completionCallback)}, completionCallback: completionCallback) + let connerror = MailServerConnectionError.findErrorCode(error: error!) + self.errorhandling(error: connerror, originalCall: {self.loadMailsForRecord(record, folderPath: folderPath, completionCallback: completionCallback)}, completionCallback: completionCallback) return } if let status = status { @@ -907,11 +523,12 @@ class MailHandler { for adr in addresses { let searchExpr: MCOIMAPSearchExpression = MCOIMAPSearchExpression.search(from: adr.mailAddress) - let searchOperation: MCOIMAPSearchOperation = self.IMAPSession.searchExpressionOperation(withFolder: folderPath, expression: searchExpr) + let searchOperation: MCOIMAPSearchOperation = self.IMAPSession!.searchExpressionOperation(withFolder: folderPath, expression: searchExpr) searchOperation.start { (err, indices) -> Void in guard err == nil else { - self.errorhandling(error: err, originalCall: {self.loadMailsForRecord(record, folderPath: folderPath, completionCallback: completionCallback)}, completionCallback: completionCallback) + let connerror = MailServerConnectionError.findErrorCode(error: err!) + self.errorhandling(error: connerror, originalCall: {self.loadMailsForRecord(record, folderPath: folderPath, completionCallback: completionCallback)}, completionCallback: completionCallback) return } @@ -932,12 +549,17 @@ class MailHandler { } } - func loadMailsForInbox(completionCallback: @escaping ((_ error: Error?) -> ())) { - let folder = DataHandler.handler.findFolder(with: INBOX) - let folderstatus = IMAPSession.folderStatusOperation(folder.path) + func loadMailsForInbox(completionCallback: @escaping ((_ error: MailServerConnectionError?) -> ())) { + guard IMAPSession != nil else { + completionCallback(MailServerConnectionError.NoData) + return + } + let folder = DataHandler.handler.findFolder(with: MailHandler.INBOX) + let folderstatus = IMAPSession?.folderStatusOperation(folder.path) folderstatus?.start { (error, status) -> Void in guard error == nil else { - self.errorhandling(error: error, originalCall: {self.loadMailsForInbox(completionCallback: completionCallback)}, completionCallback: completionCallback) + let connerror = MailServerConnectionError.findErrorCode(error: error!) + self.errorhandling(error: connerror, originalCall: {self.loadMailsForInbox(completionCallback: completionCallback)}, completionCallback: completionCallback) return } if let status = status { @@ -949,8 +571,12 @@ class MailHandler { } func backgroundUpdate(completionCallback: @escaping (_ newMails: UInt32, _ completionHandler: @escaping (UIBackgroundFetchResult) -> Void) -> (), performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void){ - let folder = DataHandler.handler.findFolder(with: INBOX) - let folderstatus = IMAPSession.folderStatusOperation(folder.path) + guard IMAPSession != nil else { + completionCallback(0, completionHandler) + return + } + let folder = DataHandler.handler.findFolder(with: MailHandler.INBOX) + let folderstatus = IMAPSession?.folderStatusOperation(folder.path) // Work only in background thread.... var backgroundTaskID: Int? DispatchQueue.global(qos: .background).async { @@ -992,34 +618,43 @@ class MailHandler { } } - private func loadMessagesFromServer(_ uids: MCOIndexSet, folderPath: String, maxLoad: Int = MailHandler.MAXMAILS, record: KeyRecord?, completionCallback: @escaping ((_ error: Error?) -> ())) { + private func loadMessagesFromServer(_ uids: MCOIndexSet, folderPath: String, maxLoad: Int = MailHandler.MAXMAILS, record: KeyRecord?, completionCallback: @escaping ((_ error: MailServerConnectionError?) -> ())) { + guard IMAPSession != nil else { + completionCallback(MailServerConnectionError.NoData) + return + } let requestKind = MCOIMAPMessagesRequestKind(rawValue: MCOIMAPMessagesRequestKind.headers.rawValue | MCOIMAPMessagesRequestKind.flags.rawValue) - let fetchOperation: MCOIMAPFetchMessagesOperation = self.IMAPSession.fetchMessagesOperation(withFolder: folderPath, requestKind: requestKind, uids: uids) - fetchOperation.extraHeaders = [AUTOCRYPTHEADER, SETUPMESSAGE, TravelHandler.backupHeader] + let fetchOperation: MCOIMAPFetchMessagesOperation = self.IMAPSession!.fetchMessagesOperation(withFolder: folderPath, requestKind: requestKind, uids: uids) + fetchOperation.extraHeaders = MailHandler.extraHeaders + if uids.count() == 0 { completionCallback(nil) return } fetchOperation.start { (err, msg, vanished) -> Void in guard err == nil else { - self.errorhandling(error: err, originalCall: {self.loadMessagesFromServer(uids, folderPath: folderPath, maxLoad: maxLoad, record: record, completionCallback: completionCallback)}, completionCallback: completionCallback) + let connerror = MailServerConnectionError.findErrorCode(error: err!) + self.errorhandling(error: connerror, originalCall: {self.loadMessagesFromServer(uids, folderPath: folderPath, maxLoad: maxLoad, record: record, completionCallback: completionCallback)}, completionCallback: completionCallback) return } - var calledMails = 0 if let msgs = msg { let dispatchGroup = DispatchGroup() for m in msgs.reversed() { let message: MCOIMAPMessage = m as! MCOIMAPMessage dispatchGroup.enter() - - let op = self.IMAPSession.fetchParsedMessageOperation(withFolder: folderPath, uid: message.uid) + let op = self.IMAPSession?.fetchParsedMessageOperation(withFolder: folderPath, uid: message.uid) op?.start { err, data in guard err == nil else { - self.errorhandling(error: err, originalCall: {self.loadMessagesFromServer(uids, folderPath: folderPath, maxLoad: maxLoad, record: record, completionCallback: completionCallback)}, completionCallback: completionCallback) + let connerror = MailServerConnectionError.findErrorCode(error: err!) + self.errorhandling(error: connerror, originalCall: {self.loadMessagesFromServer(uids, folderPath: folderPath, maxLoad: maxLoad, record: record, completionCallback: completionCallback)}, completionCallback: completionCallback) return } - self.parseMail(parser: data, message: message, record: record, folderPath: folderPath) + if let parser = data { + let incomingMail = IncomingMail(rawData: parser.data(), uID: UInt64(message.uid), folderPath: folderPath, flags: message.flags) + _ = incomingMail.store(keyRecord: record) + + } dispatchGroup.leave() } calledMails += 1 @@ -1028,9 +663,10 @@ class MailHandler { } } dispatchGroup.notify(queue: DispatchQueue.main) { - self.IMAPSession.disconnectOperation().start({ err2 in + self.IMAPSession?.disconnectOperation().start({ err2 in guard err2 == nil else { - self.errorhandling(error: err2, originalCall: {self.loadMessagesFromServer(uids, folderPath: folderPath, maxLoad: maxLoad, record: record, completionCallback: completionCallback)}, completionCallback: completionCallback) + let connerror = MailServerConnectionError.findErrorCode(error: err2!) + self.errorhandling(error: connerror, originalCall: {self.loadMessagesFromServer(uids, folderPath: folderPath, maxLoad: maxLoad, record: record, completionCallback: completionCallback)}, completionCallback: completionCallback) return } }) @@ -1306,7 +942,7 @@ class MailHandler { return attachments } - private func parseMail(parser: MCOMessageParser?, message: MCOIMAPMessage, record: KeyRecord?, folderPath: String) { + /*private func parseMail(parser: MCOMessageParser?, message: MCOIMAPMessage, record: KeyRecord?, folderPath: String) { var moveToFolderPath: String? = nil var rec: [MCOAddress] = [] var cc: [MCOAddress] = [] @@ -1568,7 +1204,7 @@ class MailHandler { } } return nil - } + }*/ private func parsePublicKeys(attachment: MCOAttachment) -> [String] { var newKey = [String]() @@ -1620,7 +1256,7 @@ class MailHandler { return nil } - private func decryptText(body: String, from: MCOAddress?, autocrypt: AutocryptContact?) -> CryptoObject? { + private func decryptText(body: String, from: MCOAddress?, autocrypt: Autocrypt?) -> CryptoObject? { var sender: String? = nil if let fromMCO = from { sender = fromMCO.mailbox @@ -1646,52 +1282,87 @@ class MailHandler { } } - return pgp.decrypt(data: data, decryptionIDs: decIds, verifyIds: keyIds, fromAdr: sender) + return pgp.decrypt(data: data, decKeyIDs: decIds, signatureIDs: keyIds, fromAddr: sender ?? "") } return nil } - func checkSMTP(_ completion: @escaping (Error?) -> Void) { + func checkSMTP(_ completion: @escaping (MailServerConnectionError?) -> Void) { + if AppDelegate.getAppDelegate().currentReachabilityStatus == .notReachable { + completion(MailServerConnectionError.NoInternetconnection) + } let useraddr = UserManager.loadUserValue(Attribute.userAddr) as! String - let session = MCOSMTPSession() session.hostname = UserManager.loadUserValue(Attribute.smtpHostname) as! String session.port = UInt32(UserManager.loadUserValue(Attribute.smtpPort) as! Int) session.username = useraddr - if UserManager.loadSmtpAuthType() == MCOAuthType.xoAuth2 { + if let type = UserManager.loadUserValue(.smtpAuthType) as? Int { + session.authType = MCOAuthType(rawValue: type) + } + if session.authType == MCOAuthType.xoAuth2 { session.oAuth2Token = EmailHelper.singleton().authorization?.authState.lastTokenResponse?.accessToken } else if let pw = UserManager.loadUserValue(Attribute.userPW) as? String { session.password = pw } - session.authType = UserManager.loadSmtpAuthType() session.connectionType = MCOConnectionType.init(rawValue: UserManager.loadUserValue(Attribute.smtpConnectionType) as! Int) - - session.checkAccountOperationWith(from: MCOAddress.init(mailbox: useraddr)).start(completion) - + session.checkAccountOperationWith(from: MCOAddress.init(mailbox: useraddr)).start({(error: Error?) -> () in + if let error = error { + let conerror = MailServerConnectionError.findErrorCode(error: error) + completion(conerror) + } + else { + completion(nil) + } + }) } - func checkIMAP(_ completion: @escaping (Error?) -> Void) { - self.setupIMAPSession().checkAccountOperation().start(completion) + func checkIMAP(_ completion: @escaping (MailServerConnectionError?) -> Void) { + guard IMAPSession != nil else { + completion(MailServerConnectionError.NoData) + return + } + if AppDelegate.getAppDelegate().currentReachabilityStatus == .notReachable { + completion(MailServerConnectionError.NoInternetconnection) + } + do { + try self.setupIMAPSession().checkAccountOperation().start({(error: Error?) -> () in + if let error = error { + let conerror = MailServerConnectionError.findErrorCode(error: error) + completion(conerror) + } + else { + completion(nil) + } + }) + } catch { + completion(MailServerConnectionError.NoData) + } + } + func move(mails: [PersistentMail], from: String, to: String, folderCreated: Bool = false) { + guard IMAPSession != nil else { + return + } let uids = MCOIndexSet() - if !DataHandler.handler.existsFolder(with: to) && !folderCreated { - let op = IMAPSession.createFolderOperation(to) + let op = IMAPSession?.createFolderOperation(to) op?.start({ error in guard error == nil else { - self.errorhandling(error: error, originalCall: {self.move(mails: mails, from: from, to: to)}, completionCallback: nil) + let conError = MailServerConnectionError.findErrorCode(error: error!) + self.errorhandling(error: conError, originalCall: {self.move(mails: mails, from: from, to: to)}, completionCallback: nil) return } self.move(mails: mails, from: from, to: to, folderCreated: true) }) } else { - let folderstatusFrom = IMAPSession.folderStatusOperation(from) + let folderstatusFrom = IMAPSession?.folderStatusOperation(from) folderstatusFrom?.start { (error, status) -> Void in guard error == nil else { - self.errorhandling(error: error, originalCall: {self.move(mails: mails, from: from, to: to)}, completionCallback: nil) + let conerror = MailServerConnectionError.findErrorCode(error: error!) + self.errorhandling(error: conerror, originalCall: {self.move(mails: mails, from: from, to: to)}, completionCallback: nil) return } if let statusFrom = status { @@ -1711,21 +1382,22 @@ class MailHandler { DataHandler.handler.delete(mail: mail) } } - let op = self.IMAPSession.moveMessagesOperation(withFolder: from, uids: uids, destFolder: to) + let op = self.IMAPSession?.moveMessagesOperation(withFolder: from, uids: uids, destFolder: to) op?.start { (err, vanished) -> Void in guard err == nil else { - self.errorhandling(error: err, originalCall: {self.move(mails: mails, from: from, to: to)}, completionCallback: { err in + let conerror = MailServerConnectionError.findErrorCode(error: err!) + self.errorhandling(error: conerror, originalCall: {self.move(mails: mails, from: from, to: to)}, completionCallback: { err in guard err != nil else { return } - let op = self.IMAPSession.copyMessagesOperation(withFolder: from, uids: uids, destFolder: to) + let op = self.IMAPSession?.copyMessagesOperation(withFolder: from, uids: uids, destFolder: to) op?.start({error, _ in guard error == nil else { return } uids.enumerate({uid in - self.addFlag(uid, flags: MCOMessageFlag.deleted, folder: from) + self.setFlag(uid, flags: MCOMessageFlag.deleted, folder: from) }) }) }) @@ -1742,22 +1414,26 @@ class MailHandler { func allFolders(_ completion: @escaping (Error?, [Any]?) -> Void) { - let op = IMAPSession.fetchAllFoldersOperation() + guard IMAPSession != nil else { + completion(MailServerConnectionError.NoData, nil) + return + } + let op = IMAPSession?.fetchAllFoldersOperation() op?.start(completion) } - private func initFolder(folder: Folder, completionCallback: @escaping ((Error?) -> ())) { + private func initFolder(folder: Folder, completionCallback: @escaping ((MailServerConnectionError?) -> ())) { let folderPath = folder.path let requestKind = MCOIMAPMessagesRequestKind(rawValue: MCOIMAPMessagesRequestKind.headers.rawValue) let uids = MCOIndexSet(range: MCORangeMake(1, UINT64_MAX)) let toFetchIDs = MCOIndexSet() - - let fetchOperation: MCOIMAPFetchMessagesOperation = self.IMAPSession.fetchMessagesOperation(withFolder: folderPath, requestKind: requestKind, uids: uids) + let fetchOperation: MCOIMAPFetchMessagesOperation = self.IMAPSession!.fetchMessagesOperation(withFolder: folderPath, requestKind: requestKind, uids: uids) fetchOperation.start { (err, msg, vanished) -> Void in guard err == nil else { - self.errorhandling(error: err, originalCall: {self.initFolder(folder: folder, completionCallback: completionCallback)}, completionCallback: completionCallback) + let conerror = MailServerConnectionError.findErrorCode(error: err!) + self.errorhandling(error: conerror, originalCall: {self.initFolder(folder: folder, completionCallback: completionCallback)}, completionCallback: completionCallback) return } if let msgs = msg { @@ -1774,7 +1450,7 @@ class MailHandler { } } - private func initInbox(inbox: Folder, completionCallback: @escaping ((Error?) -> ())) { + private func initInbox(inbox: Folder, completionCallback: @escaping ((MailServerConnectionError?) -> ())) { if let date = Calendar.current.date(byAdding: .month, value: -1, to: Date()) { loadMailsSinceDate(folder: inbox, since: date, maxLoad: 100, completionCallback: completionCallback) } else { @@ -1783,18 +1459,22 @@ class MailHandler { } - func updateFolder(folder: Folder, completionCallback: @escaping ((Error?) -> ())) { - let folderstatus = IMAPSession.folderStatusOperation(folder.path) + func updateFolder(folder: Folder, completionCallback: @escaping ((MailServerConnectionError?) -> ())) { + guard IMAPSession != nil else { + completionCallback(MailServerConnectionError.NoData) + return + } + let folderstatus = IMAPSession?.folderStatusOperation(folder.path) folderstatus?.start { (error, status) -> Void in guard error == nil else { - self.errorhandling(error: error, originalCall: {self.updateFolder(folder: folder, completionCallback: completionCallback)}, completionCallback: completionCallback) + let conerror = MailServerConnectionError.findErrorCode(error: error!) + self.errorhandling(error: conerror, originalCall: {self.updateFolder(folder: folder, completionCallback: completionCallback)}, completionCallback: completionCallback) + self.IMAPSes = nil; return } if let status = status { let uidValidity = status.uidValidity folder.uidvalidity = uidValidity - - if let date = folder.lastUpdate { self.loadMailsSinceDate(folder: folder, since: date, completionCallback: completionCallback) } else { @@ -1808,7 +1488,11 @@ class MailHandler { } } - private func olderMails(folder: Folder, completionCallback: @escaping ((Error?) -> ())) { + private func olderMails(folder: Folder, completionCallback: @escaping ((MailServerConnectionError?) -> ())) { + guard IMAPSession != nil else { + completionCallback(MailServerConnectionError.NoData) + return + } let folderPath = folder.path if let mails = folder.mails { var oldestDate: Date? @@ -1821,15 +1505,16 @@ class MailHandler { } if let date = oldestDate { let searchExp = MCOIMAPSearchExpression.search(before: date) - let searchOperation = self.IMAPSession.searchExpressionOperation(withFolder: folderPath, expression: searchExp) - + let searchOperation = self.IMAPSession?.searchExpressionOperation(withFolder: folderPath, expression: searchExp) searchOperation?.start { (err, uids) -> Void in guard err == nil else { - self.errorhandling(error: err, originalCall: {self.olderMails(folder: folder, completionCallback: completionCallback)}, completionCallback: completionCallback) + let conerror = MailServerConnectionError.findErrorCode(error: err!) + self.errorhandling(error: conerror, originalCall: {self.olderMails(folder: folder, completionCallback: completionCallback)}, completionCallback: completionCallback) + self.IMAPSes = nil return } if let ids = uids { - folder.lastUpdate = Date() + //folder.lastUpdate = Date() self.loadMessagesFromServer(ids, folderPath: folderPath, record: nil, completionCallback: completionCallback) } else { completionCallback(nil) @@ -1841,18 +1526,21 @@ class MailHandler { } else { initFolder(folder: folder, completionCallback: completionCallback) } - } - - - private func loadMailsSinceDate(folder: Folder, since: Date, maxLoad: Int = MailHandler.MAXMAILS, completionCallback: @escaping ((Error?) -> ())) { + private func loadMailsSinceDate(folder: Folder, since: Date, maxLoad: Int = MailHandler.MAXMAILS, completionCallback: @escaping ((MailServerConnectionError?) -> ())) { + guard IMAPSession != nil else { + completionCallback(MailServerConnectionError.NoData) + return + } let folderPath = folder.path let searchExp = MCOIMAPSearchExpression.search(since: since) - let searchOperation = self.IMAPSession.searchExpressionOperation(withFolder: folderPath, expression: searchExp) + let searchOperation = self.IMAPSession?.searchExpressionOperation(withFolder: folderPath, expression: searchExp) searchOperation?.start { (err, uids) -> Void in guard err == nil else { - self.errorhandling(error: err, originalCall: {self.loadMailsSinceDate(folder: folder, since: since, completionCallback: completionCallback)}, completionCallback: completionCallback) + let conerror = MailServerConnectionError.findErrorCode(error: err!) + self.errorhandling(error: conerror, originalCall: {self.loadMailsSinceDate(folder: folder, since: since, completionCallback: completionCallback)}, completionCallback: completionCallback) + self.IMAPSes = nil return } if let ids = uids { @@ -1877,7 +1565,7 @@ class MailHandler { }) } - private func errorhandling(error: Error?, originalCall: @escaping () -> (), completionCallback: (((Error?) -> ()))?){ + private func errorhandling(error: MailServerConnectionError?, originalCall: @escaping () -> (), completionCallback: (((MailServerConnectionError?) -> ()))?){ // maybe refreshing oauth? if self.shouldTryRefreshOAUTH { self.retryWithRefreshedOAuth { diff --git a/enzevalos_iphone/MailServerConnectionError.swift b/enzevalos_iphone/MailServerConnectionError.swift new file mode 100644 index 0000000000000000000000000000000000000000..f93b3a404f59848703ae9aafb5f800b51548738c --- /dev/null +++ b/enzevalos_iphone/MailServerConnectionError.swift @@ -0,0 +1,151 @@ +// +// MailServerConnectionError.swift +// enzevalos_iphone +// +// Created by Oliver Wiese on 21.01.19. +// Copyright © 2019 fu-berlin. All rights reserved. +// + +import Foundation + +enum UserRecommandation: Int { + case CheckPWAddr = 1, + CheckIMAPServerConfig = 2, + CheckSMTPServerConfig = 3, + CheckSSLConfiguration = 4, + CheckOAUTH = 5 +} + +// see: https://github.com/MailCore/mailcore2/blob/31e308a36108301e2f9cc5c4489bb81ff84e6d3a/src/objc/abstract/MCOConstants.h +enum MailServerConnectionError: Error { + case NoError, ConnectionError, TLSNotAvailableError, ProtocolParseError, CertificateError, AuthenticationError, + GmailIMAPNotEnabledError, GmailExceededBandwidthLimitError, GmailTooManySimultaneousConnectionsError, MobileMeMovedError, + YahooUnavailableError, ImapIdleError, IdentityError, StartTLSNotAvailableError, AuthenticationRequiredError, + SMTPInvalidAccountError, ServerDateError, UnspecifiedError, StorageLimitSMTPError, NoInternetconnection, NoData + + var userRecommandations: [UserRecommandation] { + get { + var recommandations = [UserRecommandation] () + switch self { + case .NoError: + return recommandations + case .AuthenticationError: + recommandations.append(.CheckPWAddr) + return recommandations + case .ConnectionError, .NoData: + recommandations.append(.CheckIMAPServerConfig) + recommandations.append(.CheckSMTPServerConfig) + recommandations.append(.CheckSSLConfiguration) + recommandations.append(.CheckPWAddr) + return recommandations + case .TLSNotAvailableError, .CertificateError, .StartTLSNotAvailableError: + recommandations.append(.CheckSSLConfiguration) + return recommandations + case .ProtocolParseError, .ImapIdleError, .GmailTooManySimultaneousConnectionsError, .GmailExceededBandwidthLimitError, .IdentityError, .ServerDateError, .NoInternetconnection: + return recommandations + case .GmailIMAPNotEnabledError, .YahooUnavailableError: + recommandations.append(.CheckOAUTH) + return recommandations + case .AuthenticationRequiredError, .SMTPInvalidAccountError: + recommandations.append(.CheckPWAddr) + return recommandations + case .UnspecifiedError, .MobileMeMovedError, .StorageLimitSMTPError: + return recommandations + } + } + } + + var localizedUIBodyString: String { + get{ + let recom = self.userRecommandations + if recom.count == 1 && recom.contains(UserRecommandation.CheckPWAddr) { + return "MailServerError.Authentication.Body" + } + else if recom.count == 1 && recom.contains(UserRecommandation.CheckOAUTH) { + return "MailServerError.OAUTH.Body" + } + else if recom.count == 1 && recom.contains(UserRecommandation.CheckSSLConfiguration) { + return "MailServerError.Crypto.Body" + } + else if recom.contains(.CheckIMAPServerConfig) { + return "MailServerError.Connection.Body" + } + return "MailServerError.Default.Body" + } + } + + static func findPrioError(errors: Set<MailServerConnectionError>) -> MailServerConnectionError? { + if errors.contains(MailServerConnectionError.NoError) { + return MailServerConnectionError.NoError + } + if errors.contains(MailServerConnectionError.NoInternetconnection) { + return MailServerConnectionError.NoInternetconnection + } + if errors.contains(MailServerConnectionError.AuthenticationError) { + return MailServerConnectionError.AuthenticationError + } + if errors.contains(MailServerConnectionError.NoData) { + return MailServerConnectionError.NoData + } + return errors.first + } + + static func wrongServerConfig(errors: Set<MailServerConnectionError>) -> Bool { + if errors.contains(MailServerConnectionError.NoError) || errors.contains(MailServerConnectionError.AuthenticationError) || errors.contains(MailServerConnectionError.NoInternetconnection) { + return false + } + return true + } + + static func findErrorCode(error: Error) -> MailServerConnectionError { + let text = error.localizedDescription.uppercased() + let mscError: MailServerConnectionError + switch text { + case "A stable connection to the server could not be established.".uppercased(): + mscError = .ConnectionError + break + case "The server does not support TLS/SSL connections.".uppercased(): + mscError = .TLSNotAvailableError + break + case "Unable to parse response from server.".uppercased(): + mscError = .ProtocolParseError + break + case "The certificate for this server is invalid.".uppercased(): + mscError = .CertificateError + break + case "Unable to authenticate with the current session's credentials.".uppercased(): + mscError = .AuthenticationError + break + case "IMAP is not enabled for this Gmail account.".uppercased(): + mscError = .GmailIMAPNotEnabledError + break + case "Yahoo!'s servers are currently unavailable.".uppercased(): + mscError = .YahooUnavailableError + break + case "The server does not support STARTTLS connections.".uppercased(): + mscError = .StartTLSNotAvailableError + break + case "The SMTP storage limit was hit while trying to send a large message.".uppercased(): + mscError = .StorageLimitSMTPError + break + case "Authentication is required for this SMTP server.".uppercased(): + mscError = .AuthenticationRequiredError + break + case "Account check failed because the account is invalid.".uppercased(): + mscError = .SMTPInvalidAccountError + break + case "An error occurred during an IDLE operation.".uppercased(): + mscError = .ImapIdleError + break + default: + mscError = .UnspecifiedError + } + return mscError + } +} + + + + + + diff --git a/enzevalos_iphone/MailSession.swift b/enzevalos_iphone/MailSession.swift new file mode 100644 index 0000000000000000000000000000000000000000..46bea2b46e43944e5c372aec1eb7e4848f5bb23c --- /dev/null +++ b/enzevalos_iphone/MailSession.swift @@ -0,0 +1,539 @@ +// +// MailSessionConfiguration.swift +// enzevalos_iphone +// +// Created by Oliver Wiese on 26.02.19. +// Copyright © 2019 fu-berlin. All rights reserved. +// + +import Foundation + +enum SessionType { + case IMAP, SMTP +} + +class MailSession { + private static let SMTPPORT: [UInt32] = [587, 465, 25] + private static let SMTPPREFIX = ["smtp", "mail", "outgoing"] + + private static let IMAPPREFIX = ["mail", "imap"] + private static let IMAPPORT: [UInt32] = [143, 993] + + private static let AUTHTYPE = [MCOAuthType.saslPlain, MCOAuthType.saslLogin, MCOAuthType.SASLNTLM, MCOAuthType.saslKerberosV4, MCOAuthType.SASLCRAMMD5, MCOAuthType.SASLDIGESTMD5, MCOAuthType.SASLGSSAPI, MCOAuthType.SASLSRP, MCOAuthType.init(rawValue: 0)] + private static let CONNTECTIONTYPE = [MCOConnectionType.TLS, MCOConnectionType.startTLS] // We do not test for plain connections! + + private var sessionType: SessionType + private let mailAddr: String + private var username: String + private let password: String + + private var hostname: String? + private var port: UInt32? + private var connectionType: MCOConnectionType? + private var authType: MCOAuthType? + + private var counter = -1 + private var success = false + private var listeners: [MailSessionListener] = [MailSessionListener]() + + var pw: String { + get { + return password + } + } + + var portnumber: UInt32 { + get { + if let p = port { + return p + } + let (_,p,_,_) = loadFromProviderJson() + if let port = p { + return port + } + if sessionType == SessionType.IMAP { + if let p = Attribute.imapPort.defaultValue as? UInt32 { + return p + } + + return MailSession.IMAPPORT.first! + } + else { + if let p = Attribute.smtpPort.defaultValue as? UInt32 { + return p + } + return MailSession.SMTPPORT.first! + } + + } + } + + var servername: String { + get { + if let h = hostname { + return h + } + let (h,_,_,_) = loadFromProviderJson() + if let host = h{ + return host + } + if sessionType == SessionType.IMAP { + if let h = Attribute.imapHostname.defaultValue as? String { + return h + } + return "IMAP.EXAMPLE.COM" + } + else { + if let h = Attribute.smtpHostname.defaultValue as? String { + return h + } + return "SMTP.EXAMPLE.COM" + } + + } + } + + var name: String { + get { + return username + } + } + + var address: String { + get { + return mailAddr + } + } + + var serverAuthType: MCOAuthType { + get { + if let a = authType { + return a + } + let (_,_,_,auth) = loadFromProviderJson() + if let a = auth { + return a + } + if sessionType == SessionType.IMAP, let a = Attribute.imapAuthType.defaultValue as? Int { + return MCOAuthType.init(rawValue: a) + } + if sessionType == SessionType.SMTP, let a = Attribute.smtpAuthType.defaultValue as? Int { + return MCOAuthType.init(rawValue: a) + } + return MailSession.AUTHTYPE.first! + } + } + + var serverConnType: MCOConnectionType { + get { + if let a = connectionType { + return a + } + let (_,_,c,_) = loadFromProviderJson() + if let con = c { + return con + } + if sessionType == SessionType.IMAP, let a = Attribute.imapConnectionType.defaultValue as? Int { + return MCOConnectionType.init(rawValue: a) + } + if sessionType == SessionType.SMTP, let a = Attribute.smtpConnectionType.defaultValue as? Int { + return MCOConnectionType.init(rawValue: a) + } + return MailSession.CONNTECTIONTYPE.first! + } + } + + + var errors: Set<MailServerConnectionError> = Set() + + init(configSession sessionType: SessionType, mailAddress: String, password: String, username: String?) { + self.sessionType = sessionType + self.mailAddr = mailAddress + self.password = password + if let name = username { + self.username = name + } + else { + self.username = mailAddr + } + } + + init(loadUserDefaults sessionType: SessionType) throws{ + self.sessionType = sessionType + if let username = UserManager.loadUserValue(Attribute.userName) as? String { + self.username = username + }else { + throw MailServerConnectionError.AuthenticationError + } + if let pw = UserManager.loadUserValue(Attribute.userPW) as? String { + self.password = pw + }else { + throw MailServerConnectionError.AuthenticationError + } + if let addr = UserManager.loadUserValue(Attribute.userAddr) as? String { + mailAddr = addr + } else { + mailAddr = username + } + + _ = self.loadFromUserDefaults() + } + + func addListener(listener: MailSessionListener) { + listeners.append(listener) + } + + func testConfig(host: String, port: UInt32, authType: MCOAuthType, connType: MCOConnectionType) { + testServer(hostname: host, port: port, connectionType: connType, authType: authType, completion: completionTestConfig) + } + + + func findInJSonFileAndTest() -> Bool{ + (hostname, port, connectionType, authType) = loadFromProviderJson() + if let h = hostname, let p = port, let con = connectionType { + return findAndTestAuthType(hostname: h, port: p, connType: con) + } + else { + return false + } + } + + private func findAndTestAuthType(hostname: String, port: UInt32, connType: MCOConnectionType) -> Bool { + counter = MailSession.AUTHTYPE.count + success = false + for authType in MailSession.AUTHTYPE { + testServer(hostname: hostname, port: port, connectionType: connType, authType: authType, completion: completionTestAuthType) + } + return true + } + + func findDefaultValuesAndTest() -> Bool { + _ = self.fillWithDefaultValues() + if let host = hostname, let port = port, let connectionType = connectionType, let authType = authType { + counter = 1 + success = false + testServer(hostname: host, port: port, connectionType: connectionType, authType: authType, completion:completionFindServerConfig) + return true + } + return false + } + + func findAndTestLong () -> Bool { + // Try to find a possible config + let (_, server) = MailSession.splitAddr(userAddr: self.mailAddr) + if let domain = server { + if self.sessionType == SessionType.IMAP { + findServer(domain: domain, prefixes: MailSession.IMAPPREFIX, ports: MailSession.IMAPPORT) + } + else { + findServer(domain: domain, prefixes: MailSession.SMTPPREFIX, ports: MailSession.SMTPPORT) + } + return true + } + else { + return false + } + } + + + private func findServer(domain: String, prefixes: [String], ports: [UInt32]) { + counter = prefixes.count * ports.count * MailSession.CONNTECTIONTYPE.count * MailSession.AUTHTYPE.count + success = false + for prefix in prefixes { + for port in ports { + for conntech in MailSession.CONNTECTIONTYPE { + for authType in MailSession.AUTHTYPE { + let hostname = prefix+"."+domain + testServer(hostname: hostname, port: port, connectionType: conntech, authType: authType, completion: completionFindServerConfig) + } + } + } + } + } + + private func loadFromProviderJson() -> (hostname: String?, port: UInt32?, connType: MCOConnectionType?, authType: MCOAuthType?){ + let manager = MCOMailProvidersManager.shared()! + let path = Bundle.main.path(forResource: "providers", ofType: "json") + manager.registerProviders(withFilename: path) + + if let provider = manager.provider(forEmail: mailAddr){ + var netService: MCONetService? = nil + if sessionType == SessionType.IMAP { + if let imapServices = provider.imapServices() as? [MCONetService], imapServices.count > 0 { + netService = imapServices[0] + } + } + else { + if let smtpService = provider.smtpServices() as? [MCONetService], smtpService.count > 0 { + netService = smtpService[0] + } + } + if let server = netService { + return parseServerConfig(serverConfig: server.info()) + } + } + return (nil, nil, nil, nil) + } + + + private func parseServerConfig(serverConfig: [AnyHashable: Any]) -> (hostname: String?, port: UInt32?, connType: MCOConnectionType?, authType: MCOAuthType?) { + var hostname: String? + var port: UInt32? + var connectionType: MCOConnectionType? + if let host = serverConfig["hostname"] as? String { + hostname = host + } + + if let p = serverConfig["port"] as? UInt32 { + port = p + } + + if let trans = serverConfig["ssl"] as? Bool, trans { + connectionType = MCOConnectionType.TLS + } + if let trans = serverConfig["starttls"] as? Bool, trans { + connectionType = MCOConnectionType.startTLS + } + + return (hostname, port, connectionType, nil) + } + + private func testServer(hostname: String, port: UInt32, connectionType: MCOConnectionType, authType: MCOAuthType, completion: @escaping (_ error: MailServerConnectionError?, _ smtpSession: MCOSMTPSession?, _ imapSession: MCOIMAPSession?) -> Void) { + if AppDelegate.getAppDelegate().currentReachabilityStatus == .notReachable { + completion(MailServerConnectionError.NoInternetconnection, nil, nil) + } + if sessionType == SessionType.IMAP { + testIMAP(hostname: hostname, port: port, connectionType: connectionType, authType: authType, completion: completion) + } + else { + testSMTP(hostname: hostname, port: port, connectionType: connectionType, authType: authType, completion: completion) + } + } + + private func testSMTP(hostname: String, port: UInt32, connectionType: MCOConnectionType, authType: MCOAuthType, completion: @escaping (_ error: MailServerConnectionError?, _ smtpSession: MCOSMTPSession?, _ imapSession: MCOIMAPSession?) -> Void) { + let session = MCOSMTPSession() + session.username = username + session.password = password + + session.hostname = hostname + session.port = port + session.connectionType = connectionType + session.authType = authType + if session.authType == MCOAuthType.xoAuth2 { + session.oAuth2Token = EmailHelper.singleton().authorization?.authState.lastTokenResponse?.accessToken + } + session.checkAccountOperationWith(from: MCOAddress.init(mailbox: mailAddr)).start({(error: Error?) -> () in + if let error = error { + let connError = MailServerConnectionError.findErrorCode(error: error) + completion(connError, session, nil) + } + else { + completion(nil, session, nil) + } + }) + } + + private func testIMAP(hostname: String, port: UInt32, connectionType: MCOConnectionType, authType: MCOAuthType, completion:@escaping (_ error: MailServerConnectionError?, _ smtpSession: MCOSMTPSession?, _ imapSession: MCOIMAPSession?) -> Void) { + let session = MCOIMAPSession() + session.username = username + session.password = password + + session.hostname = hostname + session.port = port + session.connectionType = connectionType + session.authType = authType + if session.authType == MCOAuthType.xoAuth2 { + session.oAuth2Token = EmailHelper.singleton().authorization?.authState.lastTokenResponse?.accessToken + } + session.checkAccountOperation().start({(error: Error?) -> () in + if let error = error { + let connError = MailServerConnectionError.findErrorCode(error: error) + completion(connError, nil, session) + } + else { + completion(nil, nil, session) + } + }) + } + + + private func completionFindServerConfig(error: MailServerConnectionError?, smtpSession: MCOSMTPSession?, imapSession: MCOIMAPSession?){ + completionTestAuthType(error: error, smtpSession: smtpSession, imapSession: imapSession) + } + + private func completionTestConfig(error: MailServerConnectionError?, smtpSession: MCOSMTPSession?, imapSession: MCOIMAPSession?) { + if let e = error { + if e == MailServerConnectionError.AuthenticationError || e == MailServerConnectionError.NoInternetconnection { + errors.insert(e) + for l in listeners { + l.testFinish(result: false) + } + } + else { + var host: String + var port: UInt32 + var connType: MCOConnectionType + if let imap = imapSession { + host = imap.hostname + port = imap.port + connType = imap.connectionType + _ = findAndTestAuthType(hostname: host, port: port, connType: connType) + } + else if let smtp = smtpSession { + host = smtp.hostname + port = smtp.port + connType = smtp.connectionType + _ = findAndTestAuthType(hostname: host, port: port, connType: connType) + } + else { + errors.insert(e) + for l in listeners { + l.testFinish(result: false) + } + } + } + return + } + completionTestAuthType(error: error, smtpSession: smtpSession, imapSession: imapSession) + } + + private func completionTestAuthType(error: MailServerConnectionError?, smtpSession: MCOSMTPSession?, imapSession: MCOIMAPSession?){ + guard error == nil else { + counter = counter - 1 + if counter == 0 && !success { + for l in listeners { + l.testFinish(result: false) + } + } + errors.insert(error!) + return + } + if let imap = imapSession { + setServerConfig(hostname: imap.hostname, port: imap.port, connectionType: imap.connectionType, authType: imap.authType) + } + if let smtp = smtpSession { + setServerConfig(hostname: smtp.hostname, port: smtp.port, connectionType: smtp.connectionType, authType: smtp.authType) + } + counter = counter - 1 + if !success { + for l in listeners { + l.testFinish(result: true) + } + } + success = true + } + private func setServerConfig(hostname: String, port: UInt32, connectionType: MCOConnectionType, authType: MCOAuthType) { + if self.hostname == nil { + self.hostname = hostname + } + if self.port == nil { + self.port = nil + } + if self.connectionType == nil { + self.connectionType = connectionType + } + if self.authType == nil || self.authType == MCOAuthType.init(rawValue: 0) || self.authType == MCOAuthType.saslPlain { + self.authType = authType + } + storeToUserDefaults(hostname: hostname, port: port, connectionType: connectionType, authType: authType) + } + + + private func storeToUserDefaults(hostname: String, port: UInt32, connectionType: MCOConnectionType, authType: MCOAuthType) { + let connectionTypeValue = connectionType.rawValue + let authTypeValue = authType.rawValue + if sessionType == SessionType.IMAP { + UserManager.storeUserValue(hostname as AnyObject, attribute: Attribute.imapHostname) + UserManager.storeUserValue(port as AnyObject, attribute: Attribute.imapPort) + UserManager.storeUserValue(connectionTypeValue as AnyObject, attribute: Attribute.imapConnectionType) + UserManager.storeUserValue(authTypeValue as AnyObject, attribute: Attribute.imapAuthType) + } + else { + UserManager.storeUserValue(hostname as AnyObject, attribute: Attribute.smtpHostname) + UserManager.storeUserValue(port as AnyObject, attribute: Attribute.smtpPort) + UserManager.storeUserValue(connectionTypeValue as AnyObject, attribute: Attribute.smtpConnectionType) + UserManager.storeUserValue(authTypeValue as AnyObject, attribute: Attribute.smtpAuthType) + } + + UserManager.storeUserValue(password as AnyObject, attribute: Attribute.userPW) + UserManager.storeUserValue(username as AnyObject, attribute: Attribute.userName) + UserManager.storeUserValue(username as AnyObject, attribute: Attribute.accountname) + UserManager.storeUserValue(mailAddr as AnyObject, attribute: Attribute.userAddr) + } + + private func fillWithDefaultValues() -> Bool { + var filled = false + if sessionType == SessionType.IMAP { + if self.authType == nil, let authTypeValue = Attribute.imapAuthType.defaultValue as? Int { + self.authType = MCOAuthType.init(rawValue: authTypeValue) + filled = true + } + if self.connectionType == nil, let connectionTypeValue = Attribute.imapConnectionType.defaultValue as? Int { + self.connectionType = MCOConnectionType.init(rawValue: connectionTypeValue) + filled = true + } + } + else { + if self.authType == nil, let authTypeValue = Attribute.smtpAuthType.defaultValue as? Int { + self.authType = MCOAuthType.init(rawValue: authTypeValue) + filled = true + } + if self.connectionType == nil, let connectionTypeValue = Attribute.smtpConnectionType.defaultValue as? Int { + self.connectionType = MCOConnectionType.init(rawValue: connectionTypeValue) + filled = true + } + } + return filled + } + + private func loadFromUserDefaults() -> Bool { + if sessionType == SessionType.IMAP { + if let hostname = UserManager.loadUserValue(Attribute.imapHostname) as? String { + self.hostname = hostname + } + if let port = UserManager.loadUserValue(Attribute.imapPort) as? UInt32 { + self.port = port + } + if let connType = UserManager.loadUserValue(Attribute.imapConnectionType) as? Int { + self.connectionType = MCOConnectionType.init(rawValue: connType) + } + if let authType = UserManager.loadUserValue(Attribute.imapAuthType) as? Int { + self.authType = MCOAuthType.init(rawValue: authType) + } + } + else { + if let hostname = UserManager.loadUserValue(Attribute.smtpHostname) as? String { + self.hostname = hostname + } + if let port = UserManager.loadUserValue(Attribute.smtpPort) as? UInt32 { + self.port = port + } + if let connType = UserManager.loadUserValue(Attribute.smtpConnectionType) as? Int { + self.connectionType = MCOConnectionType.init(rawValue: connType) + } + if let authType = UserManager.loadUserValue(Attribute.smtpAuthType) as? Int { + self.authType = MCOAuthType.init(rawValue: authType) + } + } + + if hostname != nil, port != nil, connectionType != nil, authType != nil { + return true + } + return false + } + + private static func splitAddr(userAddr: String) -> (local: String?, domain: String?) { + let tokens = userAddr.split(separator: "@", maxSplits: 1) + if tokens.count == 2 { + let hostname = String(tokens[1]) + let local = String(tokens[0]) + return (local, hostname) + } + return (nil, nil) + } + +} + +protocol MailSessionListener { + func testFinish(result: Bool) +} diff --git a/enzevalos_iphone/Mail_Address+CoreDataClass.swift b/enzevalos_iphone/Mail_Address+CoreDataClass.swift index af6f65552addfddd0903a585bef22a7b2170e887..b62620cfed6d0189d65e3aee10e12029648d999c 100644 --- a/enzevalos_iphone/Mail_Address+CoreDataClass.swift +++ b/enzevalos_iphone/Mail_Address+CoreDataClass.swift @@ -63,4 +63,12 @@ open class Mail_Address: NSManagedObject, MailAddress { } return false } + + public func transform () -> MCOAddress { + var name = address + if let contact = contact { + name = contact.name + } + return MCOAddress.init(displayName: name, mailbox: address) + } } diff --git a/enzevalos_iphone/New Group/Mailbot.swift b/enzevalos_iphone/New Group/Mailbot.swift new file mode 100644 index 0000000000000000000000000000000000000000..c43f5671218259843f4e6522a17e8fe991b9a529 --- /dev/null +++ b/enzevalos_iphone/New Group/Mailbot.swift @@ -0,0 +1,114 @@ +// +// Mailbot.swift +// enzevalos_iphone +// +// Created by Oliver Wiese on 28.01.19. +// Copyright © 2019 fu-berlin. All rights reserved. +// + +import Foundation + +class Mailbot { + + static let faqURL = "https://userpage.fu-berlin.de/letterbox/faq.html" + static let raffleURL = "" + + + static var entrySurveyURL: String { + get { + return "https://userpage.fu-berlin.de/letterbox/entrysurvey.html?id=\(faqURL)" + } + } + + static let bitcoinStudyBody = + """ + Liebe Teilnehmerin, lieber Teilnehmer, + + Herzlichen Glückwunsch! Sie haben Letterbox erfolgreich installiert. + + Wenn Sie Fragen zur App oder Verschlüsselung haben, besuchen Sie doch unsere Hilfeseite: + \(faqURL) + + Dort finden Sie auch Videos zum Thema Ende-zu-Ende-Verschlüsselung. + Falls Sie Fragen haben oder uns Feedback geben möchten, freuen wir uns auf Ihre E-Mail! + + Die Studie umfasst drei Aufgaben und kann jederzeit abgebrochen werden. Für Fragen schreiben Sie uns bitte eine E-Mail und benutzen Sie bitte nach Möglichkeit die Letterbox dafür. + + In der ersten Aufgabe verfassen Sie bitte einen ersten Brief, indem Sie auf diese E-Mail antworten. Bitte teilen Sie uns Ihre Meinung mit. Ist etwas unklar geblieben? Was war neu für Sie? Was fanden Sie besonders interessant; was uninteressant? Hätten Sie sich noch weitere Informationen gewünscht? Sie können auch gerne Fragen zur Einführung stellen. + + Nach Beantwortung dieser E-Mail senden wir Ihnen zu einem späteren Zeitpunkt eine zweite E-Mail mit der nächsten kurzen Aufgabe zu. + + Vielen Dank für Ihre Teilnahme und mit freundlichen Grüßen, + Ihr Letterbox-Team + + PS: Diese Nachricht wurde automatisch in Letterbox erzeugt und ist nur hier gespeichert. + """ + + static let welcomeBody = + """ + Liebe Nutzerin, lieber Nutzer von Letterbox, + + Ich bin Lette, der Letterbox-Mailbot. Wir freuen uns, dass du dich für unsere App entschieden hast. Magst du mir gleich auf die E-Mail antworten? Dann kannst du gleich erfahren, wie einfach es ist sichere Mails zu schreiben. Du und ich wissen dann das es bei dir auch klappt. + + Wir freuen uns auch jederzeit über Fragen oder einem Feedback von dir. Wir freuen uns auf deine Antwort! + + Vielen Dank und viele Grüße + Lette + + PS: Diese Nachricht wurde automatisch auf deinem Gerät bei der Installation von Letterbox erzeugt und ist nur hier gespeichert. + """ + + + static func firstMail() { + if !StudySettings.studyMode || !StudySettings.presentFirstQuestionaireMail { + return + } + let subject = "Herzlich Willkommen in Letterbox" + let body = welcomeBody + + mailToParticipat(subject: subject, body: body) + } + + static func givecards() { + if !StudySettings.studyMode || !StudySettings.presentFirstQuestionaireMail { + return + } + let subject = "Teilnahmeentschädigung: Verlosung von Amazon-Gutscheinen" + let body = + """ + Liebe Teilnehmerin, lieber Teilnehmer, + + unter den teilnehmenden Personen werden 20 Amazon-Gutscheine im Wert von jeweils 50 Euro verlost. + + Um an der Verlosung teilnehmen zu können, müssen Sie uns Ihren Namen und die postalische Adresse mitteilen. + Falls Sie einen Gutschein gewinnen, wird dieser Ihnen per Post zugesendet. Außerdem werden Ihr Name und Ihre Adresse für den Nachweis der ordnungsgemäßen Verwendung der Gelder gespeichert, andernfalls werden sie gelöscht. + + Ihre Name und Ihre Adresse werden nicht mit anderen erhobenen Daten verknüpft und getrennt von diesen gespeichert. + + Wenn Sie an der Verlosung teilnehmen möchten, melden Sie sich bitte auf folgenden Link an: + \(raffleURL) + + Vielen Dank für Ihre Teilnahme und mit freundlichen Grüßen, + Ihr Letterbox-Team + + PS: Diese Nachricht wurde automatisch in Letterbox erzeugt und ist nur hier gespeichert. + """ + + mailToParticipat(subject: subject, body: body) + } + + + private static func mailToParticipat(subject: String, body: String) { + let senderAdr = SUPPORT_MAIL_ADR + let sender = MCOAddress.init(displayName: "Letterbox-Team", mailbox: senderAdr) + var keyID: String? + if let addr = DataHandler.handler.findMailAddress(adr: senderAdr) { + if let pk = addr.primaryKey { + keyID = pk.keyID + } + } + let cryptoObject = CryptoObject(chiphertext: nil, plaintext: body, decryptedData: body.data(using: .utf8), sigState: SignatureState.ValidSignature, encState: EncryptionState.ValidedEncryptedWithCurrentKey, signKey: keyID, encType: CryptoScheme.PGP, signedAdrs: [senderAdr]) + + _ = DataHandler.handler.createMail(0, sender: sender, receivers: [], cc: [], time: Date(), received: false, subject: subject, body: body, flags: MCOMessageFlag.init(rawValue: 0), record: nil, autocrypt: nil, decryptedData: cryptoObject, folderPath: UserManager.backendInboxFolderPath, secretKey: nil, encryptedBody: cryptoObject.chiperString) + } +} diff --git a/enzevalos_iphone/Onboarding.swift b/enzevalos_iphone/Onboarding.swift index c101aecf7688720774aaa38f3377a0eed90b1f4d..4a6c82c666c5bf251bd431f095d930893073bd36 100644 --- a/enzevalos_iphone/Onboarding.swift +++ b/enzevalos_iphone/Onboarding.swift @@ -22,7 +22,6 @@ import Foundation import Onboard class Onboarding: NSObject { - override init() { super.init() } @@ -32,7 +31,7 @@ class Onboarding: NSObject { static let textColor = UIColor.white static var mailaddress = UITextField.init() static var username = UITextField.init() - static var password = UITextField.init() + static var password = HideShowPasswordTextField.init()//UITextField.init() static var googleButton = UIBarButtonItem.init() static var credentials: UIView? = nil static var imapServer = UITextField.init() @@ -56,18 +55,23 @@ class Onboarding: NSObject { static let font = UIFont.init(name: "Helvetica-Light", size: 28) static let padding: CGFloat = 30 - static var doWhenDone: () -> () = { () -> () in } - static var fail: () -> () = { () -> () in } - static var work: () -> () = { () -> () in } + static var doWhenDone: () -> () = checkIMAPConfig static var credentialFails = 0 + + static var authTypeTest = 0 static var authenticationRows: [Int: String] = [MCOAuthType.saslLogin.rawValue: "Login", MCOAuthType.saslPlain.rawValue: NSLocalizedString("NormalPassword", comment: ""), MCOAuthType.SASLSRP.rawValue: "SRP", MCOAuthType.SASLCRAMMD5.rawValue: "CRAMMD5", MCOAuthType.SASLDIGESTMD5.rawValue: "DIGESTMD5", MCOAuthType.SASLNTLM.rawValue: "NTLM", MCOAuthType.SASLGSSAPI.rawValue: "GSSAPI", MCOAuthType.saslKerberosV4.rawValue: "KerberosV4", 0: "None"] - static var transportRows: [Int: String] = [MCOConnectionType.clear.rawValue: NSLocalizedString("Plaintext", comment: ""), MCOConnectionType.startTLS.rawValue: "StartTLS", MCOConnectionType.TLS.rawValue: "TLS"] - - static func onboarding(_ callback: @escaping () -> ()) -> UIViewController { + static var transportRows: [Int: String] = [MCOConnectionType.clear.rawValue: NSLocalizedString("Plaintext", comment: ""), MCOConnectionType.startTLS.rawValue: "StartTLS", MCOConnectionType.TLS.rawValue: "TLS/SSL"] + + private static var listenerIMAP = Listener(type: SessionType.IMAP) + private static var listenerSMTP = Listener(type: SessionType.SMTP) + private static var imapSession: MailSession? + private static var smtpSession: MailSession? - doWhenDone = callback + static func onboarding(_ errorCode: MailServerConnectionError? = nil) -> UIViewController { + password.isSecureTextEntry = true + doWhenDone = checkIMAPConfig //Background @@ -104,12 +108,12 @@ class Onboarding: NSObject { intro1.iconWidth = 80 } UIGraphicsBeginImageContextWithOptions(CGSize(width: intro1.iconWidth, height: intro1.iconHeight), false, 0) - IconsStyleKit.drawLetter(frame: CGRect(x: 0, y: 0, width: intro1.iconWidth, height: intro1.iconHeight), fillBackground: true) + StudySettings.securityIndicator.drawOfSecureIndictor(frame: CGRect(x: 0, y: 0, width: intro1.iconWidth, height: intro1.iconHeight), fillbackground: true, open: false) intro1.iconImageView.image = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() intro1.bodyLabel.textAlignment = NSTextAlignment.left - let intro2 = OnboardingContentViewController.content(withTitle: NSLocalizedString("Postcard", comment: ""), body: NSLocalizedString("PostcardDescription", comment: "describe the postcard"), image: IconsStyleKit.imageOfPostcardBG, buttonText: nil, action: nil) + let intro2 = OnboardingContentViewController.content(withTitle: NSLocalizedString("Postcard", comment: ""), body: NSLocalizedString("PostcardDescription", comment: "describe the postcard"), image: StudySettings.securityIndicator.imageOfInsecureIndicator(background: true), buttonText: nil, action: nil) intro2.iconHeight = 70 intro2.iconWidth = 100 @@ -118,7 +122,7 @@ class Onboarding: NSObject { intro2.iconWidth = 80 } UIGraphicsBeginImageContextWithOptions(CGSize(width: intro2.iconWidth, height: intro2.iconHeight), false, 0) - IconsStyleKit.drawPostcard(frame: CGRect(x: 0, y: 0, width: intro2.iconWidth, height: intro2.iconHeight), fillBackground: true) + StudySettings.securityIndicator.drawOfInSecureIndictor(frame: CGRect(x: 0, y: 0, width: intro2.iconWidth, height: intro2.iconHeight), fillbackground: true, open: false) intro2.iconImageView.image = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() intro2.bodyLabel.textAlignment = NSTextAlignment.left @@ -149,18 +153,34 @@ class Onboarding: NSObject { let mailaddressUnderline = UIView.init(frame: CGRect.init(x: 0, y: mailaddress.frame.maxY, width: mailaddress.frame.width, height: 0.5)) mailaddressUnderline.backgroundColor = textColor - password = UITextField.init() + + // Create passwordinput view + let frame = CGRect.init(x: 0, y: mailaddress.frame.height + padding + mailaddressUnderline.frame.height, width: 50, height: 30) + password = HideShowPasswordTextField.init(frame: frame) + password.isSecureTextEntry = true password.textColor = textColor password.tintColor = textColor password.borderStyle = UITextBorderStyle.none - password.isSecureTextEntry = true password.returnKeyType = UIReturnKeyType.continue - password.frame = CGRect.init(x: 0, y: mailaddress.frame.height + padding + mailaddressUnderline.frame.height, width: 50, height: 30) + password.attributedPlaceholder = NSAttributedString.init(string: NSLocalizedString("Password", comment: ""), attributes: [NSAttributedStringKey.foregroundColor: textColor]) password.delegate = textDelegate + + password.rightView?.tintColor = UIColor(red: 0.204, green: 0.624, blue: 0.847, alpha: 1) + + + // left view hack to add padding + password.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 3)) + password.leftViewMode = .always + + let passwordUnderline = UIView.init(frame: CGRect.init(x: 0, y: mailaddress.frame.height + padding + mailaddressUnderline.frame.height + password.frame.height, width: password.frame.width, height: 0.5)) passwordUnderline.backgroundColor = textColor + + + + // End let keyboardToolbar = UIToolbar() keyboardToolbar.sizeToFit() @@ -187,7 +207,7 @@ class Onboarding: NSObject { if self.credentialFails > 0 { bodyText = NSLocalizedString("WrongMailAddressOrPassword", comment: "") } - let page3 = OnboardingContentViewController.content(withTitle: nil, body: bodyText, videoURL: nil, inputView: credentials, buttonText: NSLocalizedString("next", comment: ""), actionBlock: callback) + let page3 = OnboardingContentViewController.content(withTitle: nil, body: bodyText, videoURL: nil, inputView: credentials, buttonText: NSLocalizedString("next", comment: ""), actionBlock: doWhenDone) page3.topPadding = 0 if self.credentialFails > 0 { page3.bodyLabel.textColor = UIColor.orange @@ -227,6 +247,7 @@ class Onboarding: NSObject { loginViewController = vc! vc?.pageChanged = {(oldPage:Int, newPage: Int) -> () in + password.isSecureTextEntry = true // Logger.queue.async(flags: .barrier) { Logger.log(onboardingPageTransition: oldPage, to: newPage, onboardingSection: "intro") // } @@ -284,16 +305,23 @@ class Onboarding: NSObject { } //UI Definition - static func detailOnboarding(_ callback: @escaping () -> ()) -> UIViewController { + static func detailOnboarding(_ errorCode: MailServerConnectionError? = nil) -> UIViewController { - let start = OnboardingContentViewController.content(withTitle: NSLocalizedString("WhatAShame", comment: ""), body: NSLocalizedString("CouldNotConnect", comment: ""), videoURL: nil, inputView: nil, buttonText: nil, actionBlock: nil) + var body = "CouldNotConnect" + if let e = errorCode { + body = e.localizedUIBodyString + } + let start = OnboardingContentViewController.content(withTitle: NSLocalizedString("WhatAShame", comment: ""), body: NSLocalizedString(body, comment: ""), videoURL: nil, inputView: nil, buttonText: nil, actionBlock: nil) Onboarding.password.returnKeyType = .done - password.text = UserManager.loadUserValue(.userPW) as? String - mailaddress.text = UserManager.loadUserValue(.userAddr) as? String - doWhenDone = { () -> () in } + password.isSecureTextEntry = true + if let imap = imapSession { + password.text = imap.pw + mailaddress.text = imap.address + } + doWhenDone = checkIMAPConfig //TODO - let email = OnboardingContentViewController.content(withTitle: nil, body: NSLocalizedString("InsertMailAddressAndPassword", comment: ""), videoURL: nil, inputView: credentials, buttonText: nil, actionBlock: callback) + let email = OnboardingContentViewController.content(withTitle: nil, body: NSLocalizedString("InsertMailAddressAndPassword", comment: ""), videoURL: nil, inputView: credentials, buttonText: nil, actionBlock: Onboarding.checkIMAPConfig) username = UITextField.init() username.borderStyle = UITextBorderStyle.none username.keyboardType = UIKeyboardType.emailAddress @@ -302,7 +330,9 @@ class Onboarding: NSObject { username.delegate = textDelegate username.frame = CGRect.init(x: 0, y: 0, width: 50, height: 30) username.placeholder = NSLocalizedString("Username", comment: "") - username.text = UserManager.loadUserValue(Attribute.userName) as? String + if let imap = imapSession { + username.text = imap.name + } username.textColor = textColor username.tintColor = textColor username.attributedPlaceholder = NSAttributedString.init(string: NSLocalizedString("Username", comment: ""), attributes: [NSAttributedStringKey.foregroundColor: textColor]) @@ -319,7 +349,9 @@ class Onboarding: NSObject { imapServer.borderStyle = UITextBorderStyle.none imapServer.textColor = textColor imapServer.frame = CGRect.init(x: 0, y: 0, width: 50, height: 30) - imapServer.text = UserManager.loadUserValue(Attribute.imapHostname) as? String + if let imap = imapSession { + imapServer.text = imap.servername + } imapServer.autocorrectionType = UITextAutocorrectionType.no imapServer.returnKeyType = .done imapServer.delegate = textDelegate @@ -338,8 +370,9 @@ class Onboarding: NSObject { imapPort.borderStyle = UITextBorderStyle.none imapPort.text = "0" imapPort.textColor = textColor - if let port = UserManager.loadUserValue(Attribute.imapPort) { - imapPort.text = "\(port as! Int)" + if let imap = imapSession { + let port = imap.portnumber + imapPort.text = "\(port)" } imapPort.keyboardType = UIKeyboardType.numberPad imapPort.returnKeyType = .done @@ -402,7 +435,7 @@ class Onboarding: NSObject { smtpServer.borderStyle = UITextBorderStyle.none smtpServer.textColor = textColor - smtpServer.text = UserManager.loadUserValue(Attribute.smtpHostname) as? String + smtpServer.text = smtpSession?.servername smtpServer.frame = CGRect.init(x: 0, y: 0, width: 50, height: 30) smtpServer.autocorrectionType = UITextAutocorrectionType.no smtpServer.returnKeyType = .done @@ -423,8 +456,9 @@ class Onboarding: NSObject { smtpPort.text = "0" smtpPort.textColor = textColor smtpPort.borderStyle = UITextBorderStyle.none - if let port = UserManager.loadUserValue(Attribute.smtpPort) { - smtpPort.text = "\(port as! Int)" + if let smtp = smtpSession { + let port = smtp.portnumber + smtpPort.text = "\(port)" } smtpPort.keyboardType = UIKeyboardType.numberPad smtpPort.returnKeyType = .done @@ -450,7 +484,9 @@ class Onboarding: NSObject { smtpTransportEncryption.frame = CGRect.init(x: 0, y: 0, width: 50, height: 100) smtpTransportEncryption.reloadAllComponents() //smtpAuthentication.backgroundColor = UIColor.whiteColor() - row = UserManager.loadUserValue(Attribute.smtpConnectionType) as! Int + if let smtp = smtpSession { + row = smtp.serverAuthType.rawValue + } smtpTransDataDelegate.pickedValue = transportRows[row]! row = smtpTransDataDelegate.rows.index(of: transportRows[row]!)! //if Array(transportRows.keys).contains(row){ @@ -474,7 +510,9 @@ class Onboarding: NSObject { smtpAuthentication.reloadAllComponents() smtpAuthentication.reloadInputViews() smtpAuthentication.tintColor = textColor - row = UserManager.loadUserValue(Attribute.smtpAuthType) as! Int + if let smtp = smtpSession { + row = smtp.serverAuthType.rawValue + } smtpAuthDataDelegate.pickedValue = authenticationRows[row]! row = Array(authenticationRows.values).index(of: authenticationRows[row]!)! smtpAuthentication.selectRow(row, inComponent: 0, animated: false) @@ -487,9 +525,10 @@ class Onboarding: NSObject { let smtp2 = OnboardingContentViewController.content(withTitle: nil, body: "SMTP-" + NSLocalizedString("Transportencryption", comment: ""), videoURL: nil, inputView: smtpAuth, buttonText: nil, actionBlock: nil, withPadding: boolPointer) - let last = OnboardingContentViewController.content(withTitle: NSLocalizedString("EverythingCorrect", comment: ""), body: nil, videoURL: nil, inputView: nil, buttonText: NSLocalizedString("next", comment: ""), actionBlock: callback) + let last = OnboardingContentViewController.content(withTitle: NSLocalizedString("EverythingCorrect", comment: ""), body: nil, videoURL: nil, inputView: nil, buttonText: NSLocalizedString("next", comment: ""), actionBlock: doWhenDone) - let vc = Onboard.OnboardingViewController(backgroundImage: background, contents: [start, email, user, imap1, imap2, smtp1, smtp2, last]) + let contents = [start, email, user, imap1, imap2, smtp1, smtp2, last] + let vc = Onboard.OnboardingViewController(backgroundImage: background, contents: contents) vc?.view.backgroundColor = defaultColor vc?.pageChanged = {(oldPage:Int, newPage: Int) -> () in Logger.log(onboardingPageTransition: oldPage, to: newPage, onboardingSection: "detail") @@ -517,166 +556,152 @@ class Onboarding: NSObject { AppDelegate.getAppDelegate().requestForAccess(callback) } - static func checkConfig(_ fail: @escaping () -> (), work: @escaping () -> ()) { - self.work = work - self.fail = fail - AppDelegate.getAppDelegate().mailHandler.checkIMAP(imapCompletion) - } - - static func imapCompletion(_ error: Error?) { - if error == nil { - AppDelegate.getAppDelegate().mailHandler.checkSMTP(smtpCompletion) - return + static func checkIMAPConfigUI() { + if Onboarding.credentialFails >= 3{ + Onboarding.manualSet = true + var error = MailServerConnectionError.AuthenticationError + if let imap = imapSession, let e = MailServerConnectionError.findPrioError(errors: imap.errors) { + error = e + } + if smtpSession == nil { + smtpSession = MailSession(configSession: .SMTP, mailAddress: mailaddress.text!, password: password.text!, username: mailaddress.text!) + } + AppDelegate.getAppDelegate().window?.rootViewController = Onboarding.detailOnboarding(error) } - fail() - } - - static func smtpCompletion(_ error: Error?) { - if error == nil { - work() - return + else { + Onboarding.manualSet = false + let contr = (Onboarding.onboarding() as! OnboardingViewController) + AppDelegate.getAppDelegate().window?.rootViewController = contr + contr.gotoLastPage() } - fail() } - - static func setValues() -> OnboardingValueState { - - if !manualSet { //manualSet is true if vales were set by the detailOnboardingView - let mailAddress = (mailaddress.text ?? "").lowercased().trimmingCharacters(in: .whitespacesAndNewlines) - var guessedUserName = "" - if mailAddress.components(separatedBy: "@").count >= 1 { - guessedUserName = mailAddress.components(separatedBy: "@")[0] + + static private func checkDetailConfig(imap: Bool) { + if let imapHost = imapServer.text, let imapPortString = imapPort.text, let smtpHost = smtpServer.text, let smtpPortString = smtpPort.text, let smtpPort = Int(smtpPortString), let imapPort = Int(imapPortString) { + let imapAuthName = imapTransDataDelegate.pickedValue + let imapConName = imapTransDataDelegate.pickedValue + let smtpConnName = smtpTransDataDelegate.pickedValue + let smtpAuthName = smtpAuthDataDelegate.pickedValue + var imapAuthValue = 0 + var imapConnValue = 0 + var smtpAuthValue = 0 + var smtpConnValue = 0 + + for (value, name) in Onboarding.authenticationRows { + if name == imapAuthName { + imapAuthValue = value + } + if name == smtpAuthName { + smtpAuthValue = value + } } - UserManager.storeUserValue(guessedUserName as AnyObject?, attribute: Attribute.userName) - UserManager.storeUserValue(mailAddress as AnyObject?, attribute: Attribute.userAddr) - UserManager.storeUserValue((password.text ?? "") as AnyObject?, attribute: Attribute.userPW) - return setServerValues(mailaddress: mailAddress) - } else { - UserManager.storeUserValue(imapServer.text as AnyObject?, attribute: Attribute.imapHostname) - UserManager.storeUserValue(Int(imapPort.text ?? "143") as AnyObject?, attribute: Attribute.imapPort) - UserManager.storeUserValue(smtpServer.text as AnyObject?, attribute: Attribute.smtpHostname) - UserManager.storeUserValue(Int(smtpPort.text ?? "587") as AnyObject?, attribute: Attribute.smtpPort) - UserManager.storeUserValue(mailaddress.text as AnyObject?, attribute: Attribute.userAddr) - UserManager.storeUserValue((password.text ?? "") as AnyObject?, attribute: Attribute.userPW) - UserManager.storeUserValue((username.text ?? "username") as AnyObject?, attribute: Attribute.userName) - UserManager.storeUserValue((username.text ?? "username") as AnyObject?, attribute: Attribute.accountname) - UserManager.storeUserValue(keyForValue(transportRows, value: imapTransDataDelegate.pickedValue)[0] as AnyObject?, attribute: Attribute.imapConnectionType) - UserManager.storeUserValue(keyForValue(authenticationRows, value: imapAuthDataDelegate.pickedValue)[0] as AnyObject?, attribute: Attribute.imapAuthType) - UserManager.storeUserValue(keyForValue(transportRows, value: smtpTransDataDelegate.pickedValue)[0] as AnyObject?, attribute: Attribute.smtpConnectionType) - UserManager.storeUserValue(keyForValue(authenticationRows, value: smtpAuthDataDelegate.pickedValue)[0] as AnyObject?, attribute: Attribute.smtpAuthType) - return OnboardingValueState.fine - } - - } - - static func setServerValues(mailaddress: String) -> OnboardingValueState { - let manager = MCOMailProvidersManager.shared()! - let path = Bundle.main.path(forResource: "providers", ofType: "json") - manager.registerProviders(withFilename: path) - - if let provider = manager.provider(forEmail: mailaddress), let imap = (provider.imapServices() as? [MCONetService]), imap != [], let smtp = (provider.smtpServices() as? [MCONetService]), smtp != [] { - let imapService = imap[0] - UserManager.storeUserValue((imapService.info()["hostname"] ?? "imap.example.com") as AnyObject?, attribute: Attribute.imapHostname) - UserManager.storeUserValue((imapService.info()["port"] ?? 587) as AnyObject?, attribute: Attribute.imapPort) - if let trans = imapService.info()["ssl"] as? Bool, trans { - UserManager.storeUserValue(MCOConnectionType.TLS.rawValue as AnyObject?, attribute: Attribute.imapConnectionType) - } else if let trans = imapService.info()["starttls"] as? Bool, trans { - UserManager.storeUserValue(MCOConnectionType.startTLS.rawValue as AnyObject?, attribute: Attribute.imapConnectionType) - } else { - UserManager.storeUserValue(MCOConnectionType.clear.rawValue as AnyObject?, attribute: Attribute.imapConnectionType) - } - - if let auth = imapService.info()["auth"] as? String, auth == "saslPlain" { - UserManager.storeUserValue(MCOAuthType.saslPlain.rawValue as AnyObject?, attribute: Attribute.imapAuthType) - } else if let auth = imapService.info()["auth"] as? String, auth == "saslLogin" { - UserManager.storeUserValue(MCOAuthType.saslLogin.rawValue as AnyObject?, attribute: Attribute.imapAuthType) - } else if let auth = imapService.info()["auth"] as? String, auth == "saslKerberosV4" { - UserManager.storeUserValue(MCOAuthType.saslKerberosV4.rawValue as AnyObject?, attribute: Attribute.imapAuthType) - } else if let auth = imapService.info()["auth"] as? String, auth == "saslCRAMMD5" { - UserManager.storeUserValue(MCOAuthType.SASLCRAMMD5.rawValue as AnyObject?, attribute: Attribute.imapAuthType) - } else if let auth = imapService.info()["auth"] as? String, auth == "saslDIGESTMD5" { - UserManager.storeUserValue(MCOAuthType.SASLDIGESTMD5.rawValue as AnyObject?, attribute: Attribute.imapAuthType) - } else if let auth = imapService.info()["auth"] as? String, auth == "saslGSSAPI" { - UserManager.storeUserValue(MCOAuthType.SASLGSSAPI.rawValue as AnyObject?, attribute: Attribute.imapAuthType) - } else if let auth = imapService.info()["auth"] as? String, auth == "saslSRP" { - UserManager.storeUserValue(MCOAuthType.SASLSRP.rawValue as AnyObject?, attribute: Attribute.imapAuthType) - } else if let auth = imapService.info()["auth"] as? String, auth == "saslNTLM" { - UserManager.storeUserValue(MCOAuthType.SASLNTLM.rawValue as AnyObject?, attribute: Attribute.imapAuthType) - } else if let auth = imapService.info()["auth"] as? String, auth == "xoAuth2" { - UserManager.storeUserValue(MCOAuthType.xoAuth2.rawValue as AnyObject?, attribute: Attribute.imapAuthType) - } else if let auth = imapService.info()["auth"] as? String, auth == "xoAuth2Outlook" { - UserManager.storeUserValue(MCOAuthType.SASLCRAMMD5.rawValue as AnyObject?, attribute: Attribute.imapAuthType) - } else { - UserManager.storeUserValue(0 as AnyObject?, attribute: Attribute.imapAuthType) + for (value, name) in Onboarding.transportRows { + if name == imapConName { + imapConnValue = value + } + if name == smtpConnName { + smtpConnValue = value + } } - - let smtpService = smtp[0] - UserManager.storeUserValue((smtpService.info()["hostname"] ?? "smtp.example.com") as AnyObject?, attribute: Attribute.smtpHostname) - UserManager.storeUserValue((smtpService.info()["port"] ?? 993) as AnyObject?, attribute: Attribute.smtpPort) - - if let trans = smtpService.info()["ssl"] as? Bool, trans { - UserManager.storeUserValue(MCOConnectionType.TLS.rawValue as AnyObject?, attribute: Attribute.smtpConnectionType) - } else if let trans = smtpService.info()["starttls"] as? Bool, trans { - UserManager.storeUserValue(MCOConnectionType.startTLS.rawValue as AnyObject?, attribute: Attribute.smtpConnectionType) - } else { - UserManager.storeUserValue(MCOConnectionType.clear.rawValue as AnyObject?, attribute: Attribute.smtpConnectionType) + if imap { + if imapSession == nil { + _ = setIMAPSession() + } + if let imap = imapSession { + imap.testConfig(host: imapHost, port: UInt32(imapPort), authType: MCOAuthType.init(rawValue: imapAuthValue), connType: MCOConnectionType.init(rawValue: imapConnValue)) + } } - - if let auth = smtpService.info()["auth"] as? String, auth == "saslPlain" { - UserManager.storeUserValue(MCOAuthType.saslPlain.rawValue as AnyObject?, attribute: Attribute.smtpAuthType) - } else if let auth = smtpService.info()["auth"] as? String, auth == "saslLogin" { - UserManager.storeUserValue(MCOAuthType.saslLogin.rawValue as AnyObject?, attribute: Attribute.smtpAuthType) - } else if let auth = smtpService.info()["auth"] as? String, auth == "saslKerberosV4" { - UserManager.storeUserValue(MCOAuthType.saslKerberosV4.rawValue as AnyObject?, attribute: Attribute.smtpAuthType) - } else if let auth = smtpService.info()["auth"] as? String, auth == "saslCRAMMD5" { - UserManager.storeUserValue(MCOAuthType.SASLCRAMMD5.rawValue as AnyObject?, attribute: Attribute.smtpAuthType) - } else if let auth = smtpService.info()["auth"] as? String, auth == "saslDIGESTMD5" { - UserManager.storeUserValue(MCOAuthType.SASLDIGESTMD5.rawValue as AnyObject?, attribute: Attribute.smtpAuthType) - } else if let auth = smtpService.info()["auth"] as? String, auth == "saslGSSAPI" { - UserManager.storeUserValue(MCOAuthType.SASLGSSAPI.rawValue as AnyObject?, attribute: Attribute.smtpAuthType) - } else if let auth = smtpService.info()["auth"] as? String, auth == "saslSRP" { - UserManager.storeUserValue(MCOAuthType.SASLSRP.rawValue as AnyObject?, attribute: Attribute.smtpAuthType) - } else if let auth = smtpService.info()["auth"] as? String, auth == "saslNTLM" { - UserManager.storeUserValue(MCOAuthType.SASLNTLM.rawValue as AnyObject?, attribute: Attribute.smtpAuthType) - } else if let auth = smtpService.info()["auth"] as? String, auth == "xoAuth2" { - UserManager.storeUserValue(MCOAuthType.xoAuth2.rawValue as AnyObject?, attribute: Attribute.smtpAuthType) - } else if let auth = smtpService.info()["auth"] as? String, auth == "xoAuth2Outlook" { - UserManager.storeUserValue(MCOAuthType.SASLCRAMMD5.rawValue as AnyObject?, attribute: Attribute.smtpAuthType) - } else { - UserManager.storeUserValue(0 as AnyObject?, attribute: Attribute.smtpAuthType) + else { + if smtpSession == nil { + _ = setSMTPSession() + } + if let smtp = smtpSession { + smtp.testConfig(host: smtpHost, port: UInt32(smtpPort), authType: MCOAuthType.init(rawValue: smtpAuthValue), connType: MCOConnectionType.init(rawValue: smtpConnValue)) + } } - - if let drafts = provider.draftsFolderPath() { - UserManager.storeUserValue(drafts as AnyObject?, attribute: Attribute.draftFolderPath) + } + } + + static private func setIMAPSession() -> MailSession { + let mailSession = MailSession(configSession: SessionType.IMAP, mailAddress: mailaddress.text!, password: password.text!, username: mailaddress.text) + mailSession.addListener(listener: listenerIMAP) + Onboarding.imapSession = mailSession + return mailSession + } + + static func checkIMAPConfig() { + let mailSession = setIMAPSession() + + if let imap = imapSession, MailServerConnectionError.wrongServerConfig(errors: imap.errors) && Onboarding.credentialFails == 2 { + if !mailSession.findAndTestLong() { + imapCompletion(imapWorks: false) } - if let sent = provider.sentMailFolderPath() { - UserManager.storeUserValue(sent as AnyObject?, attribute: Attribute.sentFolderPath) + } + else if Onboarding.credentialFails >= 3{ + checkDetailConfig(imap: true) + } + else { + if !mailSession.findInJSonFileAndTest() { + if !mailSession.findDefaultValuesAndTest() { + if !mailSession.findAndTestLong() { + imapCompletion(imapWorks: false) + } + } } - if let trash = provider.trashFolderPath() { - UserManager.storeUserValue(trash as AnyObject?, attribute: Attribute.trashFolderPath) + } + } + + static private func setSMTPSession() -> MailSession{ + let mailSession = MailSession(configSession: SessionType.SMTP, mailAddress: mailaddress.text!, password: password.text!, username: mailaddress.text) + mailSession.addListener(listener: listenerSMTP) + Onboarding.smtpSession = mailSession + return mailSession + } + + static func checkSMTPConfig() { + let mailSession = setSMTPSession() + if let imap = imapSession, MailServerConnectionError.wrongServerConfig(errors: imap.errors) { + if !mailSession.findAndTestLong() { + smtpCompletion(smtpWorks: false) } - if let archive = provider.allMailFolderPath() { - UserManager.storeUserValue(archive as AnyObject?, attribute: Attribute.archiveFolderPath) + } + else if Onboarding.credentialFails >= 3 { + checkDetailConfig(imap: false) + } + else { + if !mailSession.findInJSonFileAndTest() { + if !mailSession.findDefaultValuesAndTest() { + if !mailSession.findAndTestLong() { + smtpCompletion(smtpWorks: false) + } + } } - return OnboardingValueState.fine + } + + } + + static func imapCompletion(imapWorks: Bool) { + if imapWorks { + checkSMTPConfig() + return } else { - setDefaultValues() - return OnboardingValueState.noJson + Onboarding.credentialFails += 1 + checkIMAPConfigUI() } } - static func setDefaultValues() { - UserManager.storeUserValue("imap.example.de" as AnyObject?, attribute: Attribute.imapHostname) - UserManager.storeUserValue(MCOConnectionType.TLS.rawValue as AnyObject?, attribute: Attribute.imapConnectionType) - UserManager.storeUserValue(993 as AnyObject?, attribute: Attribute.imapPort) - UserManager.storeUserValue(MCOAuthType.saslPlain.rawValue as AnyObject?, attribute: Attribute.imapAuthType) - UserManager.storeUserValue("smtp.example.de" as AnyObject?, attribute: Attribute.smtpHostname) - UserManager.storeUserValue(MCOConnectionType.startTLS.rawValue as AnyObject?, attribute: Attribute.smtpConnectionType) - UserManager.storeUserValue(587 as AnyObject?, attribute: Attribute.smtpPort) - UserManager.storeUserValue(MCOAuthType.saslPlain.rawValue as AnyObject?, attribute: Attribute.smtpAuthType) + static func smtpCompletion(smtpWorks: Bool) { + if smtpWorks { + //work() + AppDelegate.getAppDelegate().credentialsWork() + return + } + checkIMAPConfig() } + + static func iterateEnum<T: Hashable>(_: T.Type) -> AnyIterator<T> { var i = 0 @@ -699,8 +724,11 @@ class Onboarding: NSObject { } } + + class TextFieldDelegate: NSObject, UITextFieldDelegate { + func textFieldShouldReturn(_ textField: UITextField) -> Bool { if textField == Onboarding.mailaddress { textField.resignFirstResponder() @@ -721,6 +749,19 @@ class TextFieldDelegate: NSObject, UITextFieldDelegate { textField.endEditing(true) return true } + + func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, textField string: String) -> Bool { + if textField == Onboarding.password, let passwordTextField = textField as? HideShowPasswordTextField { + return passwordTextField.textField(textField: textField, shouldChangeCharactersInRange: range, replacementString: string) + } + return true + } + + func textFieldDidEndEditing(_ textField: UITextField) { + if textField == Onboarding.password, let passwordTextField = textField as? HideShowPasswordTextField { + return passwordTextField.textFieldDidEndEditing(textField: textField) + } + } } class PickerDataDelegate: NSObject, UIPickerViewDataSource { @@ -767,3 +808,20 @@ extension PickerDataDelegate: UIPickerViewDelegate { pickedValue = rows[row] } } + +class Listener: MailSessionListener { + let type: SessionType + + init(type: SessionType) { + self.type = type + } + + func testFinish(result: Bool) { + if type == SessionType.IMAP { + Onboarding.imapCompletion(imapWorks: result) + } + else { + Onboarding.smtpCompletion(smtpWorks: result) + } + } +} diff --git a/enzevalos_iphone/OutgoingMail.swift b/enzevalos_iphone/OutgoingMail.swift new file mode 100644 index 0000000000000000000000000000000000000000..be2dd6a91c46cf2239e5d6ccd958da130a6caa2a --- /dev/null +++ b/enzevalos_iphone/OutgoingMail.swift @@ -0,0 +1,402 @@ +// +// OutgoingMail.swift +// enzevalos_iphone +// +// Created by Oliver Wiese on 27.10.18. +// Copyright © 2018 fu-berlin. All rights reserved. +// + +import Foundation +class OutgoingMail { + private var pgpAddresses: [MCOAddress] = [] + var encReceivers: [MCOAddress] { + get { + //TODO: @Olli revisit send plain mail + return pgpAddresses + } + } + private var plainAddresses: [MCOAddress] = [] + var plainReceivers: [MCOAddress] { + get { + return plainAddresses + } + } + private let toEntrys: [MCOAddress] + private let ccEntrys: [MCOAddress] + private let bccEntrys: [MCOAddress] + var username = UserManager.loadUserValue(Attribute.userName) as! String + var useraddr = UserManager.loadUserValue(Attribute.userAddr) as! String + + var sender: MCOAddress { + get { + return MCOAddress.init(displayName: username, mailbox: useraddr) + } + } + private var sk: SecretKey? { + get { + return DataHandler.handler.prefSecretKey() + } + } + private let subject: String + private var textparts: Int + private let textContent: String? + private var htmlContent: String? = nil + var pgpData: Data? { + get { + return createEncData() + } + } + + var plainData: Data? { + get { + guard plainAddresses.count > 0 else { + return nil + } + if loggingMail { + return nil + } + return createPlainData() + } + } + private var cryptoObject: CryptoObject? = nil + private var attachments: [MCOAttachment] = [] + + private var sendEncryptedIfPossible: Bool + var loggingMail = false + var warningReact = false + var inviteMail = false + var onlySelfEnc = false + var isPending = false + var autocrypt = true + + private var isDraft = false + + fileprivate var exportSecretKey = false + fileprivate var keyID: String? + fileprivate var keyData: String? + + private var informUser = false + + var imapFlag: MCOMessageFlag { + get { + if isDraft { + return MCOMessageFlag.draft + } + else if isPending { + return MCOMessageFlag.submitPending + } + else { + return MCOMessageFlag.mdnSent + } + } + } + + private var mail: PersistentMail? + + init(toEntrys: [String], ccEntrys: [String], bccEntrys: [String], subject: String, textContent: String?, htmlContent: String?, textparts: Int = 0, sendEncryptedIfPossible: Bool = true) { + self.toEntrys = OutgoingMail.mapToMCOAddresses(addr: toEntrys) + self.ccEntrys = OutgoingMail.mapToMCOAddresses(addr: ccEntrys) + self.bccEntrys = OutgoingMail.mapToMCOAddresses(addr: bccEntrys) + self.subject = subject + self.textContent = textContent + self.htmlContent = htmlContent + self.textparts = textparts + self.sendEncryptedIfPossible = sendEncryptedIfPossible + self.orderReceivers() + } + + init(mail: PersistentMail){ + toEntrys = OutgoingMail.mapToMCOAddresses(addr: mail.getReceivers()) + ccEntrys = OutgoingMail.mapToMCOAddresses(addr: mail.getCCs()) + bccEntrys = OutgoingMail.mapToMCOAddresses(addr: mail.getBCCs()) + subject = mail.subject != nil ? mail.subject!: "" + textContent = mail.body + htmlContent = mail.decryptedBody //TODO FIX HERE + textparts = 0 //TODO FIX HERE + sendEncryptedIfPossible = mail.isEncrypted //TODO FIX HERE + self.orderReceivers() + self.mail = mail + self.loggingMail = mail.isCorrectlySigned + } + + func store() -> PersistentMail? { + let me = MCOAddress.init(displayName: username, mailbox: useraddr) + let mail = DataHandler.handler.createMail(0, sender: me, receivers: toEntrys, cc: ccEntrys, time: Date(), received: false, subject: subject, body: textContent, flags: MCOMessageFlag.seen, record: nil, autocrypt: nil, decryptedData: nil, folderPath: DataHandler.handler.outgoingFolder, secretKey: nil, encryptedBody: nil) + mail?.decryptedBody = htmlContent + mail?.isEncrypted = sendEncryptedIfPossible + mail?.isCorrectlySigned = self.loggingMail + self.mail = mail + return mail + } + + func addTextAttachment(text: String) { + let attachment = MCOAttachment.init(text: text)! + attachments.append(attachment) + } + + func addAttachment(filename: String, mimeType: String, charset: String?, data: Data) { + if let attachment = MCOAttachment.init(contentsOfFile: filename){ + attachment.mimeType = mimeType + if let charset = charset { + attachment.setContentTypeParameterValue(charset, forName: "charset") + } + attachment.setContentTypeParameterValue(filename, forName: "name") + attachment.filename = filename + attachment.data = data + attachments.append(attachment) + } + } + + func send(informUser: Bool = false) { + self.informUser = informUser + if let mail = mail { + DataHandler.handler.delete(mail: mail) + } + AppDelegate.getAppDelegate().mailHandler.sendSMTP(mail: self, callback: sendCallback) + } + + func sendCallback(error: MailServerConnectionError?){ + if let error = error { + if error == .NoInternetconnection || error == .ConnectionError { + AppDelegate.getAppDelegate().noInternetConnection() + mail = self.store() + return + } + } + else { + DataHandler.handler.startToSendMore() + } + + } + + func logMail() -> Bool { + guard Logger.logging && !loggingMail else { + return false + } + // We don't log the logging mail + if loggingMail { + return false + } + let fromLogging: Mail_Address = DataHandler.handler.getMailAddress(useraddr, temporary: false) as! Mail_Address + let toLogging: [Mail_Address] = [] + let ccLogging: [Mail_Address] = [] + let bccLogging: [Mail_Address] = [] + let secureAddrsInString = pgpAddresses.map { $0.mailbox } + var secureAddresses: [Mail_Address] = [] + for addr in toLogging { + for sec in secureAddrsInString { + if addr.address == sec { + secureAddresses.append(addr) + } + } + } + for addr in ccLogging { + for sec in secureAddrsInString { + if addr.address == sec { + secureAddresses.append(addr) + } + } + } + for addr in bccLogging { + for sec in secureAddrsInString { + if addr.address == sec { + secureAddresses.append(addr) + } + } + } + var inviteMailContent: String? = nil + if inviteMail { + inviteMailContent = textparts.description + } + if let co = cryptoObject { + let isEnc = co.encryptionState == EncryptionState.ValidedEncryptedWithCurrentKey || co.encryptionState == EncryptionState.ValidEncryptedWithOldKey || co.encryptionState == EncryptionState.UnableToDecrypt + let isSig = co.signatureState == .ValidSignature || co.signatureState == .InvalidSignature || co.signatureState == .NoPublicKey + let isCorSig = co.signatureState == .ValidSignature + if isDraft { + Logger.log(createDraft: toLogging, cc: ccLogging, bcc: bccLogging, subject: subject, bodyLength: textContent?.count ?? 0, isEncrypted: isEnc, isSigned: isSig, myKeyID: keyID ?? "") + } + else { + Logger.log(sent: fromLogging, to: toLogging, cc: ccLogging, bcc: bccLogging, subject: subject, bodyLength: co.chiperString?.count ?? 0, isEncrypted: isEnc, decryptedBodyLength: ("\n" + (co.plaintext ?? "")).count, decryptedWithOldPrivateKey: false, isSigned: isSig, isCorrectlySigned: isCorSig, signingKeyID: co.signKey ?? "", myKeyID: sk?.keyID ?? "", secureAddresses: secureAddresses, encryptedForKeyIDs: OutgoingMail.addKeys(adrs: pgpAddresses), inviteMailContent: inviteMailContent, invitationMail: inviteMail) + } + } //TODO: Doppeltes logging? crpyto mail und plain mail? + else { + if isDraft { + Logger.log(createDraft: toLogging, cc: ccLogging, bcc: bccLogging, subject: subject, bodyLength: textContent?.count ?? 0, isEncrypted: false, isSigned: false, myKeyID: "") + } + else { + var textContentCount = textContent?.count ?? 0 + if textContentCount != 0 { + textContentCount += 1 //for \n + } + Logger.log(sent: fromLogging, to: toLogging, cc: ccLogging, bcc: bccLogging, subject: subject, bodyLength: textContentCount, isEncrypted: false, decryptedBodyLength: textContentCount , decryptedWithOldPrivateKey: false, isSigned: false, isCorrectlySigned: false, signingKeyID: "", myKeyID: "", secureAddresses: [], encryptedForKeyIDs: [], inviteMailContent: inviteMailContent, invitationMail: inviteMail) + } + } + return true + } + + + + private func createPlainData() -> Data { + let builder = createBuilder() + + return builder.data() + } + + private func createEncData() -> Data? { + let encMailBuilder = createBuilder() + let pgp = SwiftPGP() + var plainData = encMailBuilder.dataForEncryption() + var msg = String(data: plainData!, encoding: .utf8)! + var missingOwnPublic = false + + var pgpKeyIds: [String] = [] + var skKeyID = "" + if let sk = sk, let skID = sk.keyID { + pgpKeyIds.append(skID) + skKeyID = skID + } + if !onlySelfEnc { + pgpKeyIds.append(contentsOf: OutgoingMail.addKeys(adrs: pgpAddresses)) + } + // We add our public if one uses pgp but may not our public key + for id in pgpKeyIds { + if let key = DataHandler.handler.findKey(keyID: id) { + if !key.sentOwnPublicKey { + missingOwnPublic = true + key.sentOwnPublicKey = true + } + } + } + if missingOwnPublic, let sk = sk { + //TODO: @Olli + if let myPK = pgp.exportKey(id: sk.keyID!, isSecretkey: false, autocrypt: false) { + msg = msg + "\n" + myPK //TODO: Append pgp.asc? + } + } + cryptoObject = pgp.encrypt(plaintext: "\n\n"+msg, ids: pgpKeyIds, myId: skKeyID) + if let encData = cryptoObject?.chiphertext { + return encMailBuilder.openPGPEncryptedMessageData(withEncryptedData: encData) + } + return nil + } + + private func orderReceivers(){ + _ = toEntrys.map{orderReceiver(receiver: $0)} + _ = ccEntrys.map{orderReceiver(receiver: $0)} + _ = bccEntrys.map{orderReceiver(receiver: $0)} + } + + private func orderReceiver(receiver: MCOAddress) { + if let adr = DataHandler.handler.findMailAddress(adr: receiver.mailbox) { + let recommandation = Autocrypt.recommandateEncryption(receiver: adr) + if recommandation.recommandEnc && self.sendEncryptedIfPossible, let primaryKey = adr.primaryKey, !primaryKey.currentlyActiveKey.repealed { + pgpAddresses.append(receiver) + } + else { + plainAddresses.append(receiver) + } + } else { + plainAddresses.append(receiver) + } + } + + + private func createBuilder() -> MCOMessageBuilder { + let builder = MCOMessageBuilder() + builder.header.to = toEntrys + builder.header.cc = ccEntrys + builder.header.bcc = bccEntrys + builder.header.from = MCOAddress(displayName: username, mailbox: useraddr) + builder.header.subject = subject + builder.header.setExtraHeaderValue("letterbox", forName: "X-Mailer") + if autocrypt { + Autocrypt.addAutocryptHeader(builder) + } + if let text = textContent { + builder.textBody = "\n\n"+text + } + if let html = htmlContent { + builder.htmlBody = html + } + + for attachment in attachments { + builder.addAttachment(attachment) + } + + if exportSecretKey { + if let keyID = keyID, let keyData = keyData { + Autocrypt.createAutocryptKeyExport(builder: builder, keyID: keyID, key: keyData) + } + } + return builder + } + + private static func mapToMCOAddresses(addr: [String]) -> [MCOAddress] { + return addr.map({(value: String) -> MCOAddress in + return MCOAddress.init(mailbox: value) + }) + } + + private static func mapToMCOAddresses(addr: [Mail_Address]) -> [MCOAddress]{ + return addr.map{$0.transform()} + } + + private static func addKeys(adrs: [MCOAddress]) -> [String] { + var ids = [String]() + for a in adrs { + if let adr = DataHandler.handler.findMailAddress(adr: a.mailbox), let key = adr.primaryKey?.keyID { + ids.append(key) + } + } + return ids + } + + static func createDraft (toEntrys: [String], ccEntrys: [String], bccEntrys: [String], subject: String, textContent: String, htmlContent: String?) -> OutgoingMail{ + let mail = OutgoingMail(toEntrys: toEntrys, ccEntrys: ccEntrys, bccEntrys: bccEntrys, subject: subject, textContent: textContent, htmlContent: htmlContent) + mail.isDraft = true + return mail + } + static func createInvitationMail(toEntrys: [String], ccEntrys: [String], bccEntrys: [String], subject: String, textContent: String, htmlContent: String?) -> OutgoingMail{ + let mail = OutgoingMail(toEntrys: toEntrys, ccEntrys: ccEntrys, bccEntrys: bccEntrys, subject: subject, textContent: textContent, htmlContent: htmlContent) + mail.inviteMail = true + return mail + } + static func createTravelRepeal(addr: String, sharedSecret: String) -> OutgoingMail { + let mail = OutgoingMail(toEntrys: [addr], ccEntrys: [], bccEntrys: [], subject: "Travel Message", textContent: nil, htmlContent: nil) + let bodyText = "You are receiving this message, because the keypair it is signed with will soon be (temporary) disabled by its owner. The owner will be unable to decrypt messages encrypted with the keypair.\nTo be able to communicate securely after the keypair is disabled, you will receive a second message with a new keypair attached. To enable you to trust the new key at the same level as you do for the current key, a secret is attached in the end of this message (see SECRET). The message introducing the new keypair will have a secret attached too. ONLY if both secrets are equal AND there were no other messages introducing new keypairs in the meanwhile you can trust the new keypair!\n\nPlease do not send a message using the current keypair anymore, since it is decativated now.\n\nFor more information visit: "+TravelHandler.website+"\n\nThis Message was automatically generated by my Letterbox email client.\n\nSECRET:\n" + mail.addTextAttachment(text: bodyText+sharedSecret) + mail.addAttachment(filename: "repeal.txt", mimeType: MIMETYPE.travelRepeal.rawValue, charset: "UTF-8", data: sharedSecret.data(using: .utf8)!) + + return mail + } + //TODO: @jabo callForUse + static func createTravelCallForUse(addr: String, sharedSecret: String, pubKey: String, keyID: String, repealedKeyFingerprint: String) -> OutgoingMail { + let mail = OutgoingMail(toEntrys: [addr], ccEntrys: [], bccEntrys: [], subject: "Travel Message", textContent: nil, htmlContent: nil) + //do not use autocrypt to be able to parse new key as related to the prevoius one + mail.autocrypt = false + let bodyText = "This message introduces the senders new keypair. You can trust this key in the same level as you did with the last valid key if and ONLY IF the attached secret (see SECRET) matches with the secret attached to the previous 'Travel Message' asking to repeal the senders keypair.\n\nFor more information visit: "+TravelHandler.website+"\n\nThis Message was automatically generated by my Letterbox email client.\n\nSECRET:\n"+sharedSecret + mail.addTextAttachment(text: pubKey) + mail.addTextAttachment(text: bodyText) + mail.addAttachment(filename: "callForUse.txt", mimeType: MIMETYPE.travelUse.rawValue, charset: "UTF-8", data: (TravelHandler.callForUseSecretHeader+sharedSecret+"\n"+TravelHandler.callForUseFingerprintHeader+repealedKeyFingerprint).data(using: .utf8)!) + mail.addAttachment(filename: keyID+".asc.asc", mimeType: "application/pgp-keys", charset: "UTF-8", data: pubKey.data(using: .utf8)!) + + return mail + } + //TODO: @jabo travelBackup + + static func createSecretKeyExportMail(keyID: String, keyData: String) -> OutgoingMail{ + let useraddr = (UserManager.loadUserValue(Attribute.userAddr) as! String) + let mail = OutgoingMail(toEntrys: [useraddr], ccEntrys: [], bccEntrys: [], subject: "Autocrypt Setup Message", textContent: "", htmlContent: nil) + mail.plainAddresses = mail.pgpAddresses + mail.pgpAddresses = [] + mail.exportSecretKey = true + mail.keyData = keyData + mail.keyID = keyID + return mail + } + static func createLoggingMail(addr: String, textcontent: String) -> OutgoingMail{ + let mail = OutgoingMail(toEntrys: [addr], ccEntrys: [], bccEntrys: [], subject: "[Letterbox] Log", textContent: textcontent, htmlContent: nil) + mail.loggingMail = true + return mail + } +} diff --git a/enzevalos_iphone/PLists/enzevalos-Info.plist b/enzevalos_iphone/PLists/enzevalos-Info.plist index 5e51778971c431cc6d52d9d7adde23b621b51648..f12ce01ba3dd085801e291fb8ec99ca6e8999530 100644 --- a/enzevalos_iphone/PLists/enzevalos-Info.plist +++ b/enzevalos_iphone/PLists/enzevalos-Info.plist @@ -17,7 +17,7 @@ <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleShortVersionString</key> - <string>0.8.8</string> + <string>0.8.16</string> <key>CFBundleSignature</key> <string>????</string> <key>CFBundleURLTypes</key> @@ -32,7 +32,7 @@ </dict> </array> <key>CFBundleVersion</key> - <string>0.8.8</string> + <string>0.8.16</string> <key>LSRequiresIPhoneOS</key> <true/> <key>NSAppTransportSecurity</key> diff --git a/enzevalos_iphone/PasswordToggleVisibilityView.swift b/enzevalos_iphone/PasswordToggleVisibilityView.swift new file mode 100644 index 0000000000000000000000000000000000000000..65eb319a7a441ff5164137696586425aa9ddbaf9 --- /dev/null +++ b/enzevalos_iphone/PasswordToggleVisibilityView.swift @@ -0,0 +1,100 @@ +// +// PasswordToggleVisibilityView.swift +// Guidebook +// +// Created by Mike Sprague on 4/14/16. +// See: https://github.com/Guidebook/HideShowPasswordTextField +// +// + +import Foundation +import UIKit + +protocol PasswordToggleVisibilityDelegate: class { + func viewWasToggled(passwordToggleVisibilityView: PasswordToggleVisibilityView, isSelected selected: Bool) +} + +class PasswordToggleVisibilityView: UIView { + private let eyeOpenedImage: UIImage + private let eyeClosedImage: UIImage + private let checkmarkImage: UIImage + private let eyeButton: UIButton + private let checkmarkImageView: UIImageView + weak var delegate: PasswordToggleVisibilityDelegate? + + enum EyeState { + case open + case closed + } + + var eyeState: EyeState { + set { + eyeButton.isSelected = newValue == .open + } + get { + return eyeButton.isSelected ? .open : .closed + } + } + + var checkmarkVisible: Bool { + set { + checkmarkImageView.isHidden = !newValue + } + get { + return !checkmarkImageView.isHidden + } + } + + override var tintColor: UIColor! { + didSet { + eyeButton.tintColor = tintColor + checkmarkImageView.tintColor = tintColor + } + } + + override init(frame: CGRect) { + self.eyeOpenedImage = UIImage(named: "ic_eye_open")!.withRenderingMode(.alwaysTemplate) + self.eyeClosedImage = UIImage(named: "ic_eye_closed")! + self.checkmarkImage = UIImage(named: "ic_password_checkmark")!.withRenderingMode(.alwaysTemplate) + self.eyeButton = UIButton(type: .custom) + self.checkmarkImageView = UIImageView(image: self.checkmarkImage) + super.init(frame: frame) + setupViews() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("Don't use init with coder.") + } + + private func setupViews() { + let padding: CGFloat = 10 + let buttonWidth = (frame.width / 2) - padding + let buttonFrame = CGRect(x: buttonWidth + padding, y: 0, width: buttonWidth, height: frame.height) + eyeButton.frame = buttonFrame + eyeButton.backgroundColor = UIColor.clear + eyeButton.adjustsImageWhenHighlighted = false + eyeButton.setImage(self.eyeClosedImage, for: .normal) + eyeButton.setImage(self.eyeOpenedImage.withRenderingMode(.alwaysTemplate), for: .selected) + eyeButton.addTarget(self, action: #selector(eyeButtonPressed), for: .touchUpInside) + eyeButton.autoresizingMask = [.flexibleWidth, .flexibleHeight] + eyeButton.tintColor = self.tintColor + self.addSubview(eyeButton) + + let checkmarkImageWidth = (frame.width / 2) - padding + let checkmarkFrame = CGRect(x: padding, y: 0, width: checkmarkImageWidth, height: frame.height) + checkmarkImageView.frame = checkmarkFrame + checkmarkImageView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + checkmarkImageView.contentMode = .center + checkmarkImageView.backgroundColor = UIColor.clear + checkmarkImageView.tintColor = self.tintColor + self.addSubview(checkmarkImageView) + } + + + @objc func eyeButtonPressed(sender: AnyObject) { + eyeButton.isSelected = !eyeButton.isSelected + delegate?.viewWasToggled(passwordToggleVisibilityView: self, isSelected: eyeButton.isSelected) + } +} + +// Animation helpers diff --git a/enzevalos_iphone/PersistentKey+CoreDataClass.swift b/enzevalos_iphone/PersistentKey+CoreDataClass.swift index d631d690b503954176926540f80fff46559435a4..02b5f05baca895bbe9c9a1062ddfe04fec87f0fa 100644 --- a/enzevalos_iphone/PersistentKey+CoreDataClass.swift +++ b/enzevalos_iphone/PersistentKey+CoreDataClass.swift @@ -12,15 +12,6 @@ import CoreData @objc(PersistentKey) public class PersistentKey: NSManagedObject { - open var prefEnc: EncState { - get { - return prefer_encryption - } - set { - prefer_encryption = newValue - } - } - var counterSignedMails: Int { if let signedMails = self.signedMails { return signedMails.count diff --git a/enzevalos_iphone/PersistentKey+CoreDataProperties.swift b/enzevalos_iphone/PersistentKey+CoreDataProperties.swift index f6776c4bac9a9a1d654cd0365cc1474f5294c3ee..b1af66d58d263e57cef06b558bad1be68d334d68 100644 --- a/enzevalos_iphone/PersistentKey+CoreDataProperties.swift +++ b/enzevalos_iphone/PersistentKey+CoreDataProperties.swift @@ -130,18 +130,21 @@ extension PersistentKey { public var prefer_encryption: EncState{ set { - let name = "prefer_encryption" + let name = "preferEncryption" self.willChangeValue(forKey: name) self.setPrimitiveValue(newValue.asInt(), forKey: name) self.didChangeValue(forKey: name) } get { - let name = "prefer_encryption" + let name = "preferEncryption" self.willAccessValue(forKey: name) - let i = self.primitiveValue(forKey: name) as! Int - self.didAccessValue(forKey: name) - return EncState.find(i: i) + if let i = self.primitiveValue(forKey: name) { + let value = i as! Int + self.didAccessValue(forKey: name) + return EncState.find(i: value) + } + return EncState.NOAUTOCRYPT } } diff --git a/enzevalos_iphone/PersistentMail +CoreDataClass.swift b/enzevalos_iphone/PersistentMail +CoreDataClass.swift index 3cd60597f39fb21ff114e5462403ba42579d09e7..8e210a89adc8d75a9f44164005473184b7944823 100644 --- a/enzevalos_iphone/PersistentMail +CoreDataClass.swift +++ b/enzevalos_iphone/PersistentMail +CoreDataClass.swift @@ -26,12 +26,46 @@ import CoreData open class PersistentMail: NSManagedObject, Mail { public var predecessor: PersistentMail? = nil - var showMessage: Bool = false var isSecure: Bool { return isEncrypted && isSigned && isCorrectlySigned && !unableToDecrypt && !trouble && keyID != nil } + var encState: EncryptionState { + get{ + if unableToDecrypt { + return EncryptionState.UnableToDecrypt + } + if !isEncrypted { + return EncryptionState.NoEncryption + } + else if self.decryptedWithOldPrivateKey { + return EncryptionState.ValidEncryptedWithOldKey + } + else { + return EncryptionState.ValidedEncryptedWithCurrentKey + } + } + } + + var sigState: SignatureState { + get{ + if isSigned && isCorrectlySigned { + return SignatureState.ValidSignature + } + else if isSigned && keyID == nil { + return SignatureState.NoPublicKey + } + else if isSigned { + return SignatureState.InvalidSignature + } + else { + return SignatureState.NoSignature + } + + } + } + var isRead: Bool { get { let value = flag.contains(MCOMessageFlag.seen) diff --git a/enzevalos_iphone/PersistentMail +CoreDataProperties.swift b/enzevalos_iphone/PersistentMail +CoreDataProperties.swift index 4ae4b89bc6a6385441b754cc15f75e03a160560a..06fa2f50780e4c4bd238513c5394f0b14437f419 100644 --- a/enzevalos_iphone/PersistentMail +CoreDataProperties.swift +++ b/enzevalos_iphone/PersistentMail +CoreDataProperties.swift @@ -48,7 +48,7 @@ extension PersistentMail { public var flag: MCOMessageFlag { set { if newValue != flag { - AppDelegate.getAppDelegate().mailHandler.addFlag(self.uid, flags: newValue, folder: folder.name) + AppDelegate.getAppDelegate().mailHandler.setFlag(self.uid, flags: newValue, folder: folder.name) self.willChangeValue(forKey: "flag") self.setPrimitiveValue(newValue.rawValue, forKey: "flag") self.didChangeValue(forKey: "flag") diff --git a/enzevalos_iphone/ReadVENDelegate.swift b/enzevalos_iphone/ReadVENDelegate.swift index eaeeca8c3540328015fb4a723a4e9fd0a619c55f..66e6f8676c918495ae293edb0acf1980b70daa23 100644 --- a/enzevalos_iphone/ReadVENDelegate.swift +++ b/enzevalos_iphone/ReadVENDelegate.swift @@ -55,7 +55,6 @@ extension ReadVENDelegate: VENTokenFieldDelegate { tokenField.textTokens.add(text) tokenField.mailTokens.add(email) tokenField.reloadData() -// tokenField.sendActionsForControlEvents(UIControlEvents.EditingDidEnd) } func tokenField(_ tokenField: VENTokenField, didChangeContentHeight height: CGFloat) { @@ -82,7 +81,7 @@ extension ReadVENDelegate: VENTokenFieldDelegate { } func tokenField(_ tokenField: VENTokenField, colorSchemeForTokenAt index: UInt) -> UIColor { - if let adr = DataHandler.handler.findMailAddress(adr: tokenField.mailTokens[Int(index)] as! String) { + if let adr = DataHandler.handler.findMailAddress(adr: tokenField.mailTokens[Int(index)] as! String){ if adr.hasKey { return UIColor.init(red: 0, green: 122.0 / 255.0, blue: 1, alpha: 1) } diff --git a/enzevalos_iphone/ReadViewController.swift b/enzevalos_iphone/ReadViewController.swift index 69f1584b9d4e56f8c4d573db32524d537e60210d..b65844bd157922558a2e4a53b8fdba5c27274dc6 100644 --- a/enzevalos_iphone/ReadViewController.swift +++ b/enzevalos_iphone/ReadViewController.swift @@ -105,7 +105,7 @@ class ReadViewController: UITableViewController { if isDraft || isInArchiveFolder || isTrash { archiveButton.isEnabled = false } - + if Logger.logging, let mail = self.mail { var message = "none" if showInfoSection(mail: mail) { @@ -325,7 +325,7 @@ class ReadViewController: UITableViewController { if let mail = mail { if isTrash { Logger.log(delete: mail, toTrash: false) - AppDelegate.getAppDelegate().mailHandler.addFlag(mail.uid, flags: MCOMessageFlag.deleted, folder: mail.folder.path) + AppDelegate.getAppDelegate().mailHandler.setFlag(mail.uid, flags: MCOMessageFlag.deleted, folder: mail.folder.path) } else { Logger.log(delete: mail, toTrash: true) AppDelegate.getAppDelegate().mailHandler.move(mails: [mail], from: mail.folder.path, to: UserManager.backendTrashFolderPath) @@ -464,13 +464,13 @@ class ReadViewController: UITableViewController { iconView.contentMode = .scaleAspectFit var icon: UIImage if mail.trouble { - icon = IconsStyleKit.imageOfLetterCorrupted + icon = StudySettings.securityIndicator.imageOfCorruptedIndicator() } else if deletedWhileTravel { icon = IconsStyleKit.imageOfLetter } else if mail.isSecure { - icon = IconsStyleKit.imageOfLetterOpen + icon = StudySettings.securityIndicator.imageOfSecureIndicator(open: true) } else { - icon = IconsStyleKit.imageOfPostcard + icon = StudySettings.securityIndicator.imageOfInsecureIndicator() } iconView.image = icon iconButton.setImage(icon, for: UIControlState()) @@ -668,7 +668,7 @@ extension ReadViewController: SendViewDelegate { reactButton.isEnabled = false if isDraft { if let mail = mail { - AppDelegate.getAppDelegate().mailHandler.addFlag(mail.uid, flags: MCOMessageFlag.deleted, folder: mail.folder.path) + AppDelegate.getAppDelegate().mailHandler.setFlag(mail.uid, flags: MCOMessageFlag.deleted, folder: mail.folder.path) } self.navigationController?.viewControllers.removeLast() } diff --git a/enzevalos_iphone/SendViewController+Invitation.swift b/enzevalos_iphone/SendViewController+Invitation.swift index 36d371d91f0403a398dd3aa745561a354ccb5769..e55923401e678a6bc0ba4ec32cf2ac89a9b17954 100644 --- a/enzevalos_iphone/SendViewController+Invitation.swift +++ b/enzevalos_iphone/SendViewController+Invitation.swift @@ -34,7 +34,7 @@ extension SendViewController { var isCensored: Bool { get { - return StudySettings.invitationsmode == InvitationMode.Censorship + return StudySettings.invitationsmode == Inviation.Censorship } } @@ -95,7 +95,7 @@ extension SendViewController { } } - if (self.invitationSelection.code == nil && StudySettings.invitationsmode == InvitationMode.PasswordEnc) { + if (self.invitationSelection.code == nil && StudySettings.invitationsmode == Inviation.PasswordEnc) { self.invitationSelection.code = cipherText.password } var previousText = "" @@ -103,7 +103,7 @@ extension SendViewController { if let range = text.range(of: NSLocalizedString("Mail.Signature", comment: "")) { text.removeSubrange(range) } - + if let preMail = prefilledMail, let previousBody = preMail.body { if let range = text.range(of: previousBody) { previousText = previousBody diff --git a/enzevalos_iphone/SendViewController.swift b/enzevalos_iphone/SendViewController.swift index 2730060e7b7371ca0ba776865905fa8c0f504612..2b7c4bfc1817f40e204dbf47ede760dde0805721 100644 --- a/enzevalos_iphone/SendViewController.swift +++ b/enzevalos_iphone/SendViewController.swift @@ -59,7 +59,7 @@ class SendViewController: UIViewController { var tableDataDelegate = TableViewDataDelegate(insertCallback: { (name: String, address: String) -> Void in return }) var collectionDataDelegate = CollectionDataDelegate(suggestionFunc: AddressHandler.frequentAddresses, insertCallback: { (name: String, address: String) -> Void in return }) var recognizer: UIGestureRecognizer = UIGestureRecognizer.init() - var freeTextInviationTitle = StudySettings.freeTextInvitationTitle + var freeTextInviationTitle = StudySettings.invitationsmode.freeTextInvitationTitle //These attributes may be interesting to set in a segue to SendViewController var prefilledMail: EphemeralMail? = nil @@ -817,7 +817,8 @@ class SendViewController: UIViewController { let inviteMail = invite || mailSecurityState == .extendedPostcard(.censored) || mailSecurityState == .extendedPostcard(.partiallyEncrypted) let travelHandler = TravelHandler.instance() - mailHandler.send(toEntrys as NSArray as! [String], ccEntrys: ccEntrys as NSArray as! [String], bccEntrys: [], subject: subject, message: message, sendEncryptedIfPossible: !enforcePostcard && travelHandler.mode != .borderCrossing, callback: self.mailSend, htmlContent: hmtlmessage, inviteMail: inviteMail, textparts: counterTextparts) + mailHandler.send(toEntrys as NSArray as! [String], ccEntrys: ccEntrys as NSArray as! [String], bccEntrys: [], subject: subject, message: message, sendEncryptedIfPossible: !enforcePostcard && travelHandler.mode != .borderCrossing, callback: nil, htmlContent: hmtlmessage, inviteMail: inviteMail, textparts: counterTextparts) + self.mailSend(nil) } } diff --git a/enzevalos_iphone/StringExtension.swift b/enzevalos_iphone/StringExtension.swift index 41b190862ee47a92091ca8b432994a5a6968af1c..f3f34d94389570bda74b8c02eb94fdff65d008bf 100644 --- a/enzevalos_iphone/StringExtension.swift +++ b/enzevalos_iphone/StringExtension.swift @@ -30,7 +30,6 @@ extension String { if result == errSecSuccess { return randomBytes.base64EncodedString() } else { - print("Problem generating random bytes") return "" } } @@ -45,4 +44,10 @@ extension String { let components = self.components(separatedBy: .whitespacesAndNewlines) return components.filter { !$0.isEmpty }.joined(separator: " ") } + + func remove(seperatedBy: CharacterSet) -> String { + let components = self.components(separatedBy: .whitespacesAndNewlines) + return components.filter { !$0.isEmpty }.joined(separator: " ") + } } + diff --git a/enzevalos_iphone/StudySettings.swift b/enzevalos_iphone/StudySettings.swift index e0e22a92dd069c3f27814a91dc33ea41999406cf..3280c3d7145a8218a1d4e115a249f55e2cf01481 100644 --- a/enzevalos_iphone/StudySettings.swift +++ b/enzevalos_iphone/StudySettings.swift @@ -21,80 +21,41 @@ import Foundation import KeychainAccess -enum StudyParamter: Int { - case Warning = 0 - case Invitation = 1 - var name: String { - get { - switch self { - case .Warning: - return "warning" - case .Invitation: - return "invitation" - } - } - } - - var keyName: String { - get { - switch self { - case .Warning: - return "hideWarnings" - case .Invitation: - return "invitation mode" - } +class StudySettings { + static let allAvailableParameters: [StudyParameterProtocol.Type] = [SecurityIndicator.self, Warning.self, Inviation.self] + static var parameters: [StudyParameterProtocol.Type] = [] { + didSet{ + securityIndicator = SecurityIndicator.load() as! SecurityIndicator + invitationsmode = Inviation.load() as! Inviation } } - var numberOfTreatments: UInt32 { - get { - switch self { - case .Warning: - return 2 - case .Invitation: - return 3 - } - } + + static var studyMode = true + static var studyID: String { + return UserDefaults.standard.string(forKey: "studyID") ?? "" } -} - -enum InvitationMode: Int { - case InviteMail - case PasswordEnc - case Censorship - case FreeText -} -class StudySettings { - static var studyMode = false static var presentFirstQuestionaireMail = false - static let parameters = [StudyParamter.Invitation] - + + static var securityIndicator: SecurityIndicator = SecurityIndicator.load() as! SecurityIndicator + static var invitationsmode: Inviation = Inviation.load() as! Inviation + public static var invitationEnabled: Bool { get { - return true + return false } } - static var freeTextInvitationTitle: String { - get { - switch self.invitationsmode { - case .FreeText, .InviteMail: - return NSLocalizedString("inviteContacts", comment: "Allows users to invite contacts without encryption key") - case .Censorship, .PasswordEnc: - return NSLocalizedString("inviteContacts.Censor", comment: "Allows users to invite contacts without encryption key") + + static func isStudyParameter(type: StudyParameterProtocol.Type) -> Bool { + for para in parameters { + if type == para { + return true } } + return false } - static let faqURL = "https://userpage.fu-berlin.de/letterbox/faq.html" - static let raffleURL = "" - static var studyID: String { - return UserDefaults.standard.string(forKey: "studyID") ?? "" - } - static var entrySurveyURL: String { - get { - return "https://userpage.fu-berlin.de/letterbox/entrysurvey.html?id=\(studyID)" - } - } + static var bitcoinMails: Bool { //do we recived a mail from bitcoin.de get { return UserDefaults.standard.bool(forKey: "bitcoin") @@ -104,58 +65,19 @@ class StudySettings { let keychain = Keychain(service: "Enzevalos/Study") keychain["bitcoin"] = "true" UserDefaults.standard.set(true, forKey: "bitcoin") -// Logger.queue.async(flags: .barrier) { Logger.log(bitcoinMail: true) -// } } } } - - static var invitationsmode: InvitationMode { - get { - return UserManager.loadInvitationMode() - let value = UserDefaults.standard.integer(forKey: StudyParamter.Invitation.keyName) - if let mode = InvitationMode.init(rawValue: value) { - return mode - } - return InvitationMode.InviteMail - } - } - - - private static var studyParameters: [StudyParamter: Int] { - get { - let keychain = Keychain(service: "Enzevalos/Study") - var studyParamters = [StudyParamter: Int]() - for parameter in parameters { - var value: Int? - if let state = keychain[parameter.keyName], let num = Int(state) { - value = num - } else { - value = Int(arc4random_uniform(parameter.numberOfTreatments)) - if let value = value { - keychain[parameter.keyName] = String(value) - } - } - if let v = value { - UserDefaults.standard.set(v, forKey: parameter.keyName) - studyParamters[parameter] = v - } - } - return studyParamters - } - } - - static func setupStudy() { if !studyMode { - //Logger.logging = false + Logger.logging = false return } if UserDefaults.standard.string(forKey: "studyID") != nil && UserDefaults.standard.string(forKey: "hideWarnings") != nil { //no need to refill this fields, they are already loaded return } - //Logger.logging = true + Logger.logging = true let keychain = Keychain(service: "Enzevalos/Study") if let studyID = keychain["studyID"] { UserDefaults.standard.set(studyID, forKey: "studyID") @@ -173,91 +95,9 @@ class StudySettings { keychain["bitcoin"] = "false" UserDefaults.standard.set(false, forKey: "bitcoin") } - let parameters = studyParameters - - -// Logger.queue.async(flags: .barrier) { Logger.log(setupStudy: parameters, alreadyRegistered: !presentFirstQuestionaireMail) -// } - - } - //create local mail for first interview here - static func firstMail() { - if !studyMode || !presentFirstQuestionaireMail { - return - } - let subject = "Herzlich Willkommen in Letterbox" - let body = - """ - Liebe Teilnehmerin, lieber Teilnehmer, - - Herzlichen Glückwunsch! Sie haben Letterbox erfolgreich installiert. - - Wenn Sie Fragen zur App oder Verschlüsselung haben, besuchen Sie doch unsere Hilfeseite: - \(faqURL) - - Dort finden Sie auch Videos zum Thema Ende-zu-Ende-Verschlüsselung. - Falls Sie Fragen haben oder uns Feedback geben möchten, freuen wir uns auf Ihre E-Mail! - - Die Studie umfasst drei Aufgaben und kann jederzeit abgebrochen werden. Für Fragen schreiben Sie uns bitte eine E-Mail und benutzen Sie bitte nach Möglichkeit die Letterbox dafür. - - In der ersten Aufgabe verfassen Sie bitte einen ersten Brief, indem Sie auf diese E-Mail antworten. Bitte teilen Sie uns Ihre Meinung mit. Ist etwas unklar geblieben? Was war neu für Sie? Was fanden Sie besonders interessant; was uninteressant? Hätten Sie sich noch weitere Informationen gewünscht? Sie können auch gerne Fragen zur Einführung stellen. - - Nach Beantwortung dieser E-Mail senden wir Ihnen zu einem späteren Zeitpunkt eine zweite E-Mail mit der nächsten kurzen Aufgabe zu. - - Vielen Dank für Ihre Teilnahme und mit freundlichen Grüßen, - Ihr Letterbox-Team - - PS: Diese Nachricht wurde automatisch in Letterbox erzeugt und ist nur hier gespeichert. - """ - mailToParticipat(subject: subject, body: body) - } - - static func givecards() { - if !studyMode || !presentFirstQuestionaireMail { - return - } - let subject = "Teilnahmeentschädigung: Verlosung von Amazon-Gutscheinen" - let body = - """ - Liebe Teilnehmerin, lieber Teilnehmer, - - unter den teilnehmenden Personen werden 20 Amazon-Gutscheine im Wert von jeweils 50 Euro verlost. - - Um an der Verlosung teilnehmen zu können, müssen Sie uns Ihren Namen und die postalische Adresse mitteilen. - Falls Sie einen Gutschein gewinnen, wird dieser Ihnen per Post zugesendet. Außerdem werden Ihr Name und Ihre Adresse für den Nachweis der ordnungsgemäßen Verwendung der Gelder gespeichert, andernfalls werden sie gelöscht. - - Ihre Name und Ihre Adresse werden nicht mit anderen erhobenen Daten verknüpft und getrennt von diesen gespeichert. - - Wenn Sie an der Verlosung teilnehmen möchten, melden Sie sich bitte auf folgenden Link an: - \(raffleURL) - - Vielen Dank für Ihre Teilnahme und mit freundlichen Grüßen, - Ihr Letterbox-Team - - PS: Diese Nachricht wurde automatisch in Letterbox erzeugt und ist nur hier gespeichert. - """ - - mailToParticipat(subject: subject, body: body) } - - private static func mailToParticipat(subject: String, body: String) { - let senderAdr = SUPPORT_MAIL_ADR - let sender = MCOAddress.init(displayName: "Letterbox-Team", mailbox: senderAdr) - var keyID: String? - if let addr = DataHandler.handler.findMailAddress(adr: senderAdr) { - if let pk = addr.primaryKey { - keyID = pk.keyID - } - } - let cryptoObject = CryptoObject(chiphertext: nil, plaintext: body, decryptedData: body.data(using: .utf8), sigState: SignatureState.ValidSignature, encState: EncryptionState.ValidedEncryptedWithCurrentKey, signKey: keyID, encType: CryptoScheme.PGP, signedAdrs: [senderAdr]) - - _ = DataHandler.handler.createMail(0, sender: sender, receivers: [], cc: [], time: Date(), received: false, subject: subject, body: body, flags: MCOMessageFlag.init(rawValue: 0), record: nil, autocrypt: nil, decryptedData: cryptoObject, folderPath: UserManager.backendInboxFolderPath, secretKey: nil, encryptedBody: nil) - } - - - public static func setupStudyKeys() { if studyMode || Logger.logging { setupStudyPublicKeys() diff --git a/enzevalos_iphone/SwiftPGP.swift b/enzevalos_iphone/SwiftPGP.swift index b07eac640ad336eede678932e30730aa9e45c378..6e1a7f0332f18c400433003884177437dbac9066 100644 --- a/enzevalos_iphone/SwiftPGP.swift +++ b/enzevalos_iphone/SwiftPGP.swift @@ -1,9 +1,7 @@ // // SwiftPGP.swift -// ObjectivePGP // // Created by Oliver Wiese on 25.09.17. -// Copyright © 2017 Marcin Krzyżanowski. All rights reserved. // import Foundation @@ -11,7 +9,7 @@ import Security import KeychainAccess class SwiftPGP: Encryption { - + let cryptoScheme = CryptoScheme.PGP let PasscodeSize = 36 @@ -90,8 +88,8 @@ class SwiftPGP: Encryption { } } - //TODO: rename! bad naming, because it includes the current secretKey too - private var oldSecretKeys: [Key]{ + //TODO: @jabo oldSecretKeys + private var allSecretKeys: [Key]{ get{ var myKeys = Set<Key>() if let keys = try? keychain.getString("secretKeys"){ @@ -190,9 +188,9 @@ class SwiftPGP: Encryption { } func generateKey(adr: String, new: Bool = false) -> String{ - if oldSecretKeys.count > 0 && !new{ + if allSecretKeys.count > 0 && !new{ var primkey: Key? - for key in oldSecretKeys{ + for key in allSecretKeys{ if vaildAddress(key: key).contains(adr){ _ = storeKey(key: key) primkey = key @@ -215,12 +213,12 @@ class SwiftPGP: Encryption { do { try keychain.remove(key.keyID.longIdentifier) } catch { - //TODO: do something here + NSLog("Error while removing key from keychain. KeyID: %s, isSecretKey: %s ", key.keyID, key.isSecret) } } func deleteSecretKeys() { - let secretKeys = oldSecretKeys + let secretKeys = allSecretKeys for key in secretKeys { //a Key-object may contain both public and secret key var pubKey: Key? = nil @@ -235,10 +233,20 @@ class SwiftPGP: Encryption { do { try keychain.remove("secretKeys") } catch { - //TODO: do something here + NSLog("Eror while removing secretKeys keychain") } } + func importKeys(keys: [String]) -> [String] { + var keyIds = [String]() + for key in keys { + if let newIds = try? importKeys(key: key, pw: nil, isSecretKey: false, autocrypt: false) { + keyIds.append(contentsOf: newIds) + } + } + return keyIds + } + func importKeys (key: String, pw: String?, isSecretKey: Bool, autocrypt: Bool) throws -> [String]{ var keys = [Key]() if autocrypt{ @@ -256,7 +264,7 @@ class SwiftPGP: Encryption { } for key in keys{ if key.isSecret{ - //test key{ + //test key try ObjectivePGP.sign("1234".data(using: .utf8)!, detached: false, using: [key], passphraseForKey: {(key) -> String? in return pw}) } } @@ -269,7 +277,7 @@ class SwiftPGP: Encryption { } return [String]() } - + func importKeysFromFile(file: String, pw: String?) throws -> [String]{ if let keys = try? ObjectivePGP.readKeys(fromPath: file){ @@ -302,7 +310,7 @@ class SwiftPGP: Encryption { armoredKey = Armor.armored(key, as: PGPArmorType.secretKey) } else{ - armoredKey = Armor.armored(key, as: PGPArmorType.publicKey) + armoredKey = Armor.armored(key, as: PGPArmorType.publicKey) } if isSecretKey && autocrypt{ // Create Autocrypt Setup-message @@ -351,11 +359,8 @@ class SwiftPGP: Encryption { return nil } - func encrypt(plaintext: String, ids: [String], myId: String) -> CryptoObject { - return encrypt(plaintext: plaintext, ids: ids, myId: myId, encryptForMyID: true) - } - func encrypt(plaintext: String, ids: [String], myId: String, encryptForMyID: Bool) -> CryptoObject { + func encrypt(plaintext: String, ids: [String], myId: String, encryptForMyID: Bool = true) -> CryptoObject { let keyring = Keyring() var keys: [Key] = [] let signKey = loadKey(id: myId) @@ -373,8 +378,8 @@ class SwiftPGP: Encryption { } } if let data = plaintext.data(using: String.Encoding.utf8){ - do{ - let chipher = try ObjectivePGP.encrypt(data, addSignature: encryptForMyID, using: keys, passphraseForKey: loadPassword) + do { + let chipher = try ObjectivePGP.encrypt(data, addSignature: encryptForMyID && signKey != nil, using: keys, passphraseForKey: loadPassword) let armorChipherString = Armor.armored(chipher, as: .message) let armorChipherData = armorChipherString.data(using: .utf8) if signKey != nil{ @@ -383,21 +388,70 @@ class SwiftPGP: Encryption { return CryptoObject(chiphertext: armorChipherData, plaintext: plaintext, decryptedData: data, sigState: SignatureState.NoSignature, encState: EncryptionState.ValidedEncryptedWithCurrentKey, signKey: nil, encType: CryptoScheme.PGP, signedAdrs: []) } catch { - print("Encryption error!") + NSLog("Encryption error. Ids: %s, myID: %s, encryptedForMyID: %s", ids, myId, encryptForMyID) + } + } + + return CryptoObject(chiphertext: nil, plaintext: nil,decryptedData: nil, sigState: SignatureState.InvalidSignature, encState: EncryptionState.UnableToDecrypt, signKey: nil, encType: cryptoScheme, signedAdrs: signedAdr) + } + + func verify(data: Data, attachedSignature: Data?, verifyId: String, fromAdr: String) -> CryptoObject { + var sigKeyID: String? = nil + var signedAdr = [String]() + var sigState = SignatureState.NoSignature + let encState = EncryptionState.NoEncryption + let keyring = Keyring() + var toverify = data + + if let text = String(data: data, encoding: .utf8) { + if let unarmored = try? Armor.readArmored(text){ + toverify = unarmored } } + if let key = loadKey(id: verifyId){ + keyring.import(keys: [key]) + } - return CryptoObject(chiphertext: nil, plaintext: nil,decryptedData: nil, sigState: SignatureState.InvalidSignature, encState: EncryptionState.UnableToDecrypt, signKey: nil, encType: cryptoScheme, signedAdrs: signedAdr) + do{ + let keys = keyring.keys + try ObjectivePGP.verify(toverify, withSignature: attachedSignature, using: keys, passphraseForKey: loadPassword) + sigState = SignatureState.ValidSignature + sigKeyID = verifyId + signedAdr = vaildAddress(key: keys.first) + } catch { + let nsError = error as NSError + print(nsError) + switch nsError.code { + case 7: // no public key + sigState = SignatureState.NoPublicKey + case 8: // no signature + sigState = SignatureState.NoSignature + case 9: // unable to decrypt + sigState = SignatureState.InvalidSignature + default: + sigState = SignatureState.InvalidSignature + } + } + if !signedAdr.contains(fromAdr) && sigState == SignatureState.ValidSignature { + sigState = .InvalidSignature + } + return CryptoObject(chiphertext: data, plaintext: nil, decryptedData: nil, sigState: sigState, encState: encState, signKey: sigKeyID, encType: .PGP, signedAdrs: signedAdr) } - func decrypt(data: Data, decryptionIDs: [String], verifyIds: [String], fromAdr: String?) -> CryptoObject { -// guard let prefKey = DataHandler.handler.prefSecretKey() else { -// return CryptoObject(chiphertext: data, plaintext: nil, decryptedData: nil, sigState: .NoSignature, encState: .UnableToDecrypt, signKey: nil, encType: .PGP, signedAdrs: []) -// } //maybe we don't need this, because no decryptionIDs can be given + func decrypt(mail: IncomingMail) -> CryptoObject { + let decIds = mail.decryptionKeyIDs + let data = mail.cryptoData + let sigIDs = mail.signatureKeyIDs + if let addr = mail.signatureAddr { + return decrypt(data: data, attachedSignature: nil, decKeyIDs: decIds, signatureIDs: sigIDs, fromAddr: addr) + } + return CryptoObject(chiphertext: data, plaintext: nil, decryptedData: nil, sigState: .InvalidSignature, encState: .UnableToDecrypt, signKey: nil, encType: .PGP, signedAdrs: []) //TODO: Check decryption only + } + + func decrypt(data: Data, attachedSignature: Data? = nil, decKeyIDs: [String], signatureIDs: [String], fromAddr: String) -> CryptoObject{ let prefKey = DataHandler.handler.prefSecretKey() - var plaindata: Data? = nil var plaintext: String? = nil var sigState = SignatureState.NoSignature @@ -409,10 +463,11 @@ class SwiftPGP: Encryption { var validDecryptionIDs: [String] = [] /* - DECRYPTION + DECRYPTION */ // TODO: Maybe consider: try ObjectivePGP.recipientsKeyID(forMessage: ...) but currently not working... - if let prefID = prefID, decryptionIDs.contains(prefID), let decKey = loadKey(id: prefID) { + + if let prefID = prefID, decKeyIDs.contains(prefID), let decKey = loadKey(id: prefID) { let (currentPlain, currentEncState) = decryptMessage(data: data, keys: [decKey], encForCurrentSK: true) if currentEncState == EncryptionState.ValidedEncryptedWithCurrentKey { plaindata = currentPlain @@ -421,7 +476,7 @@ class SwiftPGP: Encryption { } } if encState != .ValidedEncryptedWithCurrentKey { - for decID in decryptionIDs { + for decID in decKeyIDs { if let decKey = loadKey(id: decID) { keyring = Keyring() let (currentPlain, currentEncState) = decryptMessage(data: data, keys: [decKey], encForCurrentSK: true) @@ -442,62 +497,39 @@ class SwiftPGP: Encryption { (plaindata, encState) = decryptMessage(data: data, keys: keyring.keys, encForCurrentSK: false) } /* - VERIFICATION + VERIFICATION */ // test if message ist signed - sigState = verifyMessage(data: data, keys: []) + sigState = verifySignature(data: data, attachedSignature: attachedSignature, keys: []) for id in validDecryptionIDs { if let key = loadKey(id: id) { keyring.import(keys: [key]) - let currentState = verifyMessage(data: data, keys: [key]) + let currentState = verifySignature(data: data, attachedSignature: attachedSignature, keys: [key]) if currentState == SignatureState.ValidSignature{ sigState = currentState sigKeyID = id signedAdr = vaildAddress(key: key) break } - //if currentState == SignatureState.InvalidSignature{ - sigState = currentState - //} + sigState = currentState } } if sigState != .ValidSignature { - for id in verifyIds { + for id in signatureIDs { if let key = loadKey(id: id) { keyring.import(keys: [key]) - let currentState = verifyMessage(data: data, keys: keyring.keys) + let currentState = verifySignature(data: data, attachedSignature: attachedSignature, keys: keyring.keys) if currentState == SignatureState.ValidSignature { sigState = currentState sigKeyID = id signedAdr = vaildAddress(key: key) break } - //if currentState == SignatureState.InvalidSignature { - sigState = currentState - //} + sigState = currentState } } } - // TODO: remove if not needed anymore (I think so) -// if sigState == SignatureState.ValidSignature && sigKeyID == nil{ -// for id in decryptionIDs{ -// if let key = loadKey(id: id){ -// keyring.import(keys: [key]) -// let currentState = verifyMessage(data: data, keys: keyring.keys) -// if currentState == SignatureState.ValidSignature{ -// sigState = currentState -// sigKeyID = id -// signedAdr = vaildAddress(key: key) -// break -// } -// if currentState == SignatureState.InvalidSignature{ -// sigState = currentState -// } -// } -// } -// } - if encState == EncryptionState.UnableToDecrypt{ sigState = SignatureState.NoSignature } @@ -507,17 +539,35 @@ class SwiftPGP: Encryption { else if encState == .NoEncryption{ plaintext = String(data: data, encoding: String.Encoding.utf8) } + + if sigState == .ValidSignature && !signedAdr.contains(fromAddr) { + sigState = .InvalidSignature + } return CryptoObject(chiphertext: data, plaintext: plaintext, decryptedData: plaindata, sigState: sigState, encState: encState, signKey: sigKeyID, encType: CryptoScheme.PGP, signedAdrs: signedAdr) } - - func decrypt(data: Data,decryptionId: String?, verifyIds: [String], fromAdr: String?) -> CryptoObject{ - if let decId = decryptionId{ - return decrypt(data: data, decryptionIDs: [decId], verifyIds: verifyIds, fromAdr: fromAdr) + //TODO: remove since unsed + /*private func verifyData(toVerifyData: Data, attachedSignature: Data?, signatureIDs: [String], keyring: Keyring) -> (sigState: SignatureState, sigKeyID: String?, signedAdr: [String]) { + var sigState = verifySignature(data: toVerifyData, attachedSignature: attachedSignature, keys: []) + var sigKeyID: String? + var signedAdr: [String] = [] + for id in signatureIDs { + if let key = loadKey(id: id){ + keyring.import(keys: [key]) + let currentState = verifySignature(data: toVerifyData, attachedSignature: attachedSignature, keys: keyring.keys) + if currentState == SignatureState.ValidSignature{ + sigState = currentState + sigKeyID = id + signedAdr = vaildAddress(key: key) + break + } + if currentState == SignatureState.InvalidSignature{ + sigState = currentState + } + } } - return decrypt(data: data, decryptionIDs: [String](), verifyIds: verifyIds, fromAdr: fromAdr) - } - + return (sigState, sigKeyID, signedAdr) + }*/ private func decryptMessage(data: Data, keys: [Key], encForCurrentSK: Bool) -> (Data?, EncryptionState){ if let dataString = String(data: data, encoding: .utf8) { @@ -543,33 +593,48 @@ class SwiftPGP: Encryption { return (nil, EncryptionState.UnableToDecrypt) } } - + } return (nil, EncryptionState.NoEncryption) } - private func verifyMessage(data: Data, keys: [Key]) -> SignatureState{ - if let dataString = String(data: data, encoding: .utf8), let unarmored = try? Armor.readArmored(dataString){ - do{ - try ObjectivePGP.verify(unarmored, withSignature: nil, using: keys, passphraseForKey: loadPassword) - return SignatureState.ValidSignature - } catch { - let nsError = error as NSError - switch nsError.code { - case 7: // no public key - return SignatureState.NoPublicKey - case 8: // no signature - return SignatureState.NoSignature - case 9: // unable to decrypt - return SignatureState.InvalidSignature - default: - return SignatureState.InvalidSignature - } - } + private func verifySignature(sigString: String, attachedSignature: Data?, keys: [Key]) -> SignatureState { + if let unarmored = try? Armor.readArmored(sigString){ + return verifySignature(data: unarmored, attachedSignature: attachedSignature, keys: keys) + } + if let data = sigString.data(using: .utf8) { + return verifySignature(data: data, attachedSignature: attachedSignature, keys: keys) } return SignatureState.NoSignature } + private func verifySignature(data: Data, attachedSignature: Data?, keys: [Key]) -> SignatureState { + var sigData = data + var sigState = SignatureState.NoSignature + if let dataString = String(data: data, encoding: .utf8), let unarmored = try? Armor.readArmored(dataString){ + sigData = unarmored + } + do{ + if keys.isEmpty && attachedSignature != nil { + return SignatureState.NoPublicKey + } + try ObjectivePGP.verify(sigData, withSignature: attachedSignature, using: keys, passphraseForKey: loadPassword) + sigState = SignatureState.ValidSignature + } catch { + let nsError = error as NSError + switch nsError.code { + case 7: // no public key + sigState = SignatureState.NoPublicKey + case 8: // no signature + sigState = SignatureState.NoSignature + case 9: // unable to decrypt + sigState = SignatureState.InvalidSignature + default: + sigState = SignatureState.InvalidSignature + } + } + return sigState + } func vaildAddress(key: Key?) -> [String]{ var adrs = [String]() @@ -583,9 +648,7 @@ class SwiftPGP: Encryption { let e = end.upperBound var adr = String(user.userID[s..<e]) if adr.count > 2 { - adr = String(user.userID[user.userID.index(s, offsetBy: 1)..<user.userID.index(e, offsetBy: -1)]) - //adr = adr.substring(to: adr.index(before: adr.endIndex)) // remove > - //adr.remove(at: adr.startIndex) // remove < + adr = String(user.userID[user.userID.index(s, offsetBy: 1)..<user.userID.index(e, offsetBy: -1)]) } adr = adr.lowercased() adrs.append(String(adr)) @@ -605,7 +668,7 @@ class SwiftPGP: Encryption { return [] } /* - encrypt a array of strings with one password. Returns encrypted strings and the password for decryption + encrypt a array of strings with one password. Returns encrypted strings and the password for decryption */ func symmetricEncrypt(textToEncrypt: [String], armored: Bool, password: String?) -> (chiphers: [String], password: String){ var pw = generatePW(size: 8, splitInBlocks: true) diff --git a/enzevalos_iphone/UserData.swift b/enzevalos_iphone/UserData.swift index 76bb9ddebcb10062883f050d38bb41a89f02a8c9..8d9124f7f388291755bb1731e7d82f85717b2fd6 100644 --- a/enzevalos_iphone/UserData.swift +++ b/enzevalos_iphone/UserData.swift @@ -27,7 +27,7 @@ enum Attribute: Int { var defaultValue: AnyObject? { switch self { case .prefEncryption: - return "mutal" as AnyObject? + return EncState.MUTUAL.name as AnyObject? case .autocryptType: return "1" as AnyObject? // only openpgp case .sentFolderPath: //save backendFolderPath here @@ -46,6 +46,18 @@ enum Attribute: Int { return "letterbox-study" as AnyObject? case .userTraveled: return false as AnyObject? + case .imapAuthType: + return MCOAuthType.SASLDIGESTMD5.rawValue as AnyObject? + case .imapConnectionType: + return MCOConnectionType.TLS.rawValue as AnyObject? + case .imapPort: + return 993 as AnyObject? + case .smtpAuthType: + return MCOAuthType.saslPlain.rawValue as AnyObject? + case .smtpPort: + return 465 as AnyObject? + case .smtpConnectionType: + return MCOConnectionType.TLS.rawValue as AnyObject? default: return nil } @@ -127,7 +139,7 @@ struct UserManager { //Usable for paths too static func convertToFrontendFolderPath(from backendFolderPath: String, with delimiter: String = ".") -> String { - if let mcoConverted = (AppDelegate.getAppDelegate().mailHandler.IMAPSession.defaultNamespace?.components(fromPath: backendFolderPath) as? [String])?.joined(separator: delimiter) { + if let mcoConverted = (AppDelegate.getAppDelegate().mailHandler.IMAPSession?.defaultNamespace?.components(fromPath: backendFolderPath) as? [String])?.joined(separator: delimiter) { if backendFolderPath != mcoConverted && UserDefaults.standard.string(forKey: backendFolderPath) != mcoConverted { UserDefaults.standard.set(mcoConverted, forKey: backendFolderPath) UserDefaults.standard.set(backendFolderPath, forKey: mcoConverted) @@ -143,7 +155,7 @@ struct UserManager { //Usable for paths too static func convertToBackendFolderPath(from frontendFolderPath: String) -> String { - if let mcoConverted = AppDelegate.getAppDelegate().mailHandler.IMAPSession.defaultNamespace?.path(forComponents: [frontendFolderPath]) { + if let mcoConverted = AppDelegate.getAppDelegate().mailHandler.IMAPSession?.defaultNamespace?.path(forComponents: [frontendFolderPath]) { if frontendFolderPath != mcoConverted && UserDefaults.standard.string(forKey: frontendFolderPath) != mcoConverted { UserDefaults.standard.set(mcoConverted, forKey: frontendFolderPath) UserDefaults.standard.set(frontendFolderPath, forKey: mcoConverted) @@ -184,20 +196,6 @@ struct UserManager { } } - static func loadImapAuthType() -> MCOAuthType { - if let auth = UserManager.loadUserValue(Attribute.imapAuthType) as? Int, auth != 0 { - return MCOAuthType.init(rawValue: auth) - } - return [] - } - - static func loadSmtpAuthType() -> MCOAuthType { - if let auth = UserManager.loadUserValue(Attribute.smtpAuthType) as? Int, auth != 0 { - return MCOAuthType.init(rawValue: auth) - } - return [] - } - static func loadUserSignature() -> String { if UserDefaults.standard.bool(forKey: "Signature.Switch"), let sig = UserDefaults.standard.string(forKey: "Signature.Text") { return "\n\n______________________________\n\n\(sig.trimmingCharacters(in: .whitespacesAndNewlines))\n\n" @@ -206,12 +204,12 @@ struct UserManager { return "" } - static func loadInvitationMode() -> InvitationMode { + static func loadInvitationMode() -> Inviation { let mode = UserDefaults.standard.integer(forKey: "Invitation.Mode") - if let invitationmode = InvitationMode(rawValue: mode) { + if let invitationmode = Inviation.init(rawValue: mode) { return invitationmode } - return InvitationMode.Censorship + return Inviation.defaultValue as! Inviation } static func resetUserValues() { @@ -220,5 +218,38 @@ struct UserManager { //UserDefaults.standard.removeObject(forKey: "\(a.hashValue)") } } + + + static func setFolderNamesFromJson() -> Bool { + var change = true + if let userAddr = loadUserValue(Attribute.userAddr) as? String { + let manager = MCOMailProvidersManager.shared()! + let path = Bundle.main.path(forResource: "providers", ofType: "json") + manager.registerProviders(withFilename: path) + if let provider = manager.provider(forEmail: userAddr) { + if let drafts = provider.draftsFolderPath() { + UserManager.storeUserValue(drafts as AnyObject?, attribute: Attribute.draftFolderPath) + } else { + change = false + } + if let sent = provider.sentMailFolderPath() { + UserManager.storeUserValue(sent as AnyObject?, attribute: Attribute.sentFolderPath) + } else { + change = false + } + if let trash = provider.trashFolderPath() { + UserManager.storeUserValue(trash as AnyObject?, attribute: Attribute.trashFolderPath) + } else { + change = false + } + if let archive = provider.allMailFolderPath() { + UserManager.storeUserValue(archive as AnyObject?, attribute: Attribute.archiveFolderPath) + } else { + change = false + } + } + } + return change + } } diff --git a/enzevalos_iphone/bitcoinde.asc b/enzevalos_iphone/bitcoinde.asc deleted file mode 100644 index b9c22ef7ced0805e94086193d835def76dba8cbd..0000000000000000000000000000000000000000 --- a/enzevalos_iphone/bitcoinde.asc +++ /dev/null @@ -1,52 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v1.4.10 (GNU/Linux) - -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 -wL9aXr0VrdOBCg== -=/tH/ ------END PGP PUBLIC KEY BLOCK----- diff --git a/enzevalos_iphone/de.lproj/InboxTableViewCell.strings b/enzevalos_iphone/de.lproj/InboxTableViewCell.strings index 3984a335b04520fa422ab168d6aa042a157138d2..abb019dce48cca698c86dac00047b8982c513073 100644 --- a/enzevalos_iphone/de.lproj/InboxTableViewCell.strings +++ b/enzevalos_iphone/de.lproj/InboxTableViewCell.strings @@ -1,6 +1,6 @@ /* Class = "UILabel"; text = "Keine weiteren Nachrichten..."; ObjectID = "5es-fE-2Ig"; */ -"5es-fE-2Ig.text" = "Keine weiteren Nachrichten..."; +"5es-fE-2Ig.text" = "Keine weiteren Mails..."; /* Class = "UILabel"; text = "Datum"; ObjectID = "Nu7-tF-hGe"; */ "Nu7-tF-hGe.text" = "Datum"; @@ -12,7 +12,7 @@ "XJ6-AX-Txg.text" = "Betreff"; /* Class = "UIButton"; normalTitle = "Alle E-Mails von diesem Kontakt"; ObjectID = "fkg-yw-zDk"; */ -"fkg-yw-zDk.normalTitle" = "Alle E-Mails von diesem Kontakt"; +"fkg-yw-zDk.normalTitle" = "Mehr Mails sehen"; /* Class = "UILabel"; text = "Name"; ObjectID = "ixt-EX-9TM"; */ "ixt-EX-9TM.text" = "Name"; diff --git a/enzevalos_iphone/de.lproj/Localizable.strings b/enzevalos_iphone/de.lproj/Localizable.strings index 3fbd7979dfb1d4d2329f64574c5e4ba80249d4bf..dcf19acade9015b327ac9103d1ff00335bc27898 100644 --- a/enzevalos_iphone/de.lproj/Localizable.strings +++ b/enzevalos_iphone/de.lproj/Localizable.strings @@ -1,10 +1,10 @@ -/* - Localizable.strings - enzevalos_iphone - - Created by jakobsbode on 06.10.16. - Copyright © 2016 fu-berlin. All rights reserved. -*/ +/* + Localizable.strings + enzevalos_iphone + + Created by jakobsbode on 06.10.16. + Copyright © 2016 fu-berlin. All rights reserved. + */ "AccessContacts" = "Zugriff auf Kontakte"; "AccessContactsDescription" = "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."; "AccessNotGranted" = "Bitte schalte unter Einstellungen den Zugriff auf die Kontakte frei, wenn du möchtest, dass die App richtig funktioniert"; @@ -20,53 +20,53 @@ "Cc" = "Kopie"; "Checkmarks" = "Du hast Nachrichten von den Adressen mit Haken bekommen"; "Close" = "Schließen"; -"codeExplanation" = "Um dein Geheimnis auf dem anderen Gerät benutzen zu können, benötigst du den folgenden Code. Dieser wird in dieser Ansicht wieder zu finden sein, damit du ihn leicht abtippen kannst."; +"codeExplanation" = "Um dein Geheimnis auf einem anderen Gerät benutzen zu können, benötigst du den folgenden Code. Dieser wird in dieser Ansicht wieder zu finden sein, damit du ihn leicht abtippen kannst."; "codeExplanationTravel" = "Um dein Geheimnis auf dem anderen Gerät benutzen zu können, benötigst du den folgenden Code. Notiere ihn dir jetzt und lasse die Notiz zuhause, damit deine Geheimnisse während der Reise geschützt sind."; -"CouldNotConnect" = "Die Verbindung zum Server konnte nicht hergestellt werden. Bitte überprüfe die folgenden Angaben und passe sie ggf. an."; +"CouldNotConnect" = "Die Verbindung zum Server konnte nicht hergestellt werden. Bitte überprüfe die folgenden Angaben und passe sie an."; "ConnectingToMailServer" = "Verbinde zum Mailserver"; "Contacts" = "Kontakte"; "Content" = "Inhalt"; "ContentNo" = "Kein Inhalt"; -"CreateAndManageKeys" = "Erstelle und verwalte Schlüssel"; +"CreateAndManageKeys" = "Automatisierte Einrichtung der Kryptographie"; "DeleteCode" = "Code löschen und erneut senden"; -"Details" = "Schlüssel und Schloss"; +"Details" = "Mehr Details"; "DiscoveryTime" = "Bekannt seit"; "Done" = "Fertig"; "Drafts" = "Entwürfe"; "edit" = "Bearbeiten"; -"Emailaddress" = "E-Mail-Adresse"; +"Emailaddress" = "Mailadresse"; "EncryptionType" = "Verschlüsselungsart"; "EverythingCorrect" = "Alles richtig?"; -"ExportInfoViewText" = "Damit deine Briefe gelesen werden können, muss das Gerät ein Geheimnis kennen. Dieses befindet sich momentan nur auf deinem Smartphone.\n Das Geheimnis kannst du einfach und sicher auf deine anderen Geräte übertragen. Wenn du das tun möchtest, öffne auf dem anderen Gerät die"; -"ExportKeyMailWasSentTopLabel" = "Dein Geheimnis wurde in einer E-Mail an die Adresse"; +"ExportInfoViewText" = "Du kannst vertrauliche Mails auf einem Gerät nur lesen, wenn das Gerät das Geheimnis kennt. Das Geheimnis befindet sich auf deinem iPhone. Das Geheimnis kann einfach und sicher übertragen werden. Wenn du das tun möchtest, öffne auf einem anderen Gerät die"; +"ExportKeyMailWasSentTopLabel" = "Dein Geheimnis wurde in einer Mail an die Adresse"; "ExportKeyMailWasSentBottomLabel" = "geschickt."; -"ExportKeyMailWillBeSentTopLabel" = "Dein Geheimnis wird in einer E-Mail an die Adresse"; +"ExportKeyMailWillBeSentTopLabel" = "Dein Geheimnis wird in einer Mail an die Adresse"; "ExportKeyMailWillBeSentBottomLabel" = "geschickt werden."; "Fingerprint" = "Fingerabdruck"; "Folders" = "Ordner"; "Forward" = "Weiterleiten"; "From" = "Von"; -"GetHelp" = "Um Hilfe zu erhalten, tippe auf den Brief oder die Postkarte in der App."; +"GetHelp" = "Um Hilfe zu erhalten, tippe auf die Icons in der App."; "GotIt" = "Verstanden!"; "Hello" = "Hallo"; "INBOX" = "INBOX"; "Inbox" = "Postfach";//Briefkasten? -"Insecure" = "Unsicher"; -"InsertMailAddress" = "Bitte gib deine E-Mail-Adresse ein"; -"InsertMailAddressAndPassword" = "Bitte gib deine E-Mail-Adresse und dein Passwort ein"; -"InsertPassword" = "Bitte gib\ndein Passwort ein"; +"Insecure" = "Unvertraulich"; +"InsertMailAddress" = "Bitte gib deine Mailadresse ein"; +"InsertMailAddressAndPassword" = "Bitte gib deine Mailadresse und dein Passwort ein"; +"InsertPassword" = "Bitte gib dein Passwort ein"; "InsertUsername" = "Bitte gib deinen Nutzernamen ein"; -"InterestedInSecureMail" = "Schön, dass du dich für sichere E-Mail interessierst!"; +"InterestedInSecureMail" = "Schön, dass du dich für vertrauliche Mail interessierst!"; "Junk" = "Spam"; -"KeyAddresses" = "Verbundene Mailadressen"; -"KeyDetails" = "Schlüssel und Schloss Details"; -"KeyID" = "Identifier"; -"KeyIsRevoked" = "Das Schloss ist zurückgezogen. Zurückgezogen wurde es am "; -"KeyIsVerified" = "Das Schloss ist verifiziert. Verifiziert wurde es am "; -"KeyNotFound" = "Schloss konnte nicht gefunden werden. Dies ist ein Fehler, bitte wende dich an die Entwickler!"; -"Letter" = "Brief"; -"LetterDamaged" = "Angerissener Brief"; -"LetterDescription" = "• Briefe wurden tatsächlich vom angegebenen Absender versendet\n• Nur Empfänger und Sender können die Nachricht lesen.\n• Für eine sichere Kommunikation müssen alle zusammenarbeiten. Dafür können in der App Kontakte eingeladen werden."; +"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 es am "; +"KeyNotFound" = "Der Schlüssel konnte nicht gefunden werden. Dies ist ein Fehler, bitte wende dich an die Entwickler!"; +"Letter" = "Vertrauliche Mail"; +"LetterDamaged" = "Manipulierte Mail"; +"LetterDescription" = "Nur du und die sendende Person kennen den Inhalt der Mail. \nDu weißt welche Mails die Person vorher versendet hat."; "mail from" = "Nachricht von"; "Message" = "Nachricht"; "MoreInformation" = "Weitere Informationen"; @@ -75,33 +75,44 @@ "None" = "Keine"; "NormalPassword" = "Normal, Passwort"; "Now" = "jetzt"; -"OneMinuteAgo" = "vor 1 min"; +"OneMinuteAgo" = "vor 1 Min."; "original message" = "originale Nachricht"; "Password" = "Passwort"; "Plaintext" = "Klartext"; -"Postcard" = "Postkarte"; -"PostcardDescription" = "• Eine Postkarte ist eine E-Mail, wie du sie bisher kennst\n• Weder vertraulich, noch steht fest, ob sie gefälscht wurde\n• Von jedem lesbar und veränderbar"; +"Postcard" = "Unvertrauliche Mail"; +"PostcardDescription" = "Du, die sendende Person und beide Mail-Provider kennen den Inhalt der Mail, aber wer hat sie versendet?\nAbsenderadressen können frei gewählt werden. Ein Betrüger kann eine bekannte Mailadresse angeben und sich so als eine andere Person ausgeben."; "Re" = "Re"; -"ReadFollowingPages" = "Wir wollen sichere E-Mail einfach nutzbar machen.\nDafür lies dir bitte die kommenden drei Seiten durch."; +"ReadFollowingPages" = "Wir machen vertrauliche Mail-Kommunikation einfach nutzbar.\Bitte lies dir dafür die nächsten drei Seiten durch."; "ReadMailOnOtherDevice" = "Auf anderem Gerät lesen"; -"ReadOnOtherDevices" = "Briefe auf anderen Geräten lesen!"; +"ReadOnOtherDevices" = "Vertrauliche Mails auf anderen Geräten lesen!"; "Receive" = "Empfangen"; "ReceiveError" = "Ein Fehler ist aufgetreten"; //mehr spezifizieren? -"ReceiveDamagedInfo" = "Mit dieser Nachricht stimmt was nicht. Der Inhalt könnte kompromittiert oder manipuliert sein."; -"ReceiveSecureInfo" = "Diese Nachricht war ordnungsgemäß verschlossen. Sie kann nicht von Dritten gelesen werden. Die Identität des Absenders wurde bestätigt"; -"ReceiveInsecureInfo" = "Diese Nachricht wurde unverschlüsselt gesendet und konnte somit von Allen auf dem Weg mitgelesen werden. Die Identität des Absenders konnte nicht bestätigt werden und der Inhalt könnte manipuliert sein."; -"ReceiveInsecureInfoVerified" = "Diese Nachricht wurde unverschlüsselt gesendet und konnte somit von Allen auf dem Weg mitgelesen werden. Die Identität des Absenders wurde bestätigt und die Nachricht wurde nicht verändert."; -"ReceiveInsecureInfoEncrypted" = "Diese Nachricht wurde verschlüsselt gesendet, aber die Identität des Absenders konnte nicht bestätigt werden."; -"ReceiveInsecureInfoDecryptionFailed" = "Diese Nachricht wurde verschlüsselt, konnte aber nicht entschlüsselt werden. Möglicherweise wurde ein alter Schlüssel verwendet oder etwas seltsames ist passiert."; +"ReceiveDamagedInfo" = "Die kryptographischen Eigenschaften der Mail sind kaputt. Der Inhalt wurde manipuliert."; +"ReceiveSecureInfo" = "Nur du und die sendende Person kennen den Inhalt der Mail."; +"ReadView.Icon.Association.No" = "Die Person hat dir vorher noch keine vertraulichen Mails geschickt."; // NEW +"ReadView.Icon.Association.One" = "Die Person hat dir vorher eine vertrauliche Mail geschickt."; // NEW +"ReadView.Icon.Association.Multi" = "Die Person hat dir vorher %@ vertrauliche Mails geschickt."; // NEW +"ReadView.Icon.Secure.Expert" = "Für Erfahrene: Diese Mail war verschlüsselt und signiert."; +"ReadView.Icon.Advice" = "Denke zweimal nach bevor du auf einen Link klickst."; +"ReceiveInsecureInfo" = "Du, die absendende Person und die beiden Mail-Provider kennen den Inhalt der Mail. Aber wir wissen nicht, wer tatsächlich die sendende Person ist. Sei achtsam, denn ein Betrüger könnte sich als die sendende Person ausgeben."; +"ReadView.Icon.Insecure.Expert" = "Für Erfahrene: Diese Mail war weder verschlüsselt noch signiert."; +"ReadView.Icon.Key" = "Wir wissen, dass die sendende Person vertrauliche Mails senden kann."; +"ReadView.Icon.NoKey" = "Wir wissen nicht, ob die sendende Person vertrauliche Mails senden kann."; +"ReceiveInsecureInfoVerified" = "Du, die sendende Person und die Mail-Provider kennen den Inhalt der Mail, aber der Inhalt wurde nicht manipuliert."; +"ReadView.Icon.Insecure.Signed.Expert" = "Für Erfahrene: Diese Mail wurde signiert, aber nicht verschlüsselt."; +"ReceiveInsecureInfoEncrypted" = "Nur du und die sendende Person kennen den Inhalt der Mail. Aber wir wissen nicht, wer tatsächlich die sendende Person ist. Sei Achtsam, denn ein Betrüger könnte sich als die sendende Person ausgeben."; +"ReadView.Icon.InSecure.Encrypted.Expert" = "Für Erfahrene: Diese Mail war verschlüsselt, aber nicht signiert."; +"ReceiveInsecureInfoDecryptionFailed" = "Diese Nachricht ist vertraulich, aber sie konnte nicht entschlüsselt werden. Wenn du die Mail auf einem anderen Gerät lesen kannst, solltest du die Geräte synchronisieren. Wenn nicht, hat die sendende Person einen Fehler gemacht und du solltest bitten die Mail nochmal zu senden."; +"ReadView.Info.DecryptionFaild.Expert" = "Für Erfahrene: Diese Mail ist verschlüsselt, aber der Entschlüsselungsschlüssel fehlt."; "Refresh" = "Erneut laden"; "Reply" = "Antworten"; "SaveAsDraft" = "Als Entwurf speichern"; "Secure" = "Sicher"; "Send" = "Senden"; "SendError" = "Ein Fehler ist aufgetreten"; //mehr spezifizieren? -"SendInsecureInfo" = "Diese Nachricht würde unsicher an alle orange eingefärbten Kontakte gesendet werden. Somit kann sie unterwegs von anderen gelesen oder manipuliert werden. Du könntest die orangen Kontakte einladen Letterbox zu verwenden, um sicher mit ihnen zu kommunizieren."; //anstatt unterwegs: auf ihrem Weg -"SendInsecureInfoAll" = "Diese Nachricht würde unsicher an alle Kontakte gesendet werden. Somit kann sie unterwegs von anderen gelesen oder manipuliert werden. Du könntest die orangen Kontakte einladen Letterbox zu verwenden, um sicher mit ihnen zu kommunizieren."; //anstatt unterwegs: auf ihrem Weg -"SendSecureInfo" = "Super! Diese Nachricht würde sicher versendet werden. Somit ist ihr Inhalt vor neugierigen Augen geschützt und kann nicht manipuliert werden."; +"SendInsecureInfo" = "Die empfangende Personen in Orange erhalten eine nicht vertrauliche Mail. Du, die empfangenden Personen und Mail-Provider kennen den Inhalt. Du kannst Sie bitten, vertraulich zu kommunizieren. \nFür Erfahrene: Diese Mail wird weder signiert noch verschlüsselt an die Personen in Orange versendet."; //anstatt unterwegs: auf ihrem Weg +"SendInsecureInfoAll" = "Diese Mail wird nicht vertraulich sein. Du, die empfangenden Personen und die Mail-Provider werden den Inhalt kennen. Du kannst sie bitten mit dir vertraulich zu kommunizieren. \nFür Erfahrene: Diese Mail wird weder verschlüsselt noch signiert."; +"SendSecureInfo" = "Diese Mail wird vertraulich sein. Nur du und die empfangenden Personen werden den Inhalt kennen. \nFür Erfahrene: Diese Mail wird signiert und verschlüsselt versendet."; "SendSuccess" = "Erfolgreich gesendet"; "Sent" = "Gesendet"; "sent at" = "gesendet am"; @@ -119,37 +130,37 @@ "Username" = "Nutzername"; "Welcome" = "Willkommen"; "WhatAShame" = "Schade!"; -"WrongMailAddressOrPassword" = "Die E-Mail-Adresse oder das Passwort waren falsch. Bitte probiere es erneut!"; +"WrongMailAddressOrPassword" = "Die Mailadresse oder das Passwort waren falsch. Bitte probiere es erneut!"; "write" = "verfassen"; "Yesterday" = "Gestern"; "NoFurtherMessages" = "Keine weiteren Nachrichten..."; "Updating" = "Aktualisiere..."; "LastUpdate" = "Letzte Aktualisierung"; -"notVerified" = "Kontakt ist noch nicht verifiziert"; -"noEncryption" = "Kontakt nutzt noch keine Verschlüsselung"; -"otherEncryption" = "Dies ist die Ablage für Postkarten dieser Person"; -"hasKeyButNoMail" = "Kontakt nutzt Verschlüsselung, hat dir aber noch keine Briefe gesendet"; +"notVerified" = "Dieser Kontakt wurde noch nicht verifiziert."; +"noEncryption" = "Dieser Kontakt hat noch nie vertrauliche Mails versendet."; +"otherEncryption" = "Dies ist die Ablage für unvertrauliche Mail dieser Person"; +"hasKeyButNoMail" = "Dieser Kontakt kann vertrauliche Mails versenden und empfangen, hat aber noch nie vertrauliche Mails versendet."; "Verified" = "Kontakt ist verifiziert"; "verifyNow" = "Jetzt verifizieren"; -"toEncrypted" = "Zur Ablage von Briefen"; -"invite" = "Kontakt einladen Verschlüsselung zu nutzen"; +"toEncrypted" = "Zur Ablage von vertraulichen Mails"; +"invite" = "Bitte um vertrauliche Kommunikation"; "discardButton" = "Verwerfen"; "allMessages" = "Alle Nachrichten dieser Ablage"; "otherRecords" = "Andere Ablagen dieses Kontakts"; -"connectedAddresses" = "Verknüpfte E-Mail-Adressen"; +"connectedAddresses" = "Verknüpfte Mailadressen"; "CC" = "An/CC"; "All" = "Alles"; "Body" = "Nachricht"; "and" = "und"; "more" = "weitere"; -"encryptedBeforeHeadline" = "Postkarte"; -"encryptedBeforeText" = "Früher hat dieser Kontakt Briefe gesendet. Vertraue dem Inhalt vielleicht nicht zu sehr oder kontaktiere den Absender ob die Nachricht legitim ist.\n"; -"corruptedText" = "Diese E-Mail könnte verändert worden sein! Bitte misstrauen Sie dem Inhalt, falls Sie ihn trotzdem lesen möchten.\n"; +"encryptedBeforeHeadline" = "Keine vertrauliche Mail"; +"encryptedBeforeText" = "Du hast bereits vertrauliche Mails von dieser Mailadresse erhalten. Die Absenderadresse und der Inhalt könnten aber manipuliert sein. Du solltest misstrauisch sein. Für deine eigene Sicherheit solltest du nicht auf Links klicken.\n"; +"corruptedText" = "Diese Mail wurde verändert! Bitte sei misstrauisch, falls du trotzdem die Mail liest.\n"; "corruptedHeadline" = "Achtung!"; "answer" = "Antworten"; -"couldNotDecryptHeadline" = "Entschlüsseln nicht möglich"; +"couldNotDecryptHeadline" = "Unlesbar"; "couldNotDecryptTravelHeadline" = "Entschlüsseln nicht möglich"; -"couldNotDecryptText" = "Diese Nachricht konnte nicht entschlüsselt werden. Vielleicht hat der Absender das falsche Schloss verwendet. Falls du von diesem Absender eine Nachricht erwartest könntest du versuchen auf einem anderen Weg in Verbindung zu treten.\n"; +"couldNotDecryptText" = "Das ist eine vertrauliche Mail, aber sie kann nicht entschlüsselt werden. Wenn du die Mail auf einem anderen Gerät lesen kannst, solltest du die Geräte synchronisieren. Wenn nicht, hat die sendende Person einen Fehler gemacht und du solltest die Person bitten die Mail nochmal zu senden. \nFür Erfahrene: Diese Mail ist verschlüsselt, aber der Entschlüsselungsschlüssel fehlt.\n"; "couldNotDecryptTravelText" = "Diese Nachricht konnte nicht entschlüsselt werden. Falls du von diesem Absender eine Nachricht erwartest könntest du versuchen auf einem anderen Weg in Verbindung zu treten. Wenn du wieder zuhause bist, probiere deine Sicherung zu laden, um die Nachricht zu lesen.\n"; "unreadableWhileTravelHeadline" = "Öffnen nicht möglich"; "unreadableWhileTravelText" = "Du hast den Brief wieder verschlossen, damit er während deiner Reise nicht lesbar ist. Wenn du wieder zuhause bist, solltest du deine Sicherung laden, damit du ihn wieder öffnen kannst."; @@ -188,21 +199,21 @@ "TravelInfo.Remember" = "An Aktivierung erinnern"; "travelFollowUpReminderText" = "Hi,\n\nich würde dir gerne einen Brief schreiben! Wenn du die Grenzkontrollen passiert hast, gib das bitte schnell in der Letterbox App an. Dann kann ich dir den Brief senden.\n\nSchöne Grüße!"; "travelFollowUpReminderSubject" = "Grenzkontrollen passiert?"; -"newKeyHeadline" = "Neues Schloss"; -"newKeyText" = "Diese Nachricht wurde mit einem neuem Schloss verbunden. Dies kann passieren wenn der Gesprächspartner ein neues Gerät hat oder wenn ein Dritter diese Nachricht gefälscht hat."; -"inviteContacts" = "Unsichere Kontakte einladen"; +"newKeyHeadline" = "Keine Ähnlichkeit zu vorherigen Mails!"; +"newKeyText" = "Das ist eine vertrauliche Mail, aber sie kann nicht mit vorherigen vertraulichen Mails von dieser Person zu geordnet werden. Wir können nicht entscheiden, ob ein Betrüger sich als die Person ausgibt oder die Person ein neues Gerät hat. Du solltest misstrauisch sein. Für deine eigene Sicherheit solltest du nicht auf Links klicken. Falls die Mail merkwürdig ist, solltest du die Person darauf ansprechen."; +"inviteContacts" = "Bitte um vertrauliche Kommunikation"; "inviteContacts.Censor" = "Erklärungsdialog anzeigen"; -"inviteSubject" = "Lass uns unsere E-Mails verschlüsseln!"; +"inviteSubject" = "Lass uns vertrauliche Mails ausprobieren!"; "inviteText" = "Hallo, \n\nbisher waren unsere E-Mails immer wie Postkarten und die E-Mail-Provider konnten immer mitlesen. Davor schützt Ende-Zu-Ende-Verschlüsselung. Ich probiere gerade Letterbox aus, aber es gibt auch andere Programme. Letterbox ist besonders einfach und unkompliziert. Wollen wir es mal gemeinsam ausprobieren? \n\n Eine Übersicht über andere Programme und weitere Erklärungen finden sich hier: \n\n http://letterbox.imp.fu-berlin.de?id=%@&invitation=Mail \n\nViele Grüße!";//"Hallo!\n\nEs gibt eine neue App die es super einfach macht verschlüsselt über E-Mail zu kommunizieren. Sie heißt Letterbox und wird aktuell in einer wissenschaftlichen Studie getestet.\n\nEs wäre toll wenn du sie mal ausprobieren würdest!\n\nGehe einfach auf https://userpage.fu-berlin.de/letterbox um mitzumachen.\n\nViele Grüße!"; "noName" = "OHNE NAME"; "you" = "Deine Ablage"; "thisIsYou" = "Hier werden E-Mails, die du dir selber schickst, gesammelt"; -"didYouSendThis" = "Hallo, haben Sie mir diese E-Mail geschickt?\nIch frage nur, weil die E-Mail unsicher versendet wurde.\n\n"; -"reactButton" = "Bestätigung erfragen"; -"sendSecureIfPossible" = "Wenn möglich als Brief senden"; -"sendInsecure" = "Als Postkarte verfassen"; -"sendInsecureAll" = "An alle als Postkarte verfassen"; -"sendSecure" = "Als Brief senden"; +"didYouSendThis" = "Hallo, haben Sie mir diese E-Mail geschickt?\nIch frage nur, weil die Mail nicht vertraulich ist und wir vorher bereits vertraulich kommuniziert haben.\n\n"; +"reactButton" = "Um Bestätigung bitten"; +"sendSecureIfPossible" = "Wenn möglich vertraulich senden"; +"sendInsecure" = "Nicht vertrauchlich machen"; +"sendInsecureAll" = "Nicht vertraulich für alle machen"; +"sendSecure" = "Vertraulich machen"; "verifyContact" = "Kontakt verifizieren"; "scanQRCode" = "Scanne den QR Code des Kontaktes"; "wrongQRCode" = "Kein passender QR Code gefunden"; @@ -210,15 +221,15 @@ "verifySuccess" = "Erfolgreich verifiziert!"; "yourFingerprint" = "Dein Fingerabdruck:"; "fingerprintMissmatchShort" = "Fingerabdruck stimmt nicht!"; -"fingerprintMissmatchText" = "Stelle sicher, dass der richtige Kontakt verifiziert wurde. Fall es der richtige war, könntest du Opfer eines Mittelmann-Angriffs sein."; +"fingerprintMissmatchText" = "Stelle sicher, dass du den QR-Code zur Verifikation von der richtigen Person gescannt hast. Falls es der richtige war, könntest du Opfer eines Mittelsmann-Angriffs sein."; "scanDifferentCode" = "Anderen QR Code scannen"; -"secureContacts" = "Sichere Kontakte"; -"secureCommunication" = "Sichere Kommunikation"; -"ErrorText" = "Es gab einen Fehler. Besteht eine Verbindung zum Internet?"; +"secureContacts" = "Vertrauliche Kontakte"; +"secureCommunication" = "Vertrauliche Kommunikation"; +"ErrorText" = "Ein Fehler ist aufgetreten. Besteht eine Verbindung zum Internet?"; "about" = "Über uns"; "YourBadges" = "Deine Abzeichen"; "copied" = "Schloss wurde kopiert"; -"copyKey" = "Schloss in Zwischenablage kopieren"; +"copyKey" = "Schlüssel in Zwischenablage kopieren"; "NeverUpdated" = "Fehler bei Aktualisierung"; "PullToRefresh" = "Aktualisieren"; "Error.noInternet.Title" = "Keine Internetverbindung!"; @@ -229,8 +240,8 @@ "Invitation.Code.Done" = "Fertig"; "Invitation.Welcome.Title" = "Vertraulich kommunizieren"; "Invitation.Welcome.Title.InvitationMail" = "Bitte um Teilnahme"; -"Invitation.Welcome.Message" = "Du kannst pikante oder sensible Textstellen markieren, um diese dann zu verschlüsseln. Zeige deinen Kontakten, dass man auch vertraulich kommunizieren kann."; -"Invitation.Welcome.Message.Censor" = "Du kannst pikante oder sensible Textstellen markieren, um diese zu verberen. Zeige deinen Kontakten, dass du lieber einige Informationen vertraulich mitteilen willst."; +"Invitation.Welcome.Message" = "Du kannst sensible Textstellen markieren, um diese vertraulich zu versenden. Zeige deinen Kontakten, dass auch vertraulich kommunizieren möglich ist."; +"Invitation.Welcome.Message.Censor" = "Du kannst sensible Textstellen markieren, um diese zu verbergen. Zeige deinen Kontakten, dass du einige Informationen lieber vertraulich mitteilen willst."; "Invitation.Welcome.Message.InvitationMail" = "Mit dieser Person kannst du noch keine Briefe austauschen. Du kannst Sie bitten mitzumachen. Nachdem die andere Person per Brief geantwortet hat, kann diese auch Briefe empfangen."; "Invitation.Welcome.Try" = "Jetzt ausprobieren"; "Invitation.Welcome.Try.InvitationMail" = "Kontakt einladen"; @@ -249,3 +260,9 @@ "Invitation.EncryptionFooter" = "\n\n____________________________\n\nTeile dieser E-Mail sind verschlüsselt!\n\nEine unverschlüsselte E-Mail ist wie eine Postkarte; der E-Mail-Provider und möglicherweise auch Andere können mitlesen. Einige Teile dieser Nachricht sind privat oder pikant. Sie sollen vor Mitlesern verborgen bleiben und wurden darum geschwärzt.\n\nDein Gegenüber nutzt mit Letterbox bereits ein Programm um die Kommunikation vor den neugierigen Augen Anderer zu schützen. Wenn Du auch mitmachst, erreicht ihr beide gemeinsam das Ziel.\n\nDu kannst die verschlüsselten Wörter jederzeit unter %@ entschlüsseln.\n\n"; "Invitation.ComposeMail" = "Die E-Mail kannst du nach deinen Wünschen anpassen. Zur wissenschaftlichen Untersuchung wird der Inhalt dieser E-Mail auch gespeichert."; "Mail.Signature" = "\n\n____________________________\n\nVerfasst mit Letterbox. Mehr Informationen: http://letterbox.imp.fu-berlin.de?invitation=0\n\n"; +"MailServerError.Authentication.Body" = "Es konnte keine Verbindung zum Server hergestellt werden. \n Das Password oder der Accountname ist falsch. Bitte überprüfe beides."; +"MailServerError.Connection.Body" = "Es konnte keine Verbindung zum Server hergestellt werden.\n Bitte überprüfe das Password, der Accountname und die Serverkonfiguration (IMAP/SMTP). Die Serverkonfiguration kann mit der Serverkonfiguration auf der Provider-Webseite verglichen werden. In manchen Fällen muss der Zugriff mittels IMAP/SMTP in den Accounteinstellungen erst freigeschaltet werden."; +"MailServerError.Crypto.Body" = "Es konnte keine Verbindung zum Server hergestellt werden.\n Die Konfiguration der Transportverschlüsselung ist falsch. Bitte überprüfe diese, sowie den Port der Serverkonfiguration. Mehr Informationen finden sich dazu auch auf der Webseite des Providers."; +"MailServerError.OAUTH.Body" = "Es konnte keine Verbindung zum Server hergestellt werden.\n Google stellt einen sicheren Zugang zu deinem Postfach bereit. Bitte nutze dazu den spezifischen Login für Google."; +"MailServerError.Default.Body" = "Es konnte keine Verbindung zum Server hergestellt werden.\n Bitte überprüfe das Password, den Accountname und die Serverkonfiguration (IMAP/SMTP). Die Serverkonfiguration kann mit der Serverkonfiguration auf der Provider-Webseite verglichen werden. In manchen Fällen muss der Zugriff mittels IMAP/SMTP in den Accounteinstellungen erst freigeschaltet werden."; + diff --git a/enzevalos_iphone/en.lproj/InboxTableViewCell.strings b/enzevalos_iphone/en.lproj/InboxTableViewCell.strings index db783df762d15c7483549ca43c6dc27baec1370d..829618ca168c02d9d11352e94ddf26cb452bc931 100644 --- a/enzevalos_iphone/en.lproj/InboxTableViewCell.strings +++ b/enzevalos_iphone/en.lproj/InboxTableViewCell.strings @@ -1,6 +1,6 @@ /* Class = "UILabel"; text = "Keine weiteren Nachrichten..."; ObjectID = "5es-fE-2Ig"; */ -"5es-fE-2Ig.text" = "No more Messages..."; +"5es-fE-2Ig.text" = "No more mails..."; /* Class = "UILabel"; text = "Datum"; ObjectID = "Nu7-tF-hGe"; */ "Nu7-tF-hGe.text" = "Date"; @@ -12,7 +12,7 @@ "XJ6-AX-Txg.text" = "Subject"; /* Class = "UIButton"; normalTitle = "Alle E-Mails von diesem Kontakt"; ObjectID = "fkg-yw-zDk"; */ -"fkg-yw-zDk.normalTitle" = "All emails from this contact"; +"fkg-yw-zDk.normalTitle" = "See more mails"; /* Class = "UILabel"; text = "Name"; ObjectID = "ixt-EX-9TM"; */ "ixt-EX-9TM.text" = "Name"; diff --git a/enzevalos_iphone/en.lproj/Localizable.strings b/enzevalos_iphone/en.lproj/Localizable.strings index 839e743c164e9164b7318696ac7dfeb1516bb12f..b554bdfd406d6465a3141f1b5248946026c11d5b 100644 --- a/enzevalos_iphone/en.lproj/Localizable.strings +++ b/enzevalos_iphone/en.lproj/Localizable.strings @@ -1,16 +1,16 @@ -/* - Localizable.strings - enzevalos_iphone - - Created by jakobsbode on 06.10.16. - Copyright © 2016 fu-berlin. All rights reserved. -*/ +/* + Localizable.strings + enzevalos_iphone + + Created by jakobsbode on 06.10.16. + Copyright © 2016 fu-berlin. All rights reserved. + */ "AccessContacts" = "Access contacts"; "AccessContactsDescription" = "This App requires access to your contacts to work properly. We do not share your data with others or transfer it over the internet."; -"AccessNotGranted" = "Please allow access to contacts in Settings, to get to know the true promise of this App"; +"AccessNotGranted" = "Please allow access to contacts in settings, if you want the app to work properly."; // TODO "Archive" = "Archive"; "Address" = "Address"; -"Addressbook" = "Addressbook"; +"Addressbook" = "Address book"; "Attach" = "Attach"; "Attachment" = "Attachment"; "Authentification" = "Authentification"; @@ -18,57 +18,57 @@ "Bcc" = "BCC"; "Cancel" = "Cancel"; "Cc" = "CC"; -"Checkmarks" = "You received Mails from Mailadresses with checkmarks"; +"Checkmarks" = "You received Mails from Mailadresses with checkmarks"; // ???? "Close" = "Close"; -"codeExplanation" = "In order to use the secret on an other device, you need the following code. You can find the code again in this view, if you want to transfer it later."; +"codeExplanation" = "In order to use the secret on a different device, you need the following code. You can find the code again in this view, if you want to transfer it later."; "codeExplanationTravel" = "In order to use the secret on an other device, you need the following code. Make a note of it now and leave it at home to ensure your secret is secure, while you travel."; -"CouldNotConnect" = "Couldn't connect to server. Please check your data and modify it maybe."; -"ConnectingToMailServer" = "Connecting to mailserver"; +"CouldNotConnect" = "Couldn't connect to server. Please check your data and modify if needed."; +"ConnectingToMailServer" = "Connecting to mailserver"; //??? "Contacts" = "Contacts"; "Content" = "Content"; "ContentNo" = "No content"; -"CreateAndManageKeys" = "Creating keys"; +"CreateAndManageKeys" = "Setting up cryptography automatically"; // ?? "DeleteCode" = "Delete code and resend"; -"Details" = "Key Details"; -"DiscoveryTime" = "Discoverytime"; +"Details" = "More Details"; +"DiscoveryTime" = "Known since"; "Done" = "Done"; "Drafts" = "Drafts"; "edit" = "Edit"; -"Emailaddress" = "Emailaddress"; +"Emailaddress" = "Mail address"; "EncryptionType" = "Encryption Type"; "EverythingCorrect" = "Everything correct?"; -"ExportInfoViewText" = "To have the ablility to read your secure emails, one has to know a secret. This secret is located on your smartphone. \nIn order to read your secure emails onto other devices, this secret has to be transfered to them. If you want to do that, open on the other device the"; -"ExportKeyMailWasSentTopLabel" = "Your secret was sent in an email to the address"; +"ExportInfoViewText" = "You can only read your confidential mails on a device if the device knows the secret. This secret is located on your iPhone. \nThis secret can be transferred easily and securely. If you want to do that, open on the other device the"; +"ExportKeyMailWasSentTopLabel" = "Your secret was sent in a mail to the address"; "ExportKeyMailWasSentBottomLabel" = ""; -"ExportKeyMailWillBeSentTopLabel" = "Your secret will be sent in an email to the address"; +"ExportKeyMailWillBeSentTopLabel" = "Your secret will be sent in a mail to the address"; "ExportKeyMailWillBeSentBottomLabel" = ""; -"Fingerprint" = "Fingerprint"; +"Fingerprint" = "Fingerprint"; //???? "Folders" = "Folders"; "Forward" = "Forward"; "From" = "From"; -"GetHelp" = "To get help, tap on the letter or postcard in the app."; +"GetHelp" = "To get help, tap on icons in the app."; "GotIt" = "Got it!"; "Hello" = "Hello"; "INBOX" = "INBOX"; "Inbox" = "Inbox"; -"Insecure" = "Insecure"; -"InsertMailAddress" = "Please enter your email address"; -"InsertMailAddressAndPassword" = "Please enter your email address and password"; +"Insecure" = "Not confidential"; +"InsertMailAddress" = "Please enter your mail address"; +"InsertMailAddressAndPassword" = "Please enter your mail address and password"; "InsertPassword" = "Please enter your password"; "InsertUsername" = "Please enter your username"; -"InterestedInSecureMail" = "Nice to see that you are interested in secure mail!"; +"InterestedInSecureMail" = "Nice to see that you are interested in confidential mail!"; "Junk" = "Junk"; -"KeyAddresses" = "Mailaddresses from the key"; +"KeyAddresses" = "Mail addresses from the key"; "KeyDetails" = "Key Details"; -"KeyID" = "KeyID"; -"KeyIsRevoked" = "The Key is revoked. It was revoked at "; -"KeyIsVerified" = "The Key is verified. It was verified at "; +"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!"; -"Letter" = "Letter"; -"LetterDamaged" = "Damaged Letter"; -"LetterDescription" = "• A confidential mail\n• Written by the stated sender\n• Needs participation of sender and receiver. You can invite contacts in the app."; +"Letter" = "Confidential mail"; +"LetterDamaged" = "Manipulated mail"; +"LetterDescription" = "Only you and the sender know the content of the mail. \nYou know which mails the sender sent before."; // Association with. You know which mails the sender sent before. "mail from" = "mail from"; -"Message" = "Message"; +"Message" = "Message"; // ???? "MoreInformation" = "More Information"; "Next" = "Next"; "next" = "next"; @@ -76,37 +76,47 @@ "NormalPassword" = "Normal, password"; "Now" = "just now"; "OneMinuteAgo" = "1 min ago"; -"original message" = "original message"; "Password" = "Password"; -"Plaintext" = "Plaintext"; -"Postcard" = "Postcard"; -"PostcardDescription" = "• The kind of mail you know\n• Neihter confidential, nor you know if it's a forgery\n• Everybody can read and manipulate it"; +"Plaintext" = "Plain text"; +"Postcard" = "Not confidential"; +"PostcardDescription" = "You, the sender and both mail providers know the content of the mail but who sent the mail?\nSender addresses can be freely chosen. A fraud can impersonate a person when using a known mail address as sender address."; "Re" = "Re"; -"ReadFollowingPages" = "We want to make secure mail easy to use.\nTherefore please read the next three pages."; -"ReadMailOnOtherDevice" = "Read this email on another device"; -"ReadOnOtherDevices" = "Read secure mails on other devices!"; +"ReadFollowingPages" = "We make confidential mail communication easy to use.\nPlease read the next three pages to learn how."; +"ReadMailOnOtherDevice" = "Read this mail on a different device"; +"ReadOnOtherDevices" = "Read secure mails on different devices!"; "Receive" = "Receive"; -"ReceiveError" = "An error occured"; //mehr spezifizieren? -"ReceiveDamagedInfo" = "Something is wrong with this message. It might have been tempered with."; -"ReceiveSecureInfo" = "This message was properly closed. It cannot be read by third parties. The identity of the sender has beed checked."; -"ReceiveInsecureInfo" = "This message was not encrypted so it was possible for everyone on the way to read its content. The identity of the sender can not verified and the content of the message might have been manipulated."; -"ReceiveInsecureInfoVerified" = "This message was not encrypted so it was possible for everyone on the way to read its content. The identity of the sender was verified and the content of the message was not changed."; -"ReceiveInsecureInfoEncrypted" = "This message was encrypted, but the identity of the sender could not be verified."; -"ReceiveInsecureInfoDecryptionFailed" = "This message is encrypted, but it could not be decrypted. This may be because an old key was used or something shady might have happened."; +"ReceiveError" = "An error occured"; +"ReceiveDamagedInfo" = "The cryptographic properties of this mail are broken. The content has be manipulated."; // Other reasons? +"ReceiveSecureInfo" = "Only you and the sender know the content of the mail."; +"ReadView.Icon.Association.No" = "The person sent you no confidential mails before."; // NEW +"ReadView.Icon.Association.One" = "The person sent you one confidential mail before."; // NEW +"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" = "You, the sender and both mail providers know the content of the mail. But we do not know if the sender address represents the real sender. Be aware that a fraud can impersonate the sender."; +"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."; +"ReceiveInsecureInfoVerified" = "You, the sender and both mail providers know the content of the mail but the content was not manipulated."; +"ReadView.Icon.Insecure.Signed.Expert" = "For experts: This mail was signed but not encrypted."; +"ReceiveInsecureInfoEncrypted" = "Only you and the sender know the content of the mail. But we do not know if the sender address represents the real sender. Be aware that a fraud can impersonate the sender."; // may impersonated; Sender is may be not the real sender +"ReadView.Icon.InSecure.Encrypted.Expert" = "For experts: This mail was encrypted but not signed."; +"ReceiveInsecureInfoDecryptionFailed" = "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 be made a mistake and you can ask the sender to send the mail again."; // ADD Import key or request a correction. +"ReadView.Info.DecryptionFaild.Expert" = "For experts: This mail is encrypted but the decryption key is missing."; "Refresh" = "Refresh"; "Reply" = "Reply"; "SaveAsDraft" = "Save as draft"; -"Secure" = "Secure"; +"Secure" = "Secure"; //??? "Send" = "Send"; "SendError" = "An error occured"; //mehr spezifizieren? -"SendInsecureInfo" = "This Mail would be send insecurely to all orange contacts. So everybody could read and manipulate it. You could invite them to use Letterbox to communicate securely."; -"SendInsecureInfoAll" = "This Mail would be send insecurely to all contacts. So everybody could read and manipulate it. You could invite them to use Letterbox to communicate securely."; -"SendSecureInfo" = "Congratulations! This Mail would be send securely. It is impossible for anybody to read or manipulate it."; +"SendInsecureInfo" = "This mail would be sent not confidentially to all orange contacts. You, the receivers and the mail providers will know the content. You could ask them to communicate confidentially. \nFor experts: The mail will be neither signed nor encrypted for orange contacts."; +"SendInsecureInfoAll" = "This mail will not be confidential. You, the receivers and the mail providers will know the content. You could ask them to communicate confidentially. \nFor experts: The mail will be neither signed nor encrypted."; +"SendSecureInfo" = "This mail will be confidential. Only you and the receivers will know the content. \nFor experts: The mail will be signed and encrypted."; "SendSuccess" = "Sent successfully"; "Sent" = "Sent"; -"sent at" = "sent at"; -"Sign" = "Sign"; -"Signed" = "Signed"; +"sent at" = "sent on"; +"Sign" = "Sign"; //?? +"Signed" = "Signed"; //??? "Subject" = "Subject"; "subject" = "subject"; "SubjectNo" = "No subject"; @@ -119,20 +129,20 @@ "Username" = "Username"; "Welcome" = "Welcome"; "WhatAShame" = "Too bad"; -"WrongMailAddressOrPassword" = "Email address or password were wrong. Please try again!"; +"WrongMailAddressOrPassword" = "Mail address or password were wrong. Please try again!"; //??? "write" = "write"; "Yesterday" = "yesterday"; -"NoFurtherMessages" = "No further messages..."; +"NoFurtherMessages" = "No further mails..."; "Updating" = "Updating..."; "LastUpdate" = "Last Update"; -"notVerified" = "Contact is not verified jet"; -"noEncryption" = "Contact is not jet using encryption"; -"otherEncryption" = "This is the unsafe tray with this Contact"; -"hasKeyButNoMail" = "Contact has a key, but you haven't received a safe email jet."; -"Verified" = "Contact is verified"; +"notVerified" = "Contact is not verified yet."; +"noEncryption" = "Contact has never sent confidential mails."; +"otherEncryption" = "This is the not confidential tray with this Contact"; //What about association???? +"hasKeyButNoMail" = "Contact could send and receive confidential mails but never send confidential mails."; +"Verified" = "Contact is verified"; //TODO other word for verified "verifyNow" = "Verify now"; -"toEncrypted" = "Switch to secure tray"; -"invite" = "Invide contact to use encryption"; +"toEncrypted" = "Switch to confidential tray"; +"invite" = "Ask for confidential communication"; // Volker: ask??? "discardButton" = "Discard"; "allMessages" = "All messages from this tray"; "otherRecords" = "Other trays of this contact"; @@ -142,14 +152,14 @@ "Body" = "Body"; "and" = "and"; "more" = "more"; -"encryptedBeforeHeadline" = "Insecure Message"; -"encryptedBeforeText" = "You received secure messages from this contact before. Maybe don't trust this email too much or ask the contact via secure message or other channel whether this message is legitimate.\n"; -"corruptedText" = "This E-Mail may have been modified! If you want to read it anyways, please be weary of its content."; +"encryptedBeforeHeadline" = "Not Confidential Mail"; +"encryptedBeforeText" = "You received confidential mails from this address before. However, the sender address and content could be manipulated. You should be caution when opening the mail. For your safety, do not click on links.\n"; // IDEE: Auf Links klicken verbieten. Hinterfragen. +"corruptedText" = "This E-Mail has been manipulated! If you want to read it anyways, please be cautions."; "corruptedHeadline" = "Attention!"; "answer" = "Answer"; -"couldNotDecryptHeadline" = "Could not decrypt Message"; +"couldNotDecryptHeadline" = "Not Readable"; "couldNotDecryptTravelHeadline" = "Could not decrypt Message"; -"couldNotDecryptText" = "It was not possible to decrypt this message. This might be because the sender used the wrong key. If you expect a message from this contact, you could try reaching out on another channel.\n"; +"couldNotDecryptText" = "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 made a mistake and you can ask the sender to send the mail again. \nFor experts: This mail is encrypted but the decryption key is missing."; "couldNotDecryptTravelText" = "It was not possible to decrypt this message. If you expect a message from this contact, you could try reaching out on another channel. If you are at home again, you can try to load your backup to read the message.\n"; "unreadableWhileTravelHeadline" = "Unable to open"; "unreadableWhileTravelText" = "You closed this letter to make it unreadable while you're traveling. If you are at home again, you should load your backup to open it again."; @@ -159,32 +169,32 @@ "CrossBorder" = "Cross another border"; "IWantToTravel" = "I want to travel!"; "SendViewBorderCrossingInfo" = "You are currently crossing the border and therefore can't send letters. If you passed the border you can send letters again."; -"newKeyHeadline" = "New padlock"; -"newKeyText" = "This message has been linked to a new padlock. This can happen if the other party has a new device or if a third party has forged this message."; -"inviteContacts" = "Invite insecure Contacts"; +"newKeyHeadline" = "No Association to Previous Mails!"; +"newKeyText" = "This mail is confidential but cannot be associated to previous confidential mails. We cannot decide if a fraud tries to impersonate the sender or the sender got a new device. You should be cautions with the mail. For your safety, do not click on links. If the mail seems to be strange, contact the sender."; // Verification via phone, messenger? See contact book. +"inviteContacts" = "Ask for confidential communication"; "inviteContacts.Censor" = "Show explanation"; -"inviteSubject" = "Lets use secure email!"; -"inviteText" = "Hey there!\n\nThere is this new App called Letterbox which makes it really easy to communicate encrypted over email.\n\nI would love for you to try it!\n\nBest regards!"; +"inviteSubject" = "Let's try to use confidential mail!"; +"inviteText" = "Hey there!\n\nThere is this new App called Letterbox which makes it really easy to communicate confidentially over mail.\n\nI would love for you to try it!\n\nBest regards!"; //TODO CHANGE! "noName" = "NO NAME"; "you" = "Your Tray"; -"thisIsYou" = "Emails you sent yourself are collected here"; -"didYouSendThis" = "Hey, did you send me this email?\nI'm just asking because it was sent insecurely.\n\n"; +"thisIsYou" = "Your mails to yourself are collected here"; +"didYouSendThis" = "Hey, did you send me this mail?\nI'm just asking because the mail is not confidentially and we communicated confidentially before.\n\n"; "reactButton" = "Request Confirmation"; -"sendSecureIfPossible" = "Send as letter when possible"; -"sendInsecure" = "Send as postcard"; -"sendInsecureAll" = "Send as postcard to everyone"; -"sendSecure" = "Send as letter"; +"sendSecureIfPossible" = "Send confidentially if possible"; +"sendInsecure" = "Make not confidential"; +"sendInsecureAll" = "Make not confidential to everyone"; +"sendSecure" = "Make confidential"; "verifyContact" = "Verify Contact"; "scanQRCode" = "Scan the QR Code of the Contact"; "wrongQRCode" = "Incompatible QR Code found"; -"fingerprintMissmatch" = "The found Fingerprint does not match!"; +"fingerprintMissmatch" = "The found Fingerprint does not match!"; //TODO Advice? "verifySuccess" = "Successfully verified!"; "yourFingerprint" = "Your Fingerprint:"; "fingerprintMissmatchShort" = "Fingerprint does not match!"; -"fingerprintMissmatchText" = "Make sure you scanned the correct contact. If you did, you might be victim of a man-in-the-middle-attack."; +"fingerprintMissmatchText" = "Make sure you scanned to verify the qr code from the correct person. If you did, you might be victim of a man-in-the-middle-attack."; "scanDifferentCode" = "Scan different QR Code"; -"secureContacts" = "Secure Contacts"; -"secureCommunication" = "Secure Communication"; +"secureContacts" = "Confidential Contacts"; +"secureCommunication" = "Confidential Communication"; "ErrorText" = "An error occured. Are you connected to the internet?"; "about" = "About"; "YourBadges" = "Your Badges"; @@ -193,30 +203,35 @@ "NeverUpdated" = "Error while updating"; "PullToRefresh" = "Pull to Refresh"; "Error.noInternet.Title" = "No internet connection!"; -"Error.noInternet.Message" = "We need internet!"; +"Error.noInternet.Message" = "We need internet."; "Invitation.Code.Title" = "Almost done!"; "Invitation.Code.Message" = "Your message has been sent.\nThere is a code required to be able to read it.\nYou can share it via SMS or messenger\n\nCode: %@"; "Invitation.Code.Share" = "Share"; "Invitation.Code.Done" = "Done"; "Invitation.Welcome.Title" = "Communicate confidentially"; "Invitation.Welcome.Title.InvitationMail" = "Please participate"; -"Invitation.Welcome.Message" = "You can mark sensitive passages to have them encrypted later. Show your contacts that it's possible to communicate securely."; -"Invitation.Welcome.Message.Censor" = "You can mark sensitive passages to have them hidden later. Show your contacts that you would perfer to share some information confidentially."; -"Invitation.Welcome.Message.InvitationMail" = "You cannot send letters to this person yet. You can invite them to participate. After they answered with a letter, you can send them letters as well."; +"Invitation.Welcome.Message" = "You can mark sensitive passages to send them confidentially. Show your contacts that it's possible to communicate confidentially."; +"Invitation.Welcome.Message.Censor" = "You can mark sensitive passages to have them hidden later. Show your contacts that you would prefer to share some information confidentially."; +"Invitation.Welcome.Message.InvitationMail" = "You cannot send confidential mails to this person yet. You can invite them to participate. After they answered confidentially, you can send confidentially mails as well."; "Invitation.Welcome.Try" = "Try now"; "Invitation.Welcome.Try.InvitationMail" = "Invite contact"; "Invitation.Welcome.Later" = "Maybe later"; "Invitation.Welcome.Dont.Ask" = "Don't show anymore"; "Invitation.Step.Title" = "Great!"; -"Invitation.Step.Message" = "You will get a code for the decryption after the message was sent."; +"Invitation.Step.Message" = "You will get a code for the decryption after the message was sent."; //TODO "Invitation.Step.Message.Censor" = "The marked passages will be obliterated upon sending."; "Invitation.Step.CTA" = "Continue"; "Invitation.Step.Undo" = "Undo"; -"Invitation.Encrypt" = "Encrypt"; +"Invitation.Encrypt" = "Encrypt"; //TODO "Invitation.Encrypt.Censor" = "Hide"; "Invitation.Decrypt" = "Decrypt"; "Invitation.Decrypt.Censor" = "Disclose"; -"Invitation.CensorFooter" = "\n\n____________________________\n\nWhy isn't everything readable?\n\nAn unencrypted email is like a postcard; the email provider and possibly others can read along. Some parts of this message are private or sensitive. They are supposed to remain hidden from other readers and have therefore been blackened.\n\nYour counterpart already uses Letterbox to protect communication from the curious eyes of others. If you join in, both of you will reach the goal together. \n\nMore information can be found at: %@\n\n"; -"Invitation.EncryptionFooter" = "\n\n____________________________\n\nTeile dieser E-Mail sind verschlüsselt!\n\nAn unencrypted email is like a postcard; the email provider and possibly others can read along. Some parts of this message are private or sensitive. They are supposed to remain hidden from other readers and have therefore been blackened.\n\nYour counterpart already uses Letterbox to protect communication from the curious eyes of others. If you join in, both of you will reach the goal together.\n\n you can decrypt the encrypted passages anytime at %@ \n\n"; -"Invitation.ComposeMail" = "You can customize the email to suit your needs. The content of this e-mail is also stored for scientific research."; +"Invitation.CensorFooter" = "\n\n____________________________\n\nWhy isn't everything readable?\n\nAn unencrypted email is like a postcard; the email provider and possibly others can read along. Some parts of this message are private or sensitive. They are supposed to remain hidden from other readers and have therefore been blackened.\n\nYour counterpart already uses Letterbox to protect communication from the curious eyes of others. If you join in, both of you will reach the goal together. \n\nMore information can be found at: %@\n\n"; //TODO +"Invitation.EncryptionFooter" = "\n\n____________________________\n\nTeile dieser E-Mail sind vertraulich\n\nThis mail is partially confidential; the email provider and possibly others can read along. Some parts of this message are private or sensitive. They are supposed to remain hidden from other readers and have therefore been blackened.\n\nYour counterpart already uses Letterbox to protect communication from the curious eyes of others. If you join in, both of you will reach the goal together.\n\n you can decrypt the encrypted passages anytime at %@ \n\n"; //TODO +"Invitation.ComposeMail" = "You can customize the mail to suit your needs. The content of this mail is also stored for scientific research."; "Mail.Signature" = "\n\n____________________________\n\nComposed with Letterbox. More information: http://letterbox.imp.fu-berlin.de?invitation=0\n\n"; +"MailServerError.Authentication.Body" = "Couldn't connect to server. \n Your account name or password is wrong. Please, check them."; +"MailServerError.Connection.Body" = "Couldn't connect to server.\n Please, check your account name and server configuration (IMAP, SMTP). You can also compare the server configuration with the configuration listed on the website of your provider. In some cases, you have to active the IMAP/SMTP connection in your account settings."; +"MailServerError.Crypto.Body" = "Couldn't connect to server.\n The transport encryption configuration is wrong. Please, check the transport encryption and port configuration. You can find more information on your provider's website."; +"MailServerError.OAUTH.Body" = "Couldn't connect to server.\n Google provides a more secure access to your mail account. Please, use the specific google login."; +"MailServerError.Default.Body" = "Couldn't connect to server.\n Please, check your account name, password and server configuration. You can also compare the server configuration with the configuration listed on the website of your provider. In some cases, you have to activate the IMAP/SMTP connection in your account settings."; diff --git a/enzevalos_iphone/keys/bitcoinde.asc b/enzevalos_iphone/keys/bitcoinde.asc deleted file mode 100644 index cf8410cba97e8c121bdc98752d468a55c9a03a88..0000000000000000000000000000000000000000 --- a/enzevalos_iphone/keys/bitcoinde.asc +++ /dev/null @@ -1,52 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- - -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 -AZSc1diw -=2lGs ------END PGP PUBLIC KEY BLOCK----- diff --git a/enzevalos_iphone/keys/support_pk.asc b/enzevalos_iphone/keys/support_pk2.asc similarity index 100% rename from enzevalos_iphone/keys/support_pk.asc rename to enzevalos_iphone/keys/support_pk2.asc diff --git a/enzevalos_iphone/mail/IncomingMail.swift b/enzevalos_iphone/mail/IncomingMail.swift new file mode 100644 index 0000000000000000000000000000000000000000..1b0e8c50d2073086eb955a0595557a6a7a162b93 --- /dev/null +++ b/enzevalos_iphone/mail/IncomingMail.swift @@ -0,0 +1,821 @@ +// +// IncomingMail.swift +// enzevalos_iphone +// +// Created by Oliver Wiese on 06.03.19. +// Copyright © 2019 fu-berlin. All rights reserved. +// + +import Foundation + +enum PGPPart { + case MESSAGE, PUBLICKEY, SIGNATURE, SECRETKEY, SIGNEDMESSAGE; + + var start: String { + get { + return pgpBlock(start: true) + } + } + + var end: String { + get { + return pgpBlock(start: false) + } + } + + private func pgpBlock(start: Bool) -> String{ + var type = "END" + if start { + type = "BEGIN" + } + switch self { + case .MESSAGE: + return "-----\(type) PGP MESSAGE-----" + case .PUBLICKEY: + return "-----\(type) PGP PUBLIC KEY BLOCK-----" + case .SIGNATURE: + return "-----\(type) PGP SIGNATURE-----" + case .SECRETKEY: + return "-----\(type) PGP SECRET KEY BLOCK-----" + case .SIGNEDMESSAGE: + return "-----\(type) PGP SIGNED MESSAGE-----" + + } + } + + func findPGPPartInString(content: String) -> [String]{ + var parts = [String]() + let startString = self.start + let endString = self.end + if content.contains(startString) { + if let start = content.range(of: startString) { + var end = content.range(of: endString+"\n") + if end == nil { + end = content.range(of: endString) + } + if end == nil && self == .SIGNEDMESSAGE { + end = content.range(of: "-----END PGP") + } + if let end = end { + let s = start.lowerBound + let e = end.upperBound + var part = content[s..<e] + if self == .SIGNEDMESSAGE { + part = content[s...] + } + var partString = String(part) + partString = partString.replacingOccurrences(of: "\r\n", with: "\n") + partString = partString.replacingOccurrences(of: "\n", with: "\r\n") + partString = partString.trimmingCharacters(in: .whitespaces) + // We do not consider parts of previous mails. + if !part.contains(">"){ + parts.append(partString) + } + } + } + } + return parts + } +} + +enum PgpMIMEType { + case SIGNATURE, ENCRYPTED, OCTET, KEYS; + + static let allValues = [PgpMIMEType.ENCRYPTED, PgpMIMEType.KEYS, PgpMIMEType.OCTET, PgpMIMEType.SIGNATURE] + + var name: String { + get{ + switch self { + case .SIGNATURE: + return "application/pgp-signature" + case .ENCRYPTED: + return "application/pgp-encrypted" + case .OCTET: + return "application/octet-stream" + case .KEYS: + return "application/pgp-keys" + } + } + } + + func isTypeOf(attachment: MCOAttachment) -> Bool { + return attachment.mimeType == self.name + } + + static func findType(attachment: MCOAttachment) -> PgpMIMEType? { + return findType(name: attachment.mimeType) + } + + static func findType(name: String) -> PgpMIMEType? { + for type in PgpMIMEType.allValues { + if type.name == name { + return type + } + } + return nil + } +} + +class IncomingMail { + private let rawData: Data + private var msgParser: MCOMessageParser + private let firstParser: MCOMessageParser + // Header fields + private let flags: MCOMessageFlag + private let uID: UInt64 + private let folderPath: String + private var moveToFolderPath: String? + + private var rec: [MCOAddress] = [] + private var cc: [MCOAddress] = [] + private var from: MCOAddress? + private var fromKeyIds: [String] { + get{ + var keyIds: [String] = [] + keyIds.append(contentsOf: newAutocrypPublicKeys) + keyIds.append(contentsOf: newPublicKeys) + if let fromAdr = from?.mailbox{ + if let adr = DataHandler.handler.findMailAddress(adr: fromAdr) { + for k in adr.publicKeys { + keyIds.append(k.keyID) + } + } + } + return keyIds + } + } + private var subject: String = "" + private var date: Date = Date() + private var autocrypt: Autocrypt? = nil + private var references: [String] = [] + private var boundary: String? + private var msgID: String = "" + private var userAgent: String = "" + + // Body info + private var secretKey: String? = nil + private var isEnc = false + private var html: String = "" + private var lineArray: [String] = [] + private var cryptoObj: CryptoObject? = nil + private var body: String = "" + private var encryptedBody: String? + private var secretKeys: [String] = [] + private var newPublicKeys: [String] = [] + private var newAutocrypPublicKeys: [String] = [] + private var newSecretKeyIDs: [String]? = [] + + // Travel info + private var readableAttachments = Set<TempAttachment>() + private var repealAttachments = Set<TempAttachment>() + private var useAttachments = Set<TempAttachment>() + private var travelMail = false + private var callForRepealMail = false + private var callForUseMail = false + private var validCallForUse = false + private var misstrustNewKey = false + private var repealsKey: PersistentKey? = nil + + + + // Crypto info + private var storeEncrypted = false + var cryptoData: Data { + get { + if let data = body.data(using: String.Encoding.utf8, allowLossyConversion: true) { + return data + } + return msgParser.data() + } + } + var decryptionKeyIDs: [String] { + get { + let secretkeys = DataHandler.handler.findSecretKeys() + var decIds = [String]() + for sk in secretkeys { + if let id = sk.keyID { + decIds.append(id) + } + } + return decIds + } + } + + var primaryDecryptionKeyID: String? { + if let sk = DataHandler.handler.prefSecretKey() { + return sk.keyID + } + return nil + } + + var signatureKeyIDs: [String] { + get { + return fromKeyIds + } + } + + var signatureAddr: String? { + get { + if let adr = from?.mailbox { + return adr + } + return nil + } + } + + + init(rawData: Data, uID: UInt64, folderPath: String, flags: MCOMessageFlag){ + self.rawData = rawData + self.uID = uID + self.folderPath = folderPath + self.flags = flags + self.firstParser = MCOMessageParser(data: rawData) + self.msgParser = firstParser + self.parseHeader() + self.parseBody() + } + + func store(keyRecord: KeyRecord?) -> PersistentMail? { + let sk = secretKeys.first //TODO FIX + let mail = DataHandler.handler.createMail(uID, sender: from, receivers: rec, cc: cc, time: date, received: true, subject: subject, body: body, readableAttachments: readableAttachments, flags: flags, record: keyRecord, autocrypt: autocrypt, decryptedData: cryptoObj, folderPath: folderPath, secretKey: sk, references: references, mailagent: userAgent, messageID: msgID, encryptedBody: encryptedBody, storeEncrypted: storeEncrypted) + if let m = mail { + let pgp = SwiftPGP() + if let autoc = autocrypt, let adr = from?.mailbox { + if let publickeys = try? pgp.importKeys(key: autoc.key, pw: nil, isSecretKey: false, autocrypt: true) { + for pk in publickeys { + _ = DataHandler.handler.newPublicKey(keyID: pk, cryptoType: CryptoScheme.PGP, adr: adr, autocrypt: true, firstMail: mail) + } + } + } + if let adr = from?.mailbox { + for keyId in newPublicKeys { + let newKey = DataHandler.handler.newPublicKey(keyID: keyId, cryptoType: CryptoScheme.PGP, adr: adr, autocrypt: false, firstMail: mail) + if misstrustNewKey { + newKey.misstrust = true + } + if validCallForUse, let repealedKey = repealsKey { + repealedKey.repealed = false + repealedKey.addChild(child: newKey) + //TODO: should we allow to add more than one key? + } + + } + } + //TODO: we should delete this mail, if it is a callForRepeal and its date is in the future + if callForRepealMail, mail?.isSecure ?? false, let signKeyID = cryptoObj?.signKey, let signKey = DataHandler.handler.findKey(keyID: signKeyID) { + if let keyDate = signKey.currentlyActiveKey.lastSeen { + if keyDate <= date && date <= Date.init() { + signKey.currentlyActiveKey = signKey + signKey.lastSeen = date + signKey.repealed = true + } + } else { + signKey.currentlyActiveKey = signKey + signKey.lastSeen = date + signKey.repealed = true + } + } + if let moveToFolderPath = moveToFolderPath, moveToFolderPath != folderPath { + AppDelegate.getAppDelegate().mailHandler.move(mails: [m], from: folderPath, to: moveToFolderPath) + } + Logger.log(received: m) + } + return mail + } + + private func parseBody() { + var isEncrypted = false + var isSigned = false + var encData: Data? + var publicKeyRaw: [String] = [] + var secretKeyRaw: [String] = [] + var signaturesRaw: [String] = [] + let pgp = SwiftPGP() + + if let cryptoObject = cryptoObj, cryptoObject.encryptionState == .ValidedEncryptedWithCurrentKey || cryptoObject.encryptionState == .ValidEncryptedWithOldKey { + readableAttachments = parseUserReadableAttachments(parser: msgParser, sentEncrypted: true) + repealAttachments = readableAttachments.filter({$0.mimeType == .travelRepeal}) + useAttachments = readableAttachments.filter({$0.mimeType == .travelUse}) + callForRepealMail = repealAttachments.count > 0 + callForUseMail = !callForRepealMail && useAttachments.count > 0 + travelMail = callForRepealMail || callForUseMail + } + if travelMail { + publicKeyRaw = parseTravelMail() + } + + for a in msgParser.attachments() { + if let attachment = a as? MCOAttachment { + if let pgpType = PgpMIMEType.findType(attachment: attachment) { + if pgpType == PgpMIMEType.ENCRYPTED { + isEncrypted = true + } + else if pgpType == PgpMIMEType.OCTET { + encData = attachment.data + } + else if pgpType == PgpMIMEType.SIGNATURE { + isSigned = true + signaturesRaw.append(contentsOf: IncomingMail.extractPGPSignature(attachment: attachment)) + } + else { + publicKeyRaw.append(contentsOf: IncomingMail.findPublicKeys(attachment: attachment)) + secretKeyRaw.append(contentsOf: IncomingMail.findSecretKeys(attachment: attachment)) + } + } + } + } + body = msgParser.plainTextBodyRenderingAndStripWhitespace(false) + publicKeyRaw.append(contentsOf:IncomingMail.extractPublicKeys(text: body)) + secretKeyRaw.append(contentsOf:IncomingMail.extractSecretKeys(text: body)) + signaturesRaw.append(contentsOf: IncomingMail.extractPGPSignature(text: body)) + if !signaturesRaw.isEmpty { + isSigned = true + } + if let encData = encData, isEncrypted { + // We drop plaintext keys. + publicKeyRaw = [] + secretKeyRaw = [] + msgParser = MCOMessageParser(data: encData) + prepareDecryption() + let cryptoObject = pgp.decrypt(mail: self) + encryptedBody = cryptoObject.chiperString + mergeCryptoObject(newCryptoObj: cryptoObject) + msgParser = MCOMessageParser(data: cryptoObject.decryptedData) + return parseBody() + } + else if isSigned { + var inlineSigned = false + var signedStrings = extractSignedParts(data: msgParser.data()) + if signedStrings.isEmpty { + signedStrings = IncomingMail.extractSignedMessage(text: body) + inlineSigned = true + } + var text: String? + var signedObject: CryptoObject? + if signedStrings.count == 1 { + text = signedStrings.first + } + else if signedStrings.count > 1 { + text = signedStrings.joined(separator: "\r\n") + } + if let signedData = text?.data(using: .utf8){ + for sig in signaturesRaw { + if let signature = sig.data(using: .utf8), let adr = from?.mailbox { + for id in fromKeyIds { + if inlineSigned { + signedObject = pgp.verify(data: signedData, attachedSignature: nil, verifyId: id, fromAdr: adr) + } + else { + signedObject = pgp.verify(data: signedData, attachedSignature: signature, verifyId: id, fromAdr: adr) + } + if let ob = signedObject, ob.signatureState == .ValidSignature { + break + } + } + if let signedObject = signedObject { + mergeCryptoObject(newCryptoObj: signedObject) + if signedObject.signatureState != .NoSignature { + if !inlineSigned || (inlineSigned && signedObject.signatureState == .ValidSignature) { + msgParser = MCOMessageParser(data: signedData) + return parseBody() + } + } + } + } + } + } + } + else { + plainTextBody() + let chiphers = IncomingMail.extractInlinePGP(text: body) + // We consider only the first encrypted part! TODO: improve + if let text = chiphers.first, let data = text.data(using: .utf8) { + msgParser = MCOMessageParser(data: data) + let cryptoObject = pgp.decrypt(mail: self) + encryptedBody = cryptoObject.chiperString + mergeCryptoObject(newCryptoObj: cryptoObject) + msgParser = MCOMessageParser(data: cryptoObject.decryptedData) + return parseBody() + } + } + newPublicKeys = pgp.importKeys(keys: publicKeyRaw) + for sk in secretKeyRaw { + if let sks = try? pgp.importKeys(key: sk, pw: nil, isSecretKey: true, autocrypt: false){ + secretKeys.append(contentsOf: sks) + } + } + } + + private func parseTravelMail() -> [String] { + var newKeysRaw: [String] = [] + storeEncrypted = true + moveToFolderPath = TravelHandler.keyManagementFolder + readableAttachments = Set<TempAttachment>() + if callForUseMail, let useAttachment = useAttachments.first, let cfu = getCallForUse(from: useAttachment, date: date), cfu.fingerprint.count > 16 { + var repealedKeyID = String(cfu.fingerprint.dropFirst(cfu.fingerprint.count-16)) + if let repealedKey = DataHandler.handler.findKey(keyID: repealedKeyID), repealedKey.repealed && repealedKey.currentlyActiveKey.lastSeen ?? date <= cfu.date { + var repeals = getRepeals(for: repealedKeyID) + repeals = repeals.filter({$0.fingerprint == cfu.fingerprint}) + repeals = repeals.filter({$0.date <= cfu.date}) + if let first = repeals.first { + var maxRepeal = first + for repeal in repeals { + if repeal.date > maxRepeal.date { + maxRepeal = repeal + } + } + if maxRepeal.secret == cfu.secret && !repealedKey.failedCallForUse { + validCallForUse = true + newKeysRaw = [] + repealsKey = repealedKey + for a in (msgParser.attachments())! { + let at = a as! MCOAttachment + newKeysRaw.append(contentsOf: IncomingMail.findPublicKeys(attachment: at)) + } + } else { + if maxRepeal.secret != cfu.secret && !repealedKey.failedCallForUse { + misstrustNewKey = true + } + repealedKey.failedCallForUse = true + } + } + } + } + if callForUseMail && !validCallForUse { + newKeysRaw = [] + for a in (msgParser.attachments())! { + let at = a as! MCOAttachment + newKeysRaw.append(contentsOf: IncomingMail.findPublicKeys(attachment: at)) + } + } + return newKeysRaw + } + + public func getRepeals(for keyID: String) -> [Repeal] { + let mails = DataHandler.handler.allMailsInFolder(key: keyID, contact: nil, folder: DataHandler.handler.findFolder(with: TravelHandler.keyManagementFolder), isSecure: true) + var repeals: [Repeal] = [] + for mail in mails { + if let repeal = getRepeal(from: mail) { + repeals.append(repeal) + } + } + return repeals + } + + private func getRepeal(from mail: PersistentMail) -> Repeal? { + if let encryptedBody = mail.encryptedBody, let mco = MCOAddress(mailbox: mail.from.mailAddress), let dec = decryptText(body: encryptedBody, from: mco, autocrypt: nil) { + if let msgParser = MCOMessageParser(data: dec.decryptedData), let html = msgParser.plainTextBodyRenderingAndStripWhitespace(false) { + + var repealAttachments = Set<TempAttachment>() + let lineArray = html.components(separatedBy: "\n") + var body = lineArray.joined(separator: "\n") + body = body.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) + body.append("\n") + let readableAttachments = parseUserReadableAttachments(parser: msgParser, sentEncrypted: true) + for at in readableAttachments { + at.encState = (dec.encryptionState) + at.sigState = dec.signatureState + } + repealAttachments = readableAttachments.filter({$0.mimeType == .travelRepeal}) + + let encState: EncryptionState = dec.encryptionState + let signState: SignatureState = dec.signatureState + + if let repealAttachment = repealAttachments.first, (encState == .ValidedEncryptedWithCurrentKey || encState == .ValidEncryptedWithOldKey) && signState == .ValidSignature , let signKeyID = dec.signKey, let signKey = DataHandler.handler.findKey(keyID: signKeyID), let fingerprint = signKey.fingerprint { + let repeal = Repeal(fingerprint: fingerprint, secret: String(data: repealAttachment.data, encoding: .utf8)!, date: mail.date) + return repeal + } + } + } + return nil + } + + private func decryptText(body: String, from: MCOAddress?, autocrypt: Autocrypt?) -> CryptoObject? { + var sender: String? = nil + if let fromMCO = from { + sender = fromMCO.mailbox + } + if let data = body.data(using: .utf8) { + let pgp = SwiftPGP() + var keyIds = [String]() + if sender != nil, let adr = DataHandler.handler.findMailAddress(adr: sender!) { + for k in adr.publicKeys { + keyIds.append(k.keyID) + } + } + if let a = autocrypt { + if let key = try? pgp.importKeys(key: a.key, pw: nil, isSecretKey: false, autocrypt: true) { + keyIds.append(contentsOf: key) + } + } + let secretkeys = DataHandler.handler.findSecretKeys() + var decIds = [String]() + for sk in secretkeys { + if let id = sk.keyID { + decIds.append(id) + } + } + + return pgp.decrypt(data: data, decKeyIDs: decIds, signatureIDs: keyIds, fromAddr: sender ?? "") + } + + return nil + } + + private func getCallForUse(from attachment: TempAttachment, date: Date) -> CallForUse? { + let content = String(data: attachment.data, encoding: .utf8) + if let components = content?.components(separatedBy: "\n"), components.count >= 2 { + let secret = String(components[0].dropFirst(TravelHandler.callForUseSecretHeader.count)) + let fingerprint = String(components[1].dropFirst(TravelHandler.callForUseFingerprintHeader.count)) + return CallForUse(fingerprint: fingerprint, secret: secret, date: date) + } + return nil + } + + private func mergeCryptoObject(newCryptoObj: CryptoObject) { + if let oldCrypto = cryptoObj { + var sigState = oldCrypto.signatureState + var encState = oldCrypto.encryptionState + var signKey = oldCrypto.signKey + var signedAddr = oldCrypto.signedAdrs + + if newCryptoObj.signatureState.rawValue > sigState.rawValue { + // TODO: What about dropped information? Users are confused? + sigState = newCryptoObj.signatureState + signKey = newCryptoObj.signKey + signedAddr = newCryptoObj.signedAdrs + } + if newCryptoObj.encryptionState.rawValue > encState.rawValue { + encState = newCryptoObj.encryptionState + } + cryptoObj = CryptoObject(chiphertext: oldCrypto.chiphertext, plaintext: newCryptoObj.plaintext, decryptedData: newCryptoObj.decryptedData, sigState: sigState, encState: encState, signKey: signKey, encType: newCryptoObj.encType, signedAdrs: signedAddr) + } + else { + cryptoObj = newCryptoObj + } + + } + + private func prepareDecryption() { + html = msgParser.plainTextRendering() + lineArray = html.components(separatedBy: "\n") + lineArray.removeFirst(4) + body = lineArray.joined(separator: "\n") + body = body.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) + body.append("\n") + } + + private func plainTextBody() { + if let text = msgParser.plainTextBodyRenderingAndStripWhitespace(false) { + body = text + var c = body.first + while (c != nil && CharacterSet.whitespacesAndNewlines.contains((c?.unicodeScalars.first)!)) { + body.removeFirst() + c = body.first + } + c = body.last + while (c != nil && CharacterSet.whitespacesAndNewlines.contains((c?.unicodeScalars.first)!)) { + body.removeLast() + c = body.last + } + } + } + + private func parseHeader() { + if let header = msgParser.header { + if let refs = header.references { + for ref in refs{ + if let string = ref as? String { + references.append(string) + } + } + } + if let tos = header.to { + for r in tos{ + rec.append(r as! MCOAddress) + } + } + if let ccs = header.cc { + for r in ccs { + cc.append(r as! MCOAddress) + } + } + + if let _ = header.extraHeaderValue(forName: Autocrypt.AUTOCRYPTHEADER){ + let autocrypt = Autocrypt(header: header) + self.autocrypt = autocrypt + let pgp = SwiftPGP() + let keys = try? pgp.importKeys(key: autocrypt.key, pw: nil, isSecretKey: false, autocrypt: true) + if let keys = keys { + newAutocrypPublicKeys = keys + } + } + + if let _ = header.extraHeaderValue(forName: TravelHandler.backupHeader) { + storeEncrypted = true + moveToFolderPath = TravelHandler.backupFolder + } + + if let _ = header.extraHeaderValue(forName: Autocrypt.SETUPMESSAGE) { + // TODO: Distinguish between other keys (future work) + moveToFolderPath = TravelHandler.backupFolder + } + + if let f = header.from { + from = f + } + if let sub = header.subject { + subject = sub + } + if let d = header.date { + date = d + } + if let id = header.messageID { + msgID = id + } + if let agent = header.userAgent { + userAgent = agent + } + boundary = findBoundary() + } + } + + private func parseUserReadableAttachments(parser: MCOMessageParser, sentEncrypted: Bool = false) -> Set<TempAttachment> { + var attachments = Set<TempAttachment>() + for at in parser.attachments() { + if let attachment = at as? MCOAttachment, let mimetype = MIMETYPE.findMIMETYPE(attachment: attachment) { + if (mimetype == .travelUse || mimetype == .travelRepeal) && !sentEncrypted { + continue + } + attachments.insert(TempAttachment(name: attachment.filename, data: attachment.data, mimeType: mimetype)) + } + } + return attachments + } + + + private func extractSignedParts(data: Data) -> [String] { + if let text = String(data: data, encoding: .utf8) { + return extractSignedParts(text: text) + } + return [String] () + } + + private func extractSignedParts(text: String) -> [String] { + var parts: [String] = [] + var boundary = IncomingMail.findBoundary(text: text) + if boundary == nil { + boundary = self.boundary + } + guard text.contains("Content-Type: multipart/signed") && boundary != nil else { + return parts + } + + parts = text.components(separatedBy: boundary!) + // If text contains a header -> we drop it + if let header = parts.first, IncomingMail.findBoundary(text: header) != nil { + parts = Array(parts.dropFirst()) + } + parts = Array(parts.filter({(s: String ) -> Bool in + // A messages, where a signed part is signed again, are strange and verification can fail -> What about a response etc? + if s.contains(PGPPart.SIGNATURE.start) { + return false + } + return true + })) + + parts = Array(parts.map({(s: String) -> String in + // Convert strings according to RFC3156. See: https://tools.ietf.org/html/rfc3156 page 6 + var newString = s.replacingOccurrences(of: "\r\n", with: "\n") + newString = newString.replacingOccurrences(of: "\n", with: "\r\n") + // Sometimes we lose tabs... TEST TODO + newString = newString.replacingOccurrences(of: " charset", with: "\tcharset") + //TODO: Remove -- if last symbol + if newString.hasSuffix("--") { + newString = String(newString.dropLast(2)) + } + else if newString.hasSuffix("--\r\n") { + newString = String(newString.dropLast(4)) + } + if newString.hasPrefix("\r\n") { + newString = String(newString.dropFirst()) + } + if newString.hasSuffix("\r\n") { + newString = String(newString.dropLast()) + } + newString = newString.trimmingCharacters(in: .whitespaces) + return newString + })) + + parts = Array(parts.filter({(s: String ) -> Bool in + if s.isEmpty { + return false + } + return true + })) + return parts + } + + + + private func findBoundary() -> String? { + if let rawString = String.init(data: rawData, encoding:.utf8) { + return IncomingMail.findBoundary(text: rawString) + } + return nil + } + + func findSignedDataAndSignature(data: Data) -> (signedTexts: [String], signature: [String]) { + var sig: [String] = [] + if let parser = MCOMessageParser.init(data: data) { + for part in parser.attachments() { + if let attachment = part as? MCOAttachment { + let data = IncomingMail.extractPGPSignature(attachment: attachment) + sig.append(contentsOf: data) + // TODO: What about more signatures? + } + } + } + + return (extractSignedParts(data: data), sig) + } + + private static func importPublicKeys(attachment: MCOAttachment) -> [String] { + var newKey = [String]() + let pgp = SwiftPGP() + if let content = attachment.decodedString() { + newKey = pgp.importKeys(keys: PGPPart.PUBLICKEY.findPGPPartInString(content: content)) + } + else if PgpMIMEType.KEYS.isTypeOf(attachment: attachment) { + if let keyIds = try? pgp.importKeys(data: attachment.data, pw: nil, secret: false) { + newKey.append(contentsOf: keyIds) + } + } + return newKey + } + + private static func findSecretKeys(attachment: MCOAttachment) -> [String] { + if let content = attachment.decodedString() { + return PGPPart.SECRETKEY.findPGPPartInString(content: content) + } + return [] + } + + private static func findPublicKeys(attachment: MCOAttachment) -> [String] { + if let content = attachment.decodedString() { + return PGPPart.PUBLICKEY.findPGPPartInString(content: content) + } + return [] + } + + private static func extractPublicKeys(text: String) -> [String] { + return PGPPart.PUBLICKEY.findPGPPartInString(content: text) + } + + private static func extractSecretKeys(text: String) -> [String] { + return PGPPart.SECRETKEY.findPGPPartInString(content: text) + } + + private static func extractSignedMessage(text: String) -> [String] { + return PGPPart.SIGNEDMESSAGE.findPGPPartInString(content: text) + } + + private static func extractInlinePGP(text: String) -> [String] { + return PGPPart.MESSAGE.findPGPPartInString(content: text) + } + + private static func extractPGPSignature(attachment: MCOAttachment) -> [String] { + if let content = String(data: attachment.data, encoding: .utf8) { + return PGPPart.SIGNATURE.findPGPPartInString(content: content) + } + return [] + } + + private static func extractPGPSignature(text: String) -> [String] { + return PGPPart.SIGNATURE.findPGPPartInString(content: text) + } + + + + private static func findBoundary(text: String) -> String? { + let boundaries = matches(for: "boundary=.*;", in: text) + if let bound = boundaries.first { + let splitted = bound.split(separator: "\"") + if splitted.count == 3 { + return "--"+String(splitted[1]) as String + } + } + return nil + } + private static func matches(for regex: String, in text: String) -> [String] { + do { + let regex = try NSRegularExpression(pattern: regex) + let results = regex.matches(in: text, range: NSRange(text.startIndex..., in: text)) + return results.map { + String(text[Range($0.range, in: text)!]) + } + } catch { + return [] + } + } +} diff --git a/enzevalos_iphone/providers.json b/enzevalos_iphone/providers.json index 365e9a2c1b94ed08c3570c5ff960fc2fd3ff08fb..2b2e8986c1b77d72c37ba73c8646377a447a67f2 100644 --- a/enzevalos_iphone/providers.json +++ b/enzevalos_iphone/providers.json @@ -235,39 +235,1339 @@ "posteo" ] }, - "outlook.com":{ + "mailbox.org":{ "servers":{ "imap":[ { "port":993, - "hostname":"imap-mail.outlook.com", - "ssl":true, + "hostname":"imap.mailbox.org", + "starttls":true, "auth":"saslPlain" } ], "smtp":[ { "port":587, - "hostname":"smtp-mail.outlook.com", + "hostname":" smtp.mailbox.org ", "starttls":true, "auth":"saslPlain" } ] }, "domain-match":[ - "outlook.com", - "outlook.de", - "outlook", - "hotmail.com", - "hotmail" + "mailbox.org" ], "mx-match": [ - "outlook.com", - "outlook.de", - "outlook", - "hotmail.com", - "hotmail" + "mailbox.org" + ] + }, + "pobox": { + "servers": { + "imap": [ + { + "port": 993, + "hostname": "mail.pobox.com", + "ssl": true + } + ], + "pop": [ + { + "port": 995, + "hostname": "mail.pobox.com", + "ssl": true + } + ], + "smtp": [ + { + "port": 587, + "hostname": "smtp.pobox.com", + "starttls": true + } + ] + }, + "mx-match": [ + "mx-1\\.pobox\\.com", + "mx-2\\.pobox\\.com", + "mx-3\\.pobox\\.com", + "mx-1\\.rightbox\\.com", + "mx-2\\.rightbox\\.com", + "mx-3\\.rightbox\\.com" + ], + "domain-match": [ + "pobox\\.com" + ] + }, + "hushmail": { + "servers": { + "imap": [ + { + "port": 993, + "hostname": "imap.hushmail.com", + "ssl": true + } + ], + "pop": [ + { + "port": 995, + "hostname": "pop.hushmail.com", + "ssl": true + } + ], + "smtp": [ + { + "port": 587, + "hostname": "smtp.hushmail.com", + "ssl": true + }, + { + "port": 465, + "hostname": "smtp.hushmail.com", + "ssl": true + }, + { + "port": 25, + "hostname": "smtp.hushmail.com", + "starttls": true + } + ] + }, + "domain-match": [ + "hushmail\\.com" + ] + }, + "mail": { + "servers": { + "imap": [ + { + "port": 993, + "hostname": "imap.mail.com", + "ssl": true + } + ], + "pop": [ + { + "port": 995, + "hostname": "pop.mail.com", + "ssl": true + } + ], + "smtp": [ + { + "port": 587, + "hostname": "smtp.mail.com", + "ssl": true + }, + { + "port": 465, + "hostname": "smtp.mail.com", + "ssl": true + }, + { + "port": 25, + "hostname": "smtp.mail.com", + "ssl": true + } + ] + }, + "domain-match": [ + "mail\\.com" + ] + }, + "zoho": { + "servers": { + "imap": [ + { + "port": 993, + "hostname": "imap.zoho.com", + "ssl": true + } + ], + "pop": [ + { + "port": 995, + "hostname": "pop.zoho.com", + "ssl": true + } + ], + "smtp": [ + { + "port": 465, + "hostname": "smtp.zoho.com", + "ssl": true + }, + { + "port": 587, + "hostname": "smtp.zoho.com", + "starttls": true + } + ] + }, + "domain-match": [ + "zoho\\.com" + ] + }, + "juno": { + "servers": { + "pop": [ + { + "port": 995, + "hostname": "pop.juno.com", + "ssl": true + } + ], + "smtp": [ + { + "port": 465, + "hostname": "smtp.juno.com", + "starttls": true + } + ] + }, + "domain-match": [ + "juno\\.com" + ] + }, + "mobileme": { + "servers": { + "imap": [ + { + "port": 993, + "hostname": "imap.mail.me.com", + "ssl": true + }, + { + "port": 143, + "hostname": "imap.mail.me.com", + "starttls": true + } + ], + "smtp": [ + { + "port": 587, + "hostname": "smtp.mail.me.com", + "starttls": true + } + ] + }, + "domain-match": [ + "me\\.com", + "mac\\.com", + "icloud\\.com" + ], + "mailboxes": { + "drafts": "Drafts", + "allmail": "Archive", + "spam": "Junk", + "sentmail": "Sent Messages", + "trash": "Deleted Messages" + } + }, + "dreamhost": { + "servers": { + "imap": [ + { + "port": 993, + "hostname": "mail.{domain}", + "ssl": true + }, + { + "port": 143, + "hostname": "mail.{domain}", + "starttls": true + } + ], + "smtp": [ + { + "port": 465, + "hostname": "mail.{domain}", + "ssl": true + }, + { + "port": 587, + "hostname": "mail.{domain}", + "starttls": true + }, + { + "port": 25, + "hostname": "mail.{domain}", + "starttls": true + } + ] + }, + "mx-match": [ + "mx1\\.sub3\\.homie\\.mail\\.dreamhost\\.com", + "mx2\\.sub3\\.homie\\.mail\\.dreamhost\\.com", + "mx1\\.sub4\\.homie\\.mail\\.dreamhost\\.com", + "mx2\\.sub4\\.homie\\.mail\\.dreamhost\\.com", + "mx1\\.sub5\\.homie\\.mail\\.dreamhost\\.com", + "mx2\\.sub5\\.homie\\.mail\\.dreamhost\\.com", + "mx1\\.balanced\\.homie\\.mail\\.dreamhost\\.com", + "mx2\\.balanced\\.homie\\.mail\\.dreamhost\\.com" + ], + "mailboxes": { + "drafts": "Drafts", + "allmail": "Archive", + "spam": "Junk", + "sentmail": "Sent Messages", + "trash": "Deleted Messages" + } + }, + "insecure-default": { + "servers": { + "imap": [ + { + "port": 143, + "starttls": true + }, + { + "port": 143 + } + ], + "smtp": [ + { + "port": 587, + "starttls": true + }, + { + "port": 25, + "starttls": true + }, + { + "port": 587 + }, + { + "port": 25 + } + ] + }, + "mailboxes": { + "drafts": "Drafts", + "allmail": "Archive", + "spam": "Junk", + "sentmail": "Sent Messages", + "trash": "Deleted Messages" + } + }, + "euro-apple": { + "servers": { + "imap": [ + { + "port": 993, + "hostname": "phonehome.euro.apple.com", + "ssl": true + } + ], + "smtp": [ + { + "port": 587, + "hostname": "phonehome.apple.com", + "starttls": true + } ] + }, + "domain-match": [ + "euro\\.apple\\.com" + ], + "mailboxes": { + "drafts": "Drafts", + "allmail": "Archive", + "spam": "Junk", + "sentmail": "Sent Messages", + "trash": "Deleted Messages" + } + }, + "default": { + "servers": { + "imap": [ + { + "port": 993, + "ssl": true + }, + { + "port": 143, + "starttls": true + } + ], + "smtp": [ + { + "port": 465, + "ssl": true + }, + { + "port": 587, + "starttls": true + }, + { + "port": 25, + "starttls": true + } + ] + }, + "mailboxes": { + "drafts": "Drafts", + "allmail": "Archive", + "spam": "Junk", + "sentmail": "Sent Messages", + "trash": "Deleted Messages" + } + }, + "insecure-fixed-port": { + "servers": { + "imap": [ + { + "starttls": true + }, + { + } + ], + "smtp": [ + { + "starttls": true + }, + { + } + ] + }, + "mailboxes": { + "drafts": "Drafts", + "allmail": "Archive", + "spam": "Junk", + "sentmail": "Sent Messages", + "trash": "Deleted Messages" + } + }, + "aol": { + "servers": { + "imap": [ + { + "port": 993, + "hostname": "imap.aol.com", + "ssl": true + }, + { + "port": 143, + "hostname": "imap.aol.com", + "starttls": true + } + ], + "smtp": [ + { + "port": 587, + "hostname": "smtp.aol.com", + "starttls": true + }, + { + "port": 465, + "hostname": "smtp.aol.com", + "ssl": true + }, + { + "port": 25, + "hostname": "smtp.aol.com", + "starttls": true + } + ] + }, + "domain-match": [ + "aim\\.com", + "aol\\..*", + "jp\\.aol\\.com" + ], + "mailboxes": { + "drafts": "Drafts", + "allmail": "Saved", + "spam": "Spam", + "sentmail": "Sent", + "trash": "Trash" + } + }, + "yahoo.co.jp": { + "servers": { + "imap": [ + { + "port": 993, + "hostname": "imap.mail.yahoo.co.jp", + "ssl": true + } + ], + "smtp": [ + { + "port": 465, + "hostname": "smtp.mail.yahoo.co.jp", + "ssl": true + } + ] + }, + "domain-match": [ + "yahoo\\.co\\.jp" + ], + "mailboxes": { + "drafts": "Draft", + "allmail": "Archive", + "spam": "Bulk Mail", + "sentmail": "Sent", + "trash": "Trash" + } + }, + "yahoo": { + "servers": { + "imap": [ + { + "port": 993, + "hostname": "imap.mail.yahoo.com", + "ssl": true + }, + { + "port": 143, + "hostname": "imap.mail.yahoo.com", + "starttls": true + } + ], + "smtp": [ + { + "port": 465, + "hostname": "smtp.mail.yahoo.com", + "ssl": true + } + ] + }, + "mx-match": [ + "mta5\\.am0\\.yahoodns\\.net", + "mta6\\.am0\\.yahoodns\\.net", + "mta7\\.am0\\.yahoodns\\.net" + ], + "domain-match": [ + "yahoo\\..*", + "ymail\\.com", + "rocketmail\\.com", + "xtra\\.co\\.nz" + ], + "domain-exclude": [ + "yahoo\\.co\\.jp" + ], + "mailboxes": { + "drafts": "Draft", + "allmail": "Archive", + "spam": "Bulk Mail", + "sentmail": "Sent", + "trash": "Trash" + } + }, + "fastmail": { + "servers": { + "imap": [ + { + "port": 993, + "hostname": "imap.fastmail.com", + "ssl": true + } + ], + "smtp": [ + { + "port": 465, + "hostname": "smtp.fastmail.com", + "ssl": true + } + ] + }, + "domain-match": [ + "123mail\\.org", + "fastmail\\..*", + "airpost\\.net", + "eml\\.cc", + "fmail\\.co\\.uk", + "fmgirl\\.com", + "fmguy\\.com", + "mailbolt\\.com", + "mailcan\\.com", + "mailhaven\\.com", + "mailmight\\.com", + "ml1\\.net", + "mm\\.st", + "myfastmail\\.com", + "proinbox\\.com", + "promessage\\.com", + "rushpost\\.com", + "sent\\.as", + "sent\\.at", + "sent\\.com", + "speedymail\\.org", + "warpmail\\.net", + "xsmail\\.com", + "150mail\\.com", + "150ml\\.com", + "16mail\\.com", + "2-mail\\.com", + "4email\\.net", + "50mail\\.com", + "allmail\\.net", + "bestmail\\.us", + "cluemail\\.com", + "elitemail\\.org", + "emailcorner\\.net", + "emailengine\\.net", + "emailengine\\.org", + "emailgroups\\.net", + "emailplus\\.org", + "emailuser\\.net", + "f-m\\.fm", + "fast-email\\.com", + "fast-mail\\.org", + "fastem\\.com", + "fastemail\\.us", + "fastemailer\\.com", + "fastest\\.cc", + "fastimap\\.com", + "fastmailbox\\.net", + "fastmessaging\\.com", + "fea\\.st", + "fmailbox\\.com", + "ftml\\.net", + "h-mail\\.us", + "hailmail\\.net", + "imap-mail\\.com", + "imap\\.cc", + "imapmail\\.org", + "inoutbox\\.com", + "internet-e-mail\\.com", + "internet-mail\\.org", + "internetemails\\.net", + "internetmailing\\.net", + "jetemail\\.net", + "justemail\\.net", + "letterboxes\\.org", + "mail-central\\.com", + "mail-page\\.com", + "mailandftp\\.com", + "mailas\\.com", + "mailc\\.net", + "mailforce\\.net", + "mailftp\\.com", + "mailingaddress\\.org", + "mailite\\.com", + "mailnew\\.com", + "mailsent\\.net", + "mailservice\\.ms", + "mailup\\.net", + "mailworks\\.org", + "mymacmail\\.com", + "nospammail\\.net", + "ownmail\\.net", + "petml\\.com", + "postinbox\\.com", + "postpro\\.net", + "realemail\\.net", + "reallyfast\\.biz", + "reallyfast\\.info", + "speedpost\\.net", + "ssl-mail\\.com", + "swift-mail\\.com", + "the-fastest\\.net", + "the-quickest\\.com", + "theinternetemail\\.com", + "veryfast\\.biz", + "veryspeedy\\.net", + "yepmail\\.net", + "your-mail\\.com", + "operamail\\.com" + ], + "mailboxes": { + "drafts": "Drafts", + "allmail": "Archive", + "spam": "Junk Mail", + "sentmail": "Sent Items", + "trash": "Trash" + }, + "mx-match": [ + "in1.smtp.messagingengine.com", + "in2.smtp.messagingengine.com", + "in1-smtp.messagingengine.com", + "in2-smtp.messagingengine.com" + ] + }, + "apple": { + "servers": { + "imap": [ + { + "port": 993, + "hostname": "phonehome.apple.com", + "ssl": true + } + ], + "smtp": [ + { + "port": 465, + "tls": true, + "hostname": "phonehome.apple.com" + }, + { + "port": 587, + "hostname": "phonehome.apple.com", + "starttls": true + } + ] + }, + "domain-match": [ + "apple\\.com" + ], + "mailboxes": { + "drafts": "Drafts", + "allmail": "Archive", + "spam": "Junk", + "sentmail": "Sent Messages", + "trash": "Deleted Messages" + } + }, + "asia-apple": { + "servers": { + "imap": [ + { + "port": 993, + "hostname": "phonehome.asia.apple.com", + "ssl": true + } + ], + "smtp": [ + { + "port": 465, + "tls": true, + "hostname": "phonehome.asia.apple.com" + }, + { + "port": 587, + "hostname": "phonehome.asia.apple.com", + "starttls": true + } + ] + }, + "domain-match": [ + "asia\\.apple\\.com" + ], + "mailboxes": { + "drafts": "Drafts", + "allmail": "Archive", + "spam": "Junk", + "sentmail": "Sent Messages", + "trash": "Deleted Messages" + } + }, + "rackspace": { + "servers": { + "imap": [ + { + "port": 993, + "hostname": "secure.emailsrvr.com", + "ssl": true + }, + { + "port": 143, + "hostname": "secure.emailsrvr.com", + "starttls": true + }, + { + "port": 143, + "hostname": "secure.emailsrvr.com" + } + ], + "smtp": [ + { + "port": 465, + "hostname": "secure.emailsrvr.com", + "ssl": true + }, + { + "port": 587, + "hostname": "secure.emailsrvr.com", + "starttls": true + }, + { + "port": 25, + "hostname": "secure.emailsrvr.com", + "starttls": true + }, + { + "port": 587, + "hostname": "secure.emailsrvr.com" + }, + { + "port": 25, + "hostname": "secure.emailsrvr.com" + } + ] + }, + "mx-match": [ + "mx1\\.emailsrvr\\.com", + "mx2\\.emailsrvr\\.com" + ], + "mailboxes": { + "drafts": "Drafts", + "allmail": "Archive", + "spam": "Junk", + "sentmail": "Sent Messages", + "trash": "Deleted Messages" + } + }, + "zimbra": { + "servers": { + "imap": [ + { + "port": 993, + "ssl": true + }, + { + "port": 143, + "starttls": true + } + ], + "smtp": [ + { + "port": 587, + "starttls": true + }, + { + "port": 465, + "ssl": true + }, + { + "port": 25, + "starttls": true + } + ] + }, + "mailboxes": { + "drafts": "Drafts", + "allmail": "Archive", + "spam": "Junk", + "sentmail": "Sent", + "trash": "Trash" + } + }, + "ovh": { + "servers": { + "imap": [ + { + "port": 993, + "hostname": "mail.{domain}", + "ssl": true + }, + { + "port": 143, + "hostname": "mail.{domain}" + } + ], + "smtp": [ + { + "port": 465, + "hostname": "mail.{domain}", + "ssl": true + }, + { + "port": 587, + "hostname": "mail.{domain}" + }, + { + "port": 25, + "hostname": "mail.{domain}" + } + ] + }, + "mx-match": [ + "mx\\d\\.ovh\\.net" + ], + "mailboxes": { + "drafts": "Drafts", + "allmail": "Archive", + "spam": "Junk", + "sentmail": "Sent Messages", + "trash": "Deleted Messages" + } + }, + "fixed-port": { + "servers": { + "imap": [ + { + "ssl": true + }, + { + "starttls": true + } + ], + "smtp": [ + { + "starttls": true + }, + { + "ssl": true + } + ] + }, + "mailboxes": { + "drafts": "Drafts", + "allmail": "Archive", + "spam": "Junk", + "sentmail": "Sent Messages", + "trash": "Deleted Messages" + } + }, + "outlook": { + "servers": { + "imap": [ + { + "port": 993, + "hostname": "imap-mail.outlook.com", + "ssl": true + } + ], + "smtp": [ + { + "port": 587, + "hostname": "smtp-mail.outlook.com", + "starttls": true + }, + { + "port": 25, + "hostname": "smtp-mail.outlook.com", + "starttls": true + } + ] + }, + "mx-match": [ + ".*\\.mail\\.outlook\\.com" + ], + "domain-match": [ + "outlook\\.com", + "outlook\\.com\\.ar", + "outlook\\.com\\.au", + "outlook\\.at", + "outlook\\.be", + "outlook\\.com\\.br", + "outlook\\.cl", + "outlook\\.cz", + "outlook\\.dk", + "outlook\\.fr", + "outlook\\.de", + "outlook\\.com\\.gr", + "outlook\\.co\\.id", + "outlook\\.ie", + "outlook\\.it", + "outlook\\.hu", + "outlook\\.jp", + "outlook\\.kr", + "outlook\\.lv", + "outlook\\.my", + "outlook\\.co\\.nz", + "outlook\\.com\\.pe", + "outlook\\.ph", + "outlook\\.pt", + "outlook\\.sa", + "outlook\\.sg", + "outlook\\.sk", + "outlook\\.es", + "outlook\\.co\\.th", + "outlook\\.com\\.tr", + "outlook\\.com\\.vn", + "hotmail\\.com", + "hotmail\\.co\\.uk", + "hotmail\\.fr", + "hotmail\\.de", + "hotmail\\.be", + "hotmail\\.com\\.ar", + "hotmail\\.es", + "hotmail\\.com\\.mx", + "hotmail\\.com", + "live\\.com", + "live\\.fr", + "live\\.de", + "live\\.be", + "live\\.com\\.ar", + "live\\.com\\.mx", + "live\\.co\\.uk" + ], + "mailboxes": { + "drafts": "Drafts", + "allmail": "Archive", + "spam": "Junk", + "sentmail": "Sent", + "trash": "Deleted" + } + }, + "qq": { + "servers": { + "imap": [ + { + "port": 993, + "hostname": "imap.exmail.qq.com", + "ssl": true + } + ], + "smtp": [ + { + "port": 465, + "hostname": "smtp.exmail.qq.com", + "ssl": true + } + ] + }, + "domain-match": [ + "qq\\.com" + ], + "mailboxes": { + "drafts": "Drafts", + "spam": "Junk", + "sentmail": "Sent Messages", + "trash": "Deleted Messages" + } + }, + "openmailbox": { + "servers": { + "imap": [ + { + "port": 143, + "hostname": "imap.openmailbox.org", + "starttls": true + } + ], + "smtp": [ + { + "port": 587, + "hostname": "smtp.openmailbox.org", + "starttls": true + } + ] + }, + "domain-match": [ + "openmailbox\\.org" + ], + "mailboxes": { + "drafts": "Drafts", + "allmail": "Archive", + "spam": "Spam", + "sentmail": "Sent", + "trash": "Trash" + } + }, + "mailru": { + "servers": { + "imap": [ + { + "port": 143, + "hostname": "imap.mail.ru", + "starttls": true + }, + { + "port": 993, + "hostname": "imap.mail.ru", + "ssl": true + } + ], + "smtp": [ + { + "port": 465, + "hostname": "smtp.mail.ru", + "ssl": true + } + ] + }, + "domain-match": [ + "mail\\.ru", + "inbox\\.ru", + "list\\.ru", + "bk\\.ru", + "mail\\.ua" + ], + "mailboxes": { + "drafts": "Черновики", + "spam": "Спам", + "sentmail": "Отправленные", + "trash": "Корзина" + } + }, + "yandex": { + "servers": { + "imap": [ + { + "port": 993, + "hostname": "imap.yandex.com", + "ssl": true + } + ], + "smtp": [ + { + "port": 465, + "hostname": "smtp.yandex.com", + "ssl": true + } + ] + }, + "domain-match": [ + "yandex\\.ru", + "yandex\\.ua", + "yandex\\.kz", + "yandex\\.by", + "yandex\\.com", + "yandex\\.com\\.tr" + ], + "mailboxes": { + "drafts": "Черновики", + "spam": "Спам", + "sentmail": "Отправленные", + "trash": "Удалённые" + } + }, + "comcast": { + "servers": { + "imap": [ + { + "port": 993, + "hostname":"imap.comcast.net", + "ssl": true + }, + { + "port": 143, + "hostname":"imap.comcast.net", + "starttls": true + } + ], + "pop": [ + { + "port": 995, + "hostname": "mail.comcast.net", + "ssl": true + }, + { + "port": 110, + "hostname": "mail.comcast.net", + "ssl": true + } + ], + "smtp": [ + { + "port": 587, + "hostname": "smtp.comcast.net", + "starttls": true + }, + { + "port": 465, + "hostname": "smtp.comcast.net", + "ssl": true + } + ] + }, + "mx-match": [ + "mx1\\.comcast\\.net", + "mx2\\.comcast\\.net" + ] + }, + "verizon": { + "servers": { + "pop": [ + { + "port": 995, + "hostname": "pop.verizon.net", + "ssl": true + } + ], + "smtp": [ + { + "port": 465, + "hostname": "smtp.verizon.net", + "ssl": true + } + ] + }, + "mx-match": [ + "relay\\.verizon\\.net" + ] + }, + "rcn": { + "servers": { + "pop": [ + { + "port": 110, + "hostname": "pop.rcn.com", + "ssl": true + } + ], + "smtp": [ + { + "port": 25, + "hostname": "smtp.rcn.com", + "ssl": true + } + ] + }, + "mx-match": [ + "mx\\.rcn\\.com" + ] + }, + "ukrnet": { + "servers": { + "imap": [ + { + "port": 993, + "hostname": "imap.ukr.net", + "ssl": true + } + ], + "smtp": [ + { + "port": 465, + "hostname": "smtp.ukr.net", + "ssl": true + } + ] + }, + "domain-match": [ + "ukr\\.net" + ], + "mailboxes": { + "drafts": "Черновики", + "spam": "Спам", + "sentmail": "Отправленные", + "trash": "Удаленные" + } + }, + "rambler": { + "servers": { + "imap": [ + { + "port": 993, + "hostname": "imap.rambler.ru", + "ssl": true + } + ], + "smtp": [ + { + "port": 465, + "hostname": "smtp.rambler.ru", + "ssl": true + } + ] + }, + "domain-match": [ + "rambler\\.ru", + "lenta\\.ru", + "autorambler\\.ru", + "myrambler\\.ru", + "ro\\.ru", + "r0\\.ru" + ], + "mailboxes": { + "drafts": "DraftBox", + "spam": "Spam", + "sentmail": "SentBox", + "trash": "Trash" + } + }, + "office365": { + "servers": { + "imap": [ + { + "port": 993, + "hostname": "outlook.office365.com", + "ssl": true + } + ], + "smtp": [ + { + "port": 587, + "hostname": "smtp.office365.com", + "starttls": true + } + ] + }, + "mailboxes": { + "drafts": "Drafts", + "spam": "Junk Email", + "sentmail": "Sent Items", + "trash": "Deleted Items" + } + }, + "wp.pl": { + "servers": { + "imap": [ + { + "port": 993, + "hostname": "imap.wp.pl", + "ssl": true + } + ], + "smtp": [ + { + "port": 465, + "hostname": "smtp.wp.pl", + "ssl": true + } + ] + }, + "domain-match": [ + "wp\\.pl" + ], + "mailboxes": { + "spam": "SPAM", + "sentmail": "Wys&AUI-ane", + "trash": "Kosz", + "drafts": "Robocze", + "allmail": "Archive" + } + }, + "o2.pl": { + "servers": { + "imap": [ + { + "port": 993, + "hostname": "poczta.o2.pl", + "ssl": true + } + ], + "smtp": [ + { + "port": 465, + "hostname": "poczta.o2.pl", + "ssl": true + } + ] + }, + "domain-match": [ + "o2\\.pl" + ], + "mailboxes": { + "spam": "Spam", + "sentmail": "Sent", + "trash": "Trash", + "drafts": "Drafts", + "allmail": "Archive" + } + }, + "facebook": { + "servers": { + "imap": [ + { + "port": 993, + "hostname": "outlook.office365.com", + "ssl": true + } + ], + "smtp": [ + { + "port": 587, + "hostname": "smtp.office365.com", + "starttls": true + } + ] + }, + "domain-match": [ + "fb\\.com" + ], + "mailboxes": { + "allmail": "Archive", + "drafts": "Drafts", + "spam": "Junk Email", + "sentmail": "Sent Items", + "trash": "Deleted Items" + } } + + } diff --git a/enzevalos_iphone/study parameters/Invitation.swift b/enzevalos_iphone/study parameters/Invitation.swift new file mode 100644 index 0000000000000000000000000000000000000000..61a1d0b00ef8e02a64f76b5e3466e248c4d5598b --- /dev/null +++ b/enzevalos_iphone/study parameters/Invitation.swift @@ -0,0 +1,74 @@ +// +// Invitation.swift +// enzevalos_iphone +// +// Created by Oliver Wiese on 28.01.19. +// Copyright © 2019 fu-berlin. All rights reserved. +// + +import Foundation + +enum Inviation: Int, StudyParameterProtocol { + case InviteMail = 0, PasswordEnc = 1, Censorship = 2, FreeText = 3 + + static var defaultValue: StudyParameterProtocol { + get { + return Inviation.InviteMail + } + } + + static func findParameter(rawvalue: Int) -> StudyParameterProtocol { + switch rawvalue { + case Inviation.InviteMail.rawValue: + return Inviation.InviteMail + case Inviation.PasswordEnc.rawValue: + return Inviation.PasswordEnc + case Inviation.Censorship.rawValue: + return Inviation.Censorship + case Inviation.FreeText.rawValue: + return Inviation.FreeText + default: + return defaultValue + } + } + + static var name: String { + get { + return "invitation" + } + } + + static var keyName: String { + get { + return "invitation mode" + } + } + + static var numberOfTreatments: UInt32 { + get { + return 4 + } + } + + var value: Int { + get { + return self.rawValue + } + } + + func startStudy() { + return + } + + var freeTextInvitationTitle: String { + get { + switch self { + case .FreeText, .InviteMail: + return NSLocalizedString("inviteContacts", comment: "Allows users to invite contacts without encryption key") + case .Censorship, .PasswordEnc: + return NSLocalizedString("inviteContacts.Censor", comment: "Allows users to invite contacts without encryption key") + } + } + } + +} diff --git a/enzevalos_iphone/study parameters/SecurityIndicator.swift b/enzevalos_iphone/study parameters/SecurityIndicator.swift new file mode 100644 index 0000000000000000000000000000000000000000..8c1489cf932d7396d21cdf80daa73b48d5066440 --- /dev/null +++ b/enzevalos_iphone/study parameters/SecurityIndicator.swift @@ -0,0 +1,171 @@ +// +// SecurityIndicator.swift +// enzevalos_iphone +// +// Created by Oliver Wiese on 22.01.19. +// Copyright © 2019 fu-berlin. All rights reserved. +// + +import Foundation + + + +enum SecurityIndicator: Int, StudyParameterProtocol { + case letter = 0, padlock = 1 + + static var defaultValue: StudyParameterProtocol { + get { + return SecurityIndicator.letter + } + } + + static func findParameter(rawvalue: Int) -> StudyParameterProtocol { + switch rawvalue { + case SecurityIndicator.letter.rawValue: + return SecurityIndicator.letter + case SecurityIndicator.padlock.rawValue: + return SecurityIndicator.padlock + default: + return defaultValue + } + } + + static var name: String { + get { + return "indicator" + } + } + + static var keyName: String { + get { + return "indicator mode" + } + } + + static var numberOfTreatments: UInt32 { + get { + return 2 + } + } + + + var value: Int { + get { + return self.rawValue + } + } + + func startStudy() { + return + } + + + + + func imageOfSecureIndicator(background: Bool = false, open: Bool = false) -> UIImage { + switch self { + case .letter: + if open { + return IconsStyleKit.imageOfLetterOpen + } + if background { + return IconsStyleKit.imageOfLetterBG + } + return IconsStyleKit.imageOfLetter + case .padlock: + if background { + return IconsStyleKit.imageOfPadlockSecureBG + } + return IconsStyleKit.imageOfPadlockSecure + } + } + + + func imageOfCorruptedIndicator(background: Bool = false) -> UIImage { + switch self { + case .letter: + return IconsStyleKit.imageOfLetterCorrupted + case .padlock: + return IconsStyleKit.imageOfPadlockError + } + } + + func imageOfInsecureIndicator(background: Bool = false) -> UIImage { + switch self { + case .letter: + if background { + return IconsStyleKit.imageOfPostcardBG + } + return IconsStyleKit.imageOfPostcard + case .padlock: + if background { + return IconsStyleKit.imageOfPadlockInsecureBG + } + return IconsStyleKit.imageOfPadlockInsecure + } + } + + func drawOfSecureIndictor(frame: CGRect?, rezising: IconsStyleKit.ResizingBehavior = .aspectFit, color: UIColor = IconsStyleKit.strokeColor, fillbackground: Bool = false, open: Bool) { + switch self { + case .letter: + if open { + var f = CGRect(x: 0, y: 0, width: 47, height: 43) + if let frame = frame { + f = frame + } + IconsStyleKit.drawLetterOpen(frame: f, resizing: rezising, color: color) + } + else { + var f = CGRect(x: 0, y: 0, width: 50, height: 35) + if let frame = frame { + f = frame + } + IconsStyleKit.drawLetter(frame: f, resizing: .aspectFit, color: color, fillBackground: fillbackground) + } + break + case .padlock: + var f = CGRect(x: 0, y: 0, width: 35, height: 50) + if let frame = frame { + f = frame + } + IconsStyleKit.drawPadlockSecure(frame: f, resizing: rezising, color: color, fillBackground: fillbackground) + } + } + + func drawOfInSecureIndictor(frame: CGRect?, rezising: IconsStyleKit.ResizingBehavior = .aspectFit, color: UIColor = IconsStyleKit.strokeColor, fillbackground: Bool = false, open: Bool) { + switch self { + case .letter: + var f = CGRect(x: 0, y: 0, width: 49, height: 34) + if let frame = frame { + f = frame + } + IconsStyleKit.drawPostcard(frame: f, resizing: rezising, color: color, fillBackground: fillbackground) + break + case .padlock: + var f = CGRect(x: 0, y: 0, width: 35, height: 50) + if let frame = frame { + f = frame + } + IconsStyleKit.drawPadlockInsecure(frame: f, resizing: rezising, color: color, fillBackground: fillbackground) + } + } + + func drawOfCorruptedIndictor(frame: CGRect?, rezising: IconsStyleKit.ResizingBehavior = .aspectFit, color: UIColor = IconsStyleKit.strokeColor, fillbackground: Bool = false, open: Bool) { + switch self { + case .letter: + var f = CGRect(x: 0, y: 0, width: 49, height: 34) + if let frame = frame { + f = frame + } + IconsStyleKit.drawLetterCorrupted(frame: f, resizing: rezising, color: color) + break + case .padlock: + var f = CGRect(x: 0, y: 0, width: 35, height: 50) + if let frame = frame { + f = frame + } + IconsStyleKit.drawPadlockError(frame: f, resizing: rezising, color: color, fillBackground: fillbackground) + } + } + +} diff --git a/enzevalos_iphone/study parameters/StudyParameterProtocol.swift b/enzevalos_iphone/study parameters/StudyParameterProtocol.swift new file mode 100644 index 0000000000000000000000000000000000000000..72e54d75544a67795c62268a8ac9a806999713a5 --- /dev/null +++ b/enzevalos_iphone/study parameters/StudyParameterProtocol.swift @@ -0,0 +1,73 @@ +// +// StudyParameterProtocol.swift +// enzevalos_iphone +// +// Created by Oliver Wiese on 22.01.19. +// Copyright © 2019 fu-berlin. All rights reserved. +// + +import Foundation +import KeychainAccess + +protocol StudyParameterProtocol { + static var name: String {get} + static var keyName: String {get} + static var numberOfTreatments: UInt32 {get} + static var defaultValue: StudyParameterProtocol {get} + static func findParameter(rawvalue: Int) -> StudyParameterProtocol + + var value: Int {get} + func startStudy() +} + +extension StudyParameterProtocol { + + static func load() -> StudyParameterProtocol { + if let param = loadKeyChain() { + return param + } + return self.defaultValue + } + + static func reset() -> Bool { + UserDefaults.standard.removeObject(forKey: self.keyName) + let keychain = Keychain(service: "Enzevalos/Study") + do { + try keychain.remove(self.keyName) + } + catch { + print(error) + return false + } + + return true + } + + private static func loadUserDefault() -> StudyParameterProtocol? { + let value = UserDefaults.standard.integer(forKey: self.keyName) + return self.findParameter(rawvalue: value) + } + + private static func loadKeyChain() -> StudyParameterProtocol? { + guard StudySettings.isStudyParameter(type: self) else { + return nil + } + let keychain = Keychain(service: "Enzevalos/Study") + var value: Int? + if let state = keychain[self.keyName], let num = Int(state) { + value = num + } else { + value = Int(arc4random_uniform(self.numberOfTreatments)) + if let value = value { + keychain[self.keyName] = String(value) + } + } + if let v = value { + UserDefaults.standard.set(v, forKey: self.keyName) + return self.findParameter(rawvalue: v) + } + return nil + } +} + + diff --git a/enzevalos_iphone/study parameters/Warning.swift b/enzevalos_iphone/study parameters/Warning.swift new file mode 100644 index 0000000000000000000000000000000000000000..5aa55e6a288c08423ed9044b6add64a2823aa5d4 --- /dev/null +++ b/enzevalos_iphone/study parameters/Warning.swift @@ -0,0 +1,60 @@ +// +// Warning.swift +// enzevalos_iphone +// +// Created by Oliver Wiese on 28.01.19. +// Copyright © 2019 fu-berlin. All rights reserved. +// + +import Foundation + +enum Warning: Int, StudyParameterProtocol { + case hide = 0, show = 1 + + static var defaultValue: StudyParameterProtocol { + get { + return Warning.hide + } + } + + static func findParameter(rawvalue: Int) -> StudyParameterProtocol { + switch rawvalue { + case Warning.hide.rawValue: + return Warning.hide + case Warning.hide.rawValue: + return Warning.show + default: + return defaultValue + } + } + + static var name: String { + get { + return "warning" + } + } + + static var keyName: String { + get{ + return "warning" + } + } + + static var numberOfTreatments: UInt32 { + get { + return 2 + } + } + + var value: Int { + get { + return self.rawValue + } + } + + func startStudy() { + return + } + + +} diff --git a/enzevalos_iphone/support_pk.asc b/enzevalos_iphone/support_pk.asc new file mode 100644 index 0000000000000000000000000000000000000000..fe55ee33791dad70774072de68dc691d18235b1c --- /dev/null +++ b/enzevalos_iphone/support_pk.asc @@ -0,0 +1,52 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +Ll/htKWmOh8fDq/IAL0= +=Rnok +-----END PGP PUBLIC KEY BLOCK----- diff --git a/enzevalos_iphoneTests/AutocryptTest.swift b/enzevalos_iphoneTests/AutocryptTest.swift new file mode 100644 index 0000000000000000000000000000000000000000..974edb17b58ddd5b38cf5209c78ebab0b9c83158 --- /dev/null +++ b/enzevalos_iphoneTests/AutocryptTest.swift @@ -0,0 +1,138 @@ +// +// Autocrypt.swift +// enzevalos_iphoneTests +// +// Created by Oliver Wiese on 01.11.18. +// Copyright © 2018 fu-berlin. All rights reserved. +// + +import XCTest +/** + Test cases: + * parse Header + * parse examples and test cases (see: https://github.com/autocrypt/specs_data/tree/master/data) + * Gossip + * Secret key export + * Secret key import + */ + +@testable import enzevalos_iphone +class AutocryptTest: XCTestCase { + let datahandler = DataHandler.handler + let mailHandler = AppDelegate.getAppDelegate().mailHandler + let pgp = SwiftPGP() + let userAdr = "bob@enzevalos.de" + let userName = "bob" + var user: MCOAddress = MCOAddress.init(mailbox: "bob@enzevalos.de") + var userKeyID: String = "" + + var simpleAutocryptExample: String{ + get{ + return """ + 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 + """ + } + } + + override func setUp() { + super.setUp() + datahandler.reset() + pgp.resetKeychains() + (user, userKeyID) = owner() + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testAutocryptHeader(){ + let outmail = OutgoingMail(toEntrys: ["alice@example.com"], ccEntrys: [], bccEntrys: [], subject: "subject", textContent: "Body", htmlContent: nil) + if let parser = MCOMessageParser(data: outmail.plainData), let key = pgp.exportKey(id: userKeyID, isSecretkey: false, autocrypt: true) { + let autocrypt = Autocrypt.init(header: parser.header) + XCTAssertEqual(autocrypt.addr, userAdr) + XCTAssertEqual(autocrypt.key.remove(seperatedBy: .whitespacesAndNewlines), key.remove(seperatedBy: .whitespacesAndNewlines)) + XCTAssertEqual(autocrypt.prefer_encryption, EncState.MUTUAL) + do { + let autoKeyIds = try pgp.importKeys(key: autocrypt.key, pw: nil, isSecretKey: false, autocrypt: true) + if autoKeyIds.count > 0, let autoKeyId = autoKeyIds.first { + XCTAssertEqual(autoKeyId, userKeyID) + } + else { + XCTFail() + } + } + catch { + XCTFail() + } + } + else { + XCTFail() + } + } + + func testSpecExample(){ + let mailData = MailTest.loadMail(name: "autocryptSimpleExample1") + if let parser = MCOMessageParser(data: mailData) { + let autocrypt = Autocrypt.init(header: parser.header) + XCTAssertEqual(autocrypt.addr, "alice@autocrypt.example") + XCTAssertEqual(autocrypt.prefer_encryption, EncState.MUTUAL) + XCTAssertEqual(autocrypt.key.remove(seperatedBy: .whitespacesAndNewlines), simpleAutocryptExample.remove(seperatedBy: .whitespacesAndNewlines)) + do { + let autoKeyIds = try pgp.importKeys(key: autocrypt.key, pw: nil, isSecretKey: false, autocrypt: true) + XCTAssertEqual(autoKeyIds.first, "71DBC5657FDE65A7") + } + catch { + XCTFail() + } + } + } + + func createUser(adr: String = String.random().lowercased(), name: String = String.random()) -> MCOAddress { + return MCOAddress.init(displayName: name, mailbox: adr.lowercased()) + } + + func createPGPUser(adr: String = String.random().lowercased(), name: String = String.random()) -> (MCOAddress, String) { + let user = createUser(adr: adr, name: name) + let id = pgp.generateKey(adr: user.mailbox) + return (user, id) + } + + func owner() -> (MCOAddress, String) { + Logger.logging = false + let (user, userid) = createPGPUser(adr: userAdr, name: userName) + UserManager.storeUserValue(userAdr as AnyObject, attribute: Attribute.userAddr) + UserManager.storeUserValue(userid as AnyObject, attribute: Attribute.prefSecretKeyID) + return (user, userid) + } +} diff --git a/enzevalos_iphoneTests/CoreDataTests.swift b/enzevalos_iphoneTests/CoreDataTests.swift index a3b3b782572b2fd73c452253981e738f3a2e175a..9708565308addd02ee762069c0619a22d1137aac 100644 --- a/enzevalos_iphoneTests/CoreDataTests.swift +++ b/enzevalos_iphoneTests/CoreDataTests.swift @@ -83,6 +83,7 @@ class CoraDataTests: XCTestCase { let (user, userid) = createPGPUser(adr: userAdr, name: userName) UserManager.storeUserValue(userAdr as AnyObject, attribute: Attribute.userAddr) UserManager.storeUserValue(userid as AnyObject, attribute: Attribute.prefSecretKeyID) + UserManager.storeUserValue(userName as AnyObject, attribute: Attribute.userName) return (user, userid) } @@ -263,12 +264,11 @@ class CoraDataTests: XCTestCase { XCTAssertTrue(myrecord.isSecure) XCTAssertEqual(myContact.publicKeys.count, 2) let cryptoObject2 = pgp.encrypt(plaintext: body, ids: [newKeyId], myId: keyID) - let decryptObject2 = pgp.decrypt(data: cryptoObject2.chiphertext!, decryptionIDs: [newKeyId], verifyIds: [keyID], fromAdr: sender.mailbox) - + let decryptObject2 = pgp.decrypt(data: cryptoObject2.chiphertext!, decKeyIDs: [newKeyId], signatureIDs: [keyID], fromAddr: userAdr) _ = testMail(from: sender, to: [user], cc: [], bcc: [], folder: folderName, cryptoObject: decryptObject2) let cryptoObject3 = pgp.encrypt(plaintext: body, ids: [oldID], myId: keyID) - let decryptObject3 = pgp.decrypt(data: cryptoObject3.chiphertext!, decryptionIDs: [oldID], verifyIds: [keyID], fromAdr: sender.mailbox) + let decryptObject3 = pgp.decrypt(data: cryptoObject3.chiphertext!, decKeyIDs: [oldID], signatureIDs: [keyID], fromAddr: userAdr) let oldMail = testMail(from: sender, to: [user], cc: [], bcc: [], folder: folderName, cryptoObject: decryptObject3) XCTAssertTrue((oldMail?.decryptedWithOldPrivateKey)!) diff --git a/enzevalos_iphoneTests/CryptoTests.swift b/enzevalos_iphoneTests/CryptoTests.swift index 28a5ba6eeb19f3077ec2492b4b0e292956396097..d9e99326d7859ac800161cf58c5d267d2ea7884a 100644 --- a/enzevalos_iphoneTests/CryptoTests.swift +++ b/enzevalos_iphoneTests/CryptoTests.swift @@ -360,17 +360,15 @@ class CryptoTests: XCTestCase { let signedMessage = """ -----BEGIN PGP SIGNATURE----- - iQGzBAEBCgAdFiEEJRxNIIPfYdSrprTDTbvambTX/SgFAlq5A9oACgkQTbvambTX - /SgIWwwAm1BTBjme8ogPdKcj2fyAzLjWPwttIW3nJN/tlB79TcId2sAAZK0hyhJQ - PU+j72x0IrgnJ0Vf40B9QU07RgLtdJPXXN1GWQPaz/69Wiut4T6mUusiqfE4RLiy - HJF7OYUNY6adteO1jCm0ZiZl3VW6XVomaXNuZtqXE+4U2k4WyQvaGbYMNvaaAYRf - vwYLyj/CO6++7lhYDet+A4OE5w0WcRHqrM4IRs/wF62cgBVl9cnonvl/2MTgR6DX - ewEcAeF+BmtMfVZhjEUa/zslLRTCRaxpVCq6BjHydakCTpZCJJTQcm+gVZrtQjl0 - 953zPJUfJ1/pvUextyKihT9a5itsxV2Tboq0mwD09M+hqWlHy0lQujI/hggcVvxE - DudoBwBZ4TilZyfRaSb9no1lJjxTZhwtsAvwOSPhRs3pGxkL9TS4GmqSsl8vZUBt - LBNFaFMvJfDXqmwIcW1Yl+apk7bWqY7yfTCgdRzhcqFDxdqhchNYvq4x035z4Udz - ZMarcccr - =OmRP + wsDcBAABCgAGBQJcgVq4AAoJEE272pm01/0o2Y0L/jS3UhX5ypJj1SKMVKWxHVW8CkzlHHsEtuhK + kkZs7sq9X8pqVGGeLjf+Bvz7dg5epAd76yD7M/hpHpEzAY+j4q0IjAQfkUApJIHnX303g9Xg2qC0 + KymaoHV2iD7TfkGdCpoP4lmq9DVwQWOs6ixKThO9QjNJFjZRFfI7bQlH2dKg89JVpLfoK438fm3t + pNAmcf60wYCc2SI4zGaduyiLBIHR9XG4tb9Tc82Sf3tguBNHpmTvmiJFCL7ZZNWg8lQP2kDmPkds + Ugo602abhT64VBxi4YPXHw2tNApEtniMbn03X1Z/oPMNDN3m+/0YZU6+Fc0RwJ9SBHvGxLSXH9qc + PH1tdx4Bm1z1P+oQrD9vRbTqxLM6g5vk0bG/5Esa4f1/yQWto5LH0cZXVG2Ugy2x+4fYWCumMXDS + Vj+6SjTsZpctBji7OUYA2vMNXRdtOBCrYvEoq+Nm2eATp0zba+2kUVYY5HJqDMxepdBUKI+esXDZ + wnNopEkrmkzNWaQZou1QtQ== + =p/QU -----END PGP SIGNATURE----- """ @@ -485,7 +483,7 @@ class CryptoTests: XCTestCase { XCTFail("No data") return } - let cryptoObject = pgp.decrypt(data: data, decryptionId: userKeyID, verifyIds: [], fromAdr: nil) + let cryptoObject = pgp.decrypt(data: data, decKeyIDs: [userKeyID], signatureIDs: [], fromAddr: userAdr) XCTAssert(cryptoObject.encryptionState == .NoEncryption) XCTAssert(cryptoObject.signatureState == .NoSignature) XCTAssert(cryptoObject.decryptedData == nil && cryptoObject.decryptedText == nil && cryptoObject.signKey == nil) @@ -502,7 +500,7 @@ class CryptoTests: XCTestCase { XCTFail("No chipher data") return } - let cryptoObject = pgp.decrypt(data: data, decryptionId: userKeyID, verifyIds: [], fromAdr: nil) + let cryptoObject = pgp.decrypt(data: data, attachedSignature: nil, decKeyIDs: [userKeyID], signatureIDs: [], fromAddr: userAdr) XCTAssert(cryptoObject.encryptionState == .ValidedEncryptedWithCurrentKey) XCTAssert(cryptoObject.signatureState == .NoSignature) XCTAssert(cryptoObject.plaintext == body && cryptoObject.plaintext == cryptoObject.decryptedText) @@ -520,13 +518,18 @@ class CryptoTests: XCTestCase { } // 1. case: correct signed mail - var cryptoObject = pgp.decrypt(data: signedData, decryptionId: keys.first, verifyIds: keys, fromAdr: nil) - XCTAssert(cryptoObject.encryptionState == .NoEncryption && cryptoObject.signatureState == .ValidSignature) - XCTAssert(cryptoObject.decryptedText == "only a signed mail!") - - // 2. case: manipulated mail - cryptoObject = pgp.decrypt(data: manipulatedDate, decryptionId: keys.first, verifyIds: keys, fromAdr: nil) - XCTAssert(cryptoObject.encryptionState == .NoEncryption && cryptoObject.signatureState == .InvalidSignature) + let text = "only a signed mail!" + if let data = text.data(using: .utf8) { + var cryptoObject = pgp.decrypt(data: data, attachedSignature: signedData, decKeyIDs: [userKeyID], signatureIDs: keys, fromAddr: "alice@enzevalos.de") + XCTAssert(cryptoObject.encryptionState == .NoEncryption && cryptoObject.signatureState == .ValidSignature) + XCTAssert(cryptoObject.chiperString == text) + // 2. case: manipulated mail + cryptoObject = pgp.decrypt(data: data, attachedSignature: manipulatedDate, decKeyIDs: keys, signatureIDs: keys, fromAddr: "alice@enzevalos.de") + XCTAssert(cryptoObject.encryptionState == .NoEncryption && cryptoObject.signatureState == .InvalidSignature) + } + else { + XCTFail("Can not make String to data.") + } } func testEncSignedMail() { @@ -537,30 +540,29 @@ class CryptoTests: XCTestCase { let senderPGP = SwiftPGP() let encObject = senderPGP.encrypt(plaintext: body, ids: [userKeyID], myId: senderID) XCTAssert(encObject.encryptionState == .ValidedEncryptedWithCurrentKey && encObject.signatureState == SignatureState.ValidSignature) - let falseEncObject = senderPGP.encrypt(plaintext: body, ids: [], myId: senderID) + let falseEncObject = senderPGP.encrypt(plaintext: body, ids: [id2], myId: senderID) guard let data = encObject.chiphertext, let data2 = falseEncObject.chiphertext else { XCTFail("no chipher data") return } // 1. case: signed but no public key available to verify signature - var cryptoObject = pgp.decrypt(data: data, decryptionId: userKeyID, verifyIds: [], fromAdr: nil) + var cryptoObject = pgp.decrypt(data: data, attachedSignature: nil, decKeyIDs: [userKeyID], signatureIDs: [], fromAddr: userAdr) XCTAssert(cryptoObject.encryptionState == .ValidedEncryptedWithCurrentKey) - XCTAssert(cryptoObject.signatureState == .NoPublicKey) + XCTAssert(cryptoObject.signatureState != .ValidSignature) // No PK XCTAssert(cryptoObject.plaintext == body && cryptoObject.plaintext == cryptoObject.decryptedText) - // 2. case: signed and public key available - cryptoObject = pgp.decrypt(data: data, decryptionId: userKeyID, verifyIds: [senderID, id2], fromAdr: nil) + cryptoObject = pgp.decrypt(data: data, attachedSignature: nil, decKeyIDs: [userKeyID], signatureIDs: [senderID, id2], fromAddr: senderAddress.mailbox) XCTAssert(cryptoObject.signatureState == .ValidSignature) XCTAssert(cryptoObject.signKey == senderID) XCTAssert(cryptoObject.signedAdrs.contains(senderAddress.mailbox) && cryptoObject.signedAdrs.count == 1) // 3. case: signed and check with wrong key - cryptoObject = pgp.decrypt(data: data, decryptionId: userKeyID, verifyIds: [id2], fromAdr: nil) - XCTAssert(cryptoObject.signatureState == .NoPublicKey) + cryptoObject = pgp.decrypt(data: data, decKeyIDs: [userKeyID], signatureIDs: [id2], fromAddr: senderAddress.mailbox) + XCTAssert(cryptoObject.signatureState != .ValidSignature) // 4. case: can not decrypt (wrong/missing decryption/encryption key) - cryptoObject = pgp.decrypt(data: data2, decryptionId: userKeyID, verifyIds: [senderID], fromAdr: nil) + cryptoObject = pgp.decrypt(data: data2, decKeyIDs: [userKeyID], signatureIDs: [senderID], fromAddr: senderAddress.mailbox) XCTAssert(cryptoObject.encryptionState == .UnableToDecrypt && cryptoObject.signatureState == .NoSignature) // 5. case: used old key to encrypt message @@ -571,9 +573,15 @@ class CryptoTests: XCTestCase { } XCTAssertEqual(keys.count, 1) _ = datahandler.newSecretKeys(keyIds: keys, addPKs: true) +<<<<<<< HEAD XCTAssertEqual(keys.first, datahandler.prefSecretKey()?.keyID) cryptoObject = pgp.decrypt(data: data, decryptionId: userKeyID, verifyIds: [senderID], fromAdr: nil) XCTAssertEqual(keys.first, datahandler.prefSecretKey()?.keyID) +======= + XCTAssertEqual(keys.first, datahandler.prefSecretKey().keyID) + cryptoObject = pgp.decrypt(data: data, decKeyIDs: [userKeyID], signatureIDs: [senderID], fromAddr: senderAddress.mailbox) + XCTAssertEqual(keys.first, datahandler.prefSecretKey().keyID) +>>>>>>> master XCTAssert(cryptoObject.encryptionState == .ValidEncryptedWithOldKey && cryptoObject.signatureState == .ValidSignature) XCTAssert(cryptoObject.decryptedText == body) } diff --git a/enzevalos_iphoneTests/MailTest.swift b/enzevalos_iphoneTests/MailTest.swift new file mode 100644 index 0000000000000000000000000000000000000000..9c47291a92571a758ad56e85ad021a1903846731 --- /dev/null +++ b/enzevalos_iphoneTests/MailTest.swift @@ -0,0 +1,363 @@ +// +// MailTest.swift +// +// +// Created by Oliver Wiese on 31.10.18. +// + +import XCTest + +/* + Test cases: + + parse incoming mails: + MUA = {Letterbox, AppleMail, iOSMail, Thunderbird (+ Enigmail) [DONE], K9 (+ OKC)(, WebMail)} + MUA x EncState x SigState (x Attachment) + + parse pgp mails: + * inline pgp DONE + * mime pgp DONE + + parse special mails: + * public key import (attachment, inline) + * secret key import (attachment, inline) + + + parse mail compontens: + * header (to, cc, bcc, subject, date etc.) DONE + * body DONE + * attachments + +What about errors and special cases? + * mixed encState/sigState in mail + * html mail + * attachments + * remote content + * java script + + create Mails: -> Export as eml (in Message builder)? + * EncState x SigState -> is correct? + * mixed receivers (plain, enc) -> Text if matching is correct DONE + * attach public key + * export secret key + + TODOS: + What about input validation e.g. addr: b@example + */ + +@testable import enzevalos_iphone +class MailTest: XCTestCase { + let datahandler = DataHandler.handler + let mailHandler = AppDelegate.getAppDelegate().mailHandler + let pgp = SwiftPGP() + let userAdr = "bob@enzevalos.de" + let userName = "bob" + var user: MCOAddress = MCOAddress.init(mailbox: "bob@enzevalos.de") + var userKeyID: String = "" + + + static let body = """ + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque dapibus id diam ac volutpat. Sed quis cursus ante. Vestibulum eget gravida felis. Nullam accumsan diam quis sem ornare lacinia. Aenean risus risus, maximus quis faucibus et, maximus at nunc. Duis pharetra augue libero, et congue diam varius eget. Nullam efficitur ex purus, non accumsan tellus laoreet hendrerit. Suspendisse gravida interdum eros, eu venenatis ante suscipit nec. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Praesent pellentesque cursus sem, non ornare nunc commodo vel. Praesent sed magna at ligula ultricies sagittis malesuada non est. Nam maximus varius mauris. Etiam dignissim congue ligula eu porta. Nunc rutrum nisl id mauris efficitur ultrices. Maecenas sit amet velit ac mauris consequat sagittis at et lorem. + """ + override func setUp() { + super.setUp() + datahandler.reset() + pgp.resetKeychains() + (user, userKeyID) = owner() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + + + func testSimpleMailCreation() { + // Init + let tos = ["to1@example.com", "to2@example.com"] + let ccs = ["cc1@example.com"] + let bccs = ["bcc1@example.com"] + let subject = "subject" + let body = "This is the body" + let outMail = OutgoingMail(toEntrys: tos, ccEntrys: ccs, bccEntrys: bccs, subject: subject, textContent: body, htmlContent: nil) + if let data = outMail.plainData { + // Test parsing! + let incMail = IncomingMail(rawData: data, uID: 0, folderPath: "INBOX", flags: MCOMessageFlag.init(rawValue: 0)) + if let mail = incMail.store(keyRecord: nil){ + XCTAssertTrue(MailTest.compareAdrs(adrs1: tos, adrs2: mail.getReceivers())) + XCTAssertTrue(MailTest.compareAdrs(adrs1: ccs, adrs2: mail.getCCs())) + XCTAssertTrue(mail.getBCCs().count == 0) + XCTAssertEqual(subject, mail.subject) + XCTAssertEqual(body, mail.body) + XCTAssertFalse(mail.isSecure) + } + else { + XCTFail() + } + } + else { + XCTFail() + } + } + + + func testFormatMail() { + // Init + let tos = ["to1@example.com", "to2@example.com"] + let ccs = ["cc1@example.com"] + let bccs = ["bcc1@example.com"] + let subject = "subject" + let body = """ + Another at: + + https://www.fu-berlin.de + + Found that one because I was submitting the same URL from a phishing email. + + See: mi.fu-berlin.de + For host name format of Azure static web sites. + https certs will be valid – Microsoft signed. + """ + let outMail = OutgoingMail(toEntrys: tos, ccEntrys: ccs, bccEntrys: bccs, subject: subject, textContent: body, htmlContent: nil) + if let data = outMail.plainData { + // Test parsing! + let incMail = IncomingMail(rawData: data, uID: 0, folderPath: "INBOX", flags: MCOMessageFlag.init(rawValue: 0)) + if let mail = incMail.store(keyRecord: nil){ + XCTAssertEqual(subject, mail.subject) + XCTAssertEqual(body, mail.body) + } + else { + XCTFail() + } + } + else { + XCTFail() + } + } + + + + func testSecureMailCreation() { + let encAdr = "enc@example.com" + let subject = "subject" + let body = "body" + _ = createPGPUser(adr: encAdr, name: encAdr) + let outMail = OutgoingMail(toEntrys: [encAdr], ccEntrys: [], bccEntrys: [], subject: subject, textContent: body, htmlContent: nil) + if let data = outMail.pgpData{ + let incMail = IncomingMail(rawData: data, uID: 1, folderPath: "INBOX", flags: MCOMessageFlag.init(rawValue: 0)) + if let mail = incMail.store(keyRecord: nil) { + XCTAssertEqual(body, mail.body) + XCTAssertTrue(mail.isSecure) + } + else { + XCTFail() + } + } + else { + XCTFail() + } + } + + func testMixedMailCreation() { + let encAdr = "enc@example.com" + let plainAdr = "plain@example.com" + let subject = "subject" + let body = "body" + _ = createPGPUser(adr: encAdr, name: encAdr) + let outMail = OutgoingMail(toEntrys: [plainAdr, encAdr], ccEntrys: [], bccEntrys: [], subject: subject, textContent: body, htmlContent: nil) + if let data = outMail.pgpData { + let incMail = IncomingMail(rawData: data, uID: 2, folderPath: "INBOX", flags: MCOMessageFlag.init(rawValue: 0)) + if let mail = incMail.store(keyRecord: nil){ + XCTAssertEqual(body, mail.body) + XCTAssertTrue(mail.isSecure) + XCTAssertTrue(MailTest.compareAdrs(adrs1: [encAdr, plainAdr], adrs2: mail.getReceivers())) + } + else { + XCTFail() + } + } + else { + XCTFail() + } + if let data = outMail.plainData { + let incMail = IncomingMail(rawData: data, uID: 3, folderPath: "INBOX", flags: MCOMessageFlag.init(rawValue: 0)) + + if let mail = incMail.store(keyRecord: nil) { + XCTAssertEqual(body, mail.body) + XCTAssertFalse(mail.isSecure) + XCTAssertTrue(MailTest.compareAdrs(adrs1: [plainAdr, encAdr], adrs2: mail.getReceivers())) + } + else { + XCTFail() + } + } + else { + XCTFail() + } + } + + func testSecretKeyImport(){ + + } + + func testThunderbirdPlainMail() { + testMailAliceToBob(name: "plainThunderbird", isSecure: false, encState: EncryptionState.NoEncryption, sigState: SignatureState.NoSignature) + } + func testThunderbirdSecureMail(){ + testSecureMail(name: "enc+signedThunderbird") + } + func testThunderBirdSecureInlineMail() { + testSecureMail(name: "enc+signedInlineThunderbird") + } + func testThunderbirdEncMail(){ + testMailAliceToBob(name: "encThunderbird", isSecure: false, encState: EncryptionState.ValidedEncryptedWithCurrentKey, sigState: SignatureState.NoSignature) + } + func testThunderbirdEncInlineMail(){ + testMailAliceToBob(name: "encInlineThunderbird", isSecure: false, encState: EncryptionState.ValidedEncryptedWithCurrentKey, sigState: SignatureState.NoSignature) + } + func testThunderbirdSigedInlineMail() { + testMailAliceToBob(name: "signedInlineThunderbird", isSecure: false, encState: EncryptionState.NoEncryption, sigState: SignatureState.ValidSignature) + } + func testThunderbirdSigedMail() { + testMailAliceToBob(name: "signedThunderbird", isSecure: false, encState: EncryptionState.NoEncryption, sigState: SignatureState.ValidSignature) + } + + func testMacPlainMail() { + testMailAliceToBob(name: "PlainMailFromMac", isSecure: false, encState: EncryptionState.NoEncryption, sigState: SignatureState.NoSignature) + } + func testMacSecureMail(){ + testSecureMail(name: "SignedEncMailFromMac") + } + func testMacEncMail(){ + testMailAliceToBob(name: "EncMailFromMac", isSecure: false, encState: EncryptionState.ValidedEncryptedWithCurrentKey, sigState: SignatureState.NoSignature) + } + func testMacSigedMail() { + testMailAliceToBob(name: "SignedMailFromMac", isSecure: false, encState: EncryptionState.NoEncryption, sigState: SignatureState.ValidSignature) + } + + func testSecureMail(name: String) { + testMailAliceToBob(name: name, isSecure: true) + } + + func testMailAliceToBob(name: String, isSecure: Bool, encState: EncryptionState? = nil, sigState: SignatureState? = nil) { + testMailAliceToBob(pkExists: true, name: name, isSecure: isSecure, encState: encState, sigState: sigState) + tearDown() + setUp() + testMailAliceToBob(pkExists: false, name: name, isSecure: isSecure, encState: encState, sigState: sigState) + } + + func testMailAliceToBob(pkExists: Bool, name: String, isSecure: Bool, encState: EncryptionState? = nil, sigState: SignatureState? = nil) { + let mailData = MailTest.loadMail(name: name ) + let (alice, _) = addAliceAndBob(addAlice: pkExists) + let incMail = IncomingMail(rawData: mailData, uID: 4, folderPath: "INBOX", flags: MCOMessageFlag.init(rawValue: 0)) + if let mail = incMail.store(keyRecord: nil) { + XCTAssertEqual(mail.isSecure, isSecure) + if let sig = sigState, sig == .ValidSignature{ + XCTAssertEqual(mail.signedKey?.keyID, alice) + XCTAssertEqual(mail.keyID, alice) + } + if isSecure{ + XCTAssertEqual(mail.signedKey?.keyID, alice) + XCTAssertEqual(mail.keyID, alice) + } + if let encState = encState { + XCTAssertEqual(mail.encState, encState) + } + if let sigState = sigState { + XCTAssertEqual(mail.sigState, sigState) + } + let body = mail.body + XCTAssertEqual(body.removeNewLines(), MailTest.body.removeNewLines()) + XCTAssertTrue(MailTest.compareAdrs(adrs1: ["bob@enzevalos.de"], adrs2: mail.getReceivers())) + } + else { + XCTFail() + } + } + + func addAliceAndBob(addAlice: Bool) -> (alice: String, bob: String){ + let aliceKeyId = importKey(file: "alicePublic", isSecretKey: false) + if addAlice { + _ = datahandler.newPublicKey(keyID: aliceKeyId, cryptoType: .PGP, adr: "alice@enzevalos.de", autocrypt: true) + } + let bobKeyId = importKey(file: "bobSecret", isSecretKey: true) + _ = datahandler.newSecretKey(keyID: bobKeyId, addPk: true) + return (aliceKeyId, bobKeyId) + } + + + static func compareAdrs(adrs1: [String], adrs2: [Mail_Address]) -> Bool{ + for adr in adrs1 { + var found = false + for adr2 in adrs2 { + if adr == adr2.address { + found = true + } + } + if !found { + return false + } + } + + for adr in adrs2 { + var found = false + for adr2 in adrs1 { + if adr.address == adr2 { + found = true + } + } + if !found { + return false + } + } + return true + + } + + func importKey(file: String, isSecretKey: Bool) -> String{ + let bundle = Bundle(for: type(of: self)) + do { + let keyData = try Data(contentsOf: bundle.url(forResource: file, withExtension: "asc")!) + let ids = try pgp.importKeys(data: keyData, pw: nil, secret: isSecretKey) + if ids.count > 0 { + return ids.first! + } + } catch { + XCTFail() + } + XCTFail() + return "" + } + + static func loadMail(name: String) -> Data { + let bundle = Bundle(for: self) + do { + let mail = try Data(contentsOf: bundle.url(forResource: name, withExtension: "eml")!) + return mail + } catch { + XCTFail() + } + return Data(base64Encoded: "")! + } + + func createUser(adr: String = String.random().lowercased(), name: String = String.random()) -> MCOAddress { + return MCOAddress.init(displayName: name, mailbox: adr.lowercased()) + } + + func createPGPUser(adr: String = String.random().lowercased(), name: String = String.random()) -> (MCOAddress, String) { + let user = createUser(adr: adr, name: name) + let id = pgp.generateKey(adr: user.mailbox) + return (user, id) + } + + func owner() -> (MCOAddress, String) { + Logger.logging = false + let (user, userid) = createPGPUser(adr: userAdr, name: userName) + UserManager.storeUserValue(userAdr as AnyObject, attribute: Attribute.userAddr) + UserManager.storeUserValue(userid as AnyObject, attribute: Attribute.prefSecretKeyID) + return (user, userid) + } + +} diff --git a/enzevalos_iphoneTests/StudyTest.swift b/enzevalos_iphoneTests/StudyTest.swift new file mode 100644 index 0000000000000000000000000000000000000000..adff51574a4674096dca56ae7747003437628676 --- /dev/null +++ b/enzevalos_iphoneTests/StudyTest.swift @@ -0,0 +1,100 @@ +// +// StudyTest.swift +// enzevalos_iphoneTests +// +// Created by Oliver Wiese on 29.01.19. +// Copyright © 2019 fu-berlin. All rights reserved. +// + +import XCTest + +@testable import enzevalos_iphone +class StudyTest: XCTestCase { + override func setUp() { + super.setUp() + self.reset() + } + + override func tearDown() { + super.tearDown() + self.reset() + } + + + private func reset() { + for p in StudySettings.parameters { + _ = p.reset() + } + } + func testSecurityIndicator(){ + testOneParameter(parameter: SecurityIndicator.self) + let secIndicator: SecurityIndicator = SecurityIndicator.load() as! SecurityIndicator + XCTAssertEqual(secIndicator.rawValue, StudySettings.securityIndicator.rawValue) + testDistribution(parameter: SecurityIndicator.self) + } + + func testOneParameter(parameter: StudyParameterProtocol.Type) { + StudySettings.parameters = [parameter] + + for para in StudySettings.allAvailableParameters { + if para.self != parameter.self { + XCTAssertEqual(para.defaultValue.value, para.load().value) + if para == Inviation.self { + XCTAssertEqual(para.defaultValue.value, StudySettings.invitationsmode.value) + } + } + } + } + + func testSecurityIndicatorAndWarning() { + testMultipleIndicators(parameters: [SecurityIndicator.self, Warning.self]) + let secIndicator: SecurityIndicator = SecurityIndicator.load() as! SecurityIndicator + XCTAssertEqual(secIndicator.rawValue, StudySettings.securityIndicator.rawValue) + + } + + func testSecurityIndicatorAndInvitation() { + testMultipleIndicators(parameters: [SecurityIndicator.self, Inviation.self]) + let secIndicator: SecurityIndicator = SecurityIndicator.load() as! SecurityIndicator + XCTAssertEqual(secIndicator.rawValue, StudySettings.securityIndicator.rawValue) + let invMode: Inviation = Inviation.load() as! Inviation + XCTAssertEqual(invMode.value, StudySettings.invitationsmode.value) + } + + func testMultipleIndicators(parameters: [StudyParameterProtocol.Type]) { + StudySettings.parameters = parameters + for para in StudySettings.allAvailableParameters { + var isPara = false + for x in parameters { + if para.keyName == x.keyName { + isPara = true + } + } + if !isPara { + XCTAssertEqual(para.defaultValue.value, para.load().value) + if para == Inviation.self { + XCTAssertEqual(para.defaultValue.value, StudySettings.invitationsmode.value) + } + } + } + } + + func testDistribution(parameter: StudyParameterProtocol.Type) { + var values: [Int] = Array(repeating: 0, count: Int(parameter.numberOfTreatments)) + let n = 100 + let mean = Double(n) / Double(parameter.numberOfTreatments) + let threshold = mean * 0.1 + + self.reset() + for _ in 0...n { + self.testOneParameter(parameter: parameter) + let v = parameter.load().value + values[v] = values[v] + 1 + self.reset() + } + for v in values { + XCTAssertLessThan(v, Int(mean + threshold)) + XCTAssertGreaterThan(v, Int(mean - threshold)) + } + } +} diff --git a/enzevalos_iphoneTests/testKeys/alicePublic.asc b/enzevalos_iphoneTests/testKeys/alicePublic.asc new file mode 100644 index 0000000000000000000000000000000000000000..73f94309803dc3fc2d82ccbf0d596b9cb60a66c4 --- /dev/null +++ b/enzevalos_iphoneTests/testKeys/alicePublic.asc @@ -0,0 +1,58 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +gXhCQhUXVfrkXAAQg+jrg04= +=XzWc +-----END PGP PUBLIC KEY BLOCK----- diff --git a/enzevalos_iphoneTests/testKeys/bobSecret.asc b/enzevalos_iphoneTests/testKeys/bobSecret.asc new file mode 100644 index 0000000000000000000000000000000000000000..4567fd75bc940e0917a591e2872075f7f9e28135 --- /dev/null +++ b/enzevalos_iphoneTests/testKeys/bobSecret.asc @@ -0,0 +1,137 @@ +-----BEGIN PGP PRIVATE KEY BLOCK----- + +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 +5hFcICXdNEGGg2WP7gSbZtF7RiNVzQ== +=XRxp +-----END PGP PRIVATE KEY BLOCK----- +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +=WHyX +-----END PGP PUBLIC KEY BLOCK----- diff --git a/enzevalos_iphoneTests/testMails/EncMailFromMac.eml b/enzevalos_iphoneTests/testMails/EncMailFromMac.eml new file mode 100644 index 0000000000000000000000000000000000000000..0478201e4e25b72619a9fd835b0ca825f3c42d92 --- /dev/null +++ b/enzevalos_iphoneTests/testMails/EncMailFromMac.eml @@ -0,0 +1,64 @@ +From: alice@enzevalos.de +Content-Type: multipart/encrypted; + boundary="Apple-Mail=_AA655859-23B9-4360-85CB-8C21BDBE3FB1"; + protocol="application/pgp-encrypted" +Mime-Version: 1.0 (Mac OS X Mail 11.5 \(3445.9.1\)) +Subject: EncMailFromMac +X-Universally-Unique-Identifier: FDED77CA-F304-4052-92A9-AAA27A78FF39 +Message-Id: <D2EDF774-9085-4735-8F57-2254387C839A@enzevalos.de> +Date: Fri, 8 Mar 2019 16:06:29 +0100 +To: Bob <bob@enzevalos.de> + +This is an OpenPGP/MIME encrypted message (RFC 2440 and 3156) +--Apple-Mail=_AA655859-23B9-4360-85CB-8C21BDBE3FB1 +Content-Transfer-Encoding: 7bit +Content-Type: application/pgp-encrypted +Content-Description: PGP/MIME Versions Identification + +Version: 1 + +--Apple-Mail=_AA655859-23B9-4360-85CB-8C21BDBE3FB1 +Content-Transfer-Encoding: 7bit +Content-Disposition: inline; + filename=encrypted.asc +Content-Type: application/octet-stream; + name=encrypted.asc +Content-Description: OpenPGP encrypted message + +-----BEGIN PGP MESSAGE----- + +hQGMA26fFf9Ygp7zAQv+JjvbKRQi2F/KFVSiPdmxAytklM3HCw3EZscCpNSfKGZ2 +o9Zd1xGjkVBcIcdUZWYDDpNuB7IX1ikg0Q9FkDavlI6Lcu3aZdx/ZBt5uZQM7HFm +7WuYnzMtidymHyNs7LcTNqZdNwHd3AYc+XyTOox8bbvbk8ojcdrIgxqeC6MqX1ch +2NTR1jDdAu0OpRAEMuwbHYSe0vCxSsnPsptUaErl0bT8N++rmghp+n9CIQ5QtvZ8 +Yze88B6YDx77eEcVnWR3Abmw9/dZSEdlzbVQZvInOIUktAGN34kj4qUZR/CisfXj ++tkvI2BQW5closNAwo/jm9+8inq5j6PjFkJ5r/xKAyRrh3m6M/d4KIUI0qFj3v2M +jSihyfehxewcMLO1oHYwRGJF9Ldb95XPWsWe/OFXuQEvNxeQUvsiL0eC3ZNQ8EJ0 +nrzMUs/M6jxEg+o1rH7CTPwPqbjArO5qyLnBAYWrQJUFM9a20Z+/INBrG5aNTJCb +pmVrw8KogTYUMWQonZHahQGMA6mH5Wf4h8YiAQv9HreKJ5Q2PvFtRbbuN8MFNZ9X +gQVwe0o0EBjIJetKb7/rNVbRukcrlpDHG+8B8Wir/P4loYqNGgLZl0RUrzK5RuxB +qu3M+eS7U+gMp4iOu/ohFChqhOXKWdStyGRT2gxX+YsjvAq+BH1fCY43yFCPKt/u +effbA1Hixrc+ZMs7LFVJouBMgQC+kddptfeWx3vykcuTgrfytAqNg9fsV7XlfM2D +wvzO4Xjv30i8lS2j2nUx1M/d6IlUTkMQjGpQjZV1aL4k7oZmF2msaXveTm6y8e7n +9TO83xrGXic0YWD0c6hUrJwluLlraQeUXrrKsMydX7CRfU0Lvs3aENp1qQ5akFzB +uqSm73bgijCMCjd1TdMySdC8A7vYZiItX2xh6VKvVAuWXxlRjr38yCnEHkLbhGNJ +liGrNRTmP/z9+3kE1cTvJvSkIfoy3EhU7/cyc9z4QGCyMEYBikTOlveynMsthEQW +QnLr6q6CFiD78Eko1Ajv2uCRR3XX7C8y+wB4BNIl0ukB9Ri66NLKIDLB49wB5ru0 +c8PCYuHvcha42jV6rJOp9ATd3kd4zoZ9/5xtEml6yfua0ijfQlNHzBL2qzIc8e2e +YYoXdyaJcbdxy+DiRVNqStH8lpv1ABNz/AZRgLCjutjqdv81uZj0cQmKnxyb84Uy +FJd6TsTaW5ictU7q28O6/hy7Af6BzFgBSGJ7l9cD9kiO2m5d5rjBYtbItCYSxfiQ +toU+2NK/vahH+0yL5zE825TsvZ6nRzW2y+8w1Z8H5980JDgUFfUPjVbJ02dytbCe +UCofCxBeEK8iBhLAqphhMWg8YIHUoHKAAkz4ZbQBiA7MBzvYc0r8iwusxx6MzQQq +Kw/RP41Su8ZX6m9DuTixLj0tb+Trz45shR1mBt6VRwcYdWrnKNheUzyVhTTJzTcQ +NseRFK/4mEOOBFOM9oBBllDjtG7ZAWxGAfCJfuEdaUxGZON05NO6NWyjVvoFfCIH +yvrPhm+2dxrSK/m1NGyCKpnwMngi1967A99exVx/6VgeFnDQnuAX+8mJPWWRY9mG +bpW4x+E3eUiJLHyg8+cLU+CP7gkE3wrSOBCp2cFE2EWj7ZW5olxuUNJ3nXXx726I +FtQ7uu6RM4ZQYpQ7Kx3E2jZ3ENGeUG2qDTR16jdOYgmntf4xmDbXKOyzKp5bZhTI +D+il9z35JXUqD0zhHa30n5LOXj66VjTHaogAKIHVCIl1FyxdeP8rAIYZWmZcM7G3 +Hu5p6nCtHS6kOePotDrCi+wanjr4kaZlVL1Z0/IfmttYAnIJcpueW2Zv9SMmWRmD +WNC/qkAnocQ5F5+3xGwGk381rsFsJ02F0z1PrDpgzDXR0MNZsBVw8K4JiT2csBbh +vdVk+lJ98T++9LZqhx5i2d5llg== +=h5an +-----END PGP MESSAGE----- + +--Apple-Mail=_AA655859-23B9-4360-85CB-8C21BDBE3FB1-- diff --git a/enzevalos_iphoneTests/testMails/PlainMailFromMac.eml b/enzevalos_iphoneTests/testMails/PlainMailFromMac.eml new file mode 100644 index 0000000000000000000000000000000000000000..2dcaf272735a26495de6cf386300cd38a6d5bf25 --- /dev/null +++ b/enzevalos_iphoneTests/testMails/PlainMailFromMac.eml @@ -0,0 +1,24 @@ +From: alice@enzevalos.de +Content-Type: text/plain; + charset=us-ascii +Content-Transfer-Encoding: quoted-printable +Mime-Version: 1.0 (Mac OS X Mail 11.5 \(3445.9.1\)) +Subject: PlainMailFromMac +X-Universally-Unique-Identifier: 241ED33E-49BA-40A1-ACE3-A59A3CB29409 +Message-Id: <D0FEF8FA-E918-4005-AE8F-97EC259643AB@enzevalos.de> +Date: Fri, 8 Mar 2019 16:05:37 +0100 +To: Bob <bob@enzevalos.de> + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque dapibus = +id diam ac volutpat. Sed quis cursus ante. Vestibulum eget gravida = +felis. Nullam accumsan diam quis sem ornare lacinia. Aenean risus risus, = +maximus quis faucibus et, maximus at nunc. Duis pharetra augue libero, = +et congue diam varius eget. Nullam efficitur ex purus, non accumsan = +tellus laoreet hendrerit. Suspendisse gravida interdum eros, eu = +venenatis ante suscipit nec. Class aptent taciti sociosqu ad litora = +torquent per conubia nostra, per inceptos himenaeos. Praesent = +pellentesque cursus sem, non ornare nunc commodo vel. Praesent sed magna = +at ligula ultricies sagittis malesuada non est. Nam maximus varius = +mauris. Etiam dignissim congue ligula eu porta. Nunc rutrum nisl id = +mauris efficitur ultrices. Maecenas sit amet velit ac mauris consequat = +sagittis at et lorem.= diff --git a/enzevalos_iphoneTests/testMails/SecureMailFromMac.eml b/enzevalos_iphoneTests/testMails/SecureMailFromMac.eml new file mode 100644 index 0000000000000000000000000000000000000000..079bff29ea83ba0c20e6a481e3e3510c9ce1a38f --- /dev/null +++ b/enzevalos_iphoneTests/testMails/SecureMailFromMac.eml @@ -0,0 +1,82 @@ +From: Bob <bob@enzevalos.de> +Content-Type: multipart/encrypted; + boundary="Apple-Mail=_C1C52216-4BAA-4FC0-A19C-AA3FC60A85AA"; + protocol="application/pgp-encrypted" +Mime-Version: 1.0 (Mac OS X Mail 11.5 \(3445.9.1\)) +Subject: SecureMailFromMac +X-Universally-Unique-Identifier: 99105245-D56C-4094-8BAC-2D0CF17B007B +Message-Id: <CEB95276-3FA2-430F-861D-9444C4169BEC@enzevalos.de> +Date: Thu, 7 Mar 2019 19:30:23 +0100 +To: alice <alice@enzevalos.de> + +This is an OpenPGP/MIME encrypted message (RFC 2440 and 3156) +--Apple-Mail=_C1C52216-4BAA-4FC0-A19C-AA3FC60A85AA +Content-Transfer-Encoding: 7bit +Content-Type: application/pgp-encrypted +Content-Description: PGP/MIME Versions Identification + +Version: 1 + +--Apple-Mail=_C1C52216-4BAA-4FC0-A19C-AA3FC60A85AA +Content-Transfer-Encoding: 7bit +Content-Disposition: inline; + filename=encrypted.asc +Content-Type: application/octet-stream; + name=encrypted.asc +Content-Description: OpenPGP encrypted message + +-----BEGIN PGP MESSAGE----- + +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 +=YkYS +-----END PGP MESSAGE----- + +--Apple-Mail=_C1C52216-4BAA-4FC0-A19C-AA3FC60A85AA-- diff --git a/enzevalos_iphoneTests/testMails/SignedEncMailFromMac.eml b/enzevalos_iphoneTests/testMails/SignedEncMailFromMac.eml new file mode 100644 index 0000000000000000000000000000000000000000..78e06b41662a5c6e4ee2b9409440bbbb4550898c --- /dev/null +++ b/enzevalos_iphoneTests/testMails/SignedEncMailFromMac.eml @@ -0,0 +1,82 @@ +From: alice@enzevalos.de +Content-Type: multipart/encrypted; + boundary="Apple-Mail=_E717ABD6-2F3E-4DB6-B2B6-18CAA74AABE5"; + protocol="application/pgp-encrypted" +Mime-Version: 1.0 (Mac OS X Mail 11.5 \(3445.9.1\)) +Subject: SignedEncMailFromMac +X-Universally-Unique-Identifier: 2747EA7F-7618-4A4D-9779-478BEC618434 +Message-Id: <ECE1713C-DBDD-4C3F-8672-FDF48F1EB911@enzevalos.de> +Date: Fri, 8 Mar 2019 16:07:06 +0100 +To: Bob <bob@enzevalos.de> + +This is an OpenPGP/MIME encrypted message (RFC 2440 and 3156) +--Apple-Mail=_E717ABD6-2F3E-4DB6-B2B6-18CAA74AABE5 +Content-Transfer-Encoding: 7bit +Content-Type: application/pgp-encrypted +Content-Description: PGP/MIME Versions Identification + +Version: 1 + +--Apple-Mail=_E717ABD6-2F3E-4DB6-B2B6-18CAA74AABE5 +Content-Transfer-Encoding: 7bit +Content-Disposition: inline; + filename=encrypted.asc +Content-Type: application/octet-stream; + name=encrypted.asc +Content-Description: OpenPGP encrypted message + +-----BEGIN PGP MESSAGE----- + +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 +=GYQG +-----END PGP MESSAGE----- + +--Apple-Mail=_E717ABD6-2F3E-4DB6-B2B6-18CAA74AABE5-- diff --git a/enzevalos_iphoneTests/testMails/SignedMailFromMac.eml b/enzevalos_iphoneTests/testMails/SignedMailFromMac.eml new file mode 100644 index 0000000000000000000000000000000000000000..f57b6385022b77fb707509c81b2b675d1942598b --- /dev/null +++ b/enzevalos_iphoneTests/testMails/SignedMailFromMac.eml @@ -0,0 +1,56 @@ +From: alice@enzevalos.de +Content-Type: multipart/signed; + boundary="Apple-Mail=_6FD29211-359B-4D3D-B663-021FB90ACCE7"; + protocol="application/pgp-signature"; + micalg=pgp-sha512 +Mime-Version: 1.0 (Mac OS X Mail 11.5 \(3445.9.1\)) +Subject: SignedMailFromMac +X-Universally-Unique-Identifier: 7A5006B1-1904-4D3A-A155-2ADE87BF1B50 +Message-Id: <BF47E140-788D-46A8-BB4D-822CE1C8C158@enzevalos.de> +Date: Fri, 8 Mar 2019 16:17:20 +0100 +To: Bob <bob@enzevalos.de> + + +--Apple-Mail=_6FD29211-359B-4D3D-B663-021FB90ACCE7 +Content-Transfer-Encoding: quoted-printable +Content-Type: text/plain; + charset=us-ascii + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque dapibus = +id diam ac volutpat. Sed quis cursus ante. Vestibulum eget gravida = +felis. Nullam accumsan diam quis sem ornare lacinia. Aenean risus risus, = +maximus quis faucibus et, maximus at nunc. Duis pharetra augue libero, = +et congue diam varius eget. Nullam efficitur ex purus, non accumsan = +tellus laoreet hendrerit. Suspendisse gravida interdum eros, eu = +venenatis ante suscipit nec. Class aptent taciti sociosqu ad litora = +torquent per conubia nostra, per inceptos himenaeos. Praesent = +pellentesque cursus sem, non ornare nunc commodo vel. Praesent sed magna = +at ligula ultricies sagittis malesuada non est. Nam maximus varius = +mauris. Etiam dignissim congue ligula eu porta. Nunc rutrum nisl id = +mauris efficitur ultrices. Maecenas sit amet velit ac mauris consequat = +sagittis at et lorem. + +--Apple-Mail=_6FD29211-359B-4D3D-B663-021FB90ACCE7 +Content-Transfer-Encoding: 7bit +Content-Disposition: attachment; + filename=signature.asc +Content-Type: application/pgp-signature; + name=signature.asc +Content-Description: Message signed with OpenPGP + +-----BEGIN PGP SIGNATURE----- + +iQGzBAEBCgAdFiEEJRxNIIPfYdSrprTDTbvambTX/SgFAlyCh4AACgkQTbvambTX +/SjHQAwAn+b0kGOcgfXEoFslecOZIDYINM9tUNHiBXH1S+5yZYE0PqWFQOfamAqC +8gGwuo4+p4LxeFttGf6qNQADIVHKimGkI7wZ+WHpY6r+qtccbZaWQ2e8dqgATdFw +QrM2JpJKvWyCE3+AEeKJscz36dcY8XYC9mXDkwW0gKbVLJFmUufQk8VchULDy23k +LNbPKzGb/wHpNR1eUO+VzGH2wBmuY5tn3Ahe/NqzmouI8Ypaw9C//R2ETblCZN3P +5s+MsEpxCt8NynLTpKU/3/iWBTkWkj5t7ACnkL14V9IFOpTkBFmhKhNa1qT1olkg +DDCOHcpI8jy24ibCGE1/1Wi3Vf66IGj7rWpGJobqc8OiW+IcQi3dyH4T7NIkzqCL +5iVkKODgotDIaZzKauVblRbYUEBSNEGhivZepOu+Mzyc8zDYngn3Elmf+9B+NyPv +UxOMrSZ9E/AbV4AhKd8MLBnRcyvu1fvBogFNb4jDVdfVfMeKkK+tfMc05LHDfdlg +HyLPlFy1 +=Kj4W +-----END PGP SIGNATURE----- + +--Apple-Mail=_6FD29211-359B-4D3D-B663-021FB90ACCE7-- diff --git a/enzevalos_iphoneTests/testMails/autocryptSimpleExample1.eml b/enzevalos_iphoneTests/testMails/autocryptSimpleExample1.eml new file mode 100644 index 0000000000000000000000000000000000000000..31787827072536e1283406d053d3a12408f5d77e --- /dev/null +++ b/enzevalos_iphoneTests/testMails/autocryptSimpleExample1.eml @@ -0,0 +1,43 @@ +Delivered-To: <bob@autocrypt.example> +From: Alice <alice@autocrypt.example> +To: Bob <bob@autocrypt.example> +Subject: an Autocrypt header example using RSA 3072 key +Autocrypt: addr=alice@autocrypt.example; prefer-encrypt=mutual; keydata= + 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 +Date: Tue, 07 Nov 2017 14:53:50 +0100 +Message-ID: <rsa-3072@autocrypt.example> +MIME-Version: 1.0 +Content-Type: text/plain + +This is an example e-mail with Autocrypt header and RSA 3072 key +as defined in Level 1. diff --git a/enzevalos_iphoneTests/testMails/enc+signedInlineThunderbird.eml b/enzevalos_iphoneTests/testMails/enc+signedInlineThunderbird.eml new file mode 100644 index 0000000000000000000000000000000000000000..c23ba71effd2862009a05b4cd45009c4a53da543 --- /dev/null +++ b/enzevalos_iphoneTests/testMails/enc+signedInlineThunderbird.eml @@ -0,0 +1,108 @@ +Return-Path: <alice@enzevalos.de> +Delivered-To: bob@enzevalos.de +To: Bob <bob@enzevalos.de> +From: alice <alice@enzevalos.de> +Subject: enc+signed with inline from Thunderbird +Openpgp: preference=signencrypt +Autocrypt: addr=alice@enzevalos.de; prefer-encrypt=mutual; keydata= + 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 + FRdV+uRcABCD6OuDTg== +Message-ID: <25ea9a1e-f826-41dc-91e8-03f74cbad172@enzevalos.de> +Date: Wed, 31 Oct 2018 12:17:03 +0100 +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:52.0) + Gecko/20100101 Thunderbird/52.9.1 +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: quoted-printable +Content-Language: en-US + + +-----BEGIN PGP MESSAGE----- +Charset: utf-8 + +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 +wSNJHK1fOFdnxcYTWCYvdI8=3D +=3D4+ip +-----END PGP MESSAGE----- + + diff --git a/enzevalos_iphoneTests/testMails/enc+signedThunderbird.eml b/enzevalos_iphoneTests/testMails/enc+signedThunderbird.eml new file mode 100644 index 0000000000000000000000000000000000000000..7e6cf91a1dbb31410d83049ce038067dc722dc28 --- /dev/null +++ b/enzevalos_iphoneTests/testMails/enc+signedThunderbird.eml @@ -0,0 +1,125 @@ +Return-Path: <alice@enzevalos.de> +Delivered-To: bob@enzevalos.de +To: Bob <bob@enzevalos.de> +From: alice <alice@enzevalos.de> +Subject: enc+signed from Thunderbird +Openpgp: preference=signencrypt +Autocrypt: addr=alice@enzevalos.de; prefer-encrypt=mutual; keydata= + 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 + FRdV+uRcABCD6OuDTg== +Message-ID: <2006b8e3-7eb8-31eb-bf91-52c20045bd0e@enzevalos.de> +Date: Wed, 31 Oct 2018 12:07:48 +0100 +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:52.0) + Gecko/20100101 Thunderbird/52.9.1 +MIME-Version: 1.0 +Content-Type: multipart/encrypted; + protocol="application/pgp-encrypted"; + boundary="0QM4cbuVDLfez6jf9tb5qRq1C9zkkFyYw" + +This is an OpenPGP/MIME encrypted message (RFC 4880 and 3156) +--0QM4cbuVDLfez6jf9tb5qRq1C9zkkFyYw +Content-Type: application/pgp-encrypted +Content-Description: PGP/MIME version identification + +Version: 1 + +--0QM4cbuVDLfez6jf9tb5qRq1C9zkkFyYw +Content-Type: application/octet-stream; name="encrypted.asc" +Content-Description: OpenPGP encrypted message +Content-Disposition: inline; filename="encrypted.asc" + +-----BEGIN PGP MESSAGE----- + +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 +=neWE +-----END PGP MESSAGE----- + +--0QM4cbuVDLfez6jf9tb5qRq1C9zkkFyYw-- diff --git a/enzevalos_iphoneTests/testMails/encInlineThunderbird.eml b/enzevalos_iphoneTests/testMails/encInlineThunderbird.eml new file mode 100644 index 0000000000000000000000000000000000000000..efd67fe5d01f051b7a50a3b87ebab9b7656c67be --- /dev/null +++ b/enzevalos_iphoneTests/testMails/encInlineThunderbird.eml @@ -0,0 +1,93 @@ +Return-Path: <alice@enzevalos.de> +Delivered-To: bob@enzevalos.de +To: Bob <bob@enzevalos.de> +From: alice <alice@enzevalos.de> +Subject: enc with inline from Thunderbird +Openpgp: preference=signencrypt +Autocrypt: addr=alice@enzevalos.de; prefer-encrypt=mutual; keydata= + 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 + FRdV+uRcABCD6OuDTg== +Message-ID: <b61496b6-f4e5-74d0-dc38-07e168075640@enzevalos.de> +Date: Wed, 31 Oct 2018 12:16:15 +0100 +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:52.0) + Gecko/20100101 Thunderbird/52.9.1 +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: quoted-printable +Content-Language: en-US + + +-----BEGIN PGP MESSAGE----- +Charset: utf-8 + +hQGMA26fFf9Ygp7zAQwAljI+Vx1FyBb7R2TdQEY/dwQYy4cDHCeJ170KrFJHBhV/ +zkZe/NF7RBk0mmNkPHem3kbrHa66hVkl3m6Zo9KTWrAGO8WD6jrcYLcXA+ll99+z +siXzOU0vmGsQf7NZV9aooejVkXm96YSTzS58805znOSHsepyHY2MzwWUUhRyZ7x1 +58xswnoejBAGSmk8yHgSm58mfBTMfVlC1ICsBguqaaxc43Xq946uEJeEKjYYyhAH +qSlDfU86AOmdjoGeaRcikdCGnaIK0FniS4EZkGb39A/4U/gIEsOT59bk2hfEGELX +e2jakX6dsRmimXp2Fhxnxt74k1WfnMJl04yR4j+ONJ7l4kDn0S1KmUTWnikpL0jk +L6VkwrAj/QafDcXdNSSrN5xC5Wou/mW8CAxJuWtfBNauWXx8tGVOWjCls6TXweIh +QnZP7eBOzZir0i+pzYHGkpSrsqCLD6k2c3ZSnwlN4o1Bl4R+9Bp0nLU0J/MWHOkR +eeLDJV4R7rLwa4yafYEphQGMA6mH5Wf4h8YiAQwAjXBRu5LT2iyvA0WPjblDDf0t +rNW1LK92AdE4AsrlQ0a6Co/lFIZTCF8C85CGh1dRK8URNrp/CmzAexGNzi2VyzkR +dCHlmr+3Il0Y05B/uPpAJjXwsH0TgvIU394IEZg6eVEQOMBgFhxmgogOSMgqVIAs +RJ7+LcURLjeJTsAr1KtsaqEXSaqH7NaYPO/MiVcahEKYgsRBtqvMyzCj4OZbYXkF +nYTpdNRhZNC0Jl9r9pebLtTbVCQJdWgSI4muKnyJomiiyKxVZNFlEUb06d5L8pc6 +kD+OO0ckbS7jdGDoarg6D4WNR8g5/AGxemLkJKpGYBzQ0UrbcZ778dXL2Hn6ZMaF +QA2Hk0wKbaXhxdr418YiIYam1B3LyqP9PH/xptZVcDkwpe6rIPj6vITSDwAYYHD+ +H0IrGTU3GTqLR/O4b/jSC59N9zYyfSoTW+C+QNmBlgSbC1GzxcrBgXXxO7TA5xIs +ZZ3hEid8wJOlqoHV48nxUecpYUmrGWIekjzF25H40ukB0QSl480vNF+qzk4KZrfe +wEq2maaKR6D+3aN7L4AVIJ/HJx6GOIUIS8nmfPr6iVL1JnBRS/J/A13DuIHGZcTA +tW4w7PbyotPbtcEpR+gQaIYg2prCeSqjlvpHCuAK30F082b42X2y/Mh4lDlOGgZI +9pS2f0zxBXOm+7Vvz006fCNlQAMkBFWT0YAqQMs6smss0PN80c2vFbYtQVlfFqb2 +vNPcf8sDTYclukFptMMSDESxea2rp+i+PyAPWW2dyipmd6KajiWx6zPNXYMB4em2 +/ZjdjCmhiZ3fsGQCDMRNyUVRC028S7okRpdb5yIwYUvlC8CmLtSPygYsiLe+j8OD +pGKIpiwFav47pu2gCRF0LCMjpIJmLTJoemhKL+EUyKVLt2E8SNJ80fZPK2x7KyV/ +VMQ8Adkvqz9pulpcmOz9WloMJz287Yg1Ptud5ANng/1zV/caSuR5zSYKxe5XJ1Qx +toIqrnO2w2qUh4G9bBP+0RyAcV3sbO4G0fTxkfwtRWx6x9zBxDSDaPViR5PYgGnM +Jgff31KYMi+kTRgOzcUCp1kcaZrRoJ/bxznhEV3FaADqmlnGGfA2LVKEY+dy+wEk +UQELoDg+Cfpv1jVq7Ghcaf5/JI02YuwP/HDl4xgtkRmmgBV5o6YLzts6rb4lyk7r +1qJcgTbRVJSDeLSkIZzU405NZdY7ZOmbioaqMHsvDXYw1E09mmcOET62knE57J1f +auXDgLhzEVxLfHcU4hvb0QMC9+tMQEpTWU3o7YSmoyoPFyro8sEICZgW+ELmg1o=3D +=3DZZML +-----END PGP MESSAGE----- + + diff --git a/enzevalos_iphoneTests/testMails/encThunderbird.eml b/enzevalos_iphoneTests/testMails/encThunderbird.eml new file mode 100644 index 0000000000000000000000000000000000000000..2d738a82942ebc76a67f16f3bf885645b2b288a1 --- /dev/null +++ b/enzevalos_iphoneTests/testMails/encThunderbird.eml @@ -0,0 +1,110 @@ +Return-Path: <alice@enzevalos.de> +Delivered-To: bob@enzevalos.de +To: Bob <bob@enzevalos.de> +From: alice <alice@enzevalos.de> +Subject: enc from Thunderbird +Openpgp: preference=signencrypt +Autocrypt: addr=alice@enzevalos.de; prefer-encrypt=mutual; keydata= + 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 + FRdV+uRcABCD6OuDTg== +Message-ID: <f11c49b1-f2e6-a981-2ed2-92e3ea8af251@enzevalos.de> +Date: Wed, 31 Oct 2018 12:15:40 +0100 +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:52.0) + Gecko/20100101 Thunderbird/52.9.1 +MIME-Version: 1.0 +Content-Type: multipart/encrypted; + protocol="application/pgp-encrypted"; + boundary="rQTpXP7Mot8JXwKx13GEOPUvkBQfoDvqM" + +This is an OpenPGP/MIME encrypted message (RFC 4880 and 3156) +--rQTpXP7Mot8JXwKx13GEOPUvkBQfoDvqM +Content-Type: application/pgp-encrypted +Content-Description: PGP/MIME version identification + +Version: 1 + +--rQTpXP7Mot8JXwKx13GEOPUvkBQfoDvqM +Content-Type: application/octet-stream; name="encrypted.asc" +Content-Description: OpenPGP encrypted message +Content-Disposition: inline; filename="encrypted.asc" + +-----BEGIN PGP MESSAGE----- + +hQGMA26fFf9Ygp7zAQv/T+jfE/eXkL66DslAsxrb1/Fle5dhBoLWwqBx8apRGSCl +IlZbvyJAArtN/k3JPAnsd0Kg0t89bOsjC3c7CkplkcIm87gW+gCG85zkchxRVUAk +N9ES8cRrTWI6tGCQPRKi9MV2w+GApf2DUo2lx8S6lhW5z8ZKLVMgg6T5sgwz81CO +N+UGhhx6T30IrZel0XhUqQaUx6Vq0T/SAiP7FeFs3QctZ/k70xKmJHKGwKixAYmV +Z7tRsiF37iP92Zr5yZz0l9O1Hh1Ov2kMi9GfrCLWr2Ca0qClv6oAbUR9pXGJAwUM +hLiVuESAk8VBDvAizILM7Gcq2LqcBPPj0TgF/FvYdK09l4ivexBBYCeCTpXEQaBO +tPucdz22RzEXdyv8aKxxZpxOj8jlspfCWFqyKxmzzah98Jb4qEzyPql2+cH/ECVP +KzJjCk03Pil41Ve2pAELJgV2aiEHR7j2UINf5/8ZbsVdoKojD3f1FQHIO1zoZE97 +jHUsrX4XmdG/x69IDSHMhQGMA6mH5Wf4h8YiAQv/a9fCg2dMoE4cUOvbTjmw3Q6z +UDlLc5/1yawp7tcCIYCWH+P6D76oXgMMbtP8mV+fZVNBSHKJ0JnrkFwK2kRNQrFu +h+nHszE6hjo0befEhc0VwAWTCDHKIZHqWxmh/gBmuJYqs0h44QCH9opuYKICoWOi +rGzFk0Ql1Zdn9PCU58Wtq39EwknK6bZxXUC5wH9+UTReP17DlPNG+0ylldoYNFQc +JPgCFUzhCCv93Ob8HyoYTnkowCvVjHDjbYIoBixOyD7iX5hO6GiuRa14MvSFrIAj +r1g5EkmFMc12XXWN/A1xacxIreFdZth+CN5qJxFUJNzWWPgmHluwuE2hkGFXeY3i +kNCExqaiNic5Jf2fN3fcyik9X4k1awiMWunqq71Tl4imUMz08/w+z06BbgPhdCZp +3R75wUqlKuuhfEz1ezijfrwFkNXK2YQUpxRnyRnhvVAuYNzaGb+vTnCuRYtRCwBu +aTnzeihTleYYBPouqWntt/B5IeFVVaB/GAYpvDzf0ukBrC0uGLPbRy06eloLWHhH +lcicPuBK/1UWUNA8MP/TUm7TYlKOgyz3NKYBmSq8ID/yjHE2JeQqDfRyrmS/Atj3 +kzSCzXVe4rIqgL3yFxnylQ2oVfk2LsTYW9zEtFCpwH8uXjpKESRCpGGZUAdvY9rJ +f4UAqybxdDCyWSCN8uo2TNOiQgiw3PHdJ/8Srx8GgElA1j2A2CZjB8NIbdTnhQft +FEQFroljMooTDoAa0kC5DfhPAdS+n2Fd/AuVX8hRDh5v1k16xhRaLaQ2A1TkR2h1 +xsLP0mAcKcXVRCwlhxGsmGgxUBzueRuEiKG+C/zTJJgxqKQFlVQhmwCsfsfs7bM8 +rtBAL1HobWNJ8Jo+tK9rodmfZzIP3V6FT2B/sGZa7dLxjm/FyhINX+VGg9RvSDnG +Qxuc28AFLFwLtJvZpTRBftbiDSVgZ6TbOQcWZx9zMN2UyRVBrx9ujM5q2bRq2WJN +znCseZPhvWiRk5H4NK8WdmGrk6pAzD0AGLIOZa0jb6XVpb30ptv+5eDyrVLb0MBO +KD3WahDRSBzuq/zsHZNDEekBxanCxWg9fdudp3DQg27TbFpuvj3lL+FHVf9Z6qA4 +zHO+8lIxQXBjRaZiibCoMKRhwlyI1ub5I3NvvMiOTSI2yOQB4f0+m3wmIlR3yGnj +loRsz7uJRbxLpF5WX/XpkMDFyJ6P/02WvK2CPYMF3dxFzsPMdVgb1CpVHEq/q8E6 +OrD/B/UlIJcAxaKHpSa+8Nd68ubA6mApwS/2AKff7Z4Qc9Mxsw5AEyk4CiWqBz+5 ++keZoqrM4HAriCtXKNh65AXIYwxiMecIkoui4mtf1zE3S1G3Xzcr6cALhWyifl0V +MkhJVMmv/RQv5ue7IrD9y8Lw8uGCLhvgMkpEhdaVjuBqMRUnJnuMtVcDJR2JZ5Ko +A+1jvNYEfzLbnK5R/8ltW1olans8gpqMOvinS/+VBNykZuxhR1v3ogcuFDWRddYK +iTAA087O16tlUoy9waomYBZks0hW0IhJ+3uZNcrjdkVoE9A8QiM8qqsB/CVITx5m +wr25XgCs/ynFMBs/VAEMbGCJaPuITPfJbsfjhnvcmjWlLuFIRc5MJK+d6QjYb5fU +FBe4BOqXtFlf4Jog+zKqb/SN2uUO/N8Qxw2YmQxDnsygYS7OSjuBf49m7Rh8OVmy +fBpUtF7IcZuVODbaSotJGrVy6Vcc47U= +=Mtyb +-----END PGP MESSAGE----- + +--rQTpXP7Mot8JXwKx13GEOPUvkBQfoDvqM-- diff --git a/enzevalos_iphoneTests/testMails/plainThunderbird.eml b/enzevalos_iphoneTests/testMails/plainThunderbird.eml new file mode 100644 index 0000000000000000000000000000000000000000..842c1dfa3055cad8cda6ac2d18af20bfab14e446 --- /dev/null +++ b/enzevalos_iphoneTests/testMails/plainThunderbird.eml @@ -0,0 +1,58 @@ +Return-Path: <alice@enzevalos.de> +Delivered-To: bob@enzevalos.de +To: Bob <bob@enzevalos.de> +From: alice <alice@enzevalos.de> +Subject: plain mail form Thunderbird +Openpgp: preference=signencrypt +Autocrypt: addr=alice@enzevalos.de; prefer-encrypt=mutual; keydata= + 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 + FRdV+uRcABCD6OuDTg== +Message-ID: <30406eb0-676d-c8d0-554a-9d05533d91bf@enzevalos.de> +Date: Wed, 31 Oct 2018 11:24:02 +0100 +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:52.0) + Gecko/20100101 Thunderbird/52.9.1 +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 7bit +Content-Language: en-US + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque dapibus id diam ac volutpat. Sed quis cursus ante. Vestibulum eget gravida felis. Nullam accumsan diam quis sem ornare lacinia. Aenean risus risus, maximus quis faucibus et, maximus at nunc. Duis pharetra augue libero, et congue diam varius eget. Nullam efficitur ex purus, non accumsan tellus laoreet hendrerit. Suspendisse gravida interdum eros, eu venenatis ante suscipit nec. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Praesent pellentesque cursus sem, non ornare nunc commodo vel. Praesent sed magna at ligula ultricies sagittis malesuada non est. Nam maximus varius mauris. Etiam dignissim congue ligula eu porta. Nunc rutrum nisl id mauris efficitur ultrices. Maecenas sit amet velit ac mauris consequat sagittis at et lorem. + diff --git a/enzevalos_iphoneTests/testMails/signedInlineThunderbird.eml b/enzevalos_iphoneTests/testMails/signedInlineThunderbird.eml new file mode 100644 index 0000000000000000000000000000000000000000..2f457ba6456560206fa736225dba44bcaf05f771 --- /dev/null +++ b/enzevalos_iphoneTests/testMails/signedInlineThunderbird.eml @@ -0,0 +1,88 @@ +Return-Path: <alice@enzevalos.de> +Delivered-To: bob@enzevalos.de +To: Bob <bob@enzevalos.de> +From: alice <alice@enzevalos.de> +Subject: signed with inline from Thunderbird +Openpgp: preference=signencrypt +Autocrypt: addr=alice@enzevalos.de; prefer-encrypt=mutual; keydata= + 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 + FRdV+uRcABCD6OuDTg== +Message-ID: <d6a408af-f34d-d5bc-f74c-2ec9a70d3c15@enzevalos.de> +Date: Wed, 31 Oct 2018 12:16:37 +0100 +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:52.0) + Gecko/20100101 Thunderbird/52.9.1 +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 7bit +Content-Language: en-US + + +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA512 + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque dapibus +id diam ac volutpat. Sed quis cursus ante. Vestibulum eget gravida +felis. Nullam accumsan diam quis sem ornare lacinia. Aenean risus risus, +maximus quis faucibus et, maximus at nunc. Duis pharetra augue libero, +et congue diam varius eget. Nullam efficitur ex purus, non accumsan +tellus laoreet hendrerit. Suspendisse gravida interdum eros, eu +venenatis ante suscipit nec. Class aptent taciti sociosqu ad litora +torquent per conubia nostra, per inceptos himenaeos. Praesent +pellentesque cursus sem, non ornare nunc commodo vel. Praesent sed magna +at ligula ultricies sagittis malesuada non est. Nam maximus varius +mauris. Etiam dignissim congue ligula eu porta. Nunc rutrum nisl id +mauris efficitur ultrices. Maecenas sit amet velit ac mauris consequat +sagittis at et lorem. +-----BEGIN PGP SIGNATURE----- + +iQGzBAEBCgAdFiEEJRxNIIPfYdSrprTDTbvambTX/SgFAlvZjxUACgkQTbvambTX +/SiZ0Av8DJ9xa/OX9TioSBtcOc3l/VdCZfm8vQCN0kiZTW8Mg9J3kZNOFsLwoqfz +5aaBL/HVfpK9ZJSZLdUGfSrBxk+K6FJN7UW1Yzbkvo7Pec1Zof+DfUJSlZT5vJiZ +naqJ/oW/nmgSSaaeBxWAOBgjQ5yQCaCN8vJLpMztl92zE5NUKP4FUL6V+HmXybMN +P5cApXABamuYFY/v4FnYCeTZ/yjpBMrcF8bUr+f9yQ8Df4oQnQVAKKsdfJVwpY1v +Pv1iRAeXa3p1YKDdxtDpqaVe66XqfBrRvrbGSNCIbIaF1Kh6ooLvmEjZLiJ9AdSx +mEfVAJgcC69r4dR2R9Tph9odD2/WAKSnoTcA7x5pb4ZZfg/TXhNhVQeqOJ4XxlFZ +u7lCeJzv8daFAs/7B31OKcXe0wYyOtBhXdQ0O5DkEubkYIFNR2918E4dUxQb1xKO +JsRL+kuWEhFXSUXm87Wyph6lPdyMYHV82HG5FfQ65BPmxUkAvlVdZEwlXEjhiiXO +eMyfhiTy +=d3k6 +-----END PGP SIGNATURE----- + diff --git a/enzevalos_iphoneTests/testMails/signedThunderbird.eml b/enzevalos_iphoneTests/testMails/signedThunderbird.eml new file mode 100644 index 0000000000000000000000000000000000000000..77fd59fc41871f6321ee49585e29e5cf016461c9 --- /dev/null +++ b/enzevalos_iphoneTests/testMails/signedThunderbird.eml @@ -0,0 +1,109 @@ +Return-Path: <alice@enzevalos.de> +Delivered-To: bob@enzevalos.de +To: Bob <bob@enzevalos.de> +From: alice <alice@enzevalos.de> +Subject: signed from Thunderbird +Openpgp: preference=signencrypt +Autocrypt: addr=alice@enzevalos.de; prefer-encrypt=mutual; keydata= + xsDNBFp+5vsBDACuHCvqCBlUT1O+IIQ0LOWsA2l/UAa+7PHNHotZJ22BtR//fmkdrIesPye2 + MeX+1R14m7tHt+Aw5xwc9t40xPD1Crbc2cnMaYJ2Siy5GBKpZh1Sr3jq9AQiNzYe1l3yPvnR + Z5M0zgc0ueyd+b61sr4KBu8PQ5BODPLW81afPBlBgVB0FDI2k1d9q4+r+obVIs43Hy6vB4Yk + UOyx5Fuaftj75Q86HNk3ig6fcvnRnbEmz+XifGYzJ5T/x2sZTGhg4CBDTDmEzdY0SFf7qgz4 + DYPrImlVksz5q0AXc22VbxuzRsK74SYKNix4i7gjaUZz6vNW+9qlJxUV4oJzj21KHH9EDlL2 + ErM7FYs4kI+POPChcFKTeJ8H4WxFBh67aHiIvHpo3f8pwitPCkk0UYU0KHcaHLgVv9R0vExB + j7BDQI1Qf/20z/FjfNz6Xgx4Lw4yGzePMopgsP2QEiKXC34g4F3dnXB6kg1l05lKuP+NhZF3 + qj139YoxlwkntfoQIhwJDUEAEQEAAc0nYWxpY2VAZW56ZXZhbG9zLmRlIDxhbGljZUBlbnpl + dmFsb3MuZGU+wsD6BBMBCAAkBQJafub7AhsDBBUICQoHCwkIBwMCAQQWAwIBAh4BAheAAhkB + AAoJEE272pm01/0oXxEL/jBE4xtcMJbYboIZcrWClBXSAEk567gjQkaIURlUEQiFGpZOqgX9 + xTmKcGUAJyvb942tbN7rytg+QQSl5BFWsVgbsXTSTpA/8WtlNVwlNhgbOUL01Bf0cldTz2jo + 67uE1Iq57m64Ig4R7td/3Tj15gh62XDHC6+v2LdWYX1SplUh4ABV+ATCB8cx44/5c5IxCcZj + HWDqut/K1JyftcEwKjD3+pK8qMjfx681MIwS0Vs16MQvU7/zWYFa4QFWpupLTCiI3snhQymE + kV1r8GD3vBWM/y4CGz4P0hSG/KQo0QOgJ9lmGpMarIkK/N1lHT4zlfdI0HbK53ijacDmILHo + qC7+IsY3zm7DIRe1hQZD91CmzaxYA5A7rkIzQc/QxvY7PqNDejKruNfD1lZa0/iNmMvKYy2Q + JNo7jqE7LrNDf7x3bkDsdfqqFlMWE9yfdySIdiwTbmQMYTp0wFUTDjupRlKEWMzlAtQN2Qm3 + X/PboR4cJWmoTD0DaeCagn11fdRqdc7AzQRafub7AQwAn+7BgmzJgzuRMiACRi7o+FSuSy9Z + u5xeb3zNJHFWwmKASSVqKnC4Lht11mSmBI4eD5MCWxJddMU81qgeOIdmntATk1qZZn3Be7de + /szht03mH4xoim9YhNCFZMhqe2qpNg+/Z99Yh8Jt+Lk/7dXMGhP3ijcJGAO4GIFOGZ+WQvk6 + hXmbDeqQJSEUkCrbv2Gb/C1Ksu8jK7ykTTpv/28jhDX1wi73AzY+f4DiWx/cXusegL/6OU3L + QSJSKkL3sufxv/SUdpJbbPPHSP8wo9uoTAS8zr4wrRXEQ+5nz03c4iHfMxZz2u+VLXWekZbc + KfGLzexYmwrfEsoUbosPkFrxD+1vCMCcn+gkgYe/pTaTjxmSuBWgBw3GkGJ6UVnmlld0rIqI + +/xGNLEtz/KJzQ12pSfWFg1NwqngRheIIwEU9DW7uxMbptxFSsMj/ppx4HXVRkRQp1kaFAj/ + PHEjUwShzx2KtHhAuEpS6RFRiHsTG42XejkqdKtZazYQeMCbAzlnABEBAAHCwn4EGAEIAagF + Alp+5vsCGwzA3SAEGQEIAAYFAlp+5vsACgkQqYflZ/iHxiKp8Qv+JEnSf7jGHRT4ZC+BEiTI + gT47LGM2Gsmv8KatJCoNQpfbiVgERSVP2SrBdonH8U0nFlcUIKOWrEynSLVhIadH8Kgl/lfC + l9olihRafobiZhwQHXvBjba4MPEgKDDb+LDYtzAUN4P3oCi7XtXc8jOIuqX782bx4d2O3PwV + v1DSQF70oJzwIl14TcE917/rvXpm0XUIuo6C4mTmMb1lpnmDyesYgwiPDW00ctObwdlES8qY + Yc+cg9RxwFJp0jGTmLk/cvt3HbIyte5a81PjCoYN6DgShzbu+xSEnd4z3aJtXf/EWzfSDryt + rd50sgDkR/RyCAv2bEWdNyhl3wdWZnQNscg4xsdqKWCP+QUtVtvYoDsRDDGahfl2zWb9IIuk + ButfaGc9vzOu3QMUzWmy1q/9qUyR6MC9Vu4BNfH47VLVlFDq92NFs4VW8UfAjcH3iVe57wzK + E14w+/4m9GqMywbmUSfEXvVvpTDNY/CgNQ2LF3Oa5Mib4u+mR0GXvI4eqbG7AAoJEE272pm0 + 1/0o5LAL/1Ra5es9ol1b4dw9cYZfPSsh4vF+zhHjwHroSt+VOjOpHkS5hj7dlMPQGsGTNKYD + F4Fvx9HpiiOcD1spAn4O7OS5nVQJL/nN36fjGaL9ZhcB6uPFIbwvlNh/QIjeAUwHRgaAiKjW + WyQ65nGHND+UfE9ny019jwuu0XJPHiY0rOEhUzXHRPP4K/sjqezk2sj9CFArootOcQb/obqK + ZfNx/9T78wOJ1cIe7GiPFJaOAknhMobrt6JwVON61EfolM3/jgzJVa8w4RyITkF3Kjpl3+ot + Q1L6n2BoJA1wH7/lCzFhHbyVNX9prSQ2CyhK2bQN+MUfd5cKTgK3YBPrbCZ4fDeL0zWLTWaN + PUGqnJ3Q4N73NoT8RNFru90P0HAgYPOMEphFh1T36OPCg7zIYuR1+eFu4mzpNirOU1MAYeVQ + cw1lQm55YnkGHnrDrikMLOk2ZqmWGw+8k96Xvsx7TrnrnPSa4uf/DbBo6Sd0xordGbSBeEJC + FRdV+uRcABCD6OuDTg== +Message-ID: <310eef89-5be5-6018-3ded-a9cda76a0342@enzevalos.de> +Date: Wed, 31 Oct 2018 12:15:17 +0100 +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:52.0) + Gecko/20100101 Thunderbird/52.9.1 +MIME-Version: 1.0 +Content-Type: multipart/signed; micalg=pgp-sha512; + protocol="application/pgp-signature"; + boundary="jGY9eHsM08PgfVXXPT2f3AZCPJW4IwZj4" + +This is an OpenPGP/MIME signed message (RFC 4880 and 3156) +--jGY9eHsM08PgfVXXPT2f3AZCPJW4IwZj4 +Content-Type: multipart/mixed; boundary="dibSubdyFVMsrRSzHsR83Pehjj4u2PlX3"; + protected-headers="v1" +From: alice <alice@enzevalos.de> +To: Bob <bob@enzevalos.de> +Message-ID: <310eef89-5be5-6018-3ded-a9cda76a0342@enzevalos.de> +Subject: signed from Thunderbird + +--dibSubdyFVMsrRSzHsR83Pehjj4u2PlX3 +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: quoted-printable +Content-Language: en-US + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque dapibus +id diam ac volutpat. Sed quis cursus ante. Vestibulum eget gravida +felis. Nullam accumsan diam quis sem ornare lacinia. Aenean risus risus, +maximus quis faucibus et, maximus at nunc. Duis pharetra augue libero, +et congue diam varius eget. Nullam efficitur ex purus, non accumsan +tellus laoreet hendrerit. Suspendisse gravida interdum eros, eu +venenatis ante suscipit nec. Class aptent taciti sociosqu ad litora +torquent per conubia nostra, per inceptos himenaeos. Praesent +pellentesque cursus sem, non ornare nunc commodo vel. Praesent sed magna +at ligula ultricies sagittis malesuada non est. Nam maximus varius +mauris. Etiam dignissim congue ligula eu porta. Nunc rutrum nisl id +mauris efficitur ultrices. Maecenas sit amet velit ac mauris consequat +sagittis at et lorem. + + + +--dibSubdyFVMsrRSzHsR83Pehjj4u2PlX3-- + +--jGY9eHsM08PgfVXXPT2f3AZCPJW4IwZj4 +Content-Type: application/pgp-signature; name="signature.asc" +Content-Description: OpenPGP digital signature +Content-Disposition: attachment; filename="signature.asc" + +-----BEGIN PGP SIGNATURE----- + +iQGzBAEBCgAdFiEEJRxNIIPfYdSrprTDTbvambTX/SgFAlvZjsUACgkQTbvambTX +/Sj26gv/VN0k/cDybI5RUU/qCIxcivOy3qM/9AauHjQQ/RJWlBAsVy/JU04xS+Qi +DdLmXP9LJa8np5T9B/rVJZrVbv5FjidsY6UsPbcqRcTZGe/X8ikscpRqUlYqkeAI +F4u2tKQiSaxbB4J9Mj4WindG3y3kcRUoTizFv7I7Zl6rLc2WVayLwFaA79pDv3M9 +NEgwv5i7gE48dppEJLUBeXtpK00N5/BxJ0w7L0hirQZFo7FMTkDgCbYA+9seDfS4 +lx4aHYjB+BUsV1n7dO6bdumnutP3eK1awk2Yyq4EJHizLNd/SsWVltOxukRqrUAp +qFlwclAEOxlWs0uLckMU6jZnhk4nUC8S20MLznNN4ASBjdo4mRIZFHIq9X8qLikl +uUvxM1Tj3+Vx/6JvHI3kxrq68QARkvTKOMOcLnPUOlQgEvUe9JZvJfSdm2xhqVa+ +vBWUTsso1k+G40NdpH72SlTxFdIOlg5GX4MVVXzDyt+t2z+PVZFOPhMyp25h7efS +JPEF5Jke +=SZPp +-----END PGP SIGNATURE----- + +--jGY9eHsM08PgfVXXPT2f3AZCPJW4IwZj4--