Skip to content

prevent pasting large input on secure compose#4914

Merged
rrrooommmaaa merged 12 commits intomasterfrom
issue-4818-check-input-on-paste-for-contenteditable
Feb 20, 2023
Merged

prevent pasting large input on secure compose#4914
rrrooommmaaa merged 12 commits intomasterfrom
issue-4818-check-input-on-paste-for-contenteditable

Conversation

@martgil
Copy link
Collaborator

@martgil martgil commented Jan 30, 2023

This PR adds a check when pasting a text input with a length greater than the limit and forbids pasting if it the condition is true.

close #4818

For manual test, please use: 55k.txt - paste it on intro and input body.


Tests (delete all except exactly one):
Difficult to test (#4914 (comment))


To be filled by reviewers

I have reviewed that this PR... (tick whichever items you personally focused on during this review):

  • addresses the issue it closes (if any)
  • code is readable and understandable
  • is accompanied with tests, or tests are not needed
  • is free of vulnerabilities
  • is documented clearly and usefully, or doesn't need documentation

@martgil martgil requested a review from rrrooommmaaa as a code owner January 30, 2023 06:19
@martgil
Copy link
Collaborator Author

martgil commented Jan 30, 2023

sir @rrrooommmaaa here is the change that works. currently, it doesn't have a test. I'd like to hear your suggestion regarding adding a test. is it necessary for us to inform the user about preventing the paste action via modal? If not, can I simply invoke the paste event in the input body and input intro then checks if both inputs received the data from the paste event?

const div = document.createElement('div');
div.appendChild(e.fragment);
const html = div.innerHTML;
this.checkInputLengthBeforePasting(div.innerText, this.view.S.cached('input_text').get(0), e);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of copying this.view.S.cached('input_text').get(0) it'd be more clean to extract the element from the squire object itself. SquireEditor actually has a method getRoot() for this. It was missing in our squire.d.ts type definitions, so I added it. You can now use this.squire.getRoot()

Another remark: is there a good reason to use div.innerText for the check because what actually used is sanitized div.innerHTML. Can it be that we inserting a big load of tags with little text? Can we perform the check on the sanitized value instead?

Also, when you preventDefault, I guess, further manipulations on e.fragment serve no purpose? If so, they should be skipped. It'd be more convenient to have the check method to return a boolean value and then we can either ev.preventDefault() or do the rest steps. The method may be called willInputLimitBeExceeded

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for all the remarks. I apply some changes according to your helpful insight.

public checkInputLengthBeforePasting = (textToPaste: string, targetInputField: HTMLElement, ev: ClipboardEvent) => {
const currentLength = targetInputField.innerText.length;
const limit = 50000;
if (textToPaste.length + currentLength > limit) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to gracefully handle the situation when the paste (partially) replaces the existing content? This will happen if there is an active selection at the moment of pasting.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure, sir, since we only want to test the input limit. But if the process in this pr affects the performance significantly I think we could consider that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want to check the resulting element size, e.g. replacing a 40k text with another 40k text should trigger no error, right?
82782ac -- is it looking good?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the changes from 82782ac look good to me. I see that I missed that scenario for subtracting content. thank you.

@rrrooommmaaa
Copy link
Contributor

sir @rrrooommmaaa here is the change that works. currently, it doesn't have a test. I'd like to hear your suggestion regarding adding a test.

As I understand, clipboard-related tests are not easy to develop. I guess @tomholub will suggest to skip the test for this issue.

is it necessary for us to inform the user about preventing the paste action via modal?

That's a question for @tomholub

@tomholub
Copy link
Collaborator

I think we should indeed do a modal, and as Roman says, ok to skip test if difficult to do.

if (this.willInputLimitBeExceeded(sanitized.trim(), this.squire.getRoot())) {
e.preventDefault();
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Xss.setElementContentDANGEROUSLY(div, sanitized); // xss-sanitized
can also be moved after if {...}, right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right - you are correct. So that Xss.set... will execute only when needed.

const html = div.innerHTML;
const sanitized = this.isRichText() ? Xss.htmlSanitizeKeepBasicTags(html, 'IMG-KEEP') : Xss.htmlSanitizeAndStripAllTags(html, '<br>', false);
Xss.setElementContentDANGEROUSLY(div, sanitized); // xss-sanitized
if (this.willInputLimitBeExceeded(sanitized.trim(), this.squire.getRoot())) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need trim()? Why? sanitized is HTML. Did you notice any extra space appear during testing?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the secure compose has an extra space.

(before)
Screenshot 2023-02-16 at 5 43 23 PM

(after)
image

@martgil
Copy link
Collaborator Author

martgil commented Feb 16, 2023

@rrrooommmaaa ready for review. thank you!

@rrrooommmaaa
Copy link
Contributor

I think we should indeed do a modal, and as Roman says, ok to skip test if difficult to do.

@martgil Please add a modal saying something like The paste operation can't be completed because the resulting text size would exceed the allowed limit of 50K.

@martgil
Copy link
Collaborator Author

martgil commented Feb 18, 2023

@rrrooommmaaa I just added the modal. I'm thinking to put the reusable warning message in ComposeInputModule but I think it was inappropriate and decided to use the same warning message in two separate places. Is it okay?

@martgil martgil marked this pull request as draft February 18, 2023 08:45
@martgil martgil marked this pull request as ready for review February 18, 2023 09:09
@martgil martgil requested a review from rrrooommmaaa February 18, 2023 09:14
@rrrooommmaaa rrrooommmaaa merged commit 09b17a8 into master Feb 20, 2023
@rrrooommmaaa rrrooommmaaa deleted the issue-4818-check-input-on-paste-for-contenteditable branch February 20, 2023 07:59
FlowCryptRobot pushed a commit that referenced this pull request Feb 22, 2023
…#4943)

* build(deps-dev): bump @openpgp/web-stream-tools from 0.0.11 to 0.0.13

Bumps [@openpgp/web-stream-tools](https://github.com/openpgpjs/web-stream-tools) from 0.0.11 to 0.0.13.
- [Release notes](https://github.com/openpgpjs/web-stream-tools/releases)
- [Commits](openpgpjs/web-stream-tools@v0.0.11...v0.0.13)

---
updated-dependencies:
- dependency-name: "@openpgp/web-stream-tools"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* #4282 fix: duplicated contact search result (#4944)

* fix: dupliated contact search result

* feat: added ui test

* fix: pr review

* #4940 Update build script to not produce .bak files (#4945)

* update build script

* rename STREAMS_OUTDIR to STREAMS_FILES

* #4844 feat: renew id token when expires (#4949)

* feat: renew id token when expires

* fix: pr reviews

* Employ user verification mechanisms from OpenPGP v5 (#4946)

* reuse getPrimeryUser method

* verifying key users

* allow localhost domain for email address

* fix

* fix and test

* use verified users in key-import-ui

* PR review fixes

---------

Co-authored-by: Roman Shevchenko <roman@flowcrypt.com>

* prevent pasting large input on secure compose (#4914)

* prevent pasting large input on secure compose

* Added type definition for SquireEditor.getRoot()

* apply requested change

* update

* cleanup

* update

* consider selection

* add warning modal

* update

* update

* update

---------

Co-authored-by: Roman Shevchenko <rrrooommmaaa@mail.ru>
Co-authored-by: Roman Shevchenko <roman@flowcrypt.com>

* fix

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ioan Moldovan <mobilestar108@outlook.com>
Co-authored-by: Roma Sosnovsky <roma.sosnovsky@gmail.com>
Co-authored-by: Roman <rrrooommmaaa@mail.ru>
Co-authored-by: Roman Shevchenko <roman@flowcrypt.com>
Co-authored-by: Mart G <46025304+martgil@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Limit size of message text when pasting to the secure compose message box

3 participants