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: e547a97216
commatwo_master
Adeeb Shihadeh 4 years ago committed by GitHub
parent c3c741af70
commit c360723411
  1. 15
      selfdrive/hardware/hw.h
  2. 86
      selfdrive/ui/qt/offroad/networking.cc
  3. 13
      selfdrive/ui/qt/offroad/networking.hpp
  4. 50
      selfdrive/ui/qt/offroad/settings.cc
  5. 2
      selfdrive/ui/qt/offroad/settings.hpp
  6. 40
      selfdrive/ui/qt/widgets/controls.hpp
  7. 22
      selfdrive/ui/qt/widgets/input.cc
  8. 2
      selfdrive/ui/qt/widgets/input.hpp
  9. 3
      selfdrive/ui/qt/widgets/keyboard.cc
  10. 193
      selfdrive/ui/qt/widgets/ssh_keys.cc
  11. 49
      selfdrive/ui/qt/widgets/ssh_keys.hpp
  12. 2
      selfdrive/ui/qt/widgets/toggle.hpp

@ -22,6 +22,9 @@ public:
static void reboot() {}; static void reboot() {};
static void poweroff() {}; static void poweroff() {};
static void set_brightness(int percent) {}; static void set_brightness(int percent) {};
static bool get_ssh_enabled() { return false; };
static void set_ssh_enabled(bool enabled) {};
}; };
class HardwareEon : public HardwareNone { class HardwareEon : public HardwareNone {
@ -39,6 +42,14 @@ public:
brightness_control.close(); 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 { class HardwareTici : public HardwareNone {
@ -56,5 +67,7 @@ public:
brightness_control.close(); 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")); };
};

@ -3,11 +3,11 @@
#include <QLabel> #include <QLabel>
#include <QPixmap> #include <QPixmap>
#include <QPushButton> #include <QPushButton>
#include <QLineEdit>
#include <QRandomGenerator> #include <QRandomGenerator>
#include <algorithm> #include <algorithm>
#include "common/params.h" #include "common/params.h"
#include "hardware/hw.h"
#include "networking.hpp" #include "networking.hpp"
#include "util.h" #include "util.h"
@ -35,6 +35,7 @@ Networking::Networking(QWidget* parent, bool show_advanced) : QWidget(parent), s
s = new QStackedLayout; s = new QStackedLayout;
QLabel* warning = new QLabel("Network manager is inactive!"); QLabel* warning = new QLabel("Network manager is inactive!");
warning->setAlignment(Qt::AlignCenter);
warning->setStyleSheet(R"(font-size: 65px;)"); warning->setStyleSheet(R"(font-size: 65px;)");
s->addWidget(warning); 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 functions
AdvancedNetworking::AdvancedNetworking(QWidget* parent, WifiManager* wifi): QWidget(parent), wifi(wifi){ AdvancedNetworking::AdvancedNetworking(QWidget* parent, WifiManager* wifi): QWidget(parent), wifi(wifi){
s = new QStackedLayout; // mainPage, SSH settings
QVBoxLayout* vlayout = new QVBoxLayout; QVBoxLayout* vlayout = new QVBoxLayout;
vlayout->setMargin(40);
// Back button // Back button
QHBoxLayout* backLayout = new QHBoxLayout;
QPushButton* back = new QPushButton("Back"); QPushButton* back = new QPushButton("Back");
back->setFixedSize(500, 100); back->setFixedSize(500, 100);
connect(back, &QPushButton::released, [=](){emit backPress();}); connect(back, &QPushButton::released, [=](){emit backPress();});
backLayout->addWidget(back, 0, Qt::AlignLeft); vlayout->addWidget(back, 0, Qt::AlignLeft);
vlayout->addWidget(layoutToWidget(backLayout, this), 0, Qt::AlignLeft);
// Enable tethering layout // Enable tethering layout
QHBoxLayout* tetheringToggleLayout = new QHBoxLayout; QHBoxLayout* tetheringToggleLayout = new QHBoxLayout;
@ -164,9 +155,9 @@ AdvancedNetworking::AdvancedNetworking(QWidget* parent, WifiManager* wifi): QWid
if (wifi->tetheringEnabled()) { if (wifi->tetheringEnabled()) {
toggle_switch->togglePosition(); 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(layoutToWidget(tetheringToggleLayout, this), 0);
vlayout->addWidget(hline(), 0); vlayout->addWidget(horizontal_line(), 0);
// Change tethering password // Change tethering password
QHBoxLayout *tetheringPassword = new QHBoxLayout; QHBoxLayout *tetheringPassword = new QHBoxLayout;
@ -181,7 +172,7 @@ AdvancedNetworking::AdvancedNetworking(QWidget* parent, WifiManager* wifi): QWid
}); });
tetheringPassword->addWidget(editPasswordButton, 1, Qt::AlignRight); tetheringPassword->addWidget(editPasswordButton, 1, Qt::AlignRight);
vlayout->addWidget(layoutToWidget(tetheringPassword, this), 0); vlayout->addWidget(layoutToWidget(tetheringPassword, this), 0);
vlayout->addWidget(hline(), 0); vlayout->addWidget(horizontal_line(), 0);
// IP adress // IP adress
QHBoxLayout* IPlayout = new QHBoxLayout; QHBoxLayout* IPlayout = new QHBoxLayout;
@ -190,65 +181,22 @@ AdvancedNetworking::AdvancedNetworking(QWidget* parent, WifiManager* wifi): QWid
ipLabel->setStyleSheet("color: #aaaaaa"); ipLabel->setStyleSheet("color: #aaaaaa");
IPlayout->addWidget(ipLabel, 0, Qt::AlignRight); IPlayout->addWidget(ipLabel, 0, Qt::AlignRight);
vlayout->addWidget(layoutToWidget(IPlayout, this), 0); vlayout->addWidget(layoutToWidget(IPlayout, this), 0);
vlayout->addWidget(hline(), 0); vlayout->addWidget(horizontal_line(), 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);
// SSH keys // SSH keys
QHBoxLayout* authSSHLayout = new QHBoxLayout(this); vlayout->addWidget(new SshToggle());
authSSHLayout->addWidget(new QLabel("SSH keys", this)); vlayout->addWidget(horizontal_line(), 0);
QPushButton* editAuthSSHButton = new QPushButton("EDIT", this); vlayout->addWidget(new SshControl());
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);
}
bool AdvancedNetworking::isSSHEnabled(){ setLayout(vlayout);
return Params().get("SshEnabled") == "1";
} }
void AdvancedNetworking::refresh(){ void AdvancedNetworking::refresh(){
ipLabel->setText(wifi->ipv4_address); ipLabel->setText(wifi->ipv4_address);
if (toggle_switch_SSH->on != isSSHEnabled()) { update();
toggle_switch_SSH->togglePosition();
}
// Qt can be lazy
repaint();
} }
void AdvancedNetworking::toggleTethering(int enable) { void AdvancedNetworking::toggleTethering(bool enable) {
if (enable) { if (enable) {
wifi->enableTethering(); wifi->enableTethering();
} else { } else {
@ -257,10 +205,6 @@ void AdvancedNetworking::toggleTethering(int enable) {
editPasswordButton->setEnabled(!enable); editPasswordButton->setEnabled(!enable);
} }
void AdvancedNetworking::toggleSSH(int enable) {
Params().write_db_value("SshEnabled", QString::number(enable).toStdString());
}
// WifiUI functions // WifiUI functions
@ -327,7 +271,7 @@ void WifiUI::refresh() {
vlayout->addLayout(hlayout, 1); vlayout->addLayout(hlayout, 1);
// Don't add the last horizontal line // 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()) { 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++; i++;

@ -5,7 +5,6 @@
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QStackedWidget> #include <QStackedWidget>
#include <QPushButton> #include <QPushButton>
#include <QTimer>
#include "wifiManager.hpp" #include "wifiManager.hpp"
#include "widgets/input.hpp" #include "widgets/input.hpp"
@ -27,14 +26,11 @@ private:
bool tetheringEnabled; bool tetheringEnabled;
signals: signals:
void openKeyboard();
void closeKeyboard();
void connectToNetwork(Network n); void connectToNetwork(Network n);
public slots: public slots:
void handleButton(QAbstractButton* m_button); void handleButton(QAbstractButton* m_button);
void refresh(); void refresh();
void prevPage(); void prevPage();
void nextPage(); void nextPage();
}; };
@ -43,24 +39,17 @@ class AdvancedNetworking : public QWidget {
Q_OBJECT Q_OBJECT
public: public:
explicit AdvancedNetworking(QWidget* parent = 0, WifiManager* wifi = 0); explicit AdvancedNetworking(QWidget* parent = 0, WifiManager* wifi = 0);
QStackedLayout* s;
private: private:
QLabel* ipLabel; QLabel* ipLabel;
QPushButton* editPasswordButton; QPushButton* editPasswordButton;
SSH* ssh;
Toggle* toggle_switch_SSH;
WifiManager* wifi = nullptr; WifiManager* wifi = nullptr;
bool isSSHEnabled();
signals: signals:
void backPress(); void backPress();
public slots: public slots:
void toggleTethering(int enable); void toggleTethering(bool enable);
void toggleSSH(int enable);
void refresh(); void refresh();
}; };

@ -11,6 +11,7 @@
#include "widgets/toggle.hpp" #include "widgets/toggle.hpp"
#include "widgets/offroad_alerts.hpp" #include "widgets/offroad_alerts.hpp"
#include "widgets/controls.hpp" #include "widgets/controls.hpp"
#include "widgets/ssh_keys.hpp"
#include "common/params.h" #include "common/params.h"
#include "common/util.h" #include "common/util.h"
#include "selfdrive/hardware/hw.h" #include "selfdrive/hardware/hw.h"
@ -20,43 +21,43 @@ QWidget * toggles_panel() {
QVBoxLayout *toggles_list = new QVBoxLayout(); QVBoxLayout *toggles_list = new QVBoxLayout();
toggles_list->setMargin(50); toggles_list->setMargin(50);
toggles_list->addWidget(new ToggleControl("OpenpilotEnabledToggle", toggles_list->addWidget(new ParamControl("OpenpilotEnabledToggle",
"Enable openpilot", "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.", "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" "../assets/offroad/icon_openpilot.png"
)); ));
toggles_list->addWidget(horizontal_line()); toggles_list->addWidget(horizontal_line());
toggles_list->addWidget(new ToggleControl("LaneChangeEnabled", toggles_list->addWidget(new ParamControl("LaneChangeEnabled",
"Enable Lane Change Assist", "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.", "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" "../assets/offroad/icon_road.png"
)); ));
toggles_list->addWidget(horizontal_line()); toggles_list->addWidget(horizontal_line());
toggles_list->addWidget(new ToggleControl("IsLdwEnabled", toggles_list->addWidget(new ParamControl("IsLdwEnabled",
"Enable Lane Departure Warnings", "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).", "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" "../assets/offroad/icon_warning.png"
)); ));
toggles_list->addWidget(horizontal_line()); toggles_list->addWidget(horizontal_line());
toggles_list->addWidget(new ToggleControl("IsRHD", toggles_list->addWidget(new ParamControl("IsRHD",
"Enable Right-Hand Drive", "Enable Right-Hand Drive",
"Allow openpilot to obey left-hand traffic conventions and perform driver monitoring on right driver seat.", "Allow openpilot to obey left-hand traffic conventions and perform driver monitoring on right driver seat.",
"../assets/offroad/icon_openpilot_mirrored.png" "../assets/offroad/icon_openpilot_mirrored.png"
)); ));
toggles_list->addWidget(horizontal_line()); toggles_list->addWidget(horizontal_line());
toggles_list->addWidget(new ToggleControl("IsMetric", toggles_list->addWidget(new ParamControl("IsMetric",
"Use Metric System", "Use Metric System",
"Display speed in km/h instead of mp/h.", "Display speed in km/h instead of mp/h.",
"../assets/offroad/icon_metric.png" "../assets/offroad/icon_metric.png"
)); ));
toggles_list->addWidget(horizontal_line()); toggles_list->addWidget(horizontal_line());
toggles_list->addWidget(new ToggleControl("CommunityFeaturesToggle", toggles_list->addWidget(new ParamControl("CommunityFeaturesToggle",
"Enable Community Features", "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", "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" "../assets/offroad/icon_shell.png"
)); ));
ToggleControl *record_toggle = new ToggleControl("RecordFront", ParamControl *record_toggle = new ParamControl("RecordFront",
"Record and Upload Driver Camera", "Record and Upload Driver Camera",
"Upload data from the driver facing camera and help improve the driver monitoring algorithm.", "Upload data from the driver facing camera and help improve the driver monitoring algorithm.",
"../assets/offroad/icon_network.png"); "../assets/offroad/icon_network.png");
@ -188,20 +189,29 @@ QWidget * network_panel(QWidget * parent) {
layout->setMargin(100); layout->setMargin(100);
layout->setSpacing(30); layout->setSpacing(30);
// TODO: can probably use the ndk for this
// simple wifi + tethering buttons // simple wifi + tethering buttons
std::vector<std::pair<const char*, const char*>> btns = { const char* launch_wifi = "am start -n com.android.settings/.wifi.WifiPickerActivity \
{"WiFi Settings", "am start -n com.android.settings/.wifi.WifiPickerActivity \ -a android.net.wifi.PICK_WIFI_NETWORK \
-a android.net.wifi.PICK_WIFI_NETWORK \ --ez extra_prefs_show_button_bar true \
--ez extra_prefs_show_button_bar true \ --es extra_prefs_set_next_text ''";
--es extra_prefs_set_next_text ''"}, layout->addWidget(new ButtonControl("WiFi Settings", "OPEN", "",
{"Tethering Settings", "am start -n com.android.settings/.TetherSettings \ [=]() { std::system(launch_wifi); }));
--ez extra_prefs_show_button_bar true \
--es extra_prefs_set_next_text ''"}, layout->addWidget(horizontal_line());
};
for (auto &b : btns) { const char* launch_tethering = "am start -n com.android.settings/.TetherSettings \
layout->addWidget(new ButtonControl(b.first, "OPEN", "", [=]() { std::system(b.second); })); --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); layout->addStretch(1);
QWidget *w = new QWidget; QWidget *w = new QWidget;

@ -10,6 +10,8 @@
#include "selfdrive/ui/qt/widgets/controls.hpp" #include "selfdrive/ui/qt/widgets/controls.hpp"
// ********** settings window + top-level panels **********
class DeveloperPanel : public QFrame { class DeveloperPanel : public QFrame {
Q_OBJECT Q_OBJECT
public: public:

@ -27,6 +27,7 @@ protected:
QLabel *title_label; QLabel *title_label;
}; };
// widget to display a value
class LabelControl : public AbstractControl { class LabelControl : public AbstractControl {
Q_OBJECT Q_OBJECT
@ -42,6 +43,7 @@ private:
QLabel label; QLabel label;
}; };
// widget for a button with a label
class ButtonControl : public AbstractControl { class ButtonControl : public AbstractControl {
Q_OBJECT Q_OBJECT
@ -51,13 +53,13 @@ public:
btn.setText(text); btn.setText(text);
btn.setStyleSheet(R"( btn.setStyleSheet(R"(
padding: 0; padding: 0;
border-radius: 40px; border-radius: 50px;
font-size: 30px; font-size: 40px;
font-weight: 500; font-weight: 500;
color: #E4E4E4; color: #E4E4E4;
background-color: #393939; background-color: #393939;
)"); )");
btn.setFixedSize(200, 80); btn.setFixedSize(250, 100);
QObject::connect(&btn, &QPushButton::released, functor); QObject::connect(&btn, &QPushButton::released, functor);
hlayout->addWidget(&btn); hlayout->addWidget(&btn);
} }
@ -71,21 +73,37 @@ class ToggleControl : public AbstractControl {
Q_OBJECT Q_OBJECT
public: public:
ToggleControl(const QString &param, 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); toggle.setFixedSize(150, 100);
// set initial state from param if (state) {
if (Params().read_db_bool(param.toStdString().c_str())) {
toggle.togglePosition(); 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); hlayout->addWidget(&toggle);
QObject::connect(&toggle, &Toggle::stateChanged, this, &ToggleControl::toggleFlipped);
} }
void setEnabled(bool enabled) { toggle.setEnabled(enabled); } void setEnabled(bool enabled) { toggle.setEnabled(enabled); }
private: signals:
void toggleFlipped(bool state);
protected:
Toggle toggle; Toggle toggle;
}; };
// widget to toggle params
class ParamControl : public ToggleControl {
Q_OBJECT
public:
ParamControl(const QString &param, 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);
});
}
};

@ -112,7 +112,6 @@ void InputDialog::setMinLength(int length){
} }
ConfirmationDialog::ConfirmationDialog(QString prompt_text, QString confirm_text, QString cancel_text, ConfirmationDialog::ConfirmationDialog(QString prompt_text, QString confirm_text, QString cancel_text,
QWidget *parent):QDialog(parent) { QWidget *parent):QDialog(parent) {
setWindowFlags(Qt::Popup); setWindowFlags(Qt::Popup);
@ -131,13 +130,17 @@ ConfirmationDialog::ConfirmationDialog(QString prompt_text, QString confirm_text
btn_layout->addStretch(1); btn_layout->addStretch(1);
layout->addLayout(btn_layout); layout->addLayout(btn_layout);
QPushButton* cancel_btn = new QPushButton(cancel_text); if (cancel_text.length()) {
btn_layout->addWidget(cancel_btn, 0, Qt::AlignRight); QPushButton* cancel_btn = new QPushButton(cancel_text);
QObject::connect(cancel_btn, SIGNAL(released()), this, SLOT(reject())); btn_layout->addWidget(cancel_btn, 0, Qt::AlignRight);
QObject::connect(cancel_btn, SIGNAL(released()), this, SLOT(reject()));
}
QPushButton* confirm_btn = new QPushButton(confirm_text); if (confirm_text.length()) {
btn_layout->addWidget(confirm_btn, 0, Qt::AlignRight); QPushButton* confirm_btn = new QPushButton(confirm_text);
QObject::connect(confirm_btn, SIGNAL(released()), this, SLOT(accept())); btn_layout->addWidget(confirm_btn, 0, Qt::AlignRight);
QObject::connect(confirm_btn, SIGNAL(released()), this, SLOT(accept()));
}
setFixedSize(900, 350); setFixedSize(900, 350);
setStyleSheet(R"( setStyleSheet(R"(
@ -158,6 +161,11 @@ ConfirmationDialog::ConfirmationDialog(QString prompt_text, QString confirm_text
setLayout(layout); 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) { bool ConfirmationDialog::confirm(const QString prompt_text) {
ConfirmationDialog d = ConfirmationDialog(prompt_text); ConfirmationDialog d = ConfirmationDialog(prompt_text);
return d.exec(); return d.exec();

@ -38,13 +38,13 @@ signals:
void emitText(QString text); void emitText(QString text);
}; };
class ConfirmationDialog : public QDialog { class ConfirmationDialog : public QDialog {
Q_OBJECT Q_OBJECT
public: public:
explicit ConfirmationDialog(QString prompt_text, QString confirm_text = "Ok", explicit ConfirmationDialog(QString prompt_text, QString confirm_text = "Ok",
QString cancel_text = "Cancel", QWidget* parent = 0); QString cancel_text = "Cancel", QWidget* parent = 0);
static bool alert(QString prompt_text);
static bool confirm(QString prompt_text); static bool confirm(QString prompt_text);
private: private:

@ -41,6 +41,9 @@ KeyboardLayout::KeyboardLayout(QWidget *parent, std::vector<QVector<QString>> la
} }
setStyleSheet(R"( setStyleSheet(R"(
* {
outline: none;
}
QPushButton { QPushButton {
font-size: 65px; font-size: 65px;
margin: 0px; margin: 0px;

@ -1,165 +1,102 @@
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QState>
#include <QStateMachine>
#include <QNetworkReply> #include <QNetworkReply>
#include "widgets/ssh_keys.hpp"
#include "widgets/input.hpp" #include "widgets/input.hpp"
#include "widgets/ssh_keys.hpp"
#include "common/params.h" #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){ SshControl::SshControl() : AbstractControl("SSH Keys", "", "") {
// init variables // 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); manager = new QNetworkAccessManager(this);
networkTimer = new QTimer(this); networkTimer = new QTimer(this);
networkTimer->setSingleShot(true); networkTimer->setSingleShot(true);
networkTimer->setInterval(5000); networkTimer->setInterval(5000);
connect(networkTimer, SIGNAL(timeout()), this, SLOT(timeout())); connect(networkTimer, SIGNAL(timeout()), this, SLOT(timeout()));
dialog = new InputDialog(""); refresh();
// 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);
//Initialize the state machine and states // TODO: add desription through AbstractControl
QStateMachine* state = new QStateMachine(this); //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.");
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();
} }
void SSH::checkForSSHKey(){ void SshControl::refresh() {
QString SSHKey = QString::fromStdString(Params().get("GithubSshKeys")); QString param = QString::fromStdString(Params().get("GithubSshKeys"));
if (SSHKey.length()) { if (param.length()) {
emit SSHAdded(); btn.setText("REMOVE");
} else { } else {
emit NoSSHAdded(); btn.setText("ADD");
} }
btn.setEnabled(true);
} }
void SSH::getSSHKeys(){ void SshControl::getUserKeys(QString username){
QString url = "https://github.com/" + usernameGitHub + ".keys"; QString url = "https://github.com/" + username + ".keys";
aborted = false;
reply = manager->get(QNetworkRequest(QUrl(url))); 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())); connect(reply, SIGNAL(finished()), this, SLOT(parseResponse()));
networkTimer->start(); networkTimer->start();
} }
void SSH::timeout(){ void SshControl::timeout(){
aborted = true;
reply->abort(); reply->abort();
} }
void SSH::parseResponse(){ void SshControl::parseResponse(){
if (!aborted) { QString err = "";
if (reply->error() != QNetworkReply::OperationCanceledError) {
networkTimer->stop(); networkTimer->stop();
QString response = reply->readAll(); QString response = reply->readAll();
if (reply->error() == QNetworkReply::NoError && response.length()) { if (reply->error() == QNetworkReply::NoError && response.length()) {
Params().write_db_value("GithubSshKeys", response.toStdString()); Params().write_db_value("GithubSshKeys", response.toStdString());
emit gotSSHKeys();
} else if(reply->error() == QNetworkReply::NoError){ } else if(reply->error() == QNetworkReply::NoError){
emit failedResponse("Username " + usernameGitHub + " has no keys on GitHub"); err = "Username '" + username + "' has no keys on GitHub";
} else { } else {
emit failedResponse("Username " + usernameGitHub + " doesn't exist"); err = "Username '" + username + "' doesn't exist on GitHub";
} }
}else{ } else {
emit failedResponse("Request timed out"); err = "Request timed out";
}
if (err.length()) {
ConfirmationDialog::alert(err);
} }
refresh();
reply->deleteLater(); reply->deleteLater();
reply = nullptr; reply = nullptr;
} }

@ -1,42 +1,47 @@
#pragma once #pragma once
#include <QWidget>
#include <QButtonGroup>
#include <QVBoxLayout>
#include <QStackedWidget>
#include <QPushButton>
#include <QTimer> #include <QTimer>
#include <QPushButton>
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
#include <QStackedLayout>
#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 Q_OBJECT
public: public:
explicit SSH(QWidget* parent = 0); SshControl();
private: private:
QStackedLayout* slayout; QPushButton btn;
InputDialog* dialog; QString username;
QNetworkAccessManager* manager;
QString usernameGitHub; // networking
QNetworkReply* reply;
QTimer* networkTimer; QTimer* networkTimer;
bool aborted; QNetworkReply* reply;
QNetworkAccessManager* manager;
void refresh();
void getUserKeys(QString username);
signals: signals:
void closeSSHSettings();
void NoSSHAdded();
void SSHAdded();
void failedResponse(QString errorString); void failedResponse(QString errorString);
void gotSSHKeys();
private slots: private slots:
void checkForSSHKey();
void getSSHKeys();
void timeout(); void timeout();
void parseResponse(); void parseResponse();
}; };

@ -37,5 +37,5 @@ private:
QPropertyAnimation *_anim = nullptr; QPropertyAnimation *_anim = nullptr;
signals: signals:
void stateChanged(int new_state); void stateChanged(bool new_state);
}; };

Loading…
Cancel
Save