Skip to content

Instantly share code, notes, and snippets.

@jkereako
Created September 8, 2020 13:15
Show Gist options
  • Save jkereako/d111ff6f4594873d409d3194371d6732 to your computer and use it in GitHub Desktop.
Save jkereako/d111ff6f4594873d409d3194371d6732 to your computer and use it in GitHub Desktop.
ReCAPTCHA v2 in Swift
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="https://www.google.com/recaptcha/api.js?onload=onLoad&render=explicit&hl=en" async defer></script>
<title></title>
<script type="text/javascript">
const post = function(value) {
window.webkit.messageHandlers.recaptcha.postMessage(value);
};
console.log = function(message) {
post(message);
};
var onLoad = function() {
grecaptcha.render(
"recaptcha",
{
sitekey: "${siteKey}",
callback: function(token) {
post(token);
},
size: "normal"
}
);
};
</script>
</head>
<body>
<div id="recaptcha"></div>
</body>
</html>
import UIKit
import WebKit
final class ReCAPTCHAViewController: UIViewController {
private var webView: WKWebView!
private let viewModel: ReCAPTCHAViewModel
init(viewModel: ReCAPTCHAViewModel) {
self.viewModel = viewModel
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func loadView() {
let webConfiguration = WKWebViewConfiguration()
let contentController = WKUserContentController()
contentController.add(viewModel, name: "recaptcha")
webConfiguration.userContentController = contentController
webView = WKWebView(frame: .zero, configuration: webConfiguration)
view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.leftBarButtonItem = UIBarButtonItem(
barButtonSystemItem: .close,
target: self,
action: #selector(didSelectCloseButton)
)
webView.loadHTMLString(viewModel.html, baseURL: viewModel.url)
}
}
// MARK: - Target-Actions
private extension ReCAPTCHAViewController {
@IBAction func didSelectCloseButton() {
dismiss(animated: true)
}
}
import WebKit
protocol ReCAPTCHAViewModelDelegate: class {
func didSolveCAPTCHA(token: String)
}
final class ReCAPTCHAViewModel: NSObject {
weak var delegate: ReCAPTCHAViewModelDelegate?
var html: String {
guard let filePath = Bundle.main.path(
forResource: "recaptcha", ofType: "html"
) else {
assertionFailure("Unable to find the file.")
return ""
}
let contents = try! String(
contentsOfFile: filePath, encoding: .utf8
)
return parse(contents, with: ["siteKey": siteKey])
}
let siteKey: String
let url: URL
/// Creates a ReCAPTCHAViewModel
/// - Parameters:
/// - siteKey: ReCAPTCHA's site key
/// - url: The URL for registered with Google
init(siteKey: String, url: URL) {
self.siteKey = siteKey
self.url = url
super.init()
}
}
// MARK: - WKScriptMessageHandler
extension ReCAPTCHAViewModel: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage) {
guard let message = message.body as? String else {
assertionFailure("Expected a string")
return
}
delegate?.didSolveCAPTCHA(token: message)
}
}
private extension ReCAPTCHAViewModel {
func parse(_ string: String, with valueMap: [String: String]) -> String {
var parsedString = string
valueMap.forEach { key, value in
parsedString = parsedString.replacingOccurrences(
of: "${\(key)}", with: value
)
}
return parsedString
}
}
@ZaynaxiOSDev
Copy link

Is this possible to generate a delegate method like didSolveCAPTCHA?

If yes, then how can I achieve that?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment