Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import { ParsedRecipients } from '../../../js/common/api/email-provider/email-pr
import { Str } from '../../../js/common/core/common.js';
import { Xss } from '../../../js/common/platform/xss.js';
import { ViewModule } from '../../../js/common/view-module.js';
import { Ui } from '../../../js/common/browser/ui.js';
import { ComposeView } from '../compose.js';
import { Lang } from '../../../js/common/lang.js';

export class ComposeInputModule extends ViewModule<ComposeView> {
public squire = new window.Squire(this.view.S.cached('input_text').get(0));
Expand Down Expand Up @@ -78,12 +80,25 @@ export class ComposeInputModule extends ViewModule<ComposeView> {
return this.view.sendBtnModule.popover.choices.richtext;
};

public willInputLimitBeExceeded = (textToPaste: string, targetInputField: HTMLElement, selectionLengthGetter: () => number | undefined) => {
const limit = 50000;
const toBeRemoved = selectionLengthGetter() || 0;
const currentLength = targetInputField.innerText.trim().length;
const isInputLimitExceeded = currentLength - toBeRemoved + textToPaste.length > limit;
return isInputLimitExceeded;
};

private handlePaste = () => {
this.squire.addEventListener('willPaste', (e: WillPasteEvent) => {
this.squire.addEventListener('willPaste', async (e: WillPasteEvent) => {
const div = document.createElement('div');
div.appendChild(e.fragment);
const html = div.innerHTML;
const sanitized = this.isRichText() ? Xss.htmlSanitizeKeepBasicTags(html, 'IMG-KEEP') : Xss.htmlSanitizeAndStripAllTags(html, '<br>', false);
if (this.willInputLimitBeExceeded(sanitized, this.squire.getRoot(), () => this.squire.getSelectedText().length)) {
e.preventDefault();
await Ui.modal.warning(Lang.compose.inputLimitExceededOnPaste);
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.

Xss.setElementContentDANGEROUSLY(div, sanitized); // xss-sanitized
e.fragment.appendChild(div);
});
Expand Down
20 changes: 20 additions & 0 deletions extension/chrome/elements/compose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { PubLookup } from '../../js/common/api/pub-lookup.js';
import { AcctStore } from '../../js/common/platform/store/acct-store.js';
import { AccountServer } from '../../js/common/api/account-server.js';
import { ComposeReplyBtnPopoverModule } from './compose-modules/compose-reply-btn-popover-module.js';
import { Lang } from '../../js/common/lang.js';

export class ComposeView extends View {
public readonly acctEmail: string;
Expand Down Expand Up @@ -222,6 +223,25 @@ export class ComposeView extends View {
'click',
this.setHandler(async () => await this.renderModule.openSettingsWithDialog('help'), this.errModule.handle(`help dialog`))
);
this.S.cached('input_intro').on(
'paste',
this.setHandler(async (el, ev) => {
const clipboardEvent = ev.originalEvent as ClipboardEvent;
if (clipboardEvent.clipboardData) {
const isInputLimitExceeded = this.inputModule.willInputLimitBeExceeded(clipboardEvent.clipboardData.getData('text/plain'), el, () => {
const selection = window.getSelection();
if (selection && selection.anchorNode === selection.focusNode && selection.anchorNode?.parentElement === el) {
return Math.abs(selection.anchorOffset - selection.focusOffset);
}
return 0;
});
if (isInputLimitExceeded) {
ev.preventDefault();
await Ui.modal.warning(Lang.compose.inputLimitExceededOnPaste);
}
}
})
);
this.attachmentsModule.setHandlers();
this.inputModule.setHandlers();
this.myPubkeyModule.setHandlers();
Expand Down
1 change: 1 addition & 0 deletions extension/js/common/lang.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export const Lang = {
enterprisePasswordPolicy:
'Please use password with the following properties:\n - one uppercase\n - one lowercase\n - one number\n - one special character eg &"#-\'_%-@,;:!*()\n - 8 characters length',
consumerPasswordPolicy: 'Please use a password at least 8 characters long',
inputLimitExceededOnPaste: "The paste operation can't be completed because the resulting text size would exceed the allowed limit of 50K.",
},
general: {
contactMinimalSubsentence,
Expand Down
1 change: 1 addition & 0 deletions extension/types/squire.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export declare class SquireEditor {
removeAllFormatting(): void;
changeFormat(formattingToAdd: any, formattingToRemove: any, range: Range): void;
setConfig(config: any): SquireEditor;
getRoot(): HTMLElement;
}

export declare class WillPasteEvent extends ClipboardEvent {
Expand Down