Merge branch 'develop'

Conflicts:
	CMakeLists.txt
	cmake/CLangFormat.cmake
	snapcraft.yaml
	src/CMakeLists.txt
	src/core/Database.cpp
	src/core/Database.h
	src/core/Tools.cpp
	src/crypto/CryptoHash.h
	src/crypto/ssh/ASN1Key.h
	src/crypto/ssh/OpenSSHKey.cpp
	src/format/Kdbx4Reader.cpp
	src/gui/DatabaseTabWidget.cpp
	src/gui/DatabaseTabWidget.h
	src/gui/DatabaseWidget.cpp
	src/gui/DatabaseWidget.h
	src/gui/DetailsWidget.cpp
	src/gui/DetailsWidget.ui
	src/gui/EditWidgetProperties.cpp
	src/gui/EntryPreviewWidget.cpp
	src/gui/EntryPreviewWidget.ui
	src/gui/FileDialog.cpp
	src/gui/dbsettings/DatabaseSettingsDialog.cpp
	src/gui/dbsettings/DatabaseSettingsDialog.h
	src/gui/group/EditGroupWidget.cpp
	src/gui/group/EditGroupWidget.h
	src/sshagent/ASN1Key.h
	src/sshagent/OpenSSHKey.cpp
	src/sshagent/SSHAgent.cpp
	tests/CMakeLists.txt
This commit is contained in:
Jonathan White 2018-12-18 22:28:56 -05:00
commit 9e2be34897
No known key found for this signature in database
GPG key ID: 440FC65F2E0C6E01
421 changed files with 18208 additions and 12907 deletions

View file

@ -19,8 +19,8 @@
#ifndef AGENTSETTINGSPAGE_H
#define AGENTSETTINGSPAGE_H
#include "gui/DatabaseTabWidget.h"
#include "gui/ApplicationSettingsWidget.h"
#include "gui/DatabaseTabWidget.h"
class AgentSettingsPage : public ISettingsPage
{

View file

@ -17,9 +17,10 @@
*/
#include "AgentSettingsWidget.h"
#include "core/Config.h"
#include "ui_AgentSettingsWidget.h"
#include "core/Config.h"
AgentSettingsWidget::AgentSettingsWidget(QWidget* parent)
: QWidget(parent)
, m_ui(new Ui::AgentSettingsWidget())

View file

@ -34,6 +34,7 @@ KeeAgentSettings::KeeAgentSettings()
bool KeeAgentSettings::operator==(KeeAgentSettings& other)
{
// clang-format off
return (m_allowUseOfSshKey == other.m_allowUseOfSshKey && m_addAtDatabaseOpen == other.m_addAtDatabaseOpen
&& m_removeAtDatabaseClose == other.m_removeAtDatabaseClose
&& m_useConfirmConstraintWhenAdding == other.m_useConfirmConstraintWhenAdding
@ -43,6 +44,7 @@ bool KeeAgentSettings::operator==(KeeAgentSettings& other)
&& m_attachmentName == other.m_attachmentName
&& m_saveAttachmentToTempFile == other.m_saveAttachmentToTempFile
&& m_fileName == other.m_fileName);
// clang-format on
}
bool KeeAgentSettings::operator!=(KeeAgentSettings& other)

View file

@ -40,16 +40,17 @@ SSHAgent::SSHAgent(QObject* parent)
SSHAgent::~SSHAgent()
{
for (QSet<OpenSSHKey> keys : m_keys.values()) {
for (OpenSSHKey key : keys) {
removeIdentity(key);
}
auto it = m_addedKeys.begin();
while (it != m_addedKeys.end()) {
OpenSSHKey key = it.key();
removeIdentity(key);
it = m_addedKeys.erase(it);
}
}
SSHAgent* SSHAgent::instance()
{
if (m_instance == nullptr) {
if (!m_instance) {
qFatal("Race condition: instance wanted before it was initialized, this is a bug.");
}
@ -161,7 +162,16 @@ bool SSHAgent::sendMessage(const QByteArray& in, QByteArray& out)
#endif
}
bool SSHAgent::addIdentity(OpenSSHKey& key, quint32 lifetime, bool confirm)
/**
* Add the identity to the SSH agent.
*
* @param key identity / key to add
* @param lifetime time after which the key should expire
* @param confirm ask for confirmation before adding the key
* @param removeOnLock autoremove from agent when the Database is locked
* @return true on success
*/
bool SSHAgent::addIdentity(OpenSSHKey& key, bool removeOnLock, quint32 lifetime, bool confirm)
{
if (!isAgentRunning()) {
m_error = tr("No agent running, cannot add identity.");
@ -203,9 +213,18 @@ bool SSHAgent::addIdentity(OpenSSHKey& key, quint32 lifetime, bool confirm)
return false;
}
OpenSSHKey keyCopy = key;
keyCopy.clearPrivate();
m_addedKeys[keyCopy] = removeOnLock;
return true;
}
/**
* Remove an identity from the SSH agent.
*
* @param key identity to remove
* @return true on success
*/
bool SSHAgent::removeIdentity(OpenSSHKey& key)
{
if (!isAgentRunning()) {
@ -224,120 +243,121 @@ bool SSHAgent::removeIdentity(OpenSSHKey& key)
request.writeString(keyData);
QByteArray responseData;
if (!sendMessage(requestData, responseData)) {
return false;
}
if (responseData.length() < 1 || static_cast<quint8>(responseData[0]) != SSH_AGENT_SUCCESS) {
m_error = tr("Agent does not have this identity.");
return false;
}
return true;
return sendMessage(requestData, responseData);
}
void SSHAgent::removeIdentityAtLock(const OpenSSHKey& key, const QUuid& uuid)
/**
* Change "remove identity on lock" setting for a key already added to the agent.
* Will to nothing if the key has not been added to the agent.
*
* @param key key to change setting for
* @param autoRemove whether to remove the key from the agent when database is locked
*/
void SSHAgent::setAutoRemoveOnLock(const OpenSSHKey& key, bool autoRemove)
{
OpenSSHKey copy = key;
copy.clearPrivate();
m_keys[uuid].insert(copy);
if (m_addedKeys.contains(key)) {
m_addedKeys[key] = autoRemove;
}
}
void SSHAgent::databaseModeChanged(DatabaseWidget::Mode mode)
void SSHAgent::databaseModeChanged()
{
DatabaseWidget* widget = qobject_cast<DatabaseWidget*>(sender());
if (widget == nullptr) {
auto* widget = qobject_cast<DatabaseWidget*>(sender());
if (!widget) {
return;
}
const QUuid& uuid = widget->database()->uuid();
if (mode == DatabaseWidget::LockedMode && m_keys.contains(uuid)) {
QSet<OpenSSHKey> keys = m_keys.take(uuid);
for (OpenSSHKey key : keys) {
if (!removeIdentity(key)) {
emit error(m_error);
}
}
} else if (mode == DatabaseWidget::ViewMode && !m_keys.contains(uuid)) {
for (Entry* e : widget->database()->rootGroup()->entriesRecursive()) {
if (widget->database()->metadata()->recycleBinEnabled()
&& e->group() == widget->database()->metadata()->recycleBin()) {
continue;
}
if (!e->attachments()->hasKey("KeeAgent.settings")) {
continue;
}
KeeAgentSettings settings;
settings.fromXml(e->attachments()->value("KeeAgent.settings"));
if (!settings.allowUseOfSshKey()) {
continue;
}
QByteArray keyData;
QString fileName;
if (settings.selectedType() == "attachment") {
fileName = settings.attachmentName();
keyData = e->attachments()->value(fileName);
} else if (!settings.fileName().isEmpty()) {
QFile file(settings.fileName());
QFileInfo fileInfo(file);
fileName = fileInfo.fileName();
if (file.size() > 1024 * 1024) {
continue;
}
if (!file.open(QIODevice::ReadOnly)) {
continue;
}
keyData = file.readAll();
}
if (keyData.isEmpty()) {
continue;
}
OpenSSHKey key;
if (!key.parsePKCS1PEM(keyData)) {
continue;
}
if (!key.openKey(e->password())) {
continue;
}
if (key.comment().isEmpty()) {
key.setComment(e->username());
}
if (key.comment().isEmpty()) {
key.setComment(fileName);
}
if (settings.removeAtDatabaseClose()) {
removeIdentityAtLock(key, uuid);
}
if (settings.addAtDatabaseOpen()) {
int lifetime = 0;
if (settings.useLifetimeConstraintWhenAdding()) {
lifetime = settings.lifetimeConstraintDuration();
}
if (!addIdentity(key, lifetime, settings.useConfirmConstraintWhenAdding())) {
if (widget->isLocked()) {
auto it = m_addedKeys.begin();
while (it != m_addedKeys.end()) {
OpenSSHKey key = it.key();
if (it.value()) {
if (!removeIdentity(key)) {
emit error(m_error);
}
it = m_addedKeys.erase(it);
} else {
// don't remove it yet
m_addedKeys[key] = false;
++it;
}
}
return;
}
for (Entry* e : widget->database()->rootGroup()->entriesRecursive()) {
if (widget->database()->metadata()->recycleBinEnabled()
&& e->group() == widget->database()->metadata()->recycleBin()) {
continue;
}
if (!e->attachments()->hasKey("KeeAgent.settings")) {
continue;
}
KeeAgentSettings settings;
settings.fromXml(e->attachments()->value("KeeAgent.settings"));
if (!settings.allowUseOfSshKey()) {
continue;
}
QByteArray keyData;
QString fileName;
if (settings.selectedType() == "attachment") {
fileName = settings.attachmentName();
keyData = e->attachments()->value(fileName);
} else if (!settings.fileName().isEmpty()) {
QFile file(settings.fileName());
QFileInfo fileInfo(file);
fileName = fileInfo.fileName();
if (file.size() > 1024 * 1024) {
continue;
}
if (!file.open(QIODevice::ReadOnly)) {
continue;
}
keyData = file.readAll();
}
if (keyData.isEmpty()) {
continue;
}
OpenSSHKey key;
if (!key.parsePKCS1PEM(keyData)) {
continue;
}
if (!key.openKey(e->password())) {
continue;
}
if (key.comment().isEmpty()) {
key.setComment(e->username());
}
if (key.comment().isEmpty()) {
key.setComment(fileName);
}
if (!m_addedKeys.contains(key) && settings.addAtDatabaseOpen()) {
quint32 lifetime = 0;
if (settings.useLifetimeConstraintWhenAdding()) {
lifetime = static_cast<quint32>(settings.lifetimeConstraintDuration());
}
if (!addIdentity(key, settings.removeAtDatabaseClose(),
lifetime, settings.useConfirmConstraintWhenAdding())) {
emit error(m_error);
}
}
}

View file

@ -20,6 +20,7 @@
#define KEEPASSXC_SSHAGENT_H
#include <QList>
#include <QHash>
#include <QtCore>
#include "gui/DatabaseWidget.h"
@ -35,15 +36,15 @@ public:
const QString errorString() const;
bool isAgentRunning() const;
bool addIdentity(OpenSSHKey& key, quint32 lifetime = 0, bool confirm = false);
bool addIdentity(OpenSSHKey& key, bool removeOnLock, quint32 lifetime, bool confirm);
bool removeIdentity(OpenSSHKey& key);
void removeIdentityAtLock(const OpenSSHKey& key, const QUuid& uuid);
void setAutoRemoveOnLock(const OpenSSHKey& key, bool autoRemove);
signals:
void error(const QString& message);
public slots:
void databaseModeChanged(DatabaseWidget::Mode mode = DatabaseWidget::LockedMode);
void databaseModeChanged();
private:
const quint8 SSH_AGENT_FAILURE = 5;
@ -71,7 +72,7 @@ private:
const quint32 AGENT_COPYDATA_ID = 0x804e50ba;
#endif
QMap<QUuid, QSet<OpenSSHKey>> m_keys;
QHash<OpenSSHKey, bool> m_addedKeys;
QString m_error;
};