Skip to content

Commit

Permalink
Login & Logout flows now working
Browse files Browse the repository at this point in the history
 * Login will now trigger the proper actions and grab the URL and open it for the user
 * Logout will properly trigger the proper actions and set the correct UI states
  • Loading branch information
SneWs committed Jul 12, 2024
1 parent 081c7d6 commit 0643682
Show file tree
Hide file tree
Showing 10 changed files with 154 additions and 33 deletions.
29 changes: 23 additions & 6 deletions AccountsTabUiManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,43 @@
#include <QUrl>

#include "./ui_MainWindow.h"
#include "MainWindow.h"
#include "models.h"

AccountsTabUiManager::AccountsTabUiManager(Ui::MainWindow* u, QObject* parent)
AccountsTabUiManager::AccountsTabUiManager(Ui::MainWindow* u, TailRunner* runner, QObject* parent)
: QObject(parent)
, ui(u)
, pTailRunner(runner)
{

connect(ui->btnAdminConsole, &QPushButton::clicked,
this, [this]() {
connect(ui->btnAdminConsole, &QPushButton::clicked, this, [this]() {
QDesktopServices::openUrl(QUrl("https://login.tailscale.com/admin"));
}
);

connect(ui->btnLogout, &QPushButton::clicked, this, [this]() {
pTailRunner->logout();
auto* wnd = dynamic_cast<MainWindow*>(this->parent());
wnd->userLoggedOut();
wnd->hide();
}
);
}

AccountsTabUiManager::~AccountsTabUiManager() {
}

void AccountsTabUiManager::onTailStatusChanged(TailStatus* pTailStatus) {
if (pTailStatus->user->id <= 0)
return; // Not logged in
if (pTailStatus->user->id <= 0) {
// Not logged in

// Hide account details view, nothing to show
ui->accountDetailsContainer->setVisible(false);
ui->lstAccounts->clear();
return;
}

// Show account details view
ui->accountDetailsContainer->setVisible(true);
ui->lstAccounts->clear();
auto* pCurrent = new QListWidgetItem(pTailStatus->user->displayName + "\n" +
pTailStatus->user->loginName);
Expand All @@ -42,6 +58,7 @@ void AccountsTabUiManager::onTailStatusChanged(TailStatus* pTailStatus) {
ui->lblTailnetName->setText(pTailStatus->user->loginName);
ui->lblEmail->setText(pTailStatus->user->loginName);
ui->lblStatus->setText(pTailStatus->backendState);
ui->lblKeyExpiry->setText("");

// Show the key expiry date in a more human readable format
const auto now = QDateTime::currentDateTime();
Expand Down
5 changes: 4 additions & 1 deletion AccountsTabUiManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

#include <QObject>

#include "TailRunner.h"

QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
Expand All @@ -19,13 +21,14 @@ class AccountsTabUiManager : public QObject
{
Q_OBJECT
public:
explicit AccountsTabUiManager(Ui::MainWindow* ui, QObject* parent = nullptr);
explicit AccountsTabUiManager(Ui::MainWindow* ui, TailRunner* runner, QObject* parent = nullptr);
virtual ~AccountsTabUiManager();

void onTailStatusChanged(TailStatus* pTailStatus);

private:
Ui::MainWindow* ui;
TailRunner* pTailRunner;
};


Expand Down
17 changes: 16 additions & 1 deletion MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ MainWindow::MainWindow(QWidget* parent)
, pTailStatus(nullptr)
{
ui->setupUi(this);
accountsTabUi = new AccountsTabUiManager(ui, this);

pCurrentExecution = new TailRunner(settings, this);
connect(pCurrentExecution, &TailRunner::statusUpdated, this, &MainWindow::onTailStatusChanged);
connect(pCurrentExecution, &TailRunner::loginFlowCompleted, this, &MainWindow::loginFlowCompleted);

accountsTabUi = new AccountsTabUiManager(ui, pCurrentExecution, this);
pTrayManager = new TrayMenuManager(settings, pCurrentExecution, this);

changeToState(TailState::NotLoggedIn);
Expand Down Expand Up @@ -63,12 +64,26 @@ void MainWindow::settingsClosed() {
hide();
}

void MainWindow::loginFlowCompleted() {
pCurrentExecution->start();
}

TailState MainWindow::changeToState(TailState newState)
{
auto retVal = eCurrentState;
eCurrentState = newState;

if (eCurrentState == TailState::NotLoggedIn)
{
// Clear the status
delete pTailStatus;
pTailStatus = new TailStatus();
pTailStatus->self = new TailDeviceInfo();
pTailStatus->user = new TailUser();
}

pTrayManager->stateChangedTo(newState, pTailStatus);
accountsTabUi->onTailStatusChanged(pTailStatus);

return retVal;
}
Expand Down
3 changes: 3 additions & 0 deletions MainWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class MainWindow : public QMainWindow
void syncSettingsToUi();
void syncSettingsFromUi();

void userLoggedOut() { changeToState(TailState::NotLoggedIn); }

private:
Ui::MainWindow* ui;
AccountsTabUiManager* accountsTabUi;
Expand All @@ -44,6 +46,7 @@ class MainWindow : public QMainWindow

private slots:
void settingsClosed();
void loginFlowCompleted();

private:
// Switch to the new state and return the prev (old) state back to caller
Expand Down
4 changes: 2 additions & 2 deletions MainWindow.ui
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
<enum>QTabWidget::TabPosition::North</enum>
</property>
<property name="currentIndex">
<number>1</number>
<number>0</number>
</property>
<property name="iconSize">
<size>
Expand Down Expand Up @@ -139,7 +139,7 @@
</layout>
</item>
<item>
<widget class="QWidget" name="widget_6" native="true">
<widget class="QWidget" name="accountDetailsContainer" native="true">
<property name="minimumSize">
<size>
<width>325</width>
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ To do that, plese see the Getting started section below.
9. It will now be installed to `/usr/local/bin/tail-tray` and can be started by running `tail-tray` in a terminal or by clicking the Tail Tray icon in the launcher.

### Participating & Filing bugs
* If you would like to participate in the development of this project, please feel free to fork the repo and submit a pull request.
* If you find any bugs, please file an issue in the issues tab.
* If you would like to participate in the development of this project, feel free to fork the repo and submit a pull request.
* Bugs, we all get them... Please file an issue in the issues tab and we'll sort it out together.
### Screenshots
![Screenshot](screenshots/launcher.png)
Expand Down
72 changes: 66 additions & 6 deletions TailRunner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
#include <QMessageBox>
#include <QDebug>
#include <QByteArray>
#include <QDesktopServices>
#include <QJsonDocument>
#include <QJsonObject>
#include <QTimer>

TailRunner::TailRunner(const TailSettings& s, QObject* parent)
: QObject(parent)
: QObject(parent)
, settings(s)
, pProcess(nullptr)
, eCommand(Command::Status)
Expand All @@ -23,6 +25,20 @@ void TailRunner::checkStatus() {
runCommand("status", QStringList(), true);
}

void TailRunner::login() {
eCommand = Command::Login;
QStringList args;
args << "--operator" << qEnvironmentVariable("USER");

runCommand("login", args, false, true);
}

void TailRunner::logout() {
eCommand = Command::Logout;
QStringList args;
runCommand("logout", args, false, true);
}

void TailRunner::start(bool usePkExec) {
eCommand = Command::Connect;
QStringList args;
Expand Down Expand Up @@ -77,7 +93,7 @@ void TailRunner::stop() {
void TailRunner::runCommand(QString cmd, QStringList args, bool jsonResult, bool usePkExec) {
if (pProcess != nullptr) {
if (pProcess->state() == QProcess::Running) {
assert(!"Process already running!");
qDebug() << "Process already running!" << "Will skip running " << cmd << args << "command";
return;
}

Expand Down Expand Up @@ -107,7 +123,7 @@ void TailRunner::runCommand(QString cmd, QStringList args, bool jsonResult, bool
}
else {
// After we've invoked a command not status command we check for new status update
if (eCommand != Command::Status) {
if (eCommand != Command::Status && eCommand != Command::Logout) {
checkStatus();
}
}
Expand All @@ -116,11 +132,46 @@ void TailRunner::runCommand(QString cmd, QStringList args, bool jsonResult, bool
connect(pProcess, &QProcess::readyReadStandardOutput,
this, &TailRunner::onProcessCanReadStdOut);

// TODO: @grenis This needs some refactoring
connect(pProcess, &QProcess::readyReadStandardError,
this, [this]() {
QString errorInfo(pProcess->readAllStandardError());
if (!errorInfo.isEmpty()) {
qDebug() << errorInfo;
// NOTE! For whatever reason, the login command output is not captured by the readyReadStandardOutput signal
// and arrives as a error output, so we need to check for that here.
if (eCommand == Command::Login) {
QString message(pProcess->readAllStandardError());
if (!message.isEmpty()) {
qDebug() << message;
if (message.startsWith("Success", Qt::CaseSensitivity::CaseInsensitive)) {
// Login was successfull
// Wait for a bit before triggering flow completed
// Flow completed will call start etc
QTimer::singleShot(1000, this, [this]() {
emit loginFlowCompleted();
});
}
else {
QRegularExpression regex(R"(https:\/\/login\.tailscale\.com\/a\/[a-zA-Z0-9]+)");
QRegularExpressionMatch match = regex.match(message);
if (match.hasMatch()) {
QString url = match.captured(0);
auto res = QMessageBox::information(nullptr, "Login", "To login you will have to visit " + url + "\n\nPress OK to open the URL",
QMessageBox::Ok, QMessageBox::Ok);
if (res == QMessageBox::Ok)
QDesktopServices::openUrl(QUrl(url));
}
else {
// Failure
QMessageBox::warning(nullptr, "Login failure", "Login failed. Message: \n" + message,
QMessageBox::Ok, QMessageBox::Ok);
}
}
}
}
else {
QString errorInfo(pProcess->readAllStandardError());
if (!errorInfo.isEmpty()) {
qDebug() << errorInfo;
}
}
});

Expand All @@ -135,6 +186,12 @@ void TailRunner::runCommand(QString cmd, QStringList args, bool jsonResult, bool
else {
pProcess->start("tailscale", args);
}

// We need to handle the login by reading as soon as ther is output available since
// the process will be running until the login flow have completed
if (eCommand == Command::Login) {
pProcess->waitForReadyRead();
}
}

void TailRunner::onProcessCanReadStdOut() {
Expand Down Expand Up @@ -174,6 +231,9 @@ void TailRunner::onProcessCanReadStdOut() {
}
break;
}
case Command::Login: {
break;
}
default:
// Just echo out to console for now
qDebug() << QString(data);
Expand Down
6 changes: 6 additions & 0 deletions TailRunner.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,18 @@ class TailRunner : public QObject

void checkStatus();

void login();
void logout();

void start(bool usePkExec = false);
void stop();

private:
const TailSettings& settings;
QProcess* pProcess;
enum class Command {
Login,
Logout,
Connect,
Disconnect,
SettingsChange,
Expand All @@ -35,6 +40,7 @@ class TailRunner : public QObject

signals:
void statusUpdated(TailStatus* newStatus);
void loginFlowCompleted();

private:
void runCommand(QString cmd, QStringList args, bool jsonResult = false, bool usePkExec = false);
Expand Down
Loading

0 comments on commit 0643682

Please sign in to comment.