diff --git a/src/client/idv.client.js b/src/client/idv.client.js index ba593b8c..74ec6f94 100644 --- a/src/client/idv.client.js +++ b/src/client/idv.client.js @@ -155,6 +155,30 @@ class IDVClient { getSessionConfiguration(sessionId) { return this.idvService.getSessionConfiguration(sessionId); } + + /** + * Fetches the tracked devices for the given sessionID. + * + * @param {string} sessionId + * + * @typedef {import('../idv_service/session/retrieve/devices/session.tracked.devices.response')} SessionTrackedDevicesResponse + * + * @returns {Promise} + */ + getSessionTrackedDevices(sessionId) { + return this.idvService.getSessionTrackedDevices(sessionId); + } + + /** + * Deletes the tracked devices for given sessionID. + * + * @param {string} sessionId + * + * @returns {Promise} + */ + deleteSessionTrackedDevices(sessionId) { + return this.idvService.deleteSessionTrackedDevices(sessionId); + } } module.exports = IDVClient; diff --git a/src/idv_service/idv.service.js b/src/idv_service/idv.service.js index 895f1981..f8c2e30e 100644 --- a/src/idv_service/idv.service.js +++ b/src/idv_service/idv.service.js @@ -15,6 +15,7 @@ const CreateFaceCaptureResourceResponse = require('./session/retrieve/create.fac const CreateFaceCaptureResourcePayload = require('./session/create/face_capture/create.face.capture.resource.payload'); const UploadFaceCaptureImagePayload = require('./session/create/face_capture/upload.face.capture.image.payload'); const SessionConfigurationResponse = require('./session/retrieve/configuration/session.configuration.response'); +const SessionTrackedDevicesResponse = require('./session/retrieve/devices/session.tracked.devices.response'); const DEFAULT_API_URL = config.yoti.idvApi; @@ -309,6 +310,8 @@ class IDVService { * @returns {Promise} */ getSessionConfiguration(sessionId) { + Validation.isString(sessionId, 'sessionId'); + const request = new RequestBuilder() .withPemString(this.pem.toString()) .withBaseUrl(this.apiUrl) @@ -323,6 +326,55 @@ class IDVService { .catch((err) => reject(new IDVError(err))); }); } + + /** + * @param {string} sessionId + * + * @returns {Promise} + */ + getSessionTrackedDevices(sessionId) { + Validation.isString(sessionId, 'sessionId'); + + const request = new RequestBuilder() + .withPemString(this.pem.toString()) + .withBaseUrl(this.apiUrl) + .withEndpoint(`/sessions/${sessionId}/tracked-devices`) + .withQueryParam('sdkId', this.sdkId) + .withGet() + .build(); + + return new Promise((resolve, reject) => { + request.execute() + // eslint-disable-next-line max-len + .then((response) => resolve(new SessionTrackedDevicesResponse(response.getParsedResponse()))) + .catch((err) => reject(new IDVError(err))); + }); + } + + /** + * Deletes tracked devices for a given session + * + * @param {string} sessionId + * + * @returns {Promise} + */ + deleteSessionTrackedDevices(sessionId) { + Validation.isString(sessionId, 'sessionId'); + + const request = new RequestBuilder() + .withPemString(this.pem.toString()) + .withBaseUrl(this.apiUrl) + .withEndpoint(`/sessions/${sessionId}/tracked-devices`) + .withQueryParam('sdkId', this.sdkId) + .withMethod('DELETE') + .build(); + + return new Promise((resolve, reject) => { + request.execute(true) + .then(() => resolve()) + .catch((err) => reject(new IDVError(err))); + }); + } } module.exports = IDVService; diff --git a/src/idv_service/session/retrieve/devices/device.description.response.js b/src/idv_service/session/retrieve/devices/device.description.response.js new file mode 100644 index 00000000..0514fd58 --- /dev/null +++ b/src/idv_service/session/retrieve/devices/device.description.response.js @@ -0,0 +1,139 @@ +'use strict'; + +const Validation = require('../../../../yoti_common/validation'); + +class DeviceDescriptionResponse { + constructor(payload) { + Validation.isString(payload.ip_address, 'ip_address', true); + /** @private */ + this.ipAddress = payload.ip_address; + + Validation.isString(payload.ip_iso_country_code, 'ip_iso_country_code', true); + /** @private */ + this.ipISOCountryCode = payload.ip_iso_country_code; + + Validation.isString(payload.manufacture_name, 'manufacture_name', true); + /** @private */ + this.manufactureName = payload.manufacture_name; + + Validation.isString(payload.model_name, 'model_name', true); + /** @private */ + this.modelName = payload.model_name; + + Validation.isString(payload.os_name, 'os_name', true); + /** @private */ + this.osName = payload.os_name; + + Validation.isString(payload.os_version, 'os_version', true); + /** @private */ + this.osVersion = payload.os_version; + + Validation.isString(payload.browser_name, 'browser_name', true); + /** @private */ + this.browserName = payload.browser_name; + + Validation.isString(payload.browser_version, 'browser_version', true); + /** @private */ + this.browserVersion = payload.browser_version; + + Validation.isString(payload.locale, 'locale', true); + /** @private */ + this.locale = payload.locale; + + Validation.isString(payload.client_version, 'client_version'); + /** @private */ + this.clientVersion = payload.client_version; + } + + /** + * Returns the device ip address. + * + * @returns {string | undefined} + */ + getIpAddress() { + return this.ipAddress; + } + + /** + * Returns the device ip ISO country code. + * + * @returns {string | undefined} + */ + getIpISOCountryCode() { + return this.ipISOCountryCode; + } + + /** + * Returns the device manufacture name. + * + * @returns {string | undefined} + */ + getManufactureName() { + return this.manufactureName; + } + + /** + * Returns the device model name. + * + * @returns {string | undefined} + */ + getModelName() { + return this.modelName; + } + + /** + * Returns the device OS name. + * + * @returns {string | undefined} + */ + getOSName() { + return this.osName; + } + + /** + * Returns the device OS version. + * + * @returns {string | undefined} + */ + getOSVersion() { + return this.osVersion; + } + + /** + * Returns the device browser name. + * + * @returns {string | undefined} + */ + getBrowserName() { + return this.browserName; + } + + /** + * Returns the device browser version. + * + * @returns {string | undefined} + */ + getBrowserVersion() { + return this.browserVersion; + } + + /** + * Returns the device locale. + * + * @returns {string | undefined} + */ + getLocale() { + return this.locale; + } + + /** + * Returns the client version. + * + * @returns {string} + */ + getClientVersion() { + return this.clientVersion; + } +} + +module.exports = DeviceDescriptionResponse; diff --git a/src/idv_service/session/retrieve/devices/session.tracked.devices.response.js b/src/idv_service/session/retrieve/devices/session.tracked.devices.response.js new file mode 100644 index 00000000..c7d20578 --- /dev/null +++ b/src/idv_service/session/retrieve/devices/session.tracked.devices.response.js @@ -0,0 +1,26 @@ +'use strict'; + +const Validation = require('../../../../yoti_common/validation'); +const TrackedDeviceEventResponse = require('./tracked.device.event.response'); + +class TrackedDevicesResponse { + /** + * @param {{}[]} response + */ + constructor(response) { + Validation.isArray(response, 'tracked devices'); + /** @private */ + this.deviceEvents = response.map((item) => new TrackedDeviceEventResponse(item)); + } + + /** + * Returns the list of tracked device events. + * + * @returns {TrackedDeviceEventResponse[]} + */ + getDeviceEvents() { + return this.deviceEvents; + } +} + +module.exports = TrackedDevicesResponse; diff --git a/src/idv_service/session/retrieve/devices/tracked.device.event.response.js b/src/idv_service/session/retrieve/devices/tracked.device.event.response.js new file mode 100644 index 00000000..fb70a9bc --- /dev/null +++ b/src/idv_service/session/retrieve/devices/tracked.device.event.response.js @@ -0,0 +1,49 @@ +'use strict'; + +const Validation = require('../../../../yoti_common/validation'); +const DeviceDescriptionResponse = require('./device.description.response'); + +class TrackedDeviceEventResponse { + constructor(payload) { + Validation.isString(payload.event, 'event'); + /** @private */ + this.event = payload.event; + + Validation.isStringDate(payload.created, 'created'); + /** @private */ + this.created = new Date(payload.created); + + Validation.isPlainObject(payload.device, 'device'); + /** @private */ + this.device = new DeviceDescriptionResponse(payload.device); + } + + /** + * Returns the event. + * + * @returns {string} + */ + getEvent() { + return this.event; + } + + /** + * Returns the created date. + * + * @returns {Date} + */ + getCreated() { + return this.created; + } + + /** + * Returns the device description. + * + * @returns {DeviceDescriptionResponse} + */ + getDevice() { + return this.device; + } +} + +module.exports = TrackedDeviceEventResponse; diff --git a/tests/client/idv.client.spec.js b/tests/client/idv.client.spec.js index 933b80d1..f8e67194 100644 --- a/tests/client/idv.client.spec.js +++ b/tests/client/idv.client.spec.js @@ -17,6 +17,7 @@ const GetSessionResult = require('../../src/idv_service/session/retrieve/get.ses const Media = require('../../src/data_type/media'); const SupportedDocumentResponse = require('../../src/idv_service/support/supported.documents.response'); const SessionConfigurationResponse = require('../../src/idv_service/session/retrieve/configuration/session.configuration.response'); +const SessionTrackedDevicesResponse = require('../../src/idv_service/session/retrieve/devices/session.tracked.devices.response'); const CaptureResponse = require('../../src/idv_service/session/retrieve/configuration/capture/capture.response'); const CreateFaceCaptureResourceResponse = require('../../src/idv_service/session/retrieve/create.face.capture.resource.response'); @@ -51,6 +52,7 @@ describe.each([ const sessionMediaUriRegExp = new RegExp(`${apiUrlPath}/sessions/${SESSION_ID}/media/${MEDIA_ID}/content\\?sdkId=${APP_ID}`); const supportedDocumentsUriRegExp = new RegExp(`${apiUrlPath}/supported-documents`); const sessionConfigUriRegExp = new RegExp(`/sessions/${SESSION_ID}/configuration`); + const sessionTrackedDevicesUriRegExp = new RegExp(`/sessions/${SESSION_ID}/tracked-devices`); const faceCaptureCreateUri = new RegExp(`^/idverify/v1/sessions/${SESSION_ID}/resources/face-capture`); const uploadFaceCaptureImageUri = new RegExp(`^/idverify/v1/sessions/${SESSION_ID}/resources/face-capture/${RESOURCE_ID}/image`); @@ -265,6 +267,74 @@ describe.each([ }); }); + describe('#getSessionTrackedDevices', () => { + const setupResponse = (responseBody, responseStatusCode = 200) => { + nock(apiUrlDomain) + .get(sessionTrackedDevicesUriRegExp) + .reply(responseStatusCode, responseBody); + }; + + beforeEach(() => { + setupResponse(JSON.stringify([ + { + event: 'CONFIG_FIRST_LOADED', + created: '2021-06-11T11:39:24Z', + device: { + client_version: '2.12.0', + }, + }, + { + event: 'RESOURCE_CREATED', + resource_id: '3fa85f64-5717-4562-b3fc-2c963f66afa6', + created: '2021-06-11T11:39:24Z', + device: { + client_version: '2.12.0', + }, + }, + { + event: 'CLIENT_SESSION_TOKEN_DELETED', + created: '2021-06-11T11:39:24Z', + device: { + client_version: '2.12.0', + }, + }, + ])); + }); + + it('should return an IDV session tracked devices', (done) => { + idvClient + .getSessionTrackedDevices(SESSION_ID) + .then((result) => { + expect(result).toBeInstanceOf(SessionTrackedDevicesResponse); + expect(result.getDeviceEvents()).toHaveLength(3); + done(); + }) + .catch(done); + }); + }); + + describe('#deleteSessionTrackedDevices', () => { + const setupResponse = (responseStatusCode = 204) => { + nock(apiUrlDomain) + .delete(sessionTrackedDevicesUriRegExp) + .reply(responseStatusCode); + }; + + beforeEach(() => { + setupResponse(); + }); + + it('should have no response', (done) => { + idvClient + .deleteSessionTrackedDevices(SESSION_ID, MEDIA_ID) + .then((result) => { + expect(result).toBeUndefined(); + done(); + }) + .catch(done); + }); + }); + describe('#createFaceCaptureResource', () => { const createFaceCaptureResourcePayload = new CreateFaceCaptureResourcePayloadBuilder().withRequirementId('abc').build(); diff --git a/tests/idv_service/idv.service.spec.js b/tests/idv_service/idv.service.spec.js index 7e46ccd9..70b15c63 100644 --- a/tests/idv_service/idv.service.spec.js +++ b/tests/idv_service/idv.service.spec.js @@ -15,6 +15,7 @@ const GetSessionResult = require('../../src/idv_service/session/retrieve/get.ses const Media = require('../../src/data_type/media'); const SupportedDocumentResponse = require('../../src/idv_service/support/supported.documents.response'); const SessionConfigurationResponse = require('../../src/idv_service/session/retrieve/configuration/session.configuration.response'); +const SessionTrackedDevicesResponse = require('../../src/idv_service/session/retrieve/devices/session.tracked.devices.response'); const CaptureResponse = require('../../src/idv_service/session/retrieve/configuration/capture/capture.response'); const CreateFaceCaptureResourceResponse = require('../../src/idv_service/session/retrieve/create.face.capture.resource.response'); const { UploadFaceCaptureImagePayloadBuilder } = require('../..'); @@ -28,6 +29,7 @@ const APP_ID = uuid(); const SESSION_CREATE_URI = new RegExp(`^/idverify/v1/sessions\\?sdkId=${APP_ID}`); const SESSION_URI = new RegExp(`^/idverify/v1/sessions/${SESSION_ID}\\?sdkId=${APP_ID}`); const SESSION_CONFIG_URI = new RegExp(`^/idverify/v1/sessions/${SESSION_ID}/configuration`); +const SESSION_TRACKED_DEVICES_URI = new RegExp(`^/idverify/v1/sessions/${SESSION_ID}/tracked-devices`); const FACE_CAPTURE_CREATE_URI = new RegExp(`^/idverify/v1/sessions/${SESSION_ID}/resources/face-capture`); const UPLOAD_FACE_CAPTURE_IMAGE_URI = new RegExp(`^/idverify/v1/sessions/${SESSION_ID}/resources/face-capture/${RESOURCE_ID}/image`); const MEDIA_URI = new RegExp(`^/idverify/v1/sessions/${SESSION_ID}/media/${MEDIA_ID}/content\\?sdkId=${APP_ID}`); @@ -542,6 +544,169 @@ describe('IDVService', () => { }); }); + describe('#getSessionTrackedDevices', () => { + describe('when a valid response is returned', () => { + it('should return a session tracked devices response', (done) => { + nock(config.yoti.idvApi) + .get(SESSION_TRACKED_DEVICES_URI) + .reply( + 200, + JSON.stringify([ + { + event: 'CONFIG_FIRST_LOADED', + created: '2021-06-11T11:39:24Z', + device: { + ip_address: '123.123.123.123', + ip_iso_country_code: 'GBR', + manufacture_name: 'Apple', + model_name: 'IphoneX', + os_name: 'MacOs', + os_version: '10.13.14', + browser_name: 'Chrome', + browser_version: '72.0.3626.119', + locale: 'en-GB', + client_version: '2.12.0', + }, + }, + { + event: 'RESOURCE_CREATED', + resource_id: '3fa85f64-5717-4562-b3fc-2c963f66afa6', + created: '2021-06-11T11:39:24Z', + device: { + ip_address: '123.123.123.123', + ip_iso_country_code: 'GBR', + manufacture_name: 'Apple', + model_name: 'IphoneX', + os_name: 'MacOs', + os_version: '10.13.14', + browser_name: 'Chrome', + browser_version: '72.0.3626.119', + locale: 'en-GB', + client_version: '2.12.0', + }, + }, + { + event: 'CLIENT_SESSION_TOKEN_DELETED', + created: '2021-06-11T11:39:24Z', + device: { + ip_address: '123.123.123.123', + ip_iso_country_code: 'GBR', + manufacture_name: 'Apple', + model_name: 'IphoneX', + os_name: 'MacOs', + os_version: '10.13.14', + browser_name: 'Chrome', + browser_version: '72.0.3626.119', + locale: 'en-GB', + client_version: '2.12.0', + }, + }, + ]) + ); + + idvService + .getSessionTrackedDevices(SESSION_ID) + .then((result) => { + expect(result).toBeInstanceOf(SessionTrackedDevicesResponse); + expect(result.getDeviceEvents()).toHaveLength(3); + done(); + }) + .catch(done); + }); + }); + describe('when response content is invalid', () => { + it('should reject', (done) => { + nock(config.yoti.idvApi) + .get(SESSION_TRACKED_DEVICES_URI) + .reply(200, { rubbish: 'garbage' }); + + idvService + .getSessionTrackedDevices(SESSION_ID) + .catch((err) => { + expect(err.message).toBe('tracked devices must be an array'); + done(); + }) + .catch(done); + }); + }); + describe('when response code is invalid', () => { + it('should reject', (done) => { + nock(config.yoti.idvApi).get(SESSION_TRACKED_DEVICES_URI).reply(400); + + idvService + .getSessionTrackedDevices(SESSION_ID) + .catch((err) => { + expect(err.message).toBe('Bad Request'); + done(); + }) + .catch(done); + }); + }); + describe('when response code is invalid with body', () => { + it('should reject with response body and message', (done) => { + nock(config.yoti.idvApi) + .get(SESSION_TRACKED_DEVICES_URI) + .reply(400, SOME_ERROR_RESPONSE, JSON_RESPONSE_HEADERS); + + idvService + .getSessionTrackedDevices(SESSION_ID) + .catch((err) => { + expect(err.message).toBe(SOME_ERROR_MESSAGE); + done(); + }) + .catch(done); + }); + }); + }); + + describe('#deleteSessionTrackedDevices', () => { + describe('when a valid response is returned', () => { + it('should have no response', (done) => { + nock(config.yoti.idvApi) + .delete(SESSION_TRACKED_DEVICES_URI) + .reply(204); + + idvService + .deleteSessionTrackedDevices(SESSION_ID) + .then((result) => { + expect(result).toBeUndefined(); + done(); + }) + .catch(done); + }); + }); + describe('when response code is invalid', () => { + it('should reject', (done) => { + nock(config.yoti.idvApi) + .delete(SESSION_TRACKED_DEVICES_URI) + .reply(400); + + idvService + .deleteSessionTrackedDevices(SESSION_ID) + .catch((err) => { + expect(err.message).toBe('Bad Request'); + done(); + }) + .catch(done); + }); + }); + describe('when response code is invalid with response body', () => { + it('should reject with response message and body', (done) => { + nock(config.yoti.idvApi) + .delete(SESSION_TRACKED_DEVICES_URI) + .reply(400, SOME_ERROR_RESPONSE, JSON_RESPONSE_HEADERS); + + idvService + .deleteSessionTrackedDevices(SESSION_ID) + .catch((err) => { + expect(err.message).toBe(SOME_ERROR_MESSAGE); + done(); + }) + .catch(done); + }); + }); + }); + describe('#createFaceCaptureResource', () => { let createFaceCaptureResourcePayload; diff --git a/tests/idv_service/session/retrieve/devices/device.description.response.spec.js b/tests/idv_service/session/retrieve/devices/device.description.response.spec.js new file mode 100644 index 00000000..5f9477b8 --- /dev/null +++ b/tests/idv_service/session/retrieve/devices/device.description.response.spec.js @@ -0,0 +1,103 @@ +const DeviceDescriptionResponse = require('../../../../../src/idv_service/session/retrieve/devices/device.description.response'); + +const payloadResponse = { + ip_address: '123.123.123.123', + ip_iso_country_code: 'GBR', + manufacture_name: 'Apple', + model_name: 'IphoneX', + os_name: 'iOS', + os_version: '10.13.14', + browser_name: 'Chrome', + browser_version: '72.0.3626.119', + locale: 'en-GB', + client_version: '2.12.0', +}; + +describe('DeviceDescriptionResponse', () => { + let deviceDescriptionResponse; + + beforeEach(() => { + deviceDescriptionResponse = new DeviceDescriptionResponse(payloadResponse); + }); + + describe('#getIpAddress', () => { + it('Should return the ip address', () => { + expect(deviceDescriptionResponse.getIpAddress()).toBe('123.123.123.123'); + }); + }); + + describe('#getIpISOCountryCode', () => { + it('Should return the ip ISO country code', () => { + expect(deviceDescriptionResponse.getIpISOCountryCode()).toBe('GBR'); + }); + }); + + describe('#getManufactureName', () => { + it('Should return the manufacture name', () => { + expect(deviceDescriptionResponse.getManufactureName()).toBe('Apple'); + }); + }); + + describe('#getModelName', () => { + it('Should return the model name', () => { + expect(deviceDescriptionResponse.getModelName()).toBe('IphoneX'); + }); + }); + + describe('#getOSName', () => { + it('Should return the OS name', () => { + expect(deviceDescriptionResponse.getOSName()).toBe('iOS'); + }); + }); + + describe('#getOSVersion', () => { + it('Should return the OS version', () => { + expect(deviceDescriptionResponse.getOSVersion()).toBe('10.13.14'); + }); + }); + + describe('#getBrowserName', () => { + it('Should return the browser name', () => { + expect(deviceDescriptionResponse.getBrowserName()).toBe('Chrome'); + }); + }); + + describe('#getBrowserVersion', () => { + it('Should return the browser version', () => { + expect(deviceDescriptionResponse.getBrowserVersion()).toBe('72.0.3626.119'); + }); + }); + + describe('#getLocale', () => { + it('Should return the locale', () => { + expect(deviceDescriptionResponse.getLocale()).toBe('en-GB'); + }); + }); + + describe('#getClientVersion', () => { + it('Should return the client version', () => { + expect(deviceDescriptionResponse.getClientVersion()).toBe('2.12.0'); + }); + }); + + describe('#constructor', () => { + it.each([ + ['ip_address', 123, 'ip_address must be a string'], + ['ip_iso_country_code', 123, 'ip_iso_country_code must be a string'], + ['manufacture_name', 123, 'manufacture_name must be a string'], + ['model_name', 123, 'model_name must be a string'], + ['os_name', 123, 'os_name must be a string'], + ['os_version', 123, 'os_version must be a string'], + ['browser_name', 123, 'browser_name must be a string'], + ['browser_version', 123, 'browser_version must be a string'], + ['locale', 123, 'locale must be a string'], + ['client_version', undefined, 'client_version must be a string'], + ])('Should error when invalid %s', (propertyName, invalidValue, expectedError) => { + const invalidPayloadResponse = { + ...payloadResponse, + [propertyName]: invalidValue, + }; + expect(() => new DeviceDescriptionResponse(invalidPayloadResponse)).toThrow(expectedError); + }); + }); +}); diff --git a/tests/idv_service/session/retrieve/devices/tracked.device.event.response.spec.js b/tests/idv_service/session/retrieve/devices/tracked.device.event.response.spec.js new file mode 100644 index 00000000..dfa4a8ec --- /dev/null +++ b/tests/idv_service/session/retrieve/devices/tracked.device.event.response.spec.js @@ -0,0 +1,62 @@ +const TrackedDeviceEventResponse = require('../../../../../src/idv_service/session/retrieve/devices/tracked.device.event.response'); +const DeviceDescriptionResponse = require('../../../../../src/idv_service/session/retrieve/devices/device.description.response'); + +const payloadResponse = { + event: 'CONFIG_FIRST_LOADED', + created: '2021-06-11T11:39:24Z', + device: { + ip_address: '123.123.123.123', + ip_iso_country_code: 'GBR', + manufacture_name: 'Apple', + model_name: 'IphoneX', + os_name: 'iOS', + os_version: '10.13.14', + browser_name: 'Chrome', + browser_version: '72.0.3626.119', + locale: 'en-GB', + client_version: '2.12.0', + }, +}; + +describe('TrackedDeviceEventResponse', () => { + let trackedDeviceEventResponse; + + beforeEach(() => { + trackedDeviceEventResponse = new TrackedDeviceEventResponse(payloadResponse); + }); + + describe('#getEvent', () => { + it('Should return the event', () => { + expect(trackedDeviceEventResponse.getEvent()).toBe('CONFIG_FIRST_LOADED'); + }); + }); + + describe('#getCreated', () => { + it('Should return the created date', () => { + const created = trackedDeviceEventResponse.getCreated(); + expect(created).toBeInstanceOf(Date); + expect(new Date(created).toISOString()).toBe('2021-06-11T11:39:24.000Z'); + }); + }); + + describe('#getDevice', () => { + it('Should return the device description', () => { + expect(trackedDeviceEventResponse.getDevice()).toBeInstanceOf(DeviceDescriptionResponse); + }); + }); + + describe('#constructor', () => { + it.each([ + ['event', 123, 'event must be a string'], + ['created', '2021-06-11B11:39.24.000Z', 'created must be a date like string'], + ['device', 'device-info', 'device must be a plain object'], + ['device', { missing: 'properties' }, 'client_version must be a string'], + ])('Should error when invalid %s', (propertyName, invalidValue, expectedError) => { + const invalidPayloadResponse = { + ...payloadResponse, + [propertyName]: invalidValue, + }; + expect(() => new TrackedDeviceEventResponse(invalidPayloadResponse)).toThrow(expectedError); + }); + }); +}); diff --git a/tests/idv_service/session/retrieve/devices/tracked.devices.response.spec.js b/tests/idv_service/session/retrieve/devices/tracked.devices.response.spec.js new file mode 100644 index 00000000..626c28ed --- /dev/null +++ b/tests/idv_service/session/retrieve/devices/tracked.devices.response.spec.js @@ -0,0 +1,84 @@ +const TrackedDeviceEventResponse = require('../../../../../src/idv_service/session/retrieve/devices/tracked.device.event.response'); +const SessionTrackedDevicesResponse = require('../../../../../src/idv_service/session/retrieve/devices/session.tracked.devices.response'); + +const payloadResponse = [ + { + event: 'CONFIG_FIRST_LOADED', + created: '2021-06-11T11:39:24Z', + device: { + ip_address: '123.123.123.123', + ip_iso_country_code: 'GBR', + manufacture_name: 'Apple', + model_name: 'IphoneX', + os_name: 'MacOs', + os_version: '10.13.14', + browser_name: 'Chrome', + browser_version: '72.0.3626.119', + locale: 'en-GB', + client_version: '2.12.0', + }, + }, + { + event: 'RESOURCE_CREATED', + resource_id: '3fa85f64-5717-4562-b3fc-2c963f66afa6', + created: '2021-06-11T11:39:24Z', + device: { + ip_address: '123.123.123.123', + ip_iso_country_code: 'GBR', + manufacture_name: 'Apple', + model_name: 'IphoneX', + os_name: 'MacOs', + os_version: '10.13.14', + browser_name: 'Chrome', + browser_version: '72.0.3626.119', + locale: 'en-GB', + client_version: '2.12.0', + }, + }, + { + event: 'CLIENT_SESSION_TOKEN_DELETED', + created: '2021-06-11T11:39:24Z', + device: { + ip_address: '123.123.123.123', + ip_iso_country_code: 'GBR', + manufacture_name: 'Apple', + model_name: 'IphoneX', + os_name: 'MacOs', + os_version: '10.13.14', + browser_name: 'Chrome', + browser_version: '72.0.3626.119', + locale: 'en-GB', + client_version: '2.12.0', + }, + }, +]; + +describe('SessionTrackedDevicesResponse', () => { + let identityProfileResponse; + + beforeEach(() => { + identityProfileResponse = new SessionTrackedDevicesResponse(payloadResponse); + }); + + describe('#deviceEvents', () => { + it('Should return the list of device events', () => { + const deviceEvents = identityProfileResponse.getDeviceEvents(); + expect(deviceEvents).toHaveLength(3); + deviceEvents.forEach((deviceEvent) => { + expect(deviceEvent).toBeInstanceOf(TrackedDeviceEventResponse); + }); + expect(deviceEvents[0].getEvent()).toBe('CONFIG_FIRST_LOADED'); + expect(deviceEvents[1].getEvent()).toBe('RESOURCE_CREATED'); + expect(deviceEvents[2].getEvent()).toBe('CLIENT_SESSION_TOKEN_DELETED'); + }); + }); + + describe('#constructor', () => { + it.each([ + ['type', 123, 'tracked devices must be an array'], + ['content', [{ not: 'right' }], 'event must be a string'], + ])('Should error when invalid %s', (propertyName, invalidValue, expectedError) => { + expect(() => new SessionTrackedDevicesResponse(invalidValue)).toThrow(expectedError); + }); + }); +}); diff --git a/types/src/client/idv.client.d.ts b/types/src/client/idv.client.d.ts index 487e93ea..ebfd0524 100644 --- a/types/src/client/idv.client.d.ts +++ b/types/src/client/idv.client.d.ts @@ -115,4 +115,22 @@ declare class IDVClient { * @returns {Promise} */ getSessionConfiguration(sessionId: string): Promise; + /** + * Fetches the tracked devices for the given sessionID. + * + * @param {string} sessionId + * + * @typedef {import('../idv_service/session/retrieve/devices/session.tracked.devices.response')} SessionTrackedDevicesResponse + * + * @returns {Promise} + */ + getSessionTrackedDevices(sessionId: string): Promise; + /** + * Deletes the tracked devices for given sessionID. + * + * @param {string} sessionId + * + * @returns {Promise} + */ + deleteSessionTrackedDevices(sessionId: string): Promise; } diff --git a/types/src/idv_service/idv.service.d.ts b/types/src/idv_service/idv.service.d.ts index 969724e8..c92758ba 100644 --- a/types/src/idv_service/idv.service.d.ts +++ b/types/src/idv_service/idv.service.d.ts @@ -91,6 +91,20 @@ declare class IDVService { * @returns {Promise} */ getSessionConfiguration(sessionId: string): Promise; + /** + * @param {string} sessionId + * + * @returns {Promise} + */ + getSessionTrackedDevices(sessionId: string): Promise; + /** + * Deletes tracked devices for a given session + * + * @param {string} sessionId + * + * @returns {Promise} + */ + deleteSessionTrackedDevices(sessionId: string): Promise; } import SessionSpecification = require("./session/create/session.specification"); import CreateSessionResult = require("./session/create/create.session.result"); @@ -101,3 +115,4 @@ import CreateFaceCaptureResourcePayload = require("./session/create/face_capture import CreateFaceCaptureResourceResponse = require("./session/retrieve/create.face.capture.resource.response"); import UploadFaceCaptureImagePayload = require("./session/create/face_capture/upload.face.capture.image.payload"); import SessionConfigurationResponse = require("./session/retrieve/configuration/session.configuration.response"); +import SessionTrackedDevicesResponse = require("./session/retrieve/devices/session.tracked.devices.response"); diff --git a/types/src/idv_service/session/retrieve/devices/device.description.response.d.ts b/types/src/idv_service/session/retrieve/devices/device.description.response.d.ts new file mode 100644 index 00000000..655fb5ef --- /dev/null +++ b/types/src/idv_service/session/retrieve/devices/device.description.response.d.ts @@ -0,0 +1,84 @@ +export = DeviceDescriptionResponse; +declare class DeviceDescriptionResponse { + constructor(payload: any); + /** @private */ + private ipAddress; + /** @private */ + private ipISOCountryCode; + /** @private */ + private manufactureName; + /** @private */ + private modelName; + /** @private */ + private osName; + /** @private */ + private osVersion; + /** @private */ + private browserName; + /** @private */ + private browserVersion; + /** @private */ + private locale; + /** @private */ + private clientVersion; + /** + * Returns the device ip address. + * + * @returns {string | undefined} + */ + getIpAddress(): string | undefined; + /** + * Returns the device ip ISO country code. + * + * @returns {string | undefined} + */ + getIpISOCountryCode(): string | undefined; + /** + * Returns the device manufacture name. + * + * @returns {string | undefined} + */ + getManufactureName(): string | undefined; + /** + * Returns the device model name. + * + * @returns {string | undefined} + */ + getModelName(): string | undefined; + /** + * Returns the device OS name. + * + * @returns {string | undefined} + */ + getOSName(): string | undefined; + /** + * Returns the device OS version. + * + * @returns {string | undefined} + */ + getOSVersion(): string | undefined; + /** + * Returns the device browser name. + * + * @returns {string | undefined} + */ + getBrowserName(): string | undefined; + /** + * Returns the device browser version. + * + * @returns {string | undefined} + */ + getBrowserVersion(): string | undefined; + /** + * Returns the device locale. + * + * @returns {string | undefined} + */ + getLocale(): string | undefined; + /** + * Returns the client version. + * + * @returns {string} + */ + getClientVersion(): string; +} diff --git a/types/src/idv_service/session/retrieve/devices/session.tracked.devices.response.d.ts b/types/src/idv_service/session/retrieve/devices/session.tracked.devices.response.d.ts new file mode 100644 index 00000000..e5c44cba --- /dev/null +++ b/types/src/idv_service/session/retrieve/devices/session.tracked.devices.response.d.ts @@ -0,0 +1,16 @@ +export = TrackedDevicesResponse; +declare class TrackedDevicesResponse { + /** + * @param {{}[]} response + */ + constructor(response: {}[]); + /** @private */ + private deviceEvents; + /** + * Returns the list of tracked device events. + * + * @returns {TrackedDeviceEventResponse[]} + */ + getDeviceEvents(): TrackedDeviceEventResponse[]; +} +import TrackedDeviceEventResponse = require("./tracked.device.event.response"); diff --git a/types/src/idv_service/session/retrieve/devices/tracked.device.event.response.d.ts b/types/src/idv_service/session/retrieve/devices/tracked.device.event.response.d.ts new file mode 100644 index 00000000..00a95a6c --- /dev/null +++ b/types/src/idv_service/session/retrieve/devices/tracked.device.event.response.d.ts @@ -0,0 +1,29 @@ +export = TrackedDeviceEventResponse; +declare class TrackedDeviceEventResponse { + constructor(payload: any); + /** @private */ + private event; + /** @private */ + private created; + /** @private */ + private device; + /** + * Returns the event. + * + * @returns {string} + */ + getEvent(): string; + /** + * Returns the created date. + * + * @returns {Date} + */ + getCreated(): Date; + /** + * Returns the device description. + * + * @returns {DeviceDescriptionResponse} + */ + getDevice(): DeviceDescriptionResponse; +} +import DeviceDescriptionResponse = require("./device.description.response");