Skip to content

Commit

Permalink
SDK-2152 Support liveness check (#354)
Browse files Browse the repository at this point in the history
Added `static` liveness check support in request builder.
Added `static` liveness check support in response handler.
Updated the IDV example to display the Zoom liveness frames or the Static liveness image as per user's choice.
  • Loading branch information
abdalmajeed-yoti authored Oct 28, 2022
1 parent 47f7274 commit 95ced2a
Show file tree
Hide file tree
Showing 9 changed files with 166 additions and 3 deletions.
7 changes: 7 additions & 0 deletions examples/idv/src/controllers/index.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,18 @@ async function createSession() {
.withManualCheckAlways()
.build()
)
// For zoom liveness check [only one type of liveness check to be enabled at a time]
.withRequestedCheck(
new RequestedLivenessCheckBuilder()
.forZoomLiveness()
.build()
)
// For static liveness check
// .withRequestedCheck(
// new RequestedLivenessCheckBuilder()
// .forStaticLiveness()
// .build()
// )
.withRequestedCheck(
new RequestedFaceMatchCheckBuilder()
.withManualCheckNever()
Expand Down
32 changes: 32 additions & 0 deletions examples/idv/views/pages/success.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -696,5 +696,37 @@
<% }); %>
<% } %>

<% if (sessionResult.getResources().getStaticLivenessResources().length > 0) { %>
<div class="row pt-4">
<div class="col">
<h2>Static Liveness Resources</h2>
</div>
</div>
<%
let livenessNum = 0;
sessionResult.getResources().getStaticLivenessResources().forEach(function(livenessResource){
livenessNum++;
%>
<div class="row pt-4">
<div class="col">
<table class="table table-striped table-light">
<tbody>
<tr>
<td><%= livenessResource.getImage().getId() %></td>
</tr>
<tr>
<img class="card-img-top" src="/media?mediaId=<%= livenessResource.getImage().getId() %>" />
</tr>
</tbody>
</table>
</div>
</div>
<% }); %>
<% } %>
</div>
<%- include('layout/footer'); -%>
1 change: 1 addition & 0 deletions src/idv_service/idv.constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ module.exports = Object.freeze({
SANCTIONS: 'SANCTIONS',
LIVENESS: 'LIVENESS',
ZOOM: 'ZOOM',
STATIC: 'STATIC',
CAMERA: 'CAMERA',
CAMERA_AND_UPLOAD: 'CAMERA_AND_UPLOAD',
RESOURCE_UPDATE: 'RESOURCE_UPDATE',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ class RequestedLivenessCheckBuilder {
return this.forLivenessType(IDVConstants.ZOOM);
}

/**
* Sets the type to be of a Static liveness check
*
* @returns {this}
*/
forStaticLiveness() {
return this.forLivenessType(IDVConstants.STATIC);
}

/**
* Sets the type of the liveness check to the supplied value
*
Expand Down
13 changes: 13 additions & 0 deletions src/idv_service/session/retrieve/resource.container.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const IdDocumentResourceResponse = require('./id.document.resource.response');
const ZoomLivenessResourceResponse = require('./zoom.liveness.resource.response');
const StaticLivenessResourceResponse = require('./static.liveness.resource.response');
const LivenessResourceResponse = require('./liveness.resource.response');
const IDVConstants = require('../../idv.constants');
const Validation = require('../../../yoti_common/validation');
Expand Down Expand Up @@ -35,6 +36,8 @@ class ResourceContainer {
switch (resource.liveness_type) {
case IDVConstants.ZOOM:
return new ZoomLivenessResourceResponse(resource);
case IDVConstants.STATIC:
return new StaticLivenessResourceResponse(resource);
default:
return new LivenessResourceResponse(resource);
}
Expand Down Expand Up @@ -83,6 +86,16 @@ class ResourceContainer {
.getLivenessCapture()
.filter((resource) => resource instanceof ZoomLivenessResourceResponse);
}

/**
* @returns {StaticLivenessResourceResponse[]}
* The list of Static liveness resources
*/
getStaticLivenessResources() {
return this
.getLivenessCapture()
.filter((resource) => resource instanceof StaticLivenessResourceResponse);
}
}

module.exports = ResourceContainer;
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use strict';

const LivenessResourceResponse = require('./liveness.resource.response');
const Validation = require('../../../yoti_common/validation');
const MediaResponse = require('./media.response');

class StaticLivenessResourceResponse extends LivenessResourceResponse {
constructor(resource) {
super(resource);

const { image } = resource;

if (image) {
const { media } = image;

Validation.isPlainObject(media, 'media');

this.image = new MediaResponse(media);
}
}

/**
* @returns {MediaResponse}
*/
getImage() {
return this.image;
}
}

module.exports = StaticLivenessResourceResponse;
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,22 @@ describe('RequestedLivenessCheckBuilder', () => {
expect(JSON.stringify(check)).toBe(expectedJson);
});

it('should build RequestedLivenessCheck for static liveness', () => {
const expectedJson = JSON.stringify({
type: 'LIVENESS',
config: {
max_retries: 1,
liveness_type: 'STATIC',
},
});

const check = new RequestedLivenessCheckBuilder()
.forStaticLiveness()
.build();

expect(JSON.stringify(check)).toBe(expectedJson);
});

it('should build RequestedLivenessCheck with custom retries', () => {
const expectedJson = JSON.stringify({
type: 'LIVENESS',
Expand Down
27 changes: 24 additions & 3 deletions tests/idv_service/session/retrieve/resource.container.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ const IdDocumentResourceResponse = require('../../../../src/idv_service/session/
const ZoomLivenessResourceResponse = require('../../../../src/idv_service/session/retrieve/zoom.liveness.resource.response');
const LivenessResourceResponse = require('../../../../src/idv_service/session/retrieve/liveness.resource.response');
const SupplementaryDocumentResourceResponse = require('../../../../src/idv_service/session/retrieve/supplementary.document.resource.response');
const StaticLivenessResourceResponse = require('../../../../src/idv_service/session/retrieve/static.liveness.resource.response');

const ZOOM = 'ZOOM';
const STATIC = 'STATIC';
const SOME_UNKNOWN_LIVENESS_TYPE = 'SOME_UNKNOWN_LIVENESS_TYPE';

describe('ResourceContainer', () => {
Expand All @@ -24,6 +26,9 @@ describe('ResourceContainer', () => {
{
liveness_type: ZOOM,
},
{
liveness_type: STATIC,
},
{
liveness_type: SOME_UNKNOWN_LIVENESS_TYPE,
},
Expand Down Expand Up @@ -75,7 +80,7 @@ describe('ResourceContainer', () => {
describe('when liveness capture is available', () => {
it('should return array of liveness resource response', () => {
const livenessCapture = resourceContainer.getLivenessCapture();
expect(livenessCapture.length).toBe(2);
expect(livenessCapture.length).toBe(3);
livenessCapture.forEach((item) => {
expect(item).toBeInstanceOf(LivenessResourceResponse);
});
Expand All @@ -87,10 +92,16 @@ describe('ResourceContainer', () => {
expect(livenessCapture[0].getLivenessType()).toBe(ZOOM);
});

it('should return static liveness resource response', () => {
const livenessCapture = resourceContainer.getLivenessCapture();
expect(livenessCapture[1]).toBeInstanceOf(StaticLivenessResourceResponse);
expect(livenessCapture[1].getLivenessType()).toBe(STATIC);
});

it('should return unknown liveness resource response', () => {
const livenessCapture = resourceContainer.getLivenessCapture();
expect(livenessCapture[1]).toBeInstanceOf(LivenessResourceResponse);
expect(livenessCapture[1].getLivenessType()).toBe(SOME_UNKNOWN_LIVENESS_TYPE);
expect(livenessCapture[2]).toBeInstanceOf(LivenessResourceResponse);
expect(livenessCapture[2].getLivenessType()).toBe(SOME_UNKNOWN_LIVENESS_TYPE);
});
});
describe('when liveness capture is not available', () => {
Expand All @@ -112,4 +123,14 @@ describe('ResourceContainer', () => {
});
});
});

describe('#getStaticLivenessResources', () => {
it('should return array of StaticLivenessResourceResponse', () => {
const livenessCapture = resourceContainer.getStaticLivenessResources();
livenessCapture.forEach((item) => {
expect(item).toBeInstanceOf(StaticLivenessResourceResponse);
expect(item.getLivenessType()).toBe(STATIC);
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const StaticLivenessResourceResponse = require('../../../../src/idv_service/session/retrieve/static.liveness.resource.response');
const MediaResponse = require('../../../../src/idv_service/session/retrieve/media.response');

describe('StaticLivenessResourceResponse', () => {
let staticLivenessResourceResponse;

beforeEach(() => {
staticLivenessResourceResponse = new StaticLivenessResourceResponse({
liveness_type: 'some-liveness-type',
id: 'some-id',
image: {
media: {},
},
});
});

describe('#getId', () => {
it('should return ID', () => {
expect(staticLivenessResourceResponse.getId()).toBe('some-id');
});
});

describe('#getLivenessType', () => {
it('should return liveness type', () => {
expect(staticLivenessResourceResponse.getLivenessType()).toBe('some-liveness-type');
});
});

describe('#getImage', () => {
it('should return media', () => {
expect(staticLivenessResourceResponse.getImage()).toBeInstanceOf(MediaResponse);
});
});
});

0 comments on commit 95ced2a

Please sign in to comment.