Skip to content
This repository was archived by the owner on Feb 5, 2025. It is now read-only.

Commit 14b9724

Browse files
authored
Merge pull request #568 from wordpress-mobile/release/1.34.0
Release 1.34.0 -> trunk
2 parents 425aaf4 + 170a884 commit 14b9724

File tree

10 files changed

+147
-25
lines changed

10 files changed

+147
-25
lines changed

WordPressAuthenticator.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = "WordPressAuthenticator"
3-
s.version = "1.33.0"
3+
s.version = "1.34.0"
44
s.summary = "WordPressAuthenticator implements an easy and elegant way to authenticate your WordPress Apps."
55

66
s.description = <<-DESC

WordPressAuthenticator.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
020BE74A23B0BD2E007FE54C /* WordPressAuthenticatorDisplayImages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 020BE74923B0BD2E007FE54C /* WordPressAuthenticatorDisplayImages.swift */; };
1111
1A21EE9822832BC300C940C6 /* WordPressComOAuthClientFacade+Swift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A21EE9722832BC200C940C6 /* WordPressComOAuthClientFacade+Swift.swift */; };
1212
1A4095182271AEFC009AA86D /* WPAuthenticator-Swift.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A4095152271AEFC009AA86D /* WPAuthenticator-Swift.h */; settings = {ATTRIBUTES = (Private, ); }; };
13+
3108613125AFA4830022F75E /* PasteboardTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3108613025AFA4830022F75E /* PasteboardTests.swift */; };
1314
3F550D4E23DA429B007E5897 /* AppSelectorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F550D4D23DA429B007E5897 /* AppSelectorTests.swift */; };
1415
3F550D5123DA4A9C007E5897 /* LinkMailPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F550D5023DA4A9C007E5897 /* LinkMailPresenter.swift */; };
1516
3F550D5323DA4AC6007E5897 /* URLHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F550D5223DA4AC6007E5897 /* URLHandler.swift */; };
@@ -213,6 +214,7 @@
213214
1A21EE9722832BC200C940C6 /* WordPressComOAuthClientFacade+Swift.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "WordPressComOAuthClientFacade+Swift.swift"; sourceTree = "<group>"; };
214215
1A4095152271AEFC009AA86D /* WPAuthenticator-Swift.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "WPAuthenticator-Swift.h"; sourceTree = "<group>"; };
215216
276354F054C34AD36CA32AB6 /* Pods-WordPressAuthenticator.release-alpha.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressAuthenticator.release-alpha.xcconfig"; path = "Pods/Target Support Files/Pods-WordPressAuthenticator/Pods-WordPressAuthenticator.release-alpha.xcconfig"; sourceTree = "<group>"; };
217+
3108613025AFA4830022F75E /* PasteboardTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasteboardTests.swift; sourceTree = "<group>"; };
216218
33FEF45B466FF8EAAE5F3923 /* Pods-WordPressAuthenticator.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressAuthenticator.release.xcconfig"; path = "Pods/Target Support Files/Pods-WordPressAuthenticator/Pods-WordPressAuthenticator.release.xcconfig"; sourceTree = "<group>"; };
217219
37AFD4EF492B00CA7AEC11A3 /* Pods-WordPressAuthenticatorTests.release-alpha.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressAuthenticatorTests.release-alpha.xcconfig"; path = "Pods/Target Support Files/Pods-WordPressAuthenticatorTests/Pods-WordPressAuthenticatorTests.release-alpha.xcconfig"; sourceTree = "<group>"; };
218220
3F550D4D23DA429B007E5897 /* AppSelectorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSelectorTests.swift; sourceTree = "<group>"; };
@@ -535,6 +537,7 @@
535537
B501C03D208FC52500D1E58F /* Authenticator */ = {
536538
isa = PBXGroup;
537539
children = (
540+
3108613025AFA4830022F75E /* PasteboardTests.swift */,
538541
B501C03E208FC52500D1E58F /* WordPressAuthenticatorTests.swift */,
539542
CE16177721B70C1A00B82A47 /* WordPressAuthenticatorDisplayTextTests.swift */,
540543
BA53D64724DFDF97001F1ABF /* WordPressSourceTagTests.swift */,
@@ -1362,6 +1365,7 @@
13621365
BA53D64B24DFE07D001F1ABF /* WordpressAuthenticatorProvider.swift in Sources */,
13631366
CE16177821B70C1A00B82A47 /* WordPressAuthenticatorDisplayTextTests.swift in Sources */,
13641367
B501C048208FC79C00D1E58F /* LoginFacadeTests.m in Sources */,
1368+
3108613125AFA4830022F75E /* PasteboardTests.swift in Sources */,
13651369
D85C36F0256E118D00D56E34 /* NavigationToEnterAccountTests.swift in Sources */,
13661370
D85C36E6256E0DDE00D56E34 /* NavigationToEnterSiteTests.swift in Sources */,
13671371
D85C3882256E3FEC00D56E34 /* WordPressComSiteInfoTests.swift in Sources */,

WordPressAuthenticator/Authenticator/WordPressAuthenticator.swift

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -156,20 +156,34 @@ import WordPressKit
156156
/// - onLoginButtonTapped: Called when the login button on the prologue screen is tapped.
157157
/// - onCompletion: Called when the login UI presentation completes.
158158
public class func showLogin(from presenter: UIViewController, animated: Bool, showCancel: Bool = false, restrictToWPCom: Bool = false, onLoginButtonTapped: (() -> Void)? = nil, onCompletion: (() -> Void)? = nil) {
159-
defer {
160-
trackOpenedLogin()
159+
guard let loginViewController = loginUI(showCancel: showCancel, restrictToWPCom: restrictToWPCom, onLoginButtonTapped: onLoginButtonTapped) else {
160+
return
161161
}
162+
presenter.present(loginViewController, animated: animated, completion: onCompletion)
163+
trackOpenedLogin()
164+
}
162165

166+
/// Returns the view controller for the login flow.
167+
/// The caller is responsible for tracking `.openedLogin` event when displaying the view controller as in `showLogin`.
168+
///
169+
/// - Parameters:
170+
/// - showCancel: Whether a cancel CTA is shown on the login prologue screen.
171+
/// - restrictToWPCom: Whether only WordPress.com login is enabled.
172+
/// - onLoginButtonTapped: Called when the login button on the prologue screen is tapped.
173+
/// - Returns: The root view controller for the login flow.
174+
public class func loginUI(showCancel: Bool = false, restrictToWPCom: Bool = false, onLoginButtonTapped: (() -> Void)? = nil) -> UIViewController? {
163175
let storyboard = Storyboard.login.instance
164-
if let controller = storyboard.instantiateInitialViewController() {
165-
if let childController = controller.children.first as? LoginPrologueViewController {
166-
childController.loginFields.restrictToWPCom = restrictToWPCom
167-
childController.showCancel = showCancel
168-
childController.onLoginButtonTapped = onLoginButtonTapped
169-
}
170-
controller.modalPresentationStyle = .fullScreen
171-
presenter.present(controller, animated: animated, completion: onCompletion)
176+
guard let controller = storyboard.instantiateInitialViewController() else {
177+
assertionFailure("Cannot instantiate initial login controller from Login.storyboard")
178+
return nil
179+
}
180+
if let childController = controller.children.first as? LoginPrologueViewController {
181+
childController.loginFields.restrictToWPCom = restrictToWPCom
182+
childController.showCancel = showCancel
183+
childController.onLoginButtonTapped = onLoginButtonTapped
172184
}
185+
controller.modalPresentationStyle = .fullScreen
186+
return controller
173187
}
174188

175189
/// Used to present the new wpcom-only login flow from the app delegate

WordPressAuthenticator/Authenticator/WordPressAuthenticatorStyles.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ public struct WordPressAuthenticatorStyle {
3939

4040
public let disabledTitleColor: UIColor
4141

42+
/// Color of the spinner that is shown when a button is disabled.
43+
public let disabledButtonActivityIndicatorColor: UIColor
44+
4245
/// Style: Text Buttons
4346
///
4447
public let textButtonColor: UIColor
@@ -109,6 +112,7 @@ public struct WordPressAuthenticatorStyle {
109112
primaryTitleColor: UIColor,
110113
secondaryTitleColor: UIColor,
111114
disabledTitleColor: UIColor,
115+
disabledButtonActivityIndicatorColor: UIColor,
112116
textButtonColor: UIColor,
113117
textButtonHighlightColor: UIColor,
114118
instructionColor: UIColor,
@@ -139,6 +143,7 @@ public struct WordPressAuthenticatorStyle {
139143
self.primaryTitleColor = primaryTitleColor
140144
self.secondaryTitleColor = secondaryTitleColor
141145
self.disabledTitleColor = disabledTitleColor
146+
self.disabledButtonActivityIndicatorColor = disabledButtonActivityIndicatorColor
142147
self.textButtonColor = textButtonColor
143148
self.textButtonHighlightColor = textButtonHighlightColor
144149
self.instructionColor = instructionColor

WordPressAuthenticator/Extensions/UIPasteboard+Detect.swift

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,53 @@ extension UIPasteboard {
2525
}
2626
}
2727
}
28+
29+
/// Attempts to detect and return a authenticator code from the pasteboard.
30+
/// Expects to run on main thread.
31+
/// - Parameters:
32+
/// - completion: Called with a length digit authentication code on success
33+
@available(iOS 14.0, *)
34+
public func detectAuthenticatorCode(length: Int = 6, completion: @escaping (Result<String, Error>) -> Void) {
35+
UIPasteboard.general.detect(patterns: [.number]) { result in
36+
switch result {
37+
case .success(let detections):
38+
guard let firstMatch = detections.first else {
39+
completion(.success(""))
40+
return
41+
}
42+
guard let matchedNumber = firstMatch.value as? NSNumber else {
43+
completion(.success(""))
44+
return
45+
}
46+
47+
let authenticationCode = matchedNumber.stringValue
48+
49+
/// Reject numbers with decimal points or signs in them
50+
let codeCharacterSet = CharacterSet(charactersIn: authenticationCode)
51+
if !codeCharacterSet.isSubset(of: CharacterSet.decimalDigits) {
52+
completion(.success(""))
53+
return
54+
}
55+
56+
/// We need length digits. No more, no less.
57+
if authenticationCode.count > length {
58+
completion(.success(""))
59+
return
60+
} else if authenticationCode.count == length {
61+
completion(.success(authenticationCode))
62+
return
63+
}
64+
65+
let missingDigits = 6 - authenticationCode.count
66+
let paddingZeros = String(repeating: "0", count: missingDigits)
67+
let paddedAuthenticationCode = paddingZeros + authenticationCode
68+
69+
completion(.success(paddedAuthenticationCode))
70+
return
71+
case .failure(let error):
72+
completion(.failure(error))
73+
return
74+
}
75+
}
76+
}
2877
}

WordPressAuthenticator/NUX/NUXButton.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import WordPressKit
1212
open override var isEnabled: Bool {
1313
didSet {
1414
if #available(iOS 13, *) {
15-
activityIndicator.color = isEnabled ? style.primaryTitleColor : style.secondaryTitleColor
15+
activityIndicator.color = isEnabled ? style.primaryTitleColor : style.disabledButtonActivityIndicatorColor
1616
}
1717
}
1818
}

WordPressAuthenticator/Signin/Login2FAViewController.swift

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -296,14 +296,12 @@ class Login2FAViewController: LoginViewController, NUXKeyboardResponder, UITextF
296296
}
297297

298298
if #available(iOS 14.0, *) {
299-
UIPasteboard.general.detect(patterns: [.number]) { [weak self] result in
299+
UIPasteboard.general.detectAuthenticatorCode() { [weak self] result in
300300
switch result {
301-
case .success(let detections):
302-
if let pasteString = detections.first?.value as? String {
303-
self?.handle(code: pasteString)
304-
}
305-
case .failure:
306-
break
301+
case .success(let authenticatorCode):
302+
self?.handle(code: authenticatorCode)
303+
case .failure:
304+
break
307305
}
308306
}
309307
} else {

WordPressAuthenticator/Unified Auth/View Related/2FA/TwoFAViewController.swift

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -318,13 +318,10 @@ private extension TwoFAViewController {
318318
}
319319

320320
if #available(iOS 14.0, *) {
321-
UIPasteboard.general.detect(patterns: [.number]) { [weak self] result in
321+
UIPasteboard.general.detectAuthenticatorCode() { [weak self] result in
322322
switch result {
323-
case .success(let detections):
324-
if let pasteCode = detections.first?.value as? Int {
325-
let pasteString = String(pasteCode)
326-
self?.handle(code: pasteString, textField: codeField)
327-
}
323+
case .success(let authenticatorCode):
324+
self?.handle(code: authenticatorCode, textField: codeField)
328325
case .failure:
329326
break
330327
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import XCTest
2+
3+
class PasteboardTests: XCTestCase {
4+
let timeout = TimeInterval(3)
5+
6+
override class func tearDown() {
7+
super.tearDown()
8+
let pasteboard = UIPasteboard.general
9+
pasteboard.string = ""
10+
}
11+
12+
func testNominalAuthCode() throws {
13+
guard #available(iOS 14.0, *) else {
14+
throw XCTSkip("Unsupported iOS version")
15+
}
16+
17+
let expect = expectation(description: "Could read nominal auth code from pasteboard")
18+
let pasteboard = UIPasteboard.general
19+
pasteboard.string = "123456"
20+
21+
UIPasteboard.general.detectAuthenticatorCode() { result in
22+
switch result {
23+
case .success(let authenticationCode):
24+
XCTAssertEqual(authenticationCode, "123456")
25+
case .failure(_):
26+
XCTAssert(false)
27+
}
28+
expect.fulfill()
29+
}
30+
31+
waitForExpectations(timeout: timeout, handler: nil)
32+
}
33+
34+
func testLeadingZeroInAuthCodePreserved() throws {
35+
guard #available(iOS 14.0, *) else {
36+
throw XCTSkip("Unsupported iOS version")
37+
}
38+
39+
let expect = expectation(description: "Could read leading zero auth code from pasteboard")
40+
let pasteboard = UIPasteboard.general
41+
pasteboard.string = "012345"
42+
43+
UIPasteboard.general.detectAuthenticatorCode() { result in
44+
switch result {
45+
case .success(let authenticationCode):
46+
XCTAssertEqual(authenticationCode, "012345")
47+
case .failure(_):
48+
XCTAssert(false)
49+
}
50+
expect.fulfill()
51+
}
52+
53+
waitForExpectations(timeout: timeout, handler: nil)
54+
}}

WordPressAuthenticatorTests/Mocks/WordpressAuthenticatorProvider.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public class WordpressAuthenticatorProvider: NSObject {
3232
primaryTitleColor: UIColor.random(),
3333
secondaryTitleColor: UIColor.random(),
3434
disabledTitleColor: UIColor.random(),
35+
disabledButtonActivityIndicatorColor: UIColor.random(),
3536
textButtonColor: UIColor.random(),
3637
textButtonHighlightColor: UIColor.random(),
3738
instructionColor: UIColor.random(),

0 commit comments

Comments
 (0)