diff --git a/src/plugins/impl/fingerprint.plugin.ts b/src/plugins/impl/fingerprint.plugin.ts index 1f1fd6e..8cefa83 100644 --- a/src/plugins/impl/fingerprint.plugin.ts +++ b/src/plugins/impl/fingerprint.plugin.ts @@ -11,6 +11,8 @@ import { ExternalIdDbGateway } from '../../db/external.id.db.gateway'; import { IsValidInstance } from 'protocol-common/validation/decorators/parameter/is.valid.instance.decorator'; import { ValidateParams } from 'protocol-common/validation/decorators/function/validate.params.decorator'; import { IsValidInstanceOf } from 'protocol-common/validation/decorators/parameter/is.valid.instance.of.decorator'; +import { BioAuthSaveParamsDto } from '../../remote/dto/bio.auth.save.params.dto'; +import { BioAuthSaveDto } from '../../remote/dto/bio.auth.save.dto'; export class FingerprintPlugin implements IPlugin { @@ -23,9 +25,9 @@ export class FingerprintPlugin implements IPlugin { ) { } /** - * The verify logic involves calling verify against the identity service, and then handling certain error codes - * by asking the identity service for the positions with the highest image quality - * TODO identity service could just handle both these tasks in one call. + * The verify logic involves calling verify against the Bio Auth Service, and then handling certain error codes by asking the Bio Auth Service for + * the positions with the highest image quality + * TODO - PRO-3134: Update this after Bio Auth Service handles both these tasks in one call. */ @ValidateParams public async verify( @@ -59,12 +61,12 @@ export class FingerprintPlugin implements IPlugin { } } - // The identity service should throw this error on no match, but just to be safe double check it and throw here + // Bio Auth Service should throw this error on no match, but just to be safe double check it and throw here if (response.data.status !== 'matched') { throw new ProtocolException(ProtocolErrorCode.FINGERPRINT_NO_MATCH, 'Fingerprint did not match stored records for citizen supplied through filters'); } - // TODO right now the data we get from identity service uses did we should change it to agent id and then we don't need this conversion + // TODO right now the data we get from Bio Auth Service uses did we should change it to agent id and then we don't need this conversion return { status: response.data.status, id: response.data.did @@ -77,17 +79,16 @@ export class FingerprintPlugin implements IPlugin { e.details = e.details || {}; e.details.bestPositions = response.data; } catch (ex) { - Logger.error('Error calling identity service position quality check', ex); + Logger.error('Error calling Bio Auth Service position quality check', ex); } return e; } - public async save(id: string, params: any) { - // TEMP until the identity service is updated + public async save(id: string, params: BioAuthSaveParamsDto | BioAuthSaveParamsDto[]) { const data = Array.isArray(params) ? params : [params]; - for (const datum of data) { - datum.did = id; - } - await this.bioAuthService.templatize(data); + const fingerprints: BioAuthSaveDto[] = data.map((param: BioAuthSaveParamsDto) => { + return {id, params: param}; + }); + await this.bioAuthService.bulkSave({fingerprints}); } } diff --git a/src/remote/bio.auth.service.interface.ts b/src/remote/bio.auth.service.interface.ts index 0c929fc..b8b3020 100644 --- a/src/remote/bio.auth.service.interface.ts +++ b/src/remote/bio.auth.service.interface.ts @@ -1,6 +1,8 @@ +import { BioAuthBulkSaveDto } from './dto/bio.auth.bulk.save.dto'; + export abstract class IBioAuthService { abstract verifyFingerprint(position: number, image: string, dids: string): Promise; abstract verifyFingerprintTemplate(position: number, template: string, dids: string): Promise; - abstract templatize(data: any): Promise; + abstract bulkSave(dto: BioAuthBulkSaveDto): Promise; abstract qualityCheck(dids: string): Promise; } diff --git a/src/remote/dto/bio.auth.bulk.save.dto.ts b/src/remote/dto/bio.auth.bulk.save.dto.ts new file mode 100644 index 0000000..fed9b57 --- /dev/null +++ b/src/remote/dto/bio.auth.bulk.save.dto.ts @@ -0,0 +1,9 @@ +import { BioAuthSaveDto } from './bio.auth.save.dto'; +import { ValidateNested } from 'class-validator'; + +/** + * DTO for each fingerprint in the body of the request sent to Bio Auth Service's /save endpoint + */ +export class BioAuthBulkSaveDto { + @ValidateNested() readonly fingerprints: Array; +} diff --git a/src/remote/dto/bio.auth.save.dto.ts b/src/remote/dto/bio.auth.save.dto.ts new file mode 100644 index 0000000..b958f71 --- /dev/null +++ b/src/remote/dto/bio.auth.save.dto.ts @@ -0,0 +1,11 @@ +import { BioAuthSaveParamsDto } from './bio.auth.save.params.dto'; +import { IsString, ValidateNested } from 'class-validator'; +import { Type } from 'class-transformer'; + +/** + * DTO for the body of the request sent to Bio Auth Service's /save endpoint + */ +export class BioAuthSaveDto { + @IsString() readonly id: string; + @ValidateNested() @Type(() => BioAuthSaveParamsDto) readonly params: BioAuthSaveParamsDto; +} diff --git a/src/remote/dto/bio.auth.save.params.dto.ts b/src/remote/dto/bio.auth.save.params.dto.ts new file mode 100644 index 0000000..ac71d77 --- /dev/null +++ b/src/remote/dto/bio.auth.save.params.dto.ts @@ -0,0 +1,17 @@ +import { FingerprintTypeEnum } from '../fingerprint.type.enum'; +import { IsEnum, IsInt, IsISO8601, IsNumber, IsOptional, IsString, Length } from 'class-validator'; +import { FingerprintPositionEnum } from '../fingerprint.position.enum'; + +/** + * DTO for the params of each fingerprint in the body of the request sent to Bio Auth Service's /save endpoint + */ +export class BioAuthSaveParamsDto { + @IsInt() readonly type_id: number; + @IsISO8601() readonly capture_date: string; + @IsEnum(FingerprintPositionEnum) readonly position: FingerprintPositionEnum; + @IsOptional() @IsString() readonly image?: string; + @IsOptional() @IsString() readonly template?: string; + @IsOptional() @IsNumber() readonly quality_score?: number; + @IsOptional() @Length(2, 2) readonly missing_code?: string; + @IsEnum(FingerprintTypeEnum) readonly type: FingerprintTypeEnum; +} diff --git a/src/remote/fingerprint.position.enum.ts b/src/remote/fingerprint.position.enum.ts new file mode 100644 index 0000000..2fedf21 --- /dev/null +++ b/src/remote/fingerprint.position.enum.ts @@ -0,0 +1,15 @@ +/** + * This enum is a simple way to capture which finger is represented by a given fingerprint. + */ +export enum FingerprintPositionEnum { + RIGHT_THUMB = '1', + RIGHT_INDEX = '2', + RIGHT_MIDDLE = '3', + RIGHT_RING = '4', + RIGHT_PINKY = '5', + LEFT_THUMB = '6', + LEFT_INDEX = '7', + LEFT_MIDDLE = '8', + LEFT_RING = '9', + LEFT_PINKY = '10' +} diff --git a/src/remote/fingerprint.type.enum.ts b/src/remote/fingerprint.type.enum.ts new file mode 100644 index 0000000..f6ad476 --- /dev/null +++ b/src/remote/fingerprint.type.enum.ts @@ -0,0 +1,7 @@ +/** + * Currently supported modes of interacting with Bio Auth Service via fingerprints + */ +export enum FingerprintTypeEnum { + IMAGE = 'IMAGE', + TEMPLATE = 'TEMPLATE' +} diff --git a/src/remote/impl/bio.auth.service.ts b/src/remote/impl/bio.auth.service.ts index 5f71a33..64c80b6 100644 --- a/src/remote/impl/bio.auth.service.ts +++ b/src/remote/impl/bio.auth.service.ts @@ -2,12 +2,11 @@ import { ProtocolHttpService } from 'protocol-common/protocol.http.service'; import { AxiosRequestConfig } from 'axios'; import { HttpService, Injectable } from '@nestjs/common'; import { IBioAuthService } from '../bio.auth.service.interface'; +import { BioAuthBulkSaveDto } from '../dto/bio.auth.bulk.save.dto'; +import { FingerprintTypeEnum } from '../fingerprint.type.enum'; /** - * This service class is a facade for the IdentityService HTTP API. - * - * Right now the backend (ie which fingerprint template db to connect to) is defined by an environment variable, eventually we'll want this to - * be set in a country profile, so the process of setting the backend will change. + * This service class is a facade for the Bio Auth Service HTTP API. */ @Injectable() export class BioAuthService implements IBioAuthService { @@ -21,12 +20,11 @@ export class BioAuthService implements IBioAuthService { } /** - * Send a request to IdentityService to verify a fingerprint image. - * TODO right now this keeps the identity service url the same, we probably want to change that so it better matches our plugin pattern + * Send a request to Bio Auth Service to verify a fingerprint image. * * @param position The position of the finger that the fingerprint template refers to. * @param image The image of the fingerprint. - * @param dids A comma-separated list of dids that the fingerprint template may correspond to. + * @param dids A comma-separated list of dids that the fingerprint may correspond to. */ public async verifyFingerprint(position: number, image: string, dids: string): Promise { const request: AxiosRequestConfig = { @@ -45,7 +43,7 @@ export class BioAuthService implements IBioAuthService { } /** - * Send a request to IdentityService to verify a fingerprint template. + * Send a request to Bio Auth Service to verify a fingerprint template. * * @param position The position of the finger that the fingerprint template refers to. * @param template The template of the fingerprint. @@ -62,28 +60,29 @@ export class BioAuthService implements IBioAuthService { filters: { dids }, - imageType: 'TEMPLATE', + imageType: FingerprintTypeEnum.TEMPLATE, }, }; return this.http.requestWithRetry(request); } /** - * TODO the identity service should update the templatizer endpoint to accept data in the format { id, filters, params } - * Until it does, we just forward the params as the data it's currently expecting + * Send a request to Bio Auth Service to save one or more fingerprints. They may be fingerprint templates or images. + * + * @param dto Body of the request to be sent to Bio Auth Service. See the class definition for the shape. */ - public async templatize(data: any): Promise { + public async bulkSave(dto: BioAuthBulkSaveDto): Promise { const request: AxiosRequestConfig = { method: 'POST', - url: `${this.baseUrl}/api/v1/templatizer/bulk/template`, - data, + url: `${this.baseUrl}/api/v1/save`, + data: dto, }; return this.http.requestWithRetry(request); } /** - * Queries the identity service to get the finger positions with the best quality scores - * TODO the identity service should update the positions endpoint to accept data in the body instead of via url params + * Queries the Bio Auth Service to get the finger positions with the best quality scores + * TODO PRO-3084: use the Bio Auth Service POST /positions endpoint to accept data in the body instead of via url params */ public async qualityCheck(dids: string): Promise { const request: AxiosRequestConfig = { diff --git a/src/sms/sms.service.ts b/src/sms/sms.service.ts index 156856c..99dd219 100644 --- a/src/sms/sms.service.ts +++ b/src/sms/sms.service.ts @@ -34,7 +34,7 @@ export class SmsService { const externalIds: ExternalId[] = await this.externalIdDbGateway.fetchExternalIds(VerifyFiltersDto.getIds(filters)); if (externalIds.some((id: ExternalId) => id.did !== externalIds[0].did)) { - throw new ProtocolException(ProtocolErrorCode.DUPLICATE_ENTRY, 'Provided filters did not uniquely identity a did'); + throw new ProtocolException(ProtocolErrorCode.DUPLICATE_ENTRY, 'Provided filters did not uniquely identify a did'); } const did: string = externalIds[0].did; diff --git a/test/e2e/escrow.fingerprint.e2e-spec.ts b/test/e2e/escrow.fingerprint.e2e-spec.ts index 511defa..c37fa29 100644 --- a/test/e2e/escrow.fingerprint.e2e-spec.ts +++ b/test/e2e/escrow.fingerprint.e2e-spec.ts @@ -30,7 +30,7 @@ describe('EscrowController (e2e) using fingerprint plugin', () => { jest.setTimeout(10000); status = 'matched'; - did = 'agentId123'; // Right now identity service returns did, eventually it will return agentId + did = 'agentId123'; // Right now Bio Auth Service returns did, eventually it will return agentId const mockAgencyService = new MockAgencyService('foo'); const mockBioAuthService = new MockBioAuthService(status, did); diff --git a/test/mock/mock.bio.auth.service.ts b/test/mock/mock.bio.auth.service.ts index ef9261b..19157ea 100644 --- a/test/mock/mock.bio.auth.service.ts +++ b/test/mock/mock.bio.auth.service.ts @@ -1,10 +1,11 @@ import { IBioAuthService } from '../../src/remote/bio.auth.service.interface'; +import { BioAuthBulkSaveDto } from '../../src/remote/dto/bio.auth.bulk.save.dto'; export class MockBioAuthService implements IBioAuthService { constructor(private readonly status: string, private readonly did: string) {} - async templatize(data: any): Promise { + async bulkSave(dto: BioAuthBulkSaveDto): Promise { return Promise.resolve(undefined); }