Fix bugs introduced by database refactor #2491 (#2503)

* Fix SSHAgent identity removal on database lock
* Refactor storage and manipulation of SSHAgent keys to streamline process with multiple db's
* Clear password field when widget is hidden, resolves #2502
This commit is contained in:
Janek Bevendorff 2018-11-23 13:49:55 +01:00 committed by Jonathan White
parent d612cad09a
commit 785a64cc3b
8 changed files with 155 additions and 131 deletions

View file

@ -38,16 +38,17 @@ SSHAgent::SSHAgent(QObject* parent)
SSHAgent::~SSHAgent()
{
for (const 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.");
}
@ -159,7 +160,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.");
@ -201,9 +211,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()) {
@ -222,120 +241,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::Mode::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::Mode::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.parse(keyData)) {
continue;
}
if (!key.openPrivateKey(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.parse(keyData)) {
continue;
}
if (!key.openPrivateKey(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);
}
}
}