diff --git a/README.md b/README.md index f9c206d..ec08500 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,9 @@ const POST_URI = 'https://my-domain.com/submissions' // Your form's secret key downloaded from FormSG upon form creation const formSecretKey = process.env.FORM_SECRET_KEY +// Set to true if you need to download and decrypt attachments from submissions +const HAS_ATTACHMENTS = false + app.post( '/submissions', // Endpoint authentication by verifying signatures @@ -62,13 +65,12 @@ app.post( // Parse JSON from raw request body express.json(), // Decrypt the submission - function (req, res, next) { - const submission = formsg.crypto.decrypt( - formSecretKey, - // If `verifiedContent` is provided in `req.body.data`, the return object - // will include a verified key. - req.body.data - ) + async function (req, res, next) { + // If `verifiedContent` is provided in `req.body.data`, the return object + // will include a verified key. + const submission = HAS_ATTACHMENTS + ? await formsg.crypto.decryptWithAttachments(formSecretKey, req.body.data) + : formsg.crypto.decrypt(formSecretKey, req.body.data) // If the decryption failed, submission will be `null`. if (submission) { @@ -79,42 +81,6 @@ app.post( } ) -// Example for submissions with attachments -app.post( - '/submissions-attachment', - // Endpoint authentication by verifying signatures - function (req, res, next) { - try { - formsg.webhooks.authenticate(req.get('X-FormSG-Signature'), POST_URI) - // Continue processing the POST body - return next() - } catch (e) { - return res.status(401).send({ message: 'Unauthorized' }) - } - }, - // Parse JSON from raw request body - express.json(), - // Decrypt the submission and attachments - async function (req, res, next) { - const submission = formsg.crypto.decryptWithAttachments( - formSecretKey, - // If `verifiedContent` is provided in `req.body.data`, the return object - // will include a verified key. - req.body.data - ) - - // If the decryption failed at any point, submission will be `null`. - if (submission) { - // Continue processing the submission - - // processSubmission(submission.content) - // processAttachments(submission.attachments) - } else { - // Could not decrypt the submission - } - } -) - app.listen(8080, () => console.log('Running on port 8080')) ``` @@ -126,12 +92,12 @@ The underlying cryptosystem is `x25519-xsalsa20-poly1305` which is implemented b ### Format of Submission Response -| Key | Type | Description | -| ---------------- | ------ | ----------------------------------- | -| formId | string | Unique form identifier. | -| submissionId | string | Unique response identifier, displayed as 'Response ID' to form respondents | -| encryptedContent | string | The encrypted submission in base64. | -| created | string | Creation timestamp. | +| Key | Type | Description | +| ---------------------- | ---------------------- | -------------------------------------------------------------------------------------------------------- | +| formId | string | Unique form identifier. | +| submissionId | string | Unique response identifier, displayed as 'Response ID' to form respondents | +| encryptedContent | string | The encrypted submission in base64. | +| created | string | Creation timestamp. | | attachmentDownloadUrls | Record | (Optional) Records containing field IDs and URLs where encrypted uploaded attachments can be downloaded. | ### Format of Decrypted Submissions @@ -190,19 +156,20 @@ If the decrypted content is the correct shape, then: ### Processing Attachments -`formsg.crypto.decryptWithAttachments(formSecretKey: string, decryptParams: DecryptParams)` behaves similarly except it will return a `Promise`. +`formsg.crypto.decryptWithAttachments(formSecretKey: string, decryptParams: DecryptParams)` (available from version 0.9.0 onwards) behaves similarly except it will return a `Promise`. + +`DecryptedContentAndAttachments` is an object containing two fields: -`DecryptedContentAndAttachments` is an object containing two fields: - - `content`: the standard form decrypted responses (same as the return type of `formsg.crypto.decrypt`) - - `attachments`: A `Record` containing a map of field ids of the attachment fields to a object containing the original user supplied filename and a `Uint8Array` containing the contents of the uploaded file. +- `content`: the standard form decrypted responses (same as the return type of `formsg.crypto.decrypt`) +- `attachments`: A `Record` containing a map of field ids of the attachment fields to a object containing the original user supplied filename and a `Uint8Array` containing the contents of the uploaded file. If the contents of any file fails to decrypt or there is a mismatch between the attachments and submission (e.g. the submission doesn't contain the original file name), then `null` will be returned. -Attachments are downloaded using S3 pre-signed URLs, with a expiry time of *one hour*. You must call `decryptWithAttachments` within this time window, or else the URL to the encrypted files will become invalid. +Attachments are downloaded using S3 pre-signed URLs, with a expiry time of _one hour_. You must call `decryptWithAttachments` within this time window, or else the URL to the encrypted files will become invalid. Attachments are end-to-end encrypted in the same way as normal form submissions, so any eavesdropper will not be able to view form attachments without your secret key. -*Warning:* We do not have the ability to scan any attachments for malicious content (e.g. spyware or viruses), so careful handling is neeeded. +_Warning:_ We do not have the ability to scan any attachments for malicious content (e.g. spyware or viruses), so careful handling is needed. ## Verifying Signatures Manually