feat(#448): support encrypting submission payload#766
feat(#448): support encrypting submission payload#766garethbowen wants to merge 16 commits intomainfrom
Conversation
🦋 Changeset detectedLatest commit: 0b4a7c1 The changes in this PR will be included in the next version bump. This PR includes changesets to release 5 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
| // ); | ||
| // el3.textContent = this.signature; | ||
| // manifest.appendChild(el3); | ||
| // } |
There was a problem hiding this comment.
This part is still waiting on a decision. I suspect it's going to get removed completely because it's a) optional, and b) not implemented in central.
|
@latin-panda This is ready for review. I'm still waiting on a couple of answers and it'll need a fair amount of QA testing, but as I'm AFK for the next week I thought I'd send it over for review in the meantime. Thanks! |
latin-panda
left a comment
There was a problem hiding this comment.
Really interesting! I left some comments below
|
|
||
| ## Implementation | ||
|
|
||
| The symmetric encryption parts of the spec are implemnted using CryptoJS because the particularly algorithm required by the spec is not supported by Subtle Crypto, and we use CryptoJS elsewhere. |
There was a problem hiding this comment.
| The symmetric encryption parts of the spec are implemnted using CryptoJS because the particularly algorithm required by the spec is not supported by Subtle Crypto, and we use CryptoJS elsewhere. | |
| The symmetric encryption parts of the spec are implemented using CryptoJS because the particular algorithm required by the spec is not supported by Subtle Crypto, and we use CryptoJS elsewhere. |
| symmetricKey: Uint8Array<ArrayBuffer>, | ||
| seed: Seed | ||
| ): Promise<File> => { | ||
| const content = await getBlobData(attachment); |
There was a problem hiding this comment.
I'm curious about the amount of memory WF is allocating to submissions overall, including attachments and raw data, since it loads the submission into memory again. It'd be good to check how large forms perform on low-end devices, as part of the test plan.
| const bytes = []; | ||
| for (let i = 0; i < buffer.length; i += 4) { | ||
| bytes.push( | ||
| (buffer[i]! << 24) | (buffer[i + 1]! << 16) | (buffer[i + 2]! << 8) | buffer[i + 3]! |
There was a problem hiding this comment.
This increases by 4, and it will go out of bounds. However, the bitwise operation treats undefined as 0. It would be better to still check that buffer[i], buffer[i + 1], etc., are defined to make it more robust.
| readonly instanceId: string, | ||
| readonly symmetricKey: Uint8Array<ArrayBuffer> | ||
| ) { | ||
| const key = CryptoJS.lib.WordArray.create(symmetricKey); |
There was a problem hiding this comment.
Does it make sense to use this function here too?
| const key = CryptoJS.lib.WordArray.create(symmetricKey); | |
| const key = arrayBufferToWordArray(symmetricKey); |
| const el = document.createElementNS(ODK_SUBMISSIONS_NAMESPACE_URI, 'base64EncryptedKey'); | ||
| el.textContent = this.base64EncryptedKey; | ||
| manifest.appendChild(el); | ||
|
|
||
| const el2 = document.createElementNS(ODK_SUBMISSIONS_NAMESPACE_URI, 'encryptedXmlFile'); | ||
| el2.textContent = ENCRYPTED_SUBMISSION_ATTACHMENT_NAME; | ||
| manifest.appendChild(el2); |
There was a problem hiding this comment.
| const el = document.createElementNS(ODK_SUBMISSIONS_NAMESPACE_URI, 'base64EncryptedKey'); | |
| el.textContent = this.base64EncryptedKey; | |
| manifest.appendChild(el); | |
| const el2 = document.createElementNS(ODK_SUBMISSIONS_NAMESPACE_URI, 'encryptedXmlFile'); | |
| el2.textContent = ENCRYPTED_SUBMISSION_ATTACHMENT_NAME; | |
| manifest.appendChild(el2); | |
| const keyEl = document.createElementNS(ODK_SUBMISSIONS_NAMESPACE_URI, 'base64EncryptedKey'); | |
| el.textContent = this.base64EncryptedKey; | |
| manifest.appendChild(el); | |
| const xmlFileEl = document.createElementNS(ODK_SUBMISSIONS_NAMESPACE_URI, 'encryptedXmlFile'); | |
| el2.textContent = ENCRYPTED_SUBMISSION_ATTACHMENT_NAME; | |
| manifest.appendChild(el2); |
| import { | ||
| ODK_SUBMISSIONS_NAMESPACE_URI, | ||
| OPENROSA_XFORMS_NAMESPACE_URI, | ||
| } from '@getodk/common/constants/xmlns.ts'; |
There was a problem hiding this comment.
How about moving this to /instance-state? It seems like this file is handling a lot of DOM element work, and currently parse/model isn't importing from client-reactivity. What do you think?
|
|
||
| class Seed { | ||
| readonly ivSeedArray; | ||
| counter = 0; |
There was a problem hiding this comment.
I think it can be private
| counter = 0; | |
| private counter = 0; |
Closes #448
I have verified this PR works in these browsers (latest versions):
What else has been done to verify that this works as intended?
Minimal testing. I'd really like to add an e2e test one day that actually verifies that the submission can be decrypted, but that requires actually starting up backend. If we end up in the same repo as frontend then there already is a framework to do this so postponing it until we figure out where we're going to go!
Why is this the best possible solution? Were any other approaches considered?
How does this change affect users? Describe intentional changes to behavior and behavior that could have accidentally been affected by code changes. In other words, what are the regression risks?
Do we need any specific form for testing your changes? If so, please attach one.
No specific form but it only works in central (not demo) and only if you set up encryption as laid out in the test plan.
What's changed