diff --git a/.changeset/forty-seas-prove.md b/.changeset/forty-seas-prove.md new file mode 100644 index 0000000..b61b130 --- /dev/null +++ b/.changeset/forty-seas-prove.md @@ -0,0 +1,5 @@ +--- +'fingerprint-pro-server-api-php-sdk': minor +--- + +Add `relay` detection method to the VPN Detection Smart Signal diff --git a/.changeset/orange-poets-drive.md b/.changeset/orange-poets-drive.md new file mode 100644 index 0000000..2f8bcdd --- /dev/null +++ b/.changeset/orange-poets-drive.md @@ -0,0 +1,5 @@ +--- +'fingerprint-pro-server-api-php-sdk': minor +--- + +**events**: Add a `suspect` field to the `identification` product schema \ No newline at end of file diff --git a/.schema-version b/.schema-version index 852700e..cf2dc0b 100644 --- a/.schema-version +++ b/.schema-version @@ -1 +1 @@ -v2.1.0 \ No newline at end of file +v2.2.0 \ No newline at end of file diff --git a/README.md b/README.md index e76cae5..b845ab1 100644 --- a/README.md +++ b/README.md @@ -305,7 +305,6 @@ Class | Method | HTTP request | Description - [ProductVirtualMachine](docs/Model/ProductVirtualMachine.md) - [Products](docs/Model/Products.md) - [Proxy](docs/Model/Proxy.md) - - [RelatedVisitor](docs/Model/RelatedVisitor.md) - [RemoteControl](docs/Model/RemoteControl.md) - [RootApps](docs/Model/RootApps.md) - [SuspectScore](docs/Model/SuspectScore.md) diff --git a/docs/Model/Identification.md b/docs/Model/Identification.md index 88c3a02..7befc46 100644 --- a/docs/Model/Identification.md +++ b/docs/Model/Identification.md @@ -10,6 +10,7 @@ Name | Type | Description | Notes **ip** | **string** | IP address of the requesting browser or bot. | **ip_location** | [**\Fingerprint\ServerAPI\Model\DeprecatedGeolocation**](DeprecatedGeolocation.md) | | [optional] **linked_id** | **string** | A customer-provided id that was sent with the request. | [optional] +**suspect** | **bool** | Field is `true` if you have previously set the `suspect` flag for this event using the [Server API Update event endpoint](https://dev.fingerprint.com/reference/updateevent). | [optional] **timestamp** | **int** | Timestamp of the event with millisecond precision in Unix time. | **time** | [**\DateTime**](\DateTime.md) | Time expressed according to ISO 8601 in UTC format, when the request from the JS agent was made. We recommend to treat requests that are older than 2 minutes as malicious. Otherwise, request replay attacks are possible. | **url** | **string** | Page URL from which the request was sent. | diff --git a/docs/Model/RelatedVisitor.md b/docs/Model/RelatedVisitor.md deleted file mode 100644 index 9ecc39a..0000000 --- a/docs/Model/RelatedVisitor.md +++ /dev/null @@ -1,9 +0,0 @@ -# RelatedVisitor - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**visitor_id** | **string** | Visitor ID of a browser that originates from the same mobile device as the input visitor ID. | - -[[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) - diff --git a/docs/Model/VPNMethods.md b/docs/Model/VPNMethods.md index 5294f5c..3e864e9 100644 --- a/docs/Model/VPNMethods.md +++ b/docs/Model/VPNMethods.md @@ -7,6 +7,7 @@ Name | Type | Description | Notes **public_vpn** | **bool** | Request IP address is owned and used by a public VPN service provider. | **auxiliary_mobile** | **bool** | This method applies to mobile devices only. Indicates the result of additional methods used to detect a VPN in mobile devices. | **os_mismatch** | **bool** | The browser runs on a different operating system than the operating system inferred from the request network signature. | +**relay** | **bool** | Request IP address belongs to a relay service provider, indicating the use of relay services like [Apple Private relay](https://support.apple.com/en-us/102602) or [Cloudflare Warp](https://developers.cloudflare.com/warp-client/). * Like VPNs, relay services anonymize the visitor's true IP address. * Unlike traditional VPNs, relay services don't let visitors spoof their location by choosing an exit node in a different country. This field allows you to differentiate VPN users and relay service users in your fraud prevention logic. | [[Back to Model list]](../../README.md#documentation-for-models) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to README]](../../README.md) diff --git a/res/fingerprint-server-api.yaml b/res/fingerprint-server-api.yaml index fb9cb34..b5eaa9d 100644 --- a/res/fingerprint-server-api.yaml +++ b/res/fingerprint-server-api.yaml @@ -527,6 +527,7 @@ paths: publicVPN: false auxiliaryMobile: false osMismatch: false + relay: false proxy: result: false tampering: @@ -848,6 +849,12 @@ components: linkedId: type: string description: A customer-provided id that was sent with the request. + suspect: + description: >- + Field is `true` if you have previously set the `suspect` flag for + this event using the [Server API Update event + endpoint](https://dev.fingerprint.com/reference/updateevent). + type: boolean timestamp: description: Timestamp of the event with millisecond precision in Unix time. type: integer @@ -1218,6 +1225,7 @@ components: - publicVPN - auxiliaryMobile - osMismatch + - relay properties: timezoneMismatch: type: boolean @@ -1239,6 +1247,23 @@ components: description: >- The browser runs on a different operating system than the operating system inferred from the request network signature. + relay: + type: boolean + description: > + Request IP address belongs to a relay service provider, indicating + the use of relay services like [Apple Private + relay](https://support.apple.com/en-us/102602) or [Cloudflare + Warp](https://developers.cloudflare.com/warp-client/). + + + * Like VPNs, relay services anonymize the visitor's true IP address. + + * Unlike traditional VPNs, relay services don't let visitors spoof + their location by choosing an exit node in a different country. + + + This field allows you to differentiate VPN users and relay service + users in your fraud prevention logic. VPN: type: object additionalProperties: false @@ -2290,14 +2315,3 @@ components: $ref: '#/components/schemas/WebhookVelocity' developerTools: $ref: '#/components/schemas/WebhookDeveloperTools' - RelatedVisitor: - type: object - additionalProperties: false - required: - - visitorId - properties: - visitorId: - type: string - description: >- - Visitor ID of a browser that originates from the same mobile device - as the input visitor ID. diff --git a/src/Model/Identification.php b/src/Model/Identification.php index 180dc8f..b99ef38 100644 --- a/src/Model/Identification.php +++ b/src/Model/Identification.php @@ -59,6 +59,7 @@ class Identification implements ModelInterface, \ArrayAccess 'ip' => 'string', 'ip_location' => '\Fingerprint\ServerAPI\Model\DeprecatedGeolocation', 'linked_id' => 'string', + 'suspect' => 'bool', 'timestamp' => 'int', 'time' => '\DateTime', 'url' => 'string', @@ -82,6 +83,7 @@ class Identification implements ModelInterface, \ArrayAccess 'ip' => null, 'ip_location' => null, 'linked_id' => null, + 'suspect' => null, 'timestamp' => 'int64', 'time' => 'date-time', 'url' => null, @@ -106,6 +108,7 @@ class Identification implements ModelInterface, \ArrayAccess 'ip' => 'ip', 'ip_location' => 'ipLocation', 'linked_id' => 'linkedId', + 'suspect' => 'suspect', 'timestamp' => 'timestamp', 'time' => 'time', 'url' => 'url', @@ -129,6 +132,7 @@ class Identification implements ModelInterface, \ArrayAccess 'ip' => 'setIp', 'ip_location' => 'setIpLocation', 'linked_id' => 'setLinkedId', + 'suspect' => 'setSuspect', 'timestamp' => 'setTimestamp', 'time' => 'setTime', 'url' => 'setUrl', @@ -152,6 +156,7 @@ class Identification implements ModelInterface, \ArrayAccess 'ip' => 'getIp', 'ip_location' => 'getIpLocation', 'linked_id' => 'getLinkedId', + 'suspect' => 'getSuspect', 'timestamp' => 'getTimestamp', 'time' => 'getTime', 'url' => 'getUrl', @@ -184,6 +189,7 @@ public function __construct(?array $data = null) $this->container['ip'] = isset($data['ip']) ? $data['ip'] : null; $this->container['ip_location'] = isset($data['ip_location']) ? $data['ip_location'] : null; $this->container['linked_id'] = isset($data['linked_id']) ? $data['linked_id'] : null; + $this->container['suspect'] = isset($data['suspect']) ? $data['suspect'] : null; $this->container['timestamp'] = isset($data['timestamp']) ? $data['timestamp'] : null; $this->container['time'] = isset($data['time']) ? $data['time'] : null; $this->container['url'] = isset($data['url']) ? $data['url'] : null; @@ -467,6 +473,28 @@ public function setLinkedId(?string $linked_id): self return $this; } + /** + * Gets suspect. + */ + public function getSuspect(): ?bool + { + return $this->container['suspect']; + } + + /** + * Sets suspect. + * + * @param ?bool $suspect Field is `true` if you have previously set the `suspect` flag for this event using the [Server API Update event endpoint](https://dev.fingerprint.com/reference/updateevent). + * + * @return $this + */ + public function setSuspect(?bool $suspect): self + { + $this->container['suspect'] = $suspect; + + return $this; + } + /** * Gets timestamp. */ diff --git a/src/Model/RelatedVisitor.php b/src/Model/RelatedVisitor.php deleted file mode 100644 index d3be6a9..0000000 --- a/src/Model/RelatedVisitor.php +++ /dev/null @@ -1,271 +0,0 @@ - 'string']; - - /** - * Array of property to format mappings. Used for (de)serialization. - * - * @var string[] - */ - protected static array $swaggerFormats = [ - 'visitor_id' => null]; - - /** - * Array of attributes where the key is the local name, - * and the value is the original name. - * - * @var string[] - */ - protected static array $attributeMap = [ - 'visitor_id' => 'visitorId']; - - /** - * Array of attributes to setter functions (for deserialization of responses). - * - * @var string[] - */ - protected static array $setters = [ - 'visitor_id' => 'setVisitorId']; - - /** - * Array of attributes to getter functions (for serialization of requests). - * - * @var string[] - */ - protected static array $getters = [ - 'visitor_id' => 'getVisitorId']; - - /** - * Associative array for storing property values. - * - * @var mixed[] - */ - protected array $container = []; - - /** - * Constructor. - * - * @param mixed[] $data Associated array of property values - * initializing the model - */ - public function __construct(?array $data = null) - { - $this->container['visitor_id'] = isset($data['visitor_id']) ? $data['visitor_id'] : null; - } - - /** - * Gets the string presentation of the object. - * - */ - public function __toString(): string - { - return json_encode(ObjectSerializer::sanitizeForSerialization($this)); - } - - /** - * Array of property to type mappings. Used for (de)serialization. - */ - public static function swaggerTypes(): array - { - return self::$swaggerTypes; - } - - /** - * Array of property to format mappings. Used for (de)serialization. - */ - public static function swaggerFormats(): array - { - return self::$swaggerFormats; - } - - /** - * Array of attributes where the key is the local name, - * and the value is the original name. - */ - public static function attributeMap(): array - { - return self::$attributeMap; - } - - /** - * Array of attributes to setter functions (for deserialization of responses). - */ - public static function setters(): array - { - return self::$setters; - } - - /** - * Array of attributes to getter functions (for serialization of requests). - */ - public static function getters(): array - { - return self::$getters; - } - - /** - * The original name of the model. - */ - public function getModelName(): string - { - return self::$swaggerModelName; - } - - /** - * Show all the invalid properties with reasons. - * - * @return array invalid properties with reasons - */ - public function listInvalidProperties(): array - { - $invalidProperties = []; - - if (null === $this->container['visitor_id']) { - $invalidProperties[] = "'visitor_id' can't be null"; - } - - return $invalidProperties; - } - - /** - * Validate all the properties in the model - * return true if all passed. - * - * @return bool True if all properties are valid - */ - public function valid(): bool - { - return 0 === count($this->listInvalidProperties()); - } - - /** - * Gets visitor_id. - */ - public function getVisitorId(): string - { - return $this->container['visitor_id']; - } - - /** - * Sets visitor_id. - * - * @param string $visitor_id visitor ID of a browser that originates from the same mobile device as the input visitor ID - * - * @return $this - */ - public function setVisitorId(string $visitor_id): self - { - $this->container['visitor_id'] = $visitor_id; - - return $this; - } - - /** - * Returns true if offset exists. False otherwise. - * - * @param int $offset Offset - */ - public function offsetExists($offset): bool - { - return isset($this->container[$offset]); - } - - /** - * Gets offset. - * - * @param int $offset Offset - */ - public function offsetGet($offset): mixed - { - return isset($this->container[$offset]) ? $this->container[$offset] : null; - } - - /** - * Sets value based on offset. - * - * @param int $offset Offset - * @param mixed $value Value to be set - */ - public function offsetSet($offset, mixed $value): void - { - if (is_null($offset)) { - $this->container[] = $value; - } else { - $this->container[$offset] = $value; - } - } - - /** - * Unsets offset. - * - * @param int $offset Offset - */ - public function offsetUnset($offset): void - { - unset($this->container[$offset]); - } - - /** - * Gets the string presentation of the object in a pretty JSON format. - * - */ - public function toPrettyString(): string - { - return json_encode( - ObjectSerializer::sanitizeForSerialization($this), - JSON_PRETTY_PRINT - ); - } -} diff --git a/src/Model/VPNMethods.php b/src/Model/VPNMethods.php index 985e067..82db2f2 100644 --- a/src/Model/VPNMethods.php +++ b/src/Model/VPNMethods.php @@ -55,7 +55,8 @@ class VPNMethods implements ModelInterface, \ArrayAccess 'timezone_mismatch' => 'bool', 'public_vpn' => 'bool', 'auxiliary_mobile' => 'bool', - 'os_mismatch' => 'bool']; + 'os_mismatch' => 'bool', + 'relay' => 'bool']; /** * Array of property to format mappings. Used for (de)serialization. @@ -66,7 +67,8 @@ class VPNMethods implements ModelInterface, \ArrayAccess 'timezone_mismatch' => null, 'public_vpn' => null, 'auxiliary_mobile' => null, - 'os_mismatch' => null]; + 'os_mismatch' => null, + 'relay' => null]; /** * Array of attributes where the key is the local name, @@ -78,7 +80,8 @@ class VPNMethods implements ModelInterface, \ArrayAccess 'timezone_mismatch' => 'timezoneMismatch', 'public_vpn' => 'publicVPN', 'auxiliary_mobile' => 'auxiliaryMobile', - 'os_mismatch' => 'osMismatch']; + 'os_mismatch' => 'osMismatch', + 'relay' => 'relay']; /** * Array of attributes to setter functions (for deserialization of responses). @@ -89,7 +92,8 @@ class VPNMethods implements ModelInterface, \ArrayAccess 'timezone_mismatch' => 'setTimezoneMismatch', 'public_vpn' => 'setPublicVpn', 'auxiliary_mobile' => 'setAuxiliaryMobile', - 'os_mismatch' => 'setOsMismatch']; + 'os_mismatch' => 'setOsMismatch', + 'relay' => 'setRelay']; /** * Array of attributes to getter functions (for serialization of requests). @@ -100,7 +104,8 @@ class VPNMethods implements ModelInterface, \ArrayAccess 'timezone_mismatch' => 'getTimezoneMismatch', 'public_vpn' => 'getPublicVpn', 'auxiliary_mobile' => 'getAuxiliaryMobile', - 'os_mismatch' => 'getOsMismatch']; + 'os_mismatch' => 'getOsMismatch', + 'relay' => 'getRelay']; /** * Associative array for storing property values. @@ -121,6 +126,7 @@ public function __construct(?array $data = null) $this->container['public_vpn'] = isset($data['public_vpn']) ? $data['public_vpn'] : null; $this->container['auxiliary_mobile'] = isset($data['auxiliary_mobile']) ? $data['auxiliary_mobile'] : null; $this->container['os_mismatch'] = isset($data['os_mismatch']) ? $data['os_mismatch'] : null; + $this->container['relay'] = isset($data['relay']) ? $data['relay'] : null; } /** @@ -202,6 +208,9 @@ public function listInvalidProperties(): array if (null === $this->container['os_mismatch']) { $invalidProperties[] = "'os_mismatch' can't be null"; } + if (null === $this->container['relay']) { + $invalidProperties[] = "'relay' can't be null"; + } return $invalidProperties; } @@ -305,6 +314,28 @@ public function setOsMismatch(bool $os_mismatch): self return $this; } + /** + * Gets relay. + */ + public function getRelay(): bool + { + return $this->container['relay']; + } + + /** + * Sets relay. + * + * @param bool $relay Request IP address belongs to a relay service provider, indicating the use of relay services like [Apple Private relay](https://support.apple.com/en-us/102602) or [Cloudflare Warp](https://developers.cloudflare.com/warp-client/). * Like VPNs, relay services anonymize the visitor's true IP address. * Unlike traditional VPNs, relay services don't let visitors spoof their location by choosing an exit node in a different country. This field allows you to differentiate VPN users and relay service users in your fraud prevention logic. + * + * @return $this + */ + public function setRelay(bool $relay): self + { + $this->container['relay'] = $relay; + + return $this; + } + /** * Returns true if offset exists. False otherwise. * diff --git a/test/mocks/errors/400_bot_type_invalid.json b/test/mocks/errors/400_bot_type_invalid.json new file mode 100644 index 0000000..8dd6526 --- /dev/null +++ b/test/mocks/errors/400_bot_type_invalid.json @@ -0,0 +1,6 @@ +{ + "error": { + "code": "RequestCannotBeParsed", + "message": "invalid bot type" + } +} diff --git a/test/mocks/errors/400_end_time_invalid.json b/test/mocks/errors/400_end_time_invalid.json new file mode 100644 index 0000000..8865409 --- /dev/null +++ b/test/mocks/errors/400_end_time_invalid.json @@ -0,0 +1,6 @@ +{ + "error": { + "code": "RequestCannotBeParsed", + "message": "invalid end time" + } +} \ No newline at end of file diff --git a/test/mocks/errors/400_ip_address_invalid.json b/test/mocks/errors/400_ip_address_invalid.json new file mode 100644 index 0000000..5969bab --- /dev/null +++ b/test/mocks/errors/400_ip_address_invalid.json @@ -0,0 +1,6 @@ +{ + "error": { + "code": "RequestCannotBeParsed", + "message": "invalid ip address" + } +} \ No newline at end of file diff --git a/test/mocks/errors/400_limit_invalid.json b/test/mocks/errors/400_limit_invalid.json new file mode 100644 index 0000000..46297eb --- /dev/null +++ b/test/mocks/errors/400_limit_invalid.json @@ -0,0 +1,6 @@ +{ + "error": { + "code": "RequestCannotBeParsed", + "message": "invalid limit" + } +} diff --git a/test/mocks/errors/400_linked_id_invalid.json b/test/mocks/errors/400_linked_id_invalid.json new file mode 100644 index 0000000..72de54e --- /dev/null +++ b/test/mocks/errors/400_linked_id_invalid.json @@ -0,0 +1,6 @@ +{ + "error": { + "code": "RequestCannotBeParsed", + "message": "linked_id can't be greater than 256 characters long" + } +} diff --git a/test/mocks/errors/400_pagination_key_invalid.json b/test/mocks/errors/400_pagination_key_invalid.json new file mode 100644 index 0000000..df559f9 --- /dev/null +++ b/test/mocks/errors/400_pagination_key_invalid.json @@ -0,0 +1,6 @@ +{ + "error": { + "code": "RequestCannotBeParsed", + "message": "invalid pagination key" + } +} diff --git a/test/mocks/errors/400_reverse_invalid.json b/test/mocks/errors/400_reverse_invalid.json new file mode 100644 index 0000000..540800f --- /dev/null +++ b/test/mocks/errors/400_reverse_invalid.json @@ -0,0 +1,6 @@ +{ + "error": { + "code": "RequestCannotBeParsed", + "message": "invalid reverse param" + } +} diff --git a/test/mocks/errors/400_start_time_invalid.json b/test/mocks/errors/400_start_time_invalid.json new file mode 100644 index 0000000..5d93f92 --- /dev/null +++ b/test/mocks/errors/400_start_time_invalid.json @@ -0,0 +1,6 @@ +{ + "error": { + "code": "RequestCannotBeParsed", + "message": "invalid start time" + } +} \ No newline at end of file diff --git a/test/mocks/get_event_200.json b/test/mocks/get_event_200.json index c74c604..60013c0 100644 --- a/test/mocks/get_event_200.json +++ b/test/mocks/get_event_200.json @@ -6,7 +6,7 @@ "requestId": "1708102555327.NLOjmg", "incognito": true, "linkedId": "somelinkedId", - "tag": {"a": "s", "aa": [1,3,5]}, + "tag": {}, "time": "2019-05-21T16:40:13Z", "timestamp": 1582299576512, "url": "https://www.example.com/login?hope{this{works[!", @@ -180,7 +180,8 @@ "timezoneMismatch": false, "publicVPN": false, "auxiliaryMobile": false, - "osMismatch": false + "osMismatch": false, + "relay": false } } }, diff --git a/test/mocks/get_event_search_200.json b/test/mocks/get_event_search_200.json new file mode 100644 index 0000000..9d237eb --- /dev/null +++ b/test/mocks/get_event_search_200.json @@ -0,0 +1,341 @@ +{ + "events": [ + { + "products": { + "identification": { + "data": { + "visitorId": "Ibk1527CUFmcnjLwIs4A9", + "requestId": "1708102555327.NLOjmg", + "incognito": true, + "linkedId": "somelinkedId", + "tag": {}, + "time": "2019-05-21T16:40:13Z", + "timestamp": 1582299576512, + "url": "https://www.example.com/login?hope{this{works[!", + "ip": "61.127.217.15", + "ipLocation": { + "accuracyRadius": 10, + "latitude": 49.982, + "longitude": 36.2566, + "postalCode": "61202", + "timezone": "Europe/Dusseldorf", + "city": { + "name": "Dusseldorf" + }, + "country": { + "code": "DE", + "name": "Germany" + }, + "continent": { + "code": "EU", + "name": "Europe" + }, + "subdivisions": [ + { + "isoCode": "63", + "name": "North Rhine-Westphalia" + } + ] + }, + "browserDetails": { + "browserName": "Chrome", + "browserMajorVersion": "74", + "browserFullVersion": "74.0.3729", + "os": "Windows", + "osVersion": "7", + "device": "Other", + "userAgent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) ...." + }, + "confidence": { + "score": 0.97 + }, + "visitorFound": false, + "firstSeenAt": { + "global": "2022-03-16T11:26:45.362Z", + "subscription": "2022-03-16T11:31:01.101Z" + }, + "lastSeenAt": { + "global": null, + "subscription": null + } + } + }, + "botd": { + "data": { + "bot": { + "result": "notDetected" + }, + "url": "https://www.example.com/login?hope{this{works}[!", + "ip": "61.127.217.15", + "time": "2019-05-21T16:40:13Z", + "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" + } + }, + "rootApps": { + "data": { + "result": false + } + }, + "emulator": { + "data": { + "result": false + } + }, + "ipInfo": { + "data": { + "v4": { + "address": "94.142.239.124", + "geolocation": { + "accuracyRadius": 20, + "latitude": 50.05, + "longitude": 14.4, + "postalCode": "150 00", + "timezone": "Europe/Prague", + "city": { + "name": "Prague" + }, + "country": { + "code": "CZ", + "name": "Czechia" + }, + "continent": { + "code": "EU", + "name": "Europe" + }, + "subdivisions": [ + { + "isoCode": "10", + "name": "Hlavni mesto Praha" + } + ] + }, + "asn": { + "asn": "7922", + "name": "COMCAST-7922", + "network": "73.136.0.0/13" + }, + "datacenter": { + "result": true, + "name": "DediPath" + } + }, + "v6": { + "address": "2001:db8:3333:4444:5555:6666:7777:8888", + "geolocation": { + "accuracyRadius": 5, + "latitude": 49.982, + "longitude": 36.2566, + "postalCode": "10112", + "timezone": "Europe/Berlin", + "city": { + "name": "Berlin" + }, + "country": { + "code": "DE", + "name": "Germany" + }, + "continent": { + "code": "EU", + "name": "Europe" + }, + "subdivisions": [ + { + "isoCode": "BE", + "name": "Land Berlin" + } + ] + }, + "asn": { + "asn": "6805", + "name": "Telefonica Germany", + "network": "2a02:3100::/24" + }, + "datacenter": { + "result": false, + "name": "" + } + } + } + }, + "ipBlocklist": { + "data": { + "result": false, + "details": { + "emailSpam": false, + "attackSource": false + } + } + }, + "tor": { + "data": { + "result": false + } + }, + "vpn": { + "data": { + "result": false, + "confidence": "high", + "originTimezone": "Europe/Berlin", + "originCountry": "unknown", + "methods": { + "timezoneMismatch": false, + "publicVPN": false, + "auxiliaryMobile": false, + "osMismatch": false, + "relay": false + } + } + }, + "proxy": { + "data": { + "result": false + } + }, + "incognito": { + "data": { + "result": false + } + }, + "tampering": { + "data": { + "result": false, + "anomalyScore": 0.1955, + "antiDetectBrowser": false + } + }, + "clonedApp": { + "data": { + "result": false + } + }, + "factoryReset": { + "data": { + "time": "1970-01-01T00:00:00Z", + "timestamp": 0 + } + }, + "jailbroken": { + "data": { + "result": false + } + }, + "frida": { + "data": { + "result": false + } + }, + "privacySettings": { + "data": { + "result": false + } + }, + "virtualMachine": { + "data": { + "result": false + } + }, + "rawDeviceAttributes": { + "data": { + "architecture": { + "value": 127 + }, + "audio": { + "value": 35.73832903057337 + }, + "canvas": { + "value": { + "Winding": true, + "Geometry": "4dce9d6017c3e0c052a77252f29f2b1c", + "Text": "dd2474a56ff78c1de3e7a07070ba3b7d" + } + }, + "colorDepth": { + "value": 30 + }, + "colorGamut": { + "value": "p3" + }, + "contrast": { + "value": 0 + }, + "cookiesEnabled": { + "value": true + }, + "cpuClass": {}, + "fonts": { + "value": ["Arial Unicode MS", "Gill Sans", "Helvetica Neue", "Menlo"] + } + } + }, + "highActivity": { + "data": { + "result": false + } + }, + "locationSpoofing": { + "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 + } + }, + "ipEvents": { + "intervals": { + "5m": 1, + "1h": 5, + "24h": 5 + } + }, + "distinctIpByLinkedId": { + "intervals": { + "5m": 1, + "1h": 5, + "24h": 5 + } + }, + "distinctVisitorIdByLinkedId": { + "intervals": { + "5m": 1, + "1h": 5, + "24h": 5 + } + } + } + }, + "developerTools": { + "data": { + "result": false + } + } + }} + ], + "paginationKey": "1655373953086" +} diff --git a/test/mocks/webhook.json b/test/mocks/webhook.json index 2152b84..748d252 100644 --- a/test/mocks/webhook.json +++ b/test/mocks/webhook.json @@ -125,7 +125,8 @@ "timezoneMismatch": false, "publicVPN": false, "auxiliaryMobile": false, - "osMismatch": false + "osMismatch": false, + "relay": false } }, "proxy": {