diff --git a/enzevalos_iphone.xcodeproj/project.pbxproj b/enzevalos_iphone.xcodeproj/project.pbxproj index 011d9e925c5e7af7bfe7267b1abccdb96990ecd1..77e691c65a0fe38f6dd3cfb979976a91a2544c04 100644 --- a/enzevalos_iphone.xcodeproj/project.pbxproj +++ b/enzevalos_iphone.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 37FE84A92028C40E001B7230 /* AuthStateDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 37FE84A82028C40E001B7230 /* AuthStateDelegate.m */; }; 3E048C051FAC9ABD00948524 /* HockeySDK.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E048C041FAC9ABD00948524 /* HockeySDK.swift */; }; 3E048C061FAC9ABD00948524 /* HockeySDK.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E048C041FAC9ABD00948524 /* HockeySDK.swift */; }; 3E6B07DE2011246500E49609 /* invitationText.html in Resources */ = {isa = PBXBuildFile; fileRef = 3E6B07DD2011246500E49609 /* invitationText.html */; }; @@ -19,7 +20,6 @@ 3E9708B81FAC95F5005825C9 /* PGPKeyID.m in Sources */ = {isa = PBXBuildFile; fileRef = 471BC8E71F960B7C00D64416 /* PGPKeyID.m */; }; 3E9708B91FAC95F5005825C9 /* NSData+compression.m in Sources */ = {isa = PBXBuildFile; fileRef = 471BC8FE1F960B7C00D64416 /* NSData+compression.m */; }; 3E9708BA1FAC95F5005825C9 /* TextFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1C3270D1DB907D900CE2ED5 /* TextFormatter.swift */; }; - 3E9708BB1FAC95F5005825C9 /* Providers.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1F2A5681E85586300320275 /* Providers.swift */; }; 3E9708BC1FAC95F5005825C9 /* PGPSymmetricallyEncryptedDataPacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 471BC8C81F960B7C00D64416 /* PGPSymmetricallyEncryptedDataPacket.m */; }; 3E9708BD1FAC95F5005825C9 /* ListViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F12041FC1DA409A5002E4940 /* ListViewCell.swift */; }; 3E9708BE1FAC95F5005825C9 /* PGPUser.m in Sources */ = {isa = PBXBuildFile; fileRef = 471BC8FB1F960B7C00D64416 /* PGPUser.m */; }; @@ -323,7 +323,6 @@ A135269C1D955BE000D3BFE1 /* enzevalos_iphoneUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A135269B1D955BE000D3BFE1 /* enzevalos_iphoneUITests.swift */; }; A16BA2121E0439B6005E29E3 /* providers.json in Resources */ = {isa = PBXBuildFile; fileRef = A16BA2111E0439B6005E29E3 /* providers.json */; }; A17A18F91DDCCF370058D934 /* JakobBode.asc in Resources */ = {isa = PBXBuildFile; fileRef = A17A18F81DDCCF370058D934 /* JakobBode.asc */; }; - A17FDFF3202C685800F7BA89 /* StudySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = A17FDFF2202C685800F7BA89 /* StudySettings.swift */; }; A18E7D771FBDE5D9002F7CC9 /* LoggingEventType.swift in Sources */ = {isa = PBXBuildFile; fileRef = A18E7D761FBDE5D9002F7CC9 /* LoggingEventType.swift */; }; A19C12471DE602FF007F72E7 /* jabo.asc in Resources */ = {isa = PBXBuildFile; fileRef = A19C12461DE602FF007F72E7 /* jabo.asc */; }; A1A9DE731F864B0500B808AA /* ExportCells.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1A9DE721F864B0500B808AA /* ExportCells.swift */; }; @@ -356,7 +355,6 @@ A1EB05A01D95696C008659C1 /* MessageBodyTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1EB059F1D95696C008659C1 /* MessageBodyTableViewCell.swift */; }; A1EB05A41D956E32008659C1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A1EB05A31D956E32008659C1 /* Assets.xcassets */; }; A1ECE54B1EFBE7ED0009349F /* FolderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1ECE54A1EFBE7ED0009349F /* FolderCell.swift */; }; - A1F2A5691E85586300320275 /* Providers.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1F2A5681E85586300320275 /* Providers.swift */; }; A1F992291DA7C9100073BF1B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A1F9922B1DA7C9100073BF1B /* Main.storyboard */; }; A1F992391DA7DD2E0073BF1B /* InboxTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = A1F9923B1DA7DD2E0073BF1B /* InboxTableViewCell.xib */; }; A1FA3F6C1E78565B0093C0B6 /* alice2005-public.gpg in Resources */ = {isa = PBXBuildFile; fileRef = A1FA3F6B1E78565B0093C0B6 /* alice2005-public.gpg */; }; @@ -375,6 +373,9 @@ F14D189F1ED880680080515D /* ncpayroll-public.gpg in Resources */ = {isa = PBXBuildFile; fileRef = F14D189B1ED880680080515D /* ncpayroll-public.gpg */; }; F14D18A21ED8811F0080515D /* ullimuelle-private.gpg in Resources */ = {isa = PBXBuildFile; fileRef = F14D18A01ED8811F0080515D /* ullimuelle-private.gpg */; }; F14D18A31ED8811F0080515D /* ullimuelle-public.gpg in Resources */ = {isa = PBXBuildFile; fileRef = F14D18A11ED8811F0080515D /* ullimuelle-public.gpg */; }; + F1737ACB2031D7D70000312B /* StudySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = A17FDFF2202C685800F7BA89 /* StudySettings.swift */; }; + F1866C86201F707200B72453 /* EmailHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = F1866C85201F707200B72453 /* EmailHelper.m */; }; + F1866CAB2023668F00B72453 /* GTMAppAuthDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1866CAA2023668F00B72453 /* GTMAppAuthDelegate.swift */; }; F189C17F1ED59FEF00BAE9B3 /* idsolutions-private.gpg in Resources */ = {isa = PBXBuildFile; fileRef = F189C17D1ED59FEF00BAE9B3 /* idsolutions-private.gpg */; }; F189C1801ED59FEF00BAE9B3 /* idsolutions-public.gpg in Resources */ = {isa = PBXBuildFile; fileRef = F189C17E1ED59FEF00BAE9B3 /* idsolutions-public.gpg */; }; F18B445E1E7044B70080C041 /* FlipTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = F18B445D1E7044B70080C041 /* FlipTransition.swift */; }; @@ -410,6 +411,8 @@ /* Begin PBXFileReference section */ 1D4A9E60565DECF52C011BC0 /* Pods-enzevalos_iphone-AdHoc.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-enzevalos_iphone-AdHoc.release.xcconfig"; path = "../enzevalos_iphone_workspace/Pods/Target Support Files/Pods-enzevalos_iphone-AdHoc/Pods-enzevalos_iphone-AdHoc.release.xcconfig"; sourceTree = "<group>"; }; + 37FE84A82028C40E001B7230 /* AuthStateDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AuthStateDelegate.m; sourceTree = "<group>"; }; + 37FE84AA2028CA63001B7230 /* AuthStateDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AuthStateDelegate.h; sourceTree = "<group>"; }; 3E048C041FAC9ABD00948524 /* HockeySDK.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HockeySDK.swift; sourceTree = "<group>"; }; 3E6B07DD2011246500E49609 /* invitationText.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = invitationText.html; path = Invitation/invitationText.html; sourceTree = "<group>"; }; 3E9708AD1FAC925D005825C9 /* enzevalos_iphone.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = enzevalos_iphone.entitlements; sourceTree = "<group>"; }; @@ -667,7 +670,6 @@ A1EB059F1D95696C008659C1 /* MessageBodyTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageBodyTableViewCell.swift; sourceTree = "<group>"; }; A1EB05A31D956E32008659C1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; A1ECE54A1EFBE7ED0009349F /* FolderCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FolderCell.swift; sourceTree = "<group>"; }; - A1F2A5681E85586300320275 /* Providers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Providers.swift; sourceTree = "<group>"; }; A1F992301DA7D22D0073BF1B /* de */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = de; path = de.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; A1F992321DA7D2360073BF1B /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; A1F992341DA7DA570073BF1B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; }; @@ -696,6 +698,9 @@ F14D189B1ED880680080515D /* ncpayroll-public.gpg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = "ncpayroll-public.gpg"; path = "keys/ncpayroll-public.gpg"; sourceTree = "<group>"; }; F14D18A01ED8811F0080515D /* ullimuelle-private.gpg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = "ullimuelle-private.gpg"; path = "keys/ullimuelle-private.gpg"; sourceTree = "<group>"; }; F14D18A11ED8811F0080515D /* ullimuelle-public.gpg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = "ullimuelle-public.gpg"; path = "keys/ullimuelle-public.gpg"; sourceTree = "<group>"; }; + F1866C85201F707200B72453 /* EmailHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EmailHelper.m; sourceTree = "<group>"; }; + F1866C87201F70B700B72453 /* EmailHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EmailHelper.h; sourceTree = "<group>"; }; + F1866CAA2023668F00B72453 /* GTMAppAuthDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GTMAppAuthDelegate.swift; sourceTree = "<group>"; }; F189C17D1ED59FEF00BAE9B3 /* idsolutions-private.gpg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = "idsolutions-private.gpg"; path = "keys/idsolutions-private.gpg"; sourceTree = "<group>"; }; F189C17E1ED59FEF00BAE9B3 /* idsolutions-public.gpg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = "idsolutions-public.gpg"; path = "keys/idsolutions-public.gpg"; sourceTree = "<group>"; }; F18B445D1E7044B70080C041 /* FlipTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlipTransition.swift; sourceTree = "<group>"; }; @@ -1146,6 +1151,7 @@ A13526771D955BDF00D3BFE1 /* enzevalos_iphone */ = { isa = PBXGroup; children = ( + F1866C84201F703200B72453 /* OAuth */, 3EB4FA9C2012007C001D0625 /* Dialog */, 3EC35F1F2003755F008BDF95 /* Invitation */, F1C733331FEC1CAC005A497E /* About */, @@ -1222,7 +1228,6 @@ A18C76851E8185ED00B21414 /* onboarding */ = { isa = PBXGroup; children = ( - A1F2A5681E85586300320275 /* Providers.swift */, A1083A531E8BFEA6003666B7 /* Onboarding.swift */, A102AA891EDDB4E80024B457 /* videoOnboarding2.m4v */, A1C62E992018F716000E5273 /* OnboardingValueState.swift */, @@ -1334,6 +1339,18 @@ name = inbox; sourceTree = "<group>"; }; + F1866C84201F703200B72453 /* OAuth */ = { + isa = PBXGroup; + children = ( + F1866C85201F707200B72453 /* EmailHelper.m */, + F1866C87201F70B700B72453 /* EmailHelper.h */, + F1866CAA2023668F00B72453 /* GTMAppAuthDelegate.swift */, + 37FE84AA2028CA63001B7230 /* AuthStateDelegate.h */, + 37FE84A82028C40E001B7230 /* AuthStateDelegate.m */, + ); + path = OAuth; + sourceTree = "<group>"; + }; F1ACF21D1E0C290500C1B843 /* contactView */ = { isa = PBXGroup; children = ( @@ -1628,16 +1645,22 @@ ); inputPaths = ( "${SRCROOT}/../enzevalos_iphone_workspace/Pods/Target Support Files/Pods-enzevalos_iphone/Pods-enzevalos_iphone-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/AppAuth/AppAuth.framework", "${BUILT_PRODUCTS_DIR}/BZipCompression/BZipCompression.framework", "${BUILT_PRODUCTS_DIR}/FrameAccessor/FrameAccessor.framework", + "${BUILT_PRODUCTS_DIR}/GTMAppAuth/GTMAppAuth.framework", + "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework", "${BUILT_PRODUCTS_DIR}/KeychainAccess/KeychainAccess.framework", "${BUILT_PRODUCTS_DIR}/Onboard/Onboard.framework", "${BUILT_PRODUCTS_DIR}/VENTokenField/VENTokenField.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AppAuth.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BZipCompression.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FrameAccessor.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMAppAuth.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/KeychainAccess.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Onboard.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/VENTokenField.framework", @@ -1716,11 +1739,11 @@ ); inputPaths = ( "${SRCROOT}/../enzevalos_iphone_workspace/Pods/Target Support Files/Pods-enzevalos_iphone/Pods-enzevalos_iphone-resources.sh", - $PODS_CONFIGURATION_BUILD_DIR/HockeySDK/HockeySDKResources.bundle, + "${PODS_CONFIGURATION_BUILD_DIR}/HockeySDK/HockeySDKResources.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/HockeySDKResources.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -1770,11 +1793,11 @@ ); inputPaths = ( "${SRCROOT}/../enzevalos_iphone_workspace/Pods/Target Support Files/Pods-enzevalos_iphone-AdHoc/Pods-enzevalos_iphone-AdHoc-resources.sh", - $PODS_CONFIGURATION_BUILD_DIR/HockeySDK/HockeySDKResources.bundle, + "${PODS_CONFIGURATION_BUILD_DIR}/HockeySDK/HockeySDKResources.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/HockeySDKResources.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -1836,16 +1859,22 @@ ); inputPaths = ( "${SRCROOT}/../enzevalos_iphone_workspace/Pods/Target Support Files/Pods-enzevalos_iphone-AdHoc/Pods-enzevalos_iphone-AdHoc-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/AppAuth/AppAuth.framework", "${BUILT_PRODUCTS_DIR}/BZipCompression/BZipCompression.framework", "${BUILT_PRODUCTS_DIR}/FrameAccessor/FrameAccessor.framework", + "${BUILT_PRODUCTS_DIR}/GTMAppAuth/GTMAppAuth.framework", + "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework", "${BUILT_PRODUCTS_DIR}/KeychainAccess/KeychainAccess.framework", "${BUILT_PRODUCTS_DIR}/Onboard/Onboard.framework", "${BUILT_PRODUCTS_DIR}/VENTokenField/VENTokenField.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AppAuth.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BZipCompression.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FrameAccessor.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMAppAuth.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/KeychainAccess.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Onboard.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/VENTokenField.framework", @@ -1871,7 +1900,6 @@ 3E9708B81FAC95F5005825C9 /* PGPKeyID.m in Sources */, 3E9708B91FAC95F5005825C9 /* NSData+compression.m in Sources */, 3E9708BA1FAC95F5005825C9 /* TextFormatter.swift in Sources */, - 3E9708BB1FAC95F5005825C9 /* Providers.swift in Sources */, 3E9708BC1FAC95F5005825C9 /* PGPSymmetricallyEncryptedDataPacket.m in Sources */, 3E9708BD1FAC95F5005825C9 /* ListViewCell.swift in Sources */, 3E9708BE1FAC95F5005825C9 /* PGPUser.m in Sources */, @@ -2018,7 +2046,6 @@ 471BC9281F960B7C00D64416 /* PGPKeyID.m in Sources */, 471BC9311F960B7C00D64416 /* NSData+compression.m in Sources */, A1C3270E1DB907D900CE2ED5 /* TextFormatter.swift in Sources */, - A1F2A5691E85586300320275 /* Providers.swift in Sources */, 471BC91A1F960B7C00D64416 /* PGPSymmetricallyEncryptedDataPacket.m in Sources */, F12041FD1DA409A5002E4940 /* ListViewCell.swift in Sources */, 471BC9301F960B7C00D64416 /* PGPUser.m in Sources */, @@ -2047,6 +2074,7 @@ 471BC9131F960B7C00D64416 /* PGPPublicSubKeyPacket.m in Sources */, F1984D721E1D327200804E1E /* IconsStyleKit.swift in Sources */, 471BC9261F960B7C00D64416 /* PGPKey.m in Sources */, + F1737ACB2031D7D70000312B /* StudySettings.swift in Sources */, 8428A8691F436A11007649A5 /* UserNameGamificationTableViewCell.swift in Sources */, A114E4321FACB23000E40243 /* StringExtension.swift in Sources */, 472F398C1E2519C8009260FB /* CNContactExtension.swift in Sources */, @@ -2074,7 +2102,7 @@ 8428A8711F436A1E007649A5 /* GamificationStatusViewController.swift in Sources */, 471BC90B1F960B7C00D64416 /* ObjectivePGPObject.m in Sources */, 471BC9241F960B7C00D64416 /* PGPFingerprint.m in Sources */, - A17FDFF3202C685800F7BA89 /* StudySettings.swift in Sources */, + F1866C86201F707200B72453 /* EmailHelper.m in Sources */, 471BC9221F960B7C00D64416 /* PGPBigNum.m in Sources */, A10DE4201EFAA2CE005E8189 /* FolderViewController.swift in Sources */, 473AC39720054D29006EB8A6 /* NSArray+PGPUtils.m in Sources */, @@ -2101,6 +2129,7 @@ A1EB05A01D95696C008659C1 /* MessageBodyTableViewCell.swift in Sources */, F18B44621E73286C0080C041 /* ReadVENDelegate.swift in Sources */, 471BC91E1F960B7C00D64416 /* PGPUserAttributePacket.m in Sources */, + F1866CAB2023668F00B72453 /* GTMAppAuthDelegate.swift in Sources */, 475B00421F7BB6D6006CDD41 /* PersistentKey+CoreDataClass.swift in Sources */, 471BC9161F960B7C00D64416 /* PGPSignaturePacket.m in Sources */, 3EC35F2420037651008BDF95 /* InvitationHelper.swift in Sources */, @@ -2114,6 +2143,7 @@ 8428A85E1F436A05007649A5 /* CircleView.swift in Sources */, F1C7AC821FED6473007629DB /* AboutViewController.swift in Sources */, 472F397C1E1D0B0B009260FB /* PersistentMail +CoreDataProperties.swift in Sources */, + 37FE84A92028C40E001B7230 /* AuthStateDelegate.m in Sources */, 8428A85C1F436A05007649A5 /* ArrowView.swift in Sources */, A1EB05961D956939008659C1 /* InboxTableViewCell.swift in Sources */, A1083A541E8BFEA6003666B7 /* Onboarding.swift in Sources */, @@ -2462,6 +2492,7 @@ CODE_SIGN_ENTITLEMENTS = enzevalos_iphone/PLists/enzevalos_iphone.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEFINES_MODULE = NO; DEVELOPMENT_TEAM = VJ9C93G68Y; GCC_SYMBOLS_PRIVATE_EXTERN = NO; INFOPLIST_FILE = "enzevalos_iphone/PLists/enzevalos-Info.plist"; @@ -2514,6 +2545,7 @@ CODE_SIGN_ENTITLEMENTS = enzevalos_iphone/PLists/enzevalos_iphone.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEFINES_MODULE = NO; DEVELOPMENT_TEAM = VJ9C93G68Y; GCC_SYMBOLS_PRIVATE_EXTERN = NO; INFOPLIST_FILE = "enzevalos_iphone/PLists/enzevalos-Info.plist"; diff --git a/enzevalos_iphone/AppDelegate.swift b/enzevalos_iphone/AppDelegate.swift index 95d509fe4211d23d92c0b440c068ac92d8626e82..7bf264b13864a083053ce502d3e0d8a2591b63aa 100644 --- a/enzevalos_iphone/AppDelegate.swift +++ b/enzevalos_iphone/AppDelegate.swift @@ -12,6 +12,7 @@ import CoreData import Onboard import SystemConfiguration +import GTMAppAuth @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { @@ -66,16 +67,56 @@ class AppDelegate: UIResponder, UIApplicationDelegate { return self.orientationLock } + func application(_ application: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool { + if url.absoluteURL.absoluteString.hasPrefix("com.googleusercontent.apps.459157836079-csn0a9p3r8p7q6216fn5u7a6vcum80gn") { + if let currentAuthorizationFlow = EmailHelper.singleton().currentAuthorizationFlow { + if currentAuthorizationFlow.resumeAuthorizationFlow(with: url) { + EmailHelper.singleton().currentAuthorizationFlow = nil + return true + } + } + } + + return false + } + + func googleLogin(vc: UIViewController) { + if (Onboarding.mailaddress.text?.lowercased() ?? "").contains("gmail") || (Onboarding.mailaddress.text?.lowercased() ?? "").contains("google") { + 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() + return + } + UserManager.storeUserValue(userEmail as AnyObject, attribute: Attribute.userName) + UserManager.storeUserValue(userEmail as AnyObject, attribute: Attribute.userAddr) + UserManager.storeUserValue("imap.gmail.com" as AnyObject, attribute: Attribute.imapHostname) + UserManager.storeUserValue(993 as AnyObject, attribute: Attribute.imapPort) + UserManager.storeUserValue(MCOConnectionType.TLS.rawValue as AnyObject, attribute: Attribute.imapConnectionType) + UserManager.storeUserValue(MCOAuthType.xoAuth2.rawValue as AnyObject, attribute: Attribute.imapAuthType) + UserManager.storeUserValue("smtp.gmail.com" as AnyObject, attribute: Attribute.smtpHostname) + UserManager.storeUserValue(587 as AnyObject, attribute: Attribute.smtpPort) + 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) + }) + } + } + func credentialCheck() { self.window?.rootViewController = Onboarding.checkConfigView() - if Onboarding.setValues() != OnboardingValueState.fine { - credentialsFailed() + if Onboarding.googleAuth { + Onboarding.googleAuth = false + googleLogin(vc: self.window!.rootViewController!) return } - else if !Onboarding.checkConfig(self.credentialsFailed, work: self.credentialsWork) { - self.window?.rootViewController = Onboarding.detailOnboarding(self.credentialCheck) + if Onboarding.setValues() != OnboardingValueState.fine { + credentialsFailed() return } + + Onboarding.checkConfig(self.credentialsFailed, work: self.credentialsWork) } func credentialsFailed() { @@ -110,13 +151,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate { // Option removed from Settings app, but this might still be usefull in the future func resetApp() { +// TODO: remove after testing +// GTMKeychain.removePasswordFromKeychain(forName: "googleOAuthCodingKey") + if UserDefaults.standard.bool(forKey: "reset") { DataHandler.handler.reset() Onboarding.credentials = nil Onboarding.credentialFails = 0 Onboarding.manualSet = false UserManager.resetUserValues() - self.window = UIWindow(frame: UIScreen.main.bounds) //self.window?.rootViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("onboarding") diff --git a/enzevalos_iphone/MailHandler.swift b/enzevalos_iphone/MailHandler.swift index 6905a767cb91abe146d95beb673f9c92166fe1d1..bbfe9bb321992f4e3de94ae6d2d46eddc81c61e6 100644 --- a/enzevalos_iphone/MailHandler.swift +++ b/enzevalos_iphone/MailHandler.swift @@ -155,6 +155,13 @@ class MailHandler { var IMAPIdleSession: MCOIMAPSession? var IMAPIdleSupported: Bool? + + var shouldTryRefreshOAUTH: Bool { + get { + return (UserManager.loadImapAuthType() == MCOAuthType.xoAuth2 || UserManager.loadSmtpAuthType() == MCOAuthType.xoAuth2) && + !(EmailHelper.singleton().authorization?.authState.isTokenFresh() ?? false) + } + } func addAutocryptHeader(_ builder: MCOMessageBuilder) { let adr = (UserManager.loadUserValue(Attribute.userAddr) as! String).lowercased() @@ -251,7 +258,16 @@ class MailHandler { builder.addAttachment(keyAttachment) let sendOperation = session.sendOperation(with: builder.data() , from: userID, recipients: [userID]) - sendOperation?.start(callback) + sendOperation?.start({ error in + guard error == nil else { + self.retryWithRefreshedOAuth { + self.sendSecretKey(key: key, passcode: passcode, callback: callback) + } + return + } + + callback(nil) + }) //createSendCopy(sendData: builder.openPGPEncryptedMessageData(withEncryptedData: keyData)) } @@ -389,6 +405,7 @@ class MailHandler { } } + // TODO: add OAuth refresh fileprivate func createSendCopy(sendData: Data) { let sentFolder = UserManager.backendSentFolderPath if !DataHandler.handler.existsFolder(with: sentFolder) { @@ -404,6 +421,7 @@ class MailHandler { } } + // TODO: add OAuth refresh fileprivate func createLoggingSendCopy(sendData: Data) { let sentFolder = UserManager.loadUserValue(.loggingFolderPath) as! String if !DataHandler.handler.existsFolder(with: sentFolder) { @@ -526,24 +544,24 @@ class MailHandler { if let username = UserManager.loadUserValue(Attribute.userAddr) as? String{ imapsession.username = username } - if let pw = UserManager.loadUserValue(Attribute.userPW) as? String{ - imapsession.password = pw - } //TODO: ERROR HANDLING! imapsession.authType = UserManager.loadImapAuthType() + if UserManager.loadImapAuthType() == MCOAuthType.xoAuth2 { + imapsession.oAuth2Token = EmailHelper.singleton().authorization?.authState.lastTokenResponse?.accessToken + } else if let pw = UserManager.loadUserValue(Attribute.userPW) as? String { + imapsession.password = pw + } + if let connType = UserManager.loadUserValue(Attribute.imapConnectionType) as? Int{ imapsession.connectionType = MCOConnectionType(rawValue: connType) } - - let y = imapsession.folderStatusOperation(INBOX) - y?.start{(error, status) -> Void in - // TODO: UIDValality check here! - let uidValidity = status?.uidValidity - let nextId = status?.uidNext - let unseencount = status?.unseenCount - - } + + //TODO @Olli: was this for debug purposes or is there a use for this in production +// let y = imapsession.folderStatusOperation(INBOX) +// y?.start{(error, status) -> Void in +// print("Folder status: \(status.debugDescription)") +// } return imapsession } @@ -555,6 +573,11 @@ class MailHandler { let op = IMAPIdleSession!.idleOperation(withFolder: INBOX, lastKnownUID: UInt32(DataHandler.handler.findFolder(with: INBOX).maxID)) op?.start({ error in guard error == nil else { + if self.shouldTryRefreshOAUTH { + self.retryWithRefreshedOAuth { + self.startIMAPIdleIfSupported(addNewMail: addNewMail) + } + } print("An error occured with the idle operation: \(String(describing: error))") return } @@ -573,6 +596,12 @@ class MailHandler { let op = setupIMAPSession().capabilityOperation() op?.start({ (error, capabilities) in guard error == nil else { + if self.shouldTryRefreshOAUTH { + self.retryWithRefreshedOAuth { + self.checkIdleSupport(addNewMail: addNewMail) + } + return + } print("Error checking IMAP Idle capabilities: \(String(describing: error))") return } @@ -586,15 +615,23 @@ class MailHandler { fileprivate func createSMTPSession() -> MCOSMTPSession { let session = MCOSMTPSession() + session.authType = UserManager.loadSmtpAuthType() + if UserManager.loadSmtpAuthType() == MCOAuthType.xoAuth2 { + if let lastToken = EmailHelper.singleton().authorization?.authState.lastTokenResponse { + session.oAuth2Token = lastToken.accessToken + } + } else { + session.password = UserManager.loadUserValue(Attribute.userPW) as! String + } 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.password = UserManager.loadUserValue(Attribute.userPW) as! String session.authType = UserManager.loadSmtpAuthType() session.connectionType = MCOConnectionType(rawValue: UserManager.loadUserValue(Attribute.smtpConnectionType) as! Int) return session } + // TODO: add OAuth refresh func addFlag(_ uid: UInt64, flags: MCOMessageFlag, folder: String?) { var folderName = INBOX if let folder = folder{ @@ -625,7 +662,13 @@ class MailHandler { op?.start { error -> Void in if let err = error { - print("Error while updating flags: \(err)") + if self.shouldTryRefreshOAUTH { + self.retryWithRefreshedOAuth { + self.removeFlag(uid, flags: flags, folder: folder) + } + } else { + print("Error while updating flags: \(err)") + } } } } @@ -643,6 +686,12 @@ class MailHandler { searchOperation.start { (err, indices) -> Void in guard err == nil else { + if self.shouldTryRefreshOAUTH { + self.retryWithRefreshedOAuth { + self.loadMailsForRecord(record, folderPath: folderPath, newMailCallback: newMailCallback, completionCallback: completionCallback) + } + return + } completionCallback(true) return } @@ -679,6 +728,12 @@ class MailHandler { } fetchOperation.start { (err, msg, vanished) -> Void in guard err == nil else { + if self.shouldTryRefreshOAUTH { + self.retryWithRefreshedOAuth { + self.loadMessagesFromServer(uids, folderPath: folderPath, maxLoad: maxLoad, record: record, newMailCallback: newMailCallback, completionCallback: completionCallback) + } + return + } print("Error while fetching inbox: \(String(describing: err))") completionCallback(true) return @@ -952,7 +1007,11 @@ class MailHandler { session.hostname = UserManager.loadUserValue(Attribute.smtpHostname) as! String session.port = UInt32(UserManager.loadUserValue(Attribute.smtpPort) as! Int) session.username = username - session.password = UserManager.loadUserValue(Attribute.userPW) as! String + if UserManager.loadSmtpAuthType() == 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) @@ -1096,6 +1155,12 @@ class MailHandler { searchOperation?.start{(err, uids)-> Void in guard err == nil else{ + if self.shouldTryRefreshOAUTH { + self.retryWithRefreshedOAuth { + self.loadMailsSinceDate(folder: folder, since: since, newMailCallback: newMailCallback, completionCallback: completionCallback) + } + return + } completionCallback(true) return } @@ -1109,4 +1174,18 @@ class MailHandler { } } + + func retryWithRefreshedOAuth(completion: @escaping () -> ()) { + guard shouldTryRefreshOAUTH else { + print("Please only call retryWithRefreshedOAuth after checking shouldTryRefreshOAUTH or your request might be lost.") + return + } + + EmailHelper.singleton().checkIfAuthorizationIsValid({authorized in + if authorized { + self.IMAPSes = nil + } + completion() + }) + } } diff --git a/enzevalos_iphone/OAuth/AuthStateDelegate.h b/enzevalos_iphone/OAuth/AuthStateDelegate.h new file mode 100644 index 0000000000000000000000000000000000000000..30abd0d430655f3c649f91663d72a4655ece1b08 --- /dev/null +++ b/enzevalos_iphone/OAuth/AuthStateDelegate.h @@ -0,0 +1,17 @@ +// +// AuthStateDelegate.h +// enzevalos_iphone +// +// Created by joscha1 on 05.02.18. +// Copyright © 2018 fu-berlin. All rights reserved. +// + +#ifndef AuthStateDelegate_h +#define AuthStateDelegate_h + +@interface AuthStateDelegate : NSObject <OIDAuthStateChangeDelegate, OIDAuthStateErrorDelegate> { + +} +@end + +#endif /* AuthStateDelegate_h */ diff --git a/enzevalos_iphone/OAuth/AuthStateDelegate.m b/enzevalos_iphone/OAuth/AuthStateDelegate.m new file mode 100644 index 0000000000000000000000000000000000000000..9462e87cdd7274341c7220224ab629373f78f708 --- /dev/null +++ b/enzevalos_iphone/OAuth/AuthStateDelegate.m @@ -0,0 +1,35 @@ +// +// AuthStateDelegate.m +// enzevalos_iphone +// +// Created by joscha1 on 05.02.18. +// Copyright © 2018 fu-berlin. All rights reserved. +// + +#import <Foundation/Foundation.h> +#import <AppAuth/AppAuth.h> +#import "AuthStateDelegate.h" + +@implementation AuthStateDelegate + +- (id)init +{ + return [super init]; +} + +- (void)didChangeState:(OIDAuthState *)state +{ + printf("%s", state.description); +} + +- (void)authState:(OIDAuthState *)state didEncounterAuthorizationError:(NSError *)error +{ + printf("%s", error.description); +} + +- (void)authState:(OIDAuthState *)state didEncounterTransientError:(NSError *)error +{ + printf("%s", error.description); +} + +@end diff --git a/enzevalos_iphone/OAuth/EmailHelper.h b/enzevalos_iphone/OAuth/EmailHelper.h new file mode 100644 index 0000000000000000000000000000000000000000..133edca10a1e74b5204eace2efa3f7a7923b377f --- /dev/null +++ b/enzevalos_iphone/OAuth/EmailHelper.h @@ -0,0 +1,24 @@ +// +// EmailHelper.h +// enzevalos_iphone +// +// Created by Joscha on 29.01.18. +// Copyright © 2018 fu-berlin. All rights reserved. +// + +#import <Foundation/Foundation.h> +#import <MailCore/MailCore.h> +#import <AppAuth/AppAuth.h> +#import <GTMAppAuth/GTMAppAuth.h> + +@interface EmailHelper : NSObject + ++ (EmailHelper *)singleton; + +@property(nonatomic, strong, nullable) id<OIDAuthorizationFlowSession> currentAuthorizationFlow; +@property(nonatomic, nullable) GTMAppAuthFetcherAuthorization *authorization; + +- (void)doEmailLoginIfRequiredOnVC:(UIViewController*)vc completionBlock:(dispatch_block_t)completionBlock; +- (void)checkIfAuthorizationIsValid:(void (^)(BOOL authorized))completionBlock; + +@end diff --git a/enzevalos_iphone/OAuth/EmailHelper.m b/enzevalos_iphone/OAuth/EmailHelper.m new file mode 100644 index 0000000000000000000000000000000000000000..77f5563142efeaabbdaef57b15a61c3a0486b7f0 --- /dev/null +++ b/enzevalos_iphone/OAuth/EmailHelper.m @@ -0,0 +1,197 @@ +// +// EmailHelper.m +// enzevalos_iphone +// +// Created by Joscha on 29.01.18. +// Copyright © 2018 fu-berlin. All rights reserved. +// + +#import "EmailHelper.h" +#import <GTMSessionFetcher/GTMSessionFetcherService.h> +#import <GTMSessionFetcher/GTMSessionFetcher.h> +//#import "enzevalos_iphone-Swift.h" + +/*! @brief The OIDC issuer from which the configuration will be discovered. + */ +static NSString *const kIssuer = @"https://accounts.google.com"; + +/*! @brief The OAuth client ID. + @discussion For Google, register your client at + https://console.developers.google.com/apis/credentials?project=_ + The client should be registered with the "iOS" type. + */ +static NSString *const kClientID = @"459157836079-csn0a9p3r8p7q6216fn5u7a6vcum80gn.apps.googleusercontent.com"; + +/*! @brief The OAuth redirect URI for the client @c kClientID. + @discussion With Google, the scheme of the redirect URI is the reverse DNS notation of the + client ID. This scheme must be registered as a scheme in the project's Info + property list ("CFBundleURLTypes" plist key). Any path component will work, we use + 'oauthredirect' here to help disambiguate from any other use of this scheme. + */ +static NSString *const kRedirectURI = +@"com.googleusercontent.apps.459157836079-csn0a9p3r8p7q6216fn5u7a6vcum80gn:/oauthredirect"; + +/*! @brief @c NSCoding key for the authState property. You don't need to change this value. + */ +static NSString *const kExampleAuthorizerKey = @"googleOAuthCodingKey"; + +@interface EmailHelper () <OIDAuthStateChangeDelegate, + OIDAuthStateErrorDelegate> +@end + +@implementation EmailHelper + +static dispatch_once_t pred; +static EmailHelper *shared = nil; + ++ (EmailHelper *)singleton { + dispatch_once(&pred, ^{ shared = [[EmailHelper alloc] init]; }); + return shared; +} + +- (instancetype)init { + if (self = [super init]) { + [self loadState]; + } + return self; +} + +#pragma mark - + +// CALL THIS TO START +- (void)doEmailLoginIfRequiredOnVC:(UIViewController*)vc completionBlock:(dispatch_block_t)completionBlock { + // Optional: if no internet connectivity, do nothing +// AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate]; + if (true) { // TODO: we nee to check for internet conectivity here + dispatch_async(dispatch_get_main_queue(), ^{ + + // first see if we already have authorization + [self checkIfAuthorizationIsValid:^(BOOL authorized) { + NSAssert([NSThread currentThread].isMainThread, @"ERROR MAIN THREAD NEEDED"); + if (authorized) { + if (completionBlock) + completionBlock(); + } else { + [self doInitialAuthorizationWithVC:vc completionBlock:completionBlock]; + } + }]; + }); + }; +} + +/*! @brief Saves the @c GTMAppAuthFetcherAuthorization to @c NSUSerDefaults. + */ +- (void)saveState { + if (_authorization.canAuthorize) { + [GTMAppAuthFetcherAuthorization saveAuthorization:_authorization toKeychainForName:kExampleAuthorizerKey]; + } else { + NSLog(@"EmailHelper: WARNING, attempt to save a google authorization which cannot authorize, discarding"); + [GTMAppAuthFetcherAuthorization removeAuthorizationFromKeychainForName:kExampleAuthorizerKey]; + } +} + +/*! @brief Loads the @c GTMAppAuthFetcherAuthorization from @c NSUSerDefaults. + */ +- (void)loadState { + GTMAppAuthFetcherAuthorization* authorization = + [GTMAppAuthFetcherAuthorization authorizationFromKeychainForName:kExampleAuthorizerKey]; + + if (authorization.canAuthorize) { + self.authorization = authorization; + self.authorization.authState.stateChangeDelegate = self; + self.authorization.authState.errorDelegate = self; + } else { + NSLog(@"EmailHelper: WARNING, loaded google authorization cannot authorize, discarding"); + [GTMAppAuthFetcherAuthorization removeAuthorizationFromKeychainForName:kExampleAuthorizerKey]; + } + + +} + +- (void)doInitialAuthorizationWithVC:(UIViewController*)vc completionBlock:(dispatch_block_t)completionBlock { + NSURL *issuer = [NSURL URLWithString:kIssuer]; + NSURL *redirectURI = [NSURL URLWithString:kRedirectURI]; + + NSLog(@"EmailHelper: Fetching configuration for issuer: %@", issuer); + + // discovers endpoints + [OIDAuthorizationService discoverServiceConfigurationForIssuer:issuer completion:^(OIDServiceConfiguration *_Nullable configuration, NSError *_Nullable error) { + if (!configuration) { + NSLog(@"EmailHelper: Error retrieving discovery document: %@", [error localizedDescription]); + self.authorization = nil; + return; + } + + NSLog(@"EmailHelper: Got configuration: %@", configuration); + + // builds authentication request + OIDAuthorizationRequest *request = + [[OIDAuthorizationRequest alloc] initWithConfiguration:configuration + clientId:kClientID + scopes:@[OIDScopeOpenID, OIDScopeProfile, OIDScopeEmail, @"https://mail.google.com/"] + redirectURL:redirectURI + responseType:OIDResponseTypeCode + additionalParameters:nil]; + // performs authentication request + NSLog(@"EmailHelper: Initiating authorization request with scope: %@", request.scope); + self.currentAuthorizationFlow = [OIDAuthState authStateByPresentingAuthorizationRequest:request presentingViewController:vc callback:^(OIDAuthState *_Nullable authState, NSError *_Nullable error) { + if (authState) { + self.authorization = [[GTMAppAuthFetcherAuthorization alloc] initWithAuthState:authState]; + NSLog(@"EmailHelper: Got authorization tokens. Access token: %@", authState.lastTokenResponse.accessToken); + [self saveState]; + } else { + self.authorization = nil; + NSLog(@"EmailHelper: Authorization error: %@", [error localizedDescription]); + } + if (completionBlock) + dispatch_async(dispatch_get_main_queue(), completionBlock); + }]; + }]; +} + +// Performs a UserInfo request to the account to see if the token works +- (void)checkIfAuthorizationIsValid:(void (^)(BOOL authorized))completionBlock { + NSLog(@"EmailHelper: Performing userinfo request"); + + // Creates a GTMSessionFetcherService with the authorization. + // Normally you would save this service object and re-use it for all REST API calls. + GTMSessionFetcherService *fetcherService = [[GTMSessionFetcherService alloc] init]; + fetcherService.authorizer = self.authorization; + + // Creates a fetcher for the API call. + NSURL *userinfoEndpoint = [NSURL URLWithString:@"https://www.googleapis.com/oauth2/v3/userinfo"]; + GTMSessionFetcher *fetcher = [fetcherService fetcherWithURL:userinfoEndpoint]; + [fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { + // Checks for an error. + if (error) { + // OIDOAuthTokenErrorDomain indicates an issue with the authorization. + if ([error.domain isEqual:OIDOAuthTokenErrorDomain]) { + [GTMAppAuthFetcherAuthorization removeAuthorizationFromKeychainForName:kExampleAuthorizerKey]; + self.authorization = nil; + NSLog(@"EmailHelper: Authorization error during token refresh, cleared state. %@", error); + if (completionBlock) + completionBlock(NO); + } else { + // Other errors are assumed transient. + NSLog(@"EmailHelper: Transient error during token refresh. %@", error); + if (completionBlock) + completionBlock(NO); + } + return; + } + + NSLog(@"EmailHelper: authorization is valid"); + if (completionBlock) + completionBlock(YES); + }]; +} + +- (void)didChangeState:(nonnull OIDAuthState *)state { + [self saveState]; +} + +- (void)authState:(nonnull OIDAuthState *)state didEncounterAuthorizationError:(nonnull NSError *)error { + NSLog(@"Received authorization error: %@", error); +} + +@end diff --git a/enzevalos_iphone/OAuth/GTMAppAuthDelegate.swift b/enzevalos_iphone/OAuth/GTMAppAuthDelegate.swift new file mode 100644 index 0000000000000000000000000000000000000000..f5c987fa820ee735629b835b811be26a720b1ebd --- /dev/null +++ b/enzevalos_iphone/OAuth/GTMAppAuthDelegate.swift @@ -0,0 +1,19 @@ +// +// GTMAppAuthDelegate.swift +// enzevalos_iphone +// +// Created by Joscha on 01.02.18. +// Copyright © 2018 fu-berlin. All rights reserved. +// + +import Foundation + +class GTMAppAuthDelegate: NSObject, OIDAuthStateChangeDelegate, OIDAuthStateErrorDelegate { + func didChange(_ state: OIDAuthState) { + print("State: \(state)") + } + + func authState(_ state: OIDAuthState, didEncounterAuthorizationError error: Error) { + print("AuthState: \(state); Error: \(error)") + } +} diff --git a/enzevalos_iphone/Onboarding.swift b/enzevalos_iphone/Onboarding.swift index 2dc989a0b9a9eaa6417519f5659b1c127a0f25a5..28bf7100e119145c5a86fb74101d79e7a57d5d41 100644 --- a/enzevalos_iphone/Onboarding.swift +++ b/enzevalos_iphone/Onboarding.swift @@ -21,6 +21,7 @@ class Onboarding: NSObject { static var mailaddress = UITextField.init() static var username = UITextField.init() static var password = UITextField.init() + static var googleButton = UIBarButtonItem.init() static var credentials: UIView? = nil static var imapServer = UITextField.init() static var smtpServer = UITextField.init() @@ -36,6 +37,9 @@ class Onboarding: NSObject { static var smtpTransDataDelegate = PickerDataDelegate.init(rows: ["a", "b", "c"]) static var background = UIImage.init() static var manualSet = false + static var googleAuth = false + + static var loginViewController: UIViewController? static let font = UIFont.init(name: "Helvetica-Light", size: 28) static let padding: CGFloat = 30 @@ -150,9 +154,13 @@ class Onboarding: NSObject { keyboardToolbar.sizeToFit() keyboardToolbar.barTintColor = defaultColor keyboardToolbar.backgroundColor = defaultColor + let googleBarButton = UIBarButtonItem(title: "Login with Google", style: .plain, target: self, action: #selector(oauth)) + googleBarButton.tintColor = .orange + googleButton = googleBarButton let flexBarButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) let doneBarButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(self.dismissKeyboard)) - keyboardToolbar.items = [flexBarButton, doneBarButton] + doneBarButton.tintColor = .orange + keyboardToolbar.items = [googleBarButton, flexBarButton, doneBarButton] mailaddress.inputAccessoryView = keyboardToolbar password.inputAccessoryView = keyboardToolbar @@ -205,9 +213,15 @@ class Onboarding: NSObject { }) } + loginViewController = vc! return vc! } + static func oauth() { + googleAuth = true + doWhenDone() + } + static func dismissKeyboard() { mailaddress.endEditing(true) password.endEditing(true) @@ -472,11 +486,10 @@ class Onboarding: NSObject { AppDelegate.getAppDelegate().requestForAccess(callback) } - static func checkConfig(_ fail: @escaping () -> (), work: @escaping () -> ()) -> Bool { + static func checkConfig(_ fail: @escaping () -> (), work: @escaping () -> ()) { self.work = work self.fail = fail AppDelegate.getAppDelegate().mailHandler.checkIMAP(imapCompletion) - return true } static func imapCompletion(_ error: Error?) { //FIXME: vorher NSError? Mit Error? immer noch gültig? @@ -509,8 +522,7 @@ class Onboarding: NSObject { //TODO: REMOVE BEFORE STUDY loadTestAcc() return setServerValues(mailaddress: mailAddress) - } - else { + } 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) @@ -535,9 +547,10 @@ class Onboarding: NSObject { 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.web.de") as AnyObject?, attribute: Attribute.imapHostname) + UserManager.storeUserValue((imapService.info()["hostname"] ?? "imap.web.de") as AnyObject?, attribute: Attribute.imapHostname) //TODO @jakob: web.de?!? UserManager.storeUserValue((imapService.info()["port"] ?? 587) as AnyObject?, attribute: Attribute.imapPort) - + + print(imapService.info()) 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 { @@ -660,9 +673,6 @@ class Onboarding: NSObject { class TextFieldDelegate: NSObject, UITextFieldDelegate { - func textFieldDidBeginEditing(_ textField: UITextField) { - } - func textFieldShouldReturn(_ textField: UITextField) -> Bool { if textField == Onboarding.mailaddress { textField.resignFirstResponder() diff --git a/enzevalos_iphone/PLists/enzevalos-Info.plist b/enzevalos_iphone/PLists/enzevalos-Info.plist index 89a2df6f53a03a018de1c4d69c80dbf42a58955b..a90c9e33caf8d0f6c5c391d40e5abccfc9863a92 100644 --- a/enzevalos_iphone/PLists/enzevalos-Info.plist +++ b/enzevalos_iphone/PLists/enzevalos-Info.plist @@ -2,6 +2,17 @@ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> + <key>CFBundleURLTypes</key> + <array> + <dict> + <key>CFBundleTypeRole</key> + <string>Editor</string> + <key>CFBundleURLSchemes</key> + <array> + <string>com.googleusercontent.apps.459157836079-csn0a9p3r8p7q6216fn5u7a6vcum80gn</string> + </array> + </dict> + </array> <key>CFBundleDevelopmentRegion</key> <string>en</string> <key>CFBundleDisplayName</key> diff --git a/enzevalos_iphone/PersistentMail +CoreDataProperties.swift b/enzevalos_iphone/PersistentMail +CoreDataProperties.swift index ad47853b4e5748a271253464495f6bedda8d56be..9bc60cad37d6219edd208670a6f21227ddd32888 100644 --- a/enzevalos_iphone/PersistentMail +CoreDataProperties.swift +++ b/enzevalos_iphone/PersistentMail +CoreDataProperties.swift @@ -127,7 +127,11 @@ extension PersistentMail { self.willAccessValue(forKey: "from") let text = (self.primitiveValue(forKey: "from") as? Mail_Address) self.didAccessValue(forKey: "from") - return text! + if let text = text { + return text + } + print("We have a nil") + return Mail_Address() } } public var containsSecretKey: Bool{ diff --git a/enzevalos_iphone/Providers.swift b/enzevalos_iphone/Providers.swift deleted file mode 100644 index f833a4ecf68fb65591f77318bcb8e645e2fc7cc8..0000000000000000000000000000000000000000 --- a/enzevalos_iphone/Providers.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// Providers.swift -// enzevalos_iphone -// -// Created by jakobsbode on 24.03.17. -// Copyright © 2017 fu-berlin. All rights reserved. -// - -enum Provider : String { - case WEB = "web.de", FU = "fu-berlin.de", ZEDAT = "zedat.fu-berlin.de", ENZEVALOS = "enzevalos.de" -} - -class Providers { - static let config: [Provider : [Attribute : AnyObject?]] = createConfig() - - static func createConfig() -> [Provider : [Attribute : AnyObject?]] { - var config: [Provider : [Attribute : AnyObject?]] = [:] - config.updateValue([.smtpHostname : "smtp.web.de" as AnyObject?, .smtpPort : 587 as AnyObject?, .imapHostname : "imap.web.de" as AnyObject?, .imapPort : 993 as AnyObject?, .imapConnectionType: MCOConnectionType.TLS.rawValue as AnyObject?, .imapAuthType: MCOAuthType.saslPlain.rawValue as AnyObject?, .smtpConnectionType: MCOConnectionType.startTLS.rawValue as AnyObject?, .smtpAuthType: MCOAuthType.saslPlain.rawValue as AnyObject?], forKey: Provider.WEB) - config.updateValue([.smtpHostname : "mail.zedat.fu-berlin.de" as AnyObject?, .smtpPort : 587 as AnyObject?, .imapHostname : "mail.zedat.fu-berlin.de" as AnyObject?, .imapPort : 993 as AnyObject?, .imapConnectionType: MCOConnectionType.TLS.rawValue as AnyObject?, .imapAuthType: MCOAuthType.saslPlain.rawValue as AnyObject?, .smtpConnectionType: MCOConnectionType.startTLS.rawValue as AnyObject?, .smtpAuthType: MCOAuthType.saslPlain.rawValue as AnyObject?], forKey: Provider.FU) - config.updateValue([.smtpHostname : "mail.zedat.fu-berlin.de" as AnyObject?, .smtpPort : 587 as AnyObject?, .imapHostname : "mail.zedat.fu-berlin.de" as AnyObject?, .imapPort : 143 as AnyObject?, .imapConnectionType: MCOConnectionType.startTLS.rawValue as AnyObject?, .imapAuthType: MCOAuthType.saslPlain.rawValue as AnyObject?, .smtpConnectionType: MCOConnectionType.TLS.rawValue as AnyObject?, .smtpAuthType: MCOAuthType.saslPlain.rawValue as AnyObject?], forKey: Provider.ZEDAT) - config.updateValue([.smtpHostname : "mail.enzevalos.de" as AnyObject?, .smtpPort : 465 as AnyObject?, .imapHostname : "mail.enzevalos.de" as AnyObject?, .imapPort : 993 as AnyObject?, .imapConnectionType: MCOConnectionType.TLS.rawValue as AnyObject?, .imapAuthType: MCOAuthType.saslPlain.rawValue as AnyObject?, .smtpConnectionType: MCOConnectionType.TLS.rawValue as AnyObject?, .smtpAuthType: MCOAuthType.saslPlain.rawValue as AnyObject?], forKey: Provider.ENZEVALOS) - return config - } - - static func setValues(_ provider: Provider) { - for key in (config[provider]?.keys)! { - UserManager.storeUserValue(config[provider]![key]!, attribute: key) - } - } -} diff --git a/enzevalos_iphone/SendViewController.swift b/enzevalos_iphone/SendViewController.swift index 73927b52674ab04ff27b8514fdd0f1002acc3717..4a867d73a860d68db7d7061f52059165d74d43ea 100644 --- a/enzevalos_iphone/SendViewController.swift +++ b/enzevalos_iphone/SendViewController.swift @@ -472,6 +472,11 @@ class SendViewController: UIViewController { func mailSend(_ error: Error?) { if (error != nil) { + if AppDelegate.getAppDelegate().mailHandler.shouldTryRefreshOAUTH { + AppDelegate.getAppDelegate().mailHandler.retryWithRefreshedOAuth { [weak self] in + self?.pressSend(nil) + } + } NSLog("Error sending email: \(String(describing: error))") // AppDelegate.getAppDelegate().showMessage("An error occured", completion: nil) @jakob: wofür ist dieses showMessage aus AppDelegate gut? let alert = UIAlertController(title: NSLocalizedString("ReceiveError", comment: "There was an error"), message: NSLocalizedString("ErrorText", comment: ""), preferredStyle: UIAlertControllerStyle.alert) @@ -647,7 +652,7 @@ class SendViewController: UIViewController { } } - @IBAction func pressSend(_ sender: AnyObject) { + @IBAction func pressSend(_ sender: AnyObject?) { let toEntrys = toText.mailTokens let ccEntrys = ccText.mailTokens let subject = subjectText.inputText()! diff --git a/enzevalos_iphone/de.lproj/Localizable.strings b/enzevalos_iphone/de.lproj/Localizable.strings index 0f8b96dec60c037c8e1aa331c5bbb403ed4ec060..d0517d8ba45940f088dc61b529270c84f3c227fd 100644 --- a/enzevalos_iphone/de.lproj/Localizable.strings +++ b/enzevalos_iphone/de.lproj/Localizable.strings @@ -175,3 +175,4 @@ "copyKey" = "Schloss in Zwischenablage kopieren"; "NeverUpdated" = "Fehler bei Aktualisierung"; + diff --git a/enzevalos_iphone/enzevalos_iphone-Bridging-Header.h b/enzevalos_iphone/enzevalos_iphone-Bridging-Header.h index 0f6044831b2f42643b7553cda169005795a93e1b..e046e5bcd01782905829e32f4da6a1b4e92800c8 100644 --- a/enzevalos_iphone/enzevalos_iphone-Bridging-Header.h +++ b/enzevalos_iphone/enzevalos_iphone-Bridging-Header.h @@ -11,3 +11,7 @@ #import <Onboard/OnboardingContentViewController.h> #import "ObjectivePGP/ObjectivePGP.h" #import <CommonCrypto/CommonHMAC.h> +#import <AppAuth/AppAuth.h> +#import <GTMAppAuth/GTMAppAuth.h> +#import <GTMSessionFetcher/GTMSessionFetcher.h> +#import "OAuth/EmailHelper.h"