Skip to content

Commit

Permalink
SSH Agent: Entry context menu control
Browse files Browse the repository at this point in the history
  • Loading branch information
hifi authored and droidmonkey committed Apr 8, 2020
1 parent d41a37c commit ef668f5
Show file tree
Hide file tree
Showing 10 changed files with 128 additions and 0 deletions.
2 changes: 2 additions & 0 deletions docs/KEYBINDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ Copy Password | Ctrl + C
Trigger AutoType | Ctrl + Shift - V
Open URL | Ctrl + Shift - U
Copy URL | Ctrl + U
Add key to SSH Agent | Ctrl + H
Remove key from SSH Agent | Ctrl + Shift + H
Show Minimized | Ctrl + M
Hide Window | Ctrl + Shift - M
Select Next Database Tab | Ctrl + Tab *OR* Ctrl + PGDN
Expand Down
57 changes: 57 additions & 0 deletions src/gui/DatabaseWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,50 @@ void DatabaseWidget::setClipboardTextAndMinimize(const QString& text)
}
}

#ifdef WITH_XC_SSHAGENT
void DatabaseWidget::addToAgent()
{
Entry* currentEntry = m_entryView->currentEntry();
Q_ASSERT(currentEntry);
if (!currentEntry) {
return;
}

KeeAgentSettings settings;
if (!settings.fromEntry(currentEntry)) {
return;
}

OpenSSHKey key;
if (settings.toOpenSSHKey(currentEntry, key, true)) {
SSHAgent::instance()->addIdentity(key, settings);
} else {
m_messageWidget->showMessage(key.errorString(), MessageWidget::Error);
}
}

void DatabaseWidget::removeFromAgent()
{
Entry* currentEntry = m_entryView->currentEntry();
Q_ASSERT(currentEntry);
if (!currentEntry) {
return;
}

KeeAgentSettings settings;
if (!settings.fromEntry(currentEntry)) {
return;
}

OpenSSHKey key;
if (settings.toOpenSSHKey(currentEntry, key, false)) {
SSHAgent::instance()->removeIdentity(key);
} else {
m_messageWidget->showMessage(key.errorString(), MessageWidget::Error);
}
}
#endif

void DatabaseWidget::performAutoType()
{
auto currentEntry = currentSelectedEntry();
Expand Down Expand Up @@ -1625,6 +1669,19 @@ bool DatabaseWidget::currentEntryHasTotp()
return currentEntry->hasTotp();
}

#ifdef WITH_XC_SSHAGENT
bool DatabaseWidget::currentEntryHasSshKey()
{
Entry* currentEntry = m_entryView->currentEntry();
Q_ASSERT(currentEntry);
if (!currentEntry) {
return false;
}

return KeeAgentSettings::inEntry(currentEntry);
}
#endif

bool DatabaseWidget::currentEntryHasNotes()
{
auto currentEntry = currentSelectedEntry();
Expand Down
7 changes: 7 additions & 0 deletions src/gui/DatabaseWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ class DatabaseWidget : public QStackedWidget
bool currentEntryHasUrl();
bool currentEntryHasNotes();
bool currentEntryHasTotp();
#ifdef WITH_XC_SSHAGENT
bool currentEntryHasSshKey();
#endif

QByteArray entryViewState() const;
bool setEntryViewState(const QByteArray& state) const;
Expand Down Expand Up @@ -169,6 +172,10 @@ public slots:
void showTotpKeyQrCode();
void copyTotp();
void setupTotp();
#ifdef WITH_XC_SSHAGENT
void addToAgent();
void removeFromAgent();
#endif
void performAutoType();
void openUrl();
void downloadSelectedFavicons();
Expand Down
33 changes: 33 additions & 0 deletions src/gui/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,20 @@ MainWindow::MainWindow()

#ifdef WITH_XC_SSHAGENT
connect(sshAgent(), SIGNAL(error(QString)), this, SLOT(showErrorMessage(QString)));
connect(sshAgent(), SIGNAL(enabledChanged(bool)), this, SLOT(agentEnabled(bool)));
m_ui->settingsWidget->addSettingsPage(new AgentSettingsPage(m_ui->tabWidget));

m_entryContextMenu->addSeparator();
m_entryContextMenu->addAction(m_ui->actionEntryAddToAgent);
m_entryContextMenu->addAction(m_ui->actionEntryRemoveFromAgent);

m_ui->actionEntryAddToAgent->setIcon(resources()->icon("utilities-terminal"));
m_ui->actionEntryRemoveFromAgent->setIcon(resources()->icon("utilities-terminal"));
#endif

m_ui->actionEntryAddToAgent->setVisible(false);
m_ui->actionEntryRemoveFromAgent->setVisible(false);

#if defined(WITH_XC_KEESHARE)
KeeShare::init(this);
m_ui->settingsWidget->addSettingsPage(new SettingsPageKeeShare(m_ui->tabWidget));
Expand Down Expand Up @@ -269,6 +280,8 @@ MainWindow::MainWindow()
m_ui->actionEntryAutoType->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_V);
m_ui->actionEntryOpenUrl->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_U);
m_ui->actionEntryCopyURL->setShortcut(Qt::CTRL + Qt::Key_U);
m_ui->actionEntryAddToAgent->setShortcut(Qt::CTRL + Qt::Key_H);
m_ui->actionEntryRemoveFromAgent->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_H);

#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
// Qt 5.10 introduced a new "feature" to hide shortcuts in context menus
Expand All @@ -285,6 +298,8 @@ MainWindow::MainWindow()
m_ui->actionEntryAutoType->setShortcutVisibleInContextMenu(true);
m_ui->actionEntryOpenUrl->setShortcutVisibleInContextMenu(true);
m_ui->actionEntryCopyURL->setShortcutVisibleInContextMenu(true);
m_ui->actionEntryAddToAgent->setShortcutVisibleInContextMenu(true);
m_ui->actionEntryRemoveFromAgent->setShortcutVisibleInContextMenu(true);
#endif

connect(m_ui->menuEntries, SIGNAL(aboutToShow()), SLOT(obtainContextFocusLock()));
Expand Down Expand Up @@ -440,6 +455,10 @@ MainWindow::MainWindow()
m_actionMultiplexer.connect(m_ui->actionEntryAutoType, SIGNAL(triggered()), SLOT(performAutoType()));
m_actionMultiplexer.connect(m_ui->actionEntryOpenUrl, SIGNAL(triggered()), SLOT(openUrl()));
m_actionMultiplexer.connect(m_ui->actionEntryDownloadIcon, SIGNAL(triggered()), SLOT(downloadSelectedFavicons()));
#ifdef WITH_XC_SSHAGENT
m_actionMultiplexer.connect(m_ui->actionEntryAddToAgent, SIGNAL(triggered()), SLOT(addToAgent()));
m_actionMultiplexer.connect(m_ui->actionEntryRemoveFromAgent, SIGNAL(triggered()), SLOT(removeFromAgent()));
#endif

m_actionMultiplexer.connect(m_ui->actionGroupNew, SIGNAL(triggered()), SLOT(createGroup()));
m_actionMultiplexer.connect(m_ui->actionGroupEdit, SIGNAL(triggered()), SLOT(switchToGroupEdit()));
Expand Down Expand Up @@ -691,6 +710,14 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
m_ui->actionExportCsv->setEnabled(true);
m_ui->actionExportHtml->setEnabled(true);
m_ui->actionDatabaseMerge->setEnabled(m_ui->tabWidget->currentIndex() != -1);
#ifdef WITH_XC_SSHAGENT
bool singleEntryHasSshKey =
singleEntrySelected && sshAgent()->isEnabled() && dbWidget->currentEntryHasSshKey();
m_ui->actionEntryAddToAgent->setVisible(singleEntryHasSshKey);
m_ui->actionEntryAddToAgent->setEnabled(singleEntryHasSshKey);
m_ui->actionEntryRemoveFromAgent->setVisible(singleEntryHasSshKey);
m_ui->actionEntryRemoveFromAgent->setEnabled(singleEntryHasSshKey);
#endif

m_searchWidgetAction->setEnabled(true);

Expand Down Expand Up @@ -1185,6 +1212,12 @@ void MainWindow::releaseContextFocusLock()
m_contextMenuFocusLock = false;
}

void MainWindow::agentEnabled(bool enabled)
{
m_ui->actionEntryAddToAgent->setVisible(enabled);
m_ui->actionEntryRemoveFromAgent->setVisible(enabled);
}

void MainWindow::showEntryContextMenu(const QPoint& globalPos)
{
bool entrySelected = false;
Expand Down
1 change: 1 addition & 0 deletions src/gui/MainWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ private slots:
void toggleUsernamesHidden();
void obtainContextFocusLock();
void releaseContextFocusLock();
void agentEnabled(bool enabled);

private:
static void setShortcut(QAction* action, QKeySequence::StandardKey standard, int fallback = 0);
Expand Down
13 changes: 13 additions & 0 deletions src/gui/MainWindow.ui
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,9 @@
<addaction name="separator"/>
<addaction name="actionEntryOpenUrl"/>
<addaction name="actionEntryDownloadIcon"/>
<addaction name="separator"/>
<addaction name="actionEntryAddToAgent"/>
<addaction name="actionEntryRemoveFromAgent"/>
</widget>
<widget class="QMenu" name="menuGroups">
<property name="title">
Expand Down Expand Up @@ -813,6 +816,16 @@
<string notr="true">Ctrl+/</string>
</property>
</action>
<action name="actionEntryAddToAgent">
<property name="text">
<string>Add key to SSH Agent</string>
</property>
</action>
<action name="actionEntryRemoveFromAgent">
<property name="text">
<string>Remove key from SSH Agent</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
Expand Down
11 changes: 11 additions & 0 deletions src/sshagent/KeeAgentSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,17 @@ QByteArray KeeAgentSettings::toXml() const
return ba;
}

/**
* Check if an entry has KeeAgent settings configured
*
* @param entry Entry to check the attachment
* @return true if XML document exists
*/
bool KeeAgentSettings::inEntry(const Entry* entry)
{
return entry->attachments()->hasKey("KeeAgent.settings");
}

/**
* Read settings from an entry as an XML attachment.
*
Expand Down
1 change: 1 addition & 0 deletions src/sshagent/KeeAgentSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class KeeAgentSettings
bool fromXml(const QByteArray& ba);
QByteArray toXml() const;

static bool inEntry(const Entry* entry);
bool fromEntry(const Entry* entry);
void toEntry(Entry* entry) const;
bool keyConfigured() const;
Expand Down
2 changes: 2 additions & 0 deletions src/sshagent/SSHAgent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ void SSHAgent::setEnabled(bool enabled)
}

config()->set("SSHAgent", enabled);

emit enabledChanged(enabled);
}

QString SSHAgent::authSockOverride() const
Expand Down
1 change: 1 addition & 0 deletions src/sshagent/SSHAgent.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class SSHAgent : public QObject

signals:
void error(const QString& message);
void enabledChanged(bool enabled);

public slots:
void databaseModeChanged();
Expand Down

0 comments on commit ef668f5

Please sign in to comment.