diff --git a/android/build.gradle b/android/build.gradle index 509e681..5eeeadd 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -53,5 +53,5 @@ android { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "com.fingerprint.android:pro:[2.6.0, 3.0.0)" + implementation "com.fingerprint.android:pro:[2.7.0, 3.0.0)" } diff --git a/android/src/main/kotlin/com/fingerprintjs/flutter/fpjs_pro/fpjs_pro_plugin/FpjsProPlugin.kt b/android/src/main/kotlin/com/fingerprintjs/flutter/fpjs_pro/fpjs_pro_plugin/FpjsProPlugin.kt index 5aaaa36..6a6927f 100644 --- a/android/src/main/kotlin/com/fingerprintjs/flutter/fpjs_pro/fpjs_pro_plugin/FpjsProPlugin.kt +++ b/android/src/main/kotlin/com/fingerprintjs/flutter/fpjs_pro/fpjs_pro_plugin/FpjsProPlugin.kt @@ -24,6 +24,7 @@ import com.fingerprintjs.android.fpjs_pro.UnsupportedVersion import com.fingerprintjs.android.fpjs_pro.InstallationMethodRestricted import com.fingerprintjs.android.fpjs_pro.ResponseCannotBeParsed import com.fingerprintjs.android.fpjs_pro.NetworkError +import com.fingerprintjs.android.fpjs_pro.ClientTimeout import com.fingerprintjs.android.fpjs_pro.UnknownError import io.flutter.embedding.engine.plugins.FlutterPlugin @@ -70,7 +71,8 @@ class FpjsProPlugin: FlutterPlugin, MethodCallHandler { GET_VISITOR_ID -> { val tags = call.argument>("tags") ?: emptyMap() val linkedId = call.argument("linkedId") ?: "" - getVisitorId(linkedId, tags, { visitorId -> + val timeoutMillis = call.argument("timeoutMs") + getVisitorId(timeoutMillis, linkedId, tags, { visitorId -> result.success(visitorId) }, { errorCode, errorMessage -> result.error(errorCode, errorMessage, null) @@ -79,7 +81,8 @@ class FpjsProPlugin: FlutterPlugin, MethodCallHandler { GET_VISITOR_DATA -> { val tags = call.argument>("tags") ?: emptyMap() val linkedId = call.argument("linkedId") ?: "" - getVisitorData(linkedId, tags, { getVisitorData -> + val timeoutMillis = call.argument("timeoutMs") + getVisitorData(timeoutMillis, linkedId, tags, { getVisitorData -> result.success(getVisitorData) }, { errorCode, errorMessage -> result.error(errorCode, errorMessage, null) @@ -110,31 +113,53 @@ class FpjsProPlugin: FlutterPlugin, MethodCallHandler { } private fun getVisitorId( + timeoutMillis: Int?, linkedId: String, tags: Map, listener: (String) -> Unit, errorListener: (String, String) -> (Unit) ) { - fpjsClient.getVisitorId( - tags, - linkedId, - listener = {result -> listener(result.visitorId)}, - errorListener = { error -> errorListener(getErrorCode(error), error.description.toString())} - ) + if (timeoutMillis != null) { + fpjsClient.getVisitorId( + timeoutMillis, + tags, + linkedId, + listener = { result -> listener(result.visitorId) }, + errorListener = { error -> errorListener(getErrorCode(error), error.description.toString()) } + ) + } else { + fpjsClient.getVisitorId( + tags, + linkedId, + listener = { result -> listener(result.visitorId) }, + errorListener = { error -> errorListener(getErrorCode(error), error.description.toString()) } + ) + } } private fun getVisitorData( + timeoutMillis: Int?, linkedId: String, tags: Map, listener: (List) -> Unit, errorListener: (String, String) -> (Unit) ) { - fpjsClient.getVisitorId( - tags, - linkedId, - listener = {result -> listener(listOf(result.requestId, result.confidenceScore.score, result.asJson))}, - errorListener = { error -> errorListener(getErrorCode(error), error.description.toString())} - ) + if (timeoutMillis != null) { + fpjsClient.getVisitorId( + timeoutMillis, + tags, + linkedId, + listener = {result -> listener(listOf(result.requestId, result.confidenceScore.score, result.asJson, result.sealedResult ?: ""))}, + errorListener = { error -> errorListener(getErrorCode(error), error.description.toString())} + ) + } else { + fpjsClient.getVisitorId( + tags, + linkedId, + listener = {result -> listener(listOf(result.requestId, result.confidenceScore.score, result.asJson, result.sealedResult ?: ""))}, + errorListener = { error -> errorListener(getErrorCode(error), error.description.toString())} + ) + } } } @@ -170,6 +195,7 @@ private fun getErrorCode(error: Error): String { is InstallationMethodRestricted -> "InstallationMethodRestricted" is ResponseCannotBeParsed -> "ResponseCannotBeParsed" is NetworkError -> "NetworkError" + is ClientTimeout -> "ClientTimeout" else -> "UnknownError" } return errorType diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 1d44918..8be8168 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,8 +1,8 @@ PODS: - - FingerprintPro (2.6.0) + - FingerprintPro (2.7.0) - Flutter (1.0.0) - - fpjs_pro_plugin (3.0.1): - - FingerprintPro (~> 2.6.0) + - fpjs_pro_plugin (3.2.0): + - FingerprintPro (< 3.0.0, >= 2.7.0) - Flutter DEPENDENCIES: @@ -20,9 +20,9 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/fpjs_pro_plugin/ios" SPEC CHECKSUMS: - FingerprintPro: 3f06f491c77d871ab543b49fd25fddc52dc34f8c + FingerprintPro: 0c7dbd28fc83751ca64b06328e2fb22bbc7ed118 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - fpjs_pro_plugin: 83f30abadcd58450a80c6ef5837f5e914d7ce238 + fpjs_pro_plugin: dd3cab1b0690f7504ee74f6707215c54d030d980 PODFILE CHECKSUM: 2f1a6d2470f392e010cfe7ae5f9f694d8487db82 diff --git a/example/ios/Runner/AppDelegate.swift b/example/ios/Runner/AppDelegate.swift index 70693e4..b636303 100644 --- a/example/ios/Runner/AppDelegate.swift +++ b/example/ios/Runner/AppDelegate.swift @@ -1,7 +1,7 @@ import UIKit import Flutter -@UIApplicationMain +@main @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, diff --git a/example/lib/main.dart b/example/lib/main.dart index 107168f..56eff5f 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -107,7 +107,13 @@ class _MyAppState extends State { const encoder = JsonEncoder.withIndent(' '); final deviceData = await FpjsProPlugin.getVisitorData( tags: tags, linkedId: 'some linkedId'); - identificationInfo = encoder.convert(deviceData); + final jsonDeviceData = deviceData.toJson(); + if (deviceData.sealedResult != null && + deviceData.sealedResult!.isNotEmpty) { + jsonDeviceData["sealedResult"] = deviceData.sealedResult + ?.replaceRange(10, deviceData.sealedResult?.length, '...'); + } + identificationInfo = encoder.convert(jsonDeviceData); } on FingerprintProError catch (error) { identificationInfo = "Failed to get device info.\n$error"; } @@ -130,6 +136,13 @@ class _MyAppState extends State { FpjsProPlugin.getVisitorId(linkedId: 'checkIdWithTag', tags: tags), () async => FpjsProPlugin.getVisitorData( linkedId: 'checkDataWithTag', tags: tags), + () async => FpjsProPlugin.getVisitorId(timeoutMs: 5000), + () async => FpjsProPlugin.getVisitorData(timeoutMs: 5000), + ]; + + var timeoutChecks = [ + () async => FpjsProPlugin.getVisitorId(timeoutMs: 5), + () async => FpjsProPlugin.getVisitorData(timeoutMs: 5) ]; for (var check in checks) { @@ -138,6 +151,16 @@ class _MyAppState extends State { _checksResult += '.'; }); } + for (var check in timeoutChecks) { + try { + await check(); + throw Exception('Expected timeout error'); + } on FingerprintProError { + setState(() { + _checksResult += '!'; + }); + } + } setState(() { _checksResult = 'Success!'; }); diff --git a/example/pubspec.lock b/example/pubspec.lock index fc8345b..03c909b 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -45,10 +45,10 @@ packages: dependency: "direct main" description: name: cupertino_icons - sha256: "1989d917fbe8e6b39806207df5a3fdd3d816cbd090fac2ce26fb45e9a71476e5" + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.8" env_flutter: dependency: "direct main" description: @@ -74,10 +74,10 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: b543301ad291598523947dc534aaddc5aaad597b709d2426d3a0e0d44c5cb493 + sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "5.0.0" flutter_test: dependency: "direct dev" description: flutter @@ -131,10 +131,10 @@ packages: dependency: transitive description: name: lints - sha256: a2c3d198cb5ea2e179926622d433331d8b58374ab8f29cdda6e863bd62fd369c + sha256: "3315600f3fb3b135be672bf4a178c55f274bebe368325ae18462c89ac1e3b413" url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "5.0.0" matcher: dependency: transitive description: @@ -237,5 +237,5 @@ packages: source: hosted version: "14.2.5" sdks: - dart: ">=3.3.0 <4.0.0" + dart: ">=3.5.0 <4.0.0" flutter: ">=3.18.0-18.0.pre.54" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index c4547db..464b359 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -17,7 +17,7 @@ environment: dependencies: flutter: sdk: flutter - env_flutter: ^0.1.3 + env_flutter: ^0.1.4 fpjs_pro_plugin: # When depending on this package from a real application you should use: @@ -29,7 +29,7 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.2 + cupertino_icons: ^1.0.8 dev_dependencies: flutter_test: @@ -40,7 +40,7 @@ dev_dependencies: # activated in the `analysis_options.yaml` file located at the root of your # package. See that file for information about deactivating specific lint # rules and activating additional ones. - flutter_lints: ^1.0.0 + flutter_lints: ^5.0.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/example/web/index.html b/example/web/index.html index ea63dbc..7b1d02a 100644 --- a/example/web/index.html +++ b/example/web/index.html @@ -34,72 +34,8 @@ - diff --git a/ios/Classes/FPJSError+Flutter.swift b/ios/Classes/FPJSError+Flutter.swift index 98245fa..9bb2352 100644 --- a/ios/Classes/FPJSError+Flutter.swift +++ b/ios/Classes/FPJSError+Flutter.swift @@ -19,6 +19,8 @@ extension FPJSError { return ("JsonParsingError", jsonParsingError.localizedDescription) case .invalidResponseType: return ("InvalidResponseType", description) + case .clientTimeout: + return ("ClientTimeout", description) case .unknownError: fallthrough @unknown default: diff --git a/ios/Classes/SwiftFpjsProPlugin.swift b/ios/Classes/SwiftFpjsProPlugin.swift index 2350ba0..a8477c2 100644 --- a/ios/Classes/SwiftFpjsProPlugin.swift +++ b/ios/Classes/SwiftFpjsProPlugin.swift @@ -30,10 +30,10 @@ public class SwiftFpjsProPlugin: NSObject, FlutterPlugin { } } else if (call.method == "getVisitorId") { let metadata = prepareMetadata(args["linkedId"] as? String, tags: args["tags"]) - getVisitorId(metadata, result) + getVisitorId(metadata, result, args["timeoutMs"] as? Double) } else if (call.method == "getVisitorData") { let metadata = prepareMetadata(args["linkedId"] as? String, tags: args["tags"]) - getVisitorData(metadata, result) + getVisitorData(metadata, result, args["timeoutMs"] as? Double) } } @@ -79,13 +79,13 @@ public class SwiftFpjsProPlugin: NSObject, FlutterPlugin { fpjsClient = FingerprintProFactory.getInstance(configuration) } - private func getVisitorId(_ metadata: Metadata?, _ result: @escaping FlutterResult) { + private func getVisitorId(_ metadata: Metadata?, _ result: @escaping FlutterResult, _ timeout: Double? = nil) { guard let client = fpjsClient else { result(FlutterError.init(code: "undefinedFpClient", message: "You need to call init method first", details: nil)) return } - client.getVisitorId(metadata) { visitorIdResult in + let completionHandler: FingerprintPro.VisitorIdBlock = { visitorIdResult in switch visitorIdResult { case .success(let visitorId): result(visitorId) @@ -93,26 +93,39 @@ public class SwiftFpjsProPlugin: NSObject, FlutterPlugin { self.processNativeLibraryError(error, result: result) } } + + if let timeout = timeout { + client.getVisitorId(metadata, timeout: timeout / 1000, completion: completionHandler) + } else { + client.getVisitorId(metadata, completion: completionHandler) + } } - private func getVisitorData(_ metadata: Metadata?, _ result: @escaping FlutterResult) { + private func getVisitorData(_ metadata: Metadata?, _ result: @escaping FlutterResult, _ timeout: Double? = nil) { guard let client = fpjsClient else { result(FlutterError(code: "undefinedFpClient", message: "You need to call init method first", details: nil)) return } - client.getVisitorIdResponse(metadata) { visitorIdResponseResult in + let completionHandler: FingerprintPro.VisitorIdResponseBlock = { visitorIdResponseResult in switch visitorIdResponseResult { case .success(let visitorDataResponse): result([ visitorDataResponse.requestId, visitorDataResponse.confidence, - visitorDataResponse.asJSON() + visitorDataResponse.asJSON(), + visitorDataResponse.sealedResult ]) case .failure(let error): self.processNativeLibraryError(error, result: result) } } + + if let timeout = timeout { + client.getVisitorIdResponse(metadata, timeout: timeout / 1000, completion: completionHandler) + } else { + client.getVisitorIdResponse(metadata, completion: completionHandler) + } } private func processNativeLibraryError(_ error: FPJSError, result: @escaping FlutterResult) { diff --git a/ios/fpjs_pro_plugin.podspec b/ios/fpjs_pro_plugin.podspec index 56c1749..089022d 100644 --- a/ios/fpjs_pro_plugin.podspec +++ b/ios/fpjs_pro_plugin.podspec @@ -15,7 +15,7 @@ Flutter plugin for FingerprintJS Pro. s.source = { :path => '.' } s.source_files = 'Classes/**/*' s.dependency 'Flutter' - s.dependency 'FingerprintPro', '~> 2.6.0' + s.dependency 'FingerprintPro', '>= 2.7.0', '< 3.0.0' s.platform = :ios, '13.0' diff --git a/lib/error.dart b/lib/error.dart index 30092c4..6e0e193 100644 --- a/lib/error.dart +++ b/lib/error.dart @@ -158,6 +158,11 @@ class UnknownError extends FingerprintProError { UnknownError(String? message) : super('UnknownError', message); } +/// ClientTimeout error +class ClientTimeoutError extends FingerprintProError { + ClientTimeoutError(String? message) : super('ClientTimeoutError', message); +} + /// Casts error from generic platform type to FingerprintProError FingerprintProError unwrapError(PlatformException error) { switch (error.code) { @@ -238,6 +243,9 @@ FingerprintProError unwrapError(PlatformException error) { return CspBlockError(error.message); case 'IntegrationFailureError': return IntegrationFailureError(error.message); + case 'ClientTimeout': + case 'ClientTimeoutError': + return ClientTimeoutError(error.message); default: return UnknownError(error.message); } diff --git a/lib/fpjs_pro_plugin.dart b/lib/fpjs_pro_plugin.dart index bffb6c5..86578ac 100644 --- a/lib/fpjs_pro_plugin.dart +++ b/lib/fpjs_pro_plugin.dart @@ -44,19 +44,20 @@ class FpjsProPlugin { } /// Returns the visitorId generated by the native Fingerprint Pro client - /// Support [tags](https://dev.fingerprint.com/docs/quick-start-guide#tagging-your-requests) - /// Support [linkedId](https://dev.fingerprint.com/docs/quick-start-guide#tagging-your-requests) + /// Support [tags](https://dev.fingerprint.com/reference/get-function#tag) + /// Support [linkedId](https://dev.fingerprint.com/reference/get-function#linkedid) + /// Support [timeoutMs](https://dev.fingerprint.com/reference/get-function#timeout) /// Throws a [FingerprintProError] if identification request fails for any reason static Future getVisitorId( - {Map? tags, String? linkedId}) async { + {Map? tags, String? linkedId, int? timeoutMs}) async { if (!_isInitialized) { throw Exception( 'You need to initialize the FPJS Client first by calling the "initFpjs" method'); } try { - final String? visitorId = await _channel - .invokeMethod('getVisitorId', {'linkedId': linkedId, 'tags': tags}); + final String? visitorId = await _channel.invokeMethod('getVisitorId', + {'linkedId': linkedId, 'tags': tags, 'timeoutMs': timeoutMs}); return visitorId; } on PlatformException catch (exception) { throw unwrapError(exception); @@ -64,22 +65,24 @@ class FpjsProPlugin { } /// Returns the visitor data generated by the native Fingerprint Pro client - /// Support [tags](https://dev.fingerprint.com/docs/quick-start-guide#tagging-your-requests) - /// Support [linkedId](https://dev.fingerprint.com/docs/quick-start-guide#tagging-your-requests) + /// Support [tags](https://dev.fingerprint.com/reference/get-function#tag) + /// Support [linkedId](https://dev.fingerprint.com/reference/get-function#linkedid) + /// Support [timeoutMs](https://dev.fingerprint.com/reference/get-function#timeout) /// Throws a [FingerprintProError] if identification request fails for any reason static Future getVisitorData( - {Map? tags, String? linkedId}) async { + {Map? tags, String? linkedId, int? timeoutMs}) async { if (!_isInitialized) { throw Exception( 'You need to initialize the FPJS Client first by calling the "initFpjs" method'); } try { - final visitorDataTuple = await _channel - .invokeMethod('getVisitorData', {'linkedId': linkedId, 'tags': tags}); + final visitorDataTuple = await _channel.invokeMethod('getVisitorData', + {'linkedId': linkedId, 'tags': tags, 'timeoutMs': timeoutMs}); final String requestId = visitorDataTuple[0]; final num confidence = visitorDataTuple[1]; + final String sealedResult = visitorDataTuple[3] ?? ''; Map visitorDataJson; if (kIsWeb) { @@ -91,9 +94,9 @@ class FpjsProPlugin { final visitorData = _isExtendedResult ? FingerprintJSProExtendedResponse.fromJson( - visitorDataJson, requestId, confidence) + visitorDataJson, requestId, confidence, sealedResult) : FingerprintJSProResponse.fromJson( - visitorDataJson, requestId, confidence); + visitorDataJson, requestId, confidence, sealedResult); return visitorData as T; } on PlatformException catch (exception) { diff --git a/lib/fpjs_pro_plugin_web.dart b/lib/fpjs_pro_plugin_web.dart index 6caa305..c408eba 100644 --- a/lib/fpjs_pro_plugin_web.dart +++ b/lib/fpjs_pro_plugin_web.dart @@ -42,11 +42,13 @@ class FpjsProPluginWeb { case 'getVisitorId': return getVisitorId( linkedId: call.arguments['linkedId'], - tags: getTags(call.arguments['tags'])); + tags: getTags(call.arguments['tags']), + timeoutMs: call.arguments['timeoutMs']); case 'getVisitorData': return getVisitorData( linkedId: call.arguments['linkedId'], - tags: getTags(call.arguments['tags'])); + tags: getTags(call.arguments['tags']), + timeoutMs: call.arguments['timeoutMs']); default: throw PlatformException( code: 'Unimplemented', @@ -96,8 +98,10 @@ class FpjsProPluginWeb { /// Returns the visitorId generated by the native Fingerprint Pro client /// Support [tags](https://dev.fingerprint.com/docs/quick-start-guide#tagging-your-requests) /// Support [linkedId](https://dev.fingerprint.com/docs/quick-start-guide#tagging-your-requests) + /// Support [timeoutMs](https://dev.fingerprint.com/reference/get-function#timeout) /// Throws a [FingerprintProError] if identification request fails for any reason - static Future getVisitorId({Object? tags, String? linkedId}) async { + static Future getVisitorId( + {Object? tags, String? linkedId, int? timeoutMs}) async { if (!_isInitialized) { throw Exception( 'You need to initialize the FPJS Client first by calling the "initFpjs" method'); @@ -105,8 +109,8 @@ class FpjsProPluginWeb { try { FingerprintJSAgent fp = await (_fpPromise as Future); - var result = await promiseToFuture( - fp.get(FingerprintJSGetOptions(linkedId: linkedId, tag: tags))); + var result = await promiseToFuture(fp.get(FingerprintJSGetOptions( + linkedId: linkedId, tag: tags, timeout: timeoutMs))); return result.visitorId; } catch (e) { if (e is WebException) { @@ -120,9 +124,10 @@ class FpjsProPluginWeb { /// Returns the visitor data generated by the native Fingerprint Pro client /// Support [tags](https://dev.fingerprint.com/docs/quick-start-guide#tagging-your-requests) /// Support [linkedId](https://dev.fingerprint.com/docs/quick-start-guide#tagging-your-requests) + /// Support [timeoutMs](https://dev.fingerprint.com/reference/get-function#timeout) /// Throws a [FingerprintProError] if identification request fails for any reason static Future> getVisitorData( - {Object? tags, String? linkedId}) async { + {Object? tags, String? linkedId, int? timeoutMs}) async { if (!_isInitialized) { throw Exception( 'You need to initialize the FPJS Client first by calling the "initFpjs" method'); @@ -130,7 +135,10 @@ class FpjsProPluginWeb { try { FingerprintJSAgent fp = await (_fpPromise as Future); final getOptions = FingerprintJSGetOptions( - linkedId: linkedId, tag: tags, extendedResult: _isExtendedResult); + linkedId: linkedId, + tag: tags, + timeout: timeoutMs, + extendedResult: _isExtendedResult); final IdentificationResult result = await promiseToFuture(fp.get(getOptions)); @@ -147,7 +155,8 @@ class FpjsProPluginWeb { return [ typedResult.requestId, typedResult.confidenceScore.score, - serializedResult + serializedResult, + typedResult.sealedResult ?? '' ]; } catch (e) { if (e is WebException) { diff --git a/lib/js_agent_interop.dart b/lib/js_agent_interop.dart index 692b8f9..bc1996a 100644 --- a/lib/js_agent_interop.dart +++ b/lib/js_agent_interop.dart @@ -62,6 +62,10 @@ class IdentificationResult { /// A confidence score that tells how much the agent is sure about the visitor identifier external IdentificationResultConfidenceScore confidence; + + /// Sealed result, which is an encrypted content of the `/events` Server API response for this requestId, encoded in + /// base64. The field will miss if Sealed Results are disabled or unavailable for another reason. + external String? sealedResult; } /// Result of requesting a visitor id when requested with `extendedResponseFormat: true` @@ -247,8 +251,16 @@ class FingerprintJSGetOptions { /// Adds details about the visitor to the result external bool extendedResult; + /// Controls client-side timeout. Client timeout controls total time (both client-side and server-side) that any + /// identification event is allowed to run. It doesn't include time when the page is in background (not visible). + /// The value is in milliseconds. + external int? get timeout; + external factory FingerprintJSGetOptions( - {Object? tag, String? linkedId, bool extendedResult = false}); + {Object? tag, + String? linkedId, + int? timeout, + bool extendedResult = false}); } /// Interop for JS Agent exceptions diff --git a/lib/result.dart b/lib/result.dart index 3e3ccc5..c9b30b9 100644 --- a/lib/result.dart +++ b/lib/result.dart @@ -14,10 +14,14 @@ class FingerprintJSProResponse { /// A confidence score that tells how much the agent is sure about the visitor identifier final ConfidenceScore confidenceScore; + /// Sealed result, which is an encrypted content of the `/events` Server API response for this requestId, encoded in + /// base64. The field will miss if Sealed Results are disabled or unavailable for another reason. + final String? sealedResult; + /// Creates class instance from JSON Object /// that can be returned by Android or iOS agent, or can be a serialization result - FingerprintJSProResponse.fromJson( - Map json, this.requestId, num confidence) + FingerprintJSProResponse.fromJson(Map json, this.requestId, + num confidence, this.sealedResult) : visitorId = json['visitorId'], confidenceScore = ConfidenceScore(confidence); @@ -25,14 +29,16 @@ class FingerprintJSProResponse { FingerprintJSProResponse.fromJsObject(dynamic jsObject) : visitorId = jsObject.visitorId, requestId = jsObject.requestId, - confidenceScore = ConfidenceScore(jsObject.confidence.score); + confidenceScore = ConfidenceScore(jsObject.confidence.score), + sealedResult = jsObject.sealedResult; /// Serialize instance to JSON Object Map toJson() { Map fromObject = { "requestId": requestId, "visitorId": visitorId, - "confidenceScore": confidenceScore.toJson() + "confidenceScore": confidenceScore.toJson(), + "sealedResult": sealedResult }; return fromObject; @@ -76,7 +82,7 @@ class FingerprintJSProExtendedResponse extends FingerprintJSProResponse { /// Creates class instance from JSON Object /// that can be returned by Android or iOS agent, or can be a serialization result FingerprintJSProExtendedResponse.fromJson( - super.json, super.requestId, super.confidence) + super.json, super.requestId, super.confidence, super.sealedResult) : visitorFound = json['visitorFound'], ipAddress = json['ip'] ?? json['ipAddress'], ipLocation = json['ipLocation'] != null @@ -95,7 +101,9 @@ class FingerprintJSProExtendedResponse extends FingerprintJSProResponse { FingerprintJSProExtendedResponse.fromJsObject(super.jsObject) : visitorFound = jsObject.visitorFound, ipAddress = jsObject.ip, - ipLocation = IpLocation.fromJsObject(jsObject.ipLocation), + ipLocation = jsObject.ipLocation + ? IpLocation.fromJsObject(jsObject.ipLocation) + : null, osName = jsObject.os, osVersion = jsObject.osVersion, device = jsObject.device, diff --git a/lib/web_error.dart b/lib/web_error.dart index 407cf98..c7790bc 100644 --- a/lib/web_error.dart +++ b/lib/web_error.dart @@ -29,7 +29,7 @@ FingerprintProError unwrapWebError(WebException error) { return FailedError(message); } if (message == FingerprintJS.ERROR_CLIENT_TIMEOUT) { - return RequestTimeoutError(message); + return ClientTimeoutError(message); } if (message == FingerprintJS.ERROR_SERVER_TIMEOUT) { return RequestTimeoutError(message); diff --git a/test/fpjs_pro_plugin_test.dart b/test/fpjs_pro_plugin_test.dart index d358491..0f17448 100644 --- a/test/fpjs_pro_plugin_test.dart +++ b/test/fpjs_pro_plugin_test.dart @@ -16,7 +16,17 @@ void main() { const getVisitorDataResponse = { "requestId": "test_request_id", "visitorId": "test_visitor_id", - "confidenceScore": {"score": 0.09} + "confidenceScore": {"score": 0.09}, + "sealedResult": '' + }; + + const sealedResult = 'test_sealed_result'; + + const getVisitorDataResponseWithSealedResult = { + "requestId": "test_request_id", + "visitorId": "test_visitor_id", + "confidenceScore": {"score": 0.09}, + "sealedResult": sealedResult }; TestWidgetsFlutterBinding.ensureInitialized(); @@ -47,6 +57,12 @@ void main() { .setMockMethodCallHandler(channel, null); }); + test('should return visitor id when called with timeout', () async { + await FpjsProPlugin.initFpjs(testApiKey); + final result = await FpjsProPlugin.getVisitorId(timeoutMs: 1000); + expect(result, testVisitorId); + }); + test('should return visitor id when called without tags', () async { await FpjsProPlugin.initFpjs(testApiKey); final result = await FpjsProPlugin.getVisitorId(); @@ -72,7 +88,7 @@ void main() { TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(channel, (MethodCall methodCall) async { if (methodCall.method == 'getVisitorData') { - return [requestId, confidence, extendedResultAsJsonString]; + return [requestId, confidence, extendedResultAsJsonString, null]; } return null; }); @@ -83,13 +99,19 @@ void main() { .setMockMethodCallHandler(channel, null); }); - test('should return visitor id when called without tags', () async { + test('should return visitor data when called with timeout', () async { + await FpjsProPlugin.initFpjs(testApiKey); + final result = await FpjsProPlugin.getVisitorData(timeoutMs: 1000); + expect(result.toJson(), getVisitorDataResponse); + }); + + test('should return visitor data when called without tags', () async { await FpjsProPlugin.initFpjs(testApiKey); final result = await FpjsProPlugin.getVisitorData(); expect(result.toJson(), getVisitorDataResponse); }); - test('should return visitor id when called with tags', () async { + test('should return visitor data when called with tags', () async { await FpjsProPlugin.initFpjs(testApiKey); final result = await FpjsProPlugin.getVisitorData( tags: {'sessionId': DateTime.now().millisecondsSinceEpoch}); @@ -102,4 +124,32 @@ void main() { expect(result.toJson(), getVisitorDataResponse); }); }); + + group('getVisitorDataSealed', () { + setUp(() { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(channel, (MethodCall methodCall) async { + if (methodCall.method == 'getVisitorData') { + return [ + requestId, + confidence, + extendedResultAsJsonString, + sealedResult + ]; + } + return null; + }); + }); + + tearDown(() { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(channel, null); + }); + + test('should return data with sealed result', () async { + await FpjsProPlugin.initFpjs(testApiKey); + final result = await FpjsProPlugin.getVisitorData(); + expect(result.toJson(), getVisitorDataResponseWithSealedResult); + }); + }); } diff --git a/test/result_test.dart b/test/result_test.dart index fc5052d..e237198 100644 --- a/test/result_test.dart +++ b/test/result_test.dart @@ -16,14 +16,15 @@ void main() { extendedJsonMock = { "requestId": requestId, - "confidenceScore": {"score": confidence} + "confidenceScore": {"score": confidence}, + "sealedResult": '' }; extendedJsonMock.addAll(jsonMock); }); test('Check success scenario with full data', () { - final responseInstance = - FingerprintJSProResponse.fromJson(jsonMock, requestId, confidence); + final responseInstance = FingerprintJSProResponse.fromJson( + jsonMock, requestId, confidence, ''); expect(responseInstance.toJson(), extendedJsonMock); }); @@ -31,7 +32,7 @@ void main() { jsonMock.remove("visitorId"); expect( () => FingerprintJSProResponse.fromJson( - jsonMock, requestId, confidence), + jsonMock, requestId, confidence, null), throwsA(isA())); }); }); @@ -75,7 +76,8 @@ void main() { "requestId": requestId, "confidenceScore": {"score": confidence}, "ipAddress": jsonMock["ip"], - "osName": jsonMock["os"] + "osName": jsonMock["os"], + "sealedResult": null, }; extendedJsonMock.addAll(jsonMock); extendedJsonMock.remove('ip'); @@ -84,7 +86,7 @@ void main() { test('Check success scenario with full data', () { final responseInstance = FingerprintJSProExtendedResponse.fromJson( - jsonMock, requestId, confidence); + jsonMock, requestId, confidence, null); expect(responseInstance.toJson(), extendedJsonMock); }); @@ -100,7 +102,7 @@ void main() { extendedJsonMock["lastSeenAt"] = seenAt; final responseInstance = FingerprintJSProExtendedResponse.fromJson( - jsonMock, requestId, confidence); + jsonMock, requestId, confidence, null); expect(responseInstance.toJson(), extendedJsonMock); }); @@ -108,7 +110,7 @@ void main() { jsonMock.remove("visitorId"); expect( () => FingerprintJSProExtendedResponse.fromJson( - jsonMock, requestId, confidence), + jsonMock, requestId, confidence, null), throwsA(isA())); }); @@ -116,16 +118,16 @@ void main() { jsonMock.remove("firstSeenAt"); expect( () => FingerprintJSProExtendedResponse.fromJson( - jsonMock, requestId, confidence), + jsonMock, requestId, confidence, null), throwsA(isA())); }); test('Check serialization and deserialization', () { final instance = FingerprintJSProExtendedResponse.fromJson( - jsonMock, requestId, confidence); + jsonMock, requestId, confidence, null); final serializedInstance = Map.from(instance.toJson()); final deSerializedInstance = FingerprintJSProExtendedResponse.fromJson( - serializedInstance, requestId, confidence); + serializedInstance, requestId, confidence, null); expect(deSerializedInstance.toJson(), extendedJsonMock); }); @@ -137,7 +139,7 @@ void main() { jsonMock.remove('os'); final responseInstance = FingerprintJSProExtendedResponse.fromJson( - jsonMock, requestId, confidence); + jsonMock, requestId, confidence, null); expect(responseInstance.toJson(), extendedJsonMock); }); @@ -145,7 +147,7 @@ void main() { jsonMock['ipLocation'] = {}; extendedJsonMock['ipLocation'] = {}; final responseInstance = FingerprintJSProExtendedResponse.fromJson( - jsonMock, requestId, confidence); + jsonMock, requestId, confidence, null); expect(responseInstance.toJson(), extendedJsonMock); }); @@ -153,7 +155,7 @@ void main() { jsonMock.remove('ipLocation'); extendedJsonMock['ipLocation'] = null; final responseInstance = FingerprintJSProExtendedResponse.fromJson( - jsonMock, requestId, confidence); + jsonMock, requestId, confidence, null); expect(responseInstance.toJson(), extendedJsonMock); }); }); diff --git a/web/index.js b/web/index.js index ebe7a03..d925d5b 100644 --- a/web/index.js +++ b/web/index.js @@ -1 +1 @@ -var FingerprintJSFlutter=function(e){"use strict";var t=function(){return t=Object.assign||function(e){for(var t,r=1,n=arguments.length;r0){var n=e[r].toLowerCase();n!==e[r]?t+=" "+n:t+=e[r]}else t+=e[r].toUpperCase();return t}var n={default:"endpoint"},o={default:"tlsEndpoint"},R=r("WrongRegion"),i=r("SubscriptionNotActive"),E=r("UnsupportedVersion"),u=r("InstallationMethodRestricted"),a=r("HostnameRestricted"),c=r("IntegrationFailed");function O(e,t){var r=[];return function(e,t){var r,n,o=(n=function(){for(var e=0,t=0,r=arguments.length;t=5)throw e;!function(e){if(!(e instanceof Error))return!1;var t=e.message;return"Blocked by CSP"===t||"9319"===t}(e)?o.postpone():o.exclude();var t,n=o.current();if(void 0===n)throw e;return(t=R(),new Promise((function(e){return setTimeout(e,t)}))).then((function(){return E(n,r+1)}))}))};return E(i,0)}(e,(function(e){var n=new Date,o=function(){return r.push({url:e,startedAt:n,finishedAt:new Date})},R=t(e);return R.then(o,o),R})).then((function(e){return[e,{attempts:r}]}))}var _="https://fpnpmcdn.net/v//loader_v.js",l=_,d="Failed to load the JS script of the agent";function f(e){var r;e.scriptUrlPattern;var n=e.token,o=e.apiKey,R=void 0===o?n:o,i=function(e,t){var r={};for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var o=0;for(n=Object.getOwnPropertySymbols(e);o]+>/g,(function(e){return""===e?"3":""===e?r(t):""===e?r("3.8.1"):e}))}(String(e),t)}))}(E,R),s).catch(p)})).then((function(e){var r=e[0],n=e[1];return r.load(t(t({},i),{ldi:n}))}))}function s(e){return function(e,t,r,n){var o,R=document,i="securitypolicyviolation",E=function(t){var r=new URL(e,location.href),n=t.blockedURI;n!==r.href&&n!==r.protocol.slice(0,-1)&&n!==r.origin||(o=t,u())};R.addEventListener(i,E);var u=function(){return R.removeEventListener(i,E)};return Promise.resolve().then(t).then((function(e){return u(),e}),(function(e){return new Promise((function(e){return setTimeout(e)})).then((function(){if(u(),o)return function(){throw new Error("Blocked by CSP")}();throw e}))}))}(e,(function(){return function(e){return new Promise((function(t,r){var n=document.createElement("script"),o=function(){var e;return null===(e=n.parentNode)||void 0===e?void 0:e.removeChild(n)},R=document.head||document.getElementsByTagName("head")[0];n.onload=function(){o(),t()},n.onerror=function(){o(),r(new Error(d))},n.async=!0,n.src=e,R.appendChild(n)}))}(e)})).then(I)}function I(){var e=window,t="__fpjs_p_l_b",r=e[t];if(function(e,t){var r,n=null===(r=Object.getOwnPropertyDescriptor)||void 0===r?void 0:r.call(Object,e,t);(null==n?void 0:n.configurable)?delete e[t]:n&&!n.writable||(e[t]=void 0)}(e,t),"function"!=typeof(null==r?void 0:r.load))throw new Error("9319");return r}function p(e){throw e instanceof Error&&"9319"===e.message?new Error(d):e}var N={load:f,defaultScriptUrlPattern:l,ERROR_SCRIPT_LOAD_FAIL:d,ERROR_API_KEY_EXPIRED:"API key expired",ERROR_API_KEY_INVALID:"API key not found",ERROR_API_KEY_MISSING:"API key required",ERROR_BAD_REQUEST_FORMAT:"Request cannot be parsed",ERROR_BAD_RESPONSE_FORMAT:"Response cannot be parsed",ERROR_CLIENT_TIMEOUT:"Client timeout",ERROR_CSP_BLOCK:"Blocked by CSP",ERROR_FORBIDDEN_ENDPOINT:a,ERROR_FORBIDDEN_HEADER:"Not available with restricted header",ERROR_FORBIDDEN_ORIGIN:"Not available for this origin",ERROR_GENERAL_SERVER_FAILURE:"Request failed",ERROR_INSTALLATION_METHOD_RESTRICTED:u,ERROR_INTEGRATION_FAILURE:c,ERROR_NETWORK_ABORT:"Network request aborted",ERROR_NETWORK_CONNECTION:"Network connection error",ERROR_RATE_LIMIT:"Too many requests, rate limit exceeded",ERROR_SERVER_TIMEOUT:"Request failed to process",ERROR_SUBSCRIPTION_NOT_ACTIVE:i,ERROR_TOKEN_EXPIRED:"API key expired",ERROR_TOKEN_INVALID:"API key not found",ERROR_TOKEN_MISSING:"API key required",ERROR_UNSUPPORTED_VERSION:E,ERROR_WRONG_REGION:R,defaultEndpoint:n,defaultTlsEndpoint:o},T=Object.freeze({__proto__:null,ERROR_API_KEY_EXPIRED:"API key expired",ERROR_API_KEY_INVALID:"API key not found",ERROR_API_KEY_MISSING:"API key required",ERROR_BAD_REQUEST_FORMAT:"Request cannot be parsed",ERROR_BAD_RESPONSE_FORMAT:"Response cannot be parsed",ERROR_CLIENT_TIMEOUT:"Client timeout",ERROR_CSP_BLOCK:"Blocked by CSP",ERROR_FORBIDDEN_ENDPOINT:a,ERROR_FORBIDDEN_HEADER:"Not available with restricted header",ERROR_FORBIDDEN_ORIGIN:"Not available for this origin",ERROR_GENERAL_SERVER_FAILURE:"Request failed",ERROR_INSTALLATION_METHOD_RESTRICTED:u,ERROR_INTEGRATION_FAILURE:c,ERROR_NETWORK_ABORT:"Network request aborted",ERROR_NETWORK_CONNECTION:"Network connection error",ERROR_RATE_LIMIT:"Too many requests, rate limit exceeded",ERROR_SCRIPT_LOAD_FAIL:d,ERROR_SERVER_TIMEOUT:"Request failed to process",ERROR_SUBSCRIPTION_NOT_ACTIVE:i,ERROR_TOKEN_EXPIRED:"API key expired",ERROR_TOKEN_INVALID:"API key not found",ERROR_TOKEN_MISSING:"API key required",ERROR_UNSUPPORTED_VERSION:E,ERROR_WRONG_REGION:R,default:N,defaultEndpoint:n,defaultScriptUrlPattern:l,defaultTlsEndpoint:o,load:f});return e.FingerprintJS=T,e}({}); +var FingerprintJSFlutter=function(e){"use strict";var t=function(){return t=Object.assign||function(e){for(var t,n=1,r=arguments.length;n0){var r=e[n].toLowerCase();r!==e[n]?t+=" ".concat(r):t+=e[n]}else t+=e[n].toUpperCase();return t}var O=c("WrongRegion"),_=c("SubscriptionNotActive"),l=c("UnsupportedVersion"),s=c("InstallationMethodRestricted"),f=c("HostnameRestricted"),p=c("IntegrationFailed"),d="API key required",I="API key not found",N="API key expired",T="Request cannot be parsed",v="Request failed",h="Request failed to process",A="Too many requests, rate limit exceeded",S="Not available for this origin",P="Not available with restricted header",D=d,y=I,w=N,m="Failed to load the JS script of the agent",L="9319";function g(e,t){var n,r,o,R,i,E=[],c=(n=function(e){var t=function(e,t,n){if(n||2===arguments.length)for(var r,o=0,R=t.length;o=5)throw i;var t=_(n,e);if(!t)throw i;var r,o=t[0],R=t[1];return(r=R,new Promise((function(e){return setTimeout(e,r)}))).then((function(){return l(o)}))}))};return l(O).then((function(e){return[e,E]}))}var U="https://fpnpmcdn.net/v//loader_v.js",b=U;function C(e){var n;e.scriptUrlPattern;var r=e.token,o=e.apiKey,R=void 0===o?r:o,i=function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var o=0;for(r=Object.getOwnPropertySymbols(e);o]+>/g,(function(e){return""===e?"3":""===e?n(t):""===e?n("3.11.3"):e}))}(String(e),t)}))}(E,R),K)})).catch((function(e){throw c(),function(e){return e instanceof Error&&e.message===L?new Error(m):e}(e)})).then((function(e){var n=e[0],r=e[1];return c(),n.load(t(t({},i),{ldi:{attempts:r,visibilityStates:u}}))}))}function K(e){return function(e,t,n,r){var o,R=document,i="securitypolicyviolation",E=function(t){var n=new URL(e,location.href),r=t.blockedURI;r!==n.href&&r!==n.protocol.slice(0,-1)&&r!==n.origin||(o=t,a())};R.addEventListener(i,E);var a=function(){return R.removeEventListener(i,E)};return null==r||r.then(a,a),Promise.resolve().then(t).then((function(e){return a(),e}),(function(e){return new Promise((function(e){var t=new MessageChannel;t.port1.onmessage=function(){return e()},t.port2.postMessage(null)})).then((function(){if(a(),o)return n(o);throw e}))}))}(e,(function(){return function(e){return new Promise((function(t,n){if(function(e){if(URL.prototype)try{return new URL(e,location.href),!1}catch(t){if(t instanceof Error&&"TypeError"===t.name)return!0;throw t}}(e))throw new Error(u);var r=document.createElement("script"),o=function(){var e;return null===(e=r.parentNode)||void 0===e?void 0:e.removeChild(r)},R=document.head||document.getElementsByTagName("head")[0];r.onload=function(){o(),t()},r.onerror=function(){o(),n(new Error(m))},r.async=!0,r.src=e,R.appendChild(r)}))}(e)}),(function(){throw new Error(a)})).then(M)}function M(){var e=window,t="__fpjs_p_l_b",n=e[t];if(function(e,t){var n,r=null===(n=Object.getOwnPropertyDescriptor)||void 0===n?void 0:n.call(Object,e,t);(null==r?void 0:r.configurable)?delete e[t]:r&&!r.writable||(e[t]=void 0)}(e,t),"function"!=typeof(null==n?void 0:n.load))throw new Error(L);return n}var F={load:C,defaultScriptUrlPattern:b,ERROR_SCRIPT_LOAD_FAIL:m,ERROR_API_KEY_EXPIRED:N,ERROR_API_KEY_INVALID:I,ERROR_API_KEY_MISSING:d,ERROR_BAD_REQUEST_FORMAT:T,ERROR_BAD_RESPONSE_FORMAT:E,ERROR_CLIENT_TIMEOUT:o,ERROR_CSP_BLOCK:a,ERROR_FORBIDDEN_ENDPOINT:f,ERROR_FORBIDDEN_HEADER:P,ERROR_FORBIDDEN_ORIGIN:S,ERROR_GENERAL_SERVER_FAILURE:v,ERROR_INSTALLATION_METHOD_RESTRICTED:s,ERROR_INTEGRATION_FAILURE:p,ERROR_INVALID_ENDPOINT:u,ERROR_NETWORK_ABORT:i,ERROR_NETWORK_CONNECTION:R,ERROR_RATE_LIMIT:A,ERROR_SERVER_TIMEOUT:h,ERROR_SUBSCRIPTION_NOT_ACTIVE:_,ERROR_TOKEN_EXPIRED:w,ERROR_TOKEN_INVALID:y,ERROR_TOKEN_MISSING:D,ERROR_UNSUPPORTED_VERSION:l,ERROR_WRONG_REGION:O,defaultEndpoint:n,defaultTlsEndpoint:r},B=Object.freeze({__proto__:null,ERROR_API_KEY_EXPIRED:N,ERROR_API_KEY_INVALID:I,ERROR_API_KEY_MISSING:d,ERROR_BAD_REQUEST_FORMAT:T,ERROR_BAD_RESPONSE_FORMAT:E,ERROR_CLIENT_TIMEOUT:o,ERROR_CSP_BLOCK:a,ERROR_FORBIDDEN_ENDPOINT:f,ERROR_FORBIDDEN_HEADER:P,ERROR_FORBIDDEN_ORIGIN:S,ERROR_GENERAL_SERVER_FAILURE:v,ERROR_INSTALLATION_METHOD_RESTRICTED:s,ERROR_INTEGRATION_FAILURE:p,ERROR_INVALID_ENDPOINT:u,ERROR_NETWORK_ABORT:i,ERROR_NETWORK_CONNECTION:R,ERROR_RATE_LIMIT:A,ERROR_SCRIPT_LOAD_FAIL:m,ERROR_SERVER_TIMEOUT:h,ERROR_SUBSCRIPTION_NOT_ACTIVE:_,ERROR_TOKEN_EXPIRED:w,ERROR_TOKEN_INVALID:y,ERROR_TOKEN_MISSING:D,ERROR_UNSUPPORTED_VERSION:l,ERROR_WRONG_REGION:O,default:F,defaultEndpoint:n,defaultScriptUrlPattern:b,defaultTlsEndpoint:r,load:C});return e.FingerprintJS=B,e}({}); diff --git a/web/package.json b/web/package.json index bcc672b..5b9dab3 100644 --- a/web/package.json +++ b/web/package.json @@ -9,7 +9,7 @@ "build": "rollup -c rollup.config.js" }, "dependencies": { - "@fingerprintjs/fingerprintjs-pro": "^3.8.1" + "@fingerprintjs/fingerprintjs-pro": "^3.11.3" }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.0.1", diff --git a/web/yarn.lock b/web/yarn.lock index 96b43d6..74f4228 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -23,12 +23,12 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@fingerprintjs/fingerprintjs-pro@^3.8.1": - version "3.8.1" - resolved "https://registry.yarnpkg.com/@fingerprintjs/fingerprintjs-pro/-/fingerprintjs-pro-3.8.1.tgz#b972659f1d341b7054106a3f27c5ba028f8f2ea2" - integrity sha512-hIpShbh75po8j7AQQ2a/avI/X4KCe/wXR9B8+yeK9UQpnADBcNBuSCaaBIQDmDoHCxCsS/2hma91dgwt/u+6cA== +"@fingerprintjs/fingerprintjs-pro@^3.11.3": + version "3.11.3" + resolved "https://registry.yarnpkg.com/@fingerprintjs/fingerprintjs-pro/-/fingerprintjs-pro-3.11.3.tgz#571e23ae84e92fe739aaf5b22e58a6786c86eb4f" + integrity sha512-ulpDKLT0bFcB8OcR3ppVUFRHMKTQRk45m0bTXmUEW4GytUcWbdKVZwQEvn5/jL9QKInVN1y09En4sBXk4JlaAQ== dependencies: - tslib "^2.0.1" + tslib "^2.4.1" "@jridgewell/gen-mapping@^0.3.0": version "0.3.2" @@ -511,10 +511,10 @@ terser@^5.0.0: commander "^2.20.0" source-map-support "~0.5.20" -tslib@^2.0.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" - integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== +tslib@^2.4.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== typescript@^4.9.3: version "4.9.3"