From 5685120412ffd7f854071d1202d339b8536aeb7d Mon Sep 17 00:00:00 2001 From: Antariksh Date: Sat, 7 Nov 2020 17:39:40 +0800 Subject: [PATCH 1/7] ref: move updateHashes hashing into model --- src/app/controllers/myinfo.server.controller.js | 7 +------ src/app/models/myinfo_hash.server.model.ts | 8 +++++++- src/types/myinfo_hash.ts | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/app/controllers/myinfo.server.controller.js b/src/app/controllers/myinfo.server.controller.js index 43c899e06a..ca29a90406 100644 --- a/src/app/controllers/myinfo.server.controller.js +++ b/src/app/controllers/myinfo.server.controller.js @@ -76,15 +76,10 @@ exports.addMyInfo = (myInfoService) => async (req, res, next) => { // Set current form fields to the new prefilledFields. req.form.form_fields = prefilledFields - const hashedUinFin = crypto - .createHmac('sha256', sessionSecret) - .update(uinFin) - .digest('hex') - Promise.props(readOnlyHashPromises) .then((readOnlyHashes) => { return MyInfoHash.updateHashes( - hashedUinFin, + uinFin, formId, readOnlyHashes, myInfoService.spCookieMaxAge, diff --git a/src/app/models/myinfo_hash.server.model.ts b/src/app/models/myinfo_hash.server.model.ts index 8ab2f54b6f..b0a608060c 100644 --- a/src/app/models/myinfo_hash.server.model.ts +++ b/src/app/models/myinfo_hash.server.model.ts @@ -1,5 +1,7 @@ +import crypto from 'crypto' import { Mongoose, Schema } from 'mongoose' +import { sessionSecret } from '../../config/config' import { IHashes, IMyInfoHashModel, IMyInfoHashSchema } from '../../types' import { FORM_SCHEMA_ID } from './form.server.model' @@ -45,11 +47,15 @@ MyInfoHashSchema.index({ expireAt: 1 }, { expireAfterSeconds: 0 }) MyInfoHashSchema.statics.updateHashes = async function ( this: IMyInfoHashModel, - hashedUinFin: string, + uinFin: string, formId: string, readOnlyHashes: IHashes, spCookieMaxAge: number, ): Promise { + const hashedUinFin = crypto + .createHmac('sha256', sessionSecret) + .update(uinFin) + .digest('hex') return this.findOneAndUpdate( { uinFin: hashedUinFin, diff --git a/src/types/myinfo_hash.ts b/src/types/myinfo_hash.ts index 32e51f23f8..b77ee989e5 100644 --- a/src/types/myinfo_hash.ts +++ b/src/types/myinfo_hash.ts @@ -22,7 +22,7 @@ export interface IMyInfoHashSchema extends IMyInfoHash, Document {} export interface IMyInfoHashModel extends Model { updateHashes: ( - hashedUinFin: string, + uinFin: string, formId: string, readOnlyHashes: IHashes, spCookieMaxAge: number, From 20234d3648128d79117d4eabdb1838d89763b6dd Mon Sep 17 00:00:00 2001 From: Antariksh Date: Sat, 7 Nov 2020 18:14:01 +0800 Subject: [PATCH 2/7] test: update updateHashes tests --- .../models/myinfo_hash.server.model.spec.ts | 61 +++++++++++++------ 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/tests/unit/backend/models/myinfo_hash.server.model.spec.ts b/tests/unit/backend/models/myinfo_hash.server.model.spec.ts index 784189d476..cf81a565a3 100644 --- a/tests/unit/backend/models/myinfo_hash.server.model.spec.ts +++ b/tests/unit/backend/models/myinfo_hash.server.model.spec.ts @@ -1,31 +1,51 @@ import { ObjectId } from 'bson' +import crypto from 'crypto' import { omit, pick } from 'lodash' import mongoose from 'mongoose' +import { mocked } from 'ts-jest/utils' -import getMyInfoHashModel from 'src/app/models/myinfo_hash.server.model' +import config from 'src/config/config' import dbHandler from '../helpers/jest-db' +jest.mock('src/config/config') +const MockConfig = mocked(config, true) + +// eslint-disable-next-line import/first +import getMyInfoHashModel from 'src/app/models/myinfo_hash.server.model' + const MyInfoHash = getMyInfoHashModel(mongoose) -const DEFAULT_PARAMS = { +const MOCK_SESSION_SECRET = 'mockSecret' +const DEFAULT_INPUT_PARAMS = { uinFin: 'testUinFin', form: new ObjectId(), fields: { name: 'mockHash' }, expireAt: new Date(Date.now()), created: new Date(Date.now()), } +const DEFAULT_HASHED_UINFIN = crypto + .createHmac('sha256', MOCK_SESSION_SECRET) + .update(DEFAULT_INPUT_PARAMS.uinFin) + .digest('hex') +const DEFAULT_SAVED_PARAMS = { + ...DEFAULT_INPUT_PARAMS, + uinFin: DEFAULT_HASHED_UINFIN, +} const DEFAULT_COOKIE_MAX_AGE = 5 describe('MyInfo Hash Model', () => { - beforeAll(async () => await dbHandler.connect()) + beforeAll(async () => { + await dbHandler.connect() + MockConfig.sessionSecret = MOCK_SESSION_SECRET + }) beforeEach(async () => await dbHandler.clearDatabase()) afterAll(async () => await dbHandler.closeDatabase()) describe('Schema', () => { it('should create and save successfully', async () => { // Act - const actual = await MyInfoHash.create(DEFAULT_PARAMS) + const actual = await MyInfoHash.create(DEFAULT_INPUT_PARAMS) // Assert // All fields should exist @@ -33,12 +53,12 @@ describe('MyInfo Hash Model', () => { expect(actual._id).toBeDefined() expect( pick(actual, ['uinFin', 'form', 'fields', 'created', 'expireAt']), - ).toEqual(DEFAULT_PARAMS) + ).toEqual(DEFAULT_INPUT_PARAMS) }) it('should throw validation error on missing uinFin', async () => { // Arrange - const missingParams = omit(DEFAULT_PARAMS, 'uinFin') + const missingParams = omit(DEFAULT_INPUT_PARAMS, 'uinFin') // Act const myInfoHash = new MyInfoHash(missingParams) @@ -52,7 +72,7 @@ describe('MyInfo Hash Model', () => { it('should throw validation error on missing form', async () => { // Arrange - const missingParams = omit(DEFAULT_PARAMS, 'form') + const missingParams = omit(DEFAULT_INPUT_PARAMS, 'form') // Act const myInfoHash = new MyInfoHash(missingParams) @@ -66,7 +86,7 @@ describe('MyInfo Hash Model', () => { it('should throw validation error on missing fields', async () => { // Arrange - const missingParams = omit(DEFAULT_PARAMS, 'fields') + const missingParams = omit(DEFAULT_INPUT_PARAMS, 'fields') // Act const myInfoHash = new MyInfoHash(missingParams) @@ -80,7 +100,7 @@ describe('MyInfo Hash Model', () => { it('should throw validation error on missing expireAt', async () => { // Arrange - const missingParams = omit(DEFAULT_PARAMS, 'expireAt') + const missingParams = omit(DEFAULT_INPUT_PARAMS, 'expireAt') // Act const myInfoHash = new MyInfoHash(missingParams) @@ -100,10 +120,11 @@ describe('MyInfo Hash Model', () => { await expect(MyInfoHash.countDocuments()).resolves.toEqual(0) // Act + // Note: we are passing the PLAIN uinFin const actual = await MyInfoHash.updateHashes( - DEFAULT_PARAMS.uinFin, - DEFAULT_PARAMS.form.toHexString(), - DEFAULT_PARAMS.fields, + DEFAULT_INPUT_PARAMS.uinFin, + DEFAULT_INPUT_PARAMS.form.toHexString(), + DEFAULT_INPUT_PARAMS.fields, DEFAULT_COOKIE_MAX_AGE, ) @@ -112,27 +133,30 @@ describe('MyInfo Hash Model', () => { await expect(MyInfoHash.countDocuments()).resolves.toEqual(1) const found = await MyInfoHash.findOne({}) // Both the returned document and the found document should match + // Note: we are checking that the document contains the HASHED uinFin expect(pick(actual, ['uinFin', 'form', 'fields'])).toEqual( - pick(DEFAULT_PARAMS, ['uinFin', 'form', 'fields']), + pick(DEFAULT_SAVED_PARAMS, ['uinFin', 'form', 'fields']), ) expect(pick(found, ['uinFin', 'form', 'fields'])).toEqual( - pick(DEFAULT_PARAMS, ['uinFin', 'form', 'fields']), + pick(DEFAULT_SAVED_PARAMS, ['uinFin', 'form', 'fields']), ) }) it('should update successfully when a document already exists', async () => { // Arrange // Insert mock document into collection. - await MyInfoHash.create(DEFAULT_PARAMS) + // Note: we are inserting the HASHED uinFin directly. + await MyInfoHash.create(DEFAULT_SAVED_PARAMS) // Should have the added document. await expect(MyInfoHash.countDocuments()).resolves.toEqual(1) const mockFields = { sex: 'F' } // Act + // Note: we are passing the PLAIN uinFin and checking that it gets hashed const actual = await MyInfoHash.updateHashes( - DEFAULT_PARAMS.uinFin, - DEFAULT_PARAMS.form.toHexString(), + DEFAULT_INPUT_PARAMS.uinFin, + DEFAULT_INPUT_PARAMS.form.toHexString(), mockFields, DEFAULT_COOKIE_MAX_AGE, ) @@ -142,6 +166,9 @@ describe('MyInfo Hash Model', () => { // Both the returned document and the found document should match expect(actual!.fields).toEqual(mockFields) expect(found!.fields).toEqual(mockFields) + + expect(actual!.uinFin).toBe(DEFAULT_HASHED_UINFIN) + expect(found!.uinFin).toEqual(DEFAULT_HASHED_UINFIN) }) }) }) From 54bbf55cf648a2d515557ecfbdd8b27445143b97 Mon Sep 17 00:00:00 2001 From: Antariksh Date: Sat, 7 Nov 2020 18:23:35 +0800 Subject: [PATCH 3/7] ref: add findHashes method --- src/app/models/myinfo_hash.server.model.ts | 15 +++++++++++++++ src/types/myinfo_hash.ts | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/src/app/models/myinfo_hash.server.model.ts b/src/app/models/myinfo_hash.server.model.ts index b0a608060c..a9b9b51e6f 100644 --- a/src/app/models/myinfo_hash.server.model.ts +++ b/src/app/models/myinfo_hash.server.model.ts @@ -71,6 +71,21 @@ MyInfoHashSchema.statics.updateHashes = async function ( ) } +MyInfoHashSchema.statics.findHashes = async function ( + this: IMyInfoHashModel, + uinFin: string, + formId: string, +): Promise { + const hashedUinFin = crypto + .createHmac('sha256', sessionSecret) + .update(uinFin) + .digest('hex') + return this.findOne({ + uinFin: hashedUinFin, + form: formId, + }) +} + const compileMyInfoHashModel = (db: Mongoose) => db.model( MYINFO_HASH_SCHEMA_ID, diff --git a/src/types/myinfo_hash.ts b/src/types/myinfo_hash.ts index b77ee989e5..2920d10baa 100644 --- a/src/types/myinfo_hash.ts +++ b/src/types/myinfo_hash.ts @@ -27,4 +27,8 @@ export interface IMyInfoHashModel extends Model { readOnlyHashes: IHashes, spCookieMaxAge: number, ) => Promise + findHashes: ( + uinFin: string, + formId: string, + ) => Promise } From f75609666dc8c4a63aba2fad10e63db4fd36b10c Mon Sep 17 00:00:00 2001 From: Antariksh Date: Sat, 7 Nov 2020 18:29:19 +0800 Subject: [PATCH 4/7] ref: use findHashes function --- .../controllers/myinfo.server.controller.js | 158 ++++++++---------- 1 file changed, 71 insertions(+), 87 deletions(-) diff --git a/src/app/controllers/myinfo.server.controller.js b/src/app/controllers/myinfo.server.controller.js index ca29a90406..a39b43d9db 100644 --- a/src/app/controllers/myinfo.server.controller.js +++ b/src/app/controllers/myinfo.server.controller.js @@ -1,7 +1,6 @@ 'use strict' const bcrypt = require('bcrypt') -const crypto = require('crypto') const CircuitBreaker = require('opossum') const to = require('await-to-js').default const Promise = require('bluebird') @@ -10,7 +9,6 @@ const mongoose = require('mongoose') const moment = require('moment') const { StatusCodes } = require('http-status-codes') -const { sessionSecret } = require('../../config/config') const { createReqMeta } = require('../utils/request') const logger = require('../../config/logger').createLoggerWithLabel(module) const getMyInfoHashModel = require('../models/myinfo_hash.server.model').default @@ -137,7 +135,7 @@ function _preHashCheckConversion(field) { * @param {Object} res.locals.uinFin - UIN/FIN of form submitter * @param {Object} next - Express next middleware function */ -exports.verifyMyInfoVals = function (req, res, next) { +exports.verifyMyInfoVals = async function (req, res, next) { const { authType } = req.form const actualMyInfoFields = req.form.form_fields.filter( (field) => field.myInfo && field.myInfo.attr, @@ -145,101 +143,87 @@ exports.verifyMyInfoVals = function (req, res, next) { if (authType === 'SP' && actualMyInfoFields.length > 0) { const uinFin = res.locals.uinFin const formObjId = req.form._id - - let hashedUinFin = crypto - .createHmac('sha256', sessionSecret) - .update(uinFin) - .digest('hex') - MyInfoHash.findOne( - { uinFin: hashedUinFin, form: formObjId }, - (err, hashedObj) => { - if (err) { - logger.error({ - message: 'Error retrieving MyInfo hash from database', - meta: { - action: 'verifyMyInfoVals', - ...createReqMeta(req), - }, - error: err, - }) - return res.status(StatusCodes.SERVICE_UNAVAILABLE).json({ - message: 'MyInfo verification unavailable, please try again later.', - spcpSubmissionFailure: true, - }) + let hashedObj + try { + hashedObj = await MyInfoHash.findHashes(uinFin, formObjId) + } catch (error) { + logger.error({ + message: 'Error retrieving MyInfo hash from database', + meta: { + action: 'verifyMyInfoVals', + ...createReqMeta(req), + }, + error, + }) + return res.status(StatusCodes.SERVICE_UNAVAILABLE).json({ + message: 'MyInfo verification unavailable, please try again later.', + spcpSubmissionFailure: true, + }) + } + if (!hashedObj) { + logger.error({ + message: `Unable to find MyInfo hashes for ${formObjId}`, + meta: { + action: 'verifyMyInfoVals', + ...createReqMeta(req), + formId: formObjId, + }, + }) + return res.status(StatusCodes.GONE).json({ + message: 'MyInfo verification expired, please refresh and try again.', + spcpSubmissionFailure: true, + }) + } + // Fields from client submission + let clientFormFields = req.body.parsedResponses // responses were transformed in submissions.server.controller.js + let clientMyInfoFields = clientFormFields + .filter((field) => field.isVisible && field.myInfo && field.myInfo.attr) + .map(_preHashCheckConversion) + + // Fields from saved hash + let hashedFields = hashedObj.fields + // compare hashed values to submission values + const bcryptCompares = clientMyInfoFields.map((clientField) => { + const expected = hashedFields[clientField.attr] + return expected + ? bcrypt.compare(clientField.val, expected) + : Promise.resolve(true) + }) + Promise.all(bcryptCompares) + .then((compare) => { + return { + compare, // Array indicating hash pass/fail + fail: compare.some((v) => !v), // Whether any hashes failed } + }) + .then((hashResults) => { + if (hashResults.fail) { + // Array of MyInfo attributes that failed verification + let hashFailedAttrs = _.zip(clientMyInfoFields, hashResults.compare) + .filter(([_, compare]) => compare === false) + .map(([clientField, _]) => clientField.attr) - if (!hashedObj) { logger.error({ - message: `Unable to find MyInfo hashes for ${formObjId}`, + message: `Hash did not match for form ${formObjId}`, meta: { action: 'verifyMyInfoVals', ...createReqMeta(req), - formId: formObjId, + failedFields: hashFailedAttrs, }, }) - return res.status(StatusCodes.GONE).json({ - message: - 'MyInfo verification expired, please refresh and try again.', + return res.status(StatusCodes.UNAUTHORIZED).json({ + message: 'MyInfo verification failed.', spcpSubmissionFailure: true, }) - } - // Fields from client submission - let clientFormFields = req.body.parsedResponses // responses were transformed in submissions.server.controller.js - let clientMyInfoFields = clientFormFields - .filter( - (field) => field.isVisible && field.myInfo && field.myInfo.attr, + } else { + let verifiedKeys = _.intersection( + _.uniq(clientMyInfoFields.map((field) => field.attr)), + _.keys(hashedFields), ) - .map(_preHashCheckConversion) - - // Fields from saved hash - let hashedFields = hashedObj.fields - // compare hashed values to submission values - const bcryptCompares = clientMyInfoFields.map((clientField) => { - const expected = hashedFields[clientField.attr] - return expected - ? bcrypt.compare(clientField.val, expected) - : Promise.resolve(true) - }) - Promise.all(bcryptCompares) - .then((compare) => { - return { - compare, // Array indicating hash pass/fail - fail: compare.some((v) => !v), // Whether any hashes failed - } - }) - .then((hashResults) => { - if (hashResults.fail) { - // Array of MyInfo attributes that failed verification - let hashFailedAttrs = _.zip( - clientMyInfoFields, - hashResults.compare, - ) - .filter(([_, compare]) => compare === false) - .map(([clientField, _]) => clientField.attr) - - logger.error({ - message: `Hash did not match for form ${formObjId}`, - meta: { - action: 'verifyMyInfoVals', - ...createReqMeta(req), - failedFields: hashFailedAttrs, - }, - }) - return res.status(StatusCodes.UNAUTHORIZED).json({ - message: 'MyInfo verification failed.', - spcpSubmissionFailure: true, - }) - } else { - let verifiedKeys = _.intersection( - _.uniq(clientMyInfoFields.map((field) => field.attr)), - _.keys(hashedFields), - ) - req.hashedFields = _.pick(hashedFields, verifiedKeys) - return next() - } - }) - }, - ) + req.hashedFields = _.pick(hashedFields, verifiedKeys) + return next() + } + }) } else { return next() } From 11f2ccf7ffcc4bdb34ce5cd98c419502e04e42f2 Mon Sep 17 00:00:00 2001 From: Antariksh Date: Sat, 7 Nov 2020 18:29:31 +0800 Subject: [PATCH 5/7] test: add tests for findHashes --- .../models/myinfo_hash.server.model.spec.ts | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/unit/backend/models/myinfo_hash.server.model.spec.ts b/tests/unit/backend/models/myinfo_hash.server.model.spec.ts index cf81a565a3..3f00dff9da 100644 --- a/tests/unit/backend/models/myinfo_hash.server.model.spec.ts +++ b/tests/unit/backend/models/myinfo_hash.server.model.spec.ts @@ -171,5 +171,28 @@ describe('MyInfo Hash Model', () => { expect(found!.uinFin).toEqual(DEFAULT_HASHED_UINFIN) }) }) + + describe('findHashes', () => { + it('should find the correct document', async () => { + // Arrange + // Insert mock document into collection. + // Note: we are inserting the HASHED uinFin directly. + await MyInfoHash.create(DEFAULT_SAVED_PARAMS) + // Should have the added document. + await expect(MyInfoHash.countDocuments()).resolves.toEqual(1) + + // Act + // Note: we are passing the PLAIN uinFin and checking that it gets hashed + const actual = await MyInfoHash.findHashes( + DEFAULT_INPUT_PARAMS.uinFin, + DEFAULT_INPUT_PARAMS.form.toHexString(), + ) + // Assert + // Both the returned document and the found document should match + expect(pick(actual, ['uinFin', 'form', 'fields'])).toEqual( + pick(DEFAULT_SAVED_PARAMS, ['uinFin', 'form', 'fields']), + ) + }) + }) }) }) From be6512dca3ce898bff4c947d1cc52b2d6c975d39 Mon Sep 17 00:00:00 2001 From: Antariksh Date: Sat, 7 Nov 2020 18:50:46 +0800 Subject: [PATCH 6/7] test: update jasmine tests --- .../backend/controllers/myinfo.server.controller.spec.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/unit/backend/controllers/myinfo.server.controller.spec.js b/tests/unit/backend/controllers/myinfo.server.controller.spec.js index 2759682568..9335766ad1 100644 --- a/tests/unit/backend/controllers/myinfo.server.controller.spec.js +++ b/tests/unit/backend/controllers/myinfo.server.controller.spec.js @@ -495,7 +495,7 @@ const ALL_MYINFO_HASHES = { '$2b$10$eLakOm88NEuUawlGHsiPjeaImpYT5ZBH1JyZUseIRL9kCtDRIKdCe', } -const SESSION_SECRET = 'secret' +const SESSION_SECRET = process.env.SESSION_SECRET const User = dbHandler.makeModel('user.server.model', 'User') const Agency = dbHandler.makeModel('agency.server.model', 'Agency') @@ -506,9 +506,6 @@ const Controller = spec( 'dist/backend/app/controllers/myinfo.server.controller', { mongoose: Object.assign(mongoose, { '@noCallThru': true }), - '../../config/config': { - sessionSecret: SESSION_SECRET, - }, }, ) From acb01889c19147fa9c77f25b3e039fb6ff139ae3 Mon Sep 17 00:00:00 2001 From: Antariksh Date: Sun, 8 Nov 2020 22:08:35 +0800 Subject: [PATCH 7/7] ref: return only fields --- src/app/controllers/myinfo.server.controller.js | 8 +++----- src/app/models/myinfo_hash.server.model.ts | 5 +++-- src/types/myinfo_hash.ts | 5 +---- .../unit/backend/models/myinfo_hash.server.model.spec.ts | 4 +--- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/app/controllers/myinfo.server.controller.js b/src/app/controllers/myinfo.server.controller.js index a39b43d9db..1a818b192f 100644 --- a/src/app/controllers/myinfo.server.controller.js +++ b/src/app/controllers/myinfo.server.controller.js @@ -143,9 +143,9 @@ exports.verifyMyInfoVals = async function (req, res, next) { if (authType === 'SP' && actualMyInfoFields.length > 0) { const uinFin = res.locals.uinFin const formObjId = req.form._id - let hashedObj + let hashedFields try { - hashedObj = await MyInfoHash.findHashes(uinFin, formObjId) + hashedFields = await MyInfoHash.findHashes(uinFin, formObjId) } catch (error) { logger.error({ message: 'Error retrieving MyInfo hash from database', @@ -160,7 +160,7 @@ exports.verifyMyInfoVals = async function (req, res, next) { spcpSubmissionFailure: true, }) } - if (!hashedObj) { + if (!hashedFields) { logger.error({ message: `Unable to find MyInfo hashes for ${formObjId}`, meta: { @@ -180,8 +180,6 @@ exports.verifyMyInfoVals = async function (req, res, next) { .filter((field) => field.isVisible && field.myInfo && field.myInfo.attr) .map(_preHashCheckConversion) - // Fields from saved hash - let hashedFields = hashedObj.fields // compare hashed values to submission values const bcryptCompares = clientMyInfoFields.map((clientField) => { const expected = hashedFields[clientField.attr] diff --git a/src/app/models/myinfo_hash.server.model.ts b/src/app/models/myinfo_hash.server.model.ts index a9b9b51e6f..67376a3180 100644 --- a/src/app/models/myinfo_hash.server.model.ts +++ b/src/app/models/myinfo_hash.server.model.ts @@ -75,15 +75,16 @@ MyInfoHashSchema.statics.findHashes = async function ( this: IMyInfoHashModel, uinFin: string, formId: string, -): Promise { +): Promise { const hashedUinFin = crypto .createHmac('sha256', sessionSecret) .update(uinFin) .digest('hex') - return this.findOne({ + const hashInfo = await this.findOne({ uinFin: hashedUinFin, form: formId, }) + return hashInfo ? hashInfo.fields : null } const compileMyInfoHashModel = (db: Mongoose) => diff --git a/src/types/myinfo_hash.ts b/src/types/myinfo_hash.ts index 2920d10baa..81ce6391bf 100644 --- a/src/types/myinfo_hash.ts +++ b/src/types/myinfo_hash.ts @@ -27,8 +27,5 @@ export interface IMyInfoHashModel extends Model { readOnlyHashes: IHashes, spCookieMaxAge: number, ) => Promise - findHashes: ( - uinFin: string, - formId: string, - ) => Promise + findHashes: (uinFin: string, formId: string) => Promise } diff --git a/tests/unit/backend/models/myinfo_hash.server.model.spec.ts b/tests/unit/backend/models/myinfo_hash.server.model.spec.ts index 3f00dff9da..09fffbc2bf 100644 --- a/tests/unit/backend/models/myinfo_hash.server.model.spec.ts +++ b/tests/unit/backend/models/myinfo_hash.server.model.spec.ts @@ -189,9 +189,7 @@ describe('MyInfo Hash Model', () => { ) // Assert // Both the returned document and the found document should match - expect(pick(actual, ['uinFin', 'form', 'fields'])).toEqual( - pick(DEFAULT_SAVED_PARAMS, ['uinFin', 'form', 'fields']), - ) + expect(actual).toEqual(DEFAULT_SAVED_PARAMS.fields) }) }) })