From e1c84e3178c93e6d20dfb37cb3c3c8a0be059499 Mon Sep 17 00:00:00 2001 From: Sergey Shelomentsev Date: Wed, 31 Jul 2024 12:05:36 +0300 Subject: [PATCH 01/17] chore: update path to mocks --- scripts/sync.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/sync.sh b/scripts/sync.sh index 944a0a7..cafc606 100755 --- a/scripts/sync.sh +++ b/scripts/sync.sh @@ -18,7 +18,7 @@ examplesList=( ) for example in ${examplesList[*]}; do - curl -o ./src/test/resources/mocks/"$example" https://fingerprintjs.github.io/fingerprint-pro-server-api-openapi/examples/"$example" + curl -o ./sdk/src/test/resources/mocks/"$example" https://fingerprintjs.github.io/fingerprint-pro-server-api-openapi/examples/"$example" done ./scripts/generate.sh From a084521dba30703b0d6bd30d5ac1100909cd5308 Mon Sep 17 00:00:00 2001 From: Sergey Shelomentsev Date: Wed, 31 Jul 2024 17:47:14 +0300 Subject: [PATCH 02/17] ci: update version replacer chore: fix sed chore: no backup file in sed --- scripts/generate.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/generate.sh b/scripts/generate.sh index 7a9daed..5e1ccc1 100755 --- a/scripts/generate.sh +++ b/scripts/generate.sh @@ -19,6 +19,7 @@ fi echo "VERSION: $VERSION" -sed -i "s/projectVersion: .*/projectVersion: $VERSION/g" gradle.properties -sed -i "s/^VERSION=.*/VERSION='$VERSION'/g" ./scripts/generate.sh +sed -i '' -e "s/projectVersion = .*$/projectVersion = $VERSION/g" ./gradle.properties +sed -i '' -e "s/^VERSION=.*$/VERSION='$VERSION'/g" ./scripts/generate.sh + ./gradlew build test From f46e2428884059b1535d72589c8c23b4b61a2282 Mon Sep 17 00:00:00 2001 From: Sergey Shelomentsev Date: Wed, 31 Jul 2024 17:58:41 +0300 Subject: [PATCH 03/17] feat: add `remoteControl`, `velocity` and `developerTools` signals --- docs/DeveloperToolsResult.md | 13 ++ docs/ErrorUpdateEvent400Response.md | 13 ++ docs/ErrorUpdateEvent400ResponseError.md | 22 ++ docs/ErrorUpdateEvent409Response.md | 13 ++ docs/ErrorUpdateEvent409ResponseError.md | 21 ++ docs/ErrorVisitor400Response.md | 13 ++ docs/ErrorVisitor400ResponseError.md | 21 ++ docs/ErrorVisitor404Response.md | 13 ++ docs/ErrorVisitor404ResponseError.md | 21 ++ docs/EventUpdateRequest.md | 15 ++ docs/FactoryResetResult.md | 4 +- docs/FingerprintApi.md | 89 +++++++- docs/ProductsResponse.md | 3 + docs/RemoteControlResult.md | 13 ++ docs/SignalResponseDeveloperTools.md | 14 ++ docs/SignalResponseRemoteControl.md | 14 ++ docs/SignalResponseVelocity.md | 14 ++ docs/VelocityIntervalResult.md | 16 ++ docs/VelocityIntervals.md | 13 ++ docs/VelocityResult.md | 17 ++ docs/WebhookVisit.md | 3 + .../com/fingerprint/api/FingerprintApi.java | 97 ++++++++- .../model/DeveloperToolsResult.java | 97 +++++++++ .../model/ErrorUpdateEvent400Response.java | 98 +++++++++ .../ErrorUpdateEvent400ResponseError.java | 164 +++++++++++++++ .../model/ErrorUpdateEvent409Response.java | 98 +++++++++ .../ErrorUpdateEvent409ResponseError.java | 162 +++++++++++++++ .../model/ErrorVisitor400Response.java | 98 +++++++++ .../model/ErrorVisitor400ResponseError.java | 163 +++++++++++++++ .../model/ErrorVisitor404Response.java | 98 +++++++++ .../model/ErrorVisitor404ResponseError.java | 162 +++++++++++++++ .../fingerprint/model/EventUpdateRequest.java | 161 +++++++++++++++ .../fingerprint/model/FactoryResetResult.java | 8 +- .../fingerprint/model/ProductsResponse.java | 105 +++++++++- .../model/RemoteControlResult.java | 97 +++++++++ .../model/SignalResponseDeveloperTools.java | 131 ++++++++++++ .../model/SignalResponseRemoteControl.java | 131 ++++++++++++ .../model/SignalResponseVelocity.java | 131 ++++++++++++ .../model/VelocityIntervalResult.java | 161 +++++++++++++++ .../fingerprint/model/VelocityIntervals.java | 98 +++++++++ .../com/fingerprint/model/VelocityResult.java | 194 ++++++++++++++++++ .../com/fingerprint/model/WebhookVisit.java | 101 ++++++++- .../test/resources/mocks/get_event_200.json | 46 ++++- .../mocks/get_event_200_all_errors.json | 18 ++ .../mocks/get_event_200_extra_fields.json | 6 +- sdk/src/test/resources/mocks/webhook.json | 35 +++- 46 files changed, 2997 insertions(+), 28 deletions(-) create mode 100644 docs/DeveloperToolsResult.md create mode 100644 docs/ErrorUpdateEvent400Response.md create mode 100644 docs/ErrorUpdateEvent400ResponseError.md create mode 100644 docs/ErrorUpdateEvent409Response.md create mode 100644 docs/ErrorUpdateEvent409ResponseError.md create mode 100644 docs/ErrorVisitor400Response.md create mode 100644 docs/ErrorVisitor400ResponseError.md create mode 100644 docs/ErrorVisitor404Response.md create mode 100644 docs/ErrorVisitor404ResponseError.md create mode 100644 docs/EventUpdateRequest.md create mode 100644 docs/RemoteControlResult.md create mode 100644 docs/SignalResponseDeveloperTools.md create mode 100644 docs/SignalResponseRemoteControl.md create mode 100644 docs/SignalResponseVelocity.md create mode 100644 docs/VelocityIntervalResult.md create mode 100644 docs/VelocityIntervals.md create mode 100644 docs/VelocityResult.md create mode 100644 sdk/src/main/java/com/fingerprint/model/DeveloperToolsResult.java create mode 100644 sdk/src/main/java/com/fingerprint/model/ErrorUpdateEvent400Response.java create mode 100644 sdk/src/main/java/com/fingerprint/model/ErrorUpdateEvent400ResponseError.java create mode 100644 sdk/src/main/java/com/fingerprint/model/ErrorUpdateEvent409Response.java create mode 100644 sdk/src/main/java/com/fingerprint/model/ErrorUpdateEvent409ResponseError.java create mode 100644 sdk/src/main/java/com/fingerprint/model/ErrorVisitor400Response.java create mode 100644 sdk/src/main/java/com/fingerprint/model/ErrorVisitor400ResponseError.java create mode 100644 sdk/src/main/java/com/fingerprint/model/ErrorVisitor404Response.java create mode 100644 sdk/src/main/java/com/fingerprint/model/ErrorVisitor404ResponseError.java create mode 100644 sdk/src/main/java/com/fingerprint/model/EventUpdateRequest.java create mode 100644 sdk/src/main/java/com/fingerprint/model/RemoteControlResult.java create mode 100644 sdk/src/main/java/com/fingerprint/model/SignalResponseDeveloperTools.java create mode 100644 sdk/src/main/java/com/fingerprint/model/SignalResponseRemoteControl.java create mode 100644 sdk/src/main/java/com/fingerprint/model/SignalResponseVelocity.java create mode 100644 sdk/src/main/java/com/fingerprint/model/VelocityIntervalResult.java create mode 100644 sdk/src/main/java/com/fingerprint/model/VelocityIntervals.java create mode 100644 sdk/src/main/java/com/fingerprint/model/VelocityResult.java diff --git a/docs/DeveloperToolsResult.md b/docs/DeveloperToolsResult.md new file mode 100644 index 0000000..7ab5ba1 --- /dev/null +++ b/docs/DeveloperToolsResult.md @@ -0,0 +1,13 @@ + + +# DeveloperToolsResult + + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +|**result** | **Boolean** | `true` if the browser is Chrome with DevTools open or Firefox with Developer Tools open, `false` otherwise. | | + + + diff --git a/docs/ErrorUpdateEvent400Response.md b/docs/ErrorUpdateEvent400Response.md new file mode 100644 index 0000000..f9b7513 --- /dev/null +++ b/docs/ErrorUpdateEvent400Response.md @@ -0,0 +1,13 @@ + + +# ErrorUpdateEvent400Response + + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +|**error** | [**ErrorUpdateEvent400ResponseError**](ErrorUpdateEvent400ResponseError.md) | | [optional] | + + + diff --git a/docs/ErrorUpdateEvent400ResponseError.md b/docs/ErrorUpdateEvent400ResponseError.md new file mode 100644 index 0000000..441aede --- /dev/null +++ b/docs/ErrorUpdateEvent400ResponseError.md @@ -0,0 +1,22 @@ + + +# ErrorUpdateEvent400ResponseError + + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +|**code** | [**CodeEnum**](#CodeEnum) | Error code: * `RequestCannotBeParsed` - the JSON content of the request contains some errors that prevented us from parsing it (wrong type/surpassed limits) * `Failed` - the event is more than 10 days old and cannot be updated | | +|**message** | **String** | Details about the underlying issue with the input payload | | + + +## Enum: CodeEnum + +| Name | Value | +|---- | ----- | +| REQUEST_CANNOT_BE_PARSED | "RequestCannotBeParsed" | +| FAILED | "Failed" | + + + diff --git a/docs/ErrorUpdateEvent409Response.md b/docs/ErrorUpdateEvent409Response.md new file mode 100644 index 0000000..b9568d8 --- /dev/null +++ b/docs/ErrorUpdateEvent409Response.md @@ -0,0 +1,13 @@ + + +# ErrorUpdateEvent409Response + + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +|**error** | [**ErrorUpdateEvent409ResponseError**](ErrorUpdateEvent409ResponseError.md) | | [optional] | + + + diff --git a/docs/ErrorUpdateEvent409ResponseError.md b/docs/ErrorUpdateEvent409ResponseError.md new file mode 100644 index 0000000..31dcdd1 --- /dev/null +++ b/docs/ErrorUpdateEvent409ResponseError.md @@ -0,0 +1,21 @@ + + +# ErrorUpdateEvent409ResponseError + + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +|**code** | [**CodeEnum**](#CodeEnum) | Error code: * `StateNotReady` - The event specified with request id is not ready for updates yet. Try again. This error happens in rare cases when update API is called immediately after receiving the request id on the client. In case you need to send information right away, we recommend using the JS agent API instead. | | +|**message** | **String** | | | + + +## Enum: CodeEnum + +| Name | Value | +|---- | ----- | +| STATE_NOT_READY | "StateNotReady" | + + + diff --git a/docs/ErrorVisitor400Response.md b/docs/ErrorVisitor400Response.md new file mode 100644 index 0000000..43ae04f --- /dev/null +++ b/docs/ErrorVisitor400Response.md @@ -0,0 +1,13 @@ + + +# ErrorVisitor400Response + + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +|**error** | [**ErrorVisitor400ResponseError**](ErrorVisitor400ResponseError.md) | | [optional] | + + + diff --git a/docs/ErrorVisitor400ResponseError.md b/docs/ErrorVisitor400ResponseError.md new file mode 100644 index 0000000..0a942e6 --- /dev/null +++ b/docs/ErrorVisitor400ResponseError.md @@ -0,0 +1,21 @@ + + +# ErrorVisitor400ResponseError + + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +|**code** | [**CodeEnum**](#CodeEnum) | Error code: * `RequestCannotBeParsed` - The visitor ID parameter is missing or in the wrong format. | | +|**message** | **String** | | | + + +## Enum: CodeEnum + +| Name | Value | +|---- | ----- | +| REQUEST_CANNOT_BE_PARSED | "RequestCannotBeParsed" | + + + diff --git a/docs/ErrorVisitor404Response.md b/docs/ErrorVisitor404Response.md new file mode 100644 index 0000000..8d98e46 --- /dev/null +++ b/docs/ErrorVisitor404Response.md @@ -0,0 +1,13 @@ + + +# ErrorVisitor404Response + + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +|**error** | [**ErrorVisitor404ResponseError**](ErrorVisitor404ResponseError.md) | | [optional] | + + + diff --git a/docs/ErrorVisitor404ResponseError.md b/docs/ErrorVisitor404ResponseError.md new file mode 100644 index 0000000..a6e1658 --- /dev/null +++ b/docs/ErrorVisitor404ResponseError.md @@ -0,0 +1,21 @@ + + +# ErrorVisitor404ResponseError + + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +|**code** | [**CodeEnum**](#CodeEnum) | Error code: * `VisitorNotFound` - The specified visitor ID was not found. It never existed or it may have already been deleted. | | +|**message** | **String** | | | + + +## Enum: CodeEnum + +| Name | Value | +|---- | ----- | +| VISITOR_NOT_FOUND | "VisitorNotFound" | + + + diff --git a/docs/EventUpdateRequest.md b/docs/EventUpdateRequest.md new file mode 100644 index 0000000..1628721 --- /dev/null +++ b/docs/EventUpdateRequest.md @@ -0,0 +1,15 @@ + + +# EventUpdateRequest + + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +|**linkedId** | **String** | LinkedID value to assign to the existing event | [optional] | +|**tag** | **Object** | Full `tag` value to be set to the existing event. Replaces any existing `tag` payload completely. | [optional] | +|**suspect** | **Boolean** | Suspect flag indicating observed suspicious or fraudulent event | [optional] | + + + diff --git a/docs/FactoryResetResult.md b/docs/FactoryResetResult.md index 766035f..384483e 100644 --- a/docs/FactoryResetResult.md +++ b/docs/FactoryResetResult.md @@ -7,8 +7,8 @@ | Name | Type | Description | Notes | |------------ | ------------- | ------------- | -------------| -|**time** | **OffsetDateTime** | Time in UTC when the most recent factory reset of the Android or iOS device was done. If there is no sign of factory reset or the client is not a mobile device, the field will contain the epoch time (1 January 1970) in UTC. | | -|**timestamp** | **Long** | Same value as it's in the `time` field but represented in timestamp format. | | +|**time** | **OffsetDateTime** | Indicates the time (in UTC) of the most recent factory reset that happened on the **mobile device**. When a factory reset cannot be detected on the mobile device or when the request is initiated from a browser, this field will correspond to the *epoch* time (i.e 1 Jan 1970 UTC). See [Factory Reset Detection](https://dev.fingerprint.com/docs/smart-signals-overview#factory-reset-detection) to learn more about this Smart Signal. | | +|**timestamp** | **Long** | This field is just another representation of the value in the `time` field. The time of the most recent factory reset that happened on the **mobile device** is expressed as Unix epoch time. | | diff --git a/docs/FingerprintApi.md b/docs/FingerprintApi.md index b85382c..5322368 100644 --- a/docs/FingerprintApi.md +++ b/docs/FingerprintApi.md @@ -7,6 +7,7 @@ All URIs are relative to *https://api.fpjs.io* | [**deleteVisitorData**](FingerprintApi.md#deleteVisitorData) | **DELETE** /visitors/{visitor_id} | Delete data by visitor ID | | [**getEvent**](FingerprintApi.md#getEvent) | **GET** /events/{request_id} | Get event by request ID | | [**getVisits**](FingerprintApi.md#getVisits) | **GET** /visitors/{visitor_id} | Get visits by visitor ID | +| [**updateEvent**](FingerprintApi.md#updateEvent) | **PUT** /events/{request_id} | Update an event with a given request ID | | [**webhookTrace**](FingerprintApi.md#webhookTrace) | **TRACE** /webhook | | @@ -23,7 +24,7 @@ All delete requests are queued: * Recent data (10 days or newer) belonging to the specified visitor will be deleted within 24 hours. * Data from older (11 days or more) identification events will be deleted after 90 days. -If you are interested in using this API, please [contact our support team](https://fingerprint.com/support/) to activate it for you. Otherwise, you will receive a 403. +If you are interested in using this API, please [contact our support team](https://fingerprint.com/support/) to enable it for you. Otherwise, you will receive a 403. ### Example @@ -102,7 +103,7 @@ null (empty response body) Get event by request ID Get a detailed analysis of an individual identification event, including Smart Signals. -**Only for Enterprise customers:** Please note that the response includes mobile signals (e.g. `rootApps`) even if the request originated from a non-mobile platform. +Please note that the response includes mobile signals (e.g. `rootApps`) even if the request originated from a non-mobile platform. It is highly recommended that you **ignore** the mobile signals for such requests. Use `requestId` as the URL path parameter. This API method is scoped to a request, i.e. all returned information is by `requestId`. @@ -268,6 +269,90 @@ public class FingerprintApiExample { | **429** | Too Many Requests | * Retry-After - Indicates how many seconds you should wait before attempting the next request.
| +## updateEvent + +> updateEvent(requestId, eventUpdateRequest) + +Update an event with a given request ID + +Change information in existing events specified by `requestId` or *flag suspicious events*. + +When an event is created, it is assigned `linkedId` and `tag` submitted through the JS agent parameters. This information might not be available on the client so the Server API allows for updating the attributes after the fact. + +**Warning** It's not possible to update events older than 10 days. + + +### Example + +```java +package main; + +import com.fingerprint.api.FingerprintApi; +import com.fingerprint.model.EventResponse; +import com.fingerprint.model.Response; +import com.fingerprint.sdk.ApiClient; +import com.fingerprint.sdk.ApiException; +import com.fingerprint.sdk.Configuration; +import com.fingerprint.sdk.Region; + +public class FingerprintApiExample { + // Fingerprint Pro Secret API Key + private static final String FPJS_API_SECRET = "Fingerprint Pro Secret API Key"; + public static void main(String... args) { + // Create a new api client instance from Configuration with your Fingerprint Pro Server API Key and your Fingerprint Pro Server API Region. + /* + You can specify a region on getDefaultApiClient function's second parameter + If you leave the second parameter empty, then Region.GLOBAL will be used as a default region + Options for regions are: + Region.GLOBAL + Region.EUROPE + Region.ASIA + */ + ApiClient client = Configuration.getDefaultApiClient(FPJS_API_SECRET, Region.EUROPE); + FingerprintApi api = new FingerprintApi(client); + String requestId = "requestId_example"; // String | The unique event [identifier](https://dev.fingerprint.com/docs/js-agent#requestid). + EventUpdateRequest eventUpdateRequest = new EventUpdateRequest(); // EventUpdateRequest | + try { + apiInstance.updateEvent(requestIdeventUpdateRequest); + } catch (ApiException e) { + System.err.println("Exception when calling FingerprintApi.updateEvent:" + e.getMessage()); + } + } +} +``` + + +### Parameters + + +| Name | Type | Description | Notes | +|------------- | ------------- | ------------- | -------------| +| **requestId** | **String**| The unique event [identifier](https://dev.fingerprint.com/docs/js-agent#requestid). | | +| **eventUpdateRequest** | [**EventUpdateRequest**](EventUpdateRequest.md)| | | + +### Return type + +null (empty response body) + +### Authorization + +[ApiKeyHeader](../README.md#ApiKeyHeader), [ApiKeyQuery](../README.md#ApiKeyQuery) + +### HTTP request headers + +- **Content-Type**: application/json +- **Accept**: application/json + +### HTTP response details +| Status code | Description | Response headers | +|-------------|-------------|------------------| +| **200** | OK | - | +| **400** | Bad request | - | +| **403** | Forbidden | - | +| **404** | Not found | - | +| **409** | Conflict | - | + + ## webhookTrace > webhookTrace() diff --git a/docs/ProductsResponse.md b/docs/ProductsResponse.md index 1f2e1ee..a56b80b 100644 --- a/docs/ProductsResponse.md +++ b/docs/ProductsResponse.md @@ -29,6 +29,9 @@ Contains all information about the request identified by `requestId`, depending |**locationSpoofing** | [**SignalResponseLocationSpoofing**](SignalResponseLocationSpoofing.md) | | [optional] | |**suspectScore** | [**SignalResponseSuspectScore**](SignalResponseSuspectScore.md) | | [optional] | |**rawDeviceAttributes** | [**SignalResponseRawDeviceAttributes**](SignalResponseRawDeviceAttributes.md) | | [optional] | +|**remoteControl** | [**SignalResponseRemoteControl**](SignalResponseRemoteControl.md) | | [optional] | +|**velocity** | [**SignalResponseVelocity**](SignalResponseVelocity.md) | | [optional] | +|**developerTools** | [**SignalResponseDeveloperTools**](SignalResponseDeveloperTools.md) | | [optional] | diff --git a/docs/RemoteControlResult.md b/docs/RemoteControlResult.md new file mode 100644 index 0000000..9607f95 --- /dev/null +++ b/docs/RemoteControlResult.md @@ -0,0 +1,13 @@ + + +# RemoteControlResult + + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +|**result** | **Boolean** | `true` if the request came from a machine being remotely controlled (e.g. TeamViewer), `false` otherwise. | | + + + diff --git a/docs/SignalResponseDeveloperTools.md b/docs/SignalResponseDeveloperTools.md new file mode 100644 index 0000000..80bd2eb --- /dev/null +++ b/docs/SignalResponseDeveloperTools.md @@ -0,0 +1,14 @@ + + +# SignalResponseDeveloperTools + + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +|**data** | [**DeveloperToolsResult**](DeveloperToolsResult.md) | | [optional] | +|**error** | [**ProductError**](ProductError.md) | | [optional] | + + + diff --git a/docs/SignalResponseRemoteControl.md b/docs/SignalResponseRemoteControl.md new file mode 100644 index 0000000..6e982c5 --- /dev/null +++ b/docs/SignalResponseRemoteControl.md @@ -0,0 +1,14 @@ + + +# SignalResponseRemoteControl + + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +|**data** | [**RemoteControlResult**](RemoteControlResult.md) | | [optional] | +|**error** | [**ProductError**](ProductError.md) | | [optional] | + + + diff --git a/docs/SignalResponseVelocity.md b/docs/SignalResponseVelocity.md new file mode 100644 index 0000000..628a372 --- /dev/null +++ b/docs/SignalResponseVelocity.md @@ -0,0 +1,14 @@ + + +# SignalResponseVelocity + + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +|**data** | [**VelocityResult**](VelocityResult.md) | | [optional] | +|**error** | [**ProductError**](ProductError.md) | | [optional] | + + + diff --git a/docs/VelocityIntervalResult.md b/docs/VelocityIntervalResult.md new file mode 100644 index 0000000..3a15072 --- /dev/null +++ b/docs/VelocityIntervalResult.md @@ -0,0 +1,16 @@ + + +# VelocityIntervalResult + +Is absent if the velocity data could not be generated for the visitor ID. + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +|**_5m** | **Integer** | | | +|**_1h** | **Integer** | | | +|**_24h** | **Integer** | The `24h` interval of `distinctIp`, `distinctLinkedId`, and `distinctCountry` will be omitted if the number of `events`` for the visitor ID in the last 24 hours (`events.intervals.['24h']`) is higher than 20.000. | [optional] | + + + diff --git a/docs/VelocityIntervals.md b/docs/VelocityIntervals.md new file mode 100644 index 0000000..3291b28 --- /dev/null +++ b/docs/VelocityIntervals.md @@ -0,0 +1,13 @@ + + +# VelocityIntervals + + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +|**intervals** | [**VelocityIntervalResult**](VelocityIntervalResult.md) | | [optional] | + + + diff --git a/docs/VelocityResult.md b/docs/VelocityResult.md new file mode 100644 index 0000000..be6de4e --- /dev/null +++ b/docs/VelocityResult.md @@ -0,0 +1,17 @@ + + +# VelocityResult + +Sums key data points for a specific `visitorId` at three distinct time intervals: 5 minutes, 1 hour, and 24 hours as follows: - Number of identification events attributed to the visitor ID - Number of distinct IP addresses associated to the visitor ID. - Number of distinct countries associated with the visitor ID. - Number of distinct `linkedId`s associated with the visitor ID. The `24h` interval of `distinctIp`, `distinctLinkedId`, and `distinctCountry` will be omitted if the number of `events` for the visitor ID in the last 24 hours (`events.intervals.['24h']`) is higher than 20.000. + +## Properties + +| Name | Type | Description | Notes | +|------------ | ------------- | ------------- | -------------| +|**distinctIp** | [**VelocityIntervals**](VelocityIntervals.md) | | | +|**distinctLinkedId** | [**VelocityIntervals**](VelocityIntervals.md) | | | +|**distinctCountry** | [**VelocityIntervals**](VelocityIntervals.md) | | | +|**events** | [**VelocityIntervals**](VelocityIntervals.md) | | | + + + diff --git a/docs/WebhookVisit.md b/docs/WebhookVisit.md index 739613d..17f1a08 100644 --- a/docs/WebhookVisit.md +++ b/docs/WebhookVisit.md @@ -30,6 +30,9 @@ |**highActivity** | [**HighActivityResult**](HighActivityResult.md) | | [optional] | |**locationSpoofing** | [**LocationSpoofingResult**](LocationSpoofingResult.md) | | [optional] | |**suspectScore** | [**SuspectScoreResult**](SuspectScoreResult.md) | | [optional] | +|**remoteControl** | [**RemoteControlResult**](RemoteControlResult.md) | | [optional] | +|**velocity** | [**VelocityResult**](VelocityResult.md) | | [optional] | +|**developerTools** | [**DeveloperToolsResult**](DeveloperToolsResult.md) | | [optional] | |**requestId** | **String** | Unique identifier of the user's identification request. | | |**browserDetails** | [**BrowserDetails**](BrowserDetails.md) | | | |**ip** | **String** | | | diff --git a/sdk/src/main/java/com/fingerprint/api/FingerprintApi.java b/sdk/src/main/java/com/fingerprint/api/FingerprintApi.java index ace0a79..5fa605f 100644 --- a/sdk/src/main/java/com/fingerprint/api/FingerprintApi.java +++ b/sdk/src/main/java/com/fingerprint/api/FingerprintApi.java @@ -12,10 +12,13 @@ import com.fingerprint.model.ErrorCommon403Response; import com.fingerprint.model.ErrorCommon429Response; import com.fingerprint.model.ErrorEvent404Response; +import com.fingerprint.model.ErrorUpdateEvent400Response; +import com.fingerprint.model.ErrorUpdateEvent409Response; +import com.fingerprint.model.ErrorVisitor400Response; +import com.fingerprint.model.ErrorVisitor404Response; import com.fingerprint.model.ErrorVisits403; -import com.fingerprint.model.ErrorVisitsDelete400Response; -import com.fingerprint.model.ErrorVisitsDelete404Response; import com.fingerprint.model.EventResponse; +import com.fingerprint.model.EventUpdateRequest; import com.fingerprint.model.Response; import com.fingerprint.model.TooManyRequestsResponse; @@ -65,7 +68,7 @@ public void setApiClient(ApiClient apiClient) { /** * Delete data by visitor ID - * Request deleting all data associated with the specified visitor ID. This API is useful for compliance with privacy regulations. All delete requests are queued: * Recent data (10 days or newer) belonging to the specified visitor will be deleted within 24 hours. * Data from older (11 days or more) identification events will be deleted after 90 days. If you are interested in using this API, please [contact our support team](https://fingerprint.com/support/) to activate it for you. Otherwise, you will receive a 403. + * Request deleting all data associated with the specified visitor ID. This API is useful for compliance with privacy regulations. All delete requests are queued: * Recent data (10 days or newer) belonging to the specified visitor will be deleted within 24 hours. * Data from older (11 days or more) identification events will be deleted after 90 days. If you are interested in using this API, please [contact our support team](https://fingerprint.com/support/) to enable it for you. Otherwise, you will receive a 403. * @param visitorId The [visitor ID](https://dev.fingerprint.com/docs/js-agent#visitorid) you want to delete. (required) * @throws ApiException if fails to make API call * @http.response.details @@ -84,7 +87,7 @@ public void deleteVisitorData(String visitorId) throws ApiException { /** * Delete data by visitor ID - * Request deleting all data associated with the specified visitor ID. This API is useful for compliance with privacy regulations. All delete requests are queued: * Recent data (10 days or newer) belonging to the specified visitor will be deleted within 24 hours. * Data from older (11 days or more) identification events will be deleted after 90 days. If you are interested in using this API, please [contact our support team](https://fingerprint.com/support/) to activate it for you. Otherwise, you will receive a 403. + * Request deleting all data associated with the specified visitor ID. This API is useful for compliance with privacy regulations. All delete requests are queued: * Recent data (10 days or newer) belonging to the specified visitor will be deleted within 24 hours. * Data from older (11 days or more) identification events will be deleted after 90 days. If you are interested in using this API, please [contact our support team](https://fingerprint.com/support/) to enable it for you. Otherwise, you will receive a 403. * @param visitorId The [visitor ID](https://dev.fingerprint.com/docs/js-agent#visitorid) you want to delete. (required) * @return ApiResponse<Void> * @throws ApiException if fails to make API call @@ -140,7 +143,7 @@ public ApiResponse deleteVisitorDataWithHttpInfo(String visitorId) throws } /** * Get event by request ID - * Get a detailed analysis of an individual identification event, including Smart Signals. **Only for Enterprise customers:** Please note that the response includes mobile signals (e.g. `rootApps`) even if the request originated from a non-mobile platform. It is highly recommended that you **ignore** the mobile signals for such requests. Use `requestId` as the URL path parameter. This API method is scoped to a request, i.e. all returned information is by `requestId`. + * Get a detailed analysis of an individual identification event, including Smart Signals. Please note that the response includes mobile signals (e.g. `rootApps`) even if the request originated from a non-mobile platform. It is highly recommended that you **ignore** the mobile signals for such requests. Use `requestId` as the URL path parameter. This API method is scoped to a request, i.e. all returned information is by `requestId`. * @param requestId The unique [identifier](https://dev.fingerprint.com/docs/js-agent#requestid) of each identification request. (required) * @return EventResponse * @throws ApiException if fails to make API call @@ -158,7 +161,7 @@ public EventResponse getEvent(String requestId) throws ApiException { /** * Get event by request ID - * Get a detailed analysis of an individual identification event, including Smart Signals. **Only for Enterprise customers:** Please note that the response includes mobile signals (e.g. `rootApps`) even if the request originated from a non-mobile platform. It is highly recommended that you **ignore** the mobile signals for such requests. Use `requestId` as the URL path parameter. This API method is scoped to a request, i.e. all returned information is by `requestId`. + * Get a detailed analysis of an individual identification event, including Smart Signals. Please note that the response includes mobile signals (e.g. `rootApps`) even if the request originated from a non-mobile platform. It is highly recommended that you **ignore** the mobile signals for such requests. Use `requestId` as the URL path parameter. This API method is scoped to a request, i.e. all returned information is by `requestId`. * @param requestId The unique [identifier](https://dev.fingerprint.com/docs/js-agent#requestid) of each identification request. (required) * @return ApiResponse<EventResponse> * @throws ApiException if fails to make API call @@ -301,6 +304,88 @@ public ApiResponse getVisitsWithHttpInfo(String visitorId, String requ localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAccept, localVarContentType, localVarAuthNames, localVarReturnType, false); } + /** + * Update an event with a given request ID + * Change information in existing events specified by `requestId` or *flag suspicious events*. When an event is created, it is assigned `linkedId` and `tag` submitted through the JS agent parameters. This information might not be available on the client so the Server API allows for updating the attributes after the fact. **Warning** It's not possible to update events older than 10 days. + * @param requestId The unique event [identifier](https://dev.fingerprint.com/docs/js-agent#requestid). (required) + * @param eventUpdateRequest (required) + * @throws ApiException if fails to make API call + * @http.response.details + + + + + + + +
Status Code Description Response Headers
200 OK -
400 Bad request -
403 Forbidden -
404 Not found -
409 Conflict -
+ */ + public void updateEvent(String requestId, EventUpdateRequest eventUpdateRequest) throws ApiException { + updateEventWithHttpInfo(requestId, eventUpdateRequest); + } + + /** + * Update an event with a given request ID + * Change information in existing events specified by `requestId` or *flag suspicious events*. When an event is created, it is assigned `linkedId` and `tag` submitted through the JS agent parameters. This information might not be available on the client so the Server API allows for updating the attributes after the fact. **Warning** It's not possible to update events older than 10 days. + * @param requestId The unique event [identifier](https://dev.fingerprint.com/docs/js-agent#requestid). (required) + * @param eventUpdateRequest (required) + * @return ApiResponse<Void> + * @throws ApiException if fails to make API call + * @http.response.details + + + + + + + +
Status Code Description Response Headers
200 OK -
400 Bad request -
403 Forbidden -
404 Not found -
409 Conflict -
+ */ + public ApiResponse updateEventWithHttpInfo(String requestId, EventUpdateRequest eventUpdateRequest) throws ApiException { + Object localVarPostBody = eventUpdateRequest; + + // verify the required parameter 'requestId' is set + if (requestId == null) { + throw new ApiException(400, "Missing the required parameter 'requestId' when calling updateEvent"); + } + + // verify the required parameter 'eventUpdateRequest' is set + if (eventUpdateRequest == null) { + throw new ApiException(400, "Missing the required parameter 'eventUpdateRequest' when calling updateEvent"); + } + + // create path and map variables + String localVarPath = "/events/{request_id}" + .replaceAll("\\{" + "request_id" + "\\}", apiClient.escapeString(requestId.toString())); + + // query params + List localVarQueryParams = new ArrayList(); + Map localVarHeaderParams = new HashMap(); + Map localVarCookieParams = new HashMap(); + Map localVarFormParams = new HashMap(); + + localVarQueryParams.add(new Pair("ii", INTEGRATION_INFO)); + + + + + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = apiClient.selectHeaderAccept(localVarAccepts); + + final String[] localVarContentTypes = { + "application/json" + }; + final String localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes); + + String[] localVarAuthNames = new String[] { "ApiKeyHeader", "ApiKeyQuery" }; + + return apiClient.invokeAPI("FingerprintApi.updateEvent", localVarPath, "PUT", localVarQueryParams, localVarPostBody, + localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAccept, localVarContentType, + localVarAuthNames, null, false); + } /** * * Fake path to describe webhook format. More information about webhooks can be found in the [documentation](https://dev.fingerprint.com/docs/webhooks) diff --git a/sdk/src/main/java/com/fingerprint/model/DeveloperToolsResult.java b/sdk/src/main/java/com/fingerprint/model/DeveloperToolsResult.java new file mode 100644 index 0000000..c083d3a --- /dev/null +++ b/sdk/src/main/java/com/fingerprint/model/DeveloperToolsResult.java @@ -0,0 +1,97 @@ +package com.fingerprint.model; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fingerprint.sdk.JSON; +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * DeveloperToolsResult + */ + + +@JsonPropertyOrder({ + DeveloperToolsResult.JSON_PROPERTY_RESULT +}) +@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.7.0") +public class DeveloperToolsResult { + public static final String JSON_PROPERTY_RESULT = "result"; + private Boolean result; + + public DeveloperToolsResult() { + } + + public DeveloperToolsResult result(Boolean result) { + this.result = result; + return this; + } + + /** + * `true` if the browser is Chrome with DevTools open or Firefox with Developer Tools open, `false` otherwise. + * @return result + **/ + @jakarta.annotation.Nonnull + @Schema(example = "false", required = true, description = "`true` if the browser is Chrome with DevTools open or Firefox with Developer Tools open, `false` otherwise. ") + @JsonProperty(JSON_PROPERTY_RESULT) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public Boolean getResult() { + return result; + } + + + @JsonProperty(JSON_PROPERTY_RESULT) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setResult(Boolean result) { + this.result = result; + } + + + /** + * Return true if this DeveloperToolsResult object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + DeveloperToolsResult developerToolsResult = (DeveloperToolsResult) o; + return Objects.equals(this.result, developerToolsResult.result); + } + + @Override + public int hashCode() { + return Objects.hash(result); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class DeveloperToolsResult {\n"); + sb.append(" result: ").append(toIndentedString(result)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/sdk/src/main/java/com/fingerprint/model/ErrorUpdateEvent400Response.java b/sdk/src/main/java/com/fingerprint/model/ErrorUpdateEvent400Response.java new file mode 100644 index 0000000..4bcfdd9 --- /dev/null +++ b/sdk/src/main/java/com/fingerprint/model/ErrorUpdateEvent400Response.java @@ -0,0 +1,98 @@ +package com.fingerprint.model; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fingerprint.model.ErrorUpdateEvent400ResponseError; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fingerprint.sdk.JSON; +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * ErrorUpdateEvent400Response + */ + + +@JsonPropertyOrder({ + ErrorUpdateEvent400Response.JSON_PROPERTY_ERROR +}) +@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.7.0") +public class ErrorUpdateEvent400Response { + public static final String JSON_PROPERTY_ERROR = "error"; + private ErrorUpdateEvent400ResponseError error; + + public ErrorUpdateEvent400Response() { + } + + public ErrorUpdateEvent400Response error(ErrorUpdateEvent400ResponseError error) { + this.error = error; + return this; + } + + /** + * Get error + * @return error + **/ + @jakarta.annotation.Nullable + @Schema(description = "") + @JsonProperty(JSON_PROPERTY_ERROR) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public ErrorUpdateEvent400ResponseError getError() { + return error; + } + + + @JsonProperty(JSON_PROPERTY_ERROR) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setError(ErrorUpdateEvent400ResponseError error) { + this.error = error; + } + + + /** + * Return true if this ErrorUpdateEvent400Response object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ErrorUpdateEvent400Response errorUpdateEvent400Response = (ErrorUpdateEvent400Response) o; + return Objects.equals(this.error, errorUpdateEvent400Response.error); + } + + @Override + public int hashCode() { + return Objects.hash(error); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ErrorUpdateEvent400Response {\n"); + sb.append(" error: ").append(toIndentedString(error)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/sdk/src/main/java/com/fingerprint/model/ErrorUpdateEvent400ResponseError.java b/sdk/src/main/java/com/fingerprint/model/ErrorUpdateEvent400ResponseError.java new file mode 100644 index 0000000..b2d468d --- /dev/null +++ b/sdk/src/main/java/com/fingerprint/model/ErrorUpdateEvent400ResponseError.java @@ -0,0 +1,164 @@ +package com.fingerprint.model; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fingerprint.sdk.JSON; +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * ErrorUpdateEvent400ResponseError + */ + + +@JsonPropertyOrder({ + ErrorUpdateEvent400ResponseError.JSON_PROPERTY_CODE, + ErrorUpdateEvent400ResponseError.JSON_PROPERTY_MESSAGE +}) +@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.7.0") +public class ErrorUpdateEvent400ResponseError { + /** + * Error code: * `RequestCannotBeParsed` - the JSON content of the request contains some errors that prevented us from parsing it (wrong type/surpassed limits) * `Failed` - the event is more than 10 days old and cannot be updated + */ + public enum CodeEnum { + REQUEST_CANNOT_BE_PARSED("RequestCannotBeParsed"), + + FAILED("Failed"); + + private String value; + + CodeEnum(String value) { + this.value = value; + } + + @JsonValue + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static CodeEnum fromValue(String value) { + for (CodeEnum b : CodeEnum.values()) { + if (b.value.equals(value)) { + return b; + } + } + return null; + } + } + + public static final String JSON_PROPERTY_CODE = "code"; + private CodeEnum code; + + public static final String JSON_PROPERTY_MESSAGE = "message"; + private String message; + + public ErrorUpdateEvent400ResponseError() { + } + + public ErrorUpdateEvent400ResponseError code(CodeEnum code) { + this.code = code; + return this; + } + + /** + * Error code: * `RequestCannotBeParsed` - the JSON content of the request contains some errors that prevented us from parsing it (wrong type/surpassed limits) * `Failed` - the event is more than 10 days old and cannot be updated + * @return code + **/ + @jakarta.annotation.Nonnull + @Schema(example = "RequestCannotBeParsed", required = true, description = "Error code: * `RequestCannotBeParsed` - the JSON content of the request contains some errors that prevented us from parsing it (wrong type/surpassed limits) * `Failed` - the event is more than 10 days old and cannot be updated ") + @JsonProperty(JSON_PROPERTY_CODE) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public CodeEnum getCode() { + return code; + } + + + @JsonProperty(JSON_PROPERTY_CODE) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setCode(CodeEnum code) { + this.code = code; + } + + + public ErrorUpdateEvent400ResponseError message(String message) { + this.message = message; + return this; + } + + /** + * Details about the underlying issue with the input payload + * @return message + **/ + @jakarta.annotation.Nonnull + @Schema(example = "suspect flag must be a boolean", required = true, description = "Details about the underlying issue with the input payload") + @JsonProperty(JSON_PROPERTY_MESSAGE) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public String getMessage() { + return message; + } + + + @JsonProperty(JSON_PROPERTY_MESSAGE) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setMessage(String message) { + this.message = message; + } + + + /** + * Return true if this ErrorUpdateEvent400ResponseError object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ErrorUpdateEvent400ResponseError errorUpdateEvent400ResponseError = (ErrorUpdateEvent400ResponseError) o; + return Objects.equals(this.code, errorUpdateEvent400ResponseError.code) && + Objects.equals(this.message, errorUpdateEvent400ResponseError.message); + } + + @Override + public int hashCode() { + return Objects.hash(code, message); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ErrorUpdateEvent400ResponseError {\n"); + sb.append(" code: ").append(toIndentedString(code)).append("\n"); + sb.append(" message: ").append(toIndentedString(message)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/sdk/src/main/java/com/fingerprint/model/ErrorUpdateEvent409Response.java b/sdk/src/main/java/com/fingerprint/model/ErrorUpdateEvent409Response.java new file mode 100644 index 0000000..cfbfc22 --- /dev/null +++ b/sdk/src/main/java/com/fingerprint/model/ErrorUpdateEvent409Response.java @@ -0,0 +1,98 @@ +package com.fingerprint.model; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fingerprint.model.ErrorUpdateEvent409ResponseError; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fingerprint.sdk.JSON; +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * ErrorUpdateEvent409Response + */ + + +@JsonPropertyOrder({ + ErrorUpdateEvent409Response.JSON_PROPERTY_ERROR +}) +@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.7.0") +public class ErrorUpdateEvent409Response { + public static final String JSON_PROPERTY_ERROR = "error"; + private ErrorUpdateEvent409ResponseError error; + + public ErrorUpdateEvent409Response() { + } + + public ErrorUpdateEvent409Response error(ErrorUpdateEvent409ResponseError error) { + this.error = error; + return this; + } + + /** + * Get error + * @return error + **/ + @jakarta.annotation.Nullable + @Schema(description = "") + @JsonProperty(JSON_PROPERTY_ERROR) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public ErrorUpdateEvent409ResponseError getError() { + return error; + } + + + @JsonProperty(JSON_PROPERTY_ERROR) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setError(ErrorUpdateEvent409ResponseError error) { + this.error = error; + } + + + /** + * Return true if this ErrorUpdateEvent409Response object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ErrorUpdateEvent409Response errorUpdateEvent409Response = (ErrorUpdateEvent409Response) o; + return Objects.equals(this.error, errorUpdateEvent409Response.error); + } + + @Override + public int hashCode() { + return Objects.hash(error); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ErrorUpdateEvent409Response {\n"); + sb.append(" error: ").append(toIndentedString(error)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/sdk/src/main/java/com/fingerprint/model/ErrorUpdateEvent409ResponseError.java b/sdk/src/main/java/com/fingerprint/model/ErrorUpdateEvent409ResponseError.java new file mode 100644 index 0000000..48df779 --- /dev/null +++ b/sdk/src/main/java/com/fingerprint/model/ErrorUpdateEvent409ResponseError.java @@ -0,0 +1,162 @@ +package com.fingerprint.model; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fingerprint.sdk.JSON; +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * ErrorUpdateEvent409ResponseError + */ + + +@JsonPropertyOrder({ + ErrorUpdateEvent409ResponseError.JSON_PROPERTY_CODE, + ErrorUpdateEvent409ResponseError.JSON_PROPERTY_MESSAGE +}) +@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.7.0") +public class ErrorUpdateEvent409ResponseError { + /** + * Error code: * `StateNotReady` - The event specified with request id is not ready for updates yet. Try again. This error happens in rare cases when update API is called immediately after receiving the request id on the client. In case you need to send information right away, we recommend using the JS agent API instead. + */ + public enum CodeEnum { + STATE_NOT_READY("StateNotReady"); + + private String value; + + CodeEnum(String value) { + this.value = value; + } + + @JsonValue + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static CodeEnum fromValue(String value) { + for (CodeEnum b : CodeEnum.values()) { + if (b.value.equals(value)) { + return b; + } + } + return null; + } + } + + public static final String JSON_PROPERTY_CODE = "code"; + private CodeEnum code; + + public static final String JSON_PROPERTY_MESSAGE = "message"; + private String message; + + public ErrorUpdateEvent409ResponseError() { + } + + public ErrorUpdateEvent409ResponseError code(CodeEnum code) { + this.code = code; + return this; + } + + /** + * Error code: * `StateNotReady` - The event specified with request id is not ready for updates yet. Try again. This error happens in rare cases when update API is called immediately after receiving the request id on the client. In case you need to send information right away, we recommend using the JS agent API instead. + * @return code + **/ + @jakarta.annotation.Nonnull + @Schema(example = "StateNotReady", required = true, description = "Error code: * `StateNotReady` - The event specified with request id is not ready for updates yet. Try again. This error happens in rare cases when update API is called immediately after receiving the request id on the client. In case you need to send information right away, we recommend using the JS agent API instead. ") + @JsonProperty(JSON_PROPERTY_CODE) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public CodeEnum getCode() { + return code; + } + + + @JsonProperty(JSON_PROPERTY_CODE) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setCode(CodeEnum code) { + this.code = code; + } + + + public ErrorUpdateEvent409ResponseError message(String message) { + this.message = message; + return this; + } + + /** + * Get message + * @return message + **/ + @jakarta.annotation.Nonnull + @Schema(example = "resource is not mutable yet, try again", required = true, description = "") + @JsonProperty(JSON_PROPERTY_MESSAGE) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public String getMessage() { + return message; + } + + + @JsonProperty(JSON_PROPERTY_MESSAGE) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setMessage(String message) { + this.message = message; + } + + + /** + * Return true if this ErrorUpdateEvent409ResponseError object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ErrorUpdateEvent409ResponseError errorUpdateEvent409ResponseError = (ErrorUpdateEvent409ResponseError) o; + return Objects.equals(this.code, errorUpdateEvent409ResponseError.code) && + Objects.equals(this.message, errorUpdateEvent409ResponseError.message); + } + + @Override + public int hashCode() { + return Objects.hash(code, message); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ErrorUpdateEvent409ResponseError {\n"); + sb.append(" code: ").append(toIndentedString(code)).append("\n"); + sb.append(" message: ").append(toIndentedString(message)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/sdk/src/main/java/com/fingerprint/model/ErrorVisitor400Response.java b/sdk/src/main/java/com/fingerprint/model/ErrorVisitor400Response.java new file mode 100644 index 0000000..83937d5 --- /dev/null +++ b/sdk/src/main/java/com/fingerprint/model/ErrorVisitor400Response.java @@ -0,0 +1,98 @@ +package com.fingerprint.model; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fingerprint.model.ErrorVisitor400ResponseError; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fingerprint.sdk.JSON; +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * ErrorVisitor400Response + */ + + +@JsonPropertyOrder({ + ErrorVisitor400Response.JSON_PROPERTY_ERROR +}) +@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.7.0") +public class ErrorVisitor400Response { + public static final String JSON_PROPERTY_ERROR = "error"; + private ErrorVisitor400ResponseError error; + + public ErrorVisitor400Response() { + } + + public ErrorVisitor400Response error(ErrorVisitor400ResponseError error) { + this.error = error; + return this; + } + + /** + * Get error + * @return error + **/ + @jakarta.annotation.Nullable + @Schema(description = "") + @JsonProperty(JSON_PROPERTY_ERROR) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public ErrorVisitor400ResponseError getError() { + return error; + } + + + @JsonProperty(JSON_PROPERTY_ERROR) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setError(ErrorVisitor400ResponseError error) { + this.error = error; + } + + + /** + * Return true if this ErrorVisitor400Response object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ErrorVisitor400Response errorVisitor400Response = (ErrorVisitor400Response) o; + return Objects.equals(this.error, errorVisitor400Response.error); + } + + @Override + public int hashCode() { + return Objects.hash(error); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ErrorVisitor400Response {\n"); + sb.append(" error: ").append(toIndentedString(error)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/sdk/src/main/java/com/fingerprint/model/ErrorVisitor400ResponseError.java b/sdk/src/main/java/com/fingerprint/model/ErrorVisitor400ResponseError.java new file mode 100644 index 0000000..3479c7b --- /dev/null +++ b/sdk/src/main/java/com/fingerprint/model/ErrorVisitor400ResponseError.java @@ -0,0 +1,163 @@ +package com.fingerprint.model; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fingerprint.sdk.JSON; +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * ErrorVisitor400ResponseError + */ + + +@JsonPropertyOrder({ + ErrorVisitor400ResponseError.JSON_PROPERTY_CODE, + ErrorVisitor400ResponseError.JSON_PROPERTY_MESSAGE +}) +@JsonTypeName("ErrorVisitor400Response_error") +@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.7.0") +public class ErrorVisitor400ResponseError { + /** + * Error code: * `RequestCannotBeParsed` - The visitor ID parameter is missing or in the wrong format. + */ + public enum CodeEnum { + REQUEST_CANNOT_BE_PARSED("RequestCannotBeParsed"); + + private String value; + + CodeEnum(String value) { + this.value = value; + } + + @JsonValue + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static CodeEnum fromValue(String value) { + for (CodeEnum b : CodeEnum.values()) { + if (b.value.equals(value)) { + return b; + } + } + return null; + } + } + + public static final String JSON_PROPERTY_CODE = "code"; + private CodeEnum code; + + public static final String JSON_PROPERTY_MESSAGE = "message"; + private String message; + + public ErrorVisitor400ResponseError() { + } + + public ErrorVisitor400ResponseError code(CodeEnum code) { + this.code = code; + return this; + } + + /** + * Error code: * `RequestCannotBeParsed` - The visitor ID parameter is missing or in the wrong format. + * @return code + **/ + @jakarta.annotation.Nonnull + @Schema(example = "RequestCannotBeParsed", required = true, description = "Error code: * `RequestCannotBeParsed` - The visitor ID parameter is missing or in the wrong format. ") + @JsonProperty(JSON_PROPERTY_CODE) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public CodeEnum getCode() { + return code; + } + + + @JsonProperty(JSON_PROPERTY_CODE) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setCode(CodeEnum code) { + this.code = code; + } + + + public ErrorVisitor400ResponseError message(String message) { + this.message = message; + return this; + } + + /** + * Get message + * @return message + **/ + @jakarta.annotation.Nonnull + @Schema(example = "invalid visitor id", required = true, description = "") + @JsonProperty(JSON_PROPERTY_MESSAGE) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public String getMessage() { + return message; + } + + + @JsonProperty(JSON_PROPERTY_MESSAGE) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setMessage(String message) { + this.message = message; + } + + + /** + * Return true if this ErrorVisitor400Response_error object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ErrorVisitor400ResponseError errorVisitor400ResponseError = (ErrorVisitor400ResponseError) o; + return Objects.equals(this.code, errorVisitor400ResponseError.code) && + Objects.equals(this.message, errorVisitor400ResponseError.message); + } + + @Override + public int hashCode() { + return Objects.hash(code, message); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ErrorVisitor400ResponseError {\n"); + sb.append(" code: ").append(toIndentedString(code)).append("\n"); + sb.append(" message: ").append(toIndentedString(message)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/sdk/src/main/java/com/fingerprint/model/ErrorVisitor404Response.java b/sdk/src/main/java/com/fingerprint/model/ErrorVisitor404Response.java new file mode 100644 index 0000000..19a222c --- /dev/null +++ b/sdk/src/main/java/com/fingerprint/model/ErrorVisitor404Response.java @@ -0,0 +1,98 @@ +package com.fingerprint.model; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fingerprint.model.ErrorVisitor404ResponseError; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fingerprint.sdk.JSON; +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * ErrorVisitor404Response + */ + + +@JsonPropertyOrder({ + ErrorVisitor404Response.JSON_PROPERTY_ERROR +}) +@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.7.0") +public class ErrorVisitor404Response { + public static final String JSON_PROPERTY_ERROR = "error"; + private ErrorVisitor404ResponseError error; + + public ErrorVisitor404Response() { + } + + public ErrorVisitor404Response error(ErrorVisitor404ResponseError error) { + this.error = error; + return this; + } + + /** + * Get error + * @return error + **/ + @jakarta.annotation.Nullable + @Schema(description = "") + @JsonProperty(JSON_PROPERTY_ERROR) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public ErrorVisitor404ResponseError getError() { + return error; + } + + + @JsonProperty(JSON_PROPERTY_ERROR) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setError(ErrorVisitor404ResponseError error) { + this.error = error; + } + + + /** + * Return true if this ErrorVisitor404Response object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ErrorVisitor404Response errorVisitor404Response = (ErrorVisitor404Response) o; + return Objects.equals(this.error, errorVisitor404Response.error); + } + + @Override + public int hashCode() { + return Objects.hash(error); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ErrorVisitor404Response {\n"); + sb.append(" error: ").append(toIndentedString(error)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/sdk/src/main/java/com/fingerprint/model/ErrorVisitor404ResponseError.java b/sdk/src/main/java/com/fingerprint/model/ErrorVisitor404ResponseError.java new file mode 100644 index 0000000..1258837 --- /dev/null +++ b/sdk/src/main/java/com/fingerprint/model/ErrorVisitor404ResponseError.java @@ -0,0 +1,162 @@ +package com.fingerprint.model; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fingerprint.sdk.JSON; +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * ErrorVisitor404ResponseError + */ + + +@JsonPropertyOrder({ + ErrorVisitor404ResponseError.JSON_PROPERTY_CODE, + ErrorVisitor404ResponseError.JSON_PROPERTY_MESSAGE +}) +@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.7.0") +public class ErrorVisitor404ResponseError { + /** + * Error code: * `VisitorNotFound` - The specified visitor ID was not found. It never existed or it may have already been deleted. + */ + public enum CodeEnum { + VISITOR_NOT_FOUND("VisitorNotFound"); + + private String value; + + CodeEnum(String value) { + this.value = value; + } + + @JsonValue + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static CodeEnum fromValue(String value) { + for (CodeEnum b : CodeEnum.values()) { + if (b.value.equals(value)) { + return b; + } + } + return null; + } + } + + public static final String JSON_PROPERTY_CODE = "code"; + private CodeEnum code; + + public static final String JSON_PROPERTY_MESSAGE = "message"; + private String message; + + public ErrorVisitor404ResponseError() { + } + + public ErrorVisitor404ResponseError code(CodeEnum code) { + this.code = code; + return this; + } + + /** + * Error code: * `VisitorNotFound` - The specified visitor ID was not found. It never existed or it may have already been deleted. + * @return code + **/ + @jakarta.annotation.Nonnull + @Schema(example = "VisitorNotFound", required = true, description = "Error code: * `VisitorNotFound` - The specified visitor ID was not found. It never existed or it may have already been deleted. ") + @JsonProperty(JSON_PROPERTY_CODE) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public CodeEnum getCode() { + return code; + } + + + @JsonProperty(JSON_PROPERTY_CODE) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setCode(CodeEnum code) { + this.code = code; + } + + + public ErrorVisitor404ResponseError message(String message) { + this.message = message; + return this; + } + + /** + * Get message + * @return message + **/ + @jakarta.annotation.Nonnull + @Schema(example = "visitor not found", required = true, description = "") + @JsonProperty(JSON_PROPERTY_MESSAGE) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public String getMessage() { + return message; + } + + + @JsonProperty(JSON_PROPERTY_MESSAGE) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setMessage(String message) { + this.message = message; + } + + + /** + * Return true if this ErrorVisitor404ResponseError object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ErrorVisitor404ResponseError errorVisitor404ResponseError = (ErrorVisitor404ResponseError) o; + return Objects.equals(this.code, errorVisitor404ResponseError.code) && + Objects.equals(this.message, errorVisitor404ResponseError.message); + } + + @Override + public int hashCode() { + return Objects.hash(code, message); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ErrorVisitor404ResponseError {\n"); + sb.append(" code: ").append(toIndentedString(code)).append("\n"); + sb.append(" message: ").append(toIndentedString(message)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/sdk/src/main/java/com/fingerprint/model/EventUpdateRequest.java b/sdk/src/main/java/com/fingerprint/model/EventUpdateRequest.java new file mode 100644 index 0000000..31fe9a9 --- /dev/null +++ b/sdk/src/main/java/com/fingerprint/model/EventUpdateRequest.java @@ -0,0 +1,161 @@ +package com.fingerprint.model; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fingerprint.sdk.JSON; +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * EventUpdateRequest + */ + + +@JsonPropertyOrder({ + EventUpdateRequest.JSON_PROPERTY_LINKED_ID, + EventUpdateRequest.JSON_PROPERTY_TAG, + EventUpdateRequest.JSON_PROPERTY_SUSPECT +}) +@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.7.0") +public class EventUpdateRequest { + public static final String JSON_PROPERTY_LINKED_ID = "linkedId"; + private String linkedId; + + public static final String JSON_PROPERTY_TAG = "tag"; + private Object tag; + + public static final String JSON_PROPERTY_SUSPECT = "suspect"; + private Boolean suspect; + + public EventUpdateRequest() { + } + + public EventUpdateRequest linkedId(String linkedId) { + this.linkedId = linkedId; + return this; + } + + /** + * LinkedID value to assign to the existing event + * @return linkedId + **/ + @jakarta.annotation.Nullable + @Schema(description = "LinkedID value to assign to the existing event") + @JsonProperty(JSON_PROPERTY_LINKED_ID) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public String getLinkedId() { + return linkedId; + } + + + @JsonProperty(JSON_PROPERTY_LINKED_ID) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setLinkedId(String linkedId) { + this.linkedId = linkedId; + } + + + public EventUpdateRequest tag(Object tag) { + this.tag = tag; + return this; + } + + /** + * Full `tag` value to be set to the existing event. Replaces any existing `tag` payload completely. + * @return tag + **/ + @jakarta.annotation.Nullable + @Schema(description = "Full `tag` value to be set to the existing event. Replaces any existing `tag` payload completely.") + @JsonProperty(JSON_PROPERTY_TAG) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Object getTag() { + return tag; + } + + + @JsonProperty(JSON_PROPERTY_TAG) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setTag(Object tag) { + this.tag = tag; + } + + + public EventUpdateRequest suspect(Boolean suspect) { + this.suspect = suspect; + return this; + } + + /** + * Suspect flag indicating observed suspicious or fraudulent event + * @return suspect + **/ + @jakarta.annotation.Nullable + @Schema(description = "Suspect flag indicating observed suspicious or fraudulent event") + @JsonProperty(JSON_PROPERTY_SUSPECT) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Boolean getSuspect() { + return suspect; + } + + + @JsonProperty(JSON_PROPERTY_SUSPECT) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setSuspect(Boolean suspect) { + this.suspect = suspect; + } + + + /** + * Return true if this EventUpdateRequest object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + EventUpdateRequest eventUpdateRequest = (EventUpdateRequest) o; + return Objects.equals(this.linkedId, eventUpdateRequest.linkedId) && + Objects.equals(this.tag, eventUpdateRequest.tag) && + Objects.equals(this.suspect, eventUpdateRequest.suspect); + } + + @Override + public int hashCode() { + return Objects.hash(linkedId, tag, suspect); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class EventUpdateRequest {\n"); + sb.append(" linkedId: ").append(toIndentedString(linkedId)).append("\n"); + sb.append(" tag: ").append(toIndentedString(tag)).append("\n"); + sb.append(" suspect: ").append(toIndentedString(suspect)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/sdk/src/main/java/com/fingerprint/model/FactoryResetResult.java b/sdk/src/main/java/com/fingerprint/model/FactoryResetResult.java index 2e6e239..8c852b2 100644 --- a/sdk/src/main/java/com/fingerprint/model/FactoryResetResult.java +++ b/sdk/src/main/java/com/fingerprint/model/FactoryResetResult.java @@ -38,11 +38,11 @@ public FactoryResetResult time(OffsetDateTime time) { } /** - * Time in UTC when the most recent factory reset of the Android or iOS device was done. If there is no sign of factory reset or the client is not a mobile device, the field will contain the epoch time (1 January 1970) in UTC. + * Indicates the time (in UTC) of the most recent factory reset that happened on the **mobile device**. When a factory reset cannot be detected on the mobile device or when the request is initiated from a browser, this field will correspond to the *epoch* time (i.e 1 Jan 1970 UTC). See [Factory Reset Detection](https://dev.fingerprint.com/docs/smart-signals-overview#factory-reset-detection) to learn more about this Smart Signal. * @return time **/ @jakarta.annotation.Nonnull - @Schema(example = "2022-06-09T22:58:36Z", required = true, description = "Time in UTC when the most recent factory reset of the Android or iOS device was done. If there is no sign of factory reset or the client is not a mobile device, the field will contain the epoch time (1 January 1970) in UTC. ") + @Schema(example = "2022-06-09T22:58:36Z", required = true, description = "Indicates the time (in UTC) of the most recent factory reset that happened on the **mobile device**. When a factory reset cannot be detected on the mobile device or when the request is initiated from a browser, this field will correspond to the *epoch* time (i.e 1 Jan 1970 UTC). See [Factory Reset Detection](https://dev.fingerprint.com/docs/smart-signals-overview#factory-reset-detection) to learn more about this Smart Signal. ") @JsonProperty(JSON_PROPERTY_TIME) @JsonInclude(value = JsonInclude.Include.ALWAYS) @@ -64,11 +64,11 @@ public FactoryResetResult timestamp(Long timestamp) { } /** - * Same value as it's in the `time` field but represented in timestamp format. + * This field is just another representation of the value in the `time` field. The time of the most recent factory reset that happened on the **mobile device** is expressed as Unix epoch time. * @return timestamp **/ @jakarta.annotation.Nonnull - @Schema(example = "1654815517198", required = true, description = "Same value as it's in the `time` field but represented in timestamp format.") + @Schema(example = "1654815517198", required = true, description = "This field is just another representation of the value in the `time` field. The time of the most recent factory reset that happened on the **mobile device** is expressed as Unix epoch time. ") @JsonProperty(JSON_PROPERTY_TIMESTAMP) @JsonInclude(value = JsonInclude.Include.ALWAYS) diff --git a/sdk/src/main/java/com/fingerprint/model/ProductsResponse.java b/sdk/src/main/java/com/fingerprint/model/ProductsResponse.java index 0a9fd4f..3fbd64e 100644 --- a/sdk/src/main/java/com/fingerprint/model/ProductsResponse.java +++ b/sdk/src/main/java/com/fingerprint/model/ProductsResponse.java @@ -9,6 +9,7 @@ import com.fingerprint.model.ProductsResponseBotd; import com.fingerprint.model.ProductsResponseIdentification; import com.fingerprint.model.SignalResponseClonedApp; +import com.fingerprint.model.SignalResponseDeveloperTools; import com.fingerprint.model.SignalResponseEmulator; import com.fingerprint.model.SignalResponseFactoryReset; import com.fingerprint.model.SignalResponseFrida; @@ -21,10 +22,12 @@ import com.fingerprint.model.SignalResponsePrivacySettings; import com.fingerprint.model.SignalResponseProxy; import com.fingerprint.model.SignalResponseRawDeviceAttributes; +import com.fingerprint.model.SignalResponseRemoteControl; import com.fingerprint.model.SignalResponseRootApps; import com.fingerprint.model.SignalResponseSuspectScore; import com.fingerprint.model.SignalResponseTampering; import com.fingerprint.model.SignalResponseTor; +import com.fingerprint.model.SignalResponseVelocity; import com.fingerprint.model.SignalResponseVirtualMachine; import com.fingerprint.model.SignalResponseVpn; import java.util.Arrays; @@ -58,7 +61,10 @@ ProductsResponse.JSON_PROPERTY_HIGH_ACTIVITY, ProductsResponse.JSON_PROPERTY_LOCATION_SPOOFING, ProductsResponse.JSON_PROPERTY_SUSPECT_SCORE, - ProductsResponse.JSON_PROPERTY_RAW_DEVICE_ATTRIBUTES + ProductsResponse.JSON_PROPERTY_RAW_DEVICE_ATTRIBUTES, + ProductsResponse.JSON_PROPERTY_REMOTE_CONTROL, + ProductsResponse.JSON_PROPERTY_VELOCITY, + ProductsResponse.JSON_PROPERTY_DEVELOPER_TOOLS }) @jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.7.0") public class ProductsResponse { @@ -125,6 +131,15 @@ public class ProductsResponse { public static final String JSON_PROPERTY_RAW_DEVICE_ATTRIBUTES = "rawDeviceAttributes"; private SignalResponseRawDeviceAttributes rawDeviceAttributes; + public static final String JSON_PROPERTY_REMOTE_CONTROL = "remoteControl"; + private SignalResponseRemoteControl remoteControl; + + public static final String JSON_PROPERTY_VELOCITY = "velocity"; + private SignalResponseVelocity velocity; + + public static final String JSON_PROPERTY_DEVELOPER_TOOLS = "developerTools"; + private SignalResponseDeveloperTools developerTools; + public ProductsResponse() { } @@ -674,6 +689,84 @@ public void setRawDeviceAttributes(SignalResponseRawDeviceAttributes rawDeviceAt } + public ProductsResponse remoteControl(SignalResponseRemoteControl remoteControl) { + this.remoteControl = remoteControl; + return this; + } + + /** + * Get remoteControl + * @return remoteControl + **/ + @jakarta.annotation.Nullable + @Schema(description = "") + @JsonProperty(JSON_PROPERTY_REMOTE_CONTROL) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public SignalResponseRemoteControl getRemoteControl() { + return remoteControl; + } + + + @JsonProperty(JSON_PROPERTY_REMOTE_CONTROL) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setRemoteControl(SignalResponseRemoteControl remoteControl) { + this.remoteControl = remoteControl; + } + + + public ProductsResponse velocity(SignalResponseVelocity velocity) { + this.velocity = velocity; + return this; + } + + /** + * Get velocity + * @return velocity + **/ + @jakarta.annotation.Nullable + @Schema(description = "") + @JsonProperty(JSON_PROPERTY_VELOCITY) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public SignalResponseVelocity getVelocity() { + return velocity; + } + + + @JsonProperty(JSON_PROPERTY_VELOCITY) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setVelocity(SignalResponseVelocity velocity) { + this.velocity = velocity; + } + + + public ProductsResponse developerTools(SignalResponseDeveloperTools developerTools) { + this.developerTools = developerTools; + return this; + } + + /** + * Get developerTools + * @return developerTools + **/ + @jakarta.annotation.Nullable + @Schema(description = "") + @JsonProperty(JSON_PROPERTY_DEVELOPER_TOOLS) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public SignalResponseDeveloperTools getDeveloperTools() { + return developerTools; + } + + + @JsonProperty(JSON_PROPERTY_DEVELOPER_TOOLS) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setDeveloperTools(SignalResponseDeveloperTools developerTools) { + this.developerTools = developerTools; + } + + /** * Return true if this ProductsResponse object is equal to o. */ @@ -706,12 +799,15 @@ public boolean equals(Object o) { Objects.equals(this.highActivity, productsResponse.highActivity) && Objects.equals(this.locationSpoofing, productsResponse.locationSpoofing) && Objects.equals(this.suspectScore, productsResponse.suspectScore) && - Objects.equals(this.rawDeviceAttributes, productsResponse.rawDeviceAttributes); + Objects.equals(this.rawDeviceAttributes, productsResponse.rawDeviceAttributes) && + Objects.equals(this.remoteControl, productsResponse.remoteControl) && + Objects.equals(this.velocity, productsResponse.velocity) && + Objects.equals(this.developerTools, productsResponse.developerTools); } @Override public int hashCode() { - return Objects.hash(identification, botd, ipInfo, incognito, rootApps, emulator, clonedApp, factoryReset, jailbroken, frida, ipBlocklist, tor, privacySettings, virtualMachine, vpn, proxy, tampering, highActivity, locationSpoofing, suspectScore, rawDeviceAttributes); + return Objects.hash(identification, botd, ipInfo, incognito, rootApps, emulator, clonedApp, factoryReset, jailbroken, frida, ipBlocklist, tor, privacySettings, virtualMachine, vpn, proxy, tampering, highActivity, locationSpoofing, suspectScore, rawDeviceAttributes, remoteControl, velocity, developerTools); } @Override @@ -739,6 +835,9 @@ public String toString() { sb.append(" locationSpoofing: ").append(toIndentedString(locationSpoofing)).append("\n"); sb.append(" suspectScore: ").append(toIndentedString(suspectScore)).append("\n"); sb.append(" rawDeviceAttributes: ").append(toIndentedString(rawDeviceAttributes)).append("\n"); + sb.append(" remoteControl: ").append(toIndentedString(remoteControl)).append("\n"); + sb.append(" velocity: ").append(toIndentedString(velocity)).append("\n"); + sb.append(" developerTools: ").append(toIndentedString(developerTools)).append("\n"); sb.append("}"); return sb.toString(); } diff --git a/sdk/src/main/java/com/fingerprint/model/RemoteControlResult.java b/sdk/src/main/java/com/fingerprint/model/RemoteControlResult.java new file mode 100644 index 0000000..9600795 --- /dev/null +++ b/sdk/src/main/java/com/fingerprint/model/RemoteControlResult.java @@ -0,0 +1,97 @@ +package com.fingerprint.model; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fingerprint.sdk.JSON; +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * RemoteControlResult + */ + + +@JsonPropertyOrder({ + RemoteControlResult.JSON_PROPERTY_RESULT +}) +@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.7.0") +public class RemoteControlResult { + public static final String JSON_PROPERTY_RESULT = "result"; + private Boolean result; + + public RemoteControlResult() { + } + + public RemoteControlResult result(Boolean result) { + this.result = result; + return this; + } + + /** + * `true` if the request came from a machine being remotely controlled (e.g. TeamViewer), `false` otherwise. + * @return result + **/ + @jakarta.annotation.Nonnull + @Schema(example = "false", required = true, description = "`true` if the request came from a machine being remotely controlled (e.g. TeamViewer), `false` otherwise. ") + @JsonProperty(JSON_PROPERTY_RESULT) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public Boolean getResult() { + return result; + } + + + @JsonProperty(JSON_PROPERTY_RESULT) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setResult(Boolean result) { + this.result = result; + } + + + /** + * Return true if this RemoteControlResult object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + RemoteControlResult remoteControlResult = (RemoteControlResult) o; + return Objects.equals(this.result, remoteControlResult.result); + } + + @Override + public int hashCode() { + return Objects.hash(result); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class RemoteControlResult {\n"); + sb.append(" result: ").append(toIndentedString(result)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/sdk/src/main/java/com/fingerprint/model/SignalResponseDeveloperTools.java b/sdk/src/main/java/com/fingerprint/model/SignalResponseDeveloperTools.java new file mode 100644 index 0000000..9f27a6c --- /dev/null +++ b/sdk/src/main/java/com/fingerprint/model/SignalResponseDeveloperTools.java @@ -0,0 +1,131 @@ +package com.fingerprint.model; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fingerprint.model.DeveloperToolsResult; +import com.fingerprint.model.ProductError; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fingerprint.sdk.JSON; +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * SignalResponseDeveloperTools + */ + + +@JsonPropertyOrder({ + SignalResponseDeveloperTools.JSON_PROPERTY_DATA, + SignalResponseDeveloperTools.JSON_PROPERTY_ERROR +}) +@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.7.0") +public class SignalResponseDeveloperTools { + public static final String JSON_PROPERTY_DATA = "data"; + private DeveloperToolsResult data; + + public static final String JSON_PROPERTY_ERROR = "error"; + private ProductError error; + + public SignalResponseDeveloperTools() { + } + + public SignalResponseDeveloperTools data(DeveloperToolsResult data) { + this.data = data; + return this; + } + + /** + * Get data + * @return data + **/ + @jakarta.annotation.Nullable + @Schema(description = "") + @JsonProperty(JSON_PROPERTY_DATA) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public DeveloperToolsResult getData() { + return data; + } + + + @JsonProperty(JSON_PROPERTY_DATA) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setData(DeveloperToolsResult data) { + this.data = data; + } + + + public SignalResponseDeveloperTools error(ProductError error) { + this.error = error; + return this; + } + + /** + * Get error + * @return error + **/ + @jakarta.annotation.Nullable + @Schema(description = "") + @JsonProperty(JSON_PROPERTY_ERROR) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public ProductError getError() { + return error; + } + + + @JsonProperty(JSON_PROPERTY_ERROR) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setError(ProductError error) { + this.error = error; + } + + + /** + * Return true if this SignalResponseDeveloperTools object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SignalResponseDeveloperTools signalResponseDeveloperTools = (SignalResponseDeveloperTools) o; + return Objects.equals(this.data, signalResponseDeveloperTools.data) && + Objects.equals(this.error, signalResponseDeveloperTools.error); + } + + @Override + public int hashCode() { + return Objects.hash(data, error); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class SignalResponseDeveloperTools {\n"); + sb.append(" data: ").append(toIndentedString(data)).append("\n"); + sb.append(" error: ").append(toIndentedString(error)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/sdk/src/main/java/com/fingerprint/model/SignalResponseRemoteControl.java b/sdk/src/main/java/com/fingerprint/model/SignalResponseRemoteControl.java new file mode 100644 index 0000000..564e850 --- /dev/null +++ b/sdk/src/main/java/com/fingerprint/model/SignalResponseRemoteControl.java @@ -0,0 +1,131 @@ +package com.fingerprint.model; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fingerprint.model.ProductError; +import com.fingerprint.model.RemoteControlResult; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fingerprint.sdk.JSON; +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * SignalResponseRemoteControl + */ + + +@JsonPropertyOrder({ + SignalResponseRemoteControl.JSON_PROPERTY_DATA, + SignalResponseRemoteControl.JSON_PROPERTY_ERROR +}) +@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.7.0") +public class SignalResponseRemoteControl { + public static final String JSON_PROPERTY_DATA = "data"; + private RemoteControlResult data; + + public static final String JSON_PROPERTY_ERROR = "error"; + private ProductError error; + + public SignalResponseRemoteControl() { + } + + public SignalResponseRemoteControl data(RemoteControlResult data) { + this.data = data; + return this; + } + + /** + * Get data + * @return data + **/ + @jakarta.annotation.Nullable + @Schema(description = "") + @JsonProperty(JSON_PROPERTY_DATA) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public RemoteControlResult getData() { + return data; + } + + + @JsonProperty(JSON_PROPERTY_DATA) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setData(RemoteControlResult data) { + this.data = data; + } + + + public SignalResponseRemoteControl error(ProductError error) { + this.error = error; + return this; + } + + /** + * Get error + * @return error + **/ + @jakarta.annotation.Nullable + @Schema(description = "") + @JsonProperty(JSON_PROPERTY_ERROR) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public ProductError getError() { + return error; + } + + + @JsonProperty(JSON_PROPERTY_ERROR) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setError(ProductError error) { + this.error = error; + } + + + /** + * Return true if this SignalResponseRemoteControl object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SignalResponseRemoteControl signalResponseRemoteControl = (SignalResponseRemoteControl) o; + return Objects.equals(this.data, signalResponseRemoteControl.data) && + Objects.equals(this.error, signalResponseRemoteControl.error); + } + + @Override + public int hashCode() { + return Objects.hash(data, error); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class SignalResponseRemoteControl {\n"); + sb.append(" data: ").append(toIndentedString(data)).append("\n"); + sb.append(" error: ").append(toIndentedString(error)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/sdk/src/main/java/com/fingerprint/model/SignalResponseVelocity.java b/sdk/src/main/java/com/fingerprint/model/SignalResponseVelocity.java new file mode 100644 index 0000000..c95658c --- /dev/null +++ b/sdk/src/main/java/com/fingerprint/model/SignalResponseVelocity.java @@ -0,0 +1,131 @@ +package com.fingerprint.model; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fingerprint.model.ProductError; +import com.fingerprint.model.VelocityResult; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fingerprint.sdk.JSON; +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * SignalResponseVelocity + */ + + +@JsonPropertyOrder({ + SignalResponseVelocity.JSON_PROPERTY_DATA, + SignalResponseVelocity.JSON_PROPERTY_ERROR +}) +@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.7.0") +public class SignalResponseVelocity { + public static final String JSON_PROPERTY_DATA = "data"; + private VelocityResult data; + + public static final String JSON_PROPERTY_ERROR = "error"; + private ProductError error; + + public SignalResponseVelocity() { + } + + public SignalResponseVelocity data(VelocityResult data) { + this.data = data; + return this; + } + + /** + * Get data + * @return data + **/ + @jakarta.annotation.Nullable + @Schema(description = "") + @JsonProperty(JSON_PROPERTY_DATA) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public VelocityResult getData() { + return data; + } + + + @JsonProperty(JSON_PROPERTY_DATA) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setData(VelocityResult data) { + this.data = data; + } + + + public SignalResponseVelocity error(ProductError error) { + this.error = error; + return this; + } + + /** + * Get error + * @return error + **/ + @jakarta.annotation.Nullable + @Schema(description = "") + @JsonProperty(JSON_PROPERTY_ERROR) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public ProductError getError() { + return error; + } + + + @JsonProperty(JSON_PROPERTY_ERROR) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setError(ProductError error) { + this.error = error; + } + + + /** + * Return true if this SignalResponseVelocity object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SignalResponseVelocity signalResponseVelocity = (SignalResponseVelocity) o; + return Objects.equals(this.data, signalResponseVelocity.data) && + Objects.equals(this.error, signalResponseVelocity.error); + } + + @Override + public int hashCode() { + return Objects.hash(data, error); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class SignalResponseVelocity {\n"); + sb.append(" data: ").append(toIndentedString(data)).append("\n"); + sb.append(" error: ").append(toIndentedString(error)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/sdk/src/main/java/com/fingerprint/model/VelocityIntervalResult.java b/sdk/src/main/java/com/fingerprint/model/VelocityIntervalResult.java new file mode 100644 index 0000000..5ea4e0b --- /dev/null +++ b/sdk/src/main/java/com/fingerprint/model/VelocityIntervalResult.java @@ -0,0 +1,161 @@ +package com.fingerprint.model; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fingerprint.sdk.JSON; +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * Is absent if the velocity data could not be generated for the visitor ID. + */ + +@Schema(description = "Is absent if the velocity data could not be generated for the visitor ID. ") +@JsonPropertyOrder({ + VelocityIntervalResult.JSON_PROPERTY_5M, + VelocityIntervalResult.JSON_PROPERTY_1H, + VelocityIntervalResult.JSON_PROPERTY_24H +}) +@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.7.0") +public class VelocityIntervalResult { + public static final String JSON_PROPERTY_5M = "5m"; + private Integer _5m; + + public static final String JSON_PROPERTY_1H = "1h"; + private Integer _1h; + + public static final String JSON_PROPERTY_24H = "24h"; + private Integer _24h; + + public VelocityIntervalResult() { + } + + public VelocityIntervalResult _5m(Integer _5m) { + this._5m = _5m; + return this; + } + + /** + * Get _5m + * @return _5m + **/ + @jakarta.annotation.Nonnull + @Schema(example = "1", required = true, description = "") + @JsonProperty(JSON_PROPERTY_5M) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public Integer get5m() { + return _5m; + } + + + @JsonProperty(JSON_PROPERTY_5M) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void set5m(Integer _5m) { + this._5m = _5m; + } + + + public VelocityIntervalResult _1h(Integer _1h) { + this._1h = _1h; + return this; + } + + /** + * Get _1h + * @return _1h + **/ + @jakarta.annotation.Nonnull + @Schema(example = "1", required = true, description = "") + @JsonProperty(JSON_PROPERTY_1H) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public Integer get1h() { + return _1h; + } + + + @JsonProperty(JSON_PROPERTY_1H) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void set1h(Integer _1h) { + this._1h = _1h; + } + + + public VelocityIntervalResult _24h(Integer _24h) { + this._24h = _24h; + return this; + } + + /** + * The `24h` interval of `distinctIp`, `distinctLinkedId`, and `distinctCountry` will be omitted if the number of `events`` for the visitor ID in the last 24 hours (`events.intervals.['24h']`) is higher than 20.000. + * @return _24h + **/ + @jakarta.annotation.Nullable + @Schema(example = "1", description = "The `24h` interval of `distinctIp`, `distinctLinkedId`, and `distinctCountry` will be omitted if the number of `events`` for the visitor ID in the last 24 hours (`events.intervals.['24h']`) is higher than 20.000. ") + @JsonProperty(JSON_PROPERTY_24H) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public Integer get24h() { + return _24h; + } + + + @JsonProperty(JSON_PROPERTY_24H) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void set24h(Integer _24h) { + this._24h = _24h; + } + + + /** + * Return true if this VelocityIntervalResult object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + VelocityIntervalResult velocityIntervalResult = (VelocityIntervalResult) o; + return Objects.equals(this._5m, velocityIntervalResult._5m) && + Objects.equals(this._1h, velocityIntervalResult._1h) && + Objects.equals(this._24h, velocityIntervalResult._24h); + } + + @Override + public int hashCode() { + return Objects.hash(_5m, _1h, _24h); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class VelocityIntervalResult {\n"); + sb.append(" _5m: ").append(toIndentedString(_5m)).append("\n"); + sb.append(" _1h: ").append(toIndentedString(_1h)).append("\n"); + sb.append(" _24h: ").append(toIndentedString(_24h)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/sdk/src/main/java/com/fingerprint/model/VelocityIntervals.java b/sdk/src/main/java/com/fingerprint/model/VelocityIntervals.java new file mode 100644 index 0000000..1edba23 --- /dev/null +++ b/sdk/src/main/java/com/fingerprint/model/VelocityIntervals.java @@ -0,0 +1,98 @@ +package com.fingerprint.model; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fingerprint.model.VelocityIntervalResult; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fingerprint.sdk.JSON; +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * VelocityIntervals + */ + + +@JsonPropertyOrder({ + VelocityIntervals.JSON_PROPERTY_INTERVALS +}) +@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.7.0") +public class VelocityIntervals { + public static final String JSON_PROPERTY_INTERVALS = "intervals"; + private VelocityIntervalResult intervals; + + public VelocityIntervals() { + } + + public VelocityIntervals intervals(VelocityIntervalResult intervals) { + this.intervals = intervals; + return this; + } + + /** + * Get intervals + * @return intervals + **/ + @jakarta.annotation.Nullable + @Schema(description = "") + @JsonProperty(JSON_PROPERTY_INTERVALS) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public VelocityIntervalResult getIntervals() { + return intervals; + } + + + @JsonProperty(JSON_PROPERTY_INTERVALS) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setIntervals(VelocityIntervalResult intervals) { + this.intervals = intervals; + } + + + /** + * Return true if this VelocityIntervals object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + VelocityIntervals velocityIntervals = (VelocityIntervals) o; + return Objects.equals(this.intervals, velocityIntervals.intervals); + } + + @Override + public int hashCode() { + return Objects.hash(intervals); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class VelocityIntervals {\n"); + sb.append(" intervals: ").append(toIndentedString(intervals)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/sdk/src/main/java/com/fingerprint/model/VelocityResult.java b/sdk/src/main/java/com/fingerprint/model/VelocityResult.java new file mode 100644 index 0000000..70d0b54 --- /dev/null +++ b/sdk/src/main/java/com/fingerprint/model/VelocityResult.java @@ -0,0 +1,194 @@ +package com.fingerprint.model; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fingerprint.model.VelocityIntervals; +import java.util.Arrays; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fingerprint.sdk.JSON; +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * Sums key data points for a specific `visitorId` at three distinct time intervals: 5 minutes, 1 hour, and 24 hours as follows: - Number of identification events attributed to the visitor ID - Number of distinct IP addresses associated to the visitor ID. - Number of distinct countries associated with the visitor ID. - Number of distinct `linkedId`s associated with the visitor ID. The `24h` interval of `distinctIp`, `distinctLinkedId`, and `distinctCountry` will be omitted if the number of `events` for the visitor ID in the last 24 hours (`events.intervals.['24h']`) is higher than 20.000. + */ + +@Schema(description = "Sums key data points for a specific `visitorId` at three distinct time intervals: 5 minutes, 1 hour, and 24 hours as follows: - Number of identification events attributed to the visitor ID - Number of distinct IP addresses associated to the visitor ID. - Number of distinct countries associated with the visitor ID. - Number of distinct `linkedId`s associated with the visitor ID. The `24h` interval of `distinctIp`, `distinctLinkedId`, and `distinctCountry` will be omitted if the number of `events` for the visitor ID in the last 24 hours (`events.intervals.['24h']`) is higher than 20.000. ") +@JsonPropertyOrder({ + VelocityResult.JSON_PROPERTY_DISTINCT_IP, + VelocityResult.JSON_PROPERTY_DISTINCT_LINKED_ID, + VelocityResult.JSON_PROPERTY_DISTINCT_COUNTRY, + VelocityResult.JSON_PROPERTY_EVENTS +}) +@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.7.0") +public class VelocityResult { + public static final String JSON_PROPERTY_DISTINCT_IP = "distinctIp"; + private VelocityIntervals distinctIp; + + public static final String JSON_PROPERTY_DISTINCT_LINKED_ID = "distinctLinkedId"; + private VelocityIntervals distinctLinkedId; + + public static final String JSON_PROPERTY_DISTINCT_COUNTRY = "distinctCountry"; + private VelocityIntervals distinctCountry; + + public static final String JSON_PROPERTY_EVENTS = "events"; + private VelocityIntervals events; + + public VelocityResult() { + } + + public VelocityResult distinctIp(VelocityIntervals distinctIp) { + this.distinctIp = distinctIp; + return this; + } + + /** + * Get distinctIp + * @return distinctIp + **/ + @jakarta.annotation.Nonnull + @Schema(required = true, description = "") + @JsonProperty(JSON_PROPERTY_DISTINCT_IP) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public VelocityIntervals getDistinctIp() { + return distinctIp; + } + + + @JsonProperty(JSON_PROPERTY_DISTINCT_IP) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setDistinctIp(VelocityIntervals distinctIp) { + this.distinctIp = distinctIp; + } + + + public VelocityResult distinctLinkedId(VelocityIntervals distinctLinkedId) { + this.distinctLinkedId = distinctLinkedId; + return this; + } + + /** + * Get distinctLinkedId + * @return distinctLinkedId + **/ + @jakarta.annotation.Nonnull + @Schema(required = true, description = "") + @JsonProperty(JSON_PROPERTY_DISTINCT_LINKED_ID) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public VelocityIntervals getDistinctLinkedId() { + return distinctLinkedId; + } + + + @JsonProperty(JSON_PROPERTY_DISTINCT_LINKED_ID) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setDistinctLinkedId(VelocityIntervals distinctLinkedId) { + this.distinctLinkedId = distinctLinkedId; + } + + + public VelocityResult distinctCountry(VelocityIntervals distinctCountry) { + this.distinctCountry = distinctCountry; + return this; + } + + /** + * Get distinctCountry + * @return distinctCountry + **/ + @jakarta.annotation.Nonnull + @Schema(required = true, description = "") + @JsonProperty(JSON_PROPERTY_DISTINCT_COUNTRY) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public VelocityIntervals getDistinctCountry() { + return distinctCountry; + } + + + @JsonProperty(JSON_PROPERTY_DISTINCT_COUNTRY) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setDistinctCountry(VelocityIntervals distinctCountry) { + this.distinctCountry = distinctCountry; + } + + + public VelocityResult events(VelocityIntervals events) { + this.events = events; + return this; + } + + /** + * Get events + * @return events + **/ + @jakarta.annotation.Nonnull + @Schema(required = true, description = "") + @JsonProperty(JSON_PROPERTY_EVENTS) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + + public VelocityIntervals getEvents() { + return events; + } + + + @JsonProperty(JSON_PROPERTY_EVENTS) + @JsonInclude(value = JsonInclude.Include.ALWAYS) + public void setEvents(VelocityIntervals events) { + this.events = events; + } + + + /** + * Return true if this VelocityResult object is equal to o. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + VelocityResult velocityResult = (VelocityResult) o; + return Objects.equals(this.distinctIp, velocityResult.distinctIp) && + Objects.equals(this.distinctLinkedId, velocityResult.distinctLinkedId) && + Objects.equals(this.distinctCountry, velocityResult.distinctCountry) && + Objects.equals(this.events, velocityResult.events); + } + + @Override + public int hashCode() { + return Objects.hash(distinctIp, distinctLinkedId, distinctCountry, events); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class VelocityResult {\n"); + sb.append(" distinctIp: ").append(toIndentedString(distinctIp)).append("\n"); + sb.append(" distinctLinkedId: ").append(toIndentedString(distinctLinkedId)).append("\n"); + sb.append(" distinctCountry: ").append(toIndentedString(distinctCountry)).append("\n"); + sb.append(" events: ").append(toIndentedString(events)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/sdk/src/main/java/com/fingerprint/model/WebhookVisit.java b/sdk/src/main/java/com/fingerprint/model/WebhookVisit.java index 8d8f602..d4149e2 100644 --- a/sdk/src/main/java/com/fingerprint/model/WebhookVisit.java +++ b/sdk/src/main/java/com/fingerprint/model/WebhookVisit.java @@ -11,6 +11,7 @@ import com.fingerprint.model.ClonedAppResult; import com.fingerprint.model.Confidence; import com.fingerprint.model.DeprecatedIPLocation; +import com.fingerprint.model.DeveloperToolsResult; import com.fingerprint.model.EmulatorResult; import com.fingerprint.model.FactoryResetResult; import com.fingerprint.model.FridaResult; @@ -22,11 +23,13 @@ import com.fingerprint.model.PrivacySettingsResult; import com.fingerprint.model.ProxyResult; import com.fingerprint.model.RawDeviceAttributesResultValue; +import com.fingerprint.model.RemoteControlResult; import com.fingerprint.model.RootAppsResult; import com.fingerprint.model.SeenAt; import com.fingerprint.model.SuspectScoreResult; import com.fingerprint.model.TamperingResult; import com.fingerprint.model.TorResult; +import com.fingerprint.model.VelocityResult; import com.fingerprint.model.VirtualMachineResult; import com.fingerprint.model.VpnResult; import java.time.OffsetDateTime; @@ -66,6 +69,9 @@ WebhookVisit.JSON_PROPERTY_HIGH_ACTIVITY, WebhookVisit.JSON_PROPERTY_LOCATION_SPOOFING, WebhookVisit.JSON_PROPERTY_SUSPECT_SCORE, + WebhookVisit.JSON_PROPERTY_REMOTE_CONTROL, + WebhookVisit.JSON_PROPERTY_VELOCITY, + WebhookVisit.JSON_PROPERTY_DEVELOPER_TOOLS, WebhookVisit.JSON_PROPERTY_REQUEST_ID, WebhookVisit.JSON_PROPERTY_BROWSER_DETAILS, WebhookVisit.JSON_PROPERTY_IP, @@ -151,6 +157,15 @@ public class WebhookVisit { public static final String JSON_PROPERTY_SUSPECT_SCORE = "suspectScore"; private SuspectScoreResult suspectScore; + public static final String JSON_PROPERTY_REMOTE_CONTROL = "remoteControl"; + private RemoteControlResult remoteControl; + + public static final String JSON_PROPERTY_VELOCITY = "velocity"; + private VelocityResult velocity; + + public static final String JSON_PROPERTY_DEVELOPER_TOOLS = "developerTools"; + private DeveloperToolsResult developerTools; + public static final String JSON_PROPERTY_REQUEST_ID = "requestId"; private String requestId; @@ -799,6 +814,84 @@ public void setSuspectScore(SuspectScoreResult suspectScore) { } + public WebhookVisit remoteControl(RemoteControlResult remoteControl) { + this.remoteControl = remoteControl; + return this; + } + + /** + * Get remoteControl + * @return remoteControl + **/ + @jakarta.annotation.Nullable + @Schema(description = "") + @JsonProperty(JSON_PROPERTY_REMOTE_CONTROL) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public RemoteControlResult getRemoteControl() { + return remoteControl; + } + + + @JsonProperty(JSON_PROPERTY_REMOTE_CONTROL) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setRemoteControl(RemoteControlResult remoteControl) { + this.remoteControl = remoteControl; + } + + + public WebhookVisit velocity(VelocityResult velocity) { + this.velocity = velocity; + return this; + } + + /** + * Get velocity + * @return velocity + **/ + @jakarta.annotation.Nullable + @Schema(description = "") + @JsonProperty(JSON_PROPERTY_VELOCITY) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public VelocityResult getVelocity() { + return velocity; + } + + + @JsonProperty(JSON_PROPERTY_VELOCITY) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setVelocity(VelocityResult velocity) { + this.velocity = velocity; + } + + + public WebhookVisit developerTools(DeveloperToolsResult developerTools) { + this.developerTools = developerTools; + return this; + } + + /** + * Get developerTools + * @return developerTools + **/ + @jakarta.annotation.Nullable + @Schema(description = "") + @JsonProperty(JSON_PROPERTY_DEVELOPER_TOOLS) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + + public DeveloperToolsResult getDeveloperTools() { + return developerTools; + } + + + @JsonProperty(JSON_PROPERTY_DEVELOPER_TOOLS) + @JsonInclude(value = JsonInclude.Include.USE_DEFAULTS) + public void setDeveloperTools(DeveloperToolsResult developerTools) { + this.developerTools = developerTools; + } + + public WebhookVisit requestId(String requestId) { this.requestId = requestId; return this; @@ -1179,6 +1272,9 @@ public boolean equals(Object o) { Objects.equals(this.highActivity, webhookVisit.highActivity) && Objects.equals(this.locationSpoofing, webhookVisit.locationSpoofing) && Objects.equals(this.suspectScore, webhookVisit.suspectScore) && + Objects.equals(this.remoteControl, webhookVisit.remoteControl) && + Objects.equals(this.velocity, webhookVisit.velocity) && + Objects.equals(this.developerTools, webhookVisit.developerTools) && Objects.equals(this.requestId, webhookVisit.requestId) && Objects.equals(this.browserDetails, webhookVisit.browserDetails) && Objects.equals(this.ip, webhookVisit.ip) && @@ -1196,7 +1292,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(visitorId, clientReferrer, userAgent, bot, ipInfo, incognito, rootApps, emulator, clonedApp, factoryReset, jailbroken, frida, ipBlocklist, tor, privacySettings, virtualMachine, vpn, proxy, tampering, rawDeviceAttributes, highActivity, locationSpoofing, suspectScore, requestId, browserDetails, ip, ipLocation, timestamp, time, url, tag, linkedId, confidence, visitorFound, firstSeenAt, lastSeenAt); + return Objects.hash(visitorId, clientReferrer, userAgent, bot, ipInfo, incognito, rootApps, emulator, clonedApp, factoryReset, jailbroken, frida, ipBlocklist, tor, privacySettings, virtualMachine, vpn, proxy, tampering, rawDeviceAttributes, highActivity, locationSpoofing, suspectScore, remoteControl, velocity, developerTools, requestId, browserDetails, ip, ipLocation, timestamp, time, url, tag, linkedId, confidence, visitorFound, firstSeenAt, lastSeenAt); } @Override @@ -1226,6 +1322,9 @@ public String toString() { sb.append(" highActivity: ").append(toIndentedString(highActivity)).append("\n"); sb.append(" locationSpoofing: ").append(toIndentedString(locationSpoofing)).append("\n"); sb.append(" suspectScore: ").append(toIndentedString(suspectScore)).append("\n"); + sb.append(" remoteControl: ").append(toIndentedString(remoteControl)).append("\n"); + sb.append(" velocity: ").append(toIndentedString(velocity)).append("\n"); + sb.append(" developerTools: ").append(toIndentedString(developerTools)).append("\n"); sb.append(" requestId: ").append(toIndentedString(requestId)).append("\n"); sb.append(" browserDetails: ").append(toIndentedString(browserDetails)).append("\n"); sb.append(" ip: ").append(toIndentedString(ip)).append("\n"); diff --git a/sdk/src/test/resources/mocks/get_event_200.json b/sdk/src/test/resources/mocks/get_event_200.json index 0633376..6361db1 100644 --- a/sdk/src/test/resources/mocks/get_event_200.json +++ b/sdk/src/test/resources/mocks/get_event_200.json @@ -178,7 +178,8 @@ "methods": { "timezoneMismatch": false, "publicVPN": false, - "auxiliaryMobile": false + "auxiliaryMobile": false, + "osMismatch": false } } }, @@ -258,12 +259,7 @@ }, "cpuClass": {}, "fonts": { - "value": [ - "Arial Unicode MS", - "Gill Sans", - "Helvetica Neue", - "Menlo" - ] + "value": ["Arial Unicode MS", "Gill Sans", "Helvetica Neue", "Menlo"] } } }, @@ -276,6 +272,42 @@ "data": { "result": false } + }, + "remoteControl": { + "data": { + "result": false + } + }, + "velocity": { + "data": { + "distinctIp": { + "intervals": { + "5m": 1, + "1h": 1, + "24h": 1 + } + }, + "distinctLinkedId": {}, + "distinctCountry": { + "intervals": { + "5m": 1, + "1h": 2, + "24h": 2 + } + }, + "events": { + "intervals": { + "5m": 1, + "1h": 5, + "24h": 5 + } + } + } + }, + "developerTools": { + "data": { + "result": false + } } } } diff --git a/sdk/src/test/resources/mocks/get_event_200_all_errors.json b/sdk/src/test/resources/mocks/get_event_200_all_errors.json index 8245e5d..2fe90cc 100644 --- a/sdk/src/test/resources/mocks/get_event_200_all_errors.json +++ b/sdk/src/test/resources/mocks/get_event_200_all_errors.json @@ -135,6 +135,24 @@ "code": "Failed", "message": "internal server error" } + }, + "remoteControl": { + "error": { + "code": "Failed", + "message": "internal server error" + } + }, + "velocity": { + "error": { + "code": "Failed", + "message": "internal server error" + } + }, + "developerTools": { + "error": { + "code": "Failed", + "message": "internal server error" + } } } } diff --git a/sdk/src/test/resources/mocks/get_event_200_extra_fields.json b/sdk/src/test/resources/mocks/get_event_200_extra_fields.json index 03e50c0..c15eb56 100644 --- a/sdk/src/test/resources/mocks/get_event_200_extra_fields.json +++ b/sdk/src/test/resources/mocks/get_event_200_extra_fields.json @@ -6,6 +6,7 @@ "requestId": "0KSh65EnVoB85JBmloQK", "incognito": true, "linkedId": "somelinkedId", + "tag": {}, "time": "2019-05-21T16:40:13Z", "timestamp": 1582299576512, "url": "https://www.example.com/login", @@ -44,7 +45,8 @@ "userAgent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) ...." }, "confidence": { - "score": 0.97 + "score": 0.97, + "revision": "v1.1" }, "visitorFound": true, "firstSeenAt": { @@ -59,6 +61,8 @@ }, "botd": { "data": { + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 YaBrowser/24.1.0.0 Safari/537.36", + "requestId": "1708102555327.NLOjmg", "bot": { "result": "notDetected" }, diff --git a/sdk/src/test/resources/mocks/webhook.json b/sdk/src/test/resources/mocks/webhook.json index 9b23b07..15332a0 100644 --- a/sdk/src/test/resources/mocks/webhook.json +++ b/sdk/src/test/resources/mocks/webhook.json @@ -123,7 +123,8 @@ "methods": { "timezoneMismatch": false, "publicVPN": false, - "auxiliaryMobile": false + "auxiliaryMobile": false, + "osMismatch": false } }, "proxy": { @@ -187,5 +188,35 @@ }, "suspectScore": { "result": 0 + }, + "remoteControl": { + "result": false + }, + "velocity": { + "distinctIp": { + "intervals": { + "5m": 1, + "1h": 1, + "24h": 1 + } + }, + "distinctLinkedId": {}, + "distinctCountry": { + "intervals": { + "5m": 1, + "1h": 2, + "24h": 2 + } + }, + "events": { + "intervals": { + "5m": 1, + "1h": 5, + "24h": 5 + } + } + }, + "developerTools": { + "result": false } -} \ No newline at end of file +} From 0b8d7b5cb6a90d42b07a94d2cfb6ad4f062a95c9 Mon Sep 17 00:00:00 2001 From: Sergey Shelomentsev Date: Wed, 31 Jul 2024 17:59:03 +0300 Subject: [PATCH 04/17] feat: add DELETE API --- res/fingerprint-server-api.yaml | 311 ++++++++++++++++++++++++++++++-- 1 file changed, 292 insertions(+), 19 deletions(-) diff --git a/res/fingerprint-server-api.yaml b/res/fingerprint-server-api.yaml index 96a8159..8d365ec 100644 --- a/res/fingerprint-server-api.yaml +++ b/res/fingerprint-server-api.yaml @@ -41,9 +41,8 @@ paths: Get a detailed analysis of an individual identification event, including Smart Signals. - **Only for Enterprise customers:** Please note that the response - includes mobile signals (e.g. `rootApps`) even if the request originated - from a non-mobile platform. + Please note that the response includes mobile signals (e.g. `rootApps`) + even if the request originated from a non-mobile platform. It is highly recommended that you **ignore** the mobile signals for such requests. @@ -80,6 +79,65 @@ paths: application/json: schema: $ref: '#/components/schemas/ErrorEvent404Response' + put: + tags: + - Fingerprint + operationId: updateEvent + summary: Update an event with a given request ID + description: > + Change information in existing events specified by `requestId` or *flag + suspicious events*. + + + When an event is created, it is assigned `linkedId` and `tag` submitted + through the JS agent parameters. This information might not be available + on the client so the Server API allows for updating the attributes after + the fact. + + + **Warning** It's not possible to update events older than 10 days. + parameters: + - name: request_id + in: path + description: >- + The unique event + [identifier](https://dev.fingerprint.com/docs/js-agent#requestid). + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/EventUpdateRequest' + responses: + '200': + description: OK + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorUpdateEvent400Response' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorCommon403Response' + '404': + description: Not found + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorEvent404Response' + '409': + description: Conflict + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorUpdateEvent409Response' /visitors/{visitor_id}: get: tags: @@ -243,8 +301,8 @@ paths: If you are interested in using this API, please [contact our support - team](https://fingerprint.com/support/) to activate it for you. - Otherwise, you will receive a 403. + team](https://fingerprint.com/support/) to enable it for you. Otherwise, + you will receive a 403. parameters: - name: visitor_id in: path @@ -265,7 +323,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ErrorVisitsDelete400Response' + $ref: '#/components/schemas/ErrorVisitor400Response' '403': description: Forbidden. Access to this API is denied. content: @@ -279,7 +337,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ErrorVisitsDelete404Response' + $ref: '#/components/schemas/ErrorVisitor404Response' '429': description: Too Many Requests. The request is throttled. content: @@ -455,6 +513,27 @@ paths: result: true suspectScore: result: 0 + remoteControl: + result: false + velocity: + distinctIp: + intervals: + 5m: 1 + 1h: 1 + 24h: 1 + distinctLinkedId: {} + distinctCountry: + intervals: + 5m: 1 + 1h: 2 + 24h: 2 + events: + intervals: + 5m: 1 + 1h: 5 + 24h: 5 + developerTools: + result: false responses: default: description: The server doesn't validate the answer. @@ -709,14 +788,14 @@ components: example: request throttled required: - error - ErrorVisitsDelete404Response: + ErrorVisitor404Response: type: object additionalProperties: false properties: error: type: object additionalProperties: false - title: ErrorVisitsDelete404ResponseError + title: ErrorVisitor404ResponseError properties: code: type: string @@ -732,7 +811,7 @@ components: required: - code - message - ErrorVisitsDelete400Response: + ErrorVisitor400Response: type: object additionalProperties: false properties: @@ -809,6 +888,12 @@ components: $ref: '#/components/schemas/LocationSpoofingResult' suspectScore: $ref: '#/components/schemas/SuspectScoreResult' + remoteControl: + $ref: '#/components/schemas/RemoteControlResult' + velocity: + $ref: '#/components/schemas/VelocityResult' + developerTools: + $ref: '#/components/schemas/DeveloperToolsResult' requestId: description: Unique identifier of the user's identification request. type: string @@ -1529,6 +1614,33 @@ components: $ref: '#/components/schemas/RawDeviceAttributesResult' error: $ref: '#/components/schemas/IdentificationError' + remoteControl: + title: SignalResponseRemoteControl + type: object + additionalProperties: false + properties: + data: + $ref: '#/components/schemas/RemoteControlResult' + error: + $ref: '#/components/schemas/ProductError' + velocity: + title: SignalResponseVelocity + type: object + additionalProperties: false + properties: + data: + $ref: '#/components/schemas/VelocityResult' + error: + $ref: '#/components/schemas/ProductError' + developerTools: + title: SignalResponseDeveloperTools + type: object + additionalProperties: false + properties: + data: + $ref: '#/components/schemas/DeveloperToolsResult' + error: + $ref: '#/components/schemas/ProductError' EventResponse: description: >- Contains results from all activated products - Fingerprint Pro, Bot @@ -1820,6 +1932,36 @@ components: example: 0 required: - result + VelocityResult: + type: object + description: > + Sums key data points for a specific `visitorId` at three distinct time + intervals: 5 minutes, 1 hour, and 24 hours as follows: + + - Number of identification events attributed to the visitor ID - Number + of distinct IP addresses associated to the visitor ID. - Number of + distinct countries associated with the visitor ID. - Number of distinct + `linkedId`s associated with the visitor ID. + + The `24h` interval of `distinctIp`, `distinctLinkedId`, and + `distinctCountry` will be omitted if the number of `events` for the + visitor ID in the last 24 hours (`events.intervals.['24h']`) is higher + than 20.000. + additionalProperties: false + properties: + distinctIp: + $ref: '#/components/schemas/VelocityIntervals' + distinctLinkedId: + $ref: '#/components/schemas/VelocityIntervals' + distinctCountry: + $ref: '#/components/schemas/VelocityIntervals' + events: + $ref: '#/components/schemas/VelocityIntervals' + required: + - distinctIp + - distinctLinkedId + - distinctCountry + - events RawDeviceAttributesResult: type: object description: > @@ -1857,19 +1999,27 @@ components: additionalProperties: false properties: time: - title: Time description: > - Time in UTC when the most recent factory reset of the Android or iOS - device was done. If there is no sign of factory reset or the client - is not a mobile device, the field will contain the epoch time (1 - January 1970) in UTC. + Indicates the time (in UTC) of the most recent factory reset that + happened on the **mobile device**. + + When a factory reset cannot be detected on the mobile device or when + the request is initiated from a browser, this field will correspond + to the *epoch* time (i.e 1 Jan 1970 UTC). + + See [Factory Reset + Detection](https://dev.fingerprint.com/docs/smart-signals-overview#factory-reset-detection) + to learn more about this Smart Signal. type: string format: date-time example: '2022-06-09T22:58:36Z' timestamp: - description: >- - Same value as it's in the `time` field but represented in timestamp - format. + description: > + This field is just another representation of the value in the `time` + field. + + The time of the most recent factory reset that happened on the + **mobile device** is expressed as Unix epoch time. type: integer format: int64 example: 1654815517198 @@ -2024,4 +2174,127 @@ components: example: too many requests required: - code - - message \ No newline at end of file + - message + RemoteControlResult: + type: object + additionalProperties: false + properties: + result: + type: boolean + description: > + `true` if the request came from a machine being remotely controlled + (e.g. TeamViewer), `false` otherwise. + example: false + required: + - result + DeveloperToolsResult: + type: object + additionalProperties: false + properties: + result: + type: boolean + description: > + `true` if the browser is Chrome with DevTools open or Firefox with + Developer Tools open, `false` otherwise. + example: false + required: + - result + EventUpdateRequest: + type: object + properties: + linkedId: + type: string + description: LinkedID value to assign to the existing event + tag: + type: object + description: >- + Full `tag` value to be set to the existing event. Replaces any + existing `tag` payload completely. + suspect: + type: boolean + description: Suspect flag indicating observed suspicious or fraudulent event + ErrorUpdateEvent400Response: + type: object + additionalProperties: false + properties: + error: + type: object + additionalProperties: false + title: ErrorUpdateEvent400ResponseError + properties: + code: + type: string + description: > + Error code: * `RequestCannotBeParsed` - the JSON content of the + request contains some errors that prevented us from parsing it + (wrong type/surpassed limits) * `Failed` - the event is more + than 10 days old and cannot be updated + enum: + - RequestCannotBeParsed + - Failed + example: RequestCannotBeParsed + message: + type: string + description: Details about the underlying issue with the input payload + example: suspect flag must be a boolean + required: + - code + - message + ErrorUpdateEvent409Response: + type: object + additionalProperties: false + properties: + error: + type: object + additionalProperties: false + title: ErrorUpdateEvent409ResponseError + properties: + code: + type: string + description: > + Error code: * `StateNotReady` - The event specified with request + id is not ready for updates yet. Try again. + + This error happens in rare cases when update API is called + immediately after receiving the request id on the client. In + case you need to send information right away, we recommend using + the JS agent API instead. + enum: + - StateNotReady + example: StateNotReady + message: + type: string + example: resource is not mutable yet, try again + required: + - code + - message + VelocityIntervals: + type: object + additionalProperties: false + properties: + intervals: + $ref: '#/components/schemas/VelocityIntervalResult' + VelocityIntervalResult: + type: object + description: > + Is absent if the velocity data could not be generated for the visitor + ID. + additionalProperties: false + properties: + 5m: + type: integer + example: 1 + 1h: + type: integer + example: 1 + 24h: + type: integer + description: > + The `24h` interval of `distinctIp`, `distinctLinkedId`, and + `distinctCountry` will be omitted if the number of `events`` for the + visitor ID in the last 24 hours (`events.intervals.['24h']`) is + higher than 20.000. + example: 1 + required: + - 5m + - 1h From ffcb77256d225c89daf982da3ee86dfe1967cebd Mon Sep 17 00:00:00 2001 From: Sergey Shelomentsev Date: Mon, 5 Aug 2024 17:21:25 +0300 Subject: [PATCH 05/17] ci: fix version replacement for linux --- scripts/generate.sh | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/scripts/generate.sh b/scripts/generate.sh index 5e1ccc1..a0c7dc9 100755 --- a/scripts/generate.sh +++ b/scripts/generate.sh @@ -19,7 +19,14 @@ fi echo "VERSION: $VERSION" -sed -i '' -e "s/projectVersion = .*$/projectVersion = $VERSION/g" ./gradle.properties -sed -i '' -e "s/^VERSION=.*$/VERSION='$VERSION'/g" ./scripts/generate.sh - +platform=$(uname) +( + if [ "$platform" = "Darwin" ]; then + sed -i '' -e "s/projectVersion = .*$/projectVersion = $VERSION/g" ./gradle.properties + sed -i '' -e "s/^VERSION=.*$/VERSION='$VERSION'/g" ./scripts/generate.sh + else + sed -i "s/projectVersion = .*$/projectVersion = $VERSION/g" ./gradle.properties + sed -i "s/^VERSION=.*$/VERSION='$VERSION'/g" ./scripts/generate.sh + fi +) ./gradlew build test From 09223809229dba20897dd6eb0e516af99802d763 Mon Sep 17 00:00:00 2001 From: Sergey Shelomentsev Date: Mon, 5 Aug 2024 17:25:19 +0300 Subject: [PATCH 06/17] feat: add `Webhook.IsValidWebhookSignature` function for validating webhook signature --- docs/Visit.md | 2 +- docs/WebhookVisit.md | 2 +- res/fingerprint-server-api.yaml | 6 ++---- sdk/src/main/java/com/fingerprint/model/Visit.java | 13 ++++++++----- .../java/com/fingerprint/model/WebhookVisit.java | 13 ++++++++----- 5 files changed, 20 insertions(+), 16 deletions(-) diff --git a/docs/Visit.md b/docs/Visit.md index aac5e07..6b50495 100644 --- a/docs/Visit.md +++ b/docs/Visit.md @@ -15,7 +15,7 @@ |**timestamp** | **Long** | Timestamp of the event with millisecond precision in Unix time. | | |**time** | **OffsetDateTime** | Time expressed according to ISO 8601 in UTC format. | | |**url** | **String** | Page URL from which the identification request was sent. | | -|**tag** | **Map<String, Object>** | A customer-provided value or an object that was sent with identification request. | | +|**tag** | **Map<String, Object>** | A customer-provided value or an object that was sent with identification request. | [optional] | |**linkedId** | **String** | A customer-provided id that was sent with identification request. | [optional] | |**confidence** | [**Confidence**](Confidence.md) | | [optional] | |**visitorFound** | **Boolean** | Attribute represents if a visitor had been identified before. | | diff --git a/docs/WebhookVisit.md b/docs/WebhookVisit.md index 17f1a08..861902f 100644 --- a/docs/WebhookVisit.md +++ b/docs/WebhookVisit.md @@ -40,7 +40,7 @@ |**timestamp** | **Long** | Timestamp of the event with millisecond precision in Unix time. | | |**time** | **OffsetDateTime** | Time expressed according to ISO 8601 in UTC format. | | |**url** | **String** | Page URL from which the identification request was sent. | | -|**tag** | **Map<String, Object>** | A customer-provided value or an object that was sent with identification request. | | +|**tag** | **Map<String, Object>** | A customer-provided value or an object that was sent with identification request. | [optional] | |**linkedId** | **String** | A customer-provided id that was sent with identification request. | [optional] | |**confidence** | [**Confidence**](Confidence.md) | | [optional] | |**visitorFound** | **Boolean** | Attribute represents if a visitor had been identified before. | | diff --git a/res/fingerprint-server-api.yaml b/res/fingerprint-server-api.yaml index 8d365ec..f6e6d70 100644 --- a/res/fingerprint-server-api.yaml +++ b/res/fingerprint-server-api.yaml @@ -670,8 +670,8 @@ components: - time - timestamp - url - - tag - visitorFound + - tag lastTimestamp: description: > ⚠️ Deprecated paging attribute, please use `paginationKey` instead. @@ -998,7 +998,6 @@ components: - time - timestamp - url - - tag - visitorFound Visit: type: object @@ -1109,7 +1108,6 @@ components: - time - timestamp - url - - tag - visitorFound title: Visit BrowserDetails: @@ -1429,9 +1427,9 @@ components: - time - timestamp - url - - tag - visitorFound - visitorId + - tag error: $ref: '#/components/schemas/IdentificationError' botd: diff --git a/sdk/src/main/java/com/fingerprint/model/Visit.java b/sdk/src/main/java/com/fingerprint/model/Visit.java index 3d40695..f752af3 100644 --- a/sdk/src/main/java/com/fingerprint/model/Visit.java +++ b/sdk/src/main/java/com/fingerprint/model/Visit.java @@ -66,7 +66,7 @@ public class Visit { private String url; public static final String JSON_PROPERTY_TAG = "tag"; - private Map tag = new HashMap<>(); + private Map tag = null; public static final String JSON_PROPERTY_LINKED_ID = "linkedId"; private String linkedId; @@ -302,6 +302,9 @@ public Visit tag(Map tag) { } public Visit puttagItem(String key, Object tagItem) { + if (this.tag == null) { + this.tag = new HashMap<>(); + } this.tag.put(key, tagItem); return this; } @@ -310,10 +313,10 @@ public Visit puttagItem(String key, Object tagItem) { * A customer-provided value or an object that was sent with identification request. * @return tag **/ - @jakarta.annotation.Nonnull - @Schema(required = true, description = "A customer-provided value or an object that was sent with identification request.") + @jakarta.annotation.Nullable + @Schema(description = "A customer-provided value or an object that was sent with identification request.") @JsonProperty(JSON_PROPERTY_TAG) - @JsonInclude(content = JsonInclude.Include.ALWAYS, value = JsonInclude.Include.ALWAYS) + @JsonInclude(content = JsonInclude.Include.ALWAYS, value = JsonInclude.Include.USE_DEFAULTS) public Map getTag() { return tag; @@ -321,7 +324,7 @@ public Map getTag() { @JsonProperty(JSON_PROPERTY_TAG) - @JsonInclude(content = JsonInclude.Include.ALWAYS, value = JsonInclude.Include.ALWAYS) + @JsonInclude(content = JsonInclude.Include.ALWAYS, value = JsonInclude.Include.USE_DEFAULTS) public void setTag(Map tag) { this.tag = tag; } diff --git a/sdk/src/main/java/com/fingerprint/model/WebhookVisit.java b/sdk/src/main/java/com/fingerprint/model/WebhookVisit.java index d4149e2..48b90e6 100644 --- a/sdk/src/main/java/com/fingerprint/model/WebhookVisit.java +++ b/sdk/src/main/java/com/fingerprint/model/WebhookVisit.java @@ -188,7 +188,7 @@ public class WebhookVisit { private String url; public static final String JSON_PROPERTY_TAG = "tag"; - private Map tag = new HashMap<>(); + private Map tag = null; public static final String JSON_PROPERTY_LINKED_ID = "linkedId"; private String linkedId; @@ -1082,6 +1082,9 @@ public WebhookVisit tag(Map tag) { } public WebhookVisit puttagItem(String key, Object tagItem) { + if (this.tag == null) { + this.tag = new HashMap<>(); + } this.tag.put(key, tagItem); return this; } @@ -1090,10 +1093,10 @@ public WebhookVisit puttagItem(String key, Object tagItem) { * A customer-provided value or an object that was sent with identification request. * @return tag **/ - @jakarta.annotation.Nonnull - @Schema(required = true, description = "A customer-provided value or an object that was sent with identification request.") + @jakarta.annotation.Nullable + @Schema(description = "A customer-provided value or an object that was sent with identification request.") @JsonProperty(JSON_PROPERTY_TAG) - @JsonInclude(content = JsonInclude.Include.ALWAYS, value = JsonInclude.Include.ALWAYS) + @JsonInclude(content = JsonInclude.Include.ALWAYS, value = JsonInclude.Include.USE_DEFAULTS) public Map getTag() { return tag; @@ -1101,7 +1104,7 @@ public Map getTag() { @JsonProperty(JSON_PROPERTY_TAG) - @JsonInclude(content = JsonInclude.Include.ALWAYS, value = JsonInclude.Include.ALWAYS) + @JsonInclude(content = JsonInclude.Include.ALWAYS, value = JsonInclude.Include.USE_DEFAULTS) public void setTag(Map tag) { this.tag = tag; } From 43b0f3bd0a52b0fe441c93b1437c25f3a8cc1296 Mon Sep 17 00:00:00 2001 From: Sergey Shelomentsev Date: Mon, 5 Aug 2024 17:39:20 +0300 Subject: [PATCH 07/17] chore: update readme --- README.md | 47 ++++++++++++++++++----------------------------- 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index fc3abea..9d4142e 100644 --- a/README.md +++ b/README.md @@ -86,31 +86,6 @@ Then manually install the following JARs: - `target/fingerprint-pro-server-api-sdk-5.1.1.jar` -## Usage - -To add a HTTP proxy for the API client, use `ClientConfig`: -```java - -import org.glassfish.jersey.apache.connector.ApacheConnectorProvider; -import org.glassfish.jersey.client.ClientConfig; -import org.glassfish.jersey.client.ClientProperties; -import com.fingerprint.sdk.*; -import com.fingerprint.api.FingerprintApi; - -... - -ApiClient defaultClient = Configuration.getDefaultApiClient(); -ClientConfig clientConfig = defaultClient.getClientConfig(); -clientConfig.connectorProvider(new ApacheConnectorProvider()); -clientConfig.property(ClientProperties.PROXY_URI, "http://proxy_url_here"); -clientConfig.property(ClientProperties.PROXY_USERNAME, "proxy_username"); -clientConfig.property(ClientProperties.PROXY_PASSWORD, "proxy_password"); -defaultClient.setClientConfig(clientConfig); - -FingerprintApi apiInstance = new FingerprintApi(defaultClient); - -``` - ## Getting Started Please follow the [installation](#installation) instruction and execute the following Java code: @@ -236,6 +211,7 @@ Class | Method | HTTP request | Description *FingerprintApi* | [**deleteVisitorData**](docs/FingerprintApi.md#deleteVisitorData) | **DELETE** /visitors/{visitor_id} | Delete data by visitor ID *FingerprintApi* | [**getEvent**](docs/FingerprintApi.md#getEvent) | **GET** /events/{request_id} | Get event by request ID *FingerprintApi* | [**getVisits**](docs/FingerprintApi.md#getVisits) | **GET** /visitors/{visitor_id} | Get visits by visitor ID +*FingerprintApi* | [**updateEvent**](docs/FingerprintApi.md#updateEvent) | **PUT** /events/{request_id} | Update an event with a given request ID *FingerprintApi* | [**webhookTrace**](docs/FingerprintApi.md#webhookTrace) | **TRACE** /webhook | @@ -251,6 +227,7 @@ Class | Method | HTTP request | Description - [DataCenter](docs/DataCenter.md) - [DeprecatedIPLocation](docs/DeprecatedIPLocation.md) - [DeprecatedIPLocationCity](docs/DeprecatedIPLocationCity.md) + - [DeveloperToolsResult](docs/DeveloperToolsResult.md) - [EmulatorResult](docs/EmulatorResult.md) - [Error](docs/Error.md) - [ErrorCommon403Response](docs/ErrorCommon403Response.md) @@ -258,12 +235,17 @@ Class | Method | HTTP request | Description - [ErrorCommon429ResponseError](docs/ErrorCommon429ResponseError.md) - [ErrorEvent404Response](docs/ErrorEvent404Response.md) - [ErrorEvent404ResponseError](docs/ErrorEvent404ResponseError.md) + - [ErrorUpdateEvent400Response](docs/ErrorUpdateEvent400Response.md) + - [ErrorUpdateEvent400ResponseError](docs/ErrorUpdateEvent400ResponseError.md) + - [ErrorUpdateEvent409Response](docs/ErrorUpdateEvent409Response.md) + - [ErrorUpdateEvent409ResponseError](docs/ErrorUpdateEvent409ResponseError.md) + - [ErrorVisitor400Response](docs/ErrorVisitor400Response.md) + - [ErrorVisitor400ResponseError](docs/ErrorVisitor400ResponseError.md) + - [ErrorVisitor404Response](docs/ErrorVisitor404Response.md) + - [ErrorVisitor404ResponseError](docs/ErrorVisitor404ResponseError.md) - [ErrorVisits403](docs/ErrorVisits403.md) - - [ErrorVisitsDelete400Response](docs/ErrorVisitsDelete400Response.md) - - [ErrorVisitsDelete400ResponseError](docs/ErrorVisitsDelete400ResponseError.md) - - [ErrorVisitsDelete404Response](docs/ErrorVisitsDelete404Response.md) - - [ErrorVisitsDelete404ResponseError](docs/ErrorVisitsDelete404ResponseError.md) - [EventResponse](docs/EventResponse.md) + - [EventUpdateRequest](docs/EventUpdateRequest.md) - [FactoryResetResult](docs/FactoryResetResult.md) - [FridaResult](docs/FridaResult.md) - [HighActivityResult](docs/HighActivityResult.md) @@ -287,11 +269,13 @@ Class | Method | HTTP request | Description - [ProductsResponseIdentificationData](docs/ProductsResponseIdentificationData.md) - [ProxyResult](docs/ProxyResult.md) - [RawDeviceAttributesResultValue](docs/RawDeviceAttributesResultValue.md) + - [RemoteControlResult](docs/RemoteControlResult.md) - [Response](docs/Response.md) - [ResponseVisits](docs/ResponseVisits.md) - [RootAppsResult](docs/RootAppsResult.md) - [SeenAt](docs/SeenAt.md) - [SignalResponseClonedApp](docs/SignalResponseClonedApp.md) + - [SignalResponseDeveloperTools](docs/SignalResponseDeveloperTools.md) - [SignalResponseEmulator](docs/SignalResponseEmulator.md) - [SignalResponseFactoryReset](docs/SignalResponseFactoryReset.md) - [SignalResponseFrida](docs/SignalResponseFrida.md) @@ -304,10 +288,12 @@ Class | Method | HTTP request | Description - [SignalResponsePrivacySettings](docs/SignalResponsePrivacySettings.md) - [SignalResponseProxy](docs/SignalResponseProxy.md) - [SignalResponseRawDeviceAttributes](docs/SignalResponseRawDeviceAttributes.md) + - [SignalResponseRemoteControl](docs/SignalResponseRemoteControl.md) - [SignalResponseRootApps](docs/SignalResponseRootApps.md) - [SignalResponseSuspectScore](docs/SignalResponseSuspectScore.md) - [SignalResponseTampering](docs/SignalResponseTampering.md) - [SignalResponseTor](docs/SignalResponseTor.md) + - [SignalResponseVelocity](docs/SignalResponseVelocity.md) - [SignalResponseVirtualMachine](docs/SignalResponseVirtualMachine.md) - [SignalResponseVpn](docs/SignalResponseVpn.md) - [Subdivision](docs/Subdivision.md) @@ -315,6 +301,9 @@ Class | Method | HTTP request | Description - [TamperingResult](docs/TamperingResult.md) - [TooManyRequestsResponse](docs/TooManyRequestsResponse.md) - [TorResult](docs/TorResult.md) + - [VelocityIntervalResult](docs/VelocityIntervalResult.md) + - [VelocityIntervals](docs/VelocityIntervals.md) + - [VelocityResult](docs/VelocityResult.md) - [VirtualMachineResult](docs/VirtualMachineResult.md) - [Visit](docs/Visit.md) - [VpnResult](docs/VpnResult.md) From b8cebbebf869928c74261bb74a26a2ce0c0fde3e Mon Sep 17 00:00:00 2001 From: Sergey Shelomentsev Date: Mon, 5 Aug 2024 17:39:26 +0300 Subject: [PATCH 08/17] ci: task to copy generated readme --- sdk/sdk.gradle.kts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sdk/sdk.gradle.kts b/sdk/sdk.gradle.kts index 7cc36ca..a1da6d8 100644 --- a/sdk/sdk.gradle.kts +++ b/sdk/sdk.gradle.kts @@ -82,6 +82,11 @@ tasks.register("copyClasses") { into("src/main/java") } +tasks.register("copyReadme") { + from(layout.buildDirectory.file("generated/README.md")) + into(rootDir) +} + tasks.register("removeWrongDocumentationLinks") { doLast { fileTree("$rootDir/docs").files @@ -101,13 +106,16 @@ tasks.named("copyDocs") { tasks.named("copyClasses") { dependsOn(tasks.openApiGenerate) } + tasks.named("removeWrongDocumentationLinks") { dependsOn("copyDocs") + finalizedBy("copyReadme") } + tasks.named("build") { finalizedBy("removeWrongDocumentationLinks") } tasks.compileJava { - dependsOn(tasks.withType()) + dependsOn("copyClasses") } From 17b7dd94a84c6177c2e6264b8be3caa0f13920c7 Mon Sep 17 00:00:00 2001 From: Sergey Shelomentsev Date: Mon, 5 Aug 2024 17:40:28 +0300 Subject: [PATCH 09/17] ci: fix warning --- sdk/sdk.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/sdk.gradle.kts b/sdk/sdk.gradle.kts index a1da6d8..8c07e68 100644 --- a/sdk/sdk.gradle.kts +++ b/sdk/sdk.gradle.kts @@ -56,7 +56,7 @@ sourceSets { openApiGenerate { generatorName.set("java") inputSpec.set("$rootDir/res/fingerprint-server-api.yaml") - outputDir.set("$buildDir/generated") + outputDir.set("${layout.buildDirectory}/generated") groupId.set("com.fingerprint") id.set("fingerprint-pro-server-api-sdk") version.set(projectVersion) From b5dbe4b490f024f552d3e9c047ca6768485b1c62 Mon Sep 17 00:00:00 2001 From: Sergey Shelomentsev Date: Mon, 5 Aug 2024 18:25:50 +0300 Subject: [PATCH 10/17] test: add tests for webhook chore: update tests --- sdk/sdk.gradle.kts | 4 + .../java/com/fingerprint/sdk/Webhook.java | 53 ++++++ .../test/java/com/fingerprint/SealedTest.java | 2 +- .../java/com/fingerprint/WebhookTest.java | 48 ++++++ .../fingerprint/api/FingerprintApiTest.java | 156 +++++++++--------- 5 files changed, 188 insertions(+), 75 deletions(-) create mode 100644 sdk/src/main/java/com/fingerprint/sdk/Webhook.java create mode 100644 sdk/src/test/java/com/fingerprint/WebhookTest.java diff --git a/sdk/sdk.gradle.kts b/sdk/sdk.gradle.kts index 8c07e68..f00aee8 100644 --- a/sdk/sdk.gradle.kts +++ b/sdk/sdk.gradle.kts @@ -119,3 +119,7 @@ tasks.named("build") { tasks.compileJava { dependsOn("copyClasses") } + +tasks.test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/sdk/src/main/java/com/fingerprint/sdk/Webhook.java b/sdk/src/main/java/com/fingerprint/sdk/Webhook.java new file mode 100644 index 0000000..daf2098 --- /dev/null +++ b/sdk/src/main/java/com/fingerprint/sdk/Webhook.java @@ -0,0 +1,53 @@ +package com.fingerprint.sdk; + +import org.apache.commons.codec.binary.Hex; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +public class Webhook { + + /** + * Verifies the HMAC signature extracted from the "fpjs-event-signature" header of the incoming request. + * This is a part of the webhook signing process, which is available only for enterprise customers. + * @param header The value of the "fpjs-event-signature" header + * @param data The raw data of the incoming request + * @param secret The secret key used to sign the request + * @return true if the signature is valid + * @throws NoSuchAlgorithmException in case HMAC-SHA-256 isn't available + * @throws IllegalArgumentException if an invalid key is provided + */ + public static boolean isValidWebhookSignature(String header, byte[] data, String secret) throws NoSuchAlgorithmException { + String[] signatures = header.split(","); + for (String signature : signatures) { + String[] parts = signature.split("="); + if (parts.length == 2) { + final String version = parts[0]; + final String hash = parts[1]; + if (version.equals("v1") && isValidHmacSignature(hash, data, secret)) { + return true; + } + } + } + return false; + } + + private static final String ALGORITHM = "HmacSHA256"; + + private static boolean isValidHmacSignature(String signature, byte[] data, String secret) throws NoSuchAlgorithmException { + SecretKeySpec spec = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), ALGORITHM); + Mac mac = Mac.getInstance(ALGORITHM); + try { + mac.init(spec); + byte[] computed = mac.doFinal(data); + String computedHash = Hex.encodeHexString(computed).replace("-", "").toLowerCase(); + return computedHash.equals(signature); + } catch (InvalidKeyException e) { + return false; + } + } + +} diff --git a/sdk/src/test/java/com/fingerprint/SealedTest.java b/sdk/src/test/java/com/fingerprint/SealedTest.java index af1fa25..c618b63 100644 --- a/sdk/src/test/java/com/fingerprint/SealedTest.java +++ b/sdk/src/test/java/com/fingerprint/SealedTest.java @@ -33,7 +33,7 @@ public void unsealEventResponseTest() throws Exception { } ); - assert eventResponse.equals(expectedResponse); + assertEquals(expectedResponse, eventResponse); } @Test diff --git a/sdk/src/test/java/com/fingerprint/WebhookTest.java b/sdk/src/test/java/com/fingerprint/WebhookTest.java new file mode 100644 index 0000000..65f0cdc --- /dev/null +++ b/sdk/src/test/java/com/fingerprint/WebhookTest.java @@ -0,0 +1,48 @@ +package com.fingerprint; + +import com.fingerprint.sdk.Webhook; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; + +import java.security.NoSuchAlgorithmException; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class WebhookTest { + + private static final String validHeader = "v1=1b2c16b75bd2a870c114153ccda5bcfca63314bc722fa160d690de133ccbb9db"; + private static final String secret = "secret"; + private static final byte[] data = "data".getBytes(); + + @Test + public void validHeaderTest() throws NoSuchAlgorithmException { + boolean result = Webhook.isValidWebhookSignature(validHeader, data, secret); + Assertions.assertTrue(result); + } + + @Test + public void invalidHeaderTest() throws NoSuchAlgorithmException { + boolean result = Webhook.isValidWebhookSignature("v2=wrong", data, secret); + assert !result; + } + + @Test + public void headerWithoutVersionTest() throws NoSuchAlgorithmException { + boolean result = Webhook.isValidWebhookSignature("secretonly", data, secret); + assert !result; + } + + @Test + public void emptySecretTest() throws NoSuchAlgorithmException { + Assertions.assertThrows(IllegalArgumentException.class, () -> { + Webhook.isValidWebhookSignature("v1=value", data, ""); + }); + } + + @Test + public void emptyDataTest() throws NoSuchAlgorithmException { + boolean result = Webhook.isValidWebhookSignature(validHeader, "".getBytes(), secret); + assert !result; + } + +} diff --git a/sdk/src/test/java/com/fingerprint/api/FingerprintApiTest.java b/sdk/src/test/java/com/fingerprint/api/FingerprintApiTest.java index 3da7ec1..c594c2c 100644 --- a/sdk/src/test/java/com/fingerprint/api/FingerprintApiTest.java +++ b/sdk/src/test/java/com/fingerprint/api/FingerprintApiTest.java @@ -1,16 +1,19 @@ package com.fingerprint.api; import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fingerprint.model.*; import com.fingerprint.sdk.*; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import java.io.IOException; import java.io.InputStream; import java.util.LinkedHashMap; +import java.util.Map; import org.junit.jupiter.api.TestInstance; import org.mockito.Mockito; @@ -25,17 +28,17 @@ @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class FingerprintApiTest { private FingerprintApi api; - private final String MOCK_REQUEST_ID = "0KSh65EnVoB85JBmloQK"; - private final String MOCK_REQUEST_WITH_EXTRA_FIELDS_ID = "EXTRA_FIELDS"; - private final String MOCK_REQUEST_WITH_ALL_FAILED_SIGNALS = "ALL_FAILED_SIGNALS"; - private final String MOCK_REQUEST_BOTD_FAILED = "MOCK_REQUEST_BOTD_FAILED"; - private final String MOCK_REQUEST_BOTD_MANY_REQUEST = "MOCK_REQUEST_BOTD_MANY_REQUEST"; - private final String MOCK_REQUEST_IDENTIFICATION_FAILED = "MOCK_REQUEST_IDENTIFICATION_FAILED"; - private final String MOCK_REQUEST_IDENTIFICATION_MANY_REQUEST = "MOCK_REQUEST_IDENTIFICATION_MANY_REQUEST"; - private final String MOCK_VISITOR_ID = "AcxioeQKffpXF8iGQK3P"; - private final String MOCK_VISITOR_REQUEST_ID = "1655373780901.HhjRFX"; - private final String MOCK_WEBHOOK_VISITOR_ID = "3HNey93AkBW6CRbxV6xP"; - private final String MOCK_WEBHOOK_REQUEST_ID = "Px6VxbRC6WBkA39yeNH3"; + private static final String MOCK_REQUEST_ID = "0KSh65EnVoB85JBmloQK"; + private static final String MOCK_REQUEST_WITH_EXTRA_FIELDS_ID = "EXTRA_FIELDS"; + private static final String MOCK_REQUEST_WITH_ALL_FAILED_SIGNALS = "ALL_FAILED_SIGNALS"; + private static final String MOCK_REQUEST_BOTD_FAILED = "MOCK_REQUEST_BOTD_FAILED"; + private static final String MOCK_REQUEST_BOTD_MANY_REQUEST = "MOCK_REQUEST_BOTD_MANY_REQUEST"; + private static final String MOCK_REQUEST_IDENTIFICATION_FAILED = "MOCK_REQUEST_IDENTIFICATION_FAILED"; + private static final String MOCK_REQUEST_IDENTIFICATION_MANY_REQUEST = "MOCK_REQUEST_IDENTIFICATION_MANY_REQUEST"; + private static final String MOCK_VISITOR_ID = "AcxioeQKffpXF8iGQK3P"; + private static final String MOCK_VISITOR_REQUEST_ID = "1655373780901.HhjRFX"; + private static final String MOCK_WEBHOOK_VISITOR_ID = "3HNey93AkBW6CRbxV6xP"; + private static final String MOCK_WEBHOOK_REQUEST_ID = "Px6VxbRC6WBkA39yeNH3"; private InputStream getFileAsIOStream(final String fileName) { @@ -53,8 +56,7 @@ private InputStream getFileAsIOStream(final String fileName) { public void before() throws ApiException, IOException { api = Mockito.mock(FingerprintApi.class); when(api.getEvent(MOCK_REQUEST_ID)).thenReturn(fetchMockWithEventResponse("mocks/get_event_200.json")); -// TODO: Find the way to test SDK correctly for this scenario -// when(api.getEvent(MOCK_REQUEST_WITH_EXTRA_FIELDS_ID)).thenReturn(fetchMockWithEventResponse("mocks/get_event_200_extra_fields.json")); + when(api.getEvent(MOCK_REQUEST_WITH_EXTRA_FIELDS_ID)).thenReturn(fetchMockWithEventResponse("mocks/get_event_200_extra_fields.json")); when(api.getEvent(MOCK_REQUEST_WITH_ALL_FAILED_SIGNALS)).thenReturn(fetchMockWithEventResponse("mocks/get_event_200_all_errors.json")); when(api.getEvent(MOCK_REQUEST_BOTD_FAILED)).thenReturn(fetchMockWithEventResponse("mocks/get_event_200_botd_failed_error.json")); when(api.getEvent(MOCK_REQUEST_BOTD_MANY_REQUEST)).thenReturn(fetchMockWithEventResponse("mocks/get_event_200_botd_too_many_requests_error.json")); @@ -67,6 +69,7 @@ public void before() throws ApiException, IOException { private EventResponse fetchMockWithEventResponse(String fileName) throws IOException { ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule()); mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); JsonNullableModule jnm = new JsonNullableModule(); mapper.registerModule(jnm); @@ -88,9 +91,9 @@ private Response fetchMockVisit() throws IOException { @Test public void getEventTest() throws ApiException { EventResponse response = api.getEvent(MOCK_REQUEST_ID); - assert response.getProducts() != null; - assert response.getProducts().getIdentification() != null; - assert response.getProducts().getIdentification().getData() != null; + assertNotNull(response.getProducts()); + assertNotNull(response.getProducts().getIdentification()); + assertNotNull(response.getProducts().getIdentification().getData()); assertEquals("Ibk1527CUFmcnjLwIs4A9", response.getProducts().getIdentification().getData().getVisitorId()); assertFalse(response.getProducts().getClonedApp().getData().getResult()); @@ -109,7 +112,7 @@ public void getEventTest() throws ApiException { SignalResponseRawDeviceAttributes signalResponseRawDeviceAttributes = response.getProducts().getRawDeviceAttributes(); assertEquals(127, signalResponseRawDeviceAttributes.getData().get("architecture").getValue()); assertEquals(35.73832903057337, signalResponseRawDeviceAttributes.getData().get("audio").getValue()); - LinkedHashMap canvasAttribute = (LinkedHashMap)response.getProducts().getRawDeviceAttributes().getData().get("canvas").getValue(); + Map canvasAttribute = (Map) response.getProducts().getRawDeviceAttributes().getData().get("canvas").getValue(); assertEquals(true, canvasAttribute.get("Winding")); assertEquals("4dce9d6017c3e0c052a77252f29f2b1c", canvasAttribute.get("Geometry")); assertEquals("p3", signalResponseRawDeviceAttributes.getData().get("colorGamut").getValue()); @@ -117,43 +120,45 @@ public void getEventTest() throws ApiException { } /** - * TODO: Find the way to test SDK correctly for this scenario * Get event by requestId * This endpoint allows you to get events with all the information from each activated product (Fingerprint Pro or Bot Detection). Use the requestId as a URL path :request_id parameter. This API method is scoped to a request, i.e. all returned information is by requestId. * Answer will contain fields of additional products that don't described in schema * * @throws ApiException if the Api call fails */ -// @Test -// public void getEventWithExtraFieldsTest() throws ApiException { -// EventResponse response = api.getEvent(MOCK_REQUEST_WITH_EXTRA_FIELDS_ID); -// assert response.getProducts() != null; -// assert response.getProducts().getIdentification() != null; -// assert response.getProducts().getIdentification().getData() != null; -// assertEquals(response.getProducts().getIdentification().getData().getVisitorId(), "Ibk1527CUFmcnjLwIs4A9"); -// } + @Test + public void getEventWithExtraFieldsTest() throws ApiException { + EventResponse response = api.getEvent(MOCK_REQUEST_WITH_EXTRA_FIELDS_ID); + ProductsResponse products = response.getProducts(); + assertNotNull(products); + assertNotNull(products.getIdentification()); + assertNotNull(products.getIdentification().getData()); + assertEquals("Ibk1527CUFmcnjLwIs4A9", products.getIdentification().getData().getVisitorId()); + } @Test public void getEventWithAllFailedSignalsTest() throws ApiException { EventResponse response = api.getEvent(MOCK_REQUEST_WITH_ALL_FAILED_SIGNALS); - assert response.getProducts() != null; - assert response.getProducts().getIdentification().getError().getCode() == IdentificationError.CodeEnum.FAILED; - assert response.getProducts().getBotd().getError().getCode() == ProductError.CodeEnum.FAILED; - assert response.getProducts().getIpInfo().getError().getCode() == ProductError.CodeEnum.FAILED; - assert response.getProducts().getIncognito().getError().getCode() == IdentificationError.CodeEnum.FAILED; - assert response.getProducts().getRootApps().getError().getCode() == ProductError.CodeEnum.FAILED; - assert response.getProducts().getEmulator().getError().getCode() == ProductError.CodeEnum.FAILED; - assert response.getProducts().getIpBlocklist().getError().getCode() == ProductError.CodeEnum.FAILED; - assert response.getProducts().getTor().getError().getCode() == ProductError.CodeEnum.FAILED; - assert response.getProducts().getVpn().getError().getCode() == ProductError.CodeEnum.FAILED; - assert response.getProducts().getProxy().getError().getCode() == ProductError.CodeEnum.FAILED; - assert response.getProducts().getTampering().getError().getCode() == IdentificationError.CodeEnum.FAILED; - assert response.getProducts().getClonedApp().getError().getCode() == ProductError.CodeEnum.FAILED; - assert response.getProducts().getFactoryReset().getError().getCode() == ProductError.CodeEnum.FAILED; - assert response.getProducts().getJailbroken().getError().getCode() == ProductError.CodeEnum.FAILED; - assert response.getProducts().getFrida().getError().getCode() == ProductError.CodeEnum.FAILED; - assert response.getProducts().getPrivacySettings().getError().getCode() == ProductError.CodeEnum.FAILED; - assert response.getProducts().getVirtualMachine().getError().getCode() == ProductError.CodeEnum.FAILED; + ProductsResponse products = response.getProducts(); + + assertNotNull(products); + assertEquals(IdentificationError.CodeEnum.FAILED, products.getIdentification().getError().getCode()); + assertEquals(ProductError.CodeEnum.FAILED, products.getBotd().getError().getCode()); + assertEquals(ProductError.CodeEnum.FAILED, products.getIpInfo().getError().getCode()); + assertEquals(IdentificationError.CodeEnum.FAILED, products.getIncognito().getError().getCode()); + assertEquals(ProductError.CodeEnum.FAILED, products.getRootApps().getError().getCode()); + assertEquals(ProductError.CodeEnum.FAILED, products.getEmulator().getError().getCode()); + assertEquals(ProductError.CodeEnum.FAILED, products.getIpBlocklist().getError().getCode()); + assertEquals(ProductError.CodeEnum.FAILED, products.getTor().getError().getCode()); + assertEquals(ProductError.CodeEnum.FAILED, products.getVpn().getError().getCode()); + assertEquals(ProductError.CodeEnum.FAILED, products.getProxy().getError().getCode()); + assertEquals(IdentificationError.CodeEnum.FAILED, products.getTampering().getError().getCode()); + assertEquals(ProductError.CodeEnum.FAILED, products.getClonedApp().getError().getCode()); + assertEquals(ProductError.CodeEnum.FAILED, products.getFactoryReset().getError().getCode()); + assertEquals(ProductError.CodeEnum.FAILED, products.getJailbroken().getError().getCode()); + assertEquals(ProductError.CodeEnum.FAILED, products.getFrida().getError().getCode()); + assertEquals(ProductError.CodeEnum.FAILED, products.getPrivacySettings().getError().getCode()); + assertEquals(ProductError.CodeEnum.FAILED, products.getVirtualMachine().getError().getCode()); SignalResponseRawDeviceAttributes signalResponseRawDeviceAttributes = response.getProducts().getRawDeviceAttributes(); assertEquals("Error", signalResponseRawDeviceAttributes.getData().get("audio").getError().getName()); @@ -165,49 +170,52 @@ public void getEventWithAllFailedSignalsTest() throws ApiException { @Test public void getEventBotdFailedErrorTest() throws ApiException { EventResponse response = api.getEvent(MOCK_REQUEST_BOTD_FAILED); - assert response.getProducts() != null; - assert response.getProducts().getIdentification() != null; - assert response.getProducts().getIdentification().getData() != null; - assertEquals(response.getProducts().getIdentification().getData().getVisitorId(), "Ibk1527CUFmcnjLwIs4A9"); - assert response.getProducts().getBotd().getData() == null; - assert response.getProducts().getBotd().getError() != null; - assert response.getProducts().getBotd().getError().getCode() == ProductError.CodeEnum.FAILED; + ProductsResponse products = response.getProducts(); + assertNotNull(products); + assertNotNull(products.getIdentification()); + assertNotNull(products.getIdentification().getData()); + assertEquals("Ibk1527CUFmcnjLwIs4A9", products.getIdentification().getData().getVisitorId()); + + assertNotNull(products.getBotd()); + assertNotNull(products.getBotd().getError()); + assertEquals(ProductError.CodeEnum.FAILED, products.getBotd().getError().getCode()); } @Test public void getEventBotdManyRequestsErrorTest() throws ApiException { EventResponse response = api.getEvent(MOCK_REQUEST_BOTD_MANY_REQUEST); - assert response.getProducts() != null; - assert response.getProducts().getIdentification() != null; - assert response.getProducts().getIdentification().getData() != null; - assertEquals(response.getProducts().getIdentification().getData().getVisitorId(), "Ibk1527CUFmcnjLwIs4A9"); - assert response.getProducts().getBotd().getData() == null; - assert response.getProducts().getBotd().getError() != null; - assert response.getProducts().getBotd().getError().getCode() == ProductError.CodeEnum.TOO_MANY_REQUESTS; + ProductsResponse products = response.getProducts(); + assertNotNull(products); + assertNotNull(products.getIdentification()); + assertNotNull(products.getIdentification().getData()); + assertEquals("Ibk1527CUFmcnjLwIs4A9", response.getProducts().getIdentification().getData().getVisitorId()); + assertNotNull(products.getBotd()); + assertNotNull(products.getBotd().getError()); + assertEquals(ProductError.CodeEnum.TOO_MANY_REQUESTS, products.getBotd().getError().getCode()); } @Test public void getEventIdentificationFailedErrorTest() throws ApiException { EventResponse response = api.getEvent(MOCK_REQUEST_IDENTIFICATION_FAILED); - assert response.getProducts() != null; - assert response.getProducts().getIdentification() != null; - assert response.getProducts().getIdentification().getData() == null; - assert response.getProducts().getIdentification().getError() != null; - assert response.getProducts().getIdentification().getError().getCode() == IdentificationError.CodeEnum.FAILED; - assert response.getProducts().getBotd().getData() != null; - assert response.getProducts().getBotd().getError() == null; + ProductsResponse products = response.getProducts(); + assertNotNull(products); + assertNotNull(products.getIdentification()); + assertNotNull(products.getIdentification().getError()); + assertEquals(IdentificationError.CodeEnum.FAILED, products.getIdentification().getError().getCode()); + assertNotNull(products.getBotd()); + assertNotNull(products.getBotd().getData()); } @Test public void getEventIdentificationManyRequestsErrorTest() throws ApiException { EventResponse response = api.getEvent(MOCK_REQUEST_IDENTIFICATION_MANY_REQUEST); - assert response.getProducts() != null; - assert response.getProducts().getIdentification() != null; - assert response.getProducts().getIdentification().getData() == null; - assert response.getProducts().getIdentification().getError() != null; - assert response.getProducts().getIdentification().getError().getCode() == IdentificationError.CodeEnum._429_TOO_MANY_REQUESTS; - assert response.getProducts().getBotd().getData() != null; - assert response.getProducts().getBotd().getError() == null; + ProductsResponse products = response.getProducts(); + assertNotNull(products); + assertNotNull(products.getIdentification()); + assertNotNull(products.getIdentification().getError()); + assertEquals(IdentificationError.CodeEnum._429_TOO_MANY_REQUESTS, products.getIdentification().getError().getCode()); + assertNotNull(products.getBotd()); + assertNotNull(products.getBotd().getData()); } /** @@ -237,8 +245,8 @@ public void webhookTest() throws Exception { WebhookVisit visit = mapper.readValue(getFileAsIOStream("mocks/webhook.json"), WebhookVisit.class); - assert visit.getVisitorId().equals(MOCK_WEBHOOK_VISITOR_ID); - assert visit.getRequestId().equals(MOCK_WEBHOOK_REQUEST_ID); + assertEquals(MOCK_WEBHOOK_VISITOR_ID, visit.getVisitorId()); + assertEquals(MOCK_WEBHOOK_REQUEST_ID, visit.getRequestId()); } } From 38706aa85eebb3297773d4cc01b2be0e768c49c7 Mon Sep 17 00:00:00 2001 From: Sergey Shelomentsev Date: Mon, 5 Aug 2024 18:51:41 +0300 Subject: [PATCH 11/17] chore: add webhook sample chore: set encoding chore: add webhook sample to readme --- .../example/WebhookSignatureSample.java | 27 ++++++++++++++++ .../java/com/fingerprint/WebhookTest.java | 3 +- template/README.mustache | 31 +++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 examples/src/main/java/com/fingerprint/example/WebhookSignatureSample.java diff --git a/examples/src/main/java/com/fingerprint/example/WebhookSignatureSample.java b/examples/src/main/java/com/fingerprint/example/WebhookSignatureSample.java new file mode 100644 index 0000000..7702f70 --- /dev/null +++ b/examples/src/main/java/com/fingerprint/example/WebhookSignatureSample.java @@ -0,0 +1,27 @@ +package com.fingerprint.example; + +import com.fingerprint.sdk.Webhook; + +import java.nio.charset.StandardCharsets; +import java.security.NoSuchAlgorithmException; + +public class WebhookSignatureSample { + + public static void main(String... args) { + final String header = "v1=1b2c16b75bd2a870c114153ccda5bcfca63314bc722fa160d690de133ccbb9db"; + final String secret = "secret"; + final byte[] data = "data".getBytes(StandardCharsets.UTF_8); + + try { + boolean isSignatureValid = Webhook.isValidWebhookSignature(header, data, secret); + if (isSignatureValid) { + System.out.println("Webhook signature is valid"); + } else { + System.out.println("Webhook signature is not valid"); + } + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/sdk/src/test/java/com/fingerprint/WebhookTest.java b/sdk/src/test/java/com/fingerprint/WebhookTest.java index 65f0cdc..9e1b5e9 100644 --- a/sdk/src/test/java/com/fingerprint/WebhookTest.java +++ b/sdk/src/test/java/com/fingerprint/WebhookTest.java @@ -5,6 +5,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; +import java.nio.charset.StandardCharsets; import java.security.NoSuchAlgorithmException; @TestInstance(TestInstance.Lifecycle.PER_CLASS) @@ -12,7 +13,7 @@ public class WebhookTest { private static final String validHeader = "v1=1b2c16b75bd2a870c114153ccda5bcfca63314bc722fa160d690de133ccbb9db"; private static final String secret = "secret"; - private static final byte[] data = "data".getBytes(); + private static final byte[] data = "data".getBytes(StandardCharsets.UTF_8); @Test public void validHeaderTest() throws NoSuchAlgorithmException { diff --git a/template/README.mustache b/template/README.mustache index fba87ee..f4e1259 100644 --- a/template/README.mustache +++ b/template/README.mustache @@ -229,6 +229,37 @@ public class SealedResults { ``` To learn more, refer to example located in [src/examples/java/com/fingerprint/example/SealedResults.java](src/examples/java/com/fingerprint/example/SealedResults.java). +## Webhook signature validation +This SDK provides utility method for verifying the HMAC signature of the incoming webhook request. +```java + +@RestController +class WebhookController { + + @PostMapping("/api/webhook") + @ResponseBody + public String webhookHandler(@RequestBody String webhook, @RequestHeader HttpHeaders headers) { + final String secret = System.getenv("WEBHOOK_SIGNATURE_SECRET"); + if (secret == null || secret.isEmpty()) { + return new ResponseEntity("Secret key is not configured", HttpStatus.INTERNAL_SERVER_ERROR); + } + + final String header = headers.get("fpjs-event-signature"); + if (header == null || header.size == 0) { + return new ResponseEntity("Missing fpjs-event-signature header", HttpStatus.BAD_REQUEST); + } + final String signature = header[0]; + + final boolean isValidSignature = Webhook.isValidWebhookSignature(signature, data.getBytes(StandardCharsets.UTF_8), secret); + if (!isValidSignature) { + return new ResponseEntity("Webhook signature is not valid", HttpStatus.BAD_REQUEST); + } + + return new ResponseEntity("Webhook received", HttpStatus.OK); + } +} +``` + ## Documentation for API Endpoints All URIs are relative to *{{basePath}}* From 8b160b98437c70b1ab020c0e3a6e11ff934632c9 Mon Sep 17 00:00:00 2001 From: Sergey Shelomentsev Date: Mon, 5 Aug 2024 19:26:28 +0300 Subject: [PATCH 12/17] ci: fix build dir --- sdk/sdk.gradle.kts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/sdk.gradle.kts b/sdk/sdk.gradle.kts index f00aee8..6404647 100644 --- a/sdk/sdk.gradle.kts +++ b/sdk/sdk.gradle.kts @@ -56,7 +56,7 @@ sourceSets { openApiGenerate { generatorName.set("java") inputSpec.set("$rootDir/res/fingerprint-server-api.yaml") - outputDir.set("${layout.buildDirectory}/generated") + outputDir.set(layout.buildDirectory.dir("generated").get().asFile.path) groupId.set("com.fingerprint") id.set("fingerprint-pro-server-api-sdk") version.set(projectVersion) @@ -83,8 +83,8 @@ tasks.register("copyClasses") { } tasks.register("copyReadme") { - from(layout.buildDirectory.file("generated/README.md")) - into(rootDir) + from(file(layout.buildDirectory.file("generated/README.md"))) + into(file("$rootDir/")) } tasks.register("removeWrongDocumentationLinks") { From 7bdc4292d94fa506758854e11ed1021679e48a8d Mon Sep 17 00:00:00 2001 From: Sergey Shelomentsev Date: Mon, 5 Aug 2024 19:26:37 +0300 Subject: [PATCH 13/17] chore: updated readme --- README.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/README.md b/README.md index 9d4142e..37f4c2e 100644 --- a/README.md +++ b/README.md @@ -202,6 +202,37 @@ public class SealedResults { ``` To learn more, refer to example located in [src/examples/java/com/fingerprint/example/SealedResults.java](src/examples/java/com/fingerprint/example/SealedResults.java). +## Webhook signature validation +This SDK provides utility method for verifying the HMAC signature of the incoming webhook request. +```java + +@RestController +class WebhookController { + + @PostMapping("/api/webhook") + @ResponseBody + public String webhookHandler(@RequestBody String webhook, @RequestHeader HttpHeaders headers) { + final String secret = System.getenv("WEBHOOK_SIGNATURE_SECRET"); + if (secret == null || secret.isEmpty()) { + return new ResponseEntity("Secret key is not configured", HttpStatus.INTERNAL_SERVER_ERROR); + } + + final String header = headers.get("fpjs-event-signature"); + if (header == null || header.size == 0) { + return new ResponseEntity("Missing fpjs-event-signature header", HttpStatus.BAD_REQUEST); + } + final String signature = header[0]; + + final boolean isValidSignature = Webhook.isValidWebhookSignature(signature, data.getBytes(StandardCharsets.UTF_8), secret); + if (!isValidSignature) { + return new ResponseEntity("Webhook signature is not valid", HttpStatus.BAD_REQUEST); + } + + return new ResponseEntity("Webhook received", HttpStatus.OK); + } +} +``` + ## Documentation for API Endpoints All URIs are relative to *https://api.fpjs.io* From b1396fe9b02c05e9f649b3802a429b34062e58d2 Mon Sep 17 00:00:00 2001 From: Sergey Shelomentsev Date: Mon, 5 Aug 2024 19:34:36 +0300 Subject: [PATCH 14/17] chore: add samples chore: add samples --- scripts/sync.sh | 19 ++- ...on_too_many_requests_error_all_fields.json | 112 ++++++++++++++++++ .../mocks/get_visits_200_limit_1.json | 62 ++++++++++ .../resources/mocks/get_visits_403_error.json | 3 + .../mocks/update_event_400_error.json | 6 + .../mocks/update_event_403_error.json | 6 + .../mocks/update_event_404_error.json | 6 + .../mocks/update_event_409_error.json | 6 + .../update_event_multiple_fields_request.json | 7 ++ .../mocks/update_event_one_field_request.json | 3 + 10 files changed, 225 insertions(+), 5 deletions(-) create mode 100644 sdk/src/test/resources/mocks/get_event_200_identification_too_many_requests_error_all_fields.json create mode 100644 sdk/src/test/resources/mocks/get_visits_200_limit_1.json create mode 100644 sdk/src/test/resources/mocks/get_visits_403_error.json create mode 100644 sdk/src/test/resources/mocks/update_event_400_error.json create mode 100644 sdk/src/test/resources/mocks/update_event_403_error.json create mode 100644 sdk/src/test/resources/mocks/update_event_404_error.json create mode 100644 sdk/src/test/resources/mocks/update_event_409_error.json create mode 100644 sdk/src/test/resources/mocks/update_event_multiple_fields_request.json create mode 100644 sdk/src/test/resources/mocks/update_event_one_field_request.json diff --git a/scripts/sync.sh b/scripts/sync.sh index cafc606..f43376c 100755 --- a/scripts/sync.sh +++ b/scripts/sync.sh @@ -3,17 +3,26 @@ curl -o ./res/fingerprint-server-api.yaml https://fingerprintjs.github.io/fingerprint-pro-server-api-openapi/schemas/fingerprint-server-api-compact.yaml examplesList=( - 'get_visits_200_limit_500.json' - 'get_visits_429_too_many_requests_error.json' - 'get_event_200_extra_fields.json' 'get_event_200.json' 'get_event_200_all_errors.json' - 'get_event_403_error.json' - 'get_event_404_error.json' 'get_event_200_botd_failed_error.json' 'get_event_200_botd_too_many_requests_error.json' + 'get_event_200_extra_fields.json' 'get_event_200_identification_failed_error.json' 'get_event_200_identification_too_many_requests_error.json' + 'get_event_200_identification_too_many_requests_error_all_fields.json' + 'get_event_403_error.json' + 'get_event_404_error.json' + 'get_visits_200_limit_1.json' + 'get_visits_200_limit_500.json' + 'get_visits_403_error.json' + 'get_visits_429_too_many_requests_error.json' + 'update_event_400_error.json' + 'update_event_403_error.json' + 'update_event_404_error.json' + 'update_event_409_error.json' + 'update_event_multiple_fields_request.json' + 'update_event_one_field_request.json' 'webhook.json' ) diff --git a/sdk/src/test/resources/mocks/get_event_200_identification_too_many_requests_error_all_fields.json b/sdk/src/test/resources/mocks/get_event_200_identification_too_many_requests_error_all_fields.json new file mode 100644 index 0000000..0646213 --- /dev/null +++ b/sdk/src/test/resources/mocks/get_event_200_identification_too_many_requests_error_all_fields.json @@ -0,0 +1,112 @@ +{ + "products": { + "identification": { + "error": { + "code": "429 Too Many Requests", + "message": "too many requests" + } + }, + "botd": { + "error": { + "code": "TooManyRequests", + "message": "too many requests" + } + }, + "rootApps": { + "error": { + "code": "TooManyRequests", + "message": "too many requests" + } + }, + "emulator": { + "error": { + "code": "TooManyRequests", + "message": "too many requests" + } + }, + "ipInfo": { + "error": { + "code": "TooManyRequests", + "message": "too many requests" + } + }, + "ipBlocklist": { + "error": { + "code": "TooManyRequests", + "message": "too many requests" + } + }, + "tor": { + "error": { + "code": "TooManyRequests", + "message": "too many requests" + } + }, + "vpn": { + "error": { + "code": "TooManyRequests", + "message": "too many requests" + } + }, + "proxy": { + "error": { + "code": "TooManyRequests", + "message": "too many requests" + } + }, + "incognito": { + "error": { + "code": "429 Too Many Requests", + "message": "too many requests" + } + }, + "tampering": { + "error": { + "code": "429 Too Many Requests", + "message": "too many requests" + } + }, + "clonedApp": { + "error": { + "code": "TooManyRequests", + "message": "too many requests" + } + }, + "factoryReset": { + "error": { + "code": "TooManyRequests", + "message": "too many requests" + } + }, + "jailbroken": { + "error": { + "code": "TooManyRequests", + "message": "too many requests" + } + }, + "frida": { + "error": { + "code": "TooManyRequests", + "message": "too many requests" + } + }, + "privacySettings": { + "error": { + "code": "TooManyRequests", + "message": "too many requests" + } + }, + "virtualMachine": { + "error": { + "code": "TooManyRequests", + "message": "too many requests" + } + }, + "rawDeviceAttributes": { + "error": { + "code": "429 Too Many Requests", + "message": "too many requests" + } + } + } +} diff --git a/sdk/src/test/resources/mocks/get_visits_200_limit_1.json b/sdk/src/test/resources/mocks/get_visits_200_limit_1.json new file mode 100644 index 0000000..c5bbeed --- /dev/null +++ b/sdk/src/test/resources/mocks/get_visits_200_limit_1.json @@ -0,0 +1,62 @@ +{ + "visitorId": "AcxioeQKffpXF8iGQK3P", + "visits": [ + { + "requestId": "1655373953086.DDlfmP", + "browserDetails": { + "browserName": "Chrome", + "browserMajorVersion": "102", + "browserFullVersion": "102.0.5005", + "os": "Mac OS X", + "osVersion": "10.15.7", + "device": "Other", + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36", + "botProbability": 0 + }, + "incognito": false, + "ip": "82.118.30.68", + "ipLocation": { + "accuracyRadius": 1000, + "latitude": 50.0805, + "longitude": 14.467, + "postalCode": "130 00", + "timezone": "Europe/Prague", + "city": { + "name": "Prague" + }, + "country": { + "code": "CZ", + "name": "Czechia" + }, + "continent": { + "code": "EU", + "name": "Europe" + }, + "subdivisions": [ + { + "isoCode": "10", + "name": "Hlavni mesto Praha" + } + ] + }, + "timestamp": 1655373953094, + "time": "2022-06-16T10:05:53Z", + "url": "https://dashboard.fingerprint.com/", + "tag": {}, + "confidence": { + "score": 1 + }, + "visitorFound": true, + "firstSeenAt": { + "global": "2022-02-04T11:31:20Z", + "subscription": "2022-02-04T11:31:20Z" + }, + "lastSeenAt": { + "global": "2022-06-16T10:03:00.912Z", + "subscription": "2022-06-16T10:03:00.912Z" + } + } + ], + "lastTimestamp": 1655373953086, + "paginationKey": "1655373953086.DDlfmP" +} diff --git a/sdk/src/test/resources/mocks/get_visits_403_error.json b/sdk/src/test/resources/mocks/get_visits_403_error.json new file mode 100644 index 0000000..8a886d1 --- /dev/null +++ b/sdk/src/test/resources/mocks/get_visits_403_error.json @@ -0,0 +1,3 @@ +{ + "error": "Forbidden (HTTP 403)" +} diff --git a/sdk/src/test/resources/mocks/update_event_400_error.json b/sdk/src/test/resources/mocks/update_event_400_error.json new file mode 100644 index 0000000..7856832 --- /dev/null +++ b/sdk/src/test/resources/mocks/update_event_400_error.json @@ -0,0 +1,6 @@ +{ + "error": { + "code":"RequestCannotBeParsed", + "message":"request body is not valid" + } +} diff --git a/sdk/src/test/resources/mocks/update_event_403_error.json b/sdk/src/test/resources/mocks/update_event_403_error.json new file mode 100644 index 0000000..544d871 --- /dev/null +++ b/sdk/src/test/resources/mocks/update_event_403_error.json @@ -0,0 +1,6 @@ +{ + "error": { + "code": "TokenRequired", + "message": "secret key is required" + } +} diff --git a/sdk/src/test/resources/mocks/update_event_404_error.json b/sdk/src/test/resources/mocks/update_event_404_error.json new file mode 100644 index 0000000..389b351 --- /dev/null +++ b/sdk/src/test/resources/mocks/update_event_404_error.json @@ -0,0 +1,6 @@ +{ + "error": { + "code": "RequestNotFound", + "message": "request id is not found" + } +} diff --git a/sdk/src/test/resources/mocks/update_event_409_error.json b/sdk/src/test/resources/mocks/update_event_409_error.json new file mode 100644 index 0000000..16ad29a --- /dev/null +++ b/sdk/src/test/resources/mocks/update_event_409_error.json @@ -0,0 +1,6 @@ +{ + "error": { + "code": "StateNotReady", + "message": "resource is not mutable yet, try again" + } +} diff --git a/sdk/src/test/resources/mocks/update_event_multiple_fields_request.json b/sdk/src/test/resources/mocks/update_event_multiple_fields_request.json new file mode 100644 index 0000000..f85d2e7 --- /dev/null +++ b/sdk/src/test/resources/mocks/update_event_multiple_fields_request.json @@ -0,0 +1,7 @@ +{ + "linkedId": "myNewLinkedId", + "tag": { + "myTag": "myNewValue" + }, + "suspect": true +} diff --git a/sdk/src/test/resources/mocks/update_event_one_field_request.json b/sdk/src/test/resources/mocks/update_event_one_field_request.json new file mode 100644 index 0000000..0ebd154 --- /dev/null +++ b/sdk/src/test/resources/mocks/update_event_one_field_request.json @@ -0,0 +1,3 @@ +{ + "linkedId": "myNewLinkedId" +} From 523cfac4c4c12aa0ed2a1318c2080a2c9b8d7904 Mon Sep 17 00:00:00 2001 From: Sergey Shelomentsev Date: Mon, 5 Aug 2024 20:32:24 +0300 Subject: [PATCH 15/17] chore: add tests for update evemt --- .../fingerprint/api/FingerprintApiTest.java | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/sdk/src/test/java/com/fingerprint/api/FingerprintApiTest.java b/sdk/src/test/java/com/fingerprint/api/FingerprintApiTest.java index c594c2c..3c85855 100644 --- a/sdk/src/test/java/com/fingerprint/api/FingerprintApiTest.java +++ b/sdk/src/test/java/com/fingerprint/api/FingerprintApiTest.java @@ -6,13 +6,11 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fingerprint.model.*; import com.fingerprint.sdk.*; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import java.io.IOException; import java.io.InputStream; -import java.util.LinkedHashMap; import java.util.Map; import org.junit.jupiter.api.TestInstance; @@ -29,6 +27,7 @@ public class FingerprintApiTest { private FingerprintApi api; private static final String MOCK_REQUEST_ID = "0KSh65EnVoB85JBmloQK"; + private static final String MOCK_REQUEST_FOR_UPDATE = "1722878691275.6RRrbn"; private static final String MOCK_REQUEST_WITH_EXTRA_FIELDS_ID = "EXTRA_FIELDS"; private static final String MOCK_REQUEST_WITH_ALL_FAILED_SIGNALS = "ALL_FAILED_SIGNALS"; private static final String MOCK_REQUEST_BOTD_FAILED = "MOCK_REQUEST_BOTD_FAILED"; @@ -40,6 +39,7 @@ public class FingerprintApiTest { private static final String MOCK_WEBHOOK_VISITOR_ID = "3HNey93AkBW6CRbxV6xP"; private static final String MOCK_WEBHOOK_REQUEST_ID = "Px6VxbRC6WBkA39yeNH3"; + private static final ObjectMapper MAPPER = getMapper(); private InputStream getFileAsIOStream(final String fileName) { InputStream ioStream = this.getClass() @@ -56,6 +56,7 @@ private InputStream getFileAsIOStream(final String fileName) { public void before() throws ApiException, IOException { api = Mockito.mock(FingerprintApi.class); when(api.getEvent(MOCK_REQUEST_ID)).thenReturn(fetchMockWithEventResponse("mocks/get_event_200.json")); + //when(api.getEvent(MOCK_REQUEST_ID)).thenReturn(fetchMockWithEventResponse("mocks/update_event_400_error.json")); when(api.getEvent(MOCK_REQUEST_WITH_EXTRA_FIELDS_ID)).thenReturn(fetchMockWithEventResponse("mocks/get_event_200_extra_fields.json")); when(api.getEvent(MOCK_REQUEST_WITH_ALL_FAILED_SIGNALS)).thenReturn(fetchMockWithEventResponse("mocks/get_event_200_all_errors.json")); when(api.getEvent(MOCK_REQUEST_BOTD_FAILED)).thenReturn(fetchMockWithEventResponse("mocks/get_event_200_botd_failed_error.json")); @@ -66,14 +67,21 @@ public void before() throws ApiException, IOException { when(api.getVisits(MOCK_VISITOR_ID, MOCK_VISITOR_REQUEST_ID, null, 50, "1683900801733.Ogvu1j", null)).thenReturn(fetchMockVisit()); } - private EventResponse fetchMockWithEventResponse(String fileName) throws IOException { + private static ObjectMapper getMapper() { ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule()); mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); JsonNullableModule jnm = new JsonNullableModule(); mapper.registerModule(jnm); + return mapper; + } + + private EventResponse fetchMockWithEventResponse(String fileName) throws IOException { + return MAPPER.readValue(getFileAsIOStream(fileName), EventResponse.class); + } - return mapper.readValue(getFileAsIOStream(fileName), EventResponse.class); + private T fetchMock(String filename, Class type) throws IOException { + return MAPPER.readValue(getFileAsIOStream(filename), type); } private Response fetchMockVisit() throws IOException { @@ -119,6 +127,18 @@ public void getEventTest() throws ApiException { assertEquals(true, signalResponseRawDeviceAttributes.getData().get("cookiesEnabled").getValue()); } + @Test + public void updateOneFieldEventRequest() throws ApiException, IOException { + EventUpdateRequest request = fetchMock("mocks/update_event_one_field_request.json", EventUpdateRequest.class); + api.updateEvent(MOCK_REQUEST_FOR_UPDATE, request); + } + + @Test + public void updateMultipleFieldsEventRequest() throws ApiException, IOException { + EventUpdateRequest request = fetchMock("mocks/update_event_multiple_fields_request.json", EventUpdateRequest.class); + api.updateEvent(MOCK_REQUEST_FOR_UPDATE, request); + } + /** * Get event by requestId * This endpoint allows you to get events with all the information from each activated product (Fingerprint Pro or Bot Detection). Use the requestId as a URL path :request_id parameter. This API method is scoped to a request, i.e. all returned information is by requestId. From 504a73c084230a66b8a8c4e22c4b425e9158dca9 Mon Sep 17 00:00:00 2001 From: Sergey Shelomentsev Date: Mon, 5 Aug 2024 20:53:04 +0300 Subject: [PATCH 16/17] test: test for deleting visitor data chore: remove redundant mock chore: remove redundant exception throw chore: use correct var --- .../com/fingerprint/api/FingerprintApiTest.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/sdk/src/test/java/com/fingerprint/api/FingerprintApiTest.java b/sdk/src/test/java/com/fingerprint/api/FingerprintApiTest.java index 3c85855..708cf4f 100644 --- a/sdk/src/test/java/com/fingerprint/api/FingerprintApiTest.java +++ b/sdk/src/test/java/com/fingerprint/api/FingerprintApiTest.java @@ -27,7 +27,6 @@ public class FingerprintApiTest { private FingerprintApi api; private static final String MOCK_REQUEST_ID = "0KSh65EnVoB85JBmloQK"; - private static final String MOCK_REQUEST_FOR_UPDATE = "1722878691275.6RRrbn"; private static final String MOCK_REQUEST_WITH_EXTRA_FIELDS_ID = "EXTRA_FIELDS"; private static final String MOCK_REQUEST_WITH_ALL_FAILED_SIGNALS = "ALL_FAILED_SIGNALS"; private static final String MOCK_REQUEST_BOTD_FAILED = "MOCK_REQUEST_BOTD_FAILED"; @@ -56,7 +55,6 @@ private InputStream getFileAsIOStream(final String fileName) { public void before() throws ApiException, IOException { api = Mockito.mock(FingerprintApi.class); when(api.getEvent(MOCK_REQUEST_ID)).thenReturn(fetchMockWithEventResponse("mocks/get_event_200.json")); - //when(api.getEvent(MOCK_REQUEST_ID)).thenReturn(fetchMockWithEventResponse("mocks/update_event_400_error.json")); when(api.getEvent(MOCK_REQUEST_WITH_EXTRA_FIELDS_ID)).thenReturn(fetchMockWithEventResponse("mocks/get_event_200_extra_fields.json")); when(api.getEvent(MOCK_REQUEST_WITH_ALL_FAILED_SIGNALS)).thenReturn(fetchMockWithEventResponse("mocks/get_event_200_all_errors.json")); when(api.getEvent(MOCK_REQUEST_BOTD_FAILED)).thenReturn(fetchMockWithEventResponse("mocks/get_event_200_botd_failed_error.json")); @@ -128,15 +126,20 @@ public void getEventTest() throws ApiException { } @Test - public void updateOneFieldEventRequest() throws ApiException, IOException { + public void updateOneFieldEventRequest() throws IOException { EventUpdateRequest request = fetchMock("mocks/update_event_one_field_request.json", EventUpdateRequest.class); - api.updateEvent(MOCK_REQUEST_FOR_UPDATE, request); + assertDoesNotThrow(() -> api.updateEvent(MOCK_REQUEST_ID, request)); } @Test - public void updateMultipleFieldsEventRequest() throws ApiException, IOException { + public void updateMultipleFieldsEventRequest() throws IOException { EventUpdateRequest request = fetchMock("mocks/update_event_multiple_fields_request.json", EventUpdateRequest.class); - api.updateEvent(MOCK_REQUEST_FOR_UPDATE, request); + assertDoesNotThrow(() -> api.updateEvent(MOCK_REQUEST_ID, request)); + } + + @Test + public void deleteVisitorDataTest() { + assertDoesNotThrow(() -> api.deleteVisitorData(MOCK_VISITOR_ID)); } /** From 80d101eed1491b54a8efa2ca0a7832c0b7698fc4 Mon Sep 17 00:00:00 2001 From: Sergey Shelomentsev Date: Tue, 6 Aug 2024 13:50:45 +0300 Subject: [PATCH 17/17] chore: add more samples in readme --- README.md | 17 +++++++++++++++++ template/README.mustache | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/README.md b/README.md index 37f4c2e..0c9f3bd 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,16 @@ public class FingerprintApiExample { } catch (ApiException e) { System.err.println("Exception when calling FingerprintApi.getEvent:" + e.getMessage()); } + + // Update an event with a given requestId + try { + EventUpdateRequest request = new EventUpdateRequest(); + request.setLinkedId("myNewLinkedId"); + api.updateEvent(FPJS_REQUEST_ID, request); + } catch (ApiException e) { + System.err.println("Exception when calling FingerprintApi.updateEvent:" + e.getMessage()); + } + // Get a specific visitor's all visits try { // Fetch all visits with a given visitorId, with a page limit @@ -161,6 +171,13 @@ public class FingerprintApiExample { } catch (ApiException e) { System.err.println("Exception when calling FingerprintApi.getVisits:" + e.getMessage()); } + + // Delete visitor data with a given visitorID + try { + api.deleteVisitorData(FPJS_VISITOR_ID); + } catch (ApiException e) { + System.err.println("Exception when calling FingerprintApi.deleteVisitorData:" + e.getMessage()); + } } } ``` diff --git a/template/README.mustache b/template/README.mustache index f4e1259..6306402 100644 --- a/template/README.mustache +++ b/template/README.mustache @@ -162,6 +162,16 @@ public class FingerprintApiExample { } catch (ApiException e) { System.err.println("Exception when calling FingerprintApi.getEvent:" + e.getMessage()); } + + // Update an event with a given requestId + try { + EventUpdateRequest request = new EventUpdateRequest(); + request.setLinkedId("myNewLinkedId"); + api.updateEvent(FPJS_REQUEST_ID, request); + } catch (ApiException e) { + System.err.println("Exception when calling FingerprintApi.updateEvent:" + e.getMessage()); + } + // Get a specific visitor's all visits try { // Fetch all visits with a given visitorId, with a page limit @@ -188,6 +198,13 @@ public class FingerprintApiExample { } catch (ApiException e) { System.err.println("Exception when calling FingerprintApi.getVisits:" + e.getMessage()); } + + // Delete visitor data with a given visitorID + try { + api.deleteVisitorData(FPJS_VISITOR_ID); + } catch (ApiException e) { + System.err.println("Exception when calling FingerprintApi.deleteVisitorData:" + e.getMessage()); + } } } ```