Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request permission on big paste #1643

Merged
merged 1 commit into from
Oct 26, 2024
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
1 change: 1 addition & 0 deletions metainfo.xml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
<li>Expose current profile's name through env var `CONTOUR_PROFILE` (#1637)</li>
<li>Add terminal tabs (#90)</li>
<li>Add `SaveScreenshot` and `CopyScreenshot` action (#210)</li>
<li>Protect user from accidentally pasting too large input (#1198)</li>
<li>Add binding to exit normal mode with `Esc` (#1604)</li>
<li>Add config option to switch into insert mode after yank (#1604)</li>
<li>Improves window size/resize handling on HiDPI monitor settings (#1628)</li>
Expand Down
52 changes: 48 additions & 4 deletions src/contour/TerminalSession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ void TerminalSession::executeRole(GuardedRole role, bool allow, bool remember)
case GuardedRole::ShowHostWritableStatusLine:
executeShowHostWritableStatusLine(allow, remember);
break;
case GuardedRole::BigPaste: applyPendingPaste(allow, remember); break;
}
}

Expand Down Expand Up @@ -401,6 +402,7 @@ void TerminalSession::requestPermission(config::Permission allowedByConfig, Guar
case GuardedRole::ChangeFont: emit requestPermissionForFontChange(); break;
case GuardedRole::CaptureBuffer: emit requestPermissionForBufferCapture(); break;
case GuardedRole::ShowHostWritableStatusLine: emit requestPermissionForShowHostWritableStatusLine(); break;
case GuardedRole::BigPaste: emit requestPermissionForPasteLargeFile(); break;
// clang-format on
}
}
Expand Down Expand Up @@ -651,23 +653,65 @@ void TerminalSession::pasteFromClipboard(unsigned count, bool strip)
sessionLog()("pasteFromClipboard: mime data contains {} formats.", md->formats().size());
for (int i = 0; i < md->formats().size(); ++i)
sessionLog()("pasteFromClipboard[{}]: {}\n", i, md->formats().at(i).toStdString());
string const text = strip_if(normalize_crlf(clipboard->text(QClipboard::Clipboard)), strip);
if (text.empty())

auto const text = clipboard->text(QClipboard::Clipboard);

// 1 MB hard limit
if (text.size() > 1024 * 1024)
Yaraslaut marked this conversation as resolved.
Show resolved Hide resolved
{
sessionLog()("Clipboard contains huge text. Ignoring.");
_display->post([this]() {
emit showNotification("Screenshot", QString::fromStdString("Paste is too big"));
});
return;
}
// 512 KB soft limit to ask user for permission
if (text.size() > 1024 * 512)
{
_pendingBigPaste = clipboard;
emit requestPermissionForPasteLargeFile();
sessionLog()("Clipboard contains huge text. Requesting permission.");
return;
}

string const strippedText = strip_if(normalize_crlf(clipboard->text(QClipboard::Clipboard)), strip);
sessionLog()("Size of text: {}", strippedText.size());
if (strippedText.empty())
sessionLog()("Clipboard does not contain text.");
else if (count == 1)
terminal().sendPaste(string_view { text });
terminal().sendPaste(string_view { strippedText });
else
{
string fullPaste;
for (unsigned i = 0; i < count; ++i)
fullPaste += text;
fullPaste += strippedText;
terminal().sendPaste(string_view { fullPaste });
}
}
else
sessionLog()("Could not access clipboard.");
}

void TerminalSession::applyPendingPaste(bool allow, bool remember)
{
sessionLog()("applyPendingPaste: allow={}, remember={}", allow, remember);
if (remember)
_rememberedPermissions[GuardedRole::BigPaste] = allow;

if (!_pendingBigPaste)
return;

if (!allow)
{
_pendingBigPaste = std::nullopt;
return;
}

auto* clipboard = _pendingBigPaste.value();
auto text = clipboard->text(QClipboard::Clipboard);
terminal().sendPaste(string_view { text.toStdString() });
}

void TerminalSession::onSelectionCompleted()
{
switch (_config.onMouseSelection.value())
Expand Down
5 changes: 5 additions & 0 deletions src/contour/TerminalSession.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ enum class GuardedRole : uint8_t
ChangeFont,
CaptureBuffer,
ShowHostWritableStatusLine,
BigPaste,
};

/**
Expand Down Expand Up @@ -240,6 +241,7 @@ class TerminalSession: public QAbstractItemModel, public vtbackend::Terminal::Ev
void detachDisplay(display::TerminalDisplay& display);

Q_INVOKABLE void applyPendingFontChange(bool allow, bool remember);
Q_INVOKABLE void applyPendingPaste(bool allow, bool remember);
Q_INVOKABLE void executePendingBufferCapture(bool allow, bool remember);
Q_INVOKABLE void executeShowHostWritableStatusLine(bool allow, bool remember);
Q_INVOKABLE void resizeTerminalToDisplaySize();
Expand Down Expand Up @@ -395,6 +397,7 @@ class TerminalSession: public QAbstractItemModel, public vtbackend::Terminal::Ev
void onBell(float volume);
void onAlert();
void requestPermissionForFontChange();
void requestPermissionForPasteLargeFile();
void requestPermissionForBufferCapture();
void requestPermissionForShowHostWritableStatusLine();
void showNotification(QString const& title, QString const& content);
Expand Down Expand Up @@ -470,6 +473,7 @@ class TerminalSession: public QAbstractItemModel, public vtbackend::Terminal::Ev
};
std::optional<CaptureBufferRequest> _pendingBufferCapture;
std::optional<vtbackend::FontDef> _pendingFontChange;
std::optional<QClipboard*> _pendingBigPaste;
PermissionCache _rememberedPermissions;
std::unique_ptr<QThread> _exitWatcherThread;

Expand All @@ -494,6 +498,7 @@ struct std::formatter<contour::GuardedRole>: std::formatter<std::string_view>
case contour::GuardedRole::ChangeFont: output = "Change Font"; break;
case contour::GuardedRole::CaptureBuffer: output = "Capture Buffer"; break;
case contour::GuardedRole::ShowHostWritableStatusLine: output = "show Host Writable Statusline"; break;
case contour::GuardedRole::BigPaste: output = "paste large number of characters"; break;
}
// clang-format on
return formatter<string_view>::format(output, ctx);
Expand Down
18 changes: 18 additions & 0 deletions src/contour/ui.template/Terminal.qml.in
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,23 @@ ContourTerminal
}
}


RequestPermission {
id: requestLargeFilePaste
text: "The host application is going to paste large file, are you sure?"
onYesToAllClicked: vtWidget.session.applyPendingPaste(true, true);
onYesClicked: vtWidget.session.applyPendingPaste(true, false);
onNoToAllClicked: vtWidget.session.applyPendingPaste(false, true);
onNoClicked: vtWidget.session.applyPendingPaste(false, false);
onRejected: {
console.log("[Terminal] large file paste is rejected.", vtWidget.session)
if (vtWidget.session !== null)
vtWidget.session.applyPendingPaste(false, false);
}
}



RequestPermission {
id: requestBufferCaptureDialog
text: "The host application is requesting to capture the terminal buffer."
Expand Down Expand Up @@ -265,6 +282,7 @@ ContourTerminal
vt.requestPermissionForFontChange.connect(requestFontChangeDialog.open);
vt.requestPermissionForBufferCapture.connect(requestBufferCaptureDialog.open);
vt.requestPermissionForShowHostWritableStatusLine.connect(requestShowHostWritableStatusLine.open);
vt.requestPermissionForPasteLargeFile.connect(requestLargeFilePaste.open);
forceActiveFocus();

// TAB handling
Expand Down
Loading