diff --git a/Podfile.lock b/Podfile.lock index 1d890919d..3f1f157e9 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -143,4 +143,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: adec9882e25404ab01a7a461fcdd3ddd937d5ba6 -COCOAPODS: 1.5.2 +COCOAPODS: 1.5.3 diff --git a/WordPressAuthenticator/Authenticator/WordPressAuthenticator.swift b/WordPressAuthenticator/Authenticator/WordPressAuthenticator.swift index b28ed241a..2047a4f75 100644 --- a/WordPressAuthenticator/Authenticator/WordPressAuthenticator.swift +++ b/WordPressAuthenticator/Authenticator/WordPressAuthenticator.swift @@ -134,6 +134,10 @@ public struct WordPressAuthenticatorConfiguration { /// let googleLoginServerClientId: String + /// GoogleLogin Callback Scheme + /// + let googleLoginScheme: String + /// UserAgent /// let userAgent: String @@ -146,13 +150,16 @@ public struct WordPressAuthenticatorConfiguration { wpcomTermsOfServiceURL: String, googleLoginClientId: String, googleLoginServerClientId: String, + googleLoginScheme: String, userAgent: String) { + self.wpcomClientId = wpcomClientId self.wpcomSecret = wpcomSecret self.wpcomScheme = wpcomScheme self.wpcomTermsOfServiceURL = wpcomTermsOfServiceURL self.googleLoginClientId = googleLoginClientId self.googleLoginServerClientId = googleLoginServerClientId + self.googleLoginScheme = googleLoginScheme self.userAgent = userAgent } } @@ -196,6 +203,7 @@ public struct WordPressAuthenticatorConfiguration { static let jetpackBlogUsername = "jetpackBlogUsername" static let username = "username" static let emailMagicLinkSource = "emailMagicLinkSource" + static let magicLinkUrlPath = "magic-login" } // MARK: - Initialization @@ -232,12 +240,31 @@ public struct WordPressAuthenticatorConfiguration { return viewController is LoginPrologueViewController || viewController is NUXViewControllerBase } - /// Indicates if the specified URL is a Google Authentication Link. + /// Indicates if the received URL is a Google Authentication Callback. + /// + @objc public func isGoogleAuthUrl(_ url: URL) -> Bool { + return url.absoluteString.hasPrefix(configuration.googleLoginScheme) + } + + /// Indicates if the received URL is a WordPress.com Authentication Callback. /// - @objc public class func isGoogleAuthURL(url: URL, sourceApplication: String?, annotation: Any?) -> Bool { + @objc public func isWordPressAuthUrl(_ url: URL) -> Bool { + let expectedPrefix = configuration.wpcomScheme + "://" + Constants.magicLinkUrlPath + return url.absoluteString.hasPrefix(expectedPrefix) + } + + /// Attempts to process the specified URL as a Google Authentication Link. Returns *true* on success. + /// + @objc public func handleGoogleAuthUrl(_ url: URL, sourceApplication: String?, annotation: Any?) -> Bool { return GIDSignIn.sharedInstance().handle(url, sourceApplication: sourceApplication, annotation: annotation) } + /// Attempts to process the specified URL as a WordPress Authentication Link. Returns *true* on success. + /// + @objc public func handleWordPressAuthUrl(_ url: URL, allowWordPressComAuth: Bool, rootViewController: UIViewController) -> Bool { + return WordPressAuthenticator.openAuthenticationURL(url, allowWordPressComAuth: allowWordPressComAuth, fromRootViewController: rootViewController) + } + // MARK: - Helpers for presenting the login flow @@ -286,7 +313,6 @@ public struct WordPressAuthenticatorConfiguration { presenter.present(navController, animated: true, completion: nil) } - /// Used to present the new self-hosted login flow from BlogListViewController @objc public class func showLoginForSelfHostedSite(_ presenter: UIViewController) { defer { @@ -329,6 +355,20 @@ public struct WordPressAuthenticatorConfiguration { return NUXNavigationController(rootViewController: controller) } + + /// Returns an instance of LoginEmailViewController. This allows the host app to fine tune the way it's displayed / configure + /// it's features. + /// + public class func signinForWordPress() -> LoginEmailViewController { + let storyboard = UIStoryboard(name: "Login", bundle: bundle) + guard let controller = storyboard.instantiateViewController(withIdentifier: "emailEntry") as? LoginEmailViewController else { + fatalError() + } + + return controller + } + + private class func trackOpenedLogin() { WordPressAuthenticator.track(.openedLogin) } diff --git a/WordPressAuthenticator/Signin/LoginEmailViewController.swift b/WordPressAuthenticator/Signin/LoginEmailViewController.swift index 518e4c4d8..408baafe4 100644 --- a/WordPressAuthenticator/Signin/LoginEmailViewController.swift +++ b/WordPressAuthenticator/Signin/LoginEmailViewController.swift @@ -6,10 +6,10 @@ import WordPressKit /// This is the first screen following the log in prologue screen if the user chooses to log in. /// -class LoginEmailViewController: LoginViewController, NUXKeyboardResponder { +open class LoginEmailViewController: LoginViewController, NUXKeyboardResponder { @IBOutlet var emailTextField: WPWalkthroughTextField! - @IBOutlet var bottomContentConstraint: NSLayoutConstraint? - @IBOutlet var verticalCenterConstraint: NSLayoutConstraint? + @IBOutlet open var bottomContentConstraint: NSLayoutConstraint? + @IBOutlet open var verticalCenterConstraint: NSLayoutConstraint? @IBOutlet var inputStack: UIStackView? @IBOutlet var alternativeLoginLabel: UILabel? @@ -19,7 +19,7 @@ class LoginEmailViewController: LoginViewController, NUXKeyboardResponder { // This signup button isn't for the main flow; it's only shown during Jetpack installation var wpcomSignupButton: UIButton? - override var sourceTag: WordPressSupportSourceTag { + override open var sourceTag: WordPressSupportSourceTag { get { return .loginEmail } @@ -27,7 +27,7 @@ class LoginEmailViewController: LoginViewController, NUXKeyboardResponder { var didFindSafariSharedCredentials = false var didRequestSafariSharedCredentials = false - var offerSignupOption = false + open var offerSignupOption = false fileprivate var awaitingGoogle = false private struct Constants { @@ -39,7 +39,7 @@ class LoginEmailViewController: LoginViewController, NUXKeyboardResponder { // MARK: Lifecycle Methods - override func viewDidLoad() { + override open func viewDidLoad() { super.viewDidLoad() localizeControls() @@ -49,13 +49,13 @@ class LoginEmailViewController: LoginViewController, NUXKeyboardResponder { addSignupButton() } - override func didChangePreferredContentSize() { + override open func didChangePreferredContentSize() { super.didChangePreferredContentSize() configureEmailField() configureAlternativeLabel() } - override func viewWillAppear(_ animated: Bool) { + override open func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // The old create account vc hides the nav bar, so make sure its always visible. @@ -70,7 +70,7 @@ class LoginEmailViewController: LoginViewController, NUXKeyboardResponder { configureForWPComOnlyIfNeeded() } - override func viewDidAppear(_ animated: Bool) { + override open func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) registerForKeyboardEvents(keyboardWillShowAction: #selector(handleKeyboardWillShow(_:)), @@ -80,7 +80,7 @@ class LoginEmailViewController: LoginViewController, NUXKeyboardResponder { } - override func viewWillDisappear(_ animated: Bool) { + override open func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) unregisterForKeyboardEvents() } @@ -234,7 +234,7 @@ class LoginEmailViewController: LoginViewController, NUXKeyboardResponder { /// /// - Parameter loading: True if the form should be configured to a "loading" state. /// - override func configureViewLoading(_ loading: Bool) { + override open func configureViewLoading(_ loading: Bool) { emailTextField.isEnabled = !loading googleLoginButton?.isEnabled = !loading @@ -365,7 +365,7 @@ class LoginEmailViewController: LoginViewController, NUXKeyboardResponder { }) } - override func displayRemoteError(_ error: Error) { + override open func displayRemoteError(_ error: Error) { configureViewLoading(false) if awaitingGoogle { @@ -404,7 +404,7 @@ class LoginEmailViewController: LoginViewController, NUXKeyboardResponder { // MARK: - Segue - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + override open func prepare(for segue: UIStoryboardSegue, sender: Any?) { super.prepare(for: segue, sender: sender) if let vc = segue.destination as? LoginPrologueSignupMethodViewController { @@ -533,7 +533,7 @@ extension LoginEmailViewController { } extension LoginEmailViewController: GIDSignInDelegate { - func sign(_ signIn: GIDSignIn?, didSignInFor user: GIDGoogleUser?, withError error: Error?) { + open func sign(_ signIn: GIDSignIn?, didSignInFor user: GIDGoogleUser?, withError error: Error?) { guard let user = user, let token = user.authentication.idToken, let email = user.profile.email else { diff --git a/WordPressAuthenticator/Signin/LoginNavigationController.swift b/WordPressAuthenticator/Signin/LoginNavigationController.swift index 721c11ebf..18ac53e0c 100644 --- a/WordPressAuthenticator/Signin/LoginNavigationController.swift +++ b/WordPressAuthenticator/Signin/LoginNavigationController.swift @@ -4,8 +4,8 @@ import WordPressUI public class LoginNavigationController: RotationAwareNavigationViewController { - override public func viewDidLoad() { - super.viewDidLoad() + override public func awakeFromNib() { + super.awakeFromNib() navigationBar.barTintColor = WPStyleGuide.wordPressBlue() } diff --git a/WordPressAuthenticator/Signin/LoginViewController.swift b/WordPressAuthenticator/Signin/LoginViewController.swift index a0c51d848..673630774 100644 --- a/WordPressAuthenticator/Signin/LoginViewController.swift +++ b/WordPressAuthenticator/Signin/LoginViewController.swift @@ -3,7 +3,7 @@ import WordPressKit /// View Controller for login-specific screens -class LoginViewController: NUXViewController, LoginFacadeDelegate { +open class LoginViewController: NUXViewController, LoginFacadeDelegate { @IBOutlet var instructionLabel: UILabel? @objc var errorToPresent: Error? @@ -34,7 +34,7 @@ class LoginViewController: NUXViewController, LoginFacadeDelegate { // MARK: Lifecycle Methods - override func viewDidLoad() { + override open func viewDidLoad() { super.viewDidLoad() displayError(message: "") setupNavBarIcon() @@ -135,7 +135,7 @@ class LoginViewController: NUXViewController, LoginFacadeDelegate { /// Manages data transfer when seguing to a new VC /// - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + override open func prepare(for segue: UIStoryboardSegue, sender: Any?) { guard let source = segue.source as? LoginViewController, let destination = segue.destination as? LoginViewController else { return } @@ -146,7 +146,7 @@ class LoginViewController: NUXViewController, LoginFacadeDelegate { } // MARK: SigninWPComSyncHandler methods - dynamic func finishedLogin(withUsername username: String, authToken: String, requiredMultifactorCode: Bool) { + dynamic open func finishedLogin(withUsername username: String, authToken: String, requiredMultifactorCode: Bool) { let credentials = WordPressCredentials.wpcom(username: username, authToken: authToken, isJetpackLogin: isJetpackLogin, multifactor: requiredMultifactorCode) syncWPComAndPresentEpilogue(credentials: credentials) @@ -159,7 +159,7 @@ class LoginViewController: NUXViewController, LoginFacadeDelegate { } /// Overridden here to direct these errors to the login screen's error label - dynamic func displayRemoteError(_ error: Error) { + dynamic open func displayRemoteError(_ error: Error) { configureViewLoading(false) let err = error as NSError @@ -172,7 +172,7 @@ class LoginViewController: NUXViewController, LoginFacadeDelegate { displayError(err, sourceTag: sourceTag) } - func needsMultifactorCode() { + open func needsMultifactorCode() { displayError(message: "") configureViewLoading(false) @@ -289,7 +289,7 @@ extension LoginViewController { // MARK: - Handle changes in traitCollections. In particular, changes in Dynamic Type // extension LoginViewController { - override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + override open func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) if previousTraitCollection?.preferredContentSizeCategory != traitCollection.preferredContentSizeCategory {