Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update iOS and Android agents to 2.7.0, add sealedResults support #80

Merged
merged 10 commits into from
Dec 3, 2024
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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)"
}
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ class FpjsProPlugin: FlutterPlugin, MethodCallHandler {
fpjsClient.getVisitorId(
tags,
linkedId,
listener = {result -> listener(listOf(result.requestId, result.confidenceScore.score, result.asJson))},
listener = {result -> listener(listOf(result.requestId, result.confidenceScore.score, result.asJson, result.sealedResult ?: ""))},
errorListener = { error -> errorListener(getErrorCode(error), error.description.toString())}
)
}
Expand Down
10 changes: 5 additions & 5 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
@@ -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:
Expand All @@ -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

Expand Down
2 changes: 1 addition & 1 deletion example/ios/Runner/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import UIKit
import Flutter

@UIApplicationMain
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
Expand Down
8 changes: 7 additions & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,13 @@ class _MyAppState extends State<MyApp> {
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";
}
Expand Down
14 changes: 7 additions & 7 deletions example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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"
6 changes: 3 additions & 3 deletions example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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:
Expand All @@ -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
Expand Down
66 changes: 1 addition & 65 deletions example/web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,72 +34,8 @@
<script src="assets/packages/fpjs_pro_plugin/web/index.js" defer></script>
</head>
<body>
<!-- This script installs service_worker.js to provide PWA functionality to
application. For more information, see:
https://developers.google.com/web/fundamentals/primers/service-workers -->
<script>
var serviceWorkerVersion = null;
var scriptLoaded = false;
function loadMainDartJs() {
if (scriptLoaded) {
return;
}
scriptLoaded = true;
var scriptTag = document.createElement('script');
scriptTag.src = 'main.dart.js';
scriptTag.type = 'application/javascript';
document.body.append(scriptTag);
}

if ('serviceWorker' in navigator) {
// Service workers are supported. Use them.
window.addEventListener('load', function () {
// Wait for registration to finish before dropping the <script> tag.
// Otherwise, the browser will load the script multiple times,
// potentially different versions.
var serviceWorkerUrl = 'flutter_service_worker.js?v=' + serviceWorkerVersion;
navigator.serviceWorker.register(serviceWorkerUrl)
.then((reg) => {
function waitForActivation(serviceWorker) {
serviceWorker.addEventListener('statechange', () => {
if (serviceWorker.state == 'activated') {
console.log('Installed new service worker.');
loadMainDartJs();
}
});
}
if (!reg.active && (reg.installing || reg.waiting)) {
// No active web worker and we have installed or are installing
// one for the first time. Simply wait for it to activate.
waitForActivation(reg.installing || reg.waiting);
} else if (!reg.active.scriptURL.endsWith(serviceWorkerVersion)) {
// When the app updates the serviceWorkerVersion changes, so we
// need to ask the service worker to update.
console.log('New service worker available.');
reg.update();
waitForActivation(reg.installing);
} else {
// Existing service worker is still good.
console.log('Loading app from service worker.');
loadMainDartJs();
}
});

// If service worker doesn't succeed in a reasonable amount of time,
// fallback to plaint <script> tag.
setTimeout(() => {
if (!scriptLoaded) {
console.warn(
'Failed to load app from service worker. Falling back to plain <script> tag.',
);
loadMainDartJs();
}
}, 4000);
});
} else {
// Service workers not supported. Just drop the <script> tag.
loadMainDartJs();
}
{{flutter_bootstrap_js}}
</script>
</body>
</html>
3 changes: 2 additions & 1 deletion ios/Classes/SwiftFpjsProPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ public class SwiftFpjsProPlugin: NSObject, FlutterPlugin {
result([
visitorDataResponse.requestId,
visitorDataResponse.confidence,
visitorDataResponse.asJSON()
visitorDataResponse.asJSON(),
visitorDataResponse.sealedResult
])
case .failure(let error):
self.processNativeLibraryError(error, result: result)
Expand Down
2 changes: 1 addition & 1 deletion ios/fpjs_pro_plugin.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand Down
5 changes: 3 additions & 2 deletions lib/fpjs_pro_plugin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class FpjsProPlugin {

final String requestId = visitorDataTuple[0];
final num confidence = visitorDataTuple[1];
final String sealedResult = visitorDataTuple[3] ?? '';

Map<String, dynamic> visitorDataJson;
if (kIsWeb) {
Expand All @@ -91,9 +92,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) {
Expand Down
3 changes: 2 additions & 1 deletion lib/fpjs_pro_plugin_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ class FpjsProPluginWeb {
return [
typedResult.requestId,
typedResult.confidenceScore.score,
serializedResult
serializedResult,
typedResult.sealedResult ?? ''
];
} catch (e) {
if (e is WebException) {
Expand Down
4 changes: 4 additions & 0 deletions lib/js_agent_interop.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
20 changes: 14 additions & 6 deletions lib/result.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,31 @@ 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<String, dynamic> json, this.requestId, num confidence)
FingerprintJSProResponse.fromJson(Map<String, dynamic> json, this.requestId,
num confidence, this.sealedResult)
: visitorId = json['visitorId'],
confidenceScore = ConfidenceScore(confidence);

/// Creates class instance from JavaScript object
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;
Expand Down Expand Up @@ -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
Expand All @@ -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,
Expand Down
42 changes: 40 additions & 2 deletions test/fpjs_pro_plugin_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -72,7 +82,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;
});
Expand Down Expand Up @@ -102,4 +112,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);
});
});
}
Loading
Loading