From c3607234119295c7fe17e5208a23eddc11c0ac25 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 22 Mar 2021 03:52:28 -0700 Subject: [PATCH] Qt UI: SSH keys (#20430) * rename * toggle control * SSH toggle * hw * qcom * lines * fix that * start refactoring * adding keys * hacky remove * alerts * fix qcom ssl * use the same widgets everywhere * clean up * more cleanup * little more * bigger * fix tethering toggleg old-commit-hash: e547a97216d226135e2b3a170fe0c525cc56f0e5 --- selfdrive/hardware/hw.h | 15 +- selfdrive/ui/qt/offroad/networking.cc | 86 ++--------- selfdrive/ui/qt/offroad/networking.hpp | 13 +- selfdrive/ui/qt/offroad/settings.cc | 50 ++++--- selfdrive/ui/qt/offroad/settings.hpp | 2 + selfdrive/ui/qt/widgets/controls.hpp | 40 +++-- selfdrive/ui/qt/widgets/input.cc | 22 ++- selfdrive/ui/qt/widgets/input.hpp | 2 +- selfdrive/ui/qt/widgets/keyboard.cc | 3 + selfdrive/ui/qt/widgets/ssh_keys.cc | 193 +++++++++---------------- selfdrive/ui/qt/widgets/ssh_keys.hpp | 49 ++++--- selfdrive/ui/qt/widgets/toggle.hpp | 2 +- 12 files changed, 203 insertions(+), 274 deletions(-) diff --git a/selfdrive/hardware/hw.h b/selfdrive/hardware/hw.h index aa37d7af96..8115aa946c 100644 --- a/selfdrive/hardware/hw.h +++ b/selfdrive/hardware/hw.h @@ -22,6 +22,9 @@ public: static void reboot() {}; static void poweroff() {}; static void set_brightness(int percent) {}; + + static bool get_ssh_enabled() { return false; }; + static void set_ssh_enabled(bool enabled) {}; }; class HardwareEon : public HardwareNone { @@ -39,6 +42,14 @@ public: brightness_control.close(); } }; + + static bool get_ssh_enabled() { + return std::system("getprop persist.neos.ssh | grep -qF '1'") == 0; + }; + static void set_ssh_enabled(bool enabled) { + std::string cmd = util::string_format("setprop persist.neos.ssh %d", enabled ? 1 : 0); + std::system(cmd.c_str()); + }; }; class HardwareTici : public HardwareNone { @@ -56,5 +67,7 @@ public: brightness_control.close(); } }; -}; + static bool get_ssh_enabled() { return Params().read_db_bool("SshEnabled"); }; + static void set_ssh_enabled(bool enabled) { Params().write_db_value("SshEnabled", (enabled ? "1" : "0")); }; +}; diff --git a/selfdrive/ui/qt/offroad/networking.cc b/selfdrive/ui/qt/offroad/networking.cc index fd0af5ca5b..2c93906347 100644 --- a/selfdrive/ui/qt/offroad/networking.cc +++ b/selfdrive/ui/qt/offroad/networking.cc @@ -3,11 +3,11 @@ #include #include #include -#include #include #include #include "common/params.h" +#include "hardware/hw.h" #include "networking.hpp" #include "util.h" @@ -35,6 +35,7 @@ Networking::Networking(QWidget* parent, bool show_advanced) : QWidget(parent), s s = new QStackedLayout; QLabel* warning = new QLabel("Network manager is inactive!"); + warning->setAlignment(Qt::AlignCenter); warning->setStyleSheet(R"(font-size: 65px;)"); s->addWidget(warning); @@ -131,28 +132,18 @@ void Networking::wrongPassword(QString ssid) { } } -QFrame* hline(QWidget* parent = 0){ - QFrame* line = new QFrame(parent); - line->setFrameShape(QFrame::StyledPanel); - line->setStyleSheet("margin-left: 40px; margin-right: 40px; border-width: 1px; border-bottom-style: solid; border-color: gray;"); - line->setFixedHeight(2); - return line; -} - // AdvancedNetworking functions AdvancedNetworking::AdvancedNetworking(QWidget* parent, WifiManager* wifi): QWidget(parent), wifi(wifi){ - s = new QStackedLayout; // mainPage, SSH settings QVBoxLayout* vlayout = new QVBoxLayout; + vlayout->setMargin(40); // Back button - QHBoxLayout* backLayout = new QHBoxLayout; QPushButton* back = new QPushButton("Back"); back->setFixedSize(500, 100); connect(back, &QPushButton::released, [=](){emit backPress();}); - backLayout->addWidget(back, 0, Qt::AlignLeft); - vlayout->addWidget(layoutToWidget(backLayout, this), 0, Qt::AlignLeft); + vlayout->addWidget(back, 0, Qt::AlignLeft); // Enable tethering layout QHBoxLayout* tetheringToggleLayout = new QHBoxLayout; @@ -164,9 +155,9 @@ AdvancedNetworking::AdvancedNetworking(QWidget* parent, WifiManager* wifi): QWid if (wifi->tetheringEnabled()) { toggle_switch->togglePosition(); } - QObject::connect(toggle_switch, SIGNAL(stateChanged(int)), this, SLOT(toggleTethering(int))); + QObject::connect(toggle_switch, SIGNAL(stateChanged(bool)), this, SLOT(toggleTethering(bool))); vlayout->addWidget(layoutToWidget(tetheringToggleLayout, this), 0); - vlayout->addWidget(hline(), 0); + vlayout->addWidget(horizontal_line(), 0); // Change tethering password QHBoxLayout *tetheringPassword = new QHBoxLayout; @@ -181,7 +172,7 @@ AdvancedNetworking::AdvancedNetworking(QWidget* parent, WifiManager* wifi): QWid }); tetheringPassword->addWidget(editPasswordButton, 1, Qt::AlignRight); vlayout->addWidget(layoutToWidget(tetheringPassword, this), 0); - vlayout->addWidget(hline(), 0); + vlayout->addWidget(horizontal_line(), 0); // IP adress QHBoxLayout* IPlayout = new QHBoxLayout; @@ -190,65 +181,22 @@ AdvancedNetworking::AdvancedNetworking(QWidget* parent, WifiManager* wifi): QWid ipLabel->setStyleSheet("color: #aaaaaa"); IPlayout->addWidget(ipLabel, 0, Qt::AlignRight); vlayout->addWidget(layoutToWidget(IPlayout, this), 0); - vlayout->addWidget(hline(), 0); - - // Enable SSH - QHBoxLayout* enableSSHLayout = new QHBoxLayout(this); - enableSSHLayout->addWidget(new QLabel("Enable SSH", this)); - toggle_switch_SSH = new Toggle(this); - toggle_switch_SSH->setFixedSize(150, 100); - if (isSSHEnabled()) { - toggle_switch_SSH->togglePosition(); - } - QObject::connect(toggle_switch_SSH, SIGNAL(stateChanged(int)), this, SLOT(toggleSSH(int))); - enableSSHLayout->addWidget(toggle_switch_SSH); - vlayout->addWidget(layoutToWidget(enableSSHLayout, this)); - vlayout->addWidget(hline(), 0); + vlayout->addWidget(horizontal_line(), 0); // SSH keys - QHBoxLayout* authSSHLayout = new QHBoxLayout(this); - authSSHLayout->addWidget(new QLabel("SSH keys", this)); - QPushButton* editAuthSSHButton = new QPushButton("EDIT", this); - editAuthSSHButton->setFixedWidth(500); - connect(editAuthSSHButton, &QPushButton::released, [=](){s->setCurrentWidget(ssh);}); - authSSHLayout->addWidget(editAuthSSHButton); - vlayout->addWidget(layoutToWidget(authSSHLayout, this)); - vlayout->addSpacing(50); - - // //Disconnect or delete connections - // QHBoxLayout* dangerZone = new QHBoxLayout(this); - // QPushButton* disconnect = new QPushButton("Disconnect from WiFi", this); - // dangerZone->addWidget(disconnect); - // QPushButton* deleteAll = new QPushButton("DELETE ALL NETWORKS", this); - // dangerZone->addWidget(deleteAll); - // vlayout->addWidget(layoutToWidget(dangerZone, this)); - - // vlayout to widget - QWidget* settingsWidget = layoutToWidget(vlayout, this); - settingsWidget->setStyleSheet("margin-left: 40px; margin-right: 40px;"); - s->addWidget(settingsWidget); - - ssh = new SSH; - connect(ssh, &SSH::closeSSHSettings, [=](){s->setCurrentWidget(settingsWidget);}); - s->addWidget(ssh); - - setLayout(s); -} + vlayout->addWidget(new SshToggle()); + vlayout->addWidget(horizontal_line(), 0); + vlayout->addWidget(new SshControl()); -bool AdvancedNetworking::isSSHEnabled(){ - return Params().get("SshEnabled") == "1"; + setLayout(vlayout); } void AdvancedNetworking::refresh(){ ipLabel->setText(wifi->ipv4_address); - if (toggle_switch_SSH->on != isSSHEnabled()) { - toggle_switch_SSH->togglePosition(); - } - // Qt can be lazy - repaint(); + update(); } -void AdvancedNetworking::toggleTethering(int enable) { +void AdvancedNetworking::toggleTethering(bool enable) { if (enable) { wifi->enableTethering(); } else { @@ -257,10 +205,6 @@ void AdvancedNetworking::toggleTethering(int enable) { editPasswordButton->setEnabled(!enable); } -void AdvancedNetworking::toggleSSH(int enable) { - Params().write_db_value("SshEnabled", QString::number(enable).toStdString()); -} - // WifiUI functions @@ -327,7 +271,7 @@ void WifiUI::refresh() { vlayout->addLayout(hlayout, 1); // Don't add the last horizontal line if (page * networks_per_page <= i+1 && i+1 < (page + 1) * networks_per_page && i+1 < wifi->seen_networks.size()) { - vlayout->addWidget(hline(), 0); + vlayout->addWidget(horizontal_line(), 0); } } i++; diff --git a/selfdrive/ui/qt/offroad/networking.hpp b/selfdrive/ui/qt/offroad/networking.hpp index dd82d320bc..fba7705074 100644 --- a/selfdrive/ui/qt/offroad/networking.hpp +++ b/selfdrive/ui/qt/offroad/networking.hpp @@ -5,7 +5,6 @@ #include #include #include -#include #include "wifiManager.hpp" #include "widgets/input.hpp" @@ -27,14 +26,11 @@ private: bool tetheringEnabled; signals: - void openKeyboard(); - void closeKeyboard(); void connectToNetwork(Network n); public slots: void handleButton(QAbstractButton* m_button); void refresh(); - void prevPage(); void nextPage(); }; @@ -43,24 +39,17 @@ class AdvancedNetworking : public QWidget { Q_OBJECT public: explicit AdvancedNetworking(QWidget* parent = 0, WifiManager* wifi = 0); - QStackedLayout* s; private: QLabel* ipLabel; QPushButton* editPasswordButton; - SSH* ssh; - Toggle* toggle_switch_SSH; - WifiManager* wifi = nullptr; - bool isSSHEnabled(); - signals: void backPress(); public slots: - void toggleTethering(int enable); - void toggleSSH(int enable); + void toggleTethering(bool enable); void refresh(); }; diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index f81d585b90..6e4ade8c99 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -11,6 +11,7 @@ #include "widgets/toggle.hpp" #include "widgets/offroad_alerts.hpp" #include "widgets/controls.hpp" +#include "widgets/ssh_keys.hpp" #include "common/params.h" #include "common/util.h" #include "selfdrive/hardware/hw.h" @@ -20,43 +21,43 @@ QWidget * toggles_panel() { QVBoxLayout *toggles_list = new QVBoxLayout(); toggles_list->setMargin(50); - toggles_list->addWidget(new ToggleControl("OpenpilotEnabledToggle", + toggles_list->addWidget(new ParamControl("OpenpilotEnabledToggle", "Enable openpilot", "Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off.", "../assets/offroad/icon_openpilot.png" )); toggles_list->addWidget(horizontal_line()); - toggles_list->addWidget(new ToggleControl("LaneChangeEnabled", + toggles_list->addWidget(new ParamControl("LaneChangeEnabled", "Enable Lane Change Assist", "Perform assisted lane changes with openpilot by checking your surroundings for safety, activating the turn signal and gently nudging the steering wheel towards your desired lane. openpilot is not capable of checking if a lane change is safe. You must continuously observe your surroundings to use this feature.", "../assets/offroad/icon_road.png" )); toggles_list->addWidget(horizontal_line()); - toggles_list->addWidget(new ToggleControl("IsLdwEnabled", + toggles_list->addWidget(new ParamControl("IsLdwEnabled", "Enable Lane Departure Warnings", "Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31mph (50kph).", "../assets/offroad/icon_warning.png" )); toggles_list->addWidget(horizontal_line()); - toggles_list->addWidget(new ToggleControl("IsRHD", + toggles_list->addWidget(new ParamControl("IsRHD", "Enable Right-Hand Drive", "Allow openpilot to obey left-hand traffic conventions and perform driver monitoring on right driver seat.", "../assets/offroad/icon_openpilot_mirrored.png" )); toggles_list->addWidget(horizontal_line()); - toggles_list->addWidget(new ToggleControl("IsMetric", + toggles_list->addWidget(new ParamControl("IsMetric", "Use Metric System", "Display speed in km/h instead of mp/h.", "../assets/offroad/icon_metric.png" )); toggles_list->addWidget(horizontal_line()); - toggles_list->addWidget(new ToggleControl("CommunityFeaturesToggle", + toggles_list->addWidget(new ParamControl("CommunityFeaturesToggle", "Enable Community Features", "Use features from the open source community that are not maintained or supported by comma.ai and have not been confirmed to meet the standard safety model. These features include community supported cars and community supported hardware. Be extra cautious when using these features", "../assets/offroad/icon_shell.png" )); - ToggleControl *record_toggle = new ToggleControl("RecordFront", + ParamControl *record_toggle = new ParamControl("RecordFront", "Record and Upload Driver Camera", "Upload data from the driver facing camera and help improve the driver monitoring algorithm.", "../assets/offroad/icon_network.png"); @@ -188,20 +189,29 @@ QWidget * network_panel(QWidget * parent) { layout->setMargin(100); layout->setSpacing(30); - // TODO: can probably use the ndk for this // simple wifi + tethering buttons - std::vector> btns = { - {"WiFi Settings", "am start -n com.android.settings/.wifi.WifiPickerActivity \ - -a android.net.wifi.PICK_WIFI_NETWORK \ - --ez extra_prefs_show_button_bar true \ - --es extra_prefs_set_next_text ''"}, - {"Tethering Settings", "am start -n com.android.settings/.TetherSettings \ - --ez extra_prefs_show_button_bar true \ - --es extra_prefs_set_next_text ''"}, - }; - for (auto &b : btns) { - layout->addWidget(new ButtonControl(b.first, "OPEN", "", [=]() { std::system(b.second); })); - } + const char* launch_wifi = "am start -n com.android.settings/.wifi.WifiPickerActivity \ + -a android.net.wifi.PICK_WIFI_NETWORK \ + --ez extra_prefs_show_button_bar true \ + --es extra_prefs_set_next_text ''"; + layout->addWidget(new ButtonControl("WiFi Settings", "OPEN", "", + [=]() { std::system(launch_wifi); })); + + layout->addWidget(horizontal_line()); + + const char* launch_tethering = "am start -n com.android.settings/.TetherSettings \ + --ez extra_prefs_show_button_bar true \ + --es extra_prefs_set_next_text ''"; + layout->addWidget(new ButtonControl("Tethering Settings", "OPEN", "", + [=]() { std::system(launch_tethering); })); + + layout->addWidget(horizontal_line()); + + // SSH key management + layout->addWidget(new SshToggle()); + layout->addWidget(horizontal_line()); + layout->addWidget(new SshControl()); + layout->addStretch(1); QWidget *w = new QWidget; diff --git a/selfdrive/ui/qt/offroad/settings.hpp b/selfdrive/ui/qt/offroad/settings.hpp index 0555bfa58d..c4c9773900 100644 --- a/selfdrive/ui/qt/offroad/settings.hpp +++ b/selfdrive/ui/qt/offroad/settings.hpp @@ -10,6 +10,8 @@ #include "selfdrive/ui/qt/widgets/controls.hpp" +// ********** settings window + top-level panels ********** + class DeveloperPanel : public QFrame { Q_OBJECT public: diff --git a/selfdrive/ui/qt/widgets/controls.hpp b/selfdrive/ui/qt/widgets/controls.hpp index 82db77f480..33f0e165ca 100644 --- a/selfdrive/ui/qt/widgets/controls.hpp +++ b/selfdrive/ui/qt/widgets/controls.hpp @@ -27,6 +27,7 @@ protected: QLabel *title_label; }; +// widget to display a value class LabelControl : public AbstractControl { Q_OBJECT @@ -42,6 +43,7 @@ private: QLabel label; }; +// widget for a button with a label class ButtonControl : public AbstractControl { Q_OBJECT @@ -51,13 +53,13 @@ public: btn.setText(text); btn.setStyleSheet(R"( padding: 0; - border-radius: 40px; - font-size: 30px; + border-radius: 50px; + font-size: 40px; font-weight: 500; color: #E4E4E4; background-color: #393939; )"); - btn.setFixedSize(200, 80); + btn.setFixedSize(250, 100); QObject::connect(&btn, &QPushButton::released, functor); hlayout->addWidget(&btn); } @@ -71,21 +73,37 @@ class ToggleControl : public AbstractControl { Q_OBJECT public: - ToggleControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon) : AbstractControl(title, desc, icon) { + ToggleControl(const QString &title, const QString &desc = "", const QString &icon = "", const bool state = false) : AbstractControl(title, desc, icon) { toggle.setFixedSize(150, 100); - // set initial state from param - if (Params().read_db_bool(param.toStdString().c_str())) { + if (state) { toggle.togglePosition(); } - QObject::connect(&toggle, &Toggle::stateChanged, [=](int state) { - char value = state ? '1' : '0'; - Params().write_db_value(param.toStdString().c_str(), &value, 1); - }); hlayout->addWidget(&toggle); + QObject::connect(&toggle, &Toggle::stateChanged, this, &ToggleControl::toggleFlipped); } void setEnabled(bool enabled) { toggle.setEnabled(enabled); } -private: +signals: + void toggleFlipped(bool state); + +protected: Toggle toggle; }; + +// widget to toggle params +class ParamControl : public ToggleControl { + Q_OBJECT + +public: + ParamControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon) : ToggleControl(title, desc, icon) { + // set initial state from param + if (Params().read_db_bool(param.toStdString().c_str())) { + toggle.togglePosition(); + } + QObject::connect(this, &ToggleControl::toggleFlipped, [=](int state) { + char value = state ? '1' : '0'; + Params().write_db_value(param.toStdString().c_str(), &value, 1); + }); + } +}; diff --git a/selfdrive/ui/qt/widgets/input.cc b/selfdrive/ui/qt/widgets/input.cc index c205dafd12..c45aa0adef 100644 --- a/selfdrive/ui/qt/widgets/input.cc +++ b/selfdrive/ui/qt/widgets/input.cc @@ -112,7 +112,6 @@ void InputDialog::setMinLength(int length){ } - ConfirmationDialog::ConfirmationDialog(QString prompt_text, QString confirm_text, QString cancel_text, QWidget *parent):QDialog(parent) { setWindowFlags(Qt::Popup); @@ -131,13 +130,17 @@ ConfirmationDialog::ConfirmationDialog(QString prompt_text, QString confirm_text btn_layout->addStretch(1); layout->addLayout(btn_layout); - QPushButton* cancel_btn = new QPushButton(cancel_text); - btn_layout->addWidget(cancel_btn, 0, Qt::AlignRight); - QObject::connect(cancel_btn, SIGNAL(released()), this, SLOT(reject())); + if (cancel_text.length()) { + QPushButton* cancel_btn = new QPushButton(cancel_text); + btn_layout->addWidget(cancel_btn, 0, Qt::AlignRight); + QObject::connect(cancel_btn, SIGNAL(released()), this, SLOT(reject())); + } - QPushButton* confirm_btn = new QPushButton(confirm_text); - btn_layout->addWidget(confirm_btn, 0, Qt::AlignRight); - QObject::connect(confirm_btn, SIGNAL(released()), this, SLOT(accept())); + if (confirm_text.length()) { + QPushButton* confirm_btn = new QPushButton(confirm_text); + btn_layout->addWidget(confirm_btn, 0, Qt::AlignRight); + QObject::connect(confirm_btn, SIGNAL(released()), this, SLOT(accept())); + } setFixedSize(900, 350); setStyleSheet(R"( @@ -158,6 +161,11 @@ ConfirmationDialog::ConfirmationDialog(QString prompt_text, QString confirm_text setLayout(layout); } +bool ConfirmationDialog::alert(const QString prompt_text) { + ConfirmationDialog d = ConfirmationDialog(prompt_text, "Ok", ""); + return d.exec(); +} + bool ConfirmationDialog::confirm(const QString prompt_text) { ConfirmationDialog d = ConfirmationDialog(prompt_text); return d.exec(); diff --git a/selfdrive/ui/qt/widgets/input.hpp b/selfdrive/ui/qt/widgets/input.hpp index c831d6032a..a5d0dd9051 100644 --- a/selfdrive/ui/qt/widgets/input.hpp +++ b/selfdrive/ui/qt/widgets/input.hpp @@ -38,13 +38,13 @@ signals: void emitText(QString text); }; - class ConfirmationDialog : public QDialog { Q_OBJECT public: explicit ConfirmationDialog(QString prompt_text, QString confirm_text = "Ok", QString cancel_text = "Cancel", QWidget* parent = 0); + static bool alert(QString prompt_text); static bool confirm(QString prompt_text); private: diff --git a/selfdrive/ui/qt/widgets/keyboard.cc b/selfdrive/ui/qt/widgets/keyboard.cc index f5b6f7ff81..4dbcc2816f 100644 --- a/selfdrive/ui/qt/widgets/keyboard.cc +++ b/selfdrive/ui/qt/widgets/keyboard.cc @@ -41,6 +41,9 @@ KeyboardLayout::KeyboardLayout(QWidget *parent, std::vector> la } setStyleSheet(R"( + * { + outline: none; + } QPushButton { font-size: 65px; margin: 0px; diff --git a/selfdrive/ui/qt/widgets/ssh_keys.cc b/selfdrive/ui/qt/widgets/ssh_keys.cc index 0b402bd60e..b278bf6a7f 100644 --- a/selfdrive/ui/qt/widgets/ssh_keys.cc +++ b/selfdrive/ui/qt/widgets/ssh_keys.cc @@ -1,165 +1,102 @@ -#include -#include -#include -#include -#include #include -#include "widgets/ssh_keys.hpp" #include "widgets/input.hpp" +#include "widgets/ssh_keys.hpp" #include "common/params.h" -QWidget* layout_to_widget(QLayout* l){ - QWidget* q = new QWidget; - q->setLayout(l); - return q; -} -SSH::SSH(QWidget* parent) : QWidget(parent){ - // init variables +SshControl::SshControl() : AbstractControl("SSH Keys", "", "") { + // setup widget + btn.setStyleSheet(R"( + padding: 0; + border-radius: 50px; + font-size: 40px; + font-weight: 500; + color: #E4E4E4; + background-color: #393939; + )"); + btn.setFixedSize(250, 100); + hlayout->addWidget(&btn); + + QObject::connect(&btn, &QPushButton::released, [=]() { + if (btn.text() == "ADD") { + username = InputDialog::getText("Enter your GitHub username"); + if (username.length() > 0) { + btn.setText("LOADING"); + btn.setEnabled(false); + getUserKeys(username); + } + } else { + Params().delete_db_value("GithubSshKeys"); + refresh(); + } + }); + + // setup networking manager = new QNetworkAccessManager(this); networkTimer = new QTimer(this); networkTimer->setSingleShot(true); networkTimer->setInterval(5000); connect(networkTimer, SIGNAL(timeout()), this, SLOT(timeout())); - dialog = new InputDialog(""); - // Construct the layouts to display - slayout = new QStackedLayout(this); // Initial screen, input, waiting for response - - //Layout on entering - QVBoxLayout* initialLayout = new QVBoxLayout; - initialLayout->setContentsMargins(80, 80, 80, 80); - - QHBoxLayout* header = new QHBoxLayout; - QPushButton* exitButton = new QPushButton("BACK", this); - exitButton->setFixedSize(500, 100); - header->addWidget(exitButton, 0, Qt::AlignLeft | Qt::AlignTop); - initialLayout->addWidget(layout_to_widget(header)); - - QLabel* title = new QLabel("Authorize SSH keys"); - title->setStyleSheet(R"(font-size: 75px;)"); - header->addWidget(title, 0, Qt::AlignRight | Qt::AlignTop); - - QLabel* wallOfText = new QLabel("Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A Comma employee will NEVER ask you to add their GitHub username."); - wallOfText->setWordWrap(true); - wallOfText->setStyleSheet(R"(font-size: 60px;)"); - initialLayout->addWidget(wallOfText, 0); - - QPushButton* actionButton = new QPushButton; - actionButton->setFixedHeight(100); - initialLayout->addWidget(actionButton, 0, Qt::AlignBottom); - - slayout->addWidget(layout_to_widget(initialLayout)); - - QLabel* loading = new QLabel("Loading SSH keys from GitHub."); - slayout->addWidget(loading); - - setStyleSheet(R"( - QPushButton { - font-size: 60px; - margin: 0px; - padding: 15px; - border-radius: 25px; - color: #dddddd; - background-color: #444444; - } - )"); - setLayout(slayout); - + refresh(); - //Initialize the state machine and states - QStateMachine* state = new QStateMachine(this); - QState* initialState = new QState(); //State when entering the widget - QState* initialStateNoGithub = new QState(); //Starting state, key not connected - QState* initialStateConnected = new QState(); //Starting state, ssh connected - QState* quitState = new QState(); // State when exiting the widget - QState* removeSSH_State = new QState(); // State when user wants to remove the SSH keys - QState* defaultInputFieldState = new QState(); // State when we want the user to give us the username - QState* loadingState = new QState(); // State while waiting for the network response - - - // Adding states to the state machine and adding the transitions - state->addState(initialState); - connect(initialState, &QState::entered, [=](){checkForSSHKey(); slayout->setCurrentIndex(0);}); - initialState->addTransition(this, &SSH::NoSSHAdded, initialStateNoGithub); - initialState->addTransition(this, &SSH::SSHAdded, initialStateConnected); - - - state->addState(quitState); - connect(quitState, &QState::entered, [=](){emit closeSSHSettings();}); - quitState->addTransition(quitState, &QState::entered, initialState); - - state->addState(initialStateConnected); - connect(initialStateConnected, &QState::entered, [=](){actionButton->setText("Remove GitHub SSH keys"); actionButton->setStyleSheet(R"(background-color: #750c0c;)");}); - initialStateConnected->addTransition(exitButton, &QPushButton::released, quitState); - initialStateConnected->addTransition(actionButton, &QPushButton::released, removeSSH_State); - - state->addState(removeSSH_State); - connect(removeSSH_State, &QState::entered, [=](){Params().delete_db_value("GithubSshKeys");}); - removeSSH_State->addTransition(removeSSH_State, &QState::entered, initialState); - - state->addState(initialStateNoGithub); - connect(initialStateNoGithub, &QState::entered, [=](){actionButton->setText("Link GitHub SSH keys"); actionButton->setStyleSheet(R"(background-color: #444444;)");}); - initialStateNoGithub->addTransition(exitButton, &QPushButton::released, quitState); - initialStateNoGithub->addTransition(actionButton, &QPushButton::released, defaultInputFieldState); - connect(actionButton, &QPushButton::released, [=](){dialog->setMessage("Enter your GitHub username");}); - - state->addState(defaultInputFieldState); - connect(defaultInputFieldState, &QState::entered, [=](){dialog->show();}); - connect(dialog, &InputDialog::emitText, [=](QString a){usernameGitHub = a;}); - defaultInputFieldState->addTransition(dialog, &InputDialog::cancel, initialState); - defaultInputFieldState->addTransition(dialog, &InputDialog::emitText, loadingState); - - - state->addState(loadingState); - connect(loadingState, &QState::entered, [=](){slayout->setCurrentIndex(1); getSSHKeys();}); - connect(this, &SSH::failedResponse, [=](QString message){dialog->setMessage(message);}); - loadingState->addTransition(this, &SSH::failedResponse, defaultInputFieldState); - loadingState->addTransition(this, &SSH::gotSSHKeys, initialState); - - - state->setInitialState(initialState); - state->start(); + // TODO: add desription through AbstractControl + //QLabel("Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A Comma employee will NEVER ask you to add their GitHub username."); } -void SSH::checkForSSHKey(){ - QString SSHKey = QString::fromStdString(Params().get("GithubSshKeys")); - if (SSHKey.length()) { - emit SSHAdded(); +void SshControl::refresh() { + QString param = QString::fromStdString(Params().get("GithubSshKeys")); + if (param.length()) { + btn.setText("REMOVE"); } else { - emit NoSSHAdded(); + btn.setText("ADD"); } + btn.setEnabled(true); } -void SSH::getSSHKeys(){ - QString url = "https://github.com/" + usernameGitHub + ".keys"; - aborted = false; - reply = manager->get(QNetworkRequest(QUrl(url))); +void SshControl::getUserKeys(QString username){ + QString url = "https://github.com/" + username + ".keys"; + + QNetworkRequest request; + request.setUrl(QUrl(url)); +#ifdef QCOM + QSslConfiguration ssl = QSslConfiguration::defaultConfiguration(); + ssl.setCaCertificates(QSslCertificate::fromPath("/usr/etc/tls/cert.pem", + QSsl::Pem, QRegExp::Wildcard)); + request.setSslConfiguration(ssl); +#endif + + reply = manager->get(request); connect(reply, SIGNAL(finished()), this, SLOT(parseResponse())); networkTimer->start(); } -void SSH::timeout(){ - aborted = true; +void SshControl::timeout(){ reply->abort(); } -void SSH::parseResponse(){ - if (!aborted) { +void SshControl::parseResponse(){ + QString err = ""; + if (reply->error() != QNetworkReply::OperationCanceledError) { networkTimer->stop(); QString response = reply->readAll(); if (reply->error() == QNetworkReply::NoError && response.length()) { Params().write_db_value("GithubSshKeys", response.toStdString()); - emit gotSSHKeys(); } else if(reply->error() == QNetworkReply::NoError){ - emit failedResponse("Username " + usernameGitHub + " has no keys on GitHub"); + err = "Username '" + username + "' has no keys on GitHub"; } else { - emit failedResponse("Username " + usernameGitHub + " doesn't exist"); + err = "Username '" + username + "' doesn't exist on GitHub"; } - }else{ - emit failedResponse("Request timed out"); + } else { + err = "Request timed out"; + } + + if (err.length()) { + ConfirmationDialog::alert(err); } + + refresh(); reply->deleteLater(); reply = nullptr; } diff --git a/selfdrive/ui/qt/widgets/ssh_keys.hpp b/selfdrive/ui/qt/widgets/ssh_keys.hpp index 8d5e72dcd8..c55249c0d5 100644 --- a/selfdrive/ui/qt/widgets/ssh_keys.hpp +++ b/selfdrive/ui/qt/widgets/ssh_keys.hpp @@ -1,42 +1,47 @@ #pragma once -#include -#include -#include -#include -#include #include +#include #include -#include -#include "widgets/input.hpp" -class SSH : public QWidget { +#include "widgets/controls.hpp" +#include "selfdrive/hardware/hw.h" + +// SSH enable toggle +class SshToggle : public ToggleControl { + Q_OBJECT + +public: + SshToggle() : ToggleControl("Enable SSH", "", "", Hardware::get_ssh_enabled()) { + QObject::connect(this, &SshToggle::toggleFlipped, [=](bool state) { + Hardware::set_ssh_enabled(state); + }); + } +}; + +// SSH key management widget +class SshControl : public AbstractControl { Q_OBJECT public: - explicit SSH(QWidget* parent = 0); + SshControl(); private: - QStackedLayout* slayout; - InputDialog* dialog; - QNetworkAccessManager* manager; + QPushButton btn; + QString username; - QString usernameGitHub; - QNetworkReply* reply; + // networking QTimer* networkTimer; - bool aborted; + QNetworkReply* reply; + QNetworkAccessManager* manager; + + void refresh(); + void getUserKeys(QString username); signals: - void closeSSHSettings(); - void NoSSHAdded(); - void SSHAdded(); void failedResponse(QString errorString); - void gotSSHKeys(); private slots: - void checkForSSHKey(); - void getSSHKeys(); void timeout(); void parseResponse(); }; - diff --git a/selfdrive/ui/qt/widgets/toggle.hpp b/selfdrive/ui/qt/widgets/toggle.hpp index 4549245dc7..a08a193ecc 100644 --- a/selfdrive/ui/qt/widgets/toggle.hpp +++ b/selfdrive/ui/qt/widgets/toggle.hpp @@ -37,5 +37,5 @@ private: QPropertyAnimation *_anim = nullptr; signals: - void stateChanged(int new_state); + void stateChanged(bool new_state); };