diff --git a/src/config.ts b/src/config.ts index 21b73eb3f..28144e241 100644 --- a/src/config.ts +++ b/src/config.ts @@ -103,7 +103,8 @@ const defaultConfig: IoDevServerConfig = { canceledCount: 0, noSignatureFieldsCount: 0, response: { - getFciResponseCode: 200 + getFciResponseCode: 200, + documentExpirationDurationSeconds: 5 * 60 // make it 30 to allow testing expired documents without waiting too much } }, withCTA: false, diff --git a/src/features/messages/types/messagesConfig.ts b/src/features/messages/types/messagesConfig.ts index 9c8116eb6..cf951228a 100644 --- a/src/features/messages/types/messagesConfig.ts +++ b/src/features/messages/types/messagesConfig.ts @@ -36,7 +36,8 @@ export const MessagesConfig = t.intersection([ noSignatureFieldsCount: t.number, response: t.type({ // 200 success with payload - getFciResponseCode: HttpResponseCode + getFciResponseCode: HttpResponseCode, + documentExpirationDurationSeconds: t.number }) }), // if true, messages (all available) with nested CTA will be included diff --git a/src/routers/features/fci/index.ts b/src/routers/features/fci/index.ts index 1caff7ee2..4d91aa2f8 100644 --- a/src/routers/features/fci/index.ts +++ b/src/routers/features/fci/index.ts @@ -12,7 +12,7 @@ import { NO_FIELDS_SIGNATURE_REQUEST_ID, REJECTED_SIGNATURE_REQUEST_ID, SIGNATURE_REQUEST_ID, - signatureRequestDetailViewDoc, + signatureRequestDetailViewDoc as originalSignatureRequestDetailViewDoc, SIGNED_EXPIRED_SIGNATURE_REQUEST_ID, SIGNED_SIGNATURE_REQUEST_ID, WAIT_QTSP_SIGNATURE_REQUEST_ID @@ -38,6 +38,20 @@ addHandler( (req, res) => { const signatureRequestId = "signatureRequestId"; const now = new Date(); + const signatureRequestDetailViewDoc = { + ...originalSignatureRequestDetailViewDoc, + documents: originalSignatureRequestDetailViewDoc.documents.map(d => ({ + ...d, + url: + d.url + + `?expiration=${ + now.getTime() + + ioDevServerConfig.messages.fci.response + .documentExpirationDurationSeconds * + 1000 + }` + })) + }; const environment = EnvironmentEnum.test; res.header("x-io-sign-environment", environment); pipe( @@ -163,6 +177,33 @@ addHandler( "get", `${staticContentRootPath}/fci/:filename`, (req, res) => { + if (typeof req.query.expiration === "string") { + const now = Date.now(); + const expirationTimestamp = parseInt(req.query.expiration, 10); + if (isNaN(expirationTimestamp) || now > expirationTimestamp) { + const start = new Date( + expirationTimestamp - + ioDevServerConfig.messages.fci.response + .documentExpirationDurationSeconds * + 1000 + ).toJSON(); + const expiry = new Date(expirationTimestamp).toJSON(); + const current = new Date(now).toJSON(); + // this case reproduces the expiration mechanic when getting files from + // https://iopsignst.blob.core.windows.net/validated-documents/XXXXXXXXXXXXXXXXXXXXXXXXXX?sv=2023-08-03&spr=https%2Chttp&st=2026-03-16T15%3A28%3A20Z&se=2026-03-16T15%3A33%3A20Z&sr=b&sp=r&sig=kwZji8ZTRAQCf%2F2GDQPjOet8bxUTYIiJkZkFVUIjSOQ%3D&rsct=application%2Fpdf + res.status(403); + res.set("Content-Type", "application/xml"); + res.send(` + + AuthenticationFailed + Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. +RequestId:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +Time:${new Date(now).toJSON()} + Signature not valid in the specified time frame: Start [${start}] - Expiry [${expiry}] - Current [${current}] +`); + return; + } + } sendFileFromRootPath(`assets/fci/pdf/${req.params.filename}.pdf`, res); } );