From 357e1b032e6b3b79bee24da9ec014acb6fbbf7cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Wed, 2 Oct 2024 08:56:48 +0000 Subject: [PATCH 01/29] feat: init --- .../license-api/src/app/modules/license/dto/updateLicense.dto.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/services/license-api/src/app/modules/license/dto/updateLicense.dto.ts b/apps/services/license-api/src/app/modules/license/dto/updateLicense.dto.ts index a049e508c629..ab246ec6ea6b 100644 --- a/apps/services/license-api/src/app/modules/license/dto/updateLicense.dto.ts +++ b/apps/services/license-api/src/app/modules/license/dto/updateLicense.dto.ts @@ -30,6 +30,7 @@ export class UpdateLicenseRequest { @IsString() readonly requestId?: string } + export class UpdateLicenseResponse { @ApiProperty() @IsBoolean() From c985c07cf6da89ac6b03a75cdfed2abb06c8984a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Thu, 3 Oct 2024 14:14:22 +0000 Subject: [PATCH 02/29] feat: update client types --- .../lib/clients/baseLicenseUpdateClient.ts | 22 ++++------ .../drivingLicenseMapper.ts | 4 +- .../services/drivingLicenseClient.service.ts | 9 ++--- .../drivingLicenseUpdateClient.service.ts | 18 ++++----- .../firearmLicenseMapper.ts | 5 +-- .../services/firearmLicenseClient.service.ts | 14 +++---- .../firearmLicenseUpdateClient.service.ts | 20 +++++----- .../src/lib/licenseClient.type.ts | 40 +++++++++++++++++++ 8 files changed, 76 insertions(+), 56 deletions(-) diff --git a/libs/clients/license-client/src/lib/clients/baseLicenseUpdateClient.ts b/libs/clients/license-client/src/lib/clients/baseLicenseUpdateClient.ts index 186768ceaa6c..8a043b59578f 100644 --- a/libs/clients/license-client/src/lib/clients/baseLicenseUpdateClient.ts +++ b/libs/clients/license-client/src/lib/clients/baseLicenseUpdateClient.ts @@ -1,35 +1,29 @@ -import type { Logger } from '@island.is/logging' import { Injectable } from '@nestjs/common' import { - Pass, + PassData, PassDataInput, - RevokePassData, - SmartSolutionsApi, -} from '@island.is/clients/smartsolutions' -import { PassVerificationData, Result } from '../licenseClient.type' + PassRevocationData, + PassVerificationData, + Result, +} from '../licenseClient.type' @Injectable() export abstract class BaseLicenseUpdateClient { - constructor( - protected logger: Logger, - protected smartApi: SmartSolutionsApi, - ) {} - abstract pushUpdate( inputData: PassDataInput, nationalId: string, requestId?: string, - ): Promise> + ): Promise> abstract pullUpdate( nationalId: string, requestId?: string, - ): Promise> + ): Promise> abstract revoke( nationalId: string, requestId?: string, - ): Promise> + ): Promise> abstract verify( inputData: string, diff --git a/libs/clients/license-client/src/lib/clients/driving-license-client/drivingLicenseMapper.ts b/libs/clients/license-client/src/lib/clients/driving-license-client/drivingLicenseMapper.ts index 4a3f6aa9cd8a..f2ce6426f514 100644 --- a/libs/clients/license-client/src/lib/clients/driving-license-client/drivingLicenseMapper.ts +++ b/libs/clients/license-client/src/lib/clients/driving-license-client/drivingLicenseMapper.ts @@ -69,9 +69,7 @@ const formatRights = ( export const nationalIdIndex = 'kennitala' -export const mapNationalId = ( - nationalId: string, -): PassInputFieldValueDataInput => { +export const mapNationalId = (nationalId: string) => { return { identifier: nationalIdIndex, value: nationalId ? formatSsn(nationalId) : '', diff --git a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseClient.service.ts b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseClient.service.ts index 3c89d2f4af11..af8e49532bbb 100644 --- a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseClient.service.ts +++ b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseClient.service.ts @@ -5,11 +5,6 @@ import { RemarkCode, } from '@island.is/clients/driving-license' import { FetchError } from '@island.is/clients/middlewares' -import { - Pass, - PassDataInput, - SmartSolutionsApi, -} from '@island.is/clients/smartsolutions' import type { Logger } from '@island.is/logging' import { LOGGER_PROVIDER } from '@island.is/logging' import { BadRequestException, Inject, Injectable } from '@nestjs/common' @@ -21,10 +16,12 @@ import { PkPassVerificationInputData, VerifyPkPassResult, Result, + PassDataInput, } from '../../../licenseClient.type' import { DrivingLicenseVerifyExtraData } from '../drivingLicenseClient.type' import { createPkPassDataInput } from '../drivingLicenseMapper' import { FeatureFlagService, Features } from '@island.is/nest/feature-flags' +import { Pass, SmartSolutionsApi } from '@island.is/clients/smartsolutions' /** Category to attach each log message to */ const LOG_CATEGORY = 'drivinglicense-service' @@ -153,7 +150,7 @@ export class DrivingLicenseClient ? { imageBase64String: image.substring(image.indexOf(',') + 1).trim(), } - : null, + : undefined, } return payload diff --git a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClient.service.ts b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClient.service.ts index c29b7bc92608..57f1e01e5604 100644 --- a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClient.service.ts +++ b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClient.service.ts @@ -3,12 +3,9 @@ import { LOGGER_PROVIDER } from '@island.is/logging' import type { ConfigType } from '@island.is/nest/config' import { Inject, Injectable } from '@nestjs/common' import { - Pass, + PassData, PassDataInput, - RevokePassData, - SmartSolutionsApi, -} from '@island.is/clients/smartsolutions' -import { + PassRevocationData, PassVerificationData, Result, VerifyInputData, @@ -21,6 +18,7 @@ import { nationalIdIndex, } from '../drivingLicenseMapper' import { DrivingDigitalLicenseClientConfig } from '../drivingLicenseClient.config' +import { SmartSolutionsApi } from '@island.is/clients/smartsolutions' /** Category to attach each log message to */ const LOG_CATEGORY = 'driving-license-service' @@ -34,14 +32,14 @@ export class DrivingLicenseUpdateClient extends BaseLicenseUpdateClient { private drivingLicenseApi: DrivingLicenseApi, protected smartApi: SmartSolutionsApi, ) { - super(logger, smartApi) + super() } pushUpdate( inputData: PassDataInput, nationalId: string, requestId?: string, - ): Promise> { + ): Promise> { const inputFieldValues = inputData.inputFieldValues ?? [] //small check that nationalId doesnt' already exist if ( @@ -63,7 +61,7 @@ export class DrivingLicenseUpdateClient extends BaseLicenseUpdateClient { async pullUpdate( nationalId: string, requestId?: string, - ): Promise> { + ): Promise> { let data try { data = await Promise.all([ @@ -129,7 +127,7 @@ export class DrivingLicenseUpdateClient extends BaseLicenseUpdateClient { ? { imageBase64String: image.substring(image.indexOf(',') + 1).trim(), } - : null + : undefined const payload: PassDataInput = { inputFieldValues: inputValues, @@ -144,7 +142,7 @@ export class DrivingLicenseUpdateClient extends BaseLicenseUpdateClient { revoke( nationalId: string, requestId?: string, - ): Promise> { + ): Promise> { const passTemplateId = this.config.passTemplateId const payload: PassDataInput = { inputFieldValues: [mapNationalId(nationalId)], diff --git a/libs/clients/license-client/src/lib/clients/firearm-license-client/firearmLicenseMapper.ts b/libs/clients/license-client/src/lib/clients/firearm-license-client/firearmLicenseMapper.ts index bea0243f1cae..4069c576a2df 100644 --- a/libs/clients/license-client/src/lib/clients/firearm-license-client/firearmLicenseMapper.ts +++ b/libs/clients/license-client/src/lib/clients/firearm-license-client/firearmLicenseMapper.ts @@ -3,7 +3,6 @@ import { FirearmPropertyList, LicenseInfo, } from '@island.is/clients/firearm-license' -import { PassInputFieldValueDataInput } from '@island.is/clients/smartsolutions' import format from 'date-fns/format' import { format as formatSsn } from 'kennitala' @@ -27,9 +26,7 @@ const parsePropertyForPkpassInput = (properties?: Array) => { export const nationalIdIndex = 'kt' -export const mapNationalId = ( - nationalId: string, -): PassInputFieldValueDataInput => { +export const mapNationalId = (nationalId: string) => { return { identifier: nationalIdIndex, value: nationalId ? formatSsn(nationalId) : '', diff --git a/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseClient.service.ts b/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseClient.service.ts index c0ed478a08c3..8a0f3e2056da 100644 --- a/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseClient.service.ts +++ b/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseClient.service.ts @@ -3,22 +3,20 @@ import { LOGGER_PROVIDER } from '@island.is/logging' import { User } from '@island.is/auth-nest-tools' import { Inject, Injectable } from '@nestjs/common' import { FirearmApi } from '@island.is/clients/firearm-license' -import { - Pass, - PassDataInput, - Result, - SmartSolutionsApi, -} from '@island.is/clients/smartsolutions' import compareAsc from 'date-fns/compareAsc' import { LicenseClient, LicensePkPassAvailability, LicenseType, + PassData, + PassDataInput, PkPassVerificationInputData, + Result, VerifyPkPassResult, } from '../../../licenseClient.type' import { FirearmLicenseDto } from '../firearmLicenseClient.type' import { createPkPassDataInput } from '../firearmLicenseMapper' +import { SmartSolutionsApi } from '@island.is/clients/smartsolutions' /** Category to attach each log message to */ const LOG_CATEGORY = 'firearmlicense-service' @@ -180,12 +178,12 @@ export class FirearmLicenseClient ? { imageBase64String: parsedImage ?? '', } - : null, + : undefined, } return payload } - async getPkPass(user: User): Promise> { + async getPkPass(user: User): Promise> { const license = await this.fetchLicenseData(user) if (!license.ok || !license.data) { diff --git a/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClient.service.ts b/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClient.service.ts index 2e767da1ee6f..d2ce62709c15 100644 --- a/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClient.service.ts +++ b/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClient.service.ts @@ -4,12 +4,9 @@ import { Inject, Injectable } from '@nestjs/common' import { OpenFirearmApi } from '@island.is/clients/firearm-license' import { sanitize as sanitizeNationalId } from 'kennitala' import { - Pass, + PassData, PassDataInput, - RevokePassData, - SmartSolutionsApi, -} from '@island.is/clients/smartsolutions' -import { + PassRevocationData, PassVerificationData, Result, VerifyInputData, @@ -19,6 +16,7 @@ import { BaseLicenseUpdateClient } from '../../baseLicenseUpdateClient' import { mapNationalId } from '../firearmLicenseMapper' import type { ConfigType } from '@island.is/nest/config' import { FirearmDigitalLicenseClientConfig } from '../firearmLicenseClient.config' +import { SmartSolutionsApi } from '@island.is/clients/smartsolutions' /** Category to attach each log message to */ const LOG_CATEGORY = 'firearmlicense-service' @@ -32,14 +30,14 @@ export class FirearmLicenseUpdateClient extends BaseLicenseUpdateClient { private openFirearmApi: OpenFirearmApi, protected smartApi: SmartSolutionsApi, ) { - super(logger, smartApi) + super() } - pushUpdate( + async pushUpdate( inputData: PassDataInput, nationalId: string, requestId?: string, - ): Promise> { + ): Promise> { const inputFieldValues = inputData.inputFieldValues ?? [] //small check that nationalId doesnt' already exist if ( @@ -62,7 +60,7 @@ export class FirearmLicenseUpdateClient extends BaseLicenseUpdateClient { async pullUpdate( nationalId: string, requestId?: string, - ): Promise> { + ): Promise> { let data try { data = await Promise.all([ @@ -135,7 +133,7 @@ export class FirearmLicenseUpdateClient extends BaseLicenseUpdateClient { .substring(thumbnail.indexOf(',') + 1) .trim(), } - : null, + : undefined, } return this.smartApi.updatePkPass(payload, requestId) @@ -144,7 +142,7 @@ export class FirearmLicenseUpdateClient extends BaseLicenseUpdateClient { revoke( nationalId: string, requestId?: string, - ): Promise> { + ): Promise> { const passTemplateId = this.config.passTemplateId const payload: PassDataInput = { inputFieldValues: [mapNationalId(nationalId)], diff --git a/libs/clients/license-client/src/lib/licenseClient.type.ts b/libs/clients/license-client/src/lib/licenseClient.type.ts index a3509157fc17..938d511ca765 100644 --- a/libs/clients/license-client/src/lib/licenseClient.type.ts +++ b/libs/clients/license-client/src/lib/licenseClient.type.ts @@ -130,6 +130,46 @@ export type PassVerificationData = { } } +export type PassData = { + distributionUrl: string + deliveryPageUrl: string + distributionQRCode: string + id: string + expirationDate?: Date + whenCreated?: Date + whenModified?: Date +} + +export type PassRevocationData = { + success: boolean +} + +export type PassDataInput = { + expirationDate?: string + expirationDateWithoutTime?: string + expirationTime?: string + passTemplateId?: string + id?: string + inputFieldValues?: Array<{ + id?: string + identifier?: string + passInputFieldId?: string + value?: string + }> + thumbnail?: { + description?: string + filename?: string + height?: number + id?: string + imageBase64String?: string + originalUrl?: string + title?: string + url?: string + width?: number + } + validFrom?: string +} + export type Result = | { ok: true From 4e9b574c4be449d3b6a0b7655314ebfa44a63191 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Mon, 7 Oct 2024 10:00:02 +0000 Subject: [PATCH 03/29] fix: wip --- .../app/modules/license/license.service.ts | 72 ++++++++++++------- .../src/app/modules/license/license.types.ts | 15 ++-- libs/clients/license-client/src/index.ts | 3 + .../disabilityLicenseUpdateClient.service.ts | 2 +- .../modules/smartSolutionsFirearm.module.ts | 10 ++- .../huntingLicenseClient.config.ts | 1 + ...smartSolutionsAdapter.module-definition.ts | 5 ++ .../smartSolutionsAdapter.module.ts | 36 ++++++++++ .../smartSolutionsAdapter.service.ts | 19 +++++ .../smartSolutionsAdapter.types.ts | 7 ++ .../src/lib/factories/clientConfigFactory.ts | 7 +- .../src/lib/factories/config.types.ts | 15 ++++ libs/clients/smart-solutions-v2/src/index.ts | 1 + .../src/lib/types/result.type.ts | 1 + 14 files changed, 152 insertions(+), 42 deletions(-) create mode 100644 libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.module-definition.ts create mode 100644 libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.module.ts create mode 100644 libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.service.ts create mode 100644 libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.types.ts create mode 100644 libs/clients/license-client/src/lib/factories/config.types.ts diff --git a/apps/services/license-api/src/app/modules/license/license.service.ts b/apps/services/license-api/src/app/modules/license/license.service.ts index db3a10cc8619..644f20fdde24 100644 --- a/apps/services/license-api/src/app/modules/license/license.service.ts +++ b/apps/services/license-api/src/app/modules/license/license.service.ts @@ -2,10 +2,10 @@ import { BaseLicenseUpdateClient, LicenseType, LicenseUpdateClientService, + PassData, + PassDataInput, } from '@island.is/clients/license-client' -import { Pass, PassDataInput, Result } from '@island.is/clients/smartsolutions' -import type { Logger } from '@island.is/logging' -import { LOGGER_PROVIDER } from '@island.is/logging' +import { LOGGER_PROVIDER, type Logger } from '@island.is/logging' import { BarcodeService, TOKEN_EXPIRED_ERROR, @@ -139,7 +139,7 @@ export class LicenseService { nationalId: string, payload?: string, requestId?: string, - ): Promise> { + ): Promise { let updatePayload: PassDataInput = { expirationDate, } @@ -171,14 +171,30 @@ export class LicenseService { requestId, }) - return await service.pushUpdate(updatePayload, nationalId, requestId) + const res = await service.pushUpdate(updatePayload, nationalId, requestId) + + if (res.ok) { + return res.data + } + + this.logger.error('License update failed', { + updateType: 'push', + category: LOG_CATEGORY, + requestId, + error: res.error, + }) + + throw this.getException( + this.getErrorTypeByCode(res.error.code), + res.error.message, + ) } private async pullUpdateLicense( service: BaseLicenseUpdateClient, nationalId: string, requestId?: string, - ): Promise> { + ): Promise { /** PULL - Update electronic license with pulled data from service * 1. Fetch data from provider * 2. Parse and validate license data @@ -191,7 +207,23 @@ export class LicenseService { requestId, }) - return await service.pullUpdate(nationalId, requestId) + const res = await service.pullUpdate(nationalId, requestId) + + if (res.ok) { + return res.data + } + + this.logger.error('License update failed', { + updateType: 'pull', + category: LOG_CATEGORY, + requestId, + error: res.error, + }) + + throw this.getException( + this.getErrorTypeByCode(res.error.code), + res.error.message, + ) } async updateLicense( @@ -209,7 +241,7 @@ export class LicenseService { updateType: inputData.licenseUpdateType, }) - let updateRes: Result + let updateRes: PassData | undefined if (inputData.licenseUpdateType === 'push') { const { expiryDate, payload } = inputData @@ -236,28 +268,16 @@ export class LicenseService { updateRes = await this.pullUpdateLicense(service, nationalId, requestId) } - if (updateRes.ok) { - this.logger.info('License update successful', { - category: LOG_CATEGORY, - requestId, - updateType: inputData.licenseUpdateType, - }) - return { - updateSuccess: true, - data: updateRes.data, - } - } - - this.logger.error('License update failed', { + this.logger.info('License update successful', { category: LOG_CATEGORY, requestId, - error: updateRes.error, + updateType: inputData.licenseUpdateType, }) - throw this.getException( - this.getErrorTypeByCode(updateRes.error.code), - updateRes.error.message, - ) + return { + updateSuccess: true, + data: updateRes, + } } async revokeLicense( diff --git a/apps/services/license-api/src/app/modules/license/license.types.ts b/apps/services/license-api/src/app/modules/license/license.types.ts index c4cec1d4e62f..7a51712ffc82 100644 --- a/apps/services/license-api/src/app/modules/license/license.types.ts +++ b/apps/services/license-api/src/app/modules/license/license.types.ts @@ -1,9 +1,8 @@ import { - Pass, + PassData, PassDataInput, - Result, - RevokePassData, -} from '@island.is/clients/smartsolutions' + PassRevocationData, +} from '@island.is/clients/license-client' export enum LicenseUpdateType { PUSH = 'push', @@ -42,10 +41,10 @@ export interface GenericLicenseClient { pushUpdate: ( inputData: PassDataInput, nationalId: string, - ) => Promise> - pullUpdate: (nationalId: string) => Promise> - revoke: (nationalId: string) => Promise> - verify: (inputData: string) => Promise> + ) => Promise + pullUpdate: (nationalId: string) => Promise + revoke: (nationalId: string) => Promise + verify: (inputData: string) => Promise } export const CLIENT_FACTORY = 'client-factory' diff --git a/libs/clients/license-client/src/index.ts b/libs/clients/license-client/src/index.ts index a77fcd8dbe7a..3bfd7111fb62 100644 --- a/libs/clients/license-client/src/index.ts +++ b/libs/clients/license-client/src/index.ts @@ -8,6 +8,9 @@ export { LicenseClient, LicenseVerifyExtraDataResult, VerifyExtraDataResult, + PassData, + PassDataInput, + PassRevocationData, } from './lib/licenseClient.type' export { EhicCardResponse } from './lib/clients/ehic-card-client' export * from './lib/clients/adr-license-client' diff --git a/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClient.service.ts b/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClient.service.ts index 812e35882ad3..825ce26ff1d8 100644 --- a/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClient.service.ts +++ b/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClient.service.ts @@ -20,7 +20,7 @@ export class DisabilityLicenseUpdateClient extends BaseLicenseUpdateClient { @Inject(LOGGER_PROVIDER) protected logger: Logger, protected smartApi: SmartSolutionsApi, ) { - super(logger, smartApi) + super() } pushUpdate( diff --git a/libs/clients/license-client/src/lib/clients/firearm-license-client/modules/smartSolutionsFirearm.module.ts b/libs/clients/license-client/src/lib/clients/firearm-license-client/modules/smartSolutionsFirearm.module.ts index d324d3c3b63c..7f3cc969a0cc 100644 --- a/libs/clients/license-client/src/lib/clients/firearm-license-client/modules/smartSolutionsFirearm.module.ts +++ b/libs/clients/license-client/src/lib/clients/firearm-license-client/modules/smartSolutionsFirearm.module.ts @@ -4,18 +4,16 @@ import { } from '@island.is/clients/smartsolutions' import { FirearmDigitalLicenseClientConfig } from '../firearmLicenseClient.config' import { ConfigType } from '@nestjs/config' +import { SmartSolutionsAdapterModule } from '../../smart-solutions-adapter/smartSolutionsAdapter.module' export const SmartSolutionsFirearmModule = - SmartSolutionsApiClientModule.registerAsync({ + SmartSolutionsAdapterModule.registerAsync({ useFactory: ( config: ConfigType, ) => { - const smartConfig: SmartSolutionsConfig = { - apiKey: config.apiKey, - apiUrl: config.apiUrl, - passTemplateId: config.passTemplateId, + return { + config, } - return smartConfig }, inject: [FirearmDigitalLicenseClientConfig.KEY], }) diff --git a/libs/clients/license-client/src/lib/clients/hunting-license-client/huntingLicenseClient.config.ts b/libs/clients/license-client/src/lib/clients/hunting-license-client/huntingLicenseClient.config.ts index 1c46437a1371..3632ce1d02bd 100644 --- a/libs/clients/license-client/src/lib/clients/hunting-license-client/huntingLicenseClient.config.ts +++ b/libs/clients/license-client/src/lib/clients/hunting-license-client/huntingLicenseClient.config.ts @@ -6,6 +6,7 @@ export const schema = z.object({ apiUrl: z.string(), passTemplateId: z.string(), }) + export const HuntingDigitalLicenseClientConfig = defineConfig< z.infer >({ diff --git a/libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.module-definition.ts b/libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.module-definition.ts new file mode 100644 index 000000000000..59c45f8ee6c3 --- /dev/null +++ b/libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.module-definition.ts @@ -0,0 +1,5 @@ +import { ConfigurableModuleBuilder } from '@nestjs/common' +import { SmartSolutionsAdapterModuleOptions } from './smartSolutionsAdapter.types' + +export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } = + new ConfigurableModuleBuilder().build() diff --git a/libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.module.ts b/libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.module.ts new file mode 100644 index 000000000000..12224f7b1ead --- /dev/null +++ b/libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.module.ts @@ -0,0 +1,36 @@ +import { + SmartSolutionsApiClientModule, + SmartSolutionsConfig as SmartOldConfig, +} from '@island.is/clients/smartsolutions' +import { + SmartSolutionsModule, + SmartSolutionsConfig as SmartNewConfig, +} from '@island.is/clients/smart-solutions-v2' +import { ConfigType } from '@nestjs/config' +import { ClientConfigType } from '../../factories/config.types' +import { + ConfigurableModuleClass, + MODULE_OPTIONS_TOKEN, +} from './smartSolutionsAdapter.module-definition' +import { SmartSolutionsAdapterModuleOptions } from './smartSolutionsAdapter.types' +import { Module } from '@nestjs/common' +import { SmartSolutionsAdapterService } from './smartSolutionsAdapter.service' + +@Module({ + imports: [ + SmartSolutionsModule.registerAsync({ + useFactory: (options: SmartSolutionsAdapterModuleOptions) => { + return { config: options.config } + }, + inject: [MODULE_OPTIONS_TOKEN], + }), + SmartSolutionsApiClientModule.registerAsync({ + useFactory: (options: SmartSolutionsAdapterModuleOptions) => { + return options.config + }, + inject: [MODULE_OPTIONS_TOKEN], + }), + ], + providers: [SmartSolutionsAdapterService], +}) +export class SmartSolutionsAdapterModule extends ConfigurableModuleClass {} diff --git a/libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.service.ts b/libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.service.ts new file mode 100644 index 000000000000..fd06d43d0291 --- /dev/null +++ b/libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.service.ts @@ -0,0 +1,19 @@ +import { LOGGER_PROVIDER, type Logger } from "@island.is/logging"; +import { MODULE_OPTIONS_TOKEN } from "./smartSolutionsAdapter.module-definition"; +import { SmartSolutionsAdapterModuleOptions } from "./smartSolutionsAdapter.types"; +import { Inject } from "@nestjs/common"; +import { SmartSolutionsApi, } from "@island.is/clients/smartsolutions"; +import { SmartSolutionsService } from "@island.is/clients/smart-solutions-v2"; + +export class SmartSolutionsAdapterService { + constructor( + @Inject(LOGGER_PROVIDER) + private readonly logger: Logger, + @Inject(MODULE_OPTIONS_TOKEN) + private readonly options: SmartSolutionsAdapterModuleOptions, + private readonly newSmartService: SmartSolutionsService, + /** DEPRECATED */ + private readonly oldSmartService: SmartSolutionsApi, + ) { + + } diff --git a/libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.types.ts b/libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.types.ts new file mode 100644 index 000000000000..e1b9cc26e34c --- /dev/null +++ b/libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.types.ts @@ -0,0 +1,7 @@ +import { ClientConfigType } from '../../factories/config.types' + +export const SMART_SOLUTIONS_ADAPTER = 'smart-solutions-adapter' + +export interface SmartSolutionsAdapterModuleOptions { + config: ClientConfigType +} diff --git a/libs/clients/license-client/src/lib/factories/clientConfigFactory.ts b/libs/clients/license-client/src/lib/factories/clientConfigFactory.ts index 8e4a8478525b..6c5a3e0fb469 100644 --- a/libs/clients/license-client/src/lib/factories/clientConfigFactory.ts +++ b/libs/clients/license-client/src/lib/factories/clientConfigFactory.ts @@ -1,7 +1,12 @@ import { defineConfig } from '@island.is/nest/config' -import { SmartSolutionsApiConfigSchema as schema } from '@island.is/clients/smartsolutions' import * as z from 'zod' +const schema = z.object({ + apiKey: z.string(), + apiUrl: z.string(), + passTemplateId: z.string(), +}) + export const clientConfigFactory = (licenseId: string, organisation: string) => defineConfig>({ name: `${licenseId}DigitalLicenseClientConfig`, diff --git a/libs/clients/license-client/src/lib/factories/config.types.ts b/libs/clients/license-client/src/lib/factories/config.types.ts new file mode 100644 index 000000000000..afd80721ac6e --- /dev/null +++ b/libs/clients/license-client/src/lib/factories/config.types.ts @@ -0,0 +1,15 @@ +import { ConfigType } from '@nestjs/config' +import { AdrDigitalLicenseClientConfig } from '../clients/adr-license-client' +import { DisabilityDigitalLicenseClientConfig } from '../clients/disability-license-client' +import { DrivingDigitalLicenseClientConfig } from '../clients/driving-license-client' +import { FirearmDigitalLicenseClientConfig } from '../clients/firearm-license-client' +import { HuntingDigitalLicenseClientConfig } from '../clients/hunting-license-client' +import { MachineDigitalLicenseClientConfig } from '../clients/machine-license-client' + +export type ClientConfigType = + | ConfigType + | ConfigType + | ConfigType + | ConfigType + | ConfigType + | ConfigType diff --git a/libs/clients/smart-solutions-v2/src/index.ts b/libs/clients/smart-solutions-v2/src/index.ts index 7a95c276a65a..eee4a1511202 100644 --- a/libs/clients/smart-solutions-v2/src/index.ts +++ b/libs/clients/smart-solutions-v2/src/index.ts @@ -1,5 +1,6 @@ export { SmartSolutionsModule } from './lib/smartSolutions.module' export { SmartSolutionsService } from './lib/smartSolutions.service' +export { SmartSolutionsConfig } from './lib/smartSolutions.config' export { PkPass, RevokePassData } from './lib/types/responses.type' export { Result } from './lib/types/result.type' export * from '../gen/schema' diff --git a/libs/clients/smart-solutions-v2/src/lib/types/result.type.ts b/libs/clients/smart-solutions-v2/src/lib/types/result.type.ts index 62336a2e73b0..49a8d073847c 100644 --- a/libs/clients/smart-solutions-v2/src/lib/types/result.type.ts +++ b/libs/clients/smart-solutions-v2/src/lib/types/result.type.ts @@ -6,6 +6,7 @@ export interface ServiceError { /** Optional data */ data?: string } + /** VERIFY ACTION CODES 1-10 * * SERVICE CODES 10+ * * HTTP CODES 100+ */ From 4e5a42859429f48ec48c37f0f05857ac122d5dc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Tue, 8 Oct 2024 10:34:06 +0000 Subject: [PATCH 04/29] fix: typing --- .../clients/base/baseLicenseUpdateClient.ts | 38 ++++++ .../licenseUpdateClientV2.ts} | 4 +- .../clients/pk-pass-client/PkPassService.ts | 0 .../clients/pk-pass-client/pkPass.mapper.ts | 17 +++ .../pkPass.module-definition.ts | 5 + .../clients/pk-pass-client/pkPass.module.ts | 30 +++++ .../clients/pk-pass-client/pkPass.service.ts | 117 ++++++++++++++++++ .../clients/pk-pass-client/pkPass.types.ts | 16 +++ ...smartSolutionsAdapter.module-definition.ts | 5 - .../smartSolutionsAdapter.module.ts | 36 ------ .../smartSolutionsAdapter.service.ts | 19 --- .../smartSolutionsAdapter.types.ts | 7 -- .../src/lib/licenseClient.type.ts | 9 +- .../src/lib/smartSolutions.service.ts | 10 +- .../src/lib/types/responses.type.ts | 14 +-- 15 files changed, 244 insertions(+), 83 deletions(-) create mode 100644 libs/clients/license-client/src/lib/clients/base/baseLicenseUpdateClient.ts rename libs/clients/license-client/src/lib/clients/{baseLicenseUpdateClient.ts => base/licenseUpdateClientV2.ts} (88%) create mode 100644 libs/clients/license-client/src/lib/clients/pk-pass-client/PkPassService.ts create mode 100644 libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.mapper.ts create mode 100644 libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.module-definition.ts create mode 100644 libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.module.ts create mode 100644 libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.service.ts create mode 100644 libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.types.ts delete mode 100644 libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.module-definition.ts delete mode 100644 libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.module.ts delete mode 100644 libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.service.ts delete mode 100644 libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.types.ts diff --git a/libs/clients/license-client/src/lib/clients/base/baseLicenseUpdateClient.ts b/libs/clients/license-client/src/lib/clients/base/baseLicenseUpdateClient.ts new file mode 100644 index 000000000000..186768ceaa6c --- /dev/null +++ b/libs/clients/license-client/src/lib/clients/base/baseLicenseUpdateClient.ts @@ -0,0 +1,38 @@ +import type { Logger } from '@island.is/logging' +import { Injectable } from '@nestjs/common' +import { + Pass, + PassDataInput, + RevokePassData, + SmartSolutionsApi, +} from '@island.is/clients/smartsolutions' +import { PassVerificationData, Result } from '../licenseClient.type' + +@Injectable() +export abstract class BaseLicenseUpdateClient { + constructor( + protected logger: Logger, + protected smartApi: SmartSolutionsApi, + ) {} + + abstract pushUpdate( + inputData: PassDataInput, + nationalId: string, + requestId?: string, + ): Promise> + + abstract pullUpdate( + nationalId: string, + requestId?: string, + ): Promise> + + abstract revoke( + nationalId: string, + requestId?: string, + ): Promise> + + abstract verify( + inputData: string, + requestId?: string, + ): Promise> +} diff --git a/libs/clients/license-client/src/lib/clients/baseLicenseUpdateClient.ts b/libs/clients/license-client/src/lib/clients/base/licenseUpdateClientV2.ts similarity index 88% rename from libs/clients/license-client/src/lib/clients/baseLicenseUpdateClient.ts rename to libs/clients/license-client/src/lib/clients/base/licenseUpdateClientV2.ts index 8a043b59578f..9fe4087e716d 100644 --- a/libs/clients/license-client/src/lib/clients/baseLicenseUpdateClient.ts +++ b/libs/clients/license-client/src/lib/clients/base/licenseUpdateClientV2.ts @@ -5,10 +5,10 @@ import { PassRevocationData, PassVerificationData, Result, -} from '../licenseClient.type' +} from '../../licenseClient.type' @Injectable() -export abstract class BaseLicenseUpdateClient { +export abstract class BaseLicenseUpdateClientV2 { abstract pushUpdate( inputData: PassDataInput, nationalId: string, diff --git a/libs/clients/license-client/src/lib/clients/pk-pass-client/PkPassService.ts b/libs/clients/license-client/src/lib/clients/pk-pass-client/PkPassService.ts new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.mapper.ts b/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.mapper.ts new file mode 100644 index 000000000000..7b6ba8da4c0c --- /dev/null +++ b/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.mapper.ts @@ -0,0 +1,17 @@ +import { Pass as PassV1 } from '@island.is/clients/smartsolutions' +import { Pass as PassV2 } from '@island.is/clients/smart-solutions-v2' +import { PassData } from '../../licenseClient.type' + +export const mapPassData = (pass: PassV1 | PassV2): PassData => ({ + ...pass, + inputFieldValues: pass?.inputFieldValues.map((i) => ({ + id: i.id, + identifier: i.passInputField.identifier, + value: i.value ?? undefined, + })), + expirationDate: pass?.expirationDate + ? new Date(pass?.expirationDate) + : undefined, + whenCreated: new Date(pass.whenCreated), + whenModified: new Date(pass.whenModified), +}) diff --git a/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.module-definition.ts b/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.module-definition.ts new file mode 100644 index 000000000000..0c49e3882721 --- /dev/null +++ b/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.module-definition.ts @@ -0,0 +1,5 @@ +import { ConfigurableModuleBuilder } from '@nestjs/common' +import { PkPassModuleOptions } from './pkPass.types' + +export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } = + new ConfigurableModuleBuilder().build() diff --git a/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.module.ts b/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.module.ts new file mode 100644 index 000000000000..784221ffcc5e --- /dev/null +++ b/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.module.ts @@ -0,0 +1,30 @@ +import { SmartSolutionsApiClientModule } from '@island.is/clients/smartsolutions' +import { SmartSolutionsModule } from '@island.is/clients/smart-solutions-v2' +import { + ConfigurableModuleClass, + MODULE_OPTIONS_TOKEN, +} from './pkPass.module-definition' +import { PkPassModuleOptions } from './pkPass.types' +import { Module } from '@nestjs/common' +import { PkPassService } from './pkPass.service' +import { FeatureFlagModule } from '@island.is/nest/feature-flags' + +@Module({ + imports: [ + FeatureFlagModule, + SmartSolutionsModule.registerAsync({ + useFactory: (options: PkPassModuleOptions) => { + return { config: options.config } + }, + inject: [MODULE_OPTIONS_TOKEN], + }), + SmartSolutionsApiClientModule.registerAsync({ + useFactory: (options: PkPassModuleOptions) => { + return options.config + }, + inject: [MODULE_OPTIONS_TOKEN], + }), + ], + providers: [PkPassService], +}) +export class PkPassModule extends ConfigurableModuleClass {} diff --git a/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.service.ts b/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.service.ts new file mode 100644 index 000000000000..05145ac88773 --- /dev/null +++ b/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.service.ts @@ -0,0 +1,117 @@ +import { LOGGER_PROVIDER, type Logger } from '@island.is/logging' +import { MODULE_OPTIONS_TOKEN } from './pkPass.module-definition' +import { + PkPassModuleOptions, + VerifyPassData, + VerifyPkPassDataInput, +} from './pkPass.types' +import { Inject } from '@nestjs/common' +import { SmartSolutionsApi } from '@island.is/clients/smartsolutions' +import { SmartSolutionsService } from '@island.is/clients/smart-solutions-v2' +import { FeatureFlagService, Features } from '@island.is/nest/feature-flags' +import { + PassData, + PassDataInput, + PassRevocationData, + Result, +} from '../../licenseClient.type' +import { mapPassData } from './pkPass.mapper' + +export class PkPassService { + constructor( + @Inject(LOGGER_PROVIDER) + private readonly logger: Logger, + private readonly featureFlagService: FeatureFlagService, + @Inject(MODULE_OPTIONS_TOKEN) + private readonly options: PkPassModuleOptions, + private readonly newSmartService: SmartSolutionsService, + /** DEPRECATED */ + private readonly oldSmartService: SmartSolutionsApi, + ) {} + + async getService(): Promise { + const v2Enabled = await this.featureFlagService.getValue( + Features.licensesV2, + false, + ) + + return v2Enabled ? this.newSmartService : this.oldSmartService + } + + async verifyPkPass( + payload: VerifyPkPassDataInput, + requestId?: string, + ): Promise> { + const service = await this.getService() + + const pass = await service.verifyPkPass(payload, requestId) + + if (!pass.ok) { + return pass + } + + return { + ok: true, + data: { + valid: pass.data.valid, + pass: pass.data.pass ? mapPassData(pass.data.pass) : undefined, + }, + } + } + + async updatePkPass( + payload: PassDataInput, + requestId?: string, + ): Promise> { + const service = await this.getService() + const pass = await service.updatePkPass(payload, requestId) + if (!pass.ok) { + return pass + } + + return { + ok: true, + data: mapPassData(pass.data), + } + } + + async generatePkPass( + payload: PassDataInput, + onCreateCallback?: () => Promise, + requestId?: string, + ): Promise> { + const service = await this.getService() + const pass = await service.generatePkPass( + payload, + onCreateCallback, + requestId, + ) + + if (!pass.ok) { + return pass + } + + return { + ok: true, + data: mapPassData(pass.data), + } + } + + async revokePkPass( + passTemplateId: string, + payload: PassDataInput, + requestId?: string, + ): Promise> { + const service = await this.getService() + const pass = await service.revokePkPass(passTemplateId, payload, requestId) + if (!pass.ok) { + return pass + } + return { + ok: true, + data: { + success: pass.data.success, + }, + } + } +} diff --git a/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.types.ts b/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.types.ts new file mode 100644 index 000000000000..14c992968679 --- /dev/null +++ b/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.types.ts @@ -0,0 +1,16 @@ +import { ClientConfigType } from '../../factories/config.types' +import { PassData } from '../../licenseClient.type' + +export interface PkPassModuleOptions { + config: ClientConfigType +} + +export interface VerifyPkPassDataInput { + code: string + date: string +} + +export interface VerifyPassData { + valid: boolean + pass?: PassData +} diff --git a/libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.module-definition.ts b/libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.module-definition.ts deleted file mode 100644 index 59c45f8ee6c3..000000000000 --- a/libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.module-definition.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ConfigurableModuleBuilder } from '@nestjs/common' -import { SmartSolutionsAdapterModuleOptions } from './smartSolutionsAdapter.types' - -export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } = - new ConfigurableModuleBuilder().build() diff --git a/libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.module.ts b/libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.module.ts deleted file mode 100644 index 12224f7b1ead..000000000000 --- a/libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.module.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { - SmartSolutionsApiClientModule, - SmartSolutionsConfig as SmartOldConfig, -} from '@island.is/clients/smartsolutions' -import { - SmartSolutionsModule, - SmartSolutionsConfig as SmartNewConfig, -} from '@island.is/clients/smart-solutions-v2' -import { ConfigType } from '@nestjs/config' -import { ClientConfigType } from '../../factories/config.types' -import { - ConfigurableModuleClass, - MODULE_OPTIONS_TOKEN, -} from './smartSolutionsAdapter.module-definition' -import { SmartSolutionsAdapterModuleOptions } from './smartSolutionsAdapter.types' -import { Module } from '@nestjs/common' -import { SmartSolutionsAdapterService } from './smartSolutionsAdapter.service' - -@Module({ - imports: [ - SmartSolutionsModule.registerAsync({ - useFactory: (options: SmartSolutionsAdapterModuleOptions) => { - return { config: options.config } - }, - inject: [MODULE_OPTIONS_TOKEN], - }), - SmartSolutionsApiClientModule.registerAsync({ - useFactory: (options: SmartSolutionsAdapterModuleOptions) => { - return options.config - }, - inject: [MODULE_OPTIONS_TOKEN], - }), - ], - providers: [SmartSolutionsAdapterService], -}) -export class SmartSolutionsAdapterModule extends ConfigurableModuleClass {} diff --git a/libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.service.ts b/libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.service.ts deleted file mode 100644 index fd06d43d0291..000000000000 --- a/libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.service.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { LOGGER_PROVIDER, type Logger } from "@island.is/logging"; -import { MODULE_OPTIONS_TOKEN } from "./smartSolutionsAdapter.module-definition"; -import { SmartSolutionsAdapterModuleOptions } from "./smartSolutionsAdapter.types"; -import { Inject } from "@nestjs/common"; -import { SmartSolutionsApi, } from "@island.is/clients/smartsolutions"; -import { SmartSolutionsService } from "@island.is/clients/smart-solutions-v2"; - -export class SmartSolutionsAdapterService { - constructor( - @Inject(LOGGER_PROVIDER) - private readonly logger: Logger, - @Inject(MODULE_OPTIONS_TOKEN) - private readonly options: SmartSolutionsAdapterModuleOptions, - private readonly newSmartService: SmartSolutionsService, - /** DEPRECATED */ - private readonly oldSmartService: SmartSolutionsApi, - ) { - - } diff --git a/libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.types.ts b/libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.types.ts deleted file mode 100644 index e1b9cc26e34c..000000000000 --- a/libs/clients/license-client/src/lib/clients/smart-solutions-adapter/smartSolutionsAdapter.types.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { ClientConfigType } from '../../factories/config.types' - -export const SMART_SOLUTIONS_ADAPTER = 'smart-solutions-adapter' - -export interface SmartSolutionsAdapterModuleOptions { - config: ClientConfigType -} diff --git a/libs/clients/license-client/src/lib/licenseClient.type.ts b/libs/clients/license-client/src/lib/licenseClient.type.ts index 938d511ca765..863ef764aee2 100644 --- a/libs/clients/license-client/src/lib/licenseClient.type.ts +++ b/libs/clients/license-client/src/lib/licenseClient.type.ts @@ -136,8 +136,13 @@ export type PassData = { distributionQRCode: string id: string expirationDate?: Date - whenCreated?: Date - whenModified?: Date + whenCreated: Date + whenModified: Date + inputFieldValues?: Array<{ + id: string + identifier: string + value?: string + }> } export type PassRevocationData = { diff --git a/libs/clients/smart-solutions-v2/src/lib/smartSolutions.service.ts b/libs/clients/smart-solutions-v2/src/lib/smartSolutions.service.ts index ae2894f58569..c3dbe0e28479 100644 --- a/libs/clients/smart-solutions-v2/src/lib/smartSolutions.service.ts +++ b/libs/clients/smart-solutions-v2/src/lib/smartSolutions.service.ts @@ -4,6 +4,7 @@ import { DeletePass, DeletePassMutationVariables, DynamicBarcodeDataInput, + Pass, PassDataInput, PassTemplate, PassTemplates, @@ -18,7 +19,6 @@ import { MODULE_OPTIONS_TOKEN } from './smartSolutions.module-definition' import { DeletePassResponseData, ListTemplatesResponseData, - PkPass, RevokePassData, UpdatePassResponseData, UpsertPassResponseData, @@ -88,7 +88,7 @@ export class SmartSolutionsService { async updatePkPass( payload: PassDataInput, requestId?: string, - ): Promise> { + ): Promise> { if (!payload.passTemplateId) { this.logger.warning( 'Pkpass update failed, missing pass template id from input', @@ -153,7 +153,7 @@ export class SmartSolutionsService { payload: PassDataInput, onCreateCallback?: () => Promise, requestId?: string, - ): Promise> { + ): Promise> { const variables: UpsertPassMutationVariables = { inputData: { ...payload, @@ -246,7 +246,9 @@ export class SmartSolutionsService { } } - async listTemplates(): Promise>> { + async listTemplates( + requestId?: string, + ): Promise>> { const res = await this.fetcher.fetch( PassTemplates, ) diff --git a/libs/clients/smart-solutions-v2/src/lib/types/responses.type.ts b/libs/clients/smart-solutions-v2/src/lib/types/responses.type.ts index 5a74ce202b84..fe67b64b350a 100644 --- a/libs/clients/smart-solutions-v2/src/lib/types/responses.type.ts +++ b/libs/clients/smart-solutions-v2/src/lib/types/responses.type.ts @@ -1,10 +1,8 @@ import { Pass, PassTemplate } from '../..' -export type PkPass = Partial - export interface VerifyPassData { valid: boolean - pass?: PkPass + pass?: Pass } export interface RevokePassData { @@ -12,19 +10,19 @@ export interface RevokePassData { } export interface GetPassResponseData { - pass: PkPass + pass: Pass } export interface VerifyPassResponseData { - updateStatusOnPassWithDynamicBarcode?: PkPass + updateStatusOnPassWithDynamicBarcode?: Pass } export interface UpsertPassResponseData { - upsertPass: PkPass + upsertPass: Pass } export interface UpdatePassResponseData { - updatePass: PkPass + updatePass: Pass } export interface ListTemplatesResponseData { @@ -46,6 +44,6 @@ export interface DeletePassResponseData { export interface ListPassesResponseData { passes?: { - data: Array + data: Array } } From 2e1b2dfcc56b57fe1c658faab3533df749c5f400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Tue, 8 Oct 2024 10:35:15 +0000 Subject: [PATCH 05/29] fix: disability client --- .../services/disabilityLicenseUpdateClient.service.ts | 4 ++-- .../services/firearmLicenseUpdateClient.service.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClient.service.ts b/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClient.service.ts index 825ce26ff1d8..578d80566fc0 100644 --- a/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClient.service.ts +++ b/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClient.service.ts @@ -12,7 +12,7 @@ import { Result, VerifyInputData, } from '../../../licenseClient.type' -import { BaseLicenseUpdateClient } from '../../baseLicenseUpdateClient' +import { BaseLicenseUpdateClient } from '../../base/baseLicenseUpdateClient' @Injectable() export class DisabilityLicenseUpdateClient extends BaseLicenseUpdateClient { @@ -20,7 +20,7 @@ export class DisabilityLicenseUpdateClient extends BaseLicenseUpdateClient { @Inject(LOGGER_PROVIDER) protected logger: Logger, protected smartApi: SmartSolutionsApi, ) { - super() + super(logger, smartApi) } pushUpdate( diff --git a/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClient.service.ts b/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClient.service.ts index d2ce62709c15..855eb3206209 100644 --- a/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClient.service.ts +++ b/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClient.service.ts @@ -12,11 +12,11 @@ import { VerifyInputData, } from '../../../licenseClient.type' import { createPkPassDataInput, nationalIdIndex } from '../firearmLicenseMapper' -import { BaseLicenseUpdateClient } from '../../baseLicenseUpdateClient' import { mapNationalId } from '../firearmLicenseMapper' import type { ConfigType } from '@island.is/nest/config' import { FirearmDigitalLicenseClientConfig } from '../firearmLicenseClient.config' import { SmartSolutionsApi } from '@island.is/clients/smartsolutions' +import { BaseLicenseUpdateClient } from '../../base/baseLicenseUpdateClient' /** Category to attach each log message to */ const LOG_CATEGORY = 'firearmlicense-service' @@ -30,14 +30,14 @@ export class FirearmLicenseUpdateClient extends BaseLicenseUpdateClient { private openFirearmApi: OpenFirearmApi, protected smartApi: SmartSolutionsApi, ) { - super() + super(logger, smartApi) } async pushUpdate( inputData: PassDataInput, nationalId: string, requestId?: string, - ): Promise> { + ): Promise> { const inputFieldValues = inputData.inputFieldValues ?? [] //small check that nationalId doesnt' already exist if ( From 3c652e4da4728aa2e77c6e0238e613cc14c47780 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Tue, 8 Oct 2024 10:40:51 +0000 Subject: [PATCH 06/29] fix: revert clinet changes --- .../drivingLicenseMapper.ts | 1 - .../services/drivingLicenseClient.service.ts | 9 +- .../services/drivingLicenseMapper.ts | 126 ------------------ .../drivingLicenseUpdateClient.service.ts | 20 +-- .../modules/smartSolutionsFirearm.module.ts | 10 +- .../services/firearmLicenseClient.service.ts | 14 +- .../firearmLicenseUpdateClient.service.ts | 18 +-- 7 files changed, 41 insertions(+), 157 deletions(-) delete mode 100644 libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseMapper.ts diff --git a/libs/clients/license-client/src/lib/clients/driving-license-client/drivingLicenseMapper.ts b/libs/clients/license-client/src/lib/clients/driving-license-client/drivingLicenseMapper.ts index f2ce6426f514..afc7e7592bb1 100644 --- a/libs/clients/license-client/src/lib/clients/driving-license-client/drivingLicenseMapper.ts +++ b/libs/clients/license-client/src/lib/clients/driving-license-client/drivingLicenseMapper.ts @@ -3,7 +3,6 @@ import { DriverLicenseDto as DriversLicense, RemarkCode, } from '@island.is/clients/driving-license' -import { PassInputFieldValueDataInput } from '@island.is/clients/smartsolutions' import format from 'date-fns/format' import { info, format as formatSsn } from 'kennitala' diff --git a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseClient.service.ts b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseClient.service.ts index af8e49532bbb..3c89d2f4af11 100644 --- a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseClient.service.ts +++ b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseClient.service.ts @@ -5,6 +5,11 @@ import { RemarkCode, } from '@island.is/clients/driving-license' import { FetchError } from '@island.is/clients/middlewares' +import { + Pass, + PassDataInput, + SmartSolutionsApi, +} from '@island.is/clients/smartsolutions' import type { Logger } from '@island.is/logging' import { LOGGER_PROVIDER } from '@island.is/logging' import { BadRequestException, Inject, Injectable } from '@nestjs/common' @@ -16,12 +21,10 @@ import { PkPassVerificationInputData, VerifyPkPassResult, Result, - PassDataInput, } from '../../../licenseClient.type' import { DrivingLicenseVerifyExtraData } from '../drivingLicenseClient.type' import { createPkPassDataInput } from '../drivingLicenseMapper' import { FeatureFlagService, Features } from '@island.is/nest/feature-flags' -import { Pass, SmartSolutionsApi } from '@island.is/clients/smartsolutions' /** Category to attach each log message to */ const LOG_CATEGORY = 'drivinglicense-service' @@ -150,7 +153,7 @@ export class DrivingLicenseClient ? { imageBase64String: image.substring(image.indexOf(',') + 1).trim(), } - : undefined, + : null, } return payload diff --git a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseMapper.ts b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseMapper.ts deleted file mode 100644 index 2e3dd72ebfde..000000000000 --- a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseMapper.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { - RemarkCode, - DriverLicenseDto as DriversLicense, - CategoryDto, -} from '@island.is/clients/driving-license' -import format from 'date-fns/format' -import { info, format as formatNationalId } from 'kennitala' - -const mapRemarks = ( - license?: DriversLicense, - remarks?: Array | null, -) => { - const comments = license?.comments - if (!comments || !remarks) { - return - } - const commentString = comments.reduce( - (acc, curr) => `${acc} ${mapCommentToRemark(curr.nr ?? null, remarks)}`, - '', - ) - - return commentString -} - -const mapCommentToRemark = ( - commentId: string | null, - remarks: Array, -) => { - const remark = remarks.find((r) => r.index === commentId) - return remark?.name ? `${commentId} - ${remark.name}\n` : undefined -} - -const mapCategoryToRight = ( - category: CategoryDto, - remarks?: Array | null, -) => { - let right = `Réttindaflokkur ${category.nr}, ${ - category.categoryName - }\n - Gildir til ${ - category.dateTo ? format(category.dateTo, 'dd-MM-yyyy') : '' - }\n` - - if (category.comment) { - const mappedRemark = remarks?.find((r) => r.index === category.comment) - right += - ` - Tákntala: ${category.comment}` + - `${mappedRemark ? ' - ' + mappedRemark : ''}\n` - } - - return right -} - -const formatRights = ( - categories: Array | null, - remarks?: Array | null, -) => { - if (!categories) { - return - } - - const rights = categories.reduce( - (acc, curr) => `${acc} ${mapCategoryToRight(curr, remarks)}\n`, - '', - ) - - return rights ?? 'Engin réttindi' -} - -export const createPkPassDataInput = ( - license?: DriversLicense | null, - remarks?: Array | null, -) => { - if (!license || !remarks) return null - - return [ - { - identifier: 'gildir', - value: license.dateValidTo - ? format(license.dateValidTo, 'dd-MM-yyyy') - : '', - }, - { - identifier: 'nafn', - value: license.name ?? '', - }, - { - identifier: 'kennitala', - value: license.socialSecurityNumber - ? formatNationalId(license.socialSecurityNumber) - : '', - }, - { - identifier: 'faedingardagur', - value: license.socialSecurityNumber - ? format( - info(license.socialSecurityNumber ?? '').birthday, - 'dd-MM-yyyy', - ) - : '', - }, - { - identifier: 'utgafudagur', - value: license.publishDate - ? format(license.publishDate, 'dd-MM-yyyy') - : '', - }, - { - identifier: 'numer', - value: license.id?.toString() ?? '', - }, - { - identifier: 'rettindaflokkar', - value: license.categories - ? license.categories?.reduce((acc, curr) => `${acc} ${curr.nr}`, '') - : '', - }, - { - identifier: 'rettindi', - value: formatRights(license.categories ?? null, remarks), - }, - { - identifier: 'athugasemdir', - value: license.comments ? mapRemarks(license, remarks) : '', - }, - ] -} diff --git a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClient.service.ts b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClient.service.ts index 57f1e01e5604..418bbfe8a8ce 100644 --- a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClient.service.ts +++ b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClient.service.ts @@ -3,14 +3,17 @@ import { LOGGER_PROVIDER } from '@island.is/logging' import type { ConfigType } from '@island.is/nest/config' import { Inject, Injectable } from '@nestjs/common' import { - PassData, + Pass, PassDataInput, - PassRevocationData, + RevokePassData, + SmartSolutionsApi, +} from '@island.is/clients/smartsolutions' +import { PassVerificationData, Result, VerifyInputData, } from '../../../licenseClient.type' -import { BaseLicenseUpdateClient } from '../../baseLicenseUpdateClient' +import { BaseLicenseUpdateClient } from '../../base/baseLicenseUpdateClient' import { DrivingLicenseApi } from '@island.is/clients/driving-license' import { createPkPassDataInput, @@ -18,7 +21,6 @@ import { nationalIdIndex, } from '../drivingLicenseMapper' import { DrivingDigitalLicenseClientConfig } from '../drivingLicenseClient.config' -import { SmartSolutionsApi } from '@island.is/clients/smartsolutions' /** Category to attach each log message to */ const LOG_CATEGORY = 'driving-license-service' @@ -32,14 +34,14 @@ export class DrivingLicenseUpdateClient extends BaseLicenseUpdateClient { private drivingLicenseApi: DrivingLicenseApi, protected smartApi: SmartSolutionsApi, ) { - super() + super(logger, smartApi) } pushUpdate( inputData: PassDataInput, nationalId: string, requestId?: string, - ): Promise> { + ): Promise> { const inputFieldValues = inputData.inputFieldValues ?? [] //small check that nationalId doesnt' already exist if ( @@ -61,7 +63,7 @@ export class DrivingLicenseUpdateClient extends BaseLicenseUpdateClient { async pullUpdate( nationalId: string, requestId?: string, - ): Promise> { + ): Promise> { let data try { data = await Promise.all([ @@ -127,7 +129,7 @@ export class DrivingLicenseUpdateClient extends BaseLicenseUpdateClient { ? { imageBase64String: image.substring(image.indexOf(',') + 1).trim(), } - : undefined + : null const payload: PassDataInput = { inputFieldValues: inputValues, @@ -142,7 +144,7 @@ export class DrivingLicenseUpdateClient extends BaseLicenseUpdateClient { revoke( nationalId: string, requestId?: string, - ): Promise> { + ): Promise> { const passTemplateId = this.config.passTemplateId const payload: PassDataInput = { inputFieldValues: [mapNationalId(nationalId)], diff --git a/libs/clients/license-client/src/lib/clients/firearm-license-client/modules/smartSolutionsFirearm.module.ts b/libs/clients/license-client/src/lib/clients/firearm-license-client/modules/smartSolutionsFirearm.module.ts index 7f3cc969a0cc..d324d3c3b63c 100644 --- a/libs/clients/license-client/src/lib/clients/firearm-license-client/modules/smartSolutionsFirearm.module.ts +++ b/libs/clients/license-client/src/lib/clients/firearm-license-client/modules/smartSolutionsFirearm.module.ts @@ -4,16 +4,18 @@ import { } from '@island.is/clients/smartsolutions' import { FirearmDigitalLicenseClientConfig } from '../firearmLicenseClient.config' import { ConfigType } from '@nestjs/config' -import { SmartSolutionsAdapterModule } from '../../smart-solutions-adapter/smartSolutionsAdapter.module' export const SmartSolutionsFirearmModule = - SmartSolutionsAdapterModule.registerAsync({ + SmartSolutionsApiClientModule.registerAsync({ useFactory: ( config: ConfigType, ) => { - return { - config, + const smartConfig: SmartSolutionsConfig = { + apiKey: config.apiKey, + apiUrl: config.apiUrl, + passTemplateId: config.passTemplateId, } + return smartConfig }, inject: [FirearmDigitalLicenseClientConfig.KEY], }) diff --git a/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseClient.service.ts b/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseClient.service.ts index 8a0f3e2056da..c0ed478a08c3 100644 --- a/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseClient.service.ts +++ b/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseClient.service.ts @@ -3,20 +3,22 @@ import { LOGGER_PROVIDER } from '@island.is/logging' import { User } from '@island.is/auth-nest-tools' import { Inject, Injectable } from '@nestjs/common' import { FirearmApi } from '@island.is/clients/firearm-license' +import { + Pass, + PassDataInput, + Result, + SmartSolutionsApi, +} from '@island.is/clients/smartsolutions' import compareAsc from 'date-fns/compareAsc' import { LicenseClient, LicensePkPassAvailability, LicenseType, - PassData, - PassDataInput, PkPassVerificationInputData, - Result, VerifyPkPassResult, } from '../../../licenseClient.type' import { FirearmLicenseDto } from '../firearmLicenseClient.type' import { createPkPassDataInput } from '../firearmLicenseMapper' -import { SmartSolutionsApi } from '@island.is/clients/smartsolutions' /** Category to attach each log message to */ const LOG_CATEGORY = 'firearmlicense-service' @@ -178,12 +180,12 @@ export class FirearmLicenseClient ? { imageBase64String: parsedImage ?? '', } - : undefined, + : null, } return payload } - async getPkPass(user: User): Promise> { + async getPkPass(user: User): Promise> { const license = await this.fetchLicenseData(user) if (!license.ok || !license.data) { diff --git a/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClient.service.ts b/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClient.service.ts index 855eb3206209..fb8e3608613a 100644 --- a/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClient.service.ts +++ b/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClient.service.ts @@ -4,19 +4,21 @@ import { Inject, Injectable } from '@nestjs/common' import { OpenFirearmApi } from '@island.is/clients/firearm-license' import { sanitize as sanitizeNationalId } from 'kennitala' import { - PassData, + Pass, PassDataInput, - PassRevocationData, + RevokePassData, + SmartSolutionsApi, +} from '@island.is/clients/smartsolutions' +import { PassVerificationData, Result, VerifyInputData, } from '../../../licenseClient.type' import { createPkPassDataInput, nationalIdIndex } from '../firearmLicenseMapper' +import { BaseLicenseUpdateClient } from '../../base/baseLicenseUpdateClient' import { mapNationalId } from '../firearmLicenseMapper' import type { ConfigType } from '@island.is/nest/config' import { FirearmDigitalLicenseClientConfig } from '../firearmLicenseClient.config' -import { SmartSolutionsApi } from '@island.is/clients/smartsolutions' -import { BaseLicenseUpdateClient } from '../../base/baseLicenseUpdateClient' /** Category to attach each log message to */ const LOG_CATEGORY = 'firearmlicense-service' @@ -33,7 +35,7 @@ export class FirearmLicenseUpdateClient extends BaseLicenseUpdateClient { super(logger, smartApi) } - async pushUpdate( + pushUpdate( inputData: PassDataInput, nationalId: string, requestId?: string, @@ -60,7 +62,7 @@ export class FirearmLicenseUpdateClient extends BaseLicenseUpdateClient { async pullUpdate( nationalId: string, requestId?: string, - ): Promise> { + ): Promise> { let data try { data = await Promise.all([ @@ -133,7 +135,7 @@ export class FirearmLicenseUpdateClient extends BaseLicenseUpdateClient { .substring(thumbnail.indexOf(',') + 1) .trim(), } - : undefined, + : null, } return this.smartApi.updatePkPass(payload, requestId) @@ -142,7 +144,7 @@ export class FirearmLicenseUpdateClient extends BaseLicenseUpdateClient { revoke( nationalId: string, requestId?: string, - ): Promise> { + ): Promise> { const passTemplateId = this.config.passTemplateId const payload: PassDataInput = { inputFieldValues: [mapNationalId(nationalId)], From fc0e0e8aaf165bf9eeedf1026440c453198f648a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Tue, 8 Oct 2024 11:01:26 +0000 Subject: [PATCH 07/29] feat: conditional license api init --- .../disabilityLicenseUpdateClient.module.ts | 5 +- ...disabilityLicenseUpdateClientV2.service.ts | 85 ++++++ .../drivingLicenseUpdateClient.module.ts | 5 +- .../drivingLicenseUpdateClientV2.service.ts | 287 ++++++++++++++++++ .../firearmLicenseUpdateClient.module.ts | 14 +- .../firearmLicenseUpdateClientV2.service.ts | 256 ++++++++++++++++ .../clients/pk-pass-client/pkPass.service.ts | 9 +- .../src/lib/licenseClient.type.ts | 1 + .../src/lib/licenseUpdateClient.module.ts | 33 ++ .../src/lib/licenseUpdateClient.service.ts | 23 +- 10 files changed, 699 insertions(+), 19 deletions(-) create mode 100644 libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClientV2.service.ts create mode 100644 libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts create mode 100644 libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClientV2.service.ts diff --git a/libs/clients/license-client/src/lib/clients/disability-license-client/modules/disabilityLicenseUpdateClient.module.ts b/libs/clients/license-client/src/lib/clients/disability-license-client/modules/disabilityLicenseUpdateClient.module.ts index 7b5f0e956cbe..322999b1d61e 100644 --- a/libs/clients/license-client/src/lib/clients/disability-license-client/modules/disabilityLicenseUpdateClient.module.ts +++ b/libs/clients/license-client/src/lib/clients/disability-license-client/modules/disabilityLicenseUpdateClient.module.ts @@ -3,6 +3,7 @@ import { Module } from '@nestjs/common' import { ConfigType } from '@island.is/nest/config' import { DisabilityDigitalLicenseClientConfig } from '../disabilityLicenseClient.config' import { DisabilityLicenseUpdateClient } from '../services/disabilityLicenseUpdateClient.service' +import { DisabilityLicenseUpdateClientV2 } from '../services/disabilityLicenseUpdateClientV2.service' @Module({ imports: [ @@ -13,7 +14,7 @@ import { DisabilityLicenseUpdateClient } from '../services/disabilityLicenseUpda inject: [DisabilityDigitalLicenseClientConfig.KEY], }), ], - providers: [DisabilityLicenseUpdateClient], - exports: [DisabilityLicenseUpdateClient], + providers: [DisabilityLicenseUpdateClient, DisabilityLicenseUpdateClientV2], + exports: [DisabilityLicenseUpdateClient, DisabilityLicenseUpdateClientV2], }) export class DisabilityUpdateClientModule {} diff --git a/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClientV2.service.ts b/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClientV2.service.ts new file mode 100644 index 000000000000..cf62a97285c0 --- /dev/null +++ b/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClientV2.service.ts @@ -0,0 +1,85 @@ +import type { Logger } from '@island.is/logging' +import { LOGGER_PROVIDER } from '@island.is/logging' +import { Inject, Injectable } from '@nestjs/common' +import { + PassData, + PassDataInput, + PassRevocationData, + PassVerificationData, + Result, + VerifyInputData, +} from '../../../licenseClient.type' +import { PkPassService } from '../../pk-pass-client/pkPass.service' +import { BaseLicenseUpdateClientV2 } from '../../base/licenseUpdateClientV2' + +@Injectable() +export class DisabilityLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { + constructor( + @Inject(LOGGER_PROVIDER) protected logger: Logger, + private readonly passService: PkPassService, + ) { + super() + } + + pushUpdate( + inputData: PassDataInput, + nationalId: string, + ): Promise> { + return this.passService.updatePkPass(inputData, nationalId) + } + + async pullUpdate(): Promise> { + return { + ok: false, + error: { + code: 99, + message: 'not implemented yet', + }, + } + } + + revoke(nationalId: string): Promise> { + throw new Error('Method not implemented.') + } + + async verify(inputData: string): Promise> { + let parsedInput + try { + parsedInput = JSON.parse(inputData) as VerifyInputData + } catch (ex) { + return { + ok: false, + error: { + code: 12, + message: 'Invalid input data', + }, + } + } + + const { code, date } = parsedInput + + if (!code || !date) { + return { + ok: false, + error: { + code: 4, + message: + 'Invalid input data, either code or date are missing or invalid', + }, + } + } + + const verifyRes = await this.passService.verifyPkPass({ code, date }) + + if (!verifyRes.ok) { + return verifyRes + } + + return { + ok: true, + data: { + valid: verifyRes.data.valid, + }, + } + } +} diff --git a/libs/clients/license-client/src/lib/clients/driving-license-client/modules/drivingLicenseUpdateClient.module.ts b/libs/clients/license-client/src/lib/clients/driving-license-client/modules/drivingLicenseUpdateClient.module.ts index ffb8814deda1..790a3b1fb09f 100644 --- a/libs/clients/license-client/src/lib/clients/driving-license-client/modules/drivingLicenseUpdateClient.module.ts +++ b/libs/clients/license-client/src/lib/clients/driving-license-client/modules/drivingLicenseUpdateClient.module.ts @@ -4,6 +4,7 @@ import { ConfigType } from '@nestjs/config' import { DrivingLicenseUpdateClient } from '../services/drivingLicenseUpdateClient.service' import { DrivingDigitalLicenseClientConfig } from '../drivingLicenseClient.config' import { DrivingLicenseApiModule } from '@island.is/clients/driving-license' +import { DrivingLicenseUpdateClientV2 } from '../services/drivingLicenseUpdateClientV2.service' @Module({ imports: [ @@ -15,7 +16,7 @@ import { DrivingLicenseApiModule } from '@island.is/clients/driving-license' inject: [DrivingDigitalLicenseClientConfig.KEY], }), ], - providers: [DrivingLicenseUpdateClient], - exports: [DrivingLicenseUpdateClient], + providers: [DrivingLicenseUpdateClient, DrivingLicenseUpdateClientV2], + exports: [DrivingLicenseUpdateClient, DrivingLicenseUpdateClientV2], }) export class DrivingUpdateClientModule {} diff --git a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts new file mode 100644 index 000000000000..dc0bf1ee618b --- /dev/null +++ b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts @@ -0,0 +1,287 @@ +import type { Logger } from '@island.is/logging' +import { LOGGER_PROVIDER } from '@island.is/logging' +import type { ConfigType } from '@island.is/nest/config' +import { Inject, Injectable } from '@nestjs/common' +import { + PassData, + PassDataInput, + PassRevocationData, + PassVerificationData, + Result, + VerifyInputData, +} from '../../../licenseClient.type' +import { DrivingLicenseApi } from '@island.is/clients/driving-license' +import { + createPkPassDataInput, + mapNationalId, + nationalIdIndex, +} from '../drivingLicenseMapper' +import { DrivingDigitalLicenseClientConfig } from '../drivingLicenseClient.config' +import { BaseLicenseUpdateClientV2 } from '../../base/licenseUpdateClientV2' +import { PkPassService } from '../../pk-pass-client/pkPass.service' + +/** Category to attach each log message to */ +const LOG_CATEGORY = 'driving-license-service' + +@Injectable() +export class DrivingLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { + constructor( + @Inject(LOGGER_PROVIDER) protected logger: Logger, + @Inject(DrivingDigitalLicenseClientConfig.KEY) + private config: ConfigType, + private drivingLicenseApi: DrivingLicenseApi, + private readonly passService: PkPassService, + ) { + super() + } + + pushUpdate( + inputData: PassDataInput, + nationalId: string, + requestId?: string, + ): Promise> { + const inputFieldValues = inputData.inputFieldValues ?? [] + //small check that nationalId doesnt' already exist + if ( + inputFieldValues && + !inputFieldValues?.some((nt) => nt.identifier === nationalIdIndex) + ) { + inputFieldValues.push(mapNationalId(nationalId)) + } + return this.passService.updatePkPass( + { + ...inputData, + inputFieldValues, + passTemplateId: this.config.passTemplateId, + }, + requestId, + ) + } + + async pullUpdate( + nationalId: string, + requestId?: string, + ): Promise> { + let data + try { + data = await Promise.all([ + this.drivingLicenseApi.getCurrentLicenseV4({ nationalId }), + this.drivingLicenseApi.getRemarksCodeTable(), + ]) + } catch (e) { + this.logger.error( + 'Current driving license fetch and/or remarks fetch failed', + { + error: e, + requestId, + category: LOG_CATEGORY, + }, + ) + return { + ok: false, + error: { + code: 13, + message: `Either current driving license fetch or remarks fetch failed`, + data: JSON.stringify(e), + }, + } + } + + const [licenseInfo, remarks] = data + + if (!licenseInfo) { + this.logger.warn('No license info found for user, exiting update', { + requestId, + category: LOG_CATEGORY, + }) + return { + ok: false, + error: { + code: 3, + message: 'No license info found for user', + }, + } + } + + const inputValues = createPkPassDataInput(licenseInfo, remarks) + + if (!inputValues || !licenseInfo.dateValidTo) { + this.logger.error( + 'pkpass data input mapping failed, data may be invalid', + { + requestId, + category: LOG_CATEGORY, + }, + ) + return { + ok: false, + error: { + code: 4, + message: 'pkpass data input mapping failed, data may be invalid', + }, + } + } + + const image = licenseInfo.photo?.image + + const payload: PassDataInput = { + inputFieldValues: inputValues, + expirationDate: licenseInfo.dateValidTo.toISOString(), + passTemplateId: this.config.passTemplateId, + thumbnail: image + ? { + imageBase64String: image.substring(image.indexOf(',') + 1).trim(), + } + : undefined, + } + + return this.passService.updatePkPass(payload, requestId) + } + + revoke( + nationalId: string, + requestId?: string, + ): Promise> { + const passTemplateId = this.config.passTemplateId + const payload: PassDataInput = { + inputFieldValues: [mapNationalId(nationalId)], + } + return this.passService.revokePkPass(passTemplateId, payload, requestId) + } + + /** We need to verify the pk pass AND the license itself! */ + async verify( + inputData: string, + requestId?: string, + ): Promise> { + //need to parse the scanner data + let parsedInput + try { + parsedInput = JSON.parse(inputData) as VerifyInputData + } catch (ex) { + this.logger.error( + 'Pkpass verification data input mapping failed, data may be invalid', + { + requestId, + category: LOG_CATEGORY, + }, + ) + return { + ok: false, + error: { + code: 12, + message: + 'Pkpass verification data input mapping failed, data may be invalid', + }, + } + } + + const { code, date } = parsedInput + + if (!code || !date) { + this.logger.error( + 'Invalid verification input data, either code or date are missing or invalid ', + { + requestId, + category: LOG_CATEGORY, + }, + ) + return { + ok: false, + error: { + code: 4, + message: + 'Invalid verification input data, either code or date are missing or invalid', + }, + } + } + + const verifyRes = await this.passService.verifyPkPass( + { code, date }, + requestId, + ) + + if (!verifyRes.ok) { + return verifyRes + } + + if (!verifyRes.data.valid) { + this.logger.debug('PkPass is valid', { + requestId, + category: LOG_CATEGORY, + }) + return { + ok: true, + data: { + valid: false, + }, + } + } + + const passNationalId = verifyRes.data.pass?.inputFieldValues?.find( + (i) => i.identifier === 'kennitala', + )?.value + + if (!passNationalId) { + this.logger.error('Missing unique identifier in pkpass input', { + requestId, + category: LOG_CATEGORY, + }) + return { + ok: false, + error: { + code: 14, + message: 'Missing unique identifier in pkpass input', + }, + } + } + const nationalId = passNationalId.replace('-', '') + const license = await this.drivingLicenseApi.getCurrentLicenseV4({ + nationalId, + }) + + if (!license) { + this.logger.warn('No license info found for user', { + requestId, + category: LOG_CATEGORY, + }) + return { + ok: false, + error: { + code: 3, + message: 'No license info found for user', + }, + } + } + + const licenseNationalId = license.socialSecurityNumber + const name = license.name ?? '' + const picture = license.photo?.image ?? '' + + if (!licenseNationalId || !name || !picture) { + this.logger.error('Missing data. NationalId, name or photo missing', { + requestId, + category: LOG_CATEGORY, + }) + return { + ok: false, + error: { + code: 14, + message: 'Missing data. NationalId, name or photo missing', + }, + } + } + + return { + ok: true, + data: { + valid: licenseNationalId === nationalId, + passIdentity: { + nationalId: licenseNationalId, + name, + picture, + }, + }, + } + } +} diff --git a/libs/clients/license-client/src/lib/clients/firearm-license-client/modules/firearmLicenseUpdateClient.module.ts b/libs/clients/license-client/src/lib/clients/firearm-license-client/modules/firearmLicenseUpdateClient.module.ts index 11f8917a11a8..bf5038057445 100644 --- a/libs/clients/license-client/src/lib/clients/firearm-license-client/modules/firearmLicenseUpdateClient.module.ts +++ b/libs/clients/license-client/src/lib/clients/firearm-license-client/modules/firearmLicenseUpdateClient.module.ts @@ -1,11 +1,17 @@ import { Module } from '@nestjs/common' import { FirearmLicenseUpdateClientModule } from '@island.is/clients/firearm-license' -import { FirearmLicenseUpdateClient } from '../services/firearmLicenseUpdateClient.service' import { SmartSolutionsFirearmModule } from './smartSolutionsFirearm.module' +import { PkPassModule } from '../../pk-pass-client/pkPass.module' +import { FirearmLicenseUpdateClient } from '../services/firearmLicenseUpdateClient.service' +import { FirearmLicenseUpdateClientV2 } from '../services/firearmLicenseUpdateClientV2.service' @Module({ - imports: [FirearmLicenseUpdateClientModule, SmartSolutionsFirearmModule], - providers: [FirearmLicenseUpdateClient], - exports: [FirearmLicenseUpdateClient], + imports: [ + FirearmLicenseUpdateClientModule, + SmartSolutionsFirearmModule, + PkPassModule, + ], + providers: [FirearmLicenseUpdateClient, FirearmLicenseUpdateClientV2], + exports: [FirearmLicenseUpdateClient, FirearmLicenseUpdateClientV2], }) export class FirearmUpdateClientModule {} diff --git a/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClientV2.service.ts b/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClientV2.service.ts new file mode 100644 index 000000000000..c796bdef7763 --- /dev/null +++ b/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClientV2.service.ts @@ -0,0 +1,256 @@ +import type { Logger } from '@island.is/logging' +import { LOGGER_PROVIDER } from '@island.is/logging' +import { Inject, Injectable } from '@nestjs/common' +import { OpenFirearmApi } from '@island.is/clients/firearm-license' +import { sanitize as sanitizeNationalId } from 'kennitala' +import { + PassData, + PassDataInput, + PassRevocationData, + PassVerificationData, + Result, + VerifyInputData, +} from '../../../licenseClient.type' +import { createPkPassDataInput, nationalIdIndex } from '../firearmLicenseMapper' +import { mapNationalId } from '../firearmLicenseMapper' +import type { ConfigType } from '@island.is/nest/config' +import { FirearmDigitalLicenseClientConfig } from '../firearmLicenseClient.config' +import { BaseLicenseUpdateClientV2 } from '../../base/licenseUpdateClientV2' +import { PkPassService } from '../../pk-pass-client/pkPass.service' + +/** Category to attach each log message to */ +const LOG_CATEGORY = 'firearmlicense-service' + +@Injectable() +export class FirearmLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { + constructor( + @Inject(LOGGER_PROVIDER) protected logger: Logger, + @Inject(FirearmDigitalLicenseClientConfig.KEY) + private config: ConfigType, + private openFirearmApi: OpenFirearmApi, + private readonly passService: PkPassService, + ) { + super() + } + + pushUpdate( + inputData: PassDataInput, + nationalId: string, + requestId?: string, + ): Promise> { + const inputFieldValues = inputData.inputFieldValues ?? [] + //small check that nationalId doesnt' already exist + if ( + inputFieldValues && + !inputFieldValues?.some((nt) => nt.identifier === nationalIdIndex) + ) { + inputFieldValues.push(mapNationalId(nationalId)) + } + + return this.passService.updatePkPass( + { + ...inputData, + inputFieldValues, + passTemplateId: this.config.passTemplateId, + }, + requestId, + ) + } + + async pullUpdate( + nationalId: string, + requestId?: string, + ): Promise> { + let data + try { + data = await Promise.all([ + this.openFirearmApi.getVerificationLicenseInfo(nationalId), + this.openFirearmApi.getVerificationPropertyInfo(nationalId), + ]) + } catch (e) { + this.logger.error( + `Either license info- or license property info fetch failed`, + { + error: e, + requestId, + category: LOG_CATEGORY, + }, + ) + return { + ok: false, + error: { + code: 13, + message: `Either license info- or license property info fetch failed`, + }, + } + } + + const [licenseInfo, propertyInfo] = data + if (!licenseInfo) { + this.logger.warn('No license info found for user', { + requestId, + category: LOG_CATEGORY, + }) + return { + ok: false, + error: { + code: 3, + message: 'No license info found for user', + }, + } + } + + const inputValues = createPkPassDataInput( + licenseInfo, + propertyInfo, + nationalId, + ) + + if (!inputValues || !licenseInfo.expirationDate) { + const message = !(inputValues && licenseInfo.expirationDate) + ? 'Mapping failed, input values and expirationDate missing' + : !inputValues + ? 'Mapping failed, missing input values' + : 'Mapping failed, missing expirationDate' + + return { + ok: false, + error: { + code: 4, + message, + }, + } + } + + const thumbnail = licenseInfo.licenseImgBase64 + const payload: PassDataInput = { + inputFieldValues: inputValues, + expirationDate: new Date(licenseInfo?.expirationDate).toISOString(), + passTemplateId: this.config.passTemplateId, + thumbnail: thumbnail + ? { + imageBase64String: thumbnail + .substring(thumbnail.indexOf(',') + 1) + .trim(), + } + : undefined, + } + + return this.passService.updatePkPass(payload, requestId) + } + + revoke( + nationalId: string, + requestId?: string, + ): Promise> { + const passTemplateId = this.config.passTemplateId + const payload: PassDataInput = { + inputFieldValues: [mapNationalId(nationalId)], + } + return this.passService.revokePkPass(passTemplateId, payload, requestId) + } + + /** We need to verify the pk pass AND the license itself! */ + async verify( + inputData: string, + requestId?: string, + ): Promise> { + //need to parse the scanner data + let parsedInput + try { + parsedInput = JSON.parse(inputData) as VerifyInputData + } catch (ex) { + return { + ok: false, + error: { + code: 12, + message: 'Invalid input data', + }, + } + } + + const { code, date } = parsedInput + + if (!code || !date) { + return { + ok: false, + error: { + code: 4, + message: + 'Invalid input data, either code or date are missing or invalid', + }, + } + } + + const verifyRes = await this.passService.verifyPkPass( + { code, date }, + requestId, + ) + + if (!verifyRes.ok) { + return verifyRes + } + + if (!verifyRes.data.valid) { + return { + ok: true, + data: { + valid: false, + }, + } + } + + const passNationalId = verifyRes.data.pass?.inputFieldValues?.find( + (i) => i.identifier === 'kt', + )?.value + + if (!passNationalId) { + return { + ok: false, + error: { + code: 14, + message: 'Missing pass data', + }, + } + } + const sanitizedPassNationalId = sanitizeNationalId(passNationalId) + + const licenseInfo = await this.openFirearmApi.getVerificationLicenseInfo( + sanitizedPassNationalId, + ) + + if (!licenseInfo) { + return { + ok: false, + error: { + code: 3, + message: 'No license info found for user', + }, + } + } + + if (!licenseInfo.ssn || !licenseInfo.name) { + return { + ok: false, + error: { + code: 3, + message: 'Missing nationalId or name for user', + }, + } + } + + //now we compare the data + + return { + ok: true, + data: { + valid: licenseInfo.ssn === sanitizedPassNationalId, + passIdentity: { + name: licenseInfo.name, + nationalId: licenseInfo.ssn, + picture: licenseInfo.licenseImgBase64 ?? '', + }, + }, + } + } +} diff --git a/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.service.ts b/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.service.ts index 05145ac88773..53307923aa95 100644 --- a/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.service.ts +++ b/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.service.ts @@ -1,10 +1,5 @@ import { LOGGER_PROVIDER, type Logger } from '@island.is/logging' -import { MODULE_OPTIONS_TOKEN } from './pkPass.module-definition' -import { - PkPassModuleOptions, - VerifyPassData, - VerifyPkPassDataInput, -} from './pkPass.types' +import { VerifyPassData, VerifyPkPassDataInput } from './pkPass.types' import { Inject } from '@nestjs/common' import { SmartSolutionsApi } from '@island.is/clients/smartsolutions' import { SmartSolutionsService } from '@island.is/clients/smart-solutions-v2' @@ -22,8 +17,6 @@ export class PkPassService { @Inject(LOGGER_PROVIDER) private readonly logger: Logger, private readonly featureFlagService: FeatureFlagService, - @Inject(MODULE_OPTIONS_TOKEN) - private readonly options: PkPassModuleOptions, private readonly newSmartService: SmartSolutionsService, /** DEPRECATED */ private readonly oldSmartService: SmartSolutionsApi, diff --git a/libs/clients/license-client/src/lib/licenseClient.type.ts b/libs/clients/license-client/src/lib/licenseClient.type.ts index 863ef764aee2..a95159a40fc0 100644 --- a/libs/clients/license-client/src/lib/licenseClient.type.ts +++ b/libs/clients/license-client/src/lib/licenseClient.type.ts @@ -239,4 +239,5 @@ export interface LicenseClient { export const LICENSE_CLIENT_FACTORY = 'license-client-factory' export const LICENSE_UPDATE_CLIENT_FACTORY = 'license-client-factory' +export const LICENSE_UPDATE_CLIENT_FACTORY_V2 = 'license-client-factory-v2' export const CONFIG_PROVIDER = 'config_provider' diff --git a/libs/clients/license-client/src/lib/licenseUpdateClient.module.ts b/libs/clients/license-client/src/lib/licenseUpdateClient.module.ts index a84d88c88194..eec0a896b24f 100644 --- a/libs/clients/license-client/src/lib/licenseUpdateClient.module.ts +++ b/libs/clients/license-client/src/lib/licenseUpdateClient.module.ts @@ -3,6 +3,7 @@ import { Module } from '@nestjs/common' import { LicenseType, LICENSE_UPDATE_CLIENT_FACTORY, + LICENSE_UPDATE_CLIENT_FACTORY_V2, } from './licenseClient.type' import { LicenseUpdateClientService } from './licenseUpdateClient.service' import { @@ -19,6 +20,10 @@ import { DrivingLicenseUpdateClient, DrivingUpdateClientModule, } from './clients/driving-license-client' +import { BaseLicenseUpdateClientV2 } from './clients/base/licenseUpdateClientV2' +import { FirearmLicenseUpdateClientV2 } from './clients/firearm-license-client/services/firearmLicenseUpdateClientV2.service' +import { DisabilityLicenseUpdateClientV2 } from './clients/disability-license-client/services/disabilityLicenseUpdateClientV2.service' +import { DrivingLicenseUpdateClientV2 } from './clients/driving-license-client/services/drivingLicenseUpdateClientV2.service' @Module({ imports: [ @@ -60,6 +65,34 @@ import { DrivingLicenseUpdateClient, ], }, + { + provide: LICENSE_UPDATE_CLIENT_FACTORY_V2, + useFactory: + ( + firearmClient: FirearmLicenseUpdateClientV2, + disabilityClient: DisabilityLicenseUpdateClientV2, + drivingClient: DrivingLicenseUpdateClientV2, + ) => + async ( + type: LicenseType, + ): Promise => { + switch (type) { + case LicenseType.FirearmLicense: + return firearmClient + case LicenseType.DisabilityLicense: + return disabilityClient + case LicenseType.DrivingLicense: + return drivingClient + default: + return null + } + }, + inject: [ + FirearmLicenseUpdateClientV2, + DisabilityLicenseUpdateClientV2, + DrivingLicenseUpdateClientV2, + ], + }, ], exports: [LicenseUpdateClientService], }) diff --git a/libs/clients/license-client/src/lib/licenseUpdateClient.service.ts b/libs/clients/license-client/src/lib/licenseUpdateClient.service.ts index 44e72b9de465..2dfe6c7bbe5a 100644 --- a/libs/clients/license-client/src/lib/licenseUpdateClient.service.ts +++ b/libs/clients/license-client/src/lib/licenseUpdateClient.service.ts @@ -5,10 +5,12 @@ import { CONFIG_PROVIDER, LicenseType, LICENSE_UPDATE_CLIENT_FACTORY, + LICENSE_UPDATE_CLIENT_FACTORY_V2, } from './licenseClient.type' import type { PassTemplateIds, LicenseTypeType } from './licenseClient.type' -import { BaseLicenseUpdateClient } from './clients/baseLicenseUpdateClient' import { LOG_CATEGORY } from '@island.is/clients/smartsolutions' +import { BaseLicenseUpdateClientV2 } from './clients/base/licenseUpdateClientV2' +import { BaseLicenseUpdateClient } from './clients/base/baseLicenseUpdateClient' @Injectable() export class LicenseUpdateClientService { @@ -18,6 +20,11 @@ export class LicenseUpdateClientService { type: LicenseType, requestId?: string, ) => Promise, + @Inject(LICENSE_UPDATE_CLIENT_FACTORY_V2) + private licenseUpdateClientFactoryV2: ( + type: LicenseType, + requestId?: string, + ) => Promise, @Inject(LOGGER_PROVIDER) private logger: Logger, @Inject(CONFIG_PROVIDER) private config: PassTemplateIds, ) {} @@ -62,16 +69,26 @@ export class LicenseUpdateClientService { return this.config[licenseId] } - getLicenseUpdateClientByType(type: LicenseType, requestId?: string) { + getLicenseUpdateClientByType( + type: LicenseType, + requestId?: string, + version?: 'v1' | 'v2', + ) { + if (version === 'v2') { + return this.licenseUpdateClientFactoryV2(type, requestId) + } return this.licenseUpdateClientFactory(type, requestId) } getLicenseUpdateClientByPassTemplateId( passTemplateId: string, requestId?: string, + version?: 'v1' | 'v2', ) { const type = this.getTypeByPassTemplateId(passTemplateId, requestId) - return type ? this.licenseUpdateClientFactory(type) : null + return type + ? this.getLicenseUpdateClientByType(type, requestId, version) + : null } } From 1a16ca85ce50fb0fd950af72fb0103ba5f84ae37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Tue, 8 Oct 2024 14:50:46 +0000 Subject: [PATCH 08/29] feat: pkpass helper class --- .../src/app/modules/license/license.module.ts | 3 +- .../app/modules/license/license.service.ts | 401 ++--------------- .../app/modules/license/licenseV1.service.ts | 413 +++++++++++++++++ .../app/modules/license/licenseV2.service.ts | 414 ++++++++++++++++++ libs/clients/license-client/src/index.ts | 4 +- .../clients/base/baseLicenseUpdateClient.ts | 3 +- ...disabilityLicenseUpdateClientV2.service.ts | 2 +- .../drivingLicenseUpdateClientV2.service.ts | 2 +- .../firearmLicenseUpdateClient.module.ts | 14 +- .../firearmLicenseUpdateClientV2.service.ts | 2 +- .../machineLicenseClient.module.ts | 26 +- .../machineLicenseClient.service.ts | 21 +- .../clients/pk-pass-client/PkPassService.ts | 0 .../pkPass.module-definition.ts | 5 - .../clients/pk-pass-client/pkPass.module.ts | 30 -- .../pkPassService}/pkPass.mapper.ts | 0 .../pkPassService}/pkPass.service.ts | 6 +- .../pkPassService}/pkPass.types.ts | 0 .../src/lib/licenseUpdateClient.module.ts | 2 +- .../src/lib/licenseUpdateClient.service.ts | 28 +- libs/clients/smart-solutions-v2/src/index.ts | 2 +- 21 files changed, 912 insertions(+), 466 deletions(-) create mode 100644 apps/services/license-api/src/app/modules/license/licenseV1.service.ts create mode 100644 apps/services/license-api/src/app/modules/license/licenseV2.service.ts delete mode 100644 libs/clients/license-client/src/lib/clients/pk-pass-client/PkPassService.ts delete mode 100644 libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.module-definition.ts delete mode 100644 libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.module.ts rename libs/clients/license-client/src/lib/{clients/pk-pass-client => helpers/pkPassService}/pkPass.mapper.ts (100%) rename libs/clients/license-client/src/lib/{clients/pk-pass-client => helpers/pkPassService}/pkPass.service.ts (93%) rename libs/clients/license-client/src/lib/{clients/pk-pass-client => helpers/pkPassService}/pkPass.types.ts (100%) diff --git a/apps/services/license-api/src/app/modules/license/license.module.ts b/apps/services/license-api/src/app/modules/license/license.module.ts index 29bd6ba98ca5..d8c31e97614b 100644 --- a/apps/services/license-api/src/app/modules/license/license.module.ts +++ b/apps/services/license-api/src/app/modules/license/license.module.ts @@ -7,9 +7,10 @@ import { UserLicensesController, } from './license.controller' import { LicenseService } from './license.service' +import { FeatureFlagModule } from '@island.is/nest/feature-flags' @Module({ - imports: [LicenseUpdateClientModule, LicenseCommonModule], + imports: [LicenseUpdateClientModule, LicenseCommonModule, FeatureFlagModule], controllers: [LicensesController, UserLicensesController], providers: [ { diff --git a/apps/services/license-api/src/app/modules/license/license.service.ts b/apps/services/license-api/src/app/modules/license/license.service.ts index 644f20fdde24..20244010d353 100644 --- a/apps/services/license-api/src/app/modules/license/license.service.ts +++ b/apps/services/license-api/src/app/modules/license/license.service.ts @@ -1,23 +1,4 @@ -import { - BaseLicenseUpdateClient, - LicenseType, - LicenseUpdateClientService, - PassData, - PassDataInput, -} from '@island.is/clients/license-client' -import { LOGGER_PROVIDER, type Logger } from '@island.is/logging' -import { - BarcodeService, - TOKEN_EXPIRED_ERROR, -} from '@island.is/services/license' -import { - BadRequestException, - Inject, - Injectable, - InternalServerErrorException, -} from '@nestjs/common' -import { isJSON, isJWT } from 'class-validator' -import { uuid } from 'uuidv4' +import { Injectable } from '@nestjs/common' import { RevokeLicenseRequest, RevokeLicenseResponse, @@ -26,204 +7,25 @@ import { VerifyLicenseRequest, VerifyLicenseResponse, } from './dto' -import { ErrorType, LicenseId } from './license.types' -import { mapLicenseIdToLicenseType } from './utils/mapLicenseId' - -const LOG_CATEGORY = 'license-api' +import { LicenseId } from './license.types' +import { FeatureFlagService, Features } from '@island.is/nest/feature-flags' +import { LicenseServiceV1 } from './licenseV1.service' +import { LicenseServiceV2 } from './licenseV2.service' @Injectable() export class LicenseService { constructor( - @Inject(LOGGER_PROVIDER) private logger: Logger, - private readonly clientService: LicenseUpdateClientService, - private readonly barcodeService: BarcodeService, + private readonly featureFlagService: FeatureFlagService, + private readonly serviceV1: LicenseServiceV1, + private readonly serviceV2: LicenseServiceV2, ) {} - private getErrorTypeByCode = (code: number): ErrorType => - code < 10 ? 'BadRequest' : 'ServerError' - - //Error message is an array to maintain consistency - private getException = (errorType: ErrorType, details?: string | object) => { - return errorType === 'BadRequest' - ? new BadRequestException([details ?? 'Unknown error']) - : new InternalServerErrorException([details ?? 'Unknown error']) - } - - private generateRequestId = () => uuid() - - private async getClientByLicenseId( - licenseId: LicenseId, - requestId?: string, - ): Promise { - const type = mapLicenseIdToLicenseType(licenseId) - - this.logger.debug('Retrieving a licence client by license id', { - category: LOG_CATEGORY, - requestId: requestId, - type: type, - }) - - if (!type) { - this.logger.error(`Invalid license type`, { - category: LOG_CATEGORY, - requestId: requestId, - type, - }) - throw new InternalServerErrorException(`Invalid license type`) - } - - const service = await this.clientService.getLicenseUpdateClientByType( - type as LicenseType, - requestId, - ) - - this.logger.debug('Injecting the proper license client..', { - category: LOG_CATEGORY, - requestId: requestId, - type: type, - }) - - if (!service) { - this.logger.error(`Client service generation failed`, { - category: LOG_CATEGORY, - type, - }) - throw new InternalServerErrorException(`Client service generation failed`) - } - this.logger.debug('Client injection successful', { - category: LOG_CATEGORY, - requestId: requestId, - type: type, - }) - - return service - } - - private async getClientByPassTemplateId( - passTemplateId: string, - requestId?: string, - ): Promise { - this.logger.debug('Retrieving a licence client by pass template id', { - category: LOG_CATEGORY, - requestId: requestId, - passTemplateId, - }) - - const service = - await this.clientService.getLicenseUpdateClientByPassTemplateId( - passTemplateId, - requestId, - ) - - this.logger.debug('Injecting the proper license client..', { - category: LOG_CATEGORY, - requestId: requestId, - passTemplateId, - }) - - if (!service) { - this.logger.error(`Client service generation failed`, { - category: LOG_CATEGORY, - requestId: requestId, - passTemplateId, - }) - throw new InternalServerErrorException(`Client service generation failed`) - } - - return service - } - - private async pushUpdateLicense( - service: BaseLicenseUpdateClient, - expirationDate: string, - nationalId: string, - payload?: string, - requestId?: string, - ): Promise { - let updatePayload: PassDataInput = { - expirationDate, - } - - if (payload) { - let parsedInputPayload - try { - parsedInputPayload = JSON.parse(payload) - } catch (e) { - this.logger.warn('Unable to parse payload', { - category: LOG_CATEGORY, - updateType: 'push', - requestId, - }) - throw this.getException( - 'BadRequest', - 'Unable to parse payload for push update', - ) - } - updatePayload = { - ...updatePayload, - ...parsedInputPayload, - } - } - - this.logger.debug('Update input parse successful, executing update', { - category: LOG_CATEGORY, - updateType: 'push', - requestId, - }) - - const res = await service.pushUpdate(updatePayload, nationalId, requestId) - - if (res.ok) { - return res.data - } - - this.logger.error('License update failed', { - updateType: 'push', - category: LOG_CATEGORY, - requestId, - error: res.error, - }) - - throw this.getException( - this.getErrorTypeByCode(res.error.code), - res.error.message, - ) - } - - private async pullUpdateLicense( - service: BaseLicenseUpdateClient, - nationalId: string, - requestId?: string, - ): Promise { - /** PULL - Update electronic license with pulled data from service - * 1. Fetch data from provider - * 2. Parse and validate license data - * 3. With good data, update the electronic license with the validated license data! - */ - - this.logger.debug('Executing update', { - category: LOG_CATEGORY, - updateType: 'pull', - requestId, - }) - - const res = await service.pullUpdate(nationalId, requestId) - - if (res.ok) { - return res.data - } - - this.logger.error('License update failed', { - updateType: 'pull', - category: LOG_CATEGORY, - requestId, - error: res.error, - }) - - throw this.getException( - this.getErrorTypeByCode(res.error.code), - res.error.message, + getVersion = async () => { + const flag = await this.featureFlagService.getValue( + Features.licensesV2, + false, ) + return flag ? 'v2' : 'v1' } async updateLicense( @@ -231,53 +33,11 @@ export class LicenseService { nationalId: string, inputData: UpdateLicenseRequest, ): Promise { - const requestId = inputData.requestId ?? this.generateRequestId() - - const service = await this.getClientByLicenseId(licenseId, requestId) - - this.logger.debug('License update initiated', { - category: LOG_CATEGORY, - requestId, - updateType: inputData.licenseUpdateType, - }) - - let updateRes: PassData | undefined - if (inputData.licenseUpdateType === 'push') { - const { expiryDate, payload } = inputData - - if (!expiryDate) { - this.logger.warn('Invalid request body, missing expiryDate', { - category: LOG_CATEGORY, - requestId, - updateType: inputData.licenseUpdateType, - }) - - throw this.getException( - 'BadRequest', - 'Invalid request body, missing expiryDate', - ) - } - updateRes = await this.pushUpdateLicense( - service, - expiryDate, - nationalId, - payload, - requestId, - ) - } else { - updateRes = await this.pullUpdateLicense(service, nationalId, requestId) - } - - this.logger.info('License update successful', { - category: LOG_CATEGORY, - requestId, - updateType: inputData.licenseUpdateType, - }) - - return { - updateSuccess: true, - data: updateRes, + const version = await this.getVersion() + if (version === 'v2') { + return this.serviceV2.updateLicense(licenseId, nationalId, inputData) } + return this.serviceV1.updateLicense(licenseId, nationalId, inputData) } async revokeLicense( @@ -285,131 +45,20 @@ export class LicenseService { nationalId: string, inputData?: RevokeLicenseRequest, ): Promise { - const requestId = inputData?.requestId ?? this.generateRequestId() - const service = await this.getClientByLicenseId(licenseId, requestId) - - const revokeRes = await service.revoke(nationalId, requestId) - - this.logger.debug('License revoking initiated', { - category: LOG_CATEGORY, - requestId, - }) - - if (revokeRes.ok) { - this.logger.info('License revoked successfully', { - category: LOG_CATEGORY, - requestId, - }) - return { revokeSuccess: revokeRes.data.success } - } - - this.logger.error('License revoke failure', { - category: LOG_CATEGORY, - requestId, - error: revokeRes.error, - }) - throw this.getException( - this.getErrorTypeByCode(revokeRes.error.code), - revokeRes.error.message, - ) - } - - async getDataFromToken( - token: string, - requestId: string, - ): Promise { - try { - const { c } = await this.barcodeService.verifyToken(token) - const data = await this.barcodeService.getCache(c) - - if (!data) { - this.logger.error('No data found in cache', { - category: LOG_CATEGORY, - requestId, - }) - - return { - valid: false, - } - } - - return { - valid: true, - ...(data.extraData && { passIdentity: data.extraData }), - } - } catch (error) { - if (error.name === TOKEN_EXPIRED_ERROR) { - return { - valid: false, - } - } - this.logger.error(error.message, { - category: LOG_CATEGORY, - requestId, - error, - }) - - throw new BadRequestException(error.message) + const version = await this.getVersion() + if (version === 'v2') { + return this.serviceV2.revokeLicense(licenseId, nationalId, inputData) } + return this.serviceV1.revokeLicense(licenseId, nationalId, inputData) } async verifyLicense( inputData: VerifyLicenseRequest, ): Promise { - const requestId = inputData?.requestId ?? this.generateRequestId() - - if (isJWT(inputData.barcodeData)) { - return this.getDataFromToken(inputData.barcodeData, requestId) - } - - if (!isJSON(inputData.barcodeData)) { - const jsonErrorMsg = 'Barcode data must be in JSON format' - this.logger.warn(jsonErrorMsg, { - category: LOG_CATEGORY, - requestId, - }) - - throw new BadRequestException(jsonErrorMsg) - } - - const { passTemplateId } = JSON.parse(inputData.barcodeData) - - this.logger.debug('License verification initiated', { - category: LOG_CATEGORY, - requestId, - }) - - if (!passTemplateId) { - this.logger.warn('No pass template id supplied', { - category: LOG_CATEGORY, - requestId, - }) - throw this.getException('BadRequest', 'Missing pass template id') + const version = await this.getVersion() + if (version === 'v2') { + return this.serviceV2.verifyLicense(inputData) } - - const service = await this.getClientByPassTemplateId(passTemplateId) - - const verifyRes = await service.verify(inputData.barcodeData, requestId) - - if (verifyRes.ok) { - this.logger.info('License verified successfully', { - category: LOG_CATEGORY, - requestId, - }) - return { - valid: verifyRes.data.valid, - passIdentity: verifyRes.data.passIdentity, - } - } - this.logger.error('Verify license failure', { - category: LOG_CATEGORY, - error: verifyRes.error, - requestId, - }) - - throw this.getException(this.getErrorTypeByCode(verifyRes.error.code), { - message: verifyRes.error.message, - requestId, - }) + return this.serviceV1.verifyLicense(inputData) } } diff --git a/apps/services/license-api/src/app/modules/license/licenseV1.service.ts b/apps/services/license-api/src/app/modules/license/licenseV1.service.ts new file mode 100644 index 000000000000..be4d15ec92bc --- /dev/null +++ b/apps/services/license-api/src/app/modules/license/licenseV1.service.ts @@ -0,0 +1,413 @@ +import { + BaseLicenseUpdateClient, + LicenseType, + LicenseUpdateClientService, +} from '@island.is/clients/license-client' +import { Pass, PassDataInput, Result } from '@island.is/clients/smartsolutions' +import type { Logger } from '@island.is/logging' +import { LOGGER_PROVIDER } from '@island.is/logging' +import { + BarcodeService, + TOKEN_EXPIRED_ERROR, +} from '@island.is/services/license' +import { + BadRequestException, + Inject, + Injectable, + InternalServerErrorException, +} from '@nestjs/common' +import { isJSON, isJWT } from 'class-validator' +import { uuid } from 'uuidv4' +import { + RevokeLicenseRequest, + RevokeLicenseResponse, + UpdateLicenseRequest, + UpdateLicenseResponse, + VerifyLicenseRequest, + VerifyLicenseResponse, +} from './dto' +import { ErrorType, LicenseId } from './license.types' +import { mapLicenseIdToLicenseType } from './utils/mapLicenseId' + +const LOG_CATEGORY = 'license-api' + +@Injectable() +export class LicenseServiceV1 { + constructor( + @Inject(LOGGER_PROVIDER) private logger: Logger, + private readonly clientService: LicenseUpdateClientService, + private readonly barcodeService: BarcodeService, + ) {} + + private getErrorTypeByCode = (code: number): ErrorType => + code < 10 ? 'BadRequest' : 'ServerError' + + //Error message is an array to maintain consistency + private getException = (errorType: ErrorType, details?: string | object) => { + return errorType === 'BadRequest' + ? new BadRequestException([details ?? 'Unknown error']) + : new InternalServerErrorException([details ?? 'Unknown error']) + } + + private getLicenseUpdateClientByType = async ( + type: LicenseType, + requestId?: string, + ) => { + return this.clientService.getLicenseUpdateClientByType( + type as LicenseType, + requestId, + ) + } + private getLicenseUpdateClientByPassTemplateId = async ( + passTemplateId: string, + requestId?: string, + ) => { + return this.clientService.getLicenseUpdateClientByPassTemplateId( + passTemplateId, + requestId, + ) + } + + private generateRequestId = () => uuid() + + private async getClientByLicenseId( + licenseId: LicenseId, + requestId?: string, + ): Promise { + const type = mapLicenseIdToLicenseType(licenseId) + + this.logger.debug('Retrieving a licence client by license id', { + category: LOG_CATEGORY, + requestId: requestId, + type: type, + }) + + if (!type) { + this.logger.error(`Invalid license type`, { + category: LOG_CATEGORY, + requestId: requestId, + type, + }) + throw new InternalServerErrorException(`Invalid license type`) + } + + const service = await this.getLicenseUpdateClientByType( + type as LicenseType, + requestId, + ) + + this.logger.debug('Injecting the proper license client..', { + category: LOG_CATEGORY, + requestId: requestId, + type: type, + }) + + if (!service) { + this.logger.error(`Client service generation failed`, { + category: LOG_CATEGORY, + type, + }) + throw new InternalServerErrorException(`Client service generation failed`) + } + this.logger.debug('Client injection successful', { + category: LOG_CATEGORY, + requestId: requestId, + type: type, + }) + + return service + } + + private async getClientByPassTemplateId( + passTemplateId: string, + requestId?: string, + ): Promise { + this.logger.debug('Retrieving a licence client by pass template id', { + category: LOG_CATEGORY, + requestId: requestId, + passTemplateId, + }) + + const service = await this.getLicenseUpdateClientByPassTemplateId( + passTemplateId, + requestId, + ) + + this.logger.debug('Injecting the proper license client..', { + category: LOG_CATEGORY, + requestId: requestId, + passTemplateId, + }) + + if (!service) { + this.logger.error(`Client service generation failed`, { + category: LOG_CATEGORY, + requestId: requestId, + passTemplateId, + }) + throw new InternalServerErrorException(`Client service generation failed`) + } + + return service + } + + private async pushUpdateLicense( + service: BaseLicenseUpdateClient, + expirationDate: string, + nationalId: string, + payload?: string, + requestId?: string, + ): Promise> { + let updatePayload: PassDataInput = { + expirationDate, + } + + if (payload) { + let parsedInputPayload + try { + parsedInputPayload = JSON.parse(payload) + } catch (e) { + this.logger.warn('Unable to parse payload', { + category: LOG_CATEGORY, + updateType: 'push', + requestId, + }) + throw this.getException( + 'BadRequest', + 'Unable to parse payload for push update', + ) + } + updatePayload = { + ...updatePayload, + ...parsedInputPayload, + } + } + + this.logger.debug('Update input parse successful, executing update', { + category: LOG_CATEGORY, + updateType: 'push', + requestId, + }) + + return await service.pushUpdate(updatePayload, nationalId, requestId) + } + + private async pullUpdateLicense( + service: BaseLicenseUpdateClient, + nationalId: string, + requestId?: string, + ): Promise> { + /** PULL - Update electronic license with pulled data from service + * 1. Fetch data from provider + * 2. Parse and validate license data + * 3. With good data, update the electronic license with the validated license data! + */ + + this.logger.debug('Executing update', { + category: LOG_CATEGORY, + updateType: 'pull', + requestId, + }) + + return await service.pullUpdate(nationalId, requestId) + } + + async updateLicense( + licenseId: LicenseId, + nationalId: string, + inputData: UpdateLicenseRequest, + ): Promise { + const requestId = inputData.requestId ?? this.generateRequestId() + + const service = await this.getClientByLicenseId(licenseId, requestId) + + this.logger.debug('License update initiated', { + category: LOG_CATEGORY, + requestId, + updateType: inputData.licenseUpdateType, + }) + + let updateRes: Result + if (inputData.licenseUpdateType === 'push') { + const { expiryDate, payload } = inputData + + if (!expiryDate) { + this.logger.warn('Invalid request body, missing expiryDate', { + category: LOG_CATEGORY, + requestId, + updateType: inputData.licenseUpdateType, + }) + + throw this.getException( + 'BadRequest', + 'Invalid request body, missing expiryDate', + ) + } + updateRes = await this.pushUpdateLicense( + service, + expiryDate, + nationalId, + payload, + requestId, + ) + } else { + updateRes = await this.pullUpdateLicense(service, nationalId, requestId) + } + + if (updateRes.ok) { + this.logger.info('License update successful', { + category: LOG_CATEGORY, + requestId, + updateType: inputData.licenseUpdateType, + }) + return { + updateSuccess: true, + data: updateRes.data, + } + } + + this.logger.error('License update failed', { + category: LOG_CATEGORY, + requestId, + error: updateRes.error, + }) + + throw this.getException( + this.getErrorTypeByCode(updateRes.error.code), + updateRes.error.message, + ) + } + + async revokeLicense( + licenseId: LicenseId, + nationalId: string, + inputData?: RevokeLicenseRequest, + ): Promise { + const requestId = inputData?.requestId ?? this.generateRequestId() + const service = await this.getClientByLicenseId(licenseId, requestId) + + const revokeRes = await service.revoke(nationalId, requestId) + + this.logger.debug('License revoking initiated', { + category: LOG_CATEGORY, + requestId, + }) + + if (revokeRes.ok) { + this.logger.info('License revoked successfully', { + category: LOG_CATEGORY, + requestId, + }) + return { revokeSuccess: revokeRes.data.success } + } + + this.logger.error('License revoke failure', { + category: LOG_CATEGORY, + requestId, + error: revokeRes.error, + }) + throw this.getException( + this.getErrorTypeByCode(revokeRes.error.code), + revokeRes.error.message, + ) + } + + async getDataFromToken( + token: string, + requestId: string, + ): Promise { + try { + const { c } = await this.barcodeService.verifyToken(token) + const data = await this.barcodeService.getCache(c) + + if (!data) { + this.logger.error('No data found in cache', { + category: LOG_CATEGORY, + requestId, + }) + + return { + valid: false, + } + } + + return { + valid: true, + ...(data.extraData && { passIdentity: data.extraData }), + } + } catch (error) { + if (error.name === TOKEN_EXPIRED_ERROR) { + return { + valid: false, + } + } + this.logger.error(error.message, { + category: LOG_CATEGORY, + requestId, + error, + }) + + throw new BadRequestException(error.message) + } + } + + async verifyLicense( + inputData: VerifyLicenseRequest, + ): Promise { + const requestId = inputData?.requestId ?? this.generateRequestId() + + if (isJWT(inputData.barcodeData)) { + return this.getDataFromToken(inputData.barcodeData, requestId) + } + + if (!isJSON(inputData.barcodeData)) { + const jsonErrorMsg = 'Barcode data must be in JSON format' + this.logger.warn(jsonErrorMsg, { + category: LOG_CATEGORY, + requestId, + }) + + throw new BadRequestException(jsonErrorMsg) + } + + const { passTemplateId } = JSON.parse(inputData.barcodeData) + + this.logger.debug('License verification initiated', { + category: LOG_CATEGORY, + requestId, + }) + + if (!passTemplateId) { + this.logger.warn('No pass template id supplied', { + category: LOG_CATEGORY, + requestId, + }) + throw this.getException('BadRequest', 'Missing pass template id') + } + + const service = await this.getClientByPassTemplateId(passTemplateId) + + const verifyRes = await service.verify(inputData.barcodeData, requestId) + + if (verifyRes.ok) { + this.logger.info('License verified successfully', { + category: LOG_CATEGORY, + requestId, + }) + return { + valid: verifyRes.data.valid, + passIdentity: verifyRes.data.passIdentity, + } + } + this.logger.error('Verify license failure', { + category: LOG_CATEGORY, + error: verifyRes.error, + requestId, + }) + + throw this.getException(this.getErrorTypeByCode(verifyRes.error.code), { + message: verifyRes.error.message, + requestId, + }) + } +} diff --git a/apps/services/license-api/src/app/modules/license/licenseV2.service.ts b/apps/services/license-api/src/app/modules/license/licenseV2.service.ts new file mode 100644 index 000000000000..804a1d1efed0 --- /dev/null +++ b/apps/services/license-api/src/app/modules/license/licenseV2.service.ts @@ -0,0 +1,414 @@ +import { + BaseLicenseUpdateClientV2, + LicenseType, + LicenseUpdateClientService, + PassData, + PassDataInput, + Result, +} from '@island.is/clients/license-client' +import type { Logger } from '@island.is/logging' +import { LOGGER_PROVIDER } from '@island.is/logging' +import { + BarcodeService, + TOKEN_EXPIRED_ERROR, +} from '@island.is/services/license' +import { + BadRequestException, + Inject, + Injectable, + InternalServerErrorException, +} from '@nestjs/common' +import { isJSON, isJWT } from 'class-validator' +import { uuid } from 'uuidv4' +import { + RevokeLicenseRequest, + RevokeLicenseResponse, + UpdateLicenseRequest, + UpdateLicenseResponse, + VerifyLicenseRequest, + VerifyLicenseResponse, +} from './dto' +import { ErrorType, LicenseId } from './license.types' +import { mapLicenseIdToLicenseType } from './utils/mapLicenseId' + +const LOG_CATEGORY = 'license-api' + +@Injectable() +export class LicenseServiceV2 { + constructor( + @Inject(LOGGER_PROVIDER) private logger: Logger,, + private readonly clientService: LicenseUpdateClientService, + private readonly barcodeService: BarcodeService, + ) {} + + private getErrorTypeByCode = (code: number): ErrorType => + code < 10 ? 'BadRequest' : 'ServerError' + + //Error message is an array to maintain consistency + private getException = (errorType: ErrorType, details?: string | object) => { + return errorType === 'BadRequest' + ? new BadRequestException([details ?? 'Unknown error']) + : new InternalServerErrorException([details ?? 'Unknown error']) + } + + private getLicenseUpdateClientByType = async ( + type: LicenseType, + requestId?: string, + ) => { + return this.clientService.getLicenseUpdateClientV2ByType( + type as LicenseType, + requestId, + ) + } + private getLicenseUpdateClientByPassTemplateId = async ( + passTemplateId: string, + requestId?: string, + ) => { + return this.clientService.getLicenseUpdateClientV2ByPassTemplateId( + passTemplateId, + requestId, + ) + } + + private generateRequestId = () => uuid() + + private async getClientByLicenseId( + licenseId: LicenseId, + requestId?: string, + ): Promise { + const type = mapLicenseIdToLicenseType(licenseId) + + this.logger.debug('Retrieving a licence client by license id', { + category: LOG_CATEGORY, + requestId: requestId, + type: type, + }) + + if (!type) { + this.logger.error(`Invalid license type`, { + category: LOG_CATEGORY, + requestId: requestId, + type, + }) + throw new InternalServerErrorException(`Invalid license type`) + } + + const service = await this.getLicenseUpdateClientByType( + type as LicenseType, + requestId, + ) + + this.logger.debug('Injecting the proper license client..', { + category: LOG_CATEGORY, + requestId: requestId, + type: type, + }) + + if (!service) { + this.logger.error(`Client service generation failed`, { + category: LOG_CATEGORY, + type, + }) + throw new InternalServerErrorException(`Client service generation failed`) + } + this.logger.debug('Client injection successful', { + category: LOG_CATEGORY, + requestId: requestId, + type: type, + }) + + return service + } + + private async getClientByPassTemplateId( + passTemplateId: string, + requestId?: string, + ): Promise { + this.logger.debug('Retrieving a licence client by pass template id', { + category: LOG_CATEGORY, + requestId: requestId, + passTemplateId, + }) + + const service = await this.getLicenseUpdateClientByPassTemplateId( + passTemplateId, + requestId, + ) + + this.logger.debug('Injecting the proper license client..', { + category: LOG_CATEGORY, + requestId: requestId, + passTemplateId, + }) + + if (!service) { + this.logger.error(`Client service generation failed`, { + category: LOG_CATEGORY, + requestId: requestId, + passTemplateId, + }) + throw new InternalServerErrorException(`Client service generation failed`) + } + + return service + } + + private async pushUpdateLicense( + service: BaseLicenseUpdateClientV2, + expirationDate: string, + nationalId: string, + payload?: string, + requestId?: string, + ): Promise> { + let updatePayload: PassDataInput = { + expirationDate, + } + if (payload) { + let parsedInputPayload + try { + parsedInputPayload = JSON.parse(payload) + } catch (e) { + this.logger.warn('Unable to parse payload', { + category: LOG_CATEGORY, + updateType: 'push', + requestId, + }) + throw this.getException( + 'BadRequest', + 'Unable to parse payload for push update', + ) + } + updatePayload = { + ...updatePayload, + ...parsedInputPayload, + } + } + + this.logger.debug('Update input parse successful, executing update', { + category: LOG_CATEGORY, + updateType: 'push', + version: requestId, + }) + + return await service.pushUpdate(updatePayload, nationalId, requestId) + } + + private async pullUpdateLicense( + service: BaseLicenseUpdateClientV2, + nationalId: string, + requestId?: string, + ): Promise> { + /** PULL - Update electronic license with pulled data from service + * 1. Fetch data from provider + * 2. Parse and validate license data + * 3. With good data, update the electronic license with the validated license data! + */ + + this.logger.debug('Executing update', { + category: LOG_CATEGORY, + updateType: 'pull', + requestId, + }) + + return await service.pullUpdate(nationalId, requestId) + } + + async updateLicense( + licenseId: LicenseId, + nationalId: string, + inputData: UpdateLicenseRequest, + ): Promise { + const requestId = inputData.requestId ?? this.generateRequestId() + + const service = await this.getClientByLicenseId(licenseId, requestId) + + this.logger.debug('License update initiated', { + category: LOG_CATEGORY, + requestId, + updateType: inputData.licenseUpdateType, + }) + + let updateRes: Result + if (inputData.licenseUpdateType === 'push') { + const { expiryDate, payload } = inputData + + if (!expiryDate) { + this.logger.warn('Invalid request body, missing expiryDate', { + category: LOG_CATEGORY, + requestId, + updateType: inputData.licenseUpdateType, + }) + + throw this.getException( + 'BadRequest', + 'Invalid request body, missing expiryDate', + ) + } + updateRes = await this.pushUpdateLicense( + service, + expiryDate, + nationalId, + payload, + requestId, + ) + } else { + updateRes = await this.pullUpdateLicense(service, nationalId, requestId) + } + + if (updateRes.ok) { + this.logger.info('License update successful', { + category: LOG_CATEGORY, + requestId, + updateType: inputData.licenseUpdateType, + }) + return { + updateSuccess: true, + data: updateRes.data, + } + } + + this.logger.error('License update failed', { + category: LOG_CATEGORY, + requestId, + error: updateRes.error, + }) + + throw this.getException( + this.getErrorTypeByCode(updateRes.error.code), + updateRes.error.message, + ) + } + + async revokeLicense( + licenseId: LicenseId, + nationalId: string, + inputData?: RevokeLicenseRequest, + ): Promise { + const requestId = inputData?.requestId ?? this.generateRequestId() + const service = await this.getClientByLicenseId(licenseId, requestId) + + const revokeRes = await service.revoke(nationalId, requestId) + + this.logger.debug('License revoking initiated', { + category: LOG_CATEGORY, + requestId, + }) + + if (revokeRes.ok) { + this.logger.info('License revoked successfully', { + category: LOG_CATEGORY, + requestId, + }) + return { revokeSuccess: revokeRes.data.success } + } + + this.logger.error('License revoke failure', { + category: LOG_CATEGORY, + requestId, + error: revokeRes.error, + }) + throw this.getException( + this.getErrorTypeByCode(revokeRes.error.code), + revokeRes.error.message, + ) + } + + async getDataFromToken( + token: string, + requestId: string, + ): Promise { + try { + const { c } = await this.barcodeService.verifyToken(token) + const data = await this.barcodeService.getCache(c) + + if (!data) { + this.logger.error('No data found in cache', { + category: LOG_CATEGORY, + requestId, + }) + + return { + valid: false, + } + } + + return { + valid: true, + ...(data.extraData && { passIdentity: data.extraData }), + } + } catch (error) { + if (error.name === TOKEN_EXPIRED_ERROR) { + return { + valid: false, + } + } + this.logger.error(error.message, { + category: LOG_CATEGORY, + requestId, + error, + }) + + throw new BadRequestException(error.message) + } + } + + async verifyLicense( + inputData: VerifyLicenseRequest, + ): Promise { + const requestId = inputData?.requestId ?? this.generateRequestId() + + if (isJWT(inputData.barcodeData)) { + return this.getDataFromToken(inputData.barcodeData, requestId) + } + + if (!isJSON(inputData.barcodeData)) { + const jsonErrorMsg = 'Barcode data must be in JSON format' + this.logger.warn(jsonErrorMsg, { + category: LOG_CATEGORY, + requestId, + }) + + throw new BadRequestException(jsonErrorMsg) + } + + const { passTemplateId } = JSON.parse(inputData.barcodeData) + + this.logger.debug('License verification initiated', { + category: LOG_CATEGORY, + requestId, + }) + + if (!passTemplateId) { + this.logger.warn('No pass template id supplied', { + category: LOG_CATEGORY, + requestId, + }) + throw this.getException('BadRequest', 'Missing pass template id') + } + + const service = await this.getClientByPassTemplateId(passTemplateId) + + const verifyRes = await service.verify(inputData.barcodeData, requestId) + + if (verifyRes.ok) { + this.logger.info('License verified successfully', { + category: LOG_CATEGORY, + requestId, + }) + return { + valid: verifyRes.data.valid, + passIdentity: verifyRes.data.passIdentity, + } + } + this.logger.error('Verify license failure', { + category: LOG_CATEGORY, + error: verifyRes.error, + requestId, + }) + + throw this.getException(this.getErrorTypeByCode(verifyRes.error.code), { + message: verifyRes.error.message, + requestId, + }) + } +} diff --git a/libs/clients/license-client/src/index.ts b/libs/clients/license-client/src/index.ts index 3bfd7111fb62..a896b8ab4a15 100644 --- a/libs/clients/license-client/src/index.ts +++ b/libs/clients/license-client/src/index.ts @@ -2,9 +2,11 @@ export { LicenseClientModule } from './lib/licenseClient.module' export { LicenseUpdateClientModule } from './lib/licenseUpdateClient.module' export { LicenseClientService } from './lib/licenseClient.service' export { LicenseUpdateClientService } from './lib/licenseUpdateClient.service' -export { BaseLicenseUpdateClient } from './lib/clients/baseLicenseUpdateClient' +export { BaseLicenseUpdateClient } from './lib/clients/base/baseLicenseUpdateClient' +export { BaseLicenseUpdateClientV2 } from './lib/clients/base/licenseUpdateClientV2' export { LicenseType, + Result, LicenseClient, LicenseVerifyExtraDataResult, VerifyExtraDataResult, diff --git a/libs/clients/license-client/src/lib/clients/base/baseLicenseUpdateClient.ts b/libs/clients/license-client/src/lib/clients/base/baseLicenseUpdateClient.ts index 186768ceaa6c..d27cb08b8b48 100644 --- a/libs/clients/license-client/src/lib/clients/base/baseLicenseUpdateClient.ts +++ b/libs/clients/license-client/src/lib/clients/base/baseLicenseUpdateClient.ts @@ -3,10 +3,11 @@ import { Injectable } from '@nestjs/common' import { Pass, PassDataInput, + Result, RevokePassData, SmartSolutionsApi, } from '@island.is/clients/smartsolutions' -import { PassVerificationData, Result } from '../licenseClient.type' +import { PassVerificationData } from '../../licenseClient.type' @Injectable() export abstract class BaseLicenseUpdateClient { diff --git a/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClientV2.service.ts b/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClientV2.service.ts index cf62a97285c0..5d809003cf04 100644 --- a/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClientV2.service.ts +++ b/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClientV2.service.ts @@ -9,8 +9,8 @@ import { Result, VerifyInputData, } from '../../../licenseClient.type' -import { PkPassService } from '../../pk-pass-client/pkPass.service' import { BaseLicenseUpdateClientV2 } from '../../base/licenseUpdateClientV2' +import { PkPassService } from '../../../helpers/pkPassService/pkPass.service' @Injectable() export class DisabilityLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { diff --git a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts index dc0bf1ee618b..27f381fd468f 100644 --- a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts +++ b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts @@ -18,7 +18,7 @@ import { } from '../drivingLicenseMapper' import { DrivingDigitalLicenseClientConfig } from '../drivingLicenseClient.config' import { BaseLicenseUpdateClientV2 } from '../../base/licenseUpdateClientV2' -import { PkPassService } from '../../pk-pass-client/pkPass.service' +import { PkPassService } from '../../../helpers/pkPassService/pkPass.service' /** Category to attach each log message to */ const LOG_CATEGORY = 'driving-license-service' diff --git a/libs/clients/license-client/src/lib/clients/firearm-license-client/modules/firearmLicenseUpdateClient.module.ts b/libs/clients/license-client/src/lib/clients/firearm-license-client/modules/firearmLicenseUpdateClient.module.ts index bf5038057445..622b0ea7136b 100644 --- a/libs/clients/license-client/src/lib/clients/firearm-license-client/modules/firearmLicenseUpdateClient.module.ts +++ b/libs/clients/license-client/src/lib/clients/firearm-license-client/modules/firearmLicenseUpdateClient.module.ts @@ -1,17 +1,17 @@ import { Module } from '@nestjs/common' import { FirearmLicenseUpdateClientModule } from '@island.is/clients/firearm-license' import { SmartSolutionsFirearmModule } from './smartSolutionsFirearm.module' -import { PkPassModule } from '../../pk-pass-client/pkPass.module' -import { FirearmLicenseUpdateClient } from '../services/firearmLicenseUpdateClient.service' import { FirearmLicenseUpdateClientV2 } from '../services/firearmLicenseUpdateClientV2.service' +import { FirearmLicenseUpdateClient } from '../services/firearmLicenseUpdateClient.service' +import { PkPassService } from '../../../helpers/pkPassService/pkPass.service' @Module({ - imports: [ - FirearmLicenseUpdateClientModule, - SmartSolutionsFirearmModule, - PkPassModule, + imports: [FirearmLicenseUpdateClientModule, SmartSolutionsFirearmModule], + providers: [ + PkPassService, + FirearmLicenseUpdateClient, + FirearmLicenseUpdateClientV2, ], - providers: [FirearmLicenseUpdateClient, FirearmLicenseUpdateClientV2], exports: [FirearmLicenseUpdateClient, FirearmLicenseUpdateClientV2], }) export class FirearmUpdateClientModule {} diff --git a/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClientV2.service.ts b/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClientV2.service.ts index c796bdef7763..7f147716e860 100644 --- a/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClientV2.service.ts +++ b/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClientV2.service.ts @@ -16,7 +16,7 @@ import { mapNationalId } from '../firearmLicenseMapper' import type { ConfigType } from '@island.is/nest/config' import { FirearmDigitalLicenseClientConfig } from '../firearmLicenseClient.config' import { BaseLicenseUpdateClientV2 } from '../../base/licenseUpdateClientV2' -import { PkPassService } from '../../pk-pass-client/pkPass.service' +import { PkPassService } from '../../../helpers/pkPassService/pkPass.service' /** Category to attach each log message to */ const LOG_CATEGORY = 'firearmlicense-service' diff --git a/libs/clients/license-client/src/lib/clients/machine-license-client/machineLicenseClient.module.ts b/libs/clients/license-client/src/lib/clients/machine-license-client/machineLicenseClient.module.ts index f26612b543db..77f04303b291 100644 --- a/libs/clients/license-client/src/lib/clients/machine-license-client/machineLicenseClient.module.ts +++ b/libs/clients/license-client/src/lib/clients/machine-license-client/machineLicenseClient.module.ts @@ -1,12 +1,11 @@ import { AdrAndMachineLicenseClientModule } from '@island.is/clients/adr-and-machine-license' -import { - SmartSolutionsApiClientModule, - SmartSolutionsConfig, -} from '@island.is/clients/smartsolutions' import { Module } from '@nestjs/common' import { ConfigType } from '@island.is/nest/config' import { MachineLicenseClient } from './machineLicenseClient.service' import { MachineDigitalLicenseClientConfig } from './machineLicenseClient.config' +import { SmartSolutionsApiClientModule } from '@island.is/clients/smartsolutions' +import { SmartSolutionsModule } from '@island.is/clients/smart-solutions-v2' +import { PkPassService } from '../../helpers/pkPassService/pkPass.service' @Module({ imports: [ @@ -14,18 +13,19 @@ import { MachineDigitalLicenseClientConfig } from './machineLicenseClient.config SmartSolutionsApiClientModule.registerAsync({ useFactory: ( config: ConfigType, - ) => { - const smartConfig: SmartSolutionsConfig = { - apiKey: config.apiKey, - apiUrl: config.apiUrl, - passTemplateId: config.passTemplateId, - } - return smartConfig - }, + ) => config, + inject: [MachineDigitalLicenseClientConfig.KEY], + }), + SmartSolutionsModule.registerAsync({ + useFactory: ( + config: ConfigType, + ) => ({ + config, + }), inject: [MachineDigitalLicenseClientConfig.KEY], }), ], - providers: [MachineLicenseClient], + providers: [PkPassService, MachineLicenseClient], exports: [MachineLicenseClient], }) export class MachineClientModule {} diff --git a/libs/clients/license-client/src/lib/clients/machine-license-client/machineLicenseClient.service.ts b/libs/clients/license-client/src/lib/clients/machine-license-client/machineLicenseClient.service.ts index f49c370c883b..3db93fe75a9a 100644 --- a/libs/clients/license-client/src/lib/clients/machine-license-client/machineLicenseClient.service.ts +++ b/libs/clients/license-client/src/lib/clients/machine-license-client/machineLicenseClient.service.ts @@ -11,20 +11,18 @@ import { findLatestExpirationDate, } from './machineLicenseMapper' import { FetchError } from '@island.is/clients/middlewares' -import { - Pass, - PassDataInput, - SmartSolutionsApi, -} from '@island.is/clients/smartsolutions' import { Locale } from '@island.is/shared/types' import { LicenseClient, LicensePkPassAvailability, LicenseType, + PassData, + PassDataInput, PkPassVerificationInputData, Result, VerifyPkPassResult, } from '../../licenseClient.type' +import { PkPassService } from '../../helpers/pkPassService/pkPass.service' /** Category to attach each log message to */ const LOG_CATEGORY = 'machinelicense-service' @@ -36,7 +34,7 @@ export class MachineLicenseClient constructor( @Inject(LOGGER_PROVIDER) private logger: Logger, private machineApi: VinnuvelaApi, - private smartApi: SmartSolutionsApi, + private passService: PkPassService, ) {} clientSupportsPkPass = true @@ -150,11 +148,14 @@ export class MachineLicenseClient if (!inputValues) return null return { inputFieldValues: inputValues, - expirationDate: findLatestExpirationDate(license.data), + expirationDate: findLatestExpirationDate(license.data) ?? undefined, } } - async getPkPass(user: User, locale: Locale = 'is'): Promise> { + async getPkPass( + user: User, + locale: Locale = 'is', + ): Promise> { const license = await this.fetchLicense(user) if (!license.ok || !license.data) { this.logger.info( @@ -194,7 +195,7 @@ export class MachineLicenseClient } } - const pass = await this.smartApi.generatePkPass(payload) + const pass = await this.passService.generatePkPass(payload) return pass } @@ -259,7 +260,7 @@ export class MachineLicenseClient data: string, ): Promise>> { const { code, date } = JSON.parse(data) as PkPassVerificationInputData - const result = await this.smartApi.verifyPkPass({ code, date }) + const result = await this.passService.verifyPkPass({ code, date }) if (!result.ok) { return result diff --git a/libs/clients/license-client/src/lib/clients/pk-pass-client/PkPassService.ts b/libs/clients/license-client/src/lib/clients/pk-pass-client/PkPassService.ts deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.module-definition.ts b/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.module-definition.ts deleted file mode 100644 index 0c49e3882721..000000000000 --- a/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.module-definition.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ConfigurableModuleBuilder } from '@nestjs/common' -import { PkPassModuleOptions } from './pkPass.types' - -export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } = - new ConfigurableModuleBuilder().build() diff --git a/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.module.ts b/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.module.ts deleted file mode 100644 index 784221ffcc5e..000000000000 --- a/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.module.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { SmartSolutionsApiClientModule } from '@island.is/clients/smartsolutions' -import { SmartSolutionsModule } from '@island.is/clients/smart-solutions-v2' -import { - ConfigurableModuleClass, - MODULE_OPTIONS_TOKEN, -} from './pkPass.module-definition' -import { PkPassModuleOptions } from './pkPass.types' -import { Module } from '@nestjs/common' -import { PkPassService } from './pkPass.service' -import { FeatureFlagModule } from '@island.is/nest/feature-flags' - -@Module({ - imports: [ - FeatureFlagModule, - SmartSolutionsModule.registerAsync({ - useFactory: (options: PkPassModuleOptions) => { - return { config: options.config } - }, - inject: [MODULE_OPTIONS_TOKEN], - }), - SmartSolutionsApiClientModule.registerAsync({ - useFactory: (options: PkPassModuleOptions) => { - return options.config - }, - inject: [MODULE_OPTIONS_TOKEN], - }), - ], - providers: [PkPassService], -}) -export class PkPassModule extends ConfigurableModuleClass {} diff --git a/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.mapper.ts b/libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.mapper.ts similarity index 100% rename from libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.mapper.ts rename to libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.mapper.ts diff --git a/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.service.ts b/libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.service.ts similarity index 93% rename from libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.service.ts rename to libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.service.ts index 53307923aa95..c1d311adca1e 100644 --- a/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.service.ts +++ b/libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.service.ts @@ -1,6 +1,3 @@ -import { LOGGER_PROVIDER, type Logger } from '@island.is/logging' -import { VerifyPassData, VerifyPkPassDataInput } from './pkPass.types' -import { Inject } from '@nestjs/common' import { SmartSolutionsApi } from '@island.is/clients/smartsolutions' import { SmartSolutionsService } from '@island.is/clients/smart-solutions-v2' import { FeatureFlagService, Features } from '@island.is/nest/feature-flags' @@ -10,12 +7,11 @@ import { PassRevocationData, Result, } from '../../licenseClient.type' +import { VerifyPassData, VerifyPkPassDataInput } from './pkPass.types' import { mapPassData } from './pkPass.mapper' export class PkPassService { constructor( - @Inject(LOGGER_PROVIDER) - private readonly logger: Logger, private readonly featureFlagService: FeatureFlagService, private readonly newSmartService: SmartSolutionsService, /** DEPRECATED */ diff --git a/libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.types.ts b/libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.types.ts similarity index 100% rename from libs/clients/license-client/src/lib/clients/pk-pass-client/pkPass.types.ts rename to libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.types.ts diff --git a/libs/clients/license-client/src/lib/licenseUpdateClient.module.ts b/libs/clients/license-client/src/lib/licenseUpdateClient.module.ts index eec0a896b24f..69401bc5961c 100644 --- a/libs/clients/license-client/src/lib/licenseUpdateClient.module.ts +++ b/libs/clients/license-client/src/lib/licenseUpdateClient.module.ts @@ -15,7 +15,7 @@ import { DisabilityUpdateClientModule, } from './clients/disability-license-client' import { PassTemplateIdsProvider } from './providers/passTemplateIdsProvider' -import { BaseLicenseUpdateClient } from './clients/baseLicenseUpdateClient' +import { BaseLicenseUpdateClient } from './clients/base/baseLicenseUpdateClient' import { DrivingLicenseUpdateClient, DrivingUpdateClientModule, diff --git a/libs/clients/license-client/src/lib/licenseUpdateClient.service.ts b/libs/clients/license-client/src/lib/licenseUpdateClient.service.ts index 2dfe6c7bbe5a..5f098dfa3af7 100644 --- a/libs/clients/license-client/src/lib/licenseUpdateClient.service.ts +++ b/libs/clients/license-client/src/lib/licenseUpdateClient.service.ts @@ -69,26 +69,30 @@ export class LicenseUpdateClientService { return this.config[licenseId] } - getLicenseUpdateClientByType( - type: LicenseType, - requestId?: string, - version?: 'v1' | 'v2', - ) { - if (version === 'v2') { - return this.licenseUpdateClientFactoryV2(type, requestId) - } + //DEPRECATED + getLicenseUpdateClientByType(type: LicenseType, requestId?: string) { return this.licenseUpdateClientFactory(type, requestId) } + getLicenseUpdateClientV2ByType(type: LicenseType, requestId?: string) { + return this.licenseUpdateClientFactoryV2(type, requestId) + } + + //DEPRECATED getLicenseUpdateClientByPassTemplateId( passTemplateId: string, requestId?: string, - version?: 'v1' | 'v2', ) { const type = this.getTypeByPassTemplateId(passTemplateId, requestId) - return type - ? this.getLicenseUpdateClientByType(type, requestId, version) - : null + return type ? this.getLicenseUpdateClientByType(type, requestId) : null + } + getLicenseUpdateClientV2ByPassTemplateId( + passTemplateId: string, + requestId?: string, + ) { + const type = this.getTypeByPassTemplateId(passTemplateId, requestId) + + return type ? this.getLicenseUpdateClientV2ByType(type, requestId) : null } } diff --git a/libs/clients/smart-solutions-v2/src/index.ts b/libs/clients/smart-solutions-v2/src/index.ts index eee4a1511202..ab09215a595b 100644 --- a/libs/clients/smart-solutions-v2/src/index.ts +++ b/libs/clients/smart-solutions-v2/src/index.ts @@ -1,6 +1,6 @@ export { SmartSolutionsModule } from './lib/smartSolutions.module' export { SmartSolutionsService } from './lib/smartSolutions.service' export { SmartSolutionsConfig } from './lib/smartSolutions.config' -export { PkPass, RevokePassData } from './lib/types/responses.type' +export { RevokePassData } from './lib/types/responses.type' export { Result } from './lib/types/result.type' export * from '../gen/schema' From 01b53f29367230189eca35704b9c9fb3dfb5cb2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Tue, 8 Oct 2024 15:11:18 +0000 Subject: [PATCH 09/29] fix: works --- .../services/license-api/src/app/app.module.ts | 3 +++ .../src/app/modules/license/license.module.ts | 4 ++++ .../app/modules/license/licenseV2.service.ts | 2 +- .../disabilityLicenseUpdateClient.module.ts | 18 +++++++++++++++++- .../modules/drivingLicenseClient.module.ts | 2 +- .../drivingLicenseUpdateClient.module.ts | 18 +++++++++++++++++- .../firearmLicenseUpdateClient.module.ts | 18 +++++++++++++++++- .../machineLicenseClient.module.ts | 2 ++ .../helpers/pkPassService/pkPass.service.ts | 2 ++ 9 files changed, 64 insertions(+), 5 deletions(-) diff --git a/apps/services/license-api/src/app/app.module.ts b/apps/services/license-api/src/app/app.module.ts index 20e44d2b3548..a0aa92f003dc 100644 --- a/apps/services/license-api/src/app/app.module.ts +++ b/apps/services/license-api/src/app/app.module.ts @@ -9,6 +9,8 @@ import { DrivingDigitalLicenseClientConfig, HuntingDigitalLicenseClientConfig, } from '@island.is/clients/license-client' +import { FeatureFlagConfig } from '@island.is/nest/feature-flags' + import { LoggingModule } from '@island.is/logging' import { AuditModule } from '@island.is/nest/audit' @@ -39,6 +41,7 @@ import { LicenseModule } from './modules/license/license.module' MachineDigitalLicenseClientConfig, HuntingDigitalLicenseClientConfig, LicenseConfig, + FeatureFlagConfig, ], }), LicenseModule, diff --git a/apps/services/license-api/src/app/modules/license/license.module.ts b/apps/services/license-api/src/app/modules/license/license.module.ts index d8c31e97614b..8969b14abeda 100644 --- a/apps/services/license-api/src/app/modules/license/license.module.ts +++ b/apps/services/license-api/src/app/modules/license/license.module.ts @@ -8,6 +8,8 @@ import { } from './license.controller' import { LicenseService } from './license.service' import { FeatureFlagModule } from '@island.is/nest/feature-flags' +import { LicenseServiceV1 } from './licenseV1.service' +import { LicenseServiceV2 } from './licenseV2.service' @Module({ imports: [LicenseUpdateClientModule, LicenseCommonModule, FeatureFlagModule], @@ -18,6 +20,8 @@ import { FeatureFlagModule } from '@island.is/nest/feature-flags' useValue: logger, }, LicenseService, + LicenseServiceV1, + LicenseServiceV2, ], }) export class LicenseModule {} diff --git a/apps/services/license-api/src/app/modules/license/licenseV2.service.ts b/apps/services/license-api/src/app/modules/license/licenseV2.service.ts index 804a1d1efed0..58e58851c0c9 100644 --- a/apps/services/license-api/src/app/modules/license/licenseV2.service.ts +++ b/apps/services/license-api/src/app/modules/license/licenseV2.service.ts @@ -36,7 +36,7 @@ const LOG_CATEGORY = 'license-api' @Injectable() export class LicenseServiceV2 { constructor( - @Inject(LOGGER_PROVIDER) private logger: Logger,, + @Inject(LOGGER_PROVIDER) private logger: Logger, private readonly clientService: LicenseUpdateClientService, private readonly barcodeService: BarcodeService, ) {} diff --git a/libs/clients/license-client/src/lib/clients/disability-license-client/modules/disabilityLicenseUpdateClient.module.ts b/libs/clients/license-client/src/lib/clients/disability-license-client/modules/disabilityLicenseUpdateClient.module.ts index 322999b1d61e..88e5f9486251 100644 --- a/libs/clients/license-client/src/lib/clients/disability-license-client/modules/disabilityLicenseUpdateClient.module.ts +++ b/libs/clients/license-client/src/lib/clients/disability-license-client/modules/disabilityLicenseUpdateClient.module.ts @@ -4,17 +4,33 @@ import { ConfigType } from '@island.is/nest/config' import { DisabilityDigitalLicenseClientConfig } from '../disabilityLicenseClient.config' import { DisabilityLicenseUpdateClient } from '../services/disabilityLicenseUpdateClient.service' import { DisabilityLicenseUpdateClientV2 } from '../services/disabilityLicenseUpdateClientV2.service' +import { PkPassService } from '../../../helpers/pkPassService/pkPass.service' +import { FeatureFlagModule } from '@island.is/nest/feature-flags' +import { SmartSolutionsModule } from '@island.is/clients/smart-solutions-v2' @Module({ imports: [ + FeatureFlagModule, SmartSolutionsApiClientModule.registerAsync({ useFactory: ( config: ConfigType, ) => config, inject: [DisabilityDigitalLicenseClientConfig.KEY], }), + SmartSolutionsModule.registerAsync({ + useFactory: ( + config: ConfigType, + ) => ({ + config, + }), + inject: [DisabilityDigitalLicenseClientConfig.KEY], + }), + ], + providers: [ + PkPassService, + DisabilityLicenseUpdateClient, + DisabilityLicenseUpdateClientV2, ], - providers: [DisabilityLicenseUpdateClient, DisabilityLicenseUpdateClientV2], exports: [DisabilityLicenseUpdateClient, DisabilityLicenseUpdateClientV2], }) export class DisabilityUpdateClientModule {} diff --git a/libs/clients/license-client/src/lib/clients/driving-license-client/modules/drivingLicenseClient.module.ts b/libs/clients/license-client/src/lib/clients/driving-license-client/modules/drivingLicenseClient.module.ts index 3a2f4afb5e64..acc33acaaebd 100644 --- a/libs/clients/license-client/src/lib/clients/driving-license-client/modules/drivingLicenseClient.module.ts +++ b/libs/clients/license-client/src/lib/clients/driving-license-client/modules/drivingLicenseClient.module.ts @@ -8,8 +8,8 @@ import { FeatureFlagModule } from '@island.is/nest/feature-flags' @Module({ imports: [ - DrivingLicenseApiModule, FeatureFlagModule, + DrivingLicenseApiModule, SmartSolutionsApiClientModule.registerAsync({ useFactory: ( config: ConfigType, diff --git a/libs/clients/license-client/src/lib/clients/driving-license-client/modules/drivingLicenseUpdateClient.module.ts b/libs/clients/license-client/src/lib/clients/driving-license-client/modules/drivingLicenseUpdateClient.module.ts index 790a3b1fb09f..baea1bac5191 100644 --- a/libs/clients/license-client/src/lib/clients/driving-license-client/modules/drivingLicenseUpdateClient.module.ts +++ b/libs/clients/license-client/src/lib/clients/driving-license-client/modules/drivingLicenseUpdateClient.module.ts @@ -5,9 +5,13 @@ import { DrivingLicenseUpdateClient } from '../services/drivingLicenseUpdateClie import { DrivingDigitalLicenseClientConfig } from '../drivingLicenseClient.config' import { DrivingLicenseApiModule } from '@island.is/clients/driving-license' import { DrivingLicenseUpdateClientV2 } from '../services/drivingLicenseUpdateClientV2.service' +import { PkPassService } from '../../../helpers/pkPassService/pkPass.service' +import { FeatureFlagModule } from '@island.is/nest/feature-flags' +import { SmartSolutionsModule } from '@island.is/clients/smart-solutions-v2' @Module({ imports: [ + FeatureFlagModule, DrivingLicenseApiModule, SmartSolutionsApiClientModule.registerAsync({ useFactory: ( @@ -15,8 +19,20 @@ import { DrivingLicenseUpdateClientV2 } from '../services/drivingLicenseUpdateCl ) => config, inject: [DrivingDigitalLicenseClientConfig.KEY], }), + SmartSolutionsModule.registerAsync({ + useFactory: ( + config: ConfigType, + ) => ({ + config, + }), + inject: [DrivingDigitalLicenseClientConfig.KEY], + }), + ], + providers: [ + PkPassService, + DrivingLicenseUpdateClient, + DrivingLicenseUpdateClientV2, ], - providers: [DrivingLicenseUpdateClient, DrivingLicenseUpdateClientV2], exports: [DrivingLicenseUpdateClient, DrivingLicenseUpdateClientV2], }) export class DrivingUpdateClientModule {} diff --git a/libs/clients/license-client/src/lib/clients/firearm-license-client/modules/firearmLicenseUpdateClient.module.ts b/libs/clients/license-client/src/lib/clients/firearm-license-client/modules/firearmLicenseUpdateClient.module.ts index 622b0ea7136b..8867cf1276f5 100644 --- a/libs/clients/license-client/src/lib/clients/firearm-license-client/modules/firearmLicenseUpdateClient.module.ts +++ b/libs/clients/license-client/src/lib/clients/firearm-license-client/modules/firearmLicenseUpdateClient.module.ts @@ -4,9 +4,25 @@ import { SmartSolutionsFirearmModule } from './smartSolutionsFirearm.module' import { FirearmLicenseUpdateClientV2 } from '../services/firearmLicenseUpdateClientV2.service' import { FirearmLicenseUpdateClient } from '../services/firearmLicenseUpdateClient.service' import { PkPassService } from '../../../helpers/pkPassService/pkPass.service' +import { FeatureFlagModule } from '@island.is/nest/feature-flags' +import { SmartSolutionsModule } from '@island.is/clients/smart-solutions-v2' +import { FirearmDigitalLicenseClientConfig } from '../firearmLicenseClient.config' +import { ConfigType } from '@nestjs/config' @Module({ - imports: [FirearmLicenseUpdateClientModule, SmartSolutionsFirearmModule], + imports: [ + FeatureFlagModule, + FirearmLicenseUpdateClientModule, + SmartSolutionsFirearmModule, + SmartSolutionsModule.registerAsync({ + useFactory: ( + config: ConfigType, + ) => ({ + config, + }), + inject: [FirearmDigitalLicenseClientConfig.KEY], + }), + ], providers: [ PkPassService, FirearmLicenseUpdateClient, diff --git a/libs/clients/license-client/src/lib/clients/machine-license-client/machineLicenseClient.module.ts b/libs/clients/license-client/src/lib/clients/machine-license-client/machineLicenseClient.module.ts index 77f04303b291..be74a591ed2b 100644 --- a/libs/clients/license-client/src/lib/clients/machine-license-client/machineLicenseClient.module.ts +++ b/libs/clients/license-client/src/lib/clients/machine-license-client/machineLicenseClient.module.ts @@ -6,9 +6,11 @@ import { MachineDigitalLicenseClientConfig } from './machineLicenseClient.config import { SmartSolutionsApiClientModule } from '@island.is/clients/smartsolutions' import { SmartSolutionsModule } from '@island.is/clients/smart-solutions-v2' import { PkPassService } from '../../helpers/pkPassService/pkPass.service' +import { FeatureFlagModule } from '@island.is/nest/feature-flags' @Module({ imports: [ + FeatureFlagModule, AdrAndMachineLicenseClientModule, SmartSolutionsApiClientModule.registerAsync({ useFactory: ( diff --git a/libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.service.ts b/libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.service.ts index c1d311adca1e..b49de3cc1d4e 100644 --- a/libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.service.ts +++ b/libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.service.ts @@ -9,7 +9,9 @@ import { } from '../../licenseClient.type' import { VerifyPassData, VerifyPkPassDataInput } from './pkPass.types' import { mapPassData } from './pkPass.mapper' +import { Injectable } from '@nestjs/common' +@Injectable() export class PkPassService { constructor( private readonly featureFlagService: FeatureFlagService, From a675a0bf69960abba1f446c2a8a097d962f3e4d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Tue, 8 Oct 2024 15:51:42 +0000 Subject: [PATCH 10/29] feat: versionable license-client --- .../modules/license/dto/revokeLicense.dto.ts | 5 +++ .../modules/license/dto/updateLicense.dto.ts | 7 ++++- .../modules/license/dto/verifyLicense.dto.ts | 5 +++ .../src/app/modules/license/license.module.ts | 3 +- .../app/modules/license/license.service.ts | 21 +++---------- .../src/app/modules/license/license.types.ts | 5 +++ ...disabilityLicenseUpdateClientV2.service.ts | 4 +-- .../drivingLicenseUpdateClientV2.service.ts | 13 ++++++-- .../firearmLicenseUpdateClientV2.service.ts | 13 ++++++-- .../machineLicenseClient.service.ts | 14 +++++++-- .../helpers/pkPassService/pkPass.mapper.ts | 2 +- .../helpers/pkPassService/pkPass.service.ts | 31 ++++++++++++++----- .../src/lib/licenseClient.type.ts | 10 ++++-- .../src/lib/smartSolutions.service.ts | 7 +++++ 14 files changed, 102 insertions(+), 38 deletions(-) diff --git a/apps/services/license-api/src/app/modules/license/dto/revokeLicense.dto.ts b/apps/services/license-api/src/app/modules/license/dto/revokeLicense.dto.ts index ed3956ecf716..081c59df397d 100644 --- a/apps/services/license-api/src/app/modules/license/dto/revokeLicense.dto.ts +++ b/apps/services/license-api/src/app/modules/license/dto/revokeLicense.dto.ts @@ -12,4 +12,9 @@ export class RevokeLicenseRequest { @ApiProperty({ description: 'Optional request id for logging purposes' }) @IsString() readonly requestId?: string + + @ApiPropertyOptional() + @IsOptional() + @IsEnum(LicenseApiVersion) + readonly apiVersion?: LicenseApiVersion } diff --git a/apps/services/license-api/src/app/modules/license/dto/updateLicense.dto.ts b/apps/services/license-api/src/app/modules/license/dto/updateLicense.dto.ts index ab246ec6ea6b..dac8ab9afe46 100644 --- a/apps/services/license-api/src/app/modules/license/dto/updateLicense.dto.ts +++ b/apps/services/license-api/src/app/modules/license/dto/updateLicense.dto.ts @@ -7,7 +7,7 @@ import { IsOptional, IsString, } from 'class-validator' -import { LicenseUpdateType } from '../license.types' +import { LicenseApiVersion, LicenseUpdateType } from '../license.types' export class UpdateLicenseRequest { @ApiProperty({ enum: LicenseUpdateType, description: 'The update action' }) @@ -29,6 +29,11 @@ export class UpdateLicenseRequest { @ApiProperty({ description: 'Optional request id for logging purposes' }) @IsString() readonly requestId?: string + + @ApiPropertyOptional() + @IsOptional() + @IsEnum(LicenseApiVersion) + readonly apiVersion?: LicenseApiVersion } export class UpdateLicenseResponse { diff --git a/apps/services/license-api/src/app/modules/license/dto/verifyLicense.dto.ts b/apps/services/license-api/src/app/modules/license/dto/verifyLicense.dto.ts index f053e3d58550..64883268e700 100644 --- a/apps/services/license-api/src/app/modules/license/dto/verifyLicense.dto.ts +++ b/apps/services/license-api/src/app/modules/license/dto/verifyLicense.dto.ts @@ -11,6 +11,11 @@ export class VerifyLicenseRequest { @ApiProperty({ description: 'Optional request id for logging purposes' }) @IsString() readonly requestId?: string + + @ApiPropertyOptional() + @IsOptional() + @IsEnum(LicenseApiVersion) + readonly apiVersion?: LicenseApiVersion } class PassIdentity { diff --git a/apps/services/license-api/src/app/modules/license/license.module.ts b/apps/services/license-api/src/app/modules/license/license.module.ts index 8969b14abeda..8f8a2ed83362 100644 --- a/apps/services/license-api/src/app/modules/license/license.module.ts +++ b/apps/services/license-api/src/app/modules/license/license.module.ts @@ -7,12 +7,11 @@ import { UserLicensesController, } from './license.controller' import { LicenseService } from './license.service' -import { FeatureFlagModule } from '@island.is/nest/feature-flags' import { LicenseServiceV1 } from './licenseV1.service' import { LicenseServiceV2 } from './licenseV2.service' @Module({ - imports: [LicenseUpdateClientModule, LicenseCommonModule, FeatureFlagModule], + imports: [LicenseUpdateClientModule, LicenseCommonModule], controllers: [LicensesController, UserLicensesController], providers: [ { diff --git a/apps/services/license-api/src/app/modules/license/license.service.ts b/apps/services/license-api/src/app/modules/license/license.service.ts index 20244010d353..de99cc8f1044 100644 --- a/apps/services/license-api/src/app/modules/license/license.service.ts +++ b/apps/services/license-api/src/app/modules/license/license.service.ts @@ -7,34 +7,23 @@ import { VerifyLicenseRequest, VerifyLicenseResponse, } from './dto' -import { LicenseId } from './license.types' -import { FeatureFlagService, Features } from '@island.is/nest/feature-flags' +import { LicenseApiVersion, LicenseId } from './license.types' import { LicenseServiceV1 } from './licenseV1.service' import { LicenseServiceV2 } from './licenseV2.service' @Injectable() export class LicenseService { constructor( - private readonly featureFlagService: FeatureFlagService, private readonly serviceV1: LicenseServiceV1, private readonly serviceV2: LicenseServiceV2, ) {} - getVersion = async () => { - const flag = await this.featureFlagService.getValue( - Features.licensesV2, - false, - ) - return flag ? 'v2' : 'v1' - } - async updateLicense( licenseId: LicenseId, nationalId: string, inputData: UpdateLicenseRequest, ): Promise { - const version = await this.getVersion() - if (version === 'v2') { + if (inputData.apiVersion === LicenseApiVersion.v1) { return this.serviceV2.updateLicense(licenseId, nationalId, inputData) } return this.serviceV1.updateLicense(licenseId, nationalId, inputData) @@ -45,8 +34,7 @@ export class LicenseService { nationalId: string, inputData?: RevokeLicenseRequest, ): Promise { - const version = await this.getVersion() - if (version === 'v2') { + if (inputData?.apiVersion === LicenseApiVersion.v2) { return this.serviceV2.revokeLicense(licenseId, nationalId, inputData) } return this.serviceV1.revokeLicense(licenseId, nationalId, inputData) @@ -55,8 +43,7 @@ export class LicenseService { async verifyLicense( inputData: VerifyLicenseRequest, ): Promise { - const version = await this.getVersion() - if (version === 'v2') { + if (inputData?.apiVersion === LicenseApiVersion.v2) { return this.serviceV2.verifyLicense(inputData) } return this.serviceV1.verifyLicense(inputData) diff --git a/apps/services/license-api/src/app/modules/license/license.types.ts b/apps/services/license-api/src/app/modules/license/license.types.ts index 7a51712ffc82..08181b23a3ea 100644 --- a/apps/services/license-api/src/app/modules/license/license.types.ts +++ b/apps/services/license-api/src/app/modules/license/license.types.ts @@ -9,6 +9,11 @@ export enum LicenseUpdateType { PULL = 'pull', } +export enum LicenseApiVersion { + 'v1', + 'v2', +} + export enum LicenseId { FIREARM_LICENSE = 'firearm', DISABILITY_LICENSE = 'disability', diff --git a/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClientV2.service.ts b/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClientV2.service.ts index 5d809003cf04..bd106d9f994b 100644 --- a/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClientV2.service.ts +++ b/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClientV2.service.ts @@ -25,7 +25,7 @@ export class DisabilityLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { inputData: PassDataInput, nationalId: string, ): Promise> { - return this.passService.updatePkPass(inputData, nationalId) + return this.passService.updatePkPass(inputData, nationalId, undefined, 'v2') } async pullUpdate(): Promise> { @@ -69,7 +69,7 @@ export class DisabilityLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { } } - const verifyRes = await this.passService.verifyPkPass({ code, date }) + const verifyRes = await this.passService.verifyPkPass({ code, date }, 'v2') if (!verifyRes.ok) { return verifyRes diff --git a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts index 27f381fd468f..a1827c0ac374 100644 --- a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts +++ b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts @@ -55,6 +55,8 @@ export class DrivingLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { passTemplateId: this.config.passTemplateId, }, requestId, + undefined, + 'v2', ) } @@ -135,7 +137,7 @@ export class DrivingLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { : undefined, } - return this.passService.updatePkPass(payload, requestId) + return this.passService.updatePkPass(payload, requestId, undefined, 'v2') } revoke( @@ -146,7 +148,13 @@ export class DrivingLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { const payload: PassDataInput = { inputFieldValues: [mapNationalId(nationalId)], } - return this.passService.revokePkPass(passTemplateId, payload, requestId) + return this.passService.revokePkPass( + passTemplateId, + payload, + requestId, + undefined, + 'v2', + ) } /** We need to verify the pk pass AND the license itself! */ @@ -199,6 +207,7 @@ export class DrivingLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { const verifyRes = await this.passService.verifyPkPass( { code, date }, requestId, + 'v2', ) if (!verifyRes.ok) { diff --git a/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClientV2.service.ts b/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClientV2.service.ts index 7f147716e860..728e81c3d0e8 100644 --- a/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClientV2.service.ts +++ b/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClientV2.service.ts @@ -54,6 +54,8 @@ export class FirearmLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { passTemplateId: this.config.passTemplateId, }, requestId, + undefined, + 'v2', ) } @@ -136,7 +138,7 @@ export class FirearmLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { : undefined, } - return this.passService.updatePkPass(payload, requestId) + return this.passService.updatePkPass(payload, requestId, undefined, 'v2') } revoke( @@ -147,7 +149,13 @@ export class FirearmLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { const payload: PassDataInput = { inputFieldValues: [mapNationalId(nationalId)], } - return this.passService.revokePkPass(passTemplateId, payload, requestId) + return this.passService.revokePkPass( + passTemplateId, + payload, + requestId, + undefined, + 'v2', + ) } /** We need to verify the pk pass AND the license itself! */ @@ -185,6 +193,7 @@ export class FirearmLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { const verifyRes = await this.passService.verifyPkPass( { code, date }, requestId, + 'v2', ) if (!verifyRes.ok) { diff --git a/libs/clients/license-client/src/lib/clients/machine-license-client/machineLicenseClient.service.ts b/libs/clients/license-client/src/lib/clients/machine-license-client/machineLicenseClient.service.ts index 3db93fe75a9a..51b4fde3959a 100644 --- a/libs/clients/license-client/src/lib/clients/machine-license-client/machineLicenseClient.service.ts +++ b/libs/clients/license-client/src/lib/clients/machine-license-client/machineLicenseClient.service.ts @@ -195,7 +195,12 @@ export class MachineLicenseClient } } - const pass = await this.passService.generatePkPass(payload) + const pass = await this.passService.generatePkPass( + payload, + undefined, + undefined, + user, + ) return pass } @@ -258,9 +263,14 @@ export class MachineLicenseClient async verifyPkPass( data: string, + version?: 'v1' | 'v2', ): Promise>> { const { code, date } = JSON.parse(data) as PkPassVerificationInputData - const result = await this.passService.verifyPkPass({ code, date }) + const result = await this.passService.verifyPkPass( + { code, date }, + undefined, + version, + ) if (!result.ok) { return result diff --git a/libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.mapper.ts b/libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.mapper.ts index 7b6ba8da4c0c..ce04e21c604a 100644 --- a/libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.mapper.ts +++ b/libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.mapper.ts @@ -4,7 +4,7 @@ import { PassData } from '../../licenseClient.type' export const mapPassData = (pass: PassV1 | PassV2): PassData => ({ ...pass, - inputFieldValues: pass?.inputFieldValues.map((i) => ({ + inputFieldValues: (pass?.inputFieldValues ?? []).map((i) => ({ id: i.id, identifier: i.passInputField.identifier, value: i.value ?? undefined, diff --git a/libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.service.ts b/libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.service.ts index b49de3cc1d4e..e497f6983a2d 100644 --- a/libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.service.ts +++ b/libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.service.ts @@ -9,32 +9,43 @@ import { } from '../../licenseClient.type' import { VerifyPassData, VerifyPkPassDataInput } from './pkPass.types' import { mapPassData } from './pkPass.mapper' -import { Injectable } from '@nestjs/common' +import { Inject, Injectable } from '@nestjs/common' +import { User } from '@island.is/auth-nest-tools' +import { LOGGER_PROVIDER, type Logger } from '@island.is/logging' @Injectable() export class PkPassService { constructor( + @Inject(LOGGER_PROVIDER) private readonly logger: Logger, private readonly featureFlagService: FeatureFlagService, private readonly newSmartService: SmartSolutionsService, /** DEPRECATED */ private readonly oldSmartService: SmartSolutionsApi, ) {} - async getService(): Promise { + async getService( + user?: User, + version?: 'v1' | 'v2', + ): Promise { + if (!user) { + return version === 'v2' ? this.newSmartService : this.oldSmartService + } const v2Enabled = await this.featureFlagService.getValue( Features.licensesV2, false, + user, ) return v2Enabled ? this.newSmartService : this.oldSmartService } + //cant feature flag this, no user object available async verifyPkPass( payload: VerifyPkPassDataInput, requestId?: string, + version?: 'v1' | 'v2', ): Promise> { - const service = await this.getService() - + const service = await this.getService(undefined, version) const pass = await service.verifyPkPass(payload, requestId) if (!pass.ok) { @@ -53,8 +64,10 @@ export class PkPassService { async updatePkPass( payload: PassDataInput, requestId?: string, + user?: User, + version?: 'v1' | 'v2', ): Promise> { - const service = await this.getService() + const service = await this.getService(user, version) const pass = await service.updatePkPass(payload, requestId) if (!pass.ok) { return pass @@ -70,8 +83,10 @@ export class PkPassService { payload: PassDataInput, onCreateCallback?: () => Promise, requestId?: string, + user?: User, + version?: 'v1' | 'v2', ): Promise> { - const service = await this.getService() + const service = await this.getService(user, version) const pass = await service.generatePkPass( payload, onCreateCallback, @@ -92,8 +107,10 @@ export class PkPassService { passTemplateId: string, payload: PassDataInput, requestId?: string, + user?: User, + version?: 'v1' | 'v2', ): Promise> { - const service = await this.getService() + const service = await this.getService(user, version) const pass = await service.revokePkPass(passTemplateId, payload, requestId) if (!pass.ok) { return pass diff --git a/libs/clients/license-client/src/lib/licenseClient.type.ts b/libs/clients/license-client/src/lib/licenseClient.type.ts index a95159a40fc0..e350632bbf11 100644 --- a/libs/clients/license-client/src/lib/licenseClient.type.ts +++ b/libs/clients/license-client/src/lib/licenseClient.type.ts @@ -232,8 +232,14 @@ export interface LicenseClient { ) => Promise getPkPassUrl?: (user: User, locale?: Locale) => Promise> getPkPassQRCode?: (user: User, locale?: Locale) => Promise> - verifyPkPassDeprecated?: (data: string) => Promise> - verifyPkPass?: (data: string) => Promise>> + verifyPkPassDeprecated?: ( + data: string, + version?: 'v1' | 'v2', + ) => Promise> + verifyPkPass?: ( + data: string, + version?: 'v1' | 'v2', + ) => Promise>> verifyExtraData?: (input: User) => Promise> } diff --git a/libs/clients/smart-solutions-v2/src/lib/smartSolutions.service.ts b/libs/clients/smart-solutions-v2/src/lib/smartSolutions.service.ts index c3dbe0e28479..6c8c2dcbd39b 100644 --- a/libs/clients/smart-solutions-v2/src/lib/smartSolutions.service.ts +++ b/libs/clients/smart-solutions-v2/src/lib/smartSolutions.service.ts @@ -42,6 +42,7 @@ export class SmartSolutionsService { payload: DynamicBarcodeDataInput, requestId?: string, ): Promise> { + this.logger.debug('IN VERIFY PKPFASS V2') const variables: UpdateStatusOnPassWithDynamicBarcodeMutationVariables = { dynamicBarcodeData: payload, } @@ -89,6 +90,8 @@ export class SmartSolutionsService { payload: PassDataInput, requestId?: string, ): Promise> { + this.logger.debug('INUPDATE PKPFASS V2') + if (!payload.passTemplateId) { this.logger.warning( 'Pkpass update failed, missing pass template id from input', @@ -154,6 +157,8 @@ export class SmartSolutionsService { onCreateCallback?: () => Promise, requestId?: string, ): Promise> { + this.logger.debug('IN GENERATE PKPFASS V2') + const variables: UpsertPassMutationVariables = { inputData: { ...payload, @@ -210,6 +215,8 @@ export class SmartSolutionsService { payload: PassDataInput, requestId?: string, ): Promise> { + this.logger.debug('IN REVOKE PKPFASS V2') + const variables: DeletePassMutationVariables = { passTemplateId, values: payload, From dd50863fb830c808efb2cec5c9150dd15e00d482 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Tue, 8 Oct 2024 16:06:43 +0000 Subject: [PATCH 11/29] feat: works --- .../src/app/modules/license/dto/revokeLicense.dto.ts | 7 ++++--- .../src/app/modules/license/dto/updateLicense.dto.ts | 2 +- .../src/app/modules/license/dto/verifyLicense.dto.ts | 11 +++++++++-- .../src/app/modules/license/license.service.ts | 2 +- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/apps/services/license-api/src/app/modules/license/dto/revokeLicense.dto.ts b/apps/services/license-api/src/app/modules/license/dto/revokeLicense.dto.ts index 081c59df397d..4e7a814249c9 100644 --- a/apps/services/license-api/src/app/modules/license/dto/revokeLicense.dto.ts +++ b/apps/services/license-api/src/app/modules/license/dto/revokeLicense.dto.ts @@ -1,5 +1,6 @@ -import { ApiProperty } from '@nestjs/swagger' -import { IsBoolean, IsOptional, IsString } from 'class-validator' +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger' +import { IsBoolean, IsEnum, IsOptional, IsString } from 'class-validator' +import { LicenseApiVersion } from '../license.types' export class RevokeLicenseResponse { @ApiProperty({ description: 'Has the license been revoked?' }) @@ -13,7 +14,7 @@ export class RevokeLicenseRequest { @IsString() readonly requestId?: string - @ApiPropertyOptional() + @ApiPropertyOptional({ enum: LicenseApiVersion }) @IsOptional() @IsEnum(LicenseApiVersion) readonly apiVersion?: LicenseApiVersion diff --git a/apps/services/license-api/src/app/modules/license/dto/updateLicense.dto.ts b/apps/services/license-api/src/app/modules/license/dto/updateLicense.dto.ts index dac8ab9afe46..70677a415689 100644 --- a/apps/services/license-api/src/app/modules/license/dto/updateLicense.dto.ts +++ b/apps/services/license-api/src/app/modules/license/dto/updateLicense.dto.ts @@ -30,7 +30,7 @@ export class UpdateLicenseRequest { @IsString() readonly requestId?: string - @ApiPropertyOptional() + @ApiPropertyOptional({ enum: LicenseApiVersion }) @IsOptional() @IsEnum(LicenseApiVersion) readonly apiVersion?: LicenseApiVersion diff --git a/apps/services/license-api/src/app/modules/license/dto/verifyLicense.dto.ts b/apps/services/license-api/src/app/modules/license/dto/verifyLicense.dto.ts index 64883268e700..e596c30c7c41 100644 --- a/apps/services/license-api/src/app/modules/license/dto/verifyLicense.dto.ts +++ b/apps/services/license-api/src/app/modules/license/dto/verifyLicense.dto.ts @@ -1,6 +1,13 @@ import { IsPersonNationalId } from '@island.is/nest/core' import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger' -import { IsBoolean, IsObject, IsOptional, IsString } from 'class-validator' +import { + IsBoolean, + IsEnum, + IsObject, + IsOptional, + IsString, +} from 'class-validator' +import { LicenseApiVersion } from '../license.types' export class VerifyLicenseRequest { @ApiProperty({ description: 'PDF417 barcode scanner data' }) @@ -12,7 +19,7 @@ export class VerifyLicenseRequest { @IsString() readonly requestId?: string - @ApiPropertyOptional() + @ApiPropertyOptional({ enum: LicenseApiVersion }) @IsOptional() @IsEnum(LicenseApiVersion) readonly apiVersion?: LicenseApiVersion diff --git a/apps/services/license-api/src/app/modules/license/license.service.ts b/apps/services/license-api/src/app/modules/license/license.service.ts index de99cc8f1044..569818721d85 100644 --- a/apps/services/license-api/src/app/modules/license/license.service.ts +++ b/apps/services/license-api/src/app/modules/license/license.service.ts @@ -23,7 +23,7 @@ export class LicenseService { nationalId: string, inputData: UpdateLicenseRequest, ): Promise { - if (inputData.apiVersion === LicenseApiVersion.v1) { + if (inputData.apiVersion === LicenseApiVersion.v2) { return this.serviceV2.updateLicense(licenseId, nationalId, inputData) } return this.serviceV1.updateLicense(licenseId, nationalId, inputData) From 315ae78ddd59ad1c33e99e953a40fefa925e3a0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Tue, 8 Oct 2024 16:09:47 +0000 Subject: [PATCH 12/29] chore: remove logs --- .../smart-solutions-v2/src/lib/smartSolutions.service.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/libs/clients/smart-solutions-v2/src/lib/smartSolutions.service.ts b/libs/clients/smart-solutions-v2/src/lib/smartSolutions.service.ts index 6c8c2dcbd39b..c3dbe0e28479 100644 --- a/libs/clients/smart-solutions-v2/src/lib/smartSolutions.service.ts +++ b/libs/clients/smart-solutions-v2/src/lib/smartSolutions.service.ts @@ -42,7 +42,6 @@ export class SmartSolutionsService { payload: DynamicBarcodeDataInput, requestId?: string, ): Promise> { - this.logger.debug('IN VERIFY PKPFASS V2') const variables: UpdateStatusOnPassWithDynamicBarcodeMutationVariables = { dynamicBarcodeData: payload, } @@ -90,8 +89,6 @@ export class SmartSolutionsService { payload: PassDataInput, requestId?: string, ): Promise> { - this.logger.debug('INUPDATE PKPFASS V2') - if (!payload.passTemplateId) { this.logger.warning( 'Pkpass update failed, missing pass template id from input', @@ -157,8 +154,6 @@ export class SmartSolutionsService { onCreateCallback?: () => Promise, requestId?: string, ): Promise> { - this.logger.debug('IN GENERATE PKPFASS V2') - const variables: UpsertPassMutationVariables = { inputData: { ...payload, @@ -215,8 +210,6 @@ export class SmartSolutionsService { payload: PassDataInput, requestId?: string, ): Promise> { - this.logger.debug('IN REVOKE PKPFASS V2') - const variables: DeletePassMutationVariables = { passTemplateId, values: payload, From 6a7e4cd8de58fa5363d3873ea801d69f27d789af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Wed, 9 Oct 2024 09:13:41 +0000 Subject: [PATCH 13/29] fix: client updates --- .../app/modules/license/licenseV1.service.ts | 103 ++++++++---------- .../app/modules/license/licenseV2.service.ts | 2 +- .../lib/clients/base/licenseUpdateClientV2.ts | 2 - 3 files changed, 48 insertions(+), 59 deletions(-) diff --git a/apps/services/license-api/src/app/modules/license/licenseV1.service.ts b/apps/services/license-api/src/app/modules/license/licenseV1.service.ts index be4d15ec92bc..a73fd594dc49 100644 --- a/apps/services/license-api/src/app/modules/license/licenseV1.service.ts +++ b/apps/services/license-api/src/app/modules/license/licenseV1.service.ts @@ -17,7 +17,7 @@ import { InternalServerErrorException, } from '@nestjs/common' import { isJSON, isJWT } from 'class-validator' -import { uuid } from 'uuidv4' +import { v4 as uuid } from 'uuid' import { RevokeLicenseRequest, RevokeLicenseResponse, @@ -70,83 +70,70 @@ export class LicenseServiceV1 { private generateRequestId = () => uuid() - private async getClientByLicenseId( - licenseId: LicenseId, + private async getClient( + identifier: LicenseId | string, + type: 'licenseId' | 'passTemplateId', requestId?: string, ): Promise { - const type = mapLicenseIdToLicenseType(licenseId) + let service: BaseLicenseUpdateClient | null + let extraLoggerProperties: any - this.logger.debug('Retrieving a licence client by license id', { - category: LOG_CATEGORY, - requestId: requestId, - type: type, - }) + if (type === 'licenseId') { + const type = mapLicenseIdToLicenseType(identifier as LicenseId) - if (!type) { - this.logger.error(`Invalid license type`, { + if (!type) { + this.logger.error(`Invalid license type`, { + category: LOG_CATEGORY, + requestId: requestId, + type, + }) + throw new BadRequestException(`Invalid license type`) + } + this.logger.debug('Retrieving a licence client by license id', { category: LOG_CATEGORY, requestId: requestId, type, }) - throw new InternalServerErrorException(`Invalid license type`) - } - const service = await this.getLicenseUpdateClientByType( - type as LicenseType, - requestId, - ) - - this.logger.debug('Injecting the proper license client..', { - category: LOG_CATEGORY, - requestId: requestId, - type: type, - }) + extraLoggerProperties = { + type: type, + } - if (!service) { - this.logger.error(`Client service generation failed`, { + service = await this.getLicenseUpdateClientByType(type, requestId) + } else { + this.logger.debug('Retrieving a licence client by pass template id', { category: LOG_CATEGORY, - type, + requestId: requestId, + passTemplateId: identifier, }) - throw new InternalServerErrorException(`Client service generation failed`) - } - this.logger.debug('Client injection successful', { - category: LOG_CATEGORY, - requestId: requestId, - type: type, - }) - return service - } - - private async getClientByPassTemplateId( - passTemplateId: string, - requestId?: string, - ): Promise { - this.logger.debug('Retrieving a licence client by pass template id', { - category: LOG_CATEGORY, - requestId: requestId, - passTemplateId, - }) - - const service = await this.getLicenseUpdateClientByPassTemplateId( - passTemplateId, - requestId, - ) + extraLoggerProperties = { + passTemplateId: identifier, + } + service = await this.getLicenseUpdateClientByPassTemplateId( + identifier, + requestId, + ) + } this.logger.debug('Injecting the proper license client..', { category: LOG_CATEGORY, requestId: requestId, - passTemplateId, + ...extraLoggerProperties, }) if (!service) { this.logger.error(`Client service generation failed`, { category: LOG_CATEGORY, - requestId: requestId, - passTemplateId, + ...extraLoggerProperties, }) throw new InternalServerErrorException(`Client service generation failed`) } + this.logger.debug('Client injection successful', { + category: LOG_CATEGORY, + requestId: requestId, + ...extraLoggerProperties, + }) return service } @@ -219,7 +206,7 @@ export class LicenseServiceV1 { ): Promise { const requestId = inputData.requestId ?? this.generateRequestId() - const service = await this.getClientByLicenseId(licenseId, requestId) + const service = await this.getClient(licenseId, 'licenseId', requestId) this.logger.debug('License update initiated', { category: LOG_CATEGORY, @@ -284,7 +271,7 @@ export class LicenseServiceV1 { inputData?: RevokeLicenseRequest, ): Promise { const requestId = inputData?.requestId ?? this.generateRequestId() - const service = await this.getClientByLicenseId(licenseId, requestId) + const service = await this.getClient(licenseId, 'licenseId', requestId) const revokeRes = await service.revoke(nationalId, requestId) @@ -385,7 +372,11 @@ export class LicenseServiceV1 { throw this.getException('BadRequest', 'Missing pass template id') } - const service = await this.getClientByPassTemplateId(passTemplateId) + const service = await this.getClient( + passTemplateId, + 'passTemplateId', + requestId, + ) const verifyRes = await service.verify(inputData.barcodeData, requestId) diff --git a/apps/services/license-api/src/app/modules/license/licenseV2.service.ts b/apps/services/license-api/src/app/modules/license/licenseV2.service.ts index 58e58851c0c9..ab48a74a942a 100644 --- a/apps/services/license-api/src/app/modules/license/licenseV2.service.ts +++ b/apps/services/license-api/src/app/modules/license/licenseV2.service.ts @@ -19,7 +19,7 @@ import { InternalServerErrorException, } from '@nestjs/common' import { isJSON, isJWT } from 'class-validator' -import { uuid } from 'uuidv4' +import { v4 as uuid } from 'uuid' import { RevokeLicenseRequest, RevokeLicenseResponse, diff --git a/libs/clients/license-client/src/lib/clients/base/licenseUpdateClientV2.ts b/libs/clients/license-client/src/lib/clients/base/licenseUpdateClientV2.ts index 9fe4087e716d..608075411f3e 100644 --- a/libs/clients/license-client/src/lib/clients/base/licenseUpdateClientV2.ts +++ b/libs/clients/license-client/src/lib/clients/base/licenseUpdateClientV2.ts @@ -1,4 +1,3 @@ -import { Injectable } from '@nestjs/common' import { PassData, PassDataInput, @@ -7,7 +6,6 @@ import { Result, } from '../../licenseClient.type' -@Injectable() export abstract class BaseLicenseUpdateClientV2 { abstract pushUpdate( inputData: PassDataInput, From 3e4a6c199d4f4954e9ff00c4c2d2847e6c739f07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Wed, 9 Oct 2024 09:17:16 +0000 Subject: [PATCH 14/29] chore: add deprecated decoratorsgp --- .../services/disabilityLicenseUpdateClient.service.ts | 1 + .../services/drivingLicenseUpdateClient.service.ts | 1 + .../services/firearmLicenseUpdateClient.service.ts | 1 + libs/clients/smartsolutions/src/lib/smartsolutions.module.ts | 1 + 4 files changed, 4 insertions(+) diff --git a/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClient.service.ts b/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClient.service.ts index 578d80566fc0..4a8ccbe87ff6 100644 --- a/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClient.service.ts +++ b/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClient.service.ts @@ -15,6 +15,7 @@ import { import { BaseLicenseUpdateClient } from '../../base/baseLicenseUpdateClient' @Injectable() +/** @deprecated */ export class DisabilityLicenseUpdateClient extends BaseLicenseUpdateClient { constructor( @Inject(LOGGER_PROVIDER) protected logger: Logger, diff --git a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClient.service.ts b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClient.service.ts index 418bbfe8a8ce..23b4bc1dd07f 100644 --- a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClient.service.ts +++ b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClient.service.ts @@ -26,6 +26,7 @@ import { DrivingDigitalLicenseClientConfig } from '../drivingLicenseClient.confi const LOG_CATEGORY = 'driving-license-service' @Injectable() +/** @deprecated */ export class DrivingLicenseUpdateClient extends BaseLicenseUpdateClient { constructor( @Inject(LOGGER_PROVIDER) protected logger: Logger, diff --git a/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClient.service.ts b/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClient.service.ts index fb8e3608613a..2f37bbce3148 100644 --- a/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClient.service.ts +++ b/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClient.service.ts @@ -24,6 +24,7 @@ import { FirearmDigitalLicenseClientConfig } from '../firearmLicenseClient.confi const LOG_CATEGORY = 'firearmlicense-service' @Injectable() +/** @deprecated */ export class FirearmLicenseUpdateClient extends BaseLicenseUpdateClient { constructor( @Inject(LOGGER_PROVIDER) protected logger: Logger, diff --git a/libs/clients/smartsolutions/src/lib/smartsolutions.module.ts b/libs/clients/smartsolutions/src/lib/smartsolutions.module.ts index 72b8e3e0e63c..fa85072d8004 100644 --- a/libs/clients/smartsolutions/src/lib/smartsolutions.module.ts +++ b/libs/clients/smartsolutions/src/lib/smartsolutions.module.ts @@ -13,6 +13,7 @@ export type SmartSolutionsModuleAsyncOptions = { } @Module({}) +/** @deprecated */ export class SmartSolutionsApiClientModule { public static register(config: SmartSolutionsConfig): DynamicModule { return { From 14ac6a80d1c5eca8abb15c6ad240083148fcf027 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Wed, 9 Oct 2024 09:33:05 +0000 Subject: [PATCH 15/29] fix: tests work --- .../src/app/modules/license/license.types.ts | 4 +- .../license/test/license.service.spec.ts | 175 +++++++++++++++++- 2 files changed, 175 insertions(+), 4 deletions(-) diff --git a/apps/services/license-api/src/app/modules/license/license.types.ts b/apps/services/license-api/src/app/modules/license/license.types.ts index 08181b23a3ea..e462d494c159 100644 --- a/apps/services/license-api/src/app/modules/license/license.types.ts +++ b/apps/services/license-api/src/app/modules/license/license.types.ts @@ -10,8 +10,8 @@ export enum LicenseUpdateType { } export enum LicenseApiVersion { - 'v1', - 'v2', + v1 = 'v1', + v2 = 'v2', } export enum LicenseId { diff --git a/apps/services/license-api/src/app/modules/license/test/license.service.spec.ts b/apps/services/license-api/src/app/modules/license/test/license.service.spec.ts index 5933d9cb0a92..a2c4e76e1900 100644 --- a/apps/services/license-api/src/app/modules/license/test/license.service.spec.ts +++ b/apps/services/license-api/src/app/modules/license/test/license.service.spec.ts @@ -1,5 +1,6 @@ import { BaseLicenseUpdateClient, + BaseLicenseUpdateClientV2, LicenseType, LicenseUpdateClientService, } from '@island.is/clients/license-client' @@ -41,6 +42,9 @@ import { LicenseUpdateType, PASS_TEMPLATE_IDS, } from '../license.types' +import { SmartSolutionsService } from '@island.is/clients/smart-solutions-v2' +import { LicenseServiceV1 } from '../licenseV1.service' +import { LicenseServiceV2 } from '../licenseV2.service' const { randomUUID } = new ShortUniqueId({ length: 16 }) const cacheStore = new Map() @@ -223,6 +227,161 @@ export class MockUpdateClient extends BaseLicenseUpdateClient { } } +@Injectable() +export class MockUpdateClientV2 extends BaseLicenseUpdateClientV2 { + constructor( + @Inject(LOGGER_PROVIDER) protected logger: Logger, + private readonly clientService: LicenseUpdateClientService, + ) { + super() + } + + pushUpdate = (inputData: PassDataInput, nationalId: string) => { + if (nationalId === 'success') { + return Promise.resolve>({ + ok: true, + data: undefined, + }) + } + + if (nationalId === '') { + return Promise.resolve>({ + ok: false, + error: { + code: 5, + message: 'some user error', + }, + }) + } + //some other error + return Promise.resolve>({ + ok: false, + error: { + code: 99, + message: 'some service error', + }, + }) + } + + pullUpdate = (nationalId: string) => { + if (nationalId === 'success') { + return Promise.resolve>({ + ok: true, + data: undefined, + }) + } + + if (nationalId === '') { + return Promise.resolve>({ + ok: false, + error: { + code: 5, + message: 'some user error', + }, + }) + } + //some other error + return Promise.resolve>({ + ok: false, + error: { + code: 99, + message: 'some service error', + }, + }) + } + + revoke = (nationalId: string) => { + if (nationalId === 'success') { + return Promise.resolve>({ + ok: true, + data: { + success: true, + }, + }) + } + + if (nationalId === 'failure') { + return Promise.resolve>({ + ok: true, + data: { + success: false, + }, + }) + } + + if (nationalId === '') { + return Promise.resolve>({ + ok: false, + error: { + code: 5, + message: 'some user error', + }, + }) + } + //some other error + return Promise.resolve>({ + ok: false, + error: { + code: 99, + message: 'some service error', + }, + }) + } + + verify = (inputData: string) => { + let parsedInput + try { + parsedInput = JSON.parse(inputData) as VerifyInputData + } catch (ex) { + return Promise.resolve>({ + ok: false, + error: { + code: 12, + message: 'Invalid input data', + }, + }) + } + + const { code } = parsedInput + if (!code) { + return Promise.resolve>({ + ok: false, + error: { + code: 4, + message: + 'Invalid input data, either code or date are missing or invalid', + }, + }) + } + + if (code === 'success') { + return Promise.resolve>({ + ok: true, + data: { + valid: true, + }, + }) + } + + if (code === 'failure') { + return Promise.resolve>({ + ok: true, + data: { + valid: false, + }, + }) + } + //some other error + return Promise.resolve>({ + ok: false, + error: { + code: 99, + message: 'some service error', + }, + }) + } +} + describe('LicenseService', () => { let licenseService: LicenseService let barcodeService: BarcodeService @@ -237,6 +396,8 @@ describe('LicenseService', () => { ], providers: [ LicenseService, + LicenseServiceV1, + LicenseServiceV2, BarcodeService, { provide: LOGGER_PROVIDER, @@ -257,6 +418,10 @@ describe('LicenseService', () => { provide: SmartSolutionsApi, useClass: jest.fn(() => ({})), }, + { + provide: SmartSolutionsService, + useClass: jest.fn(() => ({})), + }, { provide: PASS_TEMPLATE_IDS, useValue: { @@ -267,15 +432,21 @@ describe('LicenseService', () => { }, { provide: LicenseUpdateClientService, - useFactory: (logger, smart) => ({ + useFactory: (logger, smart, smartv2) => ({ getLicenseUpdateClientByType: async (): Promise => new MockUpdateClient(logger, smart), getLicenseUpdateClientByPassTemplateId: async (): Promise => new MockUpdateClient(logger, smart), + getLicenseUpdateClientV2ByType: + async (): Promise => + new MockUpdateClientV2(logger, smartv2), + getLicenseUpdateClientV2ByPassTemplateId: + async (): Promise => + new MockUpdateClientV2(logger, smartv2), }), - inject: [LOGGER_PROVIDER, SmartSolutionsApi], + inject: [LOGGER_PROVIDER, SmartSolutionsApi, SmartSolutionsService], }, { provide: BarcodeService, From 3f195548d18673cd3de04b3dc0252d105a1d53d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Wed, 9 Oct 2024 09:41:37 +0000 Subject: [PATCH 16/29] fix: add version test --- .../license/test/license.service.spec.ts | 385 ++++++++++-------- 1 file changed, 206 insertions(+), 179 deletions(-) diff --git a/apps/services/license-api/src/app/modules/license/test/license.service.spec.ts b/apps/services/license-api/src/app/modules/license/test/license.service.spec.ts index a2c4e76e1900..361b6805b299 100644 --- a/apps/services/license-api/src/app/modules/license/test/license.service.spec.ts +++ b/apps/services/license-api/src/app/modules/license/test/license.service.spec.ts @@ -3,6 +3,9 @@ import { BaseLicenseUpdateClientV2, LicenseType, LicenseUpdateClientService, + PassData, + PassDataInput as PassDataInputV2, + PassRevocationData, } from '@island.is/clients/license-client' import { Pass, @@ -38,6 +41,7 @@ import { BARCODE_EXPIRE_TIME_IN_SEC } from '@island.is/services/license' import { VerifyInputData } from '../dto/verifyLicense.input' import { LicenseService } from '../license.service' import { + LicenseApiVersion, LicenseId, LicenseUpdateType, PASS_TEMPLATE_IDS, @@ -45,10 +49,12 @@ import { import { SmartSolutionsService } from '@island.is/clients/smart-solutions-v2' import { LicenseServiceV1 } from '../licenseV1.service' import { LicenseServiceV2 } from '../licenseV2.service' +import { PassVerificationData } from 'libs/clients/license-client/src/lib/licenseClient.type' const { randomUUID } = new ShortUniqueId({ length: 16 }) const cacheStore = new Map() const licenseIds = Object.values(LicenseId) +const versions = Object.values(LicenseApiVersion) const createCacheData = (licenseId: LicenseId): BarcodeData => ({ nationalId: faker.datatype.number({ min: 10, max: 10 }).toString(), @@ -467,232 +473,253 @@ describe('LicenseService', () => { barcodeService = moduleRef.get(BarcodeService) }) - describe.each(licenseIds)('given %s license type id', (licenseId) => { - describe('verify', () => { - it(`should verify the ${licenseId} license`, async () => { - //act - const result = await licenseService.verifyLicense({ - barcodeData: JSON.stringify({ - passTemplateId: licenseId.toString(), - passTemplateName: licenseId.toString(), - code: 'success', - date: '2022-06-28T15:42:11.665950Z', - }), - }) + describe.each(versions)('given version %s', (version) => { + describe.each(licenseIds)('given %s license type id', (licenseId) => { + describe('verify', () => { + it(`should verify the ${licenseId} license in api version ${version}`, async () => { + //act + const result = await licenseService.verifyLicense({ + barcodeData: JSON.stringify({ + passTemplateId: licenseId.toString(), + passTemplateName: licenseId.toString(), + code: 'success', + date: '2022-06-28T15:42:11.665950Z', + apiVersion: version, + }), + }) - //assert - expect(result).toMatchObject({ - valid: true, + //assert + expect(result).toMatchObject({ + valid: true, + }) }) - }) - it(`should verify barcodeData as token for the ${licenseId} license`, async () => { - // Act - const code = randomUUID() - const data = - licenseId === LicenseId.DRIVING_LICENSE - ? createCacheData(licenseId) - : undefined - - // Create token - const token = await barcodeService.createToken({ - v: '1', - t: getLicenseType(licenseId), - c: code, - }) + it(`should verify barcodeData as token for the ${licenseId} license`, async () => { + // Act + const code = randomUUID() + const data = + licenseId === LicenseId.DRIVING_LICENSE + ? createCacheData(licenseId) + : undefined + + // Create token + const token = await barcodeService.createToken({ + v: '1', + t: getLicenseType(licenseId), + c: code, + }) - if (data) { - // Put data in cache - await barcodeService.setCache(code, data) - } + if (data) { + // Put data in cache + await barcodeService.setCache(code, data) + } + + const result = await licenseService.verifyLicense({ + barcodeData: token.token, + }) - const result = await licenseService.verifyLicense({ - barcodeData: token.token, + // Assert + // Only driver's license is able to get extra data from the token for now + if (licenseId !== LicenseId.DRIVING_LICENSE) { + expect(result).toMatchObject({ + valid: false, + }) + } else { + expect(result).toMatchObject({ + valid: true, + passIdentity: { + nationalId: data?.nationalId, + name: data?.extraData?.name, + }, + }) + } }) - // Assert - // Only driver's license is able to get extra data from the token for now - if (licenseId !== LicenseId.DRIVING_LICENSE) { - expect(result).toMatchObject({ - valid: false, + it(`should fail to verify barcodeData token because of token expire time for the ${licenseId} license`, async () => { + jest.useFakeTimers({ + advanceTimers: true, }) - } else { - expect(result).toMatchObject({ - valid: true, - passIdentity: { - nationalId: data?.nationalId, - name: data?.extraData?.name, - }, - }) - } - }) - it(`should fail to verify barcodeData token because of token expire time for the ${licenseId} license`, async () => { - jest.useFakeTimers({ - advanceTimers: true, - }) + // Act + const code = randomUUID() + const data = createCacheData(licenseId) - // Act - const code = randomUUID() - const data = createCacheData(licenseId) + // Create token + const token = await barcodeService.createToken({ + v: '1', + t: getLicenseType(licenseId), + c: code, + }) - // Create token - const token = await barcodeService.createToken({ - v: '1', - t: getLicenseType(licenseId), - c: code, - }) + // Put data in cache + await barcodeService.setCache(code, data) - // Put data in cache - await barcodeService.setCache(code, data) + // Let the token expire + jest.advanceTimersByTime(BARCODE_EXPIRE_TIME_IN_SEC * 1000) - // Let the token expire - jest.advanceTimersByTime(BARCODE_EXPIRE_TIME_IN_SEC * 1000) + // Assert + const result = await licenseService.verifyLicense({ + barcodeData: token.token, + }) - // Assert - const result = await licenseService.verifyLicense({ - barcodeData: token.token, + expect(result).toEqual({ + valid: false, + }) }) - expect(result).toEqual({ - valid: false, - }) - }) + it(`should fail to verify the ${licenseId} license in apiversion ${version}`, async () => { + //act + const result = await licenseService.verifyLicense({ + barcodeData: JSON.stringify({ + passTemplateId: licenseId.toString(), + passTemplateName: licenseId.toString(), + code: 'failure', + date: '2022-06-28T15:42:11.665950Z', + apiVersion: version, + }), + }) - it(`should fail to verify the ${licenseId} license`, async () => { - //act - const result = await licenseService.verifyLicense({ - barcodeData: JSON.stringify({ - passTemplateId: licenseId.toString(), - passTemplateName: licenseId.toString(), - code: 'failure', - date: '2022-06-28T15:42:11.665950Z', - }), + //assert + expect(result).toMatchObject({ + valid: false, + }) }) + it(`should throw user error on bad input when trying to verify the ${licenseId} license using version ${version}`, async () => { + //act + const result = licenseService.verifyLicense({ + barcodeData: JSON.stringify({ + passTemplateId: licenseId.toString(), + passTemplateName: licenseId.toString(), + code: '', + date: '2022-06-28T15:42:11.665950Z', + apiVersion: version, + }), + }) - //assert - expect(result).toMatchObject({ - valid: false, - }) - }) - it(`should throw user error on bad input when trying to verify the ${licenseId} license`, async () => { - //act - const result = licenseService.verifyLicense({ - barcodeData: JSON.stringify({ - passTemplateId: licenseId.toString(), - passTemplateName: licenseId.toString(), - code: '', - date: '2022-06-28T15:42:11.665950Z', - }), + //assert + await expect(result).rejects.toThrow( + new BadRequestException(['Invalid input data']), + ) }) - //assert - await expect(result).rejects.toThrow( - new BadRequestException(['Invalid input data']), - ) - }) - - it(`should throw 500 error when client return an error with error code > 10 when trying to verify the ${licenseId} license`, async () => { - //act - const result = licenseService.verifyLicense({ - barcodeData: JSON.stringify({ - passTemplateId: licenseId.toString(), - passTemplateName: licenseId.toString(), - code: 'invalid', - date: '2022-06-28T15:42:11.665950Z', - }), - }) + it(`should throw 500 error when client return an error with error code > 10 when trying to verify the ${licenseId} license using version ${version}`, async () => { + //act + const result = licenseService.verifyLicense({ + barcodeData: JSON.stringify({ + passTemplateId: licenseId.toString(), + passTemplateName: licenseId.toString(), + code: 'invalid', + date: '2022-06-28T15:42:11.665950Z', + apiVersion: version, + }), + }) - //assert - await expect(result).rejects.toThrow( - new InternalServerErrorException(['some service error']), - ) - }) - }) - describe('revoke', () => { - it(`should to revoke the ${licenseId} license`, async () => { - //act - const result = await licenseService.revokeLicense(licenseId, 'success') - - //assert - expect(result).toMatchObject({ - revokeSuccess: true, + //assert + await expect(result).rejects.toThrow( + new InternalServerErrorException(['some service error']), + ) }) }) - it(`should fail to revoke the ${licenseId} license`, async () => { - //act - const result = await licenseService.revokeLicense(licenseId, 'failure') + describe('revoke', () => { + it(`should to revoke the ${licenseId} license using version ${version}`, async () => { + //act + const result = await licenseService.revokeLicense( + licenseId, + 'success', + { apiVersion: version }, + ) - //assert - expect(result).toMatchObject({ - revokeSuccess: false, + //assert + expect(result).toMatchObject({ + revokeSuccess: true, + }) }) - }) - it(`should throw user error on bad input when trying to revoke the ${licenseId} license`, async () => { - //act - const result = licenseService.revokeLicense(licenseId, '') - - //assert - await expect(result).rejects.toThrow( - new BadRequestException(['some user error']), - ) - }) - it(`should throw server error when trying to revoke the ${licenseId} license with an invalid national id`, async () => { - //act - const result = licenseService.revokeLicense(licenseId, 'invalid') - - //assert - await expect(result).rejects.toThrow( - new InternalServerErrorException(['some service error']), - ) - }) - }) - - describe.each(Object.values(LicenseUpdateType))( - 'update %s', - (licenseUpdateType) => { - it(`should ${licenseUpdateType}-update the ${licenseId} license`, async () => { + it(`should fail to revoke the ${licenseId} license using version ${version}`, async () => { //act - const result = await licenseService.updateLicense( + const result = await licenseService.revokeLicense( licenseId, - 'success', - { - licenseUpdateType, - expiryDate: '2022-01-01T00:00:00Z', - }, + 'failure', + { apiVersion: version }, ) //assert expect(result).toMatchObject({ - updateSuccess: true, - data: undefined, + revokeSuccess: false, }) }) - it(`should throw user error on bad input when trying to ${licenseUpdateType}-update the ${licenseId} `, async () => { + it(`should throw user error on bad input when trying to revoke the ${licenseId} license using version ${version}`, async () => { //act - const result = licenseService.updateLicense(licenseId, '', { - licenseUpdateType, - expiryDate: '2022-01-01T00:00:00Z', + const result = licenseService.revokeLicense(licenseId, '', { + apiVersion: version, }) //assert - await expect(result).rejects.toThrowError( + await expect(result).rejects.toThrow( new BadRequestException(['some user error']), ) }) - it(`should throw server error when trying to ${licenseUpdateType}-update the ${licenseId} with an invalid national id `, async () => { + it(`should throw server error when trying to revoke the ${licenseId} license with an invalid national id using version ${version}`, async () => { //act - const result = licenseService.updateLicense(licenseId, 'invalid', { - licenseUpdateType, - expiryDate: '2022-01-01T00:00:00Z', + const result = licenseService.revokeLicense(licenseId, 'invalid', { + apiVersion: version, }) //assert - await expect(result).rejects.toThrowError( + await expect(result).rejects.toThrow( new InternalServerErrorException(['some service error']), ) }) - }, - ) + }) + + describe.each(Object.values(LicenseUpdateType))( + 'update %s', + (licenseUpdateType) => { + it(`should ${licenseUpdateType}-update the ${licenseId} license using version ${version}`, async () => { + //act + const result = await licenseService.updateLicense( + licenseId, + 'success', + { + licenseUpdateType, + expiryDate: '2022-01-01T00:00:00Z', + apiVersion: version, + }, + ) + + //assert + expect(result).toMatchObject({ + updateSuccess: true, + data: undefined, + }) + }) + it(`should throw user error on bad input when trying to ${licenseUpdateType}-update the ${licenseId} using version ${version} `, async () => { + //act + const result = licenseService.updateLicense(licenseId, '', { + licenseUpdateType, + expiryDate: '2022-01-01T00:00:00Z', + apiVersion: version, + }) + + //assert + await expect(result).rejects.toThrowError( + new BadRequestException(['some user error']), + ) + }) + it(`should throw server error when trying to ${licenseUpdateType}-update the ${licenseId} with an invalid national id using version ${version}`, async () => { + //act + const result = licenseService.updateLicense(licenseId, 'invalid', { + licenseUpdateType, + expiryDate: '2022-01-01T00:00:00Z', + apiVersion: version, + }) + + //assert + await expect(result).rejects.toThrowError( + new InternalServerErrorException(['some service error']), + ) + }) + }, + ) + }) }) }) From bee7309bcc23e938f9d0cd50a7f3094385ed18bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Wed, 9 Oct 2024 09:48:57 +0000 Subject: [PATCH 17/29] chore: make nice --- .../app/modules/license/license.service.ts | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/apps/services/license-api/src/app/modules/license/license.service.ts b/apps/services/license-api/src/app/modules/license/license.service.ts index 569818721d85..dc6f69d4b703 100644 --- a/apps/services/license-api/src/app/modules/license/license.service.ts +++ b/apps/services/license-api/src/app/modules/license/license.service.ts @@ -18,15 +18,21 @@ export class LicenseService { private readonly serviceV2: LicenseServiceV2, ) {} + private readonly serviceMap = { + [LicenseApiVersion.v1]: this.serviceV1, + [LicenseApiVersion.v2]: this.serviceV2, + } + + private getService = (apiVersion?: LicenseApiVersion) => + apiVersion ? this.serviceMap[apiVersion] : this.serviceV1 + async updateLicense( licenseId: LicenseId, nationalId: string, inputData: UpdateLicenseRequest, ): Promise { - if (inputData.apiVersion === LicenseApiVersion.v2) { - return this.serviceV2.updateLicense(licenseId, nationalId, inputData) - } - return this.serviceV1.updateLicense(licenseId, nationalId, inputData) + const service = this.getService(inputData.apiVersion) + return service.updateLicense(licenseId, nationalId, inputData) } async revokeLicense( @@ -34,18 +40,14 @@ export class LicenseService { nationalId: string, inputData?: RevokeLicenseRequest, ): Promise { - if (inputData?.apiVersion === LicenseApiVersion.v2) { - return this.serviceV2.revokeLicense(licenseId, nationalId, inputData) - } - return this.serviceV1.revokeLicense(licenseId, nationalId, inputData) + const service = this.getService(inputData?.apiVersion) + return service.revokeLicense(licenseId, nationalId, inputData) } async verifyLicense( inputData: VerifyLicenseRequest, ): Promise { - if (inputData?.apiVersion === LicenseApiVersion.v2) { - return this.serviceV2.verifyLicense(inputData) - } - return this.serviceV1.verifyLicense(inputData) + const service = this.getService(inputData?.apiVersion) + return service.verifyLicense(inputData) } } From 9109d7f9745e110b3ceeb6c94db2bd733741472f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Wed, 9 Oct 2024 10:07:39 +0000 Subject: [PATCH 18/29] fix: json parsing --- .../disabilityLicense.types.ts | 9 +++++++ ...disabilityLicenseUpdateClientV2.service.ts | 27 ++++++++++++++++--- .../drivingLicenseUpdateClientV2.service.ts | 18 +++++++++++-- .../firearmLicenseUpdateClientV2.service.ts | 17 ++++++++++-- 4 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 libs/clients/license-client/src/lib/clients/disability-license-client/disabilityLicense.types.ts diff --git a/libs/clients/license-client/src/lib/clients/disability-license-client/disabilityLicense.types.ts b/libs/clients/license-client/src/lib/clients/disability-license-client/disabilityLicense.types.ts new file mode 100644 index 000000000000..c1a7a6edfd17 --- /dev/null +++ b/libs/clients/license-client/src/lib/clients/disability-license-client/disabilityLicense.types.ts @@ -0,0 +1,9 @@ +import { IsString } from 'class-validator' + +export class VerifyInputDataDto { + @IsString() + code!: string + + @IsString() + date!: string +} diff --git a/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClientV2.service.ts b/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClientV2.service.ts index bd106d9f994b..43e4f371ef83 100644 --- a/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClientV2.service.ts +++ b/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClientV2.service.ts @@ -11,6 +11,9 @@ import { } from '../../../licenseClient.type' import { BaseLicenseUpdateClientV2 } from '../../base/licenseUpdateClientV2' import { PkPassService } from '../../../helpers/pkPassService/pkPass.service' +import { VerifyInputDataDto } from '../disabilityLicense.types' +import { plainToInstance } from 'class-transformer' +import { validate } from 'class-validator' @Injectable() export class DisabilityLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { @@ -38,14 +41,30 @@ export class DisabilityLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { } } - revoke(nationalId: string): Promise> { - throw new Error('Method not implemented.') + async revoke(nationalId: string): Promise> { + return { + ok: false, + error: { + code: 99, + message: 'not implemented yet', + }, + } } async verify(inputData: string): Promise> { - let parsedInput + let parsedInput: VerifyInputDataDto try { - parsedInput = JSON.parse(inputData) as VerifyInputData + parsedInput = plainToInstance(VerifyInputDataDto, JSON.parse(inputData)) + const errors = await validate(parsedInput) + if (errors.length > 0) { + return { + ok: false, + error: { + code: 12, + message: 'Invalid input data', + }, + } + } } catch (ex) { return { ok: false, diff --git a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts index a1827c0ac374..f115968ad196 100644 --- a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts +++ b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts @@ -19,6 +19,9 @@ import { import { DrivingDigitalLicenseClientConfig } from '../drivingLicenseClient.config' import { BaseLicenseUpdateClientV2 } from '../../base/licenseUpdateClientV2' import { PkPassService } from '../../../helpers/pkPassService/pkPass.service' +import { VerifyInputDataDto } from '../../disability-license-client/disabilityLicense.types' +import { plainToInstance } from 'class-transformer' +import { validate } from 'class-validator' /** Category to attach each log message to */ const LOG_CATEGORY = 'driving-license-service' @@ -163,9 +166,20 @@ export class DrivingLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { requestId?: string, ): Promise> { //need to parse the scanner data - let parsedInput + let parsedInput: VerifyInputDataDto try { - parsedInput = JSON.parse(inputData) as VerifyInputData + parsedInput = plainToInstance(VerifyInputDataDto, JSON.parse(inputData)) + const errors = await validate(parsedInput) + if (errors.length > 0) { + return { + ok: false, + error: { + code: 12, + message: + 'Pkpass verification data input mapping failed, data may be invalid', + }, + } + } } catch (ex) { this.logger.error( 'Pkpass verification data input mapping failed, data may be invalid', diff --git a/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClientV2.service.ts b/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClientV2.service.ts index 728e81c3d0e8..4aded9cc6f05 100644 --- a/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClientV2.service.ts +++ b/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClientV2.service.ts @@ -17,6 +17,9 @@ import type { ConfigType } from '@island.is/nest/config' import { FirearmDigitalLicenseClientConfig } from '../firearmLicenseClient.config' import { BaseLicenseUpdateClientV2 } from '../../base/licenseUpdateClientV2' import { PkPassService } from '../../../helpers/pkPassService/pkPass.service' +import { VerifyInputDataDto } from '../../disability-license-client/disabilityLicense.types' +import { plainToInstance } from 'class-transformer' +import { validate } from 'class-validator' /** Category to attach each log message to */ const LOG_CATEGORY = 'firearmlicense-service' @@ -164,9 +167,19 @@ export class FirearmLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { requestId?: string, ): Promise> { //need to parse the scanner data - let parsedInput + let parsedInput: VerifyInputDataDto try { - parsedInput = JSON.parse(inputData) as VerifyInputData + parsedInput = plainToInstance(VerifyInputDataDto, JSON.parse(inputData)) + const errors = await validate(parsedInput) + if (errors.length > 0) { + return { + ok: false, + error: { + code: 12, + message: 'Invalid input data', + }, + } + } } catch (ex) { return { ok: false, From 9374b9d7a838245481da0480455cb22fdcdfb74d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Wed, 9 Oct 2024 10:08:42 +0000 Subject: [PATCH 19/29] chore: fix deprecation messages --- .../license-client/src/lib/licenseUpdateClient.service.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libs/clients/license-client/src/lib/licenseUpdateClient.service.ts b/libs/clients/license-client/src/lib/licenseUpdateClient.service.ts index 5f098dfa3af7..e90ddf4dda8a 100644 --- a/libs/clients/license-client/src/lib/licenseUpdateClient.service.ts +++ b/libs/clients/license-client/src/lib/licenseUpdateClient.service.ts @@ -69,7 +69,9 @@ export class LicenseUpdateClientService { return this.config[licenseId] } - //DEPRECATED + /** + * @deprecated Use getLicenseUpdateClientV2ByType instead. + */ getLicenseUpdateClientByType(type: LicenseType, requestId?: string) { return this.licenseUpdateClientFactory(type, requestId) } @@ -78,7 +80,9 @@ export class LicenseUpdateClientService { return this.licenseUpdateClientFactoryV2(type, requestId) } - //DEPRECATED + /** + * @deprecated Use getLicenseUpdateClientV2ByPassTemplateId instead. + */ getLicenseUpdateClientByPassTemplateId( passTemplateId: string, requestId?: string, From 48bc124c34f3aa92d8e12b28009f230a772335a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Wed, 9 Oct 2024 10:13:47 +0000 Subject: [PATCH 20/29] fix: update types --- .../src/lib/helpers/pkPassService/pkPass.mapper.ts | 6 +++--- .../license-client/src/lib/licenseClient.type.ts | 11 ++++------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.mapper.ts b/libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.mapper.ts index ce04e21c604a..e48ea5009ac9 100644 --- a/libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.mapper.ts +++ b/libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.mapper.ts @@ -10,8 +10,8 @@ export const mapPassData = (pass: PassV1 | PassV2): PassData => ({ value: i.value ?? undefined, })), expirationDate: pass?.expirationDate - ? new Date(pass?.expirationDate) + ? new Date(pass?.expirationDate).toISOString() : undefined, - whenCreated: new Date(pass.whenCreated), - whenModified: new Date(pass.whenModified), + whenCreated: new Date(pass.whenCreated).toISOString(), + whenModified: new Date(pass.whenModified).toISOString(), }) diff --git a/libs/clients/license-client/src/lib/licenseClient.type.ts b/libs/clients/license-client/src/lib/licenseClient.type.ts index e350632bbf11..258327eb999b 100644 --- a/libs/clients/license-client/src/lib/licenseClient.type.ts +++ b/libs/clients/license-client/src/lib/licenseClient.type.ts @@ -135,9 +135,9 @@ export type PassData = { deliveryPageUrl: string distributionQRCode: string id: string - expirationDate?: Date - whenCreated: Date - whenModified: Date + expirationDate?: string + whenCreated: string + whenModified: string inputFieldValues?: Array<{ id: string identifier: string @@ -232,10 +232,7 @@ export interface LicenseClient { ) => Promise getPkPassUrl?: (user: User, locale?: Locale) => Promise> getPkPassQRCode?: (user: User, locale?: Locale) => Promise> - verifyPkPassDeprecated?: ( - data: string, - version?: 'v1' | 'v2', - ) => Promise> + verifyPkPassDeprecated?: (data: string) => Promise> verifyPkPass?: ( data: string, version?: 'v1' | 'v2', From 86516d2e25b4da5c0c40edb3270345bd933a5da7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Wed, 9 Oct 2024 10:23:14 +0000 Subject: [PATCH 21/29] fix: rabbit review --- .../services/drivingLicenseUpdateClientV2.service.ts | 2 +- .../services/firearmLicenseUpdateClientV2.service.ts | 1 - .../src/lib/helpers/pkPassService/pkPass.service.ts | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts index f115968ad196..7fdb439ab528 100644 --- a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts +++ b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts @@ -229,7 +229,7 @@ export class DrivingLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { } if (!verifyRes.data.valid) { - this.logger.debug('PkPass is valid', { + this.logger.debug('PkPass is invalid', { requestId, category: LOG_CATEGORY, }) diff --git a/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClientV2.service.ts b/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClientV2.service.ts index 4aded9cc6f05..1ffcef956665 100644 --- a/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClientV2.service.ts +++ b/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClientV2.service.ts @@ -9,7 +9,6 @@ import { PassRevocationData, PassVerificationData, Result, - VerifyInputData, } from '../../../licenseClient.type' import { createPkPassDataInput, nationalIdIndex } from '../firearmLicenseMapper' import { mapNationalId } from '../firearmLicenseMapper' diff --git a/libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.service.ts b/libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.service.ts index e497f6983a2d..8f5cf191dbdd 100644 --- a/libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.service.ts +++ b/libs/clients/license-client/src/lib/helpers/pkPassService/pkPass.service.ts @@ -19,7 +19,7 @@ export class PkPassService { @Inject(LOGGER_PROVIDER) private readonly logger: Logger, private readonly featureFlagService: FeatureFlagService, private readonly newSmartService: SmartSolutionsService, - /** DEPRECATED */ + /** @deprecated */ private readonly oldSmartService: SmartSolutionsApi, ) {} From cb2f93b2c9bd3214ced0ddde1610ed63f0abd8f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Wed, 9 Oct 2024 10:25:44 +0000 Subject: [PATCH 22/29] chore: use constant --- .../drivingLicenseUpdateClientV2.service.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts index 7fdb439ab528..b1385302d1bc 100644 --- a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts +++ b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts @@ -26,6 +26,8 @@ import { validate } from 'class-validator' /** Category to attach each log message to */ const LOG_CATEGORY = 'driving-license-service' +const apiVersion = 'v2' + @Injectable() export class DrivingLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { constructor( @@ -59,7 +61,7 @@ export class DrivingLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { }, requestId, undefined, - 'v2', + apiVersion, ) } @@ -140,7 +142,12 @@ export class DrivingLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { : undefined, } - return this.passService.updatePkPass(payload, requestId, undefined, 'v2') + return this.passService.updatePkPass( + payload, + requestId, + undefined, + apiVersion, + ) } revoke( @@ -156,7 +163,7 @@ export class DrivingLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { payload, requestId, undefined, - 'v2', + apiVersion, ) } @@ -221,7 +228,7 @@ export class DrivingLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { const verifyRes = await this.passService.verifyPkPass( { code, date }, requestId, - 'v2', + apiVersion, ) if (!verifyRes.ok) { From 1a1d0c7b2510ead4cf869b7876c35f61b0234d09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Wed, 9 Oct 2024 10:27:12 +0000 Subject: [PATCH 23/29] chore: review --- .../services/drivingLicenseUpdateClientV2.service.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts index b1385302d1bc..be6179839ee1 100644 --- a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts +++ b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts @@ -8,7 +8,6 @@ import { PassRevocationData, PassVerificationData, Result, - VerifyInputData, } from '../../../licenseClient.type' import { DrivingLicenseApi } from '@island.is/clients/driving-license' import { @@ -49,7 +48,7 @@ export class DrivingLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { //small check that nationalId doesnt' already exist if ( inputFieldValues && - !inputFieldValues?.some((nt) => nt.identifier === nationalIdIndex) + !inputFieldValues?.some((nt) => nt.identifier === 'kennitala') ) { inputFieldValues.push(mapNationalId(nationalId)) } From 45bcea26262e2d18c1884c49665caadbd5e65cef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Wed, 9 Oct 2024 10:28:44 +0000 Subject: [PATCH 24/29] chore: remove variables --- .../services/drivingLicenseUpdateClientV2.service.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts index be6179839ee1..cebfd21f8746 100644 --- a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts +++ b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts @@ -284,8 +284,6 @@ export class DrivingLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { } const licenseNationalId = license.socialSecurityNumber - const name = license.name ?? '' - const picture = license.photo?.image ?? '' if (!licenseNationalId || !name || !picture) { this.logger.error('Missing data. NationalId, name or photo missing', { @@ -307,8 +305,8 @@ export class DrivingLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { valid: licenseNationalId === nationalId, passIdentity: { nationalId: licenseNationalId, - name, - picture, + name: license.name ?? '', + picture: license.photo?.image ?? '', }, }, } From d9d4b734fd85c11f1e44c3ee404d80beeae99070 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Wed, 9 Oct 2024 10:38:04 +0000 Subject: [PATCH 25/29] fix: better error --- .../src/app/modules/license/licenseV2.service.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/services/license-api/src/app/modules/license/licenseV2.service.ts b/apps/services/license-api/src/app/modules/license/licenseV2.service.ts index ab48a74a942a..025dbe42bf42 100644 --- a/apps/services/license-api/src/app/modules/license/licenseV2.service.ts +++ b/apps/services/license-api/src/app/modules/license/licenseV2.service.ts @@ -307,10 +307,10 @@ export class LicenseServiceV2 { requestId, error: revokeRes.error, }) - throw this.getException( - this.getErrorTypeByCode(revokeRes.error.code), - revokeRes.error.message, - ) + throw this.getException(this.getErrorTypeByCode(revokeRes.error.code), { + error: revokeRes.error, + requestId, + }) } async getDataFromToken( From e78bdf1ae32043532c2263cd9aea0d3ece5440be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Wed, 9 Oct 2024 10:47:02 +0000 Subject: [PATCH 26/29] fix: revert constat deletion --- .../app/modules/license/licenseV1.service.ts | 97 ++++++++++++------- .../app/modules/license/licenseV2.service.ts | 52 ++++++---- .../drivingLicenseUpdateClientV2.service.ts | 6 +- 3 files changed, 95 insertions(+), 60 deletions(-) diff --git a/apps/services/license-api/src/app/modules/license/licenseV1.service.ts b/apps/services/license-api/src/app/modules/license/licenseV1.service.ts index a73fd594dc49..c6f75e4e1b43 100644 --- a/apps/services/license-api/src/app/modules/license/licenseV1.service.ts +++ b/apps/services/license-api/src/app/modules/license/licenseV1.service.ts @@ -70,74 +70,97 @@ export class LicenseServiceV1 { private generateRequestId = () => uuid() - private async getClient( - identifier: LicenseId | string, - type: 'licenseId' | 'passTemplateId', + private getClientByLicenseType = async ( + licenseId: LicenseId, requestId?: string, - ): Promise { - let service: BaseLicenseUpdateClient | null - let extraLoggerProperties: any - - if (type === 'licenseId') { - const type = mapLicenseIdToLicenseType(identifier as LicenseId) + ) => { + const type = mapLicenseIdToLicenseType(licenseId) - if (!type) { - this.logger.error(`Invalid license type`, { - category: LOG_CATEGORY, - requestId: requestId, - type, - }) - throw new BadRequestException(`Invalid license type`) - } - this.logger.debug('Retrieving a licence client by license id', { + if (!type) { + this.logger.error(`Invalid license type`, { category: LOG_CATEGORY, requestId: requestId, type, }) + throw new BadRequestException(`Invalid license type`) + } + this.logger.debug('Retrieving a licence client by license id', { + category: LOG_CATEGORY, + requestId: requestId, + type, + }) - extraLoggerProperties = { - type: type, - } + const service = await this.getLicenseUpdateClientByType(type, requestId) - service = await this.getLicenseUpdateClientByType(type, requestId) - } else { - this.logger.debug('Retrieving a licence client by pass template id', { + this.logger.debug('Injecting the proper license client..', { + category: LOG_CATEGORY, + requestId: requestId, + type, + }) + + if (!service) { + this.logger.error(`Client service generation failed`, { category: LOG_CATEGORY, - requestId: requestId, - passTemplateId: identifier, + type, }) + throw new InternalServerErrorException(`Client service generation failed`) + } + this.logger.debug('Client injection successful', { + category: LOG_CATEGORY, + requestId: requestId, + type, + }) - extraLoggerProperties = { - passTemplateId: identifier, - } + return service + } + + private getClientByPassTemplateId = async ( + passTemplateId: string, + requestId?: string, + ) => { + this.logger.debug('Retrieving a licence client by pass template id', { + category: LOG_CATEGORY, + requestId: requestId, + passTemplateId, + }) + + const service = await this.getLicenseUpdateClientByPassTemplateId( + passTemplateId, + requestId, + ) - service = await this.getLicenseUpdateClientByPassTemplateId( - identifier, - requestId, - ) - } this.logger.debug('Injecting the proper license client..', { category: LOG_CATEGORY, requestId: requestId, - ...extraLoggerProperties, + passTemplateId, }) if (!service) { this.logger.error(`Client service generation failed`, { category: LOG_CATEGORY, - ...extraLoggerProperties, + passTemplateId, }) throw new InternalServerErrorException(`Client service generation failed`) } this.logger.debug('Client injection successful', { category: LOG_CATEGORY, requestId: requestId, - ...extraLoggerProperties, + passTemplateId, }) return service } + private async getClient( + identifier: LicenseId | string, + type: 'licenseId' | 'passTemplateId', + requestId?: string, + ): Promise { + return type === 'licenseId' + ? this.getClientByLicenseType(identifier as LicenseId, requestId) + : this.getClientByPassTemplateId(identifier, requestId) + } + private async pushUpdateLicense( service: BaseLicenseUpdateClient, expirationDate: string, diff --git a/apps/services/license-api/src/app/modules/license/licenseV2.service.ts b/apps/services/license-api/src/app/modules/license/licenseV2.service.ts index 025dbe42bf42..6a1494782193 100644 --- a/apps/services/license-api/src/app/modules/license/licenseV2.service.ts +++ b/apps/services/license-api/src/app/modules/license/licenseV2.service.ts @@ -72,36 +72,32 @@ export class LicenseServiceV2 { private generateRequestId = () => uuid() - private async getClientByLicenseId( + private getClientByLicenseType = async ( licenseId: LicenseId, requestId?: string, - ): Promise { + ) => { const type = mapLicenseIdToLicenseType(licenseId) - this.logger.debug('Retrieving a licence client by license id', { - category: LOG_CATEGORY, - requestId: requestId, - type: type, - }) - if (!type) { this.logger.error(`Invalid license type`, { category: LOG_CATEGORY, requestId: requestId, type, }) - throw new InternalServerErrorException(`Invalid license type`) + throw new BadRequestException(`Invalid license type`) } + this.logger.debug('Retrieving a licence client by license id', { + category: LOG_CATEGORY, + requestId: requestId, + type, + }) - const service = await this.getLicenseUpdateClientByType( - type as LicenseType, - requestId, - ) + const service = await this.getLicenseUpdateClientByType(type, requestId) this.logger.debug('Injecting the proper license client..', { category: LOG_CATEGORY, requestId: requestId, - type: type, + type, }) if (!service) { @@ -114,16 +110,16 @@ export class LicenseServiceV2 { this.logger.debug('Client injection successful', { category: LOG_CATEGORY, requestId: requestId, - type: type, + type, }) return service } - private async getClientByPassTemplateId( + private getClientByPassTemplateId = async ( passTemplateId: string, requestId?: string, - ): Promise { + ) => { this.logger.debug('Retrieving a licence client by pass template id', { category: LOG_CATEGORY, requestId: requestId, @@ -144,15 +140,29 @@ export class LicenseServiceV2 { if (!service) { this.logger.error(`Client service generation failed`, { category: LOG_CATEGORY, - requestId: requestId, passTemplateId, }) throw new InternalServerErrorException(`Client service generation failed`) } + this.logger.debug('Client injection successful', { + category: LOG_CATEGORY, + requestId: requestId, + passTemplateId, + }) return service } + private async getClient( + identifier: LicenseId | string, + type: 'licenseId' | 'passTemplateId', + requestId?: string, + ): Promise { + return type === 'licenseId' + ? this.getClientByLicenseType(identifier as LicenseId, requestId) + : this.getClientByPassTemplateId(identifier, requestId) + } + private async pushUpdateLicense( service: BaseLicenseUpdateClientV2, expirationDate: string, @@ -220,7 +230,7 @@ export class LicenseServiceV2 { ): Promise { const requestId = inputData.requestId ?? this.generateRequestId() - const service = await this.getClientByLicenseId(licenseId, requestId) + const service = await this.getClient(licenseId, 'licenseId', requestId) this.logger.debug('License update initiated', { category: LOG_CATEGORY, @@ -285,7 +295,7 @@ export class LicenseServiceV2 { inputData?: RevokeLicenseRequest, ): Promise { const requestId = inputData?.requestId ?? this.generateRequestId() - const service = await this.getClientByLicenseId(licenseId, requestId) + const service = await this.getClient(licenseId, 'licenseId', requestId) const revokeRes = await service.revoke(nationalId, requestId) @@ -386,7 +396,7 @@ export class LicenseServiceV2 { throw this.getException('BadRequest', 'Missing pass template id') } - const service = await this.getClientByPassTemplateId(passTemplateId) + const service = await this.getClient(passTemplateId, 'passTemplateId') const verifyRes = await service.verify(inputData.barcodeData, requestId) diff --git a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts index cebfd21f8746..71f7abba6b5f 100644 --- a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts +++ b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts @@ -284,6 +284,8 @@ export class DrivingLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { } const licenseNationalId = license.socialSecurityNumber + const name = license?.name ?? '' + const picture = license.photo?.image ?? '' if (!licenseNationalId || !name || !picture) { this.logger.error('Missing data. NationalId, name or photo missing', { @@ -305,8 +307,8 @@ export class DrivingLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { valid: licenseNationalId === nationalId, passIdentity: { nationalId: licenseNationalId, - name: license.name ?? '', - picture: license.photo?.image ?? '', + name, + picture, }, }, } From c87f2e6581204941fa9745ed1a51e4d93d77f0b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Wed, 9 Oct 2024 11:05:30 +0000 Subject: [PATCH 27/29] fix: move types --- .../baseLicenseUpdateClient.types.ts} | 0 .../services/disabilityLicenseUpdateClientV2.service.ts | 3 +-- .../services/drivingLicenseUpdateClientV2.service.ts | 2 +- .../services/firearmLicenseUpdateClientV2.service.ts | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) rename libs/clients/license-client/src/lib/clients/{disability-license-client/disabilityLicense.types.ts => base/baseLicenseUpdateClient.types.ts} (100%) diff --git a/libs/clients/license-client/src/lib/clients/disability-license-client/disabilityLicense.types.ts b/libs/clients/license-client/src/lib/clients/base/baseLicenseUpdateClient.types.ts similarity index 100% rename from libs/clients/license-client/src/lib/clients/disability-license-client/disabilityLicense.types.ts rename to libs/clients/license-client/src/lib/clients/base/baseLicenseUpdateClient.types.ts diff --git a/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClientV2.service.ts b/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClientV2.service.ts index 43e4f371ef83..6cb2680f166f 100644 --- a/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClientV2.service.ts +++ b/libs/clients/license-client/src/lib/clients/disability-license-client/services/disabilityLicenseUpdateClientV2.service.ts @@ -7,13 +7,12 @@ import { PassRevocationData, PassVerificationData, Result, - VerifyInputData, } from '../../../licenseClient.type' import { BaseLicenseUpdateClientV2 } from '../../base/licenseUpdateClientV2' import { PkPassService } from '../../../helpers/pkPassService/pkPass.service' -import { VerifyInputDataDto } from '../disabilityLicense.types' import { plainToInstance } from 'class-transformer' import { validate } from 'class-validator' +import { VerifyInputDataDto } from '../../base/baseLicenseUpdateClient.types' @Injectable() export class DisabilityLicenseUpdateClientV2 extends BaseLicenseUpdateClientV2 { diff --git a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts index 71f7abba6b5f..e44c73936842 100644 --- a/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts +++ b/libs/clients/license-client/src/lib/clients/driving-license-client/services/drivingLicenseUpdateClientV2.service.ts @@ -18,9 +18,9 @@ import { import { DrivingDigitalLicenseClientConfig } from '../drivingLicenseClient.config' import { BaseLicenseUpdateClientV2 } from '../../base/licenseUpdateClientV2' import { PkPassService } from '../../../helpers/pkPassService/pkPass.service' -import { VerifyInputDataDto } from '../../disability-license-client/disabilityLicense.types' import { plainToInstance } from 'class-transformer' import { validate } from 'class-validator' +import { VerifyInputDataDto } from '../../base/baseLicenseUpdateClient.types' /** Category to attach each log message to */ const LOG_CATEGORY = 'driving-license-service' diff --git a/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClientV2.service.ts b/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClientV2.service.ts index 1ffcef956665..14532958c2ce 100644 --- a/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClientV2.service.ts +++ b/libs/clients/license-client/src/lib/clients/firearm-license-client/services/firearmLicenseUpdateClientV2.service.ts @@ -16,9 +16,9 @@ import type { ConfigType } from '@island.is/nest/config' import { FirearmDigitalLicenseClientConfig } from '../firearmLicenseClient.config' import { BaseLicenseUpdateClientV2 } from '../../base/licenseUpdateClientV2' import { PkPassService } from '../../../helpers/pkPassService/pkPass.service' -import { VerifyInputDataDto } from '../../disability-license-client/disabilityLicense.types' import { plainToInstance } from 'class-transformer' import { validate } from 'class-validator' +import { VerifyInputDataDto } from '../../base/baseLicenseUpdateClient.types' /** Category to attach each log message to */ const LOG_CATEGORY = 'firearmlicense-service' From 735ecfcbf3d190782a4c6dd630c32ec97e70b4b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Wed, 9 Oct 2024 11:53:44 +0000 Subject: [PATCH 28/29] fix: linting --- .../src/app/modules/license/test/license.service.spec.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/services/license-api/src/app/modules/license/test/license.service.spec.ts b/apps/services/license-api/src/app/modules/license/test/license.service.spec.ts index 361b6805b299..951070968484 100644 --- a/apps/services/license-api/src/app/modules/license/test/license.service.spec.ts +++ b/apps/services/license-api/src/app/modules/license/test/license.service.spec.ts @@ -23,7 +23,6 @@ import { BarcodeService, LICENSE_SERVICE_CACHE_MANAGER_PROVIDER, LicenseConfig, - TOKEN_EXPIRED_ERROR, } from '@island.is/services/license' import { BadRequestException, @@ -49,7 +48,7 @@ import { import { SmartSolutionsService } from '@island.is/clients/smart-solutions-v2' import { LicenseServiceV1 } from '../licenseV1.service' import { LicenseServiceV2 } from '../licenseV2.service' -import { PassVerificationData } from 'libs/clients/license-client/src/lib/licenseClient.type' +import { PassVerificationData } from '@island.is/clients/license-client/src/lib/licenseClient.type' const { randomUUID } = new ShortUniqueId({ length: 16 }) const cacheStore = new Map() From 8d570472351e7519c4523472257ad3f4c6a19853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Eorkell=20M=C3=A1ni=20=C3=9Eorkelsson?= Date: Wed, 9 Oct 2024 11:55:28 +0000 Subject: [PATCH 29/29] fix: type --- .../smart-solutions-v2/src/lib/smartSolutions.service.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libs/clients/smart-solutions-v2/src/lib/smartSolutions.service.ts b/libs/clients/smart-solutions-v2/src/lib/smartSolutions.service.ts index c3dbe0e28479..5abbb0ef812b 100644 --- a/libs/clients/smart-solutions-v2/src/lib/smartSolutions.service.ts +++ b/libs/clients/smart-solutions-v2/src/lib/smartSolutions.service.ts @@ -26,7 +26,10 @@ import { VerifyPassResponseData, } from './types/responses.type' import { GQLFetcher } from './gqlFetch' -import { LOG_CATEGORY, SmartSolutionsModuleOptions } from './types/config.type' +import { + LOG_CATEGORY, + type SmartSolutionsModuleOptions, +} from './types/config.type' import { Result } from './types/result.type' export class SmartSolutionsService {