Skip to content

Commit

Permalink
Add SSL pinning feature
Browse files Browse the repository at this point in the history
  • Loading branch information
CAMOBAP committed Feb 8, 2022
1 parent 99e8e5c commit ed548a4
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 7 deletions.
1 change: 1 addition & 0 deletions Cartfile
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
github "ReactiveX/RxSwift" ~> 6.2.0
github "wultra/WultraSSLPinning"
12 changes: 12 additions & 0 deletions Example/HCaptcha.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -486,16 +486,22 @@
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-HCaptcha_Example/Pods-HCaptcha_Example-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/HCaptcha-Core-RxSwift/HCaptcha.framework",
"${BUILT_PRODUCTS_DIR}/PowerAuth2/PowerAuth2.framework",
"${BUILT_PRODUCTS_DIR}/RxCocoa/RxCocoa.framework",
"${BUILT_PRODUCTS_DIR}/RxRelay/RxRelay.framework",
"${BUILT_PRODUCTS_DIR}/RxSwift/RxSwift.framework",
"${BUILT_PRODUCTS_DIR}/WultraSSLPinning/WultraSSLPinning.framework",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/PowerAuthCore/PowerAuthCore.framework/PowerAuthCore",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/HCaptcha.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PowerAuth2.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxCocoa.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxRelay.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxSwift.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/WultraSSLPinning.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PowerAuthCore.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
Expand Down Expand Up @@ -598,10 +604,16 @@
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-HCaptcha_Objc_Example/Pods-HCaptcha_Objc_Example-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/HCaptcha-Core/HCaptcha.framework",
"${BUILT_PRODUCTS_DIR}/PowerAuth2/PowerAuth2.framework",
"${BUILT_PRODUCTS_DIR}/WultraSSLPinning/WultraSSLPinning.framework",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/PowerAuthCore/PowerAuthCore.framework/PowerAuthCore",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/HCaptcha.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PowerAuth2.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/WultraSSLPinning.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PowerAuthCore.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
Expand Down
18 changes: 16 additions & 2 deletions Example/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
PODS:
- AppSwizzle (1.3.1)
- HCaptcha/Core (2.0.0)
- HCaptcha/Core (2.0.0):
- WultraSSLPinning/PowerAuthIntegration
- HCaptcha/RxSwift (2.0.0):
- HCaptcha/Core
- RxSwift (~> 6.2.0)
- PowerAuth2 (1.6.2):
- PowerAuthCore (~> 1.6.2)
- PowerAuthCore (1.6.2)
- RxBlocking (6.2.0):
- RxSwift (= 6.2.0)
- RxCocoa (6.2.0):
Expand All @@ -13,6 +17,10 @@ PODS:
- RxSwift (= 6.2.0)
- RxSwift (6.2.0)
- SwiftLint (0.43.1)
- WultraSSLPinning/Lib (1.4.0)
- WultraSSLPinning/PowerAuthIntegration (1.4.0):
- PowerAuth2 (>= 1.6.0)
- WultraSSLPinning/Lib

DEPENDENCIES:
- AppSwizzle (~> 1.3)
Expand All @@ -25,24 +33,30 @@ DEPENDENCIES:
SPEC REPOS:
trunk:
- AppSwizzle
- PowerAuth2
- PowerAuthCore
- RxBlocking
- RxCocoa
- RxRelay
- RxSwift
- SwiftLint
- WultraSSLPinning

EXTERNAL SOURCES:
HCaptcha:
:path: "../"

SPEC CHECKSUMS:
AppSwizzle: db36e436f56110d93e5ae0147683435df593cabc
HCaptcha: a4c1efafe5a049c2db09d847736e369645d1079a
HCaptcha: 4ce547fc4e00a50fcad0d1a9811e67703dcdc0a1
PowerAuth2: 18365eda20a3aaec6e1d0d92679c7e90d646cc05
PowerAuthCore: 733c68b8f923d49304353ac5d7871ef49f948b38
RxBlocking: 0b29f7d2079109a8de49c411381bed7c33ef1eeb
RxCocoa: 4baf94bb35f2c0ab31bc0cb9f1900155f646ba42
RxRelay: e72dbfd157807478401ef1982e1c61c945c94b2f
RxSwift: d356ab7bee873611322f134c5f9ef379fa183d8f
SwiftLint: 99f82d07b837b942dd563c668de129a03fc3fb52
WultraSSLPinning: 73a73de4f89b0ac98154c3ef761ed6eee7760749

PODFILE CHECKSUM: 44657674683c7639f916ef6eb6fae5387395d652

Expand Down
2 changes: 2 additions & 0 deletions HCaptcha.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ invisibility is not possible.
core.source_files = 'HCaptcha/Classes/*'
core.frameworks = ['WebKit', 'JavaScriptCore']

core.dependency 'WultraSSLPinning/PowerAuthIntegration'

core.resource_bundles = {
'HCaptcha' => ['HCaptcha/Assets/**/*']
}
Expand Down
9 changes: 6 additions & 3 deletions HCaptcha/Classes/HCaptcha.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ public class HCaptcha: NSObject {
imghost: URL? = nil,
host: String? = nil,
theme: String = "light",
customTheme: String? = nil
customTheme: String? = nil,
sslPinning: Bool = false
) throws {
let infoDict = Bundle.main.infoDictionary

Expand All @@ -80,7 +81,8 @@ public class HCaptcha: NSObject {
imghost: imghost,
host: host,
theme: theme,
customTheme: customTheme)
customTheme: customTheme,
sslPinning: sslPinning)

self.init(manager: HCaptchaWebViewManager(
html: config.html,
Expand All @@ -89,7 +91,8 @@ public class HCaptcha: NSObject {
endpoint: config.getEndpointURL(locale: locale),
size: config.size,
rqdata: config.rqdata,
theme: config.actualTheme
theme: config.actualTheme,
sslPinning: config.sslPinning
))
}

Expand Down
7 changes: 6 additions & 1 deletion HCaptcha/Classes/HCaptchaConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ struct HCaptchaConfig {
self.customTheme ?? "\"\(theme)\""
}

/// Enable SSL pinning
let sslPinning: Bool

/// The Bundle that holds HCaptcha's assets
private static let bundle: Bundle = {
#if SWIFT_PACKAGE
Expand Down Expand Up @@ -144,7 +147,8 @@ struct HCaptchaConfig {
imghost: URL?,
host: String?,
theme: String,
customTheme: String?) throws {
customTheme: String?,
sslPinning: Bool) throws {
guard let filePath = HCaptchaConfig.bundle.path(forResource: "hcaptcha", ofType: "html") else {
throw HCaptchaError.htmlLoadError
}
Expand Down Expand Up @@ -187,6 +191,7 @@ struct HCaptchaConfig {
self.host = host
self.theme = theme
self.customTheme = customTheme
self.sslPinning = sslPinning
}

/**
Expand Down
14 changes: 13 additions & 1 deletion HCaptcha/Classes/HCaptchaWebViewManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import Foundation
import WebKit
import WultraSSLPinning


/** Handles comunications with the webview containing the HCaptcha challenge.
Expand Down Expand Up @@ -89,6 +90,12 @@ internal class HCaptchaWebViewManager {
/// Keep error If it happens before validate call
fileprivate var lastError: HCaptchaError?

/// Enable SSL pinning
fileprivate var sslPinning: Bool

/// SSL pinning aware navigation delegate
fileprivate let webViewNavDelegate = HCaptchaWebViewNavDelegate()

/// The webview that executes JS code
lazy var webView: WKWebView = {
let webview = WKWebView(
Expand All @@ -99,6 +106,10 @@ internal class HCaptchaWebViewManager {
webview.accessibilityTraits = UIAccessibilityTraits.link
webview.isHidden = true

if sslPinning {
webview.navigationDelegate = webViewNavDelegate
}

return webview
}()

Expand All @@ -113,8 +124,9 @@ internal class HCaptchaWebViewManager {
- theme: Widget theme, value must be valid JS Object or String with brackets
*/
init(html: String, apiKey: String, baseURL: URL, endpoint: URL,
size: HCaptchaSize, rqdata: String?, theme: String) {
size: HCaptchaSize, rqdata: String?, theme: String, sslPinning: Bool) {
self.baseURL = baseURL
self.sslPinning = sslPinning
self.decoder = HCaptchaDecoder { [weak self] result in
self?.handle(result: result)
}
Expand Down
30 changes: 30 additions & 0 deletions HCaptcha/Classes/HCaptchaWebViewNavDelegate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// HCaptchaWebViewNavDelegate.swift
// HCaptcha
//
// Copyright © 2022 HCaptcha. All rights reserved.
//

import Foundation
import WebKit
import WultraSSLPinning

class HCaptchaWebViewNavDelegate: UIResponder, WKNavigationDelegate {
fileprivate static var certStore: CertStore {
let publicKey = "BO47Jqs1wXV9dt1q1hMHuZzUPVzGNaPn9vUqRzleMiHAIYg+zZmktobi3nKVrtExIctL9f8aTdpfwhex21jbI9g="
let config = CertStoreConfiguration(serviceUrl: URL(string: "https://hcaptcha.com")!,
publicKey: publicKey)
return .powerAuthCertStore(configuration: config)
}

func webView(_ webView: WKWebView,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
switch HCaptchaWebViewNavDelegate.certStore.validate(challenge: challenge) {
case .trusted:
completionHandler(.performDefaultHandling, nil)
case .untrusted, .empty:
completionHandler(.cancelAuthenticationChallenge, nil)
}
}
}
1 change: 1 addition & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ let package = Package(
],
dependencies: [
.package(url: "https://github.com/ReactiveX/RxSwift", .upToNextMajor(from: "6.2.0"))
.package(url: "https://github.com/wultra/ssl-pinning-ios")
],
targets: [
.target(
Expand Down

0 comments on commit ed548a4

Please sign in to comment.