Improve and secure attachment handling (fixes #2400).

Externally opened attachments are now lifecycle-managed properly.

The temporary files are created with stricter permissions and entirely
random names (except for the file extension) to prevent meta data leakage.

When the database is closed, the files are overwritten with random
data and are also more reliably deleted than before.

Changes to the temporary files are monitored and the user is asked
if they want to save the changes back to the database (fixes #3130).

KeePassXC does not keep a lock on any of the temporary files, resolving
long-standing issues with applications such as Adobe Acrobat on Windows
(fixes #5950, fixes #5839).

Internally, attachments are copied less. The EntryAttachmentsWidget
now only references EntryAttachments instead of owning a separate copy
(which used to not be cleared properly under certain circumstances).
This commit is contained in:
Janek Bevendorff 2021-06-08 19:54:36 +02:00 committed by Jonathan White
parent af9eb6d6b1
commit 93f0fef1e1
11 changed files with 245 additions and 93 deletions

View file

@ -66,6 +66,7 @@ EditEntryWidget::EditEntryWidget(QWidget* parent)
, m_sshAgentUi(new Ui::EditEntryWidgetSSHAgent())
, m_historyUi(new Ui::EditEntryWidgetHistory())
, m_browserUi(new Ui::EditEntryWidgetBrowser())
, m_attachments(new EntryAttachments())
, m_customData(new CustomData())
, m_mainWidget(new QScrollArea())
, m_advancedWidget(new QWidget())
@ -537,7 +538,7 @@ void EditEntryWidget::setupSSHAgent()
connect(m_sshAgentUi->decryptButton, &QPushButton::clicked, this, &EditEntryWidget::decryptPrivateKey);
connect(m_sshAgentUi->copyToClipboardButton, &QPushButton::clicked, this, &EditEntryWidget::copyPublicKey);
connect(m_advancedUi->attachmentsWidget->entryAttachments(), &EntryAttachments::modified,
connect(m_attachments.data(), &EntryAttachments::modified,
this, &EditEntryWidget::updateSSHAgentAttachments);
// clang-format on
@ -576,7 +577,7 @@ void EditEntryWidget::updateSSHAgentAttachments()
{
// detect if KeeAgent.settings was removed by hand and reset settings
if (m_entry && KeeAgentSettings::inEntryAttachments(m_entry->attachments())
&& !KeeAgentSettings::inEntryAttachments(m_advancedUi->attachmentsWidget->entryAttachments())) {
&& !KeeAgentSettings::inEntryAttachments(m_attachments.data())) {
m_sshAgentSettings.reset();
setSSHAgentSettings();
}
@ -584,8 +585,7 @@ void EditEntryWidget::updateSSHAgentAttachments()
m_sshAgentUi->attachmentComboBox->clear();
m_sshAgentUi->attachmentComboBox->addItem("");
auto attachments = m_advancedUi->attachmentsWidget->entryAttachments();
for (const QString& fileName : attachments->keys()) {
for (const QString& fileName : m_attachments->keys()) {
if (fileName == "KeeAgent.settings") {
continue;
}
@ -698,7 +698,7 @@ bool EditEntryWidget::getOpenSSHKey(OpenSSHKey& key, bool decrypt)
if (!settings.toOpenSSHKey(m_mainUi->usernameComboBox->lineEdit()->text(),
m_mainUi->passwordEdit->text(),
m_db->filePath(),
m_advancedUi->attachmentsWidget->entryAttachments(),
m_attachments.data(),
key,
decrypt)) {
showMessage(settings.errorString(), MessageWidget::Error);
@ -828,6 +828,7 @@ void EditEntryWidget::loadEntry(Entry* entry,
void EditEntryWidget::setForms(Entry* entry, bool restore)
{
m_attachments->copyDataFrom(entry->attachments());
m_customData->copyDataFrom(entry->customData());
m_mainUi->titleEdit->setReadOnly(m_history);
@ -888,7 +889,7 @@ void EditEntryWidget::setForms(Entry* entry, bool restore)
m_mainUi->notesEdit->setPlainText(entry->notes());
m_advancedUi->attachmentsWidget->setEntryAttachments(entry->attachments());
m_advancedUi->attachmentsWidget->linkAttachments(m_attachments.data());
m_entryAttributes->copyCustomKeysFrom(entry->attributes());
if (m_attributesModel->rowCount() != 0) {
@ -1090,7 +1091,6 @@ bool EditEntryWidget::commitEntry()
}
m_historyModel->setEntries(m_entry->historyItems());
m_advancedUi->attachmentsWidget->setEntryAttachments(m_entry->attachments());
showMessage(tr("Entry updated successfully."), MessageWidget::Positive);
setModified(false);
@ -1110,7 +1110,7 @@ void EditEntryWidget::updateEntryData(Entry* entry) const
QRegularExpression newLineRegex("(?:\r?\n|\r)");
entry->attributes()->copyCustomKeysFrom(m_entryAttributes);
entry->attachments()->copyDataFrom(m_advancedUi->attachmentsWidget->entryAttachments());
entry->attachments()->copyDataFrom(m_attachments.data());
entry->customData()->copyDataFrom(m_customData.data());
entry->setTitle(m_mainUi->titleEdit->text().replace(newLineRegex, " "));
entry->setUsername(m_mainUi->usernameComboBox->lineEdit()->text().replace(newLineRegex, " "));
@ -1212,7 +1212,8 @@ void EditEntryWidget::clear()
m_mainUi->notesEdit->clear();
m_entryAttributes->clear();
m_advancedUi->attachmentsWidget->clearAttachments();
m_attachments->clear();
m_customData->clear();
m_autoTypeAssoc->clear();
m_historyModel->clear();
m_iconsWidget->reset();