mirror of
https://github.com/selfxyz/self.git
synced 2026-04-27 03:01:15 -04:00
* feat: replace Sumsub with Didit JS SDK in webview-app - Add @didit-protocol/sdk-web, remove @sumsub/websdk - Create diditProvider.ts with session creation + SDK launch - Update ProviderLaunchScreen to use Didit embedded mode - Delete sumsubProvider.ts and sumsub-websdk.d.ts Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add Socket.IO attestation flow to webview KYC After Didit JS SDK completes, connect Socket.IO to the TEE, subscribe by sessionId, and wait for signed KYC data (attestation). Emit ack_success for session cleanup. Attach attestation to the provider result before navigating to the result screen. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: update TEE URL to kyc.self.xyz, update SDK test app README for Didit Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: only route KYC (Other IDs) to Didit provider, others to Coming Soon Passport, ID card, and Aadhaar require NFC/MRZ scanning which isn't available in the WebView. Only "Other IDs" goes through the Didit JS SDK flow. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: Didit SDK full-width rendering and KYC routing - Wire onNotListedPress to launch Didit for "View other supported IDs" - Remove verificationId gate from ProviderLaunchScreen - Switch to modal mode with CSS overrides for full-screen on mobile - Force .shadow-card to 100% width/height in WebView context Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add camera permissions and file upload to Android WebView Add WebChromeClient to AndroidWebViewHost: - onPermissionRequest: auto-grants camera for Didit SDK - onShowFileChooser: opens system file picker for document upload - SelfVerificationActivity handles file chooser result callback Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: gitignore Gradle build artifacts for native-shell-android Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add runtime camera permission and CAMERA manifest declaration - Add CAMERA permission to sdk-test-app AndroidManifest.xml - Request runtime camera permission in onPermissionRequest before granting - Handle permission result in SelfVerificationActivity - Store pending PermissionRequest for async grant/deny after user response Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix ios camera * fix: address CodeRabbit review findings - Replace ngrok URL with kyc.self.xyz in Android and iOS test apps - Fix file chooser hang when context is not an Activity - Move NSCameraUsageDescription to project.yml (survives xcodegen regen) - Delete manual Info.plist that would be overwritten Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: replace ngrok URL with kyc.self.xyz in diditProvider and diditAttestation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: explicitly disable Didit SDK debug logging Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: webview lint * fix: validate origin and handle audio permission in WebView permission grants - Deny permission requests from untrusted origins - Deny instead of grant when context is not an Activity - Handle RECORD_AUDIO alongside CAMERA for liveness checks - Add RECORD_AUDIO to AndroidManifest.xml Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: seshanthS <seshanth@protonmail.com>
100 lines
3.1 KiB
Swift
100 lines
3.1 KiB
Swift
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
import Foundation
|
|
import UIKit
|
|
import WebKit
|
|
|
|
final class SelfWebViewHost: NSObject {
|
|
private var webView: WKWebView?
|
|
private let router: MessageRouter
|
|
private let isDebugMode: Bool
|
|
|
|
init(router: MessageRouter, isDebugMode: Bool = false) {
|
|
self.router = router
|
|
self.isDebugMode = isDebugMode
|
|
super.init()
|
|
}
|
|
|
|
func createWebView() -> WKWebView {
|
|
let config = WKWebViewConfiguration()
|
|
let contentController = WKUserContentController()
|
|
contentController.add(WeakScriptMessageProxy(handler: self), name: "SelfNativeIOS")
|
|
config.userContentController = contentController
|
|
config.preferences.javaScriptCanOpenWindowsAutomatically = false
|
|
config.allowsInlineMediaPlayback = true
|
|
config.mediaTypesRequiringUserActionForPlayback = []
|
|
|
|
let webView = WKWebView(frame: .zero, configuration: config)
|
|
webView.scrollView.bounces = false
|
|
webView.isOpaque = false
|
|
webView.backgroundColor = .clear
|
|
|
|
if #available(iOS 16.4, *) {
|
|
webView.isInspectable = isDebugMode
|
|
}
|
|
|
|
self.webView = webView
|
|
return webView
|
|
}
|
|
|
|
func loadContent(queryParams: String) {
|
|
guard let webView = webView else { return }
|
|
|
|
if isDebugMode {
|
|
let urlString = "http://localhost:5173?\(queryParams)"
|
|
if let url = URL(string: urlString) {
|
|
webView.load(URLRequest(url: url))
|
|
}
|
|
} else {
|
|
guard let bundlePath = Bundle.module.path(forResource: "self-sdk-web", ofType: nil) else {
|
|
return
|
|
}
|
|
let fileURL = URL(fileURLWithPath: "\(bundlePath)/index.html")
|
|
let bundleURL = URL(fileURLWithPath: bundlePath)
|
|
|
|
var components = URLComponents(url: fileURL, resolvingAgainstBaseURL: false)
|
|
if !queryParams.isEmpty {
|
|
components?.query = queryParams
|
|
}
|
|
let targetURL = components?.url ?? fileURL
|
|
|
|
webView.loadFileURL(targetURL, allowingReadAccessTo: bundleURL)
|
|
}
|
|
}
|
|
|
|
func evaluateJs(_ js: String) {
|
|
DispatchQueue.main.async { [weak self] in
|
|
self?.webView?.evaluateJavaScript(js, completionHandler: nil)
|
|
}
|
|
}
|
|
}
|
|
|
|
extension SelfWebViewHost: WKScriptMessageHandler {
|
|
func userContentController(
|
|
_ userContentController: WKUserContentController,
|
|
didReceive message: WKScriptMessage
|
|
) {
|
|
guard message.name == "SelfNativeIOS",
|
|
let body = message.body as? String else {
|
|
return
|
|
}
|
|
router.onMessageReceived(rawJson: body)
|
|
}
|
|
}
|
|
|
|
// Prevents WKWebView retain cycle with WKScriptMessageHandler
|
|
private final class WeakScriptMessageProxy: NSObject, WKScriptMessageHandler {
|
|
private weak var handler: WKScriptMessageHandler?
|
|
|
|
init(handler: WKScriptMessageHandler) {
|
|
self.handler = handler
|
|
}
|
|
|
|
func userContentController(
|
|
_ userContentController: WKUserContentController,
|
|
didReceive message: WKScriptMessage
|
|
) {
|
|
handler?.userContentController(userContentController, didReceive: message)
|
|
}
|
|
}
|