Compare commits

..

No commits in common. "master" and "1.4.2" have entirely different histories.

8 changed files with 11 additions and 112 deletions

View File

@ -1,13 +1,14 @@
--- ---
name: Bug report name: Bug report
about: Create a report to help us improve about: Create a report to help us improve
--- ---
<!-- <!--
## Is it really a bug? ## Is it really a bug?
Before opening an issue, check the following: Before opening an issue, check the following:
1. You are using the **SITE** key 1. You are using the **Client side integration** key
2. The correct domain, with protocol, is setup. 2. The correct domain, with protocol, is setup.
3. You are using an **Invisible** reCAPTCHA v2 key. 3. You are using an **Invisible** reCAPTCHA key.
4. If the widget doesn't appear, that is expected since the library will try to resolve the challenge _invisibly_. 4. If the widget doesn't appear, that is expected since the library will try to resolve the challenge _invisibly_.
https://www.google.com/recaptcha/admin#site https://www.google.com/recaptcha/admin#site
@ -19,7 +20,7 @@ A clear and concise description of what the bug is.
## To Reproduce ## To Reproduce
Steps to reproduce the behavior: Steps to reproduce the behavior:
1. Go to '...' 1. Go to '...'
2. Click on '...' 2. Click on '....'
3. ... 3. ...
4. Profit (jk See error) 4. Profit (jk See error)

View File

@ -1 +1 @@
binary "https://raw.github.com/TouchInstinct/CarthageBinaries/master/RxSwift/RxSwift.json" github "ReactiveX/RxSwift" ~> 4.3

View File

@ -1 +1 @@
binary "https://raw.github.com/TouchInstinct/CarthageBinaries/master/RxSwift/RxSwift.json" "4.5.0" github "ReactiveX/RxSwift" "4.4.0"

View File

@ -9,7 +9,7 @@
----- -----
Add Google's [Invisible ReCaptcha v2](https://developers.google.com/recaptcha/docs/invisible) to your project. This library Add Google's [Invisible ReCaptcha](https://developers.google.com/recaptcha/docs/invisible) to your project. This library
automatically handles ReCaptcha's events and retrieves the validation token or notifies you to present the challenge if automatically handles ReCaptcha's events and retrieves the validation token or notifies you to present the challenge if
invisibility is not possible. invisibility is not possible.
@ -17,15 +17,8 @@ invisibility is not possible.
#### _Warning_ ⚠️ #### _Warning_ ⚠️
Beware that this library only works for ReCaptcha v2 Invisible keys! Make sure to check the reCAPTCHA Beware that this library only works for Invisible ReCaptcha keys! Make sure to check the Invisible reCAPTCHA option
v2 Invisible badge option when creating your [API Key](https://www.google.com/recaptcha/admin/create). when creating your [API Key](https://www.google.com/recaptcha/admin).
![ReCaptcha v2 invisible key example](https://raw.githubusercontent.com/fjcaetano/ReCaptcha/master/example-v2-key.png)
You won't be able to use a ReCaptcha v3 key because it requires server-side validation. On v3, all
challenges succeed into a token which is then validated in the server for a score. For this reason,
a frontend app can't know on its own wether or not a user is valid since the challenge will always
result in a valid token.
## Installation ## Installation
@ -49,7 +42,7 @@ extension for the ReCaptcha framework.
## Usage ## Usage
Simply add `ReCaptchaKey` and `ReCaptchaDomain` (with a protocol ex. http:// or https://) to your Info.plist and run: Simply add `ReCaptchaKey` and `ReCaptchaDomain` (with a protocol) to your Info.plist and run:
``` swift ``` swift
let recaptcha = try? ReCaptcha() let recaptcha = try? ReCaptcha()

View File

@ -13,8 +13,6 @@ import WebKit
/** /**
*/ */
public class ReCaptcha { public class ReCaptcha {
public typealias BoolParameterClosure = (Bool) -> ()
fileprivate struct Constants { fileprivate struct Constants {
struct InfoDictKeys { struct InfoDictKeys {
static let APIKey = "ReCaptchaKey" static let APIKey = "ReCaptchaKey"
@ -103,12 +101,6 @@ public class ReCaptcha {
} }
} }
/// Callback for WebView loading state changing
public var onLoadingChanged: BoolParameterClosure? {
get { return manager.onLoadingChanged }
set { manager.onLoadingChanged = newValue }
}
/// The worker that handles webview events and communication /// The worker that handles webview events and communication
let manager: ReCaptchaWebViewManager let manager: ReCaptchaWebViewManager

View File

@ -18,13 +18,6 @@ internal class ReCaptchaWebViewManager {
static let ExecuteJSCommand = "execute();" static let ExecuteJSCommand = "execute();"
static let ResetCommand = "reset();" static let ResetCommand = "reset();"
static let BotUserAgent = "Googlebot/2.1" static let BotUserAgent = "Googlebot/2.1"
static let NumberOfDivsCommand = "document.getElementsByTagName(\"div\").length"
static let MinNumberOfDivs = 5
static let NumberOfDivsFinishedLoadingAttempts = 10
// A page doesn't have enough time to load on old devices
static let NumberOfDivsLoadingDelay = 0.5
} }
#if DEBUG #if DEBUG
@ -44,9 +37,6 @@ internal class ReCaptchaWebViewManager {
public var shouldSkipForTests = false public var shouldSkipForTests = false
#endif #endif
/// Callback for loading state changing
var onLoadingChanged: ReCaptcha.BoolParameterClosure?
/// Sends the result message /// Sends the result message
var completion: ((ReCaptchaResult) -> Void)? var completion: ((ReCaptchaResult) -> Void)?
@ -109,7 +99,6 @@ internal class ReCaptchaWebViewManager {
*/ */
init(html: String, apiKey: String, baseURL: URL, endpoint: String) { init(html: String, apiKey: String, baseURL: URL, endpoint: String) {
self.endpoint = endpoint self.endpoint = endpoint
self.decoder = ReCaptchaDecoder { [weak self] result in self.decoder = ReCaptchaDecoder { [weak self] result in
self?.handle(result: result) self?.handle(result: result)
} }
@ -137,7 +126,6 @@ internal class ReCaptchaWebViewManager {
Starts the challenge validation Starts the challenge validation
*/ */
func validate(on view: UIView) { func validate(on view: UIView) {
onLoadingChanged?(true)
#if DEBUG #if DEBUG
guard !shouldSkipForTests else { guard !shouldSkipForTests else {
completion?(.token("")) completion?(.token(""))
@ -178,7 +166,7 @@ internal class ReCaptchaWebViewManager {
/** Private methods for ReCaptchaWebViewManager /** Private methods for ReCaptchaWebViewManager
*/ */
fileprivate extension ReCaptchaWebViewManager { fileprivate extension ReCaptchaWebViewManager {
/** Executes the JS command that loads the ReCaptcha challenge after a page finished loading. /** Executes the JS command that loads the ReCaptcha challenge.
This method has no effect if the webview hasn't finished loading. This method has no effect if the webview hasn't finished loading.
*/ */
func execute() { func execute() {
@ -187,65 +175,10 @@ fileprivate extension ReCaptchaWebViewManager {
return return
} }
evaluateExecuteWhenLoadingFinished(count: 0)
}
/**
- parameter count: Number of checks of number of divs
Executes the JS command that returns number of divs.
*/
func evaluateExecuteWhenLoadingFinished(count: Int) {
webView.evaluateJavaScript(Constants.NumberOfDivsCommand) { [weak self] (result, error) -> Void in
if let error = error {
self?.decoder.send(error: .unexpected(error))
self?.onLoadingChanged?(false)
} else {
self?.handleNumberOfDivs(result: result, count: count)
}
}
}
/**
- parameters:
- result: Result of number of divs command evaluation
- count: Number of checks of divs count
Handles number of divs command result.
*/
func handleNumberOfDivs(result: Any?, count: Int) {
if let result = result as? Int, result >= Constants.MinNumberOfDivs {
evaluateExecute()
} else {
handleInvalidNumberOfDivsResult(count: count)
}
}
/**
- parameter count: Number of checks of number of divs
Handles invalid number of divs.
*/
func handleInvalidNumberOfDivsResult(count: Int) {
if count < Constants.NumberOfDivsFinishedLoadingAttempts {
DispatchQueue.main.asyncAfter(deadline: .now() + Constants.NumberOfDivsLoadingDelay) { [weak self] in
self?.evaluateExecuteWhenLoadingFinished(count: count + 1)
}
} else {
decoder.send(error: .htmlLoadError)
onLoadingChanged?(false)
}
}
/**
Executes the JS command that loads the ReCaptcha challenge.
*/
func evaluateExecute() {
webView.evaluateJavaScript(Constants.ExecuteJSCommand) { [weak self] _, error in webView.evaluateJavaScript(Constants.ExecuteJSCommand) { [weak self] _, error in
if let error = error { if let error = error {
self?.decoder.send(error: .unexpected(error)) self?.decoder.send(error: .unexpected(error))
} }
self?.onLoadingChanged?(false)
} }
} }

View File

@ -9,10 +9,6 @@
import RxSwift import RxSwift
import UIKit import UIKit
public enum ReCaptchaRxError: Error {
case baseWasReleased
}
/// Makes ReCaptcha compatible with RxSwift extensions /// Makes ReCaptcha compatible with RxSwift extensions
extension ReCaptcha: ReactiveCompatible {} extension ReCaptcha: ReactiveCompatible {}
@ -68,20 +64,4 @@ public extension Reactive where Base: ReCaptcha {
base?.reset() base?.reset()
} }
} }
/**
Observable of loading state
(will not work if someone changes onLoadingChanged variable; current onLodinglChanged will not work after subscription)
*/
var loadingObservable: Observable<Bool> {
return .create { [weak base] observer -> Disposable in
guard let base = base else {
observer.onError(ReCaptchaRxError.baseWasReleased)
return Disposables.create()
}
base.onLoadingChanged = { observer.onNext($0) }
return Disposables.create { [weak base] in base?.onLoadingChanged = nil }
}
}
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB