diff --git a/enzevalos_iphone.xcodeproj/project.pbxproj b/enzevalos_iphone.xcodeproj/project.pbxproj index 994a458c5d06e53bfba338bf5a51f350130c3bc3..602f15d12812c3930b4b8114143e9af3548753c4 100644 --- a/enzevalos_iphone.xcodeproj/project.pbxproj +++ b/enzevalos_iphone.xcodeproj/project.pbxproj @@ -158,6 +158,7 @@ 8428A8831F436AC9007649A5 /* GamificationDataUnitTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8428A8561F4369EA007649A5 /* GamificationDataUnitTest.swift */; }; 8428A8841F436ACC007649A5 /* GamificationElements.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8428A8541F4369CF007649A5 /* GamificationElements.xcassets */; }; 976EEBED240D47C3006FE574 /* AuthenticationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 976EEBEC240D47C3006FE574 /* AuthenticationViewModel.swift */; }; + 9771AA8C241161190023A096 /* MailAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9771AA8B241161190023A096 /* MailAccount.swift */; }; 97B2F4D6240D321B000DB34E /* AuthenticationScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97B2F4D5240D321B000DB34E /* AuthenticationScreen.swift */; }; 988C9C5D240D507A006213F0 /* PhishingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 988C9C5C240D507A006213F0 /* PhishingTests.swift */; }; A102AA8A1EDDB4F40024B457 /* videoOnboarding2.m4v in Resources */ = {isa = PBXBuildFile; fileRef = A102AA891EDDB4E80024B457 /* videoOnboarding2.m4v */; }; @@ -439,6 +440,7 @@ 91B6C9020C660BEA78FAEF28 /* Pods-enzevalos_iphone.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-enzevalos_iphone.debug.xcconfig"; path = "../enzevalos_iphone_workspace/Pods/Target Support Files/Pods-enzevalos_iphone/Pods-enzevalos_iphone.debug.xcconfig"; sourceTree = "<group>"; }; 94EE54279AB591E0CAB8EFD8 /* Pods_enzevalos_iphone.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_enzevalos_iphone.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 976EEBEC240D47C3006FE574 /* AuthenticationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationViewModel.swift; sourceTree = "<group>"; }; + 9771AA8B241161190023A096 /* MailAccount.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MailAccount.swift; sourceTree = "<group>"; }; 97B2F4D5240D321B000DB34E /* AuthenticationScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationScreen.swift; sourceTree = "<group>"; }; 988C9C5C240D507A006213F0 /* PhishingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhishingTests.swift; sourceTree = "<group>"; }; 9A132EDE8BCA06ACDB505C22 /* Pods-enzevalos_iphoneUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-enzevalos_iphoneUITests.debug.xcconfig"; path = "../enzevalos_iphone_workspace/Pods/Target Support Files/Pods-enzevalos_iphoneUITests/Pods-enzevalos_iphoneUITests.debug.xcconfig"; sourceTree = "<group>"; }; @@ -897,6 +899,7 @@ children = ( 97B2F4D5240D321B000DB34E /* AuthenticationScreen.swift */, 976EEBEC240D47C3006FE574 /* AuthenticationViewModel.swift */, + 9771AA8B241161190023A096 /* MailAccount.swift */, ); name = authentication; sourceTree = "<group>"; @@ -1723,6 +1726,7 @@ F18B445E1E7044B70080C041 /* FlipTransition.swift in Sources */, 472F397E1E1D0B0B009260FB /* EnzevalosContact+CoreDataProperties.swift in Sources */, 4751C6FA23449699006B2A4D /* CryptoManagementViewController.swift in Sources */, + 9771AA8C241161190023A096 /* MailAccount.swift in Sources */, 478154AC21FF6A9600A931EC /* Mailbot.swift in Sources */, 8428A86E1F436A1E007649A5 /* BadgeCase.swift in Sources */, A1B49E5D21E54CBF00ED86FC /* IntroContactTableViewController.swift in Sources */, diff --git a/enzevalos_iphone/AppDelegate.swift b/enzevalos_iphone/AppDelegate.swift index afe84fd8c1b090c572a4406e2b67710fcf80feda..9e1d55fd9b2fe491055f38e8831f66fe03339475 100644 --- a/enzevalos_iphone/AppDelegate.swift +++ b/enzevalos_iphone/AppDelegate.swift @@ -62,7 +62,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate { self.window = UIWindow(frame: UIScreen.main.bounds) if (newOnboarding) - {self.window?.rootViewController = UIHostingController(rootView: NewOnboardingView())} + { + let avm=AuthenticationViewModel() + self.window?.rootViewController = UIHostingController(rootView: NewOnboardingView().environmentObject(avm))} else {self.window?.rootViewController = Onboarding.onboarding()} self.window?.makeKeyAndVisible() diff --git a/enzevalos_iphone/AuthenticationScreen.swift b/enzevalos_iphone/AuthenticationScreen.swift index 65bd9f901ce0f551860c780dd3e250bfbc951cfc..470bf0cdcf195a5ca76860a5340c64f5e7727534 100644 --- a/enzevalos_iphone/AuthenticationScreen.swift +++ b/enzevalos_iphone/AuthenticationScreen.swift @@ -39,8 +39,9 @@ struct AuthenticationScreen: View { Text("Advanced options") }*/ Spacer() - Button(action: {/*self.viewModel.isDetailedAuthentication ? - self.viewModel.validate(self.login, self.password, self.username, self.imapServer, self.imapPort, self.imapEncryption, self.smtpServer, self.smtpPort, self.smtpEncryption) :*/ + + Button(action: {self.viewModel.isDetailedAuthentication ? + self.viewModel.detailValidation(self.login, self.password, self.username, self.imapServer, self.imapPort, self.imapEncryption, self.smtpServer, self.smtpPort, self.smtpEncryption) : self.viewModel.validate(self.login, self.password) }) { Text("Button") @@ -78,8 +79,12 @@ struct AuthenticationScreen: View { Text(self.encryptionOptions[$0]) } } - }*/ + }*/ + + Button(action: { self.viewModel.startGoogleOauth() }) { + Text("Google button") + } }.padding() //TODO: once SWIFTUI supports optionals improve this if statement @@ -95,6 +100,7 @@ struct AuthenticationScreen: View { } } + struct LoginAdvancedOptions:View{ var body: some View { Text("no") diff --git a/enzevalos_iphone/AuthenticationViewModel.swift b/enzevalos_iphone/AuthenticationViewModel.swift index 46806fb44f1805c8bc1ce0423252796e445aac17..07f523c73454bc18260b8eab1e4ccba5b7a3f14e 100644 --- a/enzevalos_iphone/AuthenticationViewModel.swift +++ b/enzevalos_iphone/AuthenticationViewModel.swift @@ -10,204 +10,216 @@ import Foundation class AuthenticationViewModel : ObservableObject { - static let DEFAULT_IMAP_PORT = 993 - static let DEFAULT_SMTP_PORT = 587 - @Published var errorMessage: String? @Published var isDetailedAuthentication: Bool = false - @Published var imapServer: String = "imap.web.de" - @Published var imapPort: String = String(DEFAULT_IMAP_PORT) - @Published var imapTransportEncryption = 2 - - @Published var smtpServer: String = "smtp.web.de" - @Published var smtpPort: String = String(DEFAULT_SMTP_PORT) - @Published var smtpTransportEncryption = 1 - - var imapAuthentication = UIPickerView.init() - var imapAuthDataDelegate = PickerDataDelegate.init(rows: ["a", "b", "c"]) - var imapTransDataDelegate = PickerDataDelegate.init(rows: ["a", "b", "c"]) - var smtpAuthDataDelegate = PickerDataDelegate.init(rows: ["a", "b", "c"]) - var smtpTransDataDelegate = PickerDataDelegate.init(rows: ["a", "b", "c"]) - var googleAuth = false + var isGoogleAuth = false var imapConfigurationSuccessful = false var smtpConfigurationSuccessful = false - var startTimeIMAPCheck: Date? //TODO What about SMTP? - - var startTimeView = Date() - var transportRows: [Int: String] = [MCOConnectionType.clear.rawValue: NSLocalizedString("Plaintext", comment: ""), MCOConnectionType.startTLS.rawValue: "StartTLS", MCOConnectionType.TLS.rawValue: "TLS/SSL"] - private var previousIMAP: MailSession? - private var previousSMTP: MailSession? private var currentIMAP: MailSession? private var currentSMTP: MailSession? + var imapCallback: AuthenticationCallback? = nil + var smtpCallback: AuthenticationCallback? = nil + + var dispatchGroup = DispatchGroup() func validate(_ login: String, _ password: String) -> Void { - checkIMAPConfig(login, password) + let mailAccount = MailAccount(emailAddress: login, password: password) + + checkConfig(mailAccount: mailAccount) + } + + func detailValidation(_ login: String, _ password: String, _ username: String, _ imapServer: String, _ imapPort: String, _ imapEncryption: Int, _ smtpServer: String, _ smtpPort: String, _ smtpEncryption: Int) -> Void { + let mailAccount = MailAccount(emailAddress: login, password: password, username: username, imapServer: imapServer, imapPort: Int(imapPort)!, imapEncryption: 1 << imapEncryption, smtpServer: smtpServer, smtpPort: Int(smtpPort)!, smtpEncryption: 1 << smtpEncryption) + + checkConfig(mailAccount: mailAccount) } - func validate(_ login: String, _ password: String, _ username: String, _ imapServer: String, _ imapPort: String, _ imapEncryption: Int, _ smtpServer: String, _ smtpPort: String, _ smtpEncryption: Int) -> Void { - checkDetailConfig(imap: true, login, password, username: "rtes",imapServer, Int(imapPort)!, imapEncryption, smtpServer, Int(smtpPort)!, smtpEncryption) + /** + Start asynchronous tasks for checking IMAP and SMTP configuration with a *timeoutDelay* after which the tasks are not getting consumed anymore. + */ + fileprivate func checkConfig(mailAccount: MailAccount) { + dispatchGroup = DispatchGroup() + imapCallback = AuthenticationCallback(callback: onImapCompleted) + let imapItem = DispatchWorkItem { self.checkIMAPConfig(mailAccount: mailAccount, self.imapCallback! ) } + dispatchGroup.enter() + DispatchQueue.global().async(execute: imapItem) + + smtpCallback = AuthenticationCallback(callback: onSmtpCompleted) + let smtpItem = DispatchWorkItem { self.checkSMTPConfig(mailAccount: mailAccount, self.smtpCallback!) } + dispatchGroup.enter() + DispatchQueue.global().async(execute: smtpItem) + + DispatchQueue.global().async { + let timeoutDelay: DispatchTimeInterval = DispatchTimeInterval.seconds(10) + let result = self.dispatchGroup.wait(timeout: DispatchTime.now() + timeoutDelay) + DispatchQueue.main.async { + self.timeoutOccured(timeoutResult: result) + } + } } - func checkIMAPConfig(_ login: String, _ password: String) { - var mailSession: MailSession - if googleAuth, let session = previousIMAP, session.startTestingServerConfig() { - mailSession = session + func checkIMAPConfig(mailAccount: MailAccount, _ callback: AuthenticationCallback) { + imapConfigurationSuccessful = false + let mailSession: MailSession = setupIMAPSession(mailAccount: mailAccount, callback: callback) + currentIMAP = mailSession + if (isGoogleAuth || isDetailedAuthentication) && mailSession.startTestingServerConfig(){ imapConfigurationSuccessful = true - startTimeIMAPCheck = Date() } else { - mailSession = setupIMAPSession(login, password) - if !mailSession.hasJsonFile && mailSession.startLongSearchOfServerConfig(hostFromAdr: true) { + if !mailSession.hasJsonFile && mailSession.startLongSearchOfServerConfig(hostFromAdr: true){ imapConfigurationSuccessful = true - startTimeIMAPCheck = Date() - } else if isDetailedAuthentication { - checkDetailConfig(imap: true, login, password, imapServer, Int(imapPort)!, imapTransportEncryption, smtpServer, Int(smtpPort)!, smtpTransportEncryption) - return } else { if mailSession.startTestingServerConfigFromList() || mailSession.startLongSearchOfServerConfig(hostFromAdr: true){ imapConfigurationSuccessful = true - startTimeIMAPCheck = Date() } } } - currentIMAP = mailSession } - func checkSMTPConfig(_ login: String, _ password: String) { - var mailSession: MailSession - if googleAuth, let session = previousSMTP, session.startTestingServerConfig() { - mailSession = session + func checkSMTPConfig(mailAccount: MailAccount, _ callback: AuthenticationCallback) { + smtpConfigurationSuccessful = false + let mailSession: MailSession = setupSMTPSession(mailAccount: mailAccount, callback: callback) + currentSMTP = mailSession + if (isGoogleAuth || isDetailedAuthentication) && mailSession.startTestingServerConfig() { smtpConfigurationSuccessful = true } else { - startTimeIMAPCheck = nil - mailSession = setupSMTPSession(login, password) if !mailSession.hasJsonFile && mailSession.startLongSearchOfServerConfig(hostFromAdr: !isDetailedAuthentication) { smtpConfigurationSuccessful = true - } else if isDetailedAuthentication { - checkDetailConfig(imap: false, login, password, imapServer, Int(imapPort)!, imapTransportEncryption, smtpServer, Int(smtpPort)!, smtpTransportEncryption) - return } else { if mailSession.startTestingServerConfigFromList() || mailSession.startLongSearchOfServerConfig(hostFromAdr: true){ smtpConfigurationSuccessful = true } } } - currentSMTP = mailSession } - private func setupIMAPSession(_ login: String, _ password: String, username:String? = nil) -> MailSession { - var name = login - if let n = username { - name = n + func startGoogleOauth() { + isGoogleAuth = true + googleLogin() + } + + func googleLogin() { + guard let vc = AppDelegate.getAppDelegate().window?.rootViewController else { + print("No view controller!") + return + } + Logger.log(onboardingState: .GoogleLogIn, duration: 0) + + EmailHelper.singleton().doEmailLoginIfRequired(onVC: vc, completionBlock: { + guard let userEmail = EmailHelper.singleton().authorization?.userEmail, EmailHelper.singleton().authorization?.canAuthorize() ?? false else { + print("Google authetication failed") + self.isGoogleAuth = false + return + } + let mailAccount = MailAccount(emailAddress: userEmail.lowercased(), password: "", username: userEmail.lowercased(), imapServer: "imap.gmail.com", imapPort: 993, imapEncryption: 2, smtpServer: "smtp.gmail.com", smtpPort: 587, smtpEncryption: 1, authType: MCOAuthType.xoAuth2.rawValue) + + self.checkConfig(mailAccount: mailAccount) + }) + } + + private func setupIMAPSession(mailAccount: MailAccount, callback: AuthenticationCallback) -> MailSession { + let mailSession = MailSession(configSession: SessionType.IMAP, mailAddress: mailAccount.emailAddress, password: mailAccount.password, username: mailAccount.username) + if (isGoogleAuth || isDetailedAuthentication) { + let imapConnValue = mailAccount.imapEncryption + mailSession.setServer(hostname: mailAccount.imapServer, port: UInt32(mailAccount.imapPort), connType: imapConnValue, authType: mailAccount.authType) } - let mailSession = MailSession(configSession: SessionType.IMAP, mailAddress: login, password: password, username: name) - let listenerIMAP = Listener(type: SessionType.IMAP, callback: onImapCompleted, login: login, password: password) + + let listenerIMAP = Listener(callback: callback, mailAccount: mailAccount) mailSession.addListener(listener: listenerIMAP) return mailSession } - private func setupSMTPSession(_ login: String, _ password: String, username:String? = nil) -> MailSession{ - var name = login - if let n = username { - name = n + private func setupSMTPSession(mailAccount: MailAccount, callback: AuthenticationCallback) -> MailSession { + let mailSession = MailSession(configSession: SessionType.SMTP, mailAddress: mailAccount.emailAddress, password: mailAccount.password, username: mailAccount.username) + if (isGoogleAuth || isDetailedAuthentication) { + let smtpConnValue = mailAccount.smtpEncryption + mailSession.setServer(hostname: mailAccount.smtpServer, port: UInt32(mailAccount.smtpPort), connType: smtpConnValue, authType: mailAccount.authType) } - let mailSession = MailSession(configSession: SessionType.SMTP, mailAddress: login, password: password, username: name) - let listenerSMTP = Listener(type: SessionType.SMTP, callback: onSmtpCompleted, login: login, password: password) + + let listenerSMTP = Listener(callback: callback, mailAccount: mailAccount) mailSession.addListener(listener: listenerSMTP) return mailSession } func authenticationFailed() { - previousSMTP = currentSMTP - previousIMAP = currentIMAP - currentSMTP = nil - currentIMAP = nil - var error = MailServerConnectionError.AuthenticationError - if let imap = previousIMAP, let e = MailServerConnectionError.findPrioError(errors: imap.errors) { + if let smtp = currentIMAP, let e = MailServerConnectionError.findPrioError(errors: smtp.errors) { + error = e + } + if let imap = currentIMAP, let e = MailServerConnectionError.findPrioError(errors: imap.errors) { error = e } - errorMessage = error.localizedDescription + errorMessage = NSLocalizedString(error.localizedUIBodyString, comment: "") } - private func checkDetailConfig(imap: Bool, _ login: String, _ password: String, username:String? = nil, _ imapServer:String, _ imapPort:Int, _ imapEncryption:Int, _ smtpServer:String, _ smtpPort:Int, _ smtpEncryption:Int) { - - let imapSession = setupIMAPSession(login, password) - let smtpSession = setupSMTPSession(login, password) - - var name = login - if let n = username { - name = n - } - - let imapConnValue = 1 << imapEncryption - let smtpConnValue = 1 << smtpEncryption - - smtpSession.setServer(hostname: smtpServer, port: UInt32(smtpPort), connType: smtpConnValue, authType: nil) - imapSession.setServer(hostname: imapServer, port: UInt32(imapPort), connType: imapConnValue, authType: nil) - - if imap { - previousSMTP = currentSMTP - previousIMAP = currentIMAP - currentSMTP = smtpSession - currentIMAP = imapSession - if imapSession.startTestingServerConfig() { - imapConfigurationSuccessful = true + func timeoutNotification() { + errorMessage = NSLocalizedString(MailServerConnectionError.TimeoutError.localizedUIBodyString, comment: "") + } + + func timeoutOccured(timeoutResult: DispatchTimeoutResult) { + imapCallback?.callback = nil + smtpCallback?.callback = nil + if timeoutResult == .success { + if imapConfigurationSuccessful && smtpConfigurationSuccessful { + AppDelegate.getAppDelegate().credentialsWork() + } else { + authenticationFailed() } } else { - if smtpSession.startTestingServerConfig() { - smtpConfigurationSuccessful = true - currentSMTP = smtpSession - } + timeoutNotification() } } func onImapCompleted(imapWorks: Bool, _ login: String, _ password: String) { if imapWorks { _ = currentIMAP?.storeToUserDefaults() - checkSMTPConfig(login, password) - return - - } else if let start = startTimeIMAPCheck { - startTimeIMAPCheck = nil - let duration = abs(start.timeIntervalSinceNow) - if duration > TimeInterval(10) { - isDetailedAuthentication = true - } + imapConfigurationSuccessful = true + } else { + imapConfigurationSuccessful = false + authenticationFailed() } - imapConfigurationSuccessful = false - authenticationFailed() + dispatchGroup.leave() } func onSmtpCompleted(smtpWorks: Bool, _ login: String, _ password: String) { if smtpWorks { _ = currentSMTP?.storeToUserDefaults() - AppDelegate.getAppDelegate().credentialsWork() - return + smtpConfigurationSuccessful = true + } else { + smtpConfigurationSuccessful = false + authenticationFailed() } - smtpConfigurationSuccessful = false - authenticationFailed() + dispatchGroup.leave() + return } class Listener: MailSessionListener { - let type: SessionType - let callback: (Bool, String, String) -> Void - let login: String - let password: String + let callback: AuthenticationCallback + let mailAccount: MailAccount - init(type: SessionType, callback: @escaping (Bool, String, String) -> Void, login: String , password: String) { - self.type = type + init(callback: AuthenticationCallback, mailAccount: MailAccount) { self.callback = callback - self.login = login - self.password = password + self.mailAccount = mailAccount } func testFinish(result: Bool) { - DispatchQueue.main.async(execute: { - self.callback(result, self.login, self.password) - }) + callback.onResult(worked: result, login: mailAccount.emailAddress, password: mailAccount.password) + } + } +} + +class AuthenticationCallback { + var callback: ((Bool, String, String) -> Void)? + + init(callback: @escaping (Bool, String, String) -> Void) { + self.callback = callback + } + + func onResult(worked: Bool, login: String, password: String) { + if let callback = callback { + callback(worked, login, password) } } } diff --git a/enzevalos_iphone/MailAccount.swift b/enzevalos_iphone/MailAccount.swift new file mode 100644 index 0000000000000000000000000000000000000000..87c2fde3877ac6b3890920498ab512e0e13e4ff7 --- /dev/null +++ b/enzevalos_iphone/MailAccount.swift @@ -0,0 +1,50 @@ +// +// MailAccount.swift +// enzevalos_iphone +// +// Created by SWP Usable Security für Smartphones on 05.03.20. +// Copyright © 2020 fu-berlin. All rights reserved. +// + +import Foundation + +class MailAccount { + + let emailAddress: String + let password: String + //TODO: describe what username is + let username: String? + let imapServer: String + let imapPort: Int + let imapEncryption: Int + let smtpServer: String + let smtpPort: Int + let smtpEncryption: Int + let authType: Int? + + init(emailAddress: String, password: String, username: String? = nil, imapServer: String, imapPort: Int, imapEncryption: Int, smtpServer: String, smtpPort: Int, smtpEncryption: Int, authType: Int? = nil) { + self.emailAddress = emailAddress + self.password = password + self.username = username + self.imapServer = imapServer + self.imapPort = imapPort + self.imapEncryption = imapEncryption + self.smtpServer = smtpServer + self.smtpPort = smtpPort + self.smtpEncryption = smtpEncryption + self.authType = authType + } + + init(emailAddress: String, password: String, username: String? = nil) { + self.emailAddress = emailAddress + self.password = password + username == nil ? (self.username = emailAddress) : (self.username = username) + self.imapServer = "" + self.imapPort = 0 + self.imapEncryption = 0 + self.smtpServer = "" + self.smtpPort = 0 + self.smtpEncryption = 0 + self.authType = nil + } +} diff --git a/enzevalos_iphone/MailServerConnectionError.swift b/enzevalos_iphone/MailServerConnectionError.swift index d726c974c960fc6cb35cd9944ddaac2e18bc173b..5383467225e984a6101c8f0c5dee7bdaf569df90 100644 --- a/enzevalos_iphone/MailServerConnectionError.swift +++ b/enzevalos_iphone/MailServerConnectionError.swift @@ -17,7 +17,8 @@ enum UserRecommandation: Int { CheckSSLConfiguration = 4, CheckOAUTH = 5, - Default = 100 + Default = 100, + Timeout = 200 } // see: https://github.com/MailCore/mailcore2/blob/31e308a36108301e2f9cc5c4489bb81ff84e6d3a/src/objc/abstract/MCOConstants.h @@ -26,7 +27,7 @@ enum MailServerConnectionError: Error { GmailIMAPNotEnabledError, GmailExceededBandwidthLimitError, GmailTooManySimultaneousConnectionsError, MobileMeMovedError, YahooUnavailableError, ImapIdleError, IdentityError, StartTLSNotAvailableError, AuthenticationRequiredError, SMTPInvalidAccountError, ServerDateError, UnspecifiedError, StorageLimitSMTPError, NoInternetconnection, NoData, SecurityIndicatorError, - ImapSetupError, SmtpSetupError + ImapSetupError, SmtpSetupError, TimeoutError var userRecommandations: UserRecommandation { get { @@ -53,6 +54,8 @@ enum MailServerConnectionError: Error { return .CheckIMAPServerConfig case .SmtpSetupError : return .CheckSMTPServerConfig + case .TimeoutError : + return .Timeout default : return .Default } @@ -75,6 +78,8 @@ enum MailServerConnectionError: Error { return "MailServerError.SMTP.Body" case UserRecommandation.CheckConnectionInfo : return "MailServerError.Connection.Body" + case UserRecommandation.Timeout : + return "MailServerError.Timeout.Body" default: return "MailServerError.Default.Body" } diff --git a/enzevalos_iphone/MailSession.swift b/enzevalos_iphone/MailSession.swift index 1df6ce70ad5ba706546da5a92236fc7f2e42f9c3..4069cdf813330ffbc814ddc37c185ccb698b70b2 100644 --- a/enzevalos_iphone/MailSession.swift +++ b/enzevalos_iphone/MailSession.swift @@ -643,7 +643,7 @@ class MailSession { let (_, server) = MailSession.splitAddr(userAddr: self.mailAddr) if let domain = server { if self.sessionType == SessionType.IMAP { - createServers(domain: domain, prefixes: MailSession.IMAPPREFIX, ports: MailSession.IMAPPORT) + createServers(domain: domain, prefixes: MailSession.IMAPPREFIX, ports: [UInt32(111)]) } else { createServers(domain: domain, prefixes: MailSession.SMTPPREFIX, ports: MailSession.SMTPPORT) diff --git a/enzevalos_iphone/OnboardingIntro.swift b/enzevalos_iphone/OnboardingIntro.swift index 37d7284ab9a4d3397ecba5d5d8c9294494d1ec49..ca87b787edeeffa2bf694960a19aace1f48ca057 100644 --- a/enzevalos_iphone/OnboardingIntro.swift +++ b/enzevalos_iphone/OnboardingIntro.swift @@ -59,7 +59,7 @@ struct OnboardingIntroStack:View{ struct OnboardingLoginButton: View{ - @ObservedObject private var viewModel = AuthenticationViewModel() + @EnvironmentObject private var viewModel : AuthenticationViewModel @State private var loggingIn:Bool = false @@ -72,7 +72,7 @@ struct OnboardingLoginButton: View{ {self.loggingIn = true} ) { if self.loggingIn{ - AuthenticationView(onBack: {self.loggingIn = false},onClick: onClick)//, viewModel:$viewModel) + AuthenticationView(onBack: {self.loggingIn = false},onClick: onClick) }else{ HStack{ @@ -81,7 +81,7 @@ struct OnboardingLoginButton: View{ .resizable() .frame(width: 20, height: 20) Text(NSLocalizedString("Onboarding.loginButtonText", comment: "Login")) - .font(.caption) + .font(.body) .padding(.horizontal, 15) //Spacer() @@ -89,11 +89,11 @@ struct OnboardingLoginButton: View{ if !self.loggingIn { Button(action: {//TODO: login with google - self.$viewModel.startGoogleOauth() - } ) { + self.viewModel.startGoogleOauth() + }) { HStack{ Text(NSLocalizedString("Onboarding.loginButtonTextGoogle", comment: "Login")) - .font(.caption) + .font(.body) .padding(.horizontal, 15) Image("googleIcon") .renderingMode(Image.TemplateRenderingMode?.init(Image.TemplateRenderingMode.original)) @@ -124,7 +124,7 @@ struct OnboardingLoginButton: View{ .background(Color.accentColor) .cornerRadius(8) .shadow(radius: 5) - .padding(.horizontal, 10) + .padding(.horizontal, 10) Spacer() @@ -146,7 +146,6 @@ struct AuthenticationView: View{ @State private var smtpEncryption = 0 @State private var smtpOrImap:Bool = false - @ObservedObject var viewModel=AuthenticationViewModel() var encryptionOptions = ["Plaintext", "StartTLS", "TLS/SSL"] @@ -165,6 +164,9 @@ struct AuthenticationView: View{ var onClick: ()->Void + @EnvironmentObject var viewModel:AuthenticationViewModel + + @ObservedObject private var kGuardian = KeyboardGuardian(textFieldCount: 1) var body: some View { @@ -194,9 +196,8 @@ struct AuthenticationView: View{ } Spacer() - Button(action: { - self.viewModel.isDetailedAuthentication ? - self.viewModel.validate(self.login, self.password, self.username, self.imapServer, self.imapPort, self.imapEncryption, self.smtpServer, self.smtpPort, self.smtpEncryption) : + Button(action: {self.viewModel.isDetailedAuthentication ? + self.viewModel.detailValidation(self.login, self.password, self.username, self.imapServer, self.imapPort, self.imapEncryption, self.smtpServer, self.smtpPort, self.smtpEncryption) : self.viewModel.validate(self.login, self.password) }){ HStack(alignment: .center){ @@ -228,37 +229,50 @@ struct AuthenticationView: View{ struct LoginCredentialSection: View{ - @Binding var email: String - @Binding var password: String - - - var bigspace:CGFloat = 25 - var smallspace:CGFloat = 1 - - var body: some View { - VStack { +@Binding var email: String +@Binding var password: String - Text(NSLocalizedString("Onboarding.loginDescription", comment: "")) - .fontWeight(.heavy) - .multilineTextAlignment(.center) - .padding(.bottom, bigspace) - +@State private var secured: Bool = true + + +var bigspace:CGFloat = 25 +var smallspace:CGFloat = 1 + +var body: some View { + VStack { + + Text(NSLocalizedString("Onboarding.loginDescription", comment: "")) + .fontWeight(.heavy) + .multilineTextAlignment(.center) + .padding(.bottom, bigspace) - Text(NSLocalizedString("Onboarding.enterEmail", comment: "")) - .padding(.bottom, smallspace) - TextField("maxmustermann@icloud.com", text: $email) - .padding(EdgeInsets(top: 8, leading:10, bottom: 8, trailing: 10)) - .background(Color.white) - .foregroundColor(Color.black) - .clipShape(RoundedRectangle(cornerRadius: 8)) - .shadow(radius: 8) - .padding(.bottom, bigspace) - - Text(NSLocalizedString("Onboarding.enterPassword", comment: "")) - .padding(.bottom, smallspace) - Group{ - SecureField("Your password", text: $password) + Text(NSLocalizedString("Onboarding.enterEmail", comment: "")) + .padding(.bottom, smallspace) + + TextField("maxmustermann@icloud.com", text: $email) + .padding(EdgeInsets(top: 8, leading:10, bottom: 8, trailing: 10)) + .background(Color.white) + .foregroundColor(Color.black) + .clipShape(RoundedRectangle(cornerRadius: 8)) + .shadow(radius: 8) + .padding(.bottom, bigspace) + + Text(NSLocalizedString("Onboarding.enterPassword", comment: "")) + .padding(.bottom, smallspace) + ZStack (alignment: .trailing) { + if secured { + SecureField("Your password", text: $password) + .padding(EdgeInsets(top: 8, leading:10, bottom: 8, trailing: 10)) + + .background(Color.white) + .foregroundColor(Color.black) + .clipShape(RoundedRectangle(cornerRadius: 8)) + .shadow(radius: 8) + .padding(.bottom, bigspace) + + } else { + TextField("Your password", text: $password) .padding(EdgeInsets(top: 8, leading:10, bottom: 8, trailing: 10)) .background(Color.white) @@ -268,13 +282,22 @@ struct LoginCredentialSection: View{ .padding(.bottom, bigspace) } - - - } - .padding() - .background(Color.blue) - - + + Button(action: { + self.secured.toggle() + }){ + if secured { + Image(systemName: "eye.slash") + } else { + Image(systemName: "eye") + } + }.foregroundColor(Color.primary) + .background(Color.white) + .padding([.bottom, .trailing] , 25) + } + } +.padding() +.background(Color.blue) } } @@ -287,6 +310,7 @@ struct LoginAdvancedSection: View{ @Binding var smtpPort: String @Binding var imapEncryption: Int @Binding var smtpEncryption :Int + @State var smtpOrImap:Bool = false @@ -294,6 +318,12 @@ struct LoginAdvancedSection: View{ var encryptionOptions:[String] + var userAdvOpt: some View{ + HStack { + Text("Username") + TextField("username", text: $username).foregroundColor(.black) + } + } var imapSection: some View{ VStack{ @@ -340,6 +370,7 @@ struct LoginAdvancedSection: View{ } } + var imapSmtpSwitch : some View{ Button(action: {self.smtpOrImap.toggle()}) { HStack{ @@ -377,6 +408,7 @@ struct LoginAdvancedSection: View{ advancedSectionSwitch if self.isDetailed{ VStack{ + userAdvOpt imapSection.rotation3DEffect(.degrees(self.smtpOrImap ? 90 : 0), axis: (x: 1, y: 0, z: 0), anchor: .bottom).frame(height: !self.smtpOrImap ? 200 : 0) imapSmtpSwitch smtpSection.rotation3DEffect(.degrees(!self.smtpOrImap ? -90 : 0), axis: (x: 1, y: 0, z: 0), anchor: .top).frame(height: self.smtpOrImap ? 200 : 0) @@ -390,3 +422,4 @@ struct LoginAdvancedSection: View{ } } } +