diff --git a/src/profile_dialog.cpp b/src/profile_dialog.cpp index 509c9d7..465adf2 100644 --- a/src/profile_dialog.cpp +++ b/src/profile_dialog.cpp @@ -2,7 +2,10 @@ #include #include +#include #include +#include +#include #include #include #include @@ -30,9 +33,12 @@ ProfileDialog::ProfileDialog(QWidget* parent) m_portInput(new QSpinBox(this)), m_usernameInput(new QLineEdit(this)), m_protocolInput(new QComboBox(this)), - m_authModeInput(new QComboBox(this)) + m_authModeInput(new QComboBox(this)), + m_privateKeyPathInput(new QLineEdit(this)), + m_browsePrivateKeyButton(new QPushButton(QStringLiteral("Browse"), this)), + m_knownHostsPolicyInput(new QComboBox(this)) { - resize(420, 260); + resize(520, 340); auto* layout = new QVBoxLayout(this); auto* form = new QFormLayout(); @@ -45,27 +51,66 @@ ProfileDialog::ProfileDialog(QWidget* parent) m_protocolInput->addItems({QStringLiteral("SSH"), QStringLiteral("RDP"), QStringLiteral("VNC")}); m_authModeInput->addItems({QStringLiteral("Password"), QStringLiteral("Private Key")}); + m_knownHostsPolicyInput->addItems( + {QStringLiteral("Strict"), QStringLiteral("Accept New"), QStringLiteral("Ignore")}); + + m_privateKeyPathInput->setPlaceholderText(QStringLiteral("/home/user/.ssh/id_ed25519")); + + auto* privateKeyRow = new QWidget(this); + auto* privateKeyLayout = new QHBoxLayout(privateKeyRow); + privateKeyLayout->setContentsMargins(0, 0, 0, 0); + privateKeyLayout->addWidget(m_privateKeyPathInput, 1); + privateKeyLayout->addWidget(m_browsePrivateKeyButton); + + connect(m_browsePrivateKeyButton, + &QPushButton::clicked, + this, + [this]() { + const QString selected = QFileDialog::getOpenFileName(this, + QStringLiteral("Select Private Key"), + QString(), + QStringLiteral("All Files (*)")); + if (!selected.isEmpty()) { + m_privateKeyPathInput->setText(selected); + } + }); connect(m_protocolInput, &QComboBox::currentTextChanged, this, [this](const QString& protocol) { m_portInput->setValue(standardPortForProtocol(protocol)); + refreshAuthFields(); }); + connect(m_authModeInput, + &QComboBox::currentTextChanged, + this, + [this](const QString&) { refreshAuthFields(); }); + form->addRow(QStringLiteral("Name"), m_nameInput); form->addRow(QStringLiteral("Host"), m_hostInput); form->addRow(QStringLiteral("Port"), m_portInput); form->addRow(QStringLiteral("Username"), m_usernameInput); form->addRow(QStringLiteral("Protocol"), m_protocolInput); form->addRow(QStringLiteral("Auth Mode"), m_authModeInput); + form->addRow(QStringLiteral("Private Key"), privateKeyRow); + form->addRow(QStringLiteral("Known Hosts"), m_knownHostsPolicyInput); + + auto* note = new QLabel( + QStringLiteral("Passwords are requested at connect time and are not stored."), + this); + note->setWordWrap(true); auto* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); layout->addLayout(form); + layout->addWidget(note); layout->addWidget(buttons); + + refreshAuthFields(); } void ProfileDialog::setDialogTitle(const QString& title) @@ -79,6 +124,7 @@ void ProfileDialog::setProfile(const Profile& profile) m_hostInput->setText(profile.host); m_portInput->setValue(profile.port > 0 ? profile.port : 22); m_usernameInput->setText(profile.username); + m_privateKeyPathInput->setText(profile.privateKeyPath); const int protocolIndex = m_protocolInput->findText(profile.protocol); { @@ -89,6 +135,11 @@ void ProfileDialog::setProfile(const Profile& profile) const int authModeIndex = m_authModeInput->findText(profile.authMode); m_authModeInput->setCurrentIndex(authModeIndex >= 0 ? authModeIndex : 0); + + const int knownHostsIndex = m_knownHostsPolicyInput->findText(profile.knownHostsPolicy); + m_knownHostsPolicyInput->setCurrentIndex(knownHostsIndex >= 0 ? knownHostsIndex : 0); + + refreshAuthFields(); } Profile ProfileDialog::profile() const @@ -101,6 +152,8 @@ Profile ProfileDialog::profile() const profile.username = m_usernameInput->text().trimmed(); profile.protocol = m_protocolInput->currentText(); profile.authMode = m_authModeInput->currentText(); + profile.privateKeyPath = m_privateKeyPathInput->text().trimmed(); + profile.knownHostsPolicy = m_knownHostsPolicyInput->currentText(); return profile; } @@ -120,5 +173,24 @@ void ProfileDialog::accept() return; } + if (m_protocolInput->currentText() == QStringLiteral("SSH") + && m_usernameInput->text().trimmed().isEmpty()) { + QMessageBox::warning(this, + QStringLiteral("Validation Error"), + QStringLiteral("Username is required for SSH profiles.")); + return; + } + QDialog::accept(); } + +void ProfileDialog::refreshAuthFields() +{ + const bool isSsh = m_protocolInput->currentText() == QStringLiteral("SSH"); + const bool isPrivateKey = m_authModeInput->currentText() == QStringLiteral("Private Key"); + + m_authModeInput->setEnabled(isSsh); + m_privateKeyPathInput->setEnabled(isSsh && isPrivateKey); + m_browsePrivateKeyButton->setEnabled(isSsh && isPrivateKey); + m_knownHostsPolicyInput->setEnabled(isSsh); +} diff --git a/src/profile_dialog.h b/src/profile_dialog.h index c7830ee..1496ace 100644 --- a/src/profile_dialog.h +++ b/src/profile_dialog.h @@ -7,6 +7,7 @@ class QComboBox; class QLineEdit; +class QPushButton; class QSpinBox; class ProfileDialog : public QDialog @@ -30,6 +31,11 @@ private: QLineEdit* m_usernameInput; QComboBox* m_protocolInput; QComboBox* m_authModeInput; + QLineEdit* m_privateKeyPathInput; + QPushButton* m_browsePrivateKeyButton; + QComboBox* m_knownHostsPolicyInput; + + void refreshAuthFields(); }; #endif diff --git a/src/profiles_window.cpp b/src/profiles_window.cpp index 5861c1a..a7bf4ef 100644 --- a/src/profiles_window.cpp +++ b/src/profiles_window.cpp @@ -119,12 +119,13 @@ void ProfilesWindow::loadProfiles(const QString& query) for (const Profile& profile : profiles) { auto* item = new QListWidgetItem(formatProfileListItem(profile), m_profilesList); item->setData(Qt::UserRole, QVariant::fromValue(profile.id)); - item->setToolTip(QStringLiteral("%1://%2@%3:%4\nAuth: %5") + item->setToolTip(QStringLiteral("%1://%2@%3:%4\nAuth: %5\nKnown Hosts: %6") .arg(profile.protocol, profile.username.isEmpty() ? QStringLiteral("") : profile.username, profile.host, QString::number(profile.port), - profile.authMode)); + profile.authMode, + profile.knownHostsPolicy)); m_profileCache.insert_or_assign(profile.id, profile); } }