parent
9212a489a5
commit
ce03959fe9
|
|
@ -1,11 +1,9 @@
|
|||
PODS:
|
||||
- AppSwizzle (1.2)
|
||||
- ReCaptcha/Core (1.1):
|
||||
- Result (~> 3.0)
|
||||
- ReCaptcha/Core (1.1)
|
||||
- ReCaptcha/RxSwift (1.1):
|
||||
- ReCaptcha/Core
|
||||
- RxSwift (~> 4.0)
|
||||
- Result (3.2.4)
|
||||
- RxCocoa (4.1.1):
|
||||
- RxSwift (~> 4.0)
|
||||
- RxSwift (4.1.1)
|
||||
|
|
@ -31,8 +29,7 @@ CHECKOUT OPTIONS:
|
|||
|
||||
SPEC CHECKSUMS:
|
||||
AppSwizzle: bbd3782652fc426ce59c045a92ec61d36f261984
|
||||
ReCaptcha: 7a130e2765cf13af3223683400252fe7ae30ca7b
|
||||
Result: d2d07204ce72856f1fd9130bbe42c35a7b0fea10
|
||||
ReCaptcha: b94a673f3827e9b9cf7e77db0395694549241247
|
||||
RxCocoa: fd0862fd2df95fa55562ad28ffd2522c25eb4a85
|
||||
RxSwift: c6e3b1c7b325c7d121cd4327e9d98b7ed746b570
|
||||
SwiftLint: 2e4b89feed5909c42c3735bbd6745f4345c4b772
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
F231B39F1FED4A8C00F82943 /* ReCaptchaDecoder+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = F231B39E1FED4A8C00F82943 /* ReCaptchaDecoder+Helper.swift */; };
|
||||
F288E9451F9537760018688D /* ReCaptchaError+Equatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F288E9441F9537760018688D /* ReCaptchaError+Equatable.swift */; };
|
||||
F28FAC9F200E425600E14987 /* ReCaptcha_UITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F28FAC9E200E425600E14987 /* ReCaptcha_UITests.swift */; };
|
||||
F2AE8612204F3430002E28D7 /* ReCaptchaResult__Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2AE8611204F3430002E28D7 /* ReCaptchaResult__Tests.swift */; };
|
||||
F2E2685E1F7AEE3400CD876D /* ReCaptcha__Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2E2685D1F7AEE3400CD876D /* ReCaptcha__Tests.swift */; };
|
||||
F2ECCF8A1E9FCEFE0097B199 /* ReCaptchaDecoder__Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2ECCF891E9FCEFE0097B199 /* ReCaptchaDecoder__Tests.swift */; };
|
||||
F2ECCF8C1E9FE37C0097B199 /* mock.html in Resources */ = {isa = PBXBuildFile; fileRef = F2ECCF8B1E9FE37C0097B199 /* mock.html */; };
|
||||
|
|
@ -74,6 +75,7 @@
|
|||
F28FAC9C200E425600E14987 /* ReCaptcha_UITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ReCaptcha_UITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
F28FAC9E200E425600E14987 /* ReCaptcha_UITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReCaptcha_UITests.swift; sourceTree = "<group>"; };
|
||||
F28FACA0200E425600E14987 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
F2AE8611204F3430002E28D7 /* ReCaptchaResult__Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReCaptchaResult__Tests.swift; sourceTree = "<group>"; };
|
||||
F2E2685D1F7AEE3400CD876D /* ReCaptcha__Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReCaptcha__Tests.swift; sourceTree = "<group>"; };
|
||||
F2ECCF761E9FC47B0097B199 /* ReCaptcha_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ReCaptcha_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
F2ECCF7A1E9FC47B0097B199 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
|
|
@ -211,6 +213,7 @@
|
|||
F2ECCF8D1E9FE68C0097B199 /* ReCaptchaWebViewManager__Tests.swift */,
|
||||
F2E2685D1F7AEE3400CD876D /* ReCaptcha__Tests.swift */,
|
||||
F231B3961FEC325A00F82943 /* DispatchQueue__Tests.swift */,
|
||||
F2AE8611204F3430002E28D7 /* ReCaptchaResult__Tests.swift */,
|
||||
);
|
||||
path = Core;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -447,14 +450,12 @@
|
|||
inputPaths = (
|
||||
"${SRCROOT}/Pods/Target Support Files/Pods-ReCaptcha_Example/Pods-ReCaptcha_Example-frameworks.sh",
|
||||
"${BUILT_PRODUCTS_DIR}/ReCaptcha/ReCaptcha.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/Result/Result.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/RxCocoa/RxCocoa.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/RxSwift/RxSwift.framework",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ReCaptcha.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Result.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxCocoa.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxSwift.framework",
|
||||
);
|
||||
|
|
@ -595,6 +596,7 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
F2AE8612204F3430002E28D7 /* ReCaptchaResult__Tests.swift in Sources */,
|
||||
F2ECCF961EA00A5B0097B199 /* ReCaptchaWebViewManager+Helpers.swift in Sources */,
|
||||
F2ECCF8E1E9FE68C0097B199 /* ReCaptchaWebViewManager__Tests.swift in Sources */,
|
||||
F2ECCF981EA011370097B199 /* Result+Helpers.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@
|
|||
</BuildableReference>
|
||||
</TestableReference>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
skipped = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F28FAC9B200E425600E14987"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
//
|
||||
|
||||
import ReCaptcha
|
||||
import Result
|
||||
import RxCocoa
|
||||
import RxSwift
|
||||
import UIKit
|
||||
|
|
@ -79,7 +78,6 @@ class ViewController: UIViewController {
|
|||
.disposed(by: disposeBag)
|
||||
|
||||
validate
|
||||
.map { try $0.dematerialize() }
|
||||
.bind(to: label.rx.text)
|
||||
.disposed(by: disposeBag)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// ReCaptchaResult__Tests.swift
|
||||
// ReCaptcha
|
||||
//
|
||||
// Created by Flávio Caetano on 06/03/18.
|
||||
// Copyright © 2018 ReCaptcha. All rights reserved.
|
||||
//
|
||||
|
||||
@testable import ReCaptcha
|
||||
import XCTest
|
||||
|
||||
|
||||
class ReCaptchaResult__Tests: XCTestCase {
|
||||
func test__Get_Token() {
|
||||
let token = UUID().uuidString
|
||||
let result = ReCaptchaResult.token(token)
|
||||
|
||||
do {
|
||||
let value = try result.dematerialize()
|
||||
XCTAssertEqual(value, token)
|
||||
}
|
||||
catch let err {
|
||||
XCTFail(err.localizedDescription)
|
||||
}
|
||||
}
|
||||
|
||||
func test__Get_Token__Error() {
|
||||
let error = ReCaptchaError.random()
|
||||
let result = ReCaptchaResult.error(error)
|
||||
|
||||
do {
|
||||
_ = try result.dematerialize()
|
||||
XCTFail("Shouldn't have completed")
|
||||
}
|
||||
catch let err {
|
||||
XCTAssertEqual(err as? ReCaptchaError, error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
@testable import ReCaptcha
|
||||
|
||||
import Result
|
||||
import WebKit
|
||||
import XCTest
|
||||
|
||||
|
|
@ -36,7 +35,7 @@ class ReCaptchaWebViewManager__Tests: XCTestCase {
|
|||
|
||||
func test__Validate__Token() {
|
||||
let exp1 = expectation(description: "load token")
|
||||
var result1: ReCaptchaWebViewManager.Response?
|
||||
var result1: ReCaptchaResult?
|
||||
|
||||
// Validate
|
||||
let manager = ReCaptchaWebViewManager(messageBody: "{token: key}", apiKey: apiKey)
|
||||
|
|
@ -55,12 +54,12 @@ class ReCaptchaWebViewManager__Tests: XCTestCase {
|
|||
// Verify
|
||||
XCTAssertNotNil(result1)
|
||||
XCTAssertNil(result1?.error)
|
||||
XCTAssertEqual(result1?.value, apiKey)
|
||||
XCTAssertEqual(result1?.token, apiKey)
|
||||
|
||||
|
||||
// Validate again
|
||||
let exp2 = expectation(description: "reload token")
|
||||
var result2: ReCaptchaWebViewManager.Response?
|
||||
var result2: ReCaptchaResult?
|
||||
|
||||
// Validate
|
||||
manager.validate(on: presenterView) { response in
|
||||
|
|
@ -74,7 +73,7 @@ class ReCaptchaWebViewManager__Tests: XCTestCase {
|
|||
// Verify
|
||||
XCTAssertNotNil(result2)
|
||||
XCTAssertNil(result2?.error)
|
||||
XCTAssertEqual(result2?.value, apiKey)
|
||||
XCTAssertEqual(result2?.token, apiKey)
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -96,7 +95,7 @@ class ReCaptchaWebViewManager__Tests: XCTestCase {
|
|||
|
||||
|
||||
func test__Validate__Message_Error() {
|
||||
var result: ReCaptchaWebViewManager.Response?
|
||||
var result: ReCaptchaResult?
|
||||
let exp = expectation(description: "message error")
|
||||
|
||||
// Validate
|
||||
|
|
@ -115,11 +114,11 @@ class ReCaptchaWebViewManager__Tests: XCTestCase {
|
|||
// Verify
|
||||
XCTAssertNotNil(result)
|
||||
XCTAssertEqual(result?.error, .wrongMessageFormat)
|
||||
XCTAssertNil(result?.value)
|
||||
XCTAssertNil(result?.token)
|
||||
}
|
||||
|
||||
func test__Validate__JS_Error() {
|
||||
var result: ReCaptchaWebViewManager.Response?
|
||||
var result: ReCaptchaResult?
|
||||
let exp = expectation(description: "js error")
|
||||
|
||||
// Validate
|
||||
|
|
@ -138,7 +137,7 @@ class ReCaptchaWebViewManager__Tests: XCTestCase {
|
|||
// Verify
|
||||
XCTAssertNotNil(result)
|
||||
XCTAssertNotNil(result?.error)
|
||||
XCTAssertNil(result?.value)
|
||||
XCTAssertNil(result?.token)
|
||||
|
||||
switch result!.error! {
|
||||
case .unexpected(let error as NSError):
|
||||
|
|
@ -210,7 +209,7 @@ class ReCaptchaWebViewManager__Tests: XCTestCase {
|
|||
|
||||
func test__Key_Setup() {
|
||||
let exp = expectation(description: "setup key")
|
||||
var result: ReCaptchaWebViewManager.Response?
|
||||
var result: ReCaptchaResult?
|
||||
|
||||
// Validate
|
||||
let manager = ReCaptchaWebViewManager(messageBody: "{token: key}", apiKey: apiKey)
|
||||
|
|
@ -227,13 +226,13 @@ class ReCaptchaWebViewManager__Tests: XCTestCase {
|
|||
|
||||
XCTAssertNotNil(result)
|
||||
XCTAssertNil(result?.error)
|
||||
XCTAssertEqual(result?.value, apiKey)
|
||||
XCTAssertEqual(result?.token, apiKey)
|
||||
}
|
||||
|
||||
func test__Endpoint_Setup() {
|
||||
let exp = expectation(description: "setup endpoint")
|
||||
let endpoint = String(describing: arc4random())
|
||||
var result: ReCaptchaWebViewManager.Response?
|
||||
let endpoint = ReCaptcha.Endpoint.alternate.url
|
||||
var result: ReCaptchaResult?
|
||||
|
||||
let manager = ReCaptchaWebViewManager(messageBody: "{token: endpoint}", endpoint: endpoint)
|
||||
manager.configureWebView { _ in
|
||||
|
|
@ -249,14 +248,14 @@ class ReCaptchaWebViewManager__Tests: XCTestCase {
|
|||
|
||||
XCTAssertNotNil(result)
|
||||
XCTAssertNil(result?.error)
|
||||
XCTAssertEqual(result?.value, endpoint)
|
||||
XCTAssertEqual(result?.token, endpoint)
|
||||
}
|
||||
|
||||
// MARK: Reset
|
||||
|
||||
func test__Reset() {
|
||||
let exp1 = expectation(description: "fail on first execution")
|
||||
var result1: ReCaptchaWebViewManager.Response?
|
||||
var result1: ReCaptchaResult?
|
||||
|
||||
// Validate
|
||||
let manager = ReCaptchaWebViewManager(messageBody: "{token: key}", apiKey: apiKey, shouldFail: true)
|
||||
|
|
@ -275,7 +274,7 @@ class ReCaptchaWebViewManager__Tests: XCTestCase {
|
|||
|
||||
// Resets and tries again
|
||||
let exp2 = expectation(description: "validates after reset")
|
||||
var result2: ReCaptchaWebViewManager.Response?
|
||||
var result2: ReCaptchaResult?
|
||||
|
||||
manager.reset()
|
||||
manager.validate(on: presenterView, resetOnError: false) { result in
|
||||
|
|
@ -285,12 +284,13 @@ class ReCaptchaWebViewManager__Tests: XCTestCase {
|
|||
|
||||
waitForExpectations(timeout: 10)
|
||||
|
||||
XCTAssertEqual(result2?.value, apiKey)
|
||||
XCTAssertNil(result2?.error)
|
||||
XCTAssertEqual(result2?.token, apiKey)
|
||||
}
|
||||
|
||||
func test__Validate__Reset_On_Error() {
|
||||
let exp = expectation(description: "fail on first execution")
|
||||
var result: ReCaptchaWebViewManager.Response?
|
||||
var result: ReCaptchaResult?
|
||||
|
||||
// Validate
|
||||
let manager = ReCaptchaWebViewManager(messageBody: "{token: key}", apiKey: apiKey, shouldFail: true)
|
||||
|
|
@ -305,6 +305,8 @@ class ReCaptchaWebViewManager__Tests: XCTestCase {
|
|||
}
|
||||
|
||||
waitForExpectations(timeout: 10)
|
||||
XCTAssertEqual(result?.value, apiKey)
|
||||
|
||||
XCTAssertNil(result?.error)
|
||||
XCTAssertEqual(result?.token, apiKey)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,17 +6,17 @@
|
|||
// Copyright © 2018 ReCaptcha. All rights reserved.
|
||||
//
|
||||
|
||||
import Result
|
||||
@testable import ReCaptcha
|
||||
|
||||
|
||||
extension Result {
|
||||
var value: T? {
|
||||
guard case .success(let value) = self else { return nil }
|
||||
extension ReCaptchaResult {
|
||||
var token: String? {
|
||||
guard case .token(let value) = self else { return nil }
|
||||
return value
|
||||
}
|
||||
|
||||
var error: Error? {
|
||||
guard case .failure(let error) = self else { return nil }
|
||||
var error: ReCaptchaError? {
|
||||
guard case .error(let error) = self else { return nil }
|
||||
return error
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class ReCaptcha_Rx__Tests: XCTestCase {
|
|||
}
|
||||
|
||||
|
||||
var result: ReCaptchaWebViewManager.Response?
|
||||
var result: String?
|
||||
let exp = expectation(description: "validate token")
|
||||
|
||||
// Validate
|
||||
|
|
@ -65,9 +65,7 @@ class ReCaptcha_Rx__Tests: XCTestCase {
|
|||
waitForExpectations(timeout: 10)
|
||||
|
||||
// Verify
|
||||
XCTAssertNotNil(result)
|
||||
XCTAssertEqual(result?.value, apiKey)
|
||||
XCTAssertNil(result?.error)
|
||||
XCTAssertEqual(result, apiKey)
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -106,22 +104,22 @@ class ReCaptcha_Rx__Tests: XCTestCase {
|
|||
XCTFail("should not ask to configure the webview")
|
||||
}
|
||||
|
||||
|
||||
var result: ReCaptchaWebViewManager.Response?
|
||||
var result: ReCaptchaError?
|
||||
let exp = expectation(description: "validate token")
|
||||
|
||||
// Validate
|
||||
manager.rx.validate(on: presenterView, resetOnError: false)
|
||||
.subscribe { event in
|
||||
switch event {
|
||||
case .next(let value):
|
||||
result = value
|
||||
case .next:
|
||||
XCTFail("should not have validated")
|
||||
|
||||
case .error(let error):
|
||||
XCTFail(error.localizedDescription)
|
||||
result = error as? ReCaptchaError
|
||||
exp.fulfill()
|
||||
|
||||
case .completed:
|
||||
exp.fulfill()
|
||||
XCTFail("should not have completed")
|
||||
}
|
||||
}
|
||||
.disposed(by: disposeBag)
|
||||
|
|
@ -129,10 +127,7 @@ class ReCaptcha_Rx__Tests: XCTestCase {
|
|||
waitForExpectations(timeout: 10)
|
||||
|
||||
// Verify
|
||||
XCTAssertNotNil(result)
|
||||
XCTAssertNil(result?.value)
|
||||
XCTAssertNotNil(result?.error)
|
||||
XCTAssertEqual(result?.error, .wrongMessageFormat)
|
||||
XCTAssertEqual(result, .wrongMessageFormat)
|
||||
}
|
||||
|
||||
// MARK: Dispose
|
||||
|
|
@ -164,7 +159,6 @@ class ReCaptcha_Rx__Tests: XCTestCase {
|
|||
func test__Reset() {
|
||||
let exp1 = expectation(description: "fail on first execution")
|
||||
let exp2 = expectation(description: "resets after failure")
|
||||
var result1: ReCaptchaWebViewManager.Response?
|
||||
|
||||
// Validate
|
||||
let manager = ReCaptchaWebViewManager(messageBody: "{token: key}", apiKey: apiKey, shouldFail: true)
|
||||
|
|
@ -179,37 +173,33 @@ class ReCaptcha_Rx__Tests: XCTestCase {
|
|||
validate
|
||||
.subscribe { event in
|
||||
switch event {
|
||||
case .next(let value):
|
||||
result1 = value
|
||||
case .next:
|
||||
XCTFail("should not have validated")
|
||||
|
||||
case .error(let error):
|
||||
XCTFail(error.localizedDescription)
|
||||
case .error:
|
||||
exp1.fulfill()
|
||||
|
||||
case .completed:
|
||||
exp1.fulfill()
|
||||
XCTFail("should not have completed")
|
||||
}
|
||||
}
|
||||
.disposed(by: disposeBag)
|
||||
|
||||
// Resets after failure
|
||||
validate
|
||||
.flatMap { result -> Observable<Void> in
|
||||
switch result {
|
||||
case .failure: return .just(())
|
||||
default: return .empty()
|
||||
}
|
||||
}
|
||||
.catchErrorJustReturn("error")
|
||||
.filter { $0 == "error" }
|
||||
.map { _ in () }
|
||||
.take(1)
|
||||
.do(onCompleted: exp2.fulfill)
|
||||
.bind(to: manager.rx.reset)
|
||||
.disposed(by: disposeBag)
|
||||
|
||||
waitForExpectations(timeout: 10)
|
||||
XCTAssertEqual(result1?.error, .wrongMessageFormat)
|
||||
|
||||
// Resets and tries again
|
||||
let exp3 = expectation(description: "validates after reset")
|
||||
var result2: ReCaptchaWebViewManager.Response?
|
||||
var result2: String?
|
||||
|
||||
manager.rx.validate(on: presenterView, resetOnError: false)
|
||||
.subscribe { event in
|
||||
|
|
@ -227,12 +217,12 @@ class ReCaptcha_Rx__Tests: XCTestCase {
|
|||
.disposed(by: disposeBag)
|
||||
|
||||
waitForExpectations(timeout: 10)
|
||||
XCTAssertEqual(result2?.value, apiKey)
|
||||
XCTAssertEqual(result2, apiKey)
|
||||
}
|
||||
|
||||
func test__Validate__Reset_On_Error() {
|
||||
let exp = expectation(description: "executes after failure on first execution")
|
||||
var result: ReCaptchaWebViewManager.Response?
|
||||
var result: String?
|
||||
|
||||
// Validate
|
||||
let manager = ReCaptchaWebViewManager(messageBody: "{token: key}", apiKey: apiKey, shouldFail: true)
|
||||
|
|
@ -257,6 +247,6 @@ class ReCaptcha_Rx__Tests: XCTestCase {
|
|||
.disposed(by: disposeBag)
|
||||
|
||||
waitForExpectations(timeout: 10)
|
||||
XCTAssertEqual(result?.value, apiKey)
|
||||
XCTAssertEqual(result, apiKey)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ override func viewDidLoad() {
|
|||
|
||||
|
||||
func validate() {
|
||||
recaptcha?.validate(on: view) { [weak self] result in
|
||||
recaptcha?.validate(on: view) { [weak self] (result: ReCaptchaResult) in
|
||||
print(try? result.dematerialize())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
F24EA1E61F968403001DEC17 /* ReCaptcha.swift in Sources */ = {isa = PBXBuildFile; fileRef = F24EA1DE1F9683F5001DEC17 /* ReCaptcha.swift */; };
|
||||
F24EA1E71F968406001DEC17 /* recaptcha.html in Resources */ = {isa = PBXBuildFile; fileRef = F24EA1E01F9683F5001DEC17 /* recaptcha.html */; };
|
||||
F255FBEC1F8D5654002F5FA8 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F255FBEB1F8D5654002F5FA8 /* Result.framework */; };
|
||||
F2AE8614204F3B42002E28D7 /* ReCaptchaResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2AE8613204F3B41002E28D7 /* ReCaptchaResult.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
|
|
@ -51,6 +52,7 @@
|
|||
F24EA1DE1F9683F5001DEC17 /* ReCaptcha.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReCaptcha.swift; sourceTree = "<group>"; };
|
||||
F24EA1E01F9683F5001DEC17 /* recaptcha.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = recaptcha.html; sourceTree = "<group>"; };
|
||||
F255FBEB1F8D5654002F5FA8 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = "../ReCaptcha Carthage Test/Carthage/Build/iOS/Result.framework"; sourceTree = "<group>"; };
|
||||
F2AE8613204F3B41002E28D7 /* ReCaptchaResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReCaptchaResult.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
|
@ -147,6 +149,7 @@
|
|||
F24EA1D91F9683F5001DEC17 /* ReCaptchaWebViewManager.swift */,
|
||||
F24EA1DA1F9683F5001DEC17 /* String+Dict.swift */,
|
||||
F24EA1DB1F9683F5001DEC17 /* ReCaptchaError.swift */,
|
||||
F2AE8613204F3B41002E28D7 /* ReCaptchaResult.swift */,
|
||||
F231B3991FEC51C800F82943 /* DispatchQueue+Throttle.swift */,
|
||||
F24EA1DC1F9683F5001DEC17 /* Rx */,
|
||||
F24EA1DE1F9683F5001DEC17 /* ReCaptcha.swift */,
|
||||
|
|
@ -291,6 +294,7 @@
|
|||
files = (
|
||||
F24EA1E51F968403001DEC17 /* ReCaptchaError.swift in Sources */,
|
||||
F24EA1E21F968403001DEC17 /* ReCaptchaDecoder.swift in Sources */,
|
||||
F2AE8614204F3B42002E28D7 /* ReCaptchaResult.swift in Sources */,
|
||||
F24EA1E61F968403001DEC17 /* ReCaptcha.swift in Sources */,
|
||||
F24EA1E31F968403001DEC17 /* ReCaptchaWebViewManager.swift in Sources */,
|
||||
F24EA1E41F968403001DEC17 /* String+Dict.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ invisibility is not possible.
|
|||
s.subspec 'Core' do |core|
|
||||
core.source_files = 'ReCaptcha/Classes/*'
|
||||
core.frameworks = 'WebKit'
|
||||
core.dependency 'Result', '~> 3.0'
|
||||
|
||||
core.resource_bundles = {
|
||||
'ReCaptcha' => ['ReCaptcha/Assets/**/*']
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ open class ReCaptcha: ReCaptchaWebViewManager {
|
|||
/// Alternate endpoint. Points to https://www.recaptcha.net/recaptcha/api.js
|
||||
case alternate
|
||||
|
||||
fileprivate var url: String {
|
||||
internal var url: String {
|
||||
switch self {
|
||||
case .default: return "https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit"
|
||||
case .alternate: return "https://www.recaptcha.net/recaptcha/api.js?onload=onloadCallback&render=explicit"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
//
|
||||
// ReCaptchaWebViewManager.swift
|
||||
// ReCaptcha
|
||||
//
|
||||
// Created by Flávio Caetano on 06/03/17.
|
||||
// Copyright © 2018 ReCaptcha. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/** The ReCaptcha result.
|
||||
|
||||
This may contain the validation token on success, or an error that may have occurred.
|
||||
*/
|
||||
public enum ReCaptchaResult {
|
||||
/// The validation token.
|
||||
case token(String)
|
||||
|
||||
/// An error that may have occurred.
|
||||
case error(ReCaptchaError)
|
||||
|
||||
/**
|
||||
- returns: The validation token uppon success.
|
||||
|
||||
Tries to unwrap the Result and retrieve the token if it's successful.
|
||||
|
||||
- Throws: `ReCaptchaError`
|
||||
*/
|
||||
public func dematerialize() throws -> String {
|
||||
switch self {
|
||||
case .token(let token):
|
||||
return token
|
||||
|
||||
case .error(let error):
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,15 +7,12 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
import Result
|
||||
import WebKit
|
||||
|
||||
|
||||
/** Handles comunications with the webview containing the ReCaptcha challenge.
|
||||
*/
|
||||
open class ReCaptchaWebViewManager {
|
||||
public typealias Response = Result<String, ReCaptchaError>
|
||||
|
||||
/** The `webView` delegate object that performs execution uppon script loading
|
||||
*/
|
||||
fileprivate class WebViewDelegate: NSObject, WKNavigationDelegate {
|
||||
|
|
@ -98,7 +95,7 @@ open class ReCaptchaWebViewManager {
|
|||
}
|
||||
|
||||
/// Sends the result message
|
||||
fileprivate var completion: ((Response) -> Void)?
|
||||
fileprivate var completion: ((ReCaptchaResult) -> Void)?
|
||||
|
||||
/// Configures the webview for display when required
|
||||
fileprivate var configureWebView: ((WKWebView) -> Void)?
|
||||
|
|
@ -172,11 +169,11 @@ open class ReCaptchaWebViewManager {
|
|||
- parameters:
|
||||
- view: The view that should present the webview.
|
||||
- resetOnError: If ReCaptcha should be reset if it errors. Defaults to `true`.
|
||||
- completion: A closure that receives a Result<String, NSError> which may contain a valid result token.
|
||||
- completion: A closure that receives a ReCaptchaResult which may contain a valid result token.
|
||||
|
||||
Starts the challenge validation
|
||||
*/
|
||||
open func validate(on view: UIView, resetOnError: Bool = true, completion: @escaping (Response) -> Void) {
|
||||
open func validate(on view: UIView, resetOnError: Bool = true, completion: @escaping (ReCaptchaResult) -> Void) {
|
||||
self.completion = completion
|
||||
self.shouldResetOnError = resetOnError
|
||||
|
||||
|
|
@ -266,7 +263,7 @@ fileprivate extension ReCaptchaWebViewManager {
|
|||
func handle(result: ReCaptchaDecoder.Result) {
|
||||
switch result {
|
||||
case .token(let token):
|
||||
completion?(.success(token))
|
||||
completion?(.token(token))
|
||||
|
||||
case .error(let error):
|
||||
if shouldResetOnError, let view = webView.superview, let completion = completion {
|
||||
|
|
@ -274,7 +271,7 @@ fileprivate extension ReCaptchaWebViewManager {
|
|||
validate(on: view, completion: completion)
|
||||
}
|
||||
else {
|
||||
completion?(.failure(error))
|
||||
completion?(.error(error))
|
||||
}
|
||||
|
||||
case .showReCaptcha:
|
||||
|
|
|
|||
|
|
@ -22,18 +22,25 @@ public extension Reactive where Base: ReCaptchaWebViewManager {
|
|||
|
||||
Starts the challenge validation uppon subscription.
|
||||
|
||||
The stream's element is a `Result<String, ReCaptchaError>` that may contain a valid token.
|
||||
The stream's element is a String with the validation token.
|
||||
|
||||
Sends `stop()` uppon disposal.
|
||||
|
||||
- See: `ReCaptchaWebViewManager.validate(on:resetOnError:completion:)`
|
||||
- See: `ReCaptchaWebViewManager.stop()`
|
||||
*/
|
||||
func validate(on view: UIView, resetOnError: Bool = true) -> Observable<Base.Response> {
|
||||
return Observable<Base.Response>.create { [weak base] (observer: AnyObserver<Base.Response>) in
|
||||
base?.validate(on: view, resetOnError: resetOnError) { response in
|
||||
observer.onNext(response)
|
||||
observer.onCompleted()
|
||||
func validate(on view: UIView, resetOnError: Bool = true) -> Observable<String> {
|
||||
return Observable<String>.create { [weak base] (observer: AnyObserver<String>) in
|
||||
base?.validate(on: view, resetOnError: resetOnError) { result in
|
||||
defer { observer.onCompleted() }
|
||||
|
||||
switch result {
|
||||
case .token(let token):
|
||||
observer.onNext(token)
|
||||
|
||||
case .error(let error):
|
||||
observer.onError(error)
|
||||
}
|
||||
}
|
||||
|
||||
return Disposables.create { [weak base] in
|
||||
|
|
|
|||
|
|
@ -126,15 +126,15 @@ platform :ios do
|
|||
|
||||
# Private
|
||||
|
||||
def select_similar_simulator(args)
|
||||
args.map { |device_string|
|
||||
pieces = device_string.split(' (')
|
||||
FastlaneCore::Simulator.all
|
||||
.select { |s| s.name == pieces.first }
|
||||
.sort_by { |s| Gem::Version.create(s.os_version) }
|
||||
.detect { |s| Gem::Requirement.new(pieces[1].tr('()', '')).satisfied_by?(Gem::Version.create(s.os_version)) }
|
||||
}
|
||||
.compact
|
||||
.map { |s| "#{s.name} (#{s.ios_version})"}
|
||||
end
|
||||
def select_similar_simulator(args)
|
||||
args.map { |device_string|
|
||||
pieces = device_string.split(' (')
|
||||
FastlaneCore::Simulator.all
|
||||
.select { |s| s.name == pieces.first }
|
||||
.sort_by { |s| Gem::Version.create(s.os_version) }
|
||||
.detect { |s| Gem::Requirement.new(pieces[1].tr('()', '')).satisfied_by?(Gem::Version.create(s.os_version)) }
|
||||
}
|
||||
.compact
|
||||
.map { |s| "#{s.name} (#{s.ios_version})"}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue