diff --git a/package.json b/package.json index ccffc681..a983cde3 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,6 @@ "@typescript-eslint/eslint-plugin": "^5.40.1", "@valora/eslint-config-typescript": "^0.0.1", "@valora/prettier-config": "^0.0.1", - "ajv": "^8.11.0", "dotenv": "^16.0.3", "eslint": "^8.25.0", "eslint-plugin-import": "^2.26.0", diff --git a/src/routes/accounts.ts b/src/routes/accounts.ts index 22095ca9..08562b0b 100644 --- a/src/routes/accounts.ts +++ b/src/routes/accounts.ts @@ -1,13 +1,16 @@ import express from 'express' import { asyncRoute } from './async-route' -import { validateSchema, validateZodSchema } from '../schema/' +import { validateZodSchema } from '../schema/' import { DeleteFiatAccountRequestParams, NotImplementedError, PostFiatAccountRequestBody, } from '../types' import { siweAuthMiddleware } from '../middleware/authenticate' -import { postFiatAccountRequestBodySchema } from '@fiatconnect/fiatconnect-types' +import { + deleteFiatAccountRequestParamsSchema, + postFiatAccountRequestBodySchema, +} from '@fiatconnect/fiatconnect-types' export function accountsRouter({ clientAuthMiddleware, @@ -33,9 +36,9 @@ export function accountsRouter({ _res: express.Response, next: express.NextFunction, ) => { - req.params = validateSchema( + req.params = validateZodSchema( req.params, - 'DeleteFiatAccountRequestParamsSchema', + deleteFiatAccountRequestParamsSchema, ) next() } diff --git a/src/routes/auth.ts b/src/routes/auth.ts index ae23e692..557af43b 100644 --- a/src/routes/auth.ts +++ b/src/routes/auth.ts @@ -1,6 +1,6 @@ import express from 'express' import { ErrorTypes, SiweMessage } from 'siwe' -import { validateSchema } from '../schema' +import { validateZodSchema } from '../schema' import { AuthRequestBody, FiatConnectError, @@ -8,6 +8,7 @@ import { NotImplementedError, } from '../types' import { asyncRoute } from './async-route' +import { authRequestBodySchema } from '@fiatconnect/fiatconnect-types' const MAX_EXPIRATION_TIME_MS = 4 * 60 * 60 * 1000 // 4 hours const VERSION = '1' @@ -73,10 +74,7 @@ export function authRouter({ chainId }: { chainId: number }): express.Router { _res: express.Response, next: express.NextFunction, ) => { - req.body = validateSchema( - req.body, - 'AuthRequestBodySchema', - ) + req.body = validateZodSchema(req.body, authRequestBodySchema) next() } diff --git a/src/routes/kyc.ts b/src/routes/kyc.ts index 751cc2dc..ea37b501 100644 --- a/src/routes/kyc.ts +++ b/src/routes/kyc.ts @@ -1,6 +1,6 @@ import express from 'express' import { asyncRoute } from './async-route' -import { validateSchema } from '../schema/' +import { validateZodSchema } from '../schema/' import { KycRequestParams, KycSchemas, @@ -8,6 +8,17 @@ import { SupportedKycSchemas, } from '../types' import { siweAuthMiddleware } from '../middleware/authenticate' +import { + kycRequestParamsSchema, + KycSchema, + personalDataAndDocumentsKycSchema, +} from '@fiatconnect/fiatconnect-types' +import { AnyZodObject } from 'zod' + +const kycSchemaToZodSchema: { [kycSchema in KycSchema]: AnyZodObject } = { + // if a KYC schema is missing, that should be evident at compile-time, as long as fiatconnect-types is up to date + [KycSchema.PersonalDataAndDocuments]: personalDataAndDocumentsKycSchema, +} export function kycRouter({ clientAuthMiddleware, @@ -24,10 +35,7 @@ export function kycRouter({ _res: express.Response, next: express.NextFunction, ) => { - req.params = validateSchema( - req.params, - 'KycRequestParamsSchema', - ) + req.params = validateZodSchema(req.params, kycRequestParamsSchema) next() } @@ -44,10 +52,7 @@ export function kycRouter({ _res: express.Response, ) => { // Delegate to type-specific handlers after validation provides type guards - validateSchema( - req.body, - `${req.params.kycSchema}KycSchema`, - ) + validateZodSchema(req.body, kycSchemaToZodSchema[req.params.kycSchema]) throw new NotImplementedError('POST /kyc/:kycSchema not implemented') }, diff --git a/src/routes/quote.ts b/src/routes/quote.ts index 1e782bbb..e110a7bc 100644 --- a/src/routes/quote.ts +++ b/src/routes/quote.ts @@ -1,7 +1,8 @@ import express from 'express' import { asyncRoute } from './async-route' -import { validateSchema } from '../schema/' +import { validateZodSchema } from '../schema/' import { QuoteRequestBody, NotImplementedError } from '../types' +import { quoteRequestBodySchema } from '@fiatconnect/fiatconnect-types' export function quoteRouter({ clientAuthMiddleware, @@ -18,10 +19,7 @@ export function quoteRouter({ _res: express.Response, next: express.NextFunction, ) => { - req.body = validateSchema( - req.body, - 'QuoteRequestBodySchema', - ) + req.body = validateZodSchema(req.body, quoteRequestBodySchema) next() }, ) diff --git a/src/routes/transfer.ts b/src/routes/transfer.ts index efae602f..a51767ad 100644 --- a/src/routes/transfer.ts +++ b/src/routes/transfer.ts @@ -1,12 +1,16 @@ import express from 'express' import { asyncRoute } from './async-route' -import { validateSchema } from '../schema/' +import { validateZodSchema } from '../schema/' import { TransferRequestBody, TransferStatusRequestParams, NotImplementedError, } from '../types' import { siweAuthMiddleware } from '../middleware/authenticate' +import { + transferRequestBodySchema, + transferStatusRequestParamsSchema, +} from '@fiatconnect/fiatconnect-types' export function transferRouter({ clientAuthMiddleware, @@ -23,10 +27,7 @@ export function transferRouter({ _res: express.Response, next: express.NextFunction, ) => { - req.body = validateSchema( - req.body, - 'TransferRequestBodySchema', - ) + req.body = validateZodSchema(req.body, transferRequestBodySchema) next() } @@ -35,9 +36,9 @@ export function transferRouter({ _res: express.Response, next: express.NextFunction, ) => { - req.params = validateSchema( + req.params = validateZodSchema( req.params, - 'TransferStatusRequestParamsSchema', + transferStatusRequestParamsSchema, ) next() } diff --git a/src/schema/account-number.ts b/src/schema/account-number.ts deleted file mode 100644 index 596af0cf..00000000 --- a/src/schema/account-number.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { JSONSchemaType } from 'ajv' -import { - FiatAccountSchema, - FiatAccountSchemas, - FiatAccountType, -} from '../types' - -export const accountNumberSchema: JSONSchemaType< - FiatAccountSchemas[FiatAccountSchema.AccountNumber] -> = { - $id: 'AccountNumberSchema', - type: 'object', - properties: { - institutionName: { - type: 'string', - }, - accountName: { - type: 'string', - }, - fiatAccountType: { - type: 'string', - enum: [FiatAccountType.BankAccount], - }, - accountNumber: { - type: 'string', - }, - country: { - type: 'string', - }, - }, - required: [ - 'institutionName', - 'accountName', - 'accountNumber', - 'country', - 'fiatAccountType', - ], -} diff --git a/src/schema/auth-request-body.ts b/src/schema/auth-request-body.ts deleted file mode 100644 index 3d1c370a..00000000 --- a/src/schema/auth-request-body.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { JSONSchemaType } from 'ajv' -import { AuthRequestBody } from '../types' - -export const authRequestBodySchema: JSONSchemaType = { - $id: 'AuthRequestBodySchema', - type: 'object', - properties: { - message: { - type: 'string', - }, - signature: { - type: 'string', - }, - }, - required: ['message', 'signature'], -} diff --git a/src/schema/delete-fiat-account-request-params.ts b/src/schema/delete-fiat-account-request-params.ts deleted file mode 100644 index d0a50538..00000000 --- a/src/schema/delete-fiat-account-request-params.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { JSONSchemaType } from 'ajv' -import { DeleteFiatAccountRequestParams } from '../types' - -export const deleteFiatAccountRequestParamsSchema: JSONSchemaType = - { - $id: 'DeleteFiatAccountRequestParamsSchema', - type: 'object', - properties: { - fiatAccountId: { - type: 'string', - }, - }, - required: ['fiatAccountId'], - } diff --git a/src/schema/dunia-wallet.ts b/src/schema/dunia-wallet.ts deleted file mode 100644 index 2dcb3185..00000000 --- a/src/schema/dunia-wallet.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { JSONSchemaType } from 'ajv' -import { - FiatAccountSchema, - FiatAccountSchemas, - FiatAccountType, -} from '../types' - -export const duniaWalletSchema: JSONSchemaType< - FiatAccountSchemas[FiatAccountSchema.DuniaWallet] -> = { - $id: 'DuniaWalletSchema', - type: 'object', - properties: { - institutionName: { - type: 'string', - }, - accountName: { - type: 'string', - }, - fiatAccountType: { - type: 'string', - enum: [FiatAccountType.DuniaWallet], - }, - mobile: { - type: 'string', - }, - }, - required: ['institutionName', 'accountName', 'mobile', 'fiatAccountType'], -} diff --git a/src/schema/index.ts b/src/schema/index.ts index 5eedea49..ec1c62f8 100644 --- a/src/schema/index.ts +++ b/src/schema/index.ts @@ -1,45 +1,8 @@ -import Ajv from 'ajv' import { ValidationError } from '../types' -import { quoteRequestBodySchema } from './quote-request-body' -import { kycRequestParamsSchema } from './kyc-request-params' -import { personalDataAndDocumentsKycSchema } from './personal-data-and-documents-kyc' -import { deleteFiatAccountRequestParamsSchema } from './delete-fiat-account-request-params' -import { transferRequestBodySchema } from './transfer-request-body' -import { transferStatusRequestParamsSchema } from './transfer-status-request-params' -import { authRequestBodySchema } from './auth-request-body' import { z, ZodError } from 'zod' import { ZodType } from 'zod/lib/types' -const ajv = new Ajv({ - schemas: [ - quoteRequestBodySchema, - kycRequestParamsSchema, - personalDataAndDocumentsKycSchema, - deleteFiatAccountRequestParamsSchema, - transferRequestBodySchema, - transferStatusRequestParamsSchema, - authRequestBodySchema, - ], -}) - -/** - * Validate AJV schema - * - * @deprecated - prefer validateZodSchema (more re-usable with fiatconnect-types) - * - * @param data - * @param schema - */ -export function validateSchema(data: any, schema: string): T { - if (ajv.validate(schema, data)) return data - - throw new ValidationError( - `Error while validating schema: invalid ${schema}`, - ajv.errors, - ) -} - /** * Validate zod schema * diff --git a/src/schema/kyc-request-params.ts b/src/schema/kyc-request-params.ts deleted file mode 100644 index 0a9b1b37..00000000 --- a/src/schema/kyc-request-params.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { JSONSchemaType } from 'ajv' -import { KycSchema, KycRequestParams } from '../types' - -export const kycRequestParamsSchema: JSONSchemaType = { - $id: 'KycRequestParamsSchema', - type: 'object', - properties: { - kycSchema: { - type: 'string', - enum: Object.values(KycSchema), - }, - }, - required: ['kycSchema'], -} diff --git a/src/schema/mobile-money.ts b/src/schema/mobile-money.ts deleted file mode 100644 index 0d7498c2..00000000 --- a/src/schema/mobile-money.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { JSONSchemaType } from 'ajv' -import { - FiatAccountSchema, - FiatAccountSchemas, - FiatAccountType, - SupportedOperatorEnum, -} from '../types' - -export const mobileMoneySchema: JSONSchemaType< - FiatAccountSchemas[FiatAccountSchema.MobileMoney] -> = { - $id: 'MobileMoneySchema', - type: 'object', - properties: { - institutionName: { - type: 'string', - }, - accountName: { - type: 'string', - }, - fiatAccountType: { - type: 'string', - enum: [FiatAccountType.MobileMoney], - }, - mobile: { - type: 'string', - }, - operator: { - type: 'string', - enum: [ - SupportedOperatorEnum.MTN, - SupportedOperatorEnum.ORANGE, - SupportedOperatorEnum.MOOV, - SupportedOperatorEnum.WAVE, - ], - }, - country: { - type: 'string', - }, - }, - required: [ - 'institutionName', - 'accountName', - 'mobile', - 'operator', - 'country', - 'fiatAccountType', - ], -} diff --git a/src/schema/personal-data-and-documents-kyc.ts b/src/schema/personal-data-and-documents-kyc.ts deleted file mode 100644 index 69cad7de..00000000 --- a/src/schema/personal-data-and-documents-kyc.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { JSONSchemaType } from 'ajv' -import { KycSchema, KycSchemas } from '../types' - -export const personalDataAndDocumentsKycSchema: JSONSchemaType< - KycSchemas[KycSchema.PersonalDataAndDocuments] -> = { - $id: 'PersonalDataAndDocumentsKycSchema', - type: 'object', - properties: { - firstName: { - type: 'string', - }, - middleName: { - type: 'string', - nullable: true, - }, - lastName: { - type: 'string', - }, - dateOfBirth: { - type: 'object', - properties: { - day: { - type: 'string', - }, - month: { - type: 'string', - }, - year: { - type: 'string', - }, - }, - required: ['day', 'month', 'year'], - }, - address: { - type: 'object', - properties: { - address1: { - type: 'string', - }, - address2: { - type: 'string', - nullable: true, - }, - isoCountryCode: { - type: 'string', - }, - isoRegionCode: { - type: 'string', - }, - city: { - type: 'string', - }, - postalCode: { - type: 'string', - nullable: true, - }, - }, - required: ['address1', 'isoCountryCode', 'isoRegionCode', 'city'], - }, - phoneNumber: { - type: 'string', - }, - selfieDocument: { - type: 'string', - }, - identificationDocument: { - type: 'string', - }, - }, - required: [ - 'firstName', - 'lastName', - 'dateOfBirth', - 'address', - 'phoneNumber', - 'selfieDocument', - 'identificationDocument', - ], -} diff --git a/src/schema/quote-request-body.ts b/src/schema/quote-request-body.ts deleted file mode 100644 index c5748754..00000000 --- a/src/schema/quote-request-body.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { JSONSchemaType } from 'ajv' -import { QuoteRequestBody, FiatType, CryptoType } from '../types' - -export const quoteRequestBodySchema: JSONSchemaType = { - $id: 'QuoteRequestBodySchema', - type: 'object', - properties: { - fiatType: { - type: 'string', - enum: Object.values(FiatType), - }, - cryptoType: { - type: 'string', - enum: Object.values(CryptoType), - }, - fiatAmount: { - type: 'string', - nullable: true, - }, - cryptoAmount: { - type: 'string', - nullable: true, - }, - country: { - type: 'string', - }, - region: { - type: 'string', - nullable: true, - }, - preview: { - type: 'boolean', - nullable: true, - }, - address: { - type: 'string', - }, - }, - oneOf: [ - { - required: ['fiatAmount'], - }, - { - required: ['cryptoAmount'], - }, - ], - required: ['fiatType', 'cryptoType', 'country'], -} diff --git a/src/schema/transfer-request-body.ts b/src/schema/transfer-request-body.ts deleted file mode 100644 index 71806920..00000000 --- a/src/schema/transfer-request-body.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { JSONSchemaType } from 'ajv' -import { TransferRequestBody } from '../types' - -export const transferRequestBodySchema: JSONSchemaType = { - $id: 'TransferRequestBodySchema', - type: 'object', - properties: { - fiatAccountId: { - type: 'string', - }, - quoteId: { - type: 'string', - }, - }, - required: ['fiatAccountId', 'quoteId'], -} diff --git a/src/schema/transfer-status-request-params.ts b/src/schema/transfer-status-request-params.ts deleted file mode 100644 index 89dc0138..00000000 --- a/src/schema/transfer-status-request-params.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { JSONSchemaType } from 'ajv' -import { TransferStatusRequestParams } from '../types' - -export const transferStatusRequestParamsSchema: JSONSchemaType = - { - $id: 'TransferStatusRequestParamsSchema', - type: 'object', - properties: { - transferId: { - type: 'string', - }, - }, - required: ['transferId'], - }