#include "profile_dialog.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace { int standardPortForProtocol(const QString& protocol) { if (protocol == QStringLiteral("RDP")) { return 3389; } if (protocol == QStringLiteral("VNC")) { return 5900; } return 22; // SSH default } } ProfileDialog::ProfileDialog(QWidget* parent) : QDialog(parent), m_nameInput(new QLineEdit(this)), m_hostInput(new QLineEdit(this)), m_portInput(new QSpinBox(this)), m_usernameInput(new QLineEdit(this)), m_protocolInput(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(520, 340); auto* layout = new QVBoxLayout(this); auto* form = new QFormLayout(); m_nameInput->setPlaceholderText(QStringLiteral("Production Bastion")); m_hostInput->setPlaceholderText(QStringLiteral("example.internal")); m_portInput->setRange(1, 65535); m_portInput->setValue(22); m_usernameInput->setPlaceholderText(QStringLiteral("deploy")); m_protocolInput->addItems({QStringLiteral("SSH"), QStringLiteral("RDP"), QStringLiteral("VNC")}); m_authModeInput->addItems({QStringLiteral("Password"), QStringLiteral("Private Key")}); m_knownHostsPolicyInput->addItems( {QStringLiteral("Ask"), 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) { setWindowTitle(title); } void ProfileDialog::setProfile(const Profile& profile) { m_nameInput->setText(profile.name); 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); { // Keep stored custom port when loading an existing profile. const QSignalBlocker blocker(m_protocolInput); m_protocolInput->setCurrentIndex(protocolIndex >= 0 ? protocolIndex : 0); } 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 { Profile profile; profile.id = -1; profile.name = m_nameInput->text().trimmed(); profile.host = m_hostInput->text().trimmed(); profile.port = m_portInput->value(); 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; } void ProfileDialog::accept() { if (m_nameInput->text().trimmed().isEmpty()) { QMessageBox::warning(this, QStringLiteral("Validation Error"), QStringLiteral("Profile name is required.")); return; } if (m_hostInput->text().trimmed().isEmpty()) { QMessageBox::warning(this, QStringLiteral("Validation Error"), QStringLiteral("Host is required.")); 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); }