Token secured remote server for websockify
This commit is contained in:
parent
2b5b5c22f2
commit
f13345e0f2
3 changed files with 160 additions and 52 deletions
119
SMSubServer.cpp
119
SMSubServer.cpp
|
@ -17,10 +17,12 @@
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QUuid>
|
||||||
#include "SMSubServer.h"
|
#include "SMSubServer.h"
|
||||||
#include "smsub.h"
|
#include "smsub.h"
|
||||||
|
|
||||||
SMSubServer::SMSubServer(const QString &socket)
|
SMSubServer::SMSubServer(SMSubServerSettings *serverSettings, const QString &socket) : serverSettings(serverSettings)
|
||||||
{
|
{
|
||||||
setSocketOptions(QLocalServer::UserAccessOption | QLocalServer::GroupAccessOption);
|
setSocketOptions(QLocalServer::UserAccessOption | QLocalServer::GroupAccessOption);
|
||||||
listen(socket);
|
listen(socket);
|
||||||
|
@ -30,9 +32,17 @@ void SMSubServer::incomingConnection(quintptr socketDescriptor)
|
||||||
{
|
{
|
||||||
QLocalSocket *socket = new QLocalSocket();
|
QLocalSocket *socket = new QLocalSocket();
|
||||||
socket->setSocketDescriptor(socketDescriptor);
|
socket->setSocketDescriptor(socketDescriptor);
|
||||||
QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
|
QObject::connect(socket, &QLocalSocket::readyRead, this, &SMSubServer::readyRead);
|
||||||
QObject::connect(socket, SIGNAL(disconnected()), this, SLOT(deleteSocket()));
|
QObject::connect(socket, &QLocalSocket::disconnected, this, &SMSubServer::deleteSocket);
|
||||||
sockets << socket;
|
|
||||||
|
// Set authentication state
|
||||||
|
if (serverSettings->isLocal) {
|
||||||
|
socket->setProperty("Authenticated", true);
|
||||||
|
sockets << socket;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
socket->setProperty("Authenticated", false);
|
||||||
|
}
|
||||||
|
|
||||||
// Initial open writing
|
// Initial open writing
|
||||||
socket->write(QString("SMSub Version %1\n").arg(QCoreApplication::applicationVersion()).toUtf8());
|
socket->write(QString("SMSub Version %1\n").arg(QCoreApplication::applicationVersion()).toUtf8());
|
||||||
|
@ -42,41 +52,70 @@ void SMSubServer::readyRead()
|
||||||
{
|
{
|
||||||
// Manage client input
|
// Manage client input
|
||||||
QLocalSocket *socket = (QLocalSocket*)sender();
|
QLocalSocket *socket = (QLocalSocket*)sender();
|
||||||
|
bool isAuthenticated = socket->property("Authenticated").toBool();
|
||||||
while (socket->canReadLine()) {
|
while (socket->canReadLine()) {
|
||||||
const QByteArray readData = socket->readLine().trimmed();
|
const QByteArray readData = socket->readLine().trimmed();
|
||||||
if (readData.startsWith("+dbg")) {
|
if (likely(isAuthenticated)) {
|
||||||
socket->setProperty("ReceiveDbgMsg", true);
|
if (readData.startsWith("+dbg")) {
|
||||||
socket->write("Debug messages enabled!\n");
|
socket->setProperty("ReceiveDbgMsg", true);
|
||||||
|
socket->write("Debug messages enabled!\n");
|
||||||
|
}
|
||||||
|
else if (readData.startsWith("-dbg")) {
|
||||||
|
socket->setProperty("ReceiveDbgMsg", false);
|
||||||
|
socket->write("Debug messages disabled!\n");
|
||||||
|
}
|
||||||
|
else if (readData.startsWith("+log")) {
|
||||||
|
socket->setProperty("ReceiveLog", true);
|
||||||
|
debugOutput(socket, "Log output enabled!");
|
||||||
|
}
|
||||||
|
else if (readData.startsWith("-log")) {
|
||||||
|
socket->setProperty("ReceiveLog", false);
|
||||||
|
debugOutput(socket, "Log output disabled!");
|
||||||
|
}
|
||||||
|
else if (readData.startsWith("+reg")) {
|
||||||
|
if (likely(serverSettings->canRegister)) {
|
||||||
|
QByteArray authUuid = QUuid::createUuid().toByteArray(QUuid::Id128);
|
||||||
|
authUuid = QByteArray::fromHex(authUuid).toBase64(QByteArray::OmitTrailingEquals);
|
||||||
|
emit tokenRegistered(QString::fromUtf8(authUuid));
|
||||||
|
socket->write("Token: " + authUuid + '\n');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
socket->write("Permission denied!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (readData.startsWith("kill")) {
|
||||||
|
emit killRequested();
|
||||||
|
debugOutput(socket, "Killing server!");
|
||||||
|
}
|
||||||
|
else if (readData.startsWith("stop")) {
|
||||||
|
emit stopRequested();
|
||||||
|
debugOutput(socket, "Stopping server!");
|
||||||
|
}
|
||||||
|
else if (readData.startsWith("wl")) {
|
||||||
|
const QByteArray writeData = readData.mid(3);
|
||||||
|
emit inputWritten(writeData + '\n');
|
||||||
|
debugOutput(socket, "Write line \"" + writeData + "\"!");
|
||||||
|
}
|
||||||
|
else if (readData.startsWith("w")) {
|
||||||
|
const QByteArray writeData = readData.mid(2);
|
||||||
|
emit inputWritten(writeData);
|
||||||
|
debugOutput(socket, "Write \"" + writeData + "\"!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (readData.startsWith("-dbg")) {
|
else {
|
||||||
socket->setProperty("ReceiveDbgMsg", false);
|
if (unlikely(tokens.contains(QString::fromUtf8(readData)))) {
|
||||||
socket->write("Debug messages disabled!\n");
|
socket->setProperty("Authenticated", true);
|
||||||
}
|
socket->write("Login successful!\n");
|
||||||
else if (readData.startsWith("+log")) {
|
isAuthenticated = true;
|
||||||
socket->setProperty("ReceiveLog", true);
|
sockets << socket;
|
||||||
debugOutput(socket, "Log output enabled!");
|
}
|
||||||
}
|
else {
|
||||||
else if (readData.startsWith("-log")) {
|
// Stop receiving data and disconnect socket
|
||||||
socket->setProperty("ReceiveLog", false);
|
QObject::disconnect(socket, &QLocalSocket::readyRead, this, &SMSubServer::readyRead);
|
||||||
debugOutput(socket, "Log output disabled!");
|
socket->write("Incorrect token!\n");
|
||||||
}
|
socket->disconnectFromServer();
|
||||||
else if (readData.startsWith("kill")) {
|
return;
|
||||||
emit killRequested();
|
}
|
||||||
debugOutput(socket, "Killing server!");
|
|
||||||
}
|
|
||||||
else if (readData.startsWith("stop")) {
|
|
||||||
emit stopRequested();
|
|
||||||
debugOutput(socket, "Stopping server!");
|
|
||||||
}
|
|
||||||
else if (readData.startsWith("wl")) {
|
|
||||||
const QByteArray writeData = readData.mid(3);
|
|
||||||
emit inputWritten(writeData + '\n');
|
|
||||||
debugOutput(socket, "Write line \"" + writeData + "\"!");
|
|
||||||
}
|
|
||||||
else if (readData.startsWith("w")) {
|
|
||||||
const QByteArray writeData = readData.mid(2);
|
|
||||||
emit inputWritten(writeData);
|
|
||||||
debugOutput(socket, "Write \"" + writeData + "\"!");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,3 +156,11 @@ void SMSubServer::writeOutput(const QByteArray &output)
|
||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SMSubServer::registerToken(const QString &token)
|
||||||
|
{
|
||||||
|
tokens << token;
|
||||||
|
QTimer::singleShot(30000, [this, token]() {
|
||||||
|
tokens.removeAll(token);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -23,14 +23,21 @@
|
||||||
#include <QLocalSocket>
|
#include <QLocalSocket>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
|
struct SMSubServerSettings
|
||||||
|
{
|
||||||
|
bool canRegister;
|
||||||
|
bool isLocal;
|
||||||
|
};
|
||||||
|
|
||||||
class SMSubServer : public QLocalServer
|
class SMSubServer : public QLocalServer
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
SMSubServer(const QString &socket);
|
SMSubServer(SMSubServerSettings *serverSettings, const QString &socket);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void writeOutput(const QByteArray &output);
|
void writeOutput(const QByteArray &output);
|
||||||
|
void registerToken(const QString &token);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void incomingConnection(quintptr socketDescriptor);
|
void incomingConnection(quintptr socketDescriptor);
|
||||||
|
@ -39,9 +46,12 @@ private slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline void debugOutput(QLocalSocket *socket, const QByteArray &message);
|
inline void debugOutput(QLocalSocket *socket, const QByteArray &message);
|
||||||
|
SMSubServerSettings *serverSettings;
|
||||||
QVector<QLocalSocket*> sockets;
|
QVector<QLocalSocket*> sockets;
|
||||||
|
QVector<QString> tokens;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
void tokenRegistered(const QString &password);
|
||||||
void inputWritten(const QByteArray &input);
|
void inputWritten(const QByteArray &input);
|
||||||
void killRequested();
|
void killRequested();
|
||||||
void stopRequested();
|
void stopRequested();
|
||||||
|
|
81
main.cpp
81
main.cpp
|
@ -45,7 +45,7 @@ void catchUnixSignals(std::initializer_list<int> quitSignals) {
|
||||||
|
|
||||||
sigset_t blocking_mask;
|
sigset_t blocking_mask;
|
||||||
sigemptyset(&blocking_mask);
|
sigemptyset(&blocking_mask);
|
||||||
for (auto sig : quitSignals)
|
for (int sig : quitSignals)
|
||||||
sigaddset(&blocking_mask, sig);
|
sigaddset(&blocking_mask, sig);
|
||||||
|
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
|
@ -53,7 +53,7 @@ void catchUnixSignals(std::initializer_list<int> quitSignals) {
|
||||||
sa.sa_mask = blocking_mask;
|
sa.sa_mask = blocking_mask;
|
||||||
sa.sa_flags = 0;
|
sa.sa_flags = 0;
|
||||||
|
|
||||||
for (auto sig : quitSignals)
|
for (int sig : quitSignals)
|
||||||
sigaction(sig, &sa, nullptr);
|
sigaction(sig, &sa, nullptr);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -62,7 +62,7 @@ int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
QCoreApplication a(argc, argv);
|
QCoreApplication a(argc, argv);
|
||||||
a.setApplicationName("Server Manager Subprocess");
|
a.setApplicationName("Server Manager Subprocess");
|
||||||
a.setApplicationVersion("0.1");
|
a.setApplicationVersion("0.2");
|
||||||
|
|
||||||
#ifdef Q_OS_UNIX
|
#ifdef Q_OS_UNIX
|
||||||
catchUnixSignals({SIGQUIT, SIGINT, SIGTERM, SIGHUP});
|
catchUnixSignals({SIGQUIT, SIGINT, SIGTERM, SIGHUP});
|
||||||
|
@ -82,12 +82,19 @@ int main(int argc, char *argv[])
|
||||||
commandLineParser.addOption(processArguments);
|
commandLineParser.addOption(processArguments);
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
QCommandLineOption subprocessSocket(QStringList() << "sock" << "socket", "IPC socket used for communication.", "sock");
|
QCommandLineOption subprocessSocket(QStringList() << "sock" << "socket", "IPC socket used for local communication.", "sock");
|
||||||
#else
|
#else
|
||||||
QCommandLineOption subprocessSocket(QStringList() << "sock" << "socket", "Unix socket used for communication.", "sock");
|
QCommandLineOption subprocessSocket(QStringList() << "sock" << "socket", "Unix socket used for local communication.", "sock");
|
||||||
#endif
|
#endif
|
||||||
commandLineParser.addOption(subprocessSocket);
|
commandLineParser.addOption(subprocessSocket);
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
QCommandLineOption subprocessRemoteSocket(QStringList() << "rsock" << "rsocket", "IPC socket used for remote communication.", "rsock");
|
||||||
|
#else
|
||||||
|
QCommandLineOption subprocessRemoteSocket(QStringList() << "rsock" << "rsocket", "Unix socket used for remote communication.", "rsock");
|
||||||
|
#endif
|
||||||
|
commandLineParser.addOption(subprocessRemoteSocket);
|
||||||
|
|
||||||
commandLineParser.process(a);
|
commandLineParser.process(a);
|
||||||
|
|
||||||
if (unlikely(commandLineParser.isSet(processManifest) && commandLineParser.isSet(processExecutable))) {
|
if (unlikely(commandLineParser.isSet(processManifest) && commandLineParser.isSet(processExecutable))) {
|
||||||
|
@ -163,24 +170,68 @@ int main(int argc, char *argv[])
|
||||||
if (likely(commandLineParser.isSet(subprocessSocket))) {
|
if (likely(commandLineParser.isSet(subprocessSocket))) {
|
||||||
socket = commandLineParser.value(subprocessSocket);
|
socket = commandLineParser.value(subprocessSocket);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
SMSubServer subServer(socket);
|
|
||||||
if (unlikely(!subServer.isListening())) {
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
QTextStream(stderr) << "Failed to start IPC socket!" << endl;
|
QTextStream(stderr) << "You must define at least a local IPC socket!" << endl;
|
||||||
#else
|
#else
|
||||||
QTextStream(stderr) << "Failed to start Unix socket!" << endl;
|
QTextStream(stderr) << "You must define at least a local Unix socket!" << endl;
|
||||||
#endif
|
#endif
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SMSubServerSettings localSettings;
|
||||||
|
localSettings.isLocal = true;
|
||||||
|
|
||||||
|
SMSubServer subLocal(&localSettings, socket);
|
||||||
|
if (unlikely(!subLocal.isListening())) {
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
QTextStream(stderr) << "Failed to start local IPC socket!" << endl;
|
||||||
|
#else
|
||||||
|
QTextStream(stderr) << "Failed to start local Unix socket!" << endl;
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString rsocket;
|
||||||
|
if (unlikely(commandLineParser.isSet(subprocessRemoteSocket))) {
|
||||||
|
rsocket = commandLineParser.value(subprocessRemoteSocket);
|
||||||
|
}
|
||||||
|
|
||||||
|
SMSubServerSettings remoteSettings;
|
||||||
|
remoteSettings.canRegister = false;
|
||||||
|
remoteSettings.isLocal = false;
|
||||||
|
|
||||||
|
SMSubServer subRemote(&remoteSettings, rsocket);
|
||||||
|
if (unlikely(!rsocket.isEmpty())) {
|
||||||
|
if (unlikely(!subRemote.isListening())) {
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
QTextStream(stderr) << "Failed to start remote IPC socket!" << endl;
|
||||||
|
#else
|
||||||
|
QTextStream(stderr) << "Failed to start remote Unix socket!" << endl;
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
localSettings.canRegister = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
localSettings.canRegister = false;
|
||||||
|
}
|
||||||
|
|
||||||
SMSubProcess subProcess(executable, argumentList, workingDirectory);
|
SMSubProcess subProcess(executable, argumentList, workingDirectory);
|
||||||
|
|
||||||
QObject::connect(&subProcess, SIGNAL(outputWritten(QByteArray)), &subServer, SLOT(writeOutput(QByteArray)));
|
QObject::connect(&subProcess, &SMSubProcess::outputWritten, &subLocal, &SMSubServer::writeOutput);
|
||||||
QObject::connect(&subServer, SIGNAL(inputWritten(QByteArray)), &subProcess, SLOT(writeInput(QByteArray)));
|
QObject::connect(&subLocal, &SMSubServer::inputWritten, &subProcess, &SMSubProcess::writeInput);
|
||||||
QObject::connect(&subServer, SIGNAL(killRequested()), &subProcess, SLOT(killProcess()));
|
QObject::connect(&subLocal, &SMSubServer::killRequested, &subProcess, &SMSubProcess::killProcess);
|
||||||
QObject::connect(&subServer, SIGNAL(stopRequested()), &subProcess, SLOT(stopProcess()));
|
QObject::connect(&subLocal, &SMSubServer::stopRequested, &subProcess, &SMSubProcess::stopProcess);
|
||||||
QObject::connect(&a, SIGNAL(aboutToQuit()), &subProcess, SLOT(aboutToQuit()));
|
QObject::connect(&a, &QCoreApplication::aboutToQuit, &subProcess, &SMSubProcess::aboutToQuit);
|
||||||
|
|
||||||
|
if (unlikely(!rsocket.isEmpty())) {
|
||||||
|
QObject::connect(&subLocal, &SMSubServer::tokenRegistered, &subRemote, &SMSubServer::registerToken);
|
||||||
|
QObject::connect(&subProcess, &SMSubProcess::outputWritten, &subRemote, &SMSubServer::writeOutput);
|
||||||
|
QObject::connect(&subRemote, &SMSubServer::inputWritten, &subProcess, &SMSubProcess::writeInput);
|
||||||
|
QObject::connect(&subRemote, &SMSubServer::killRequested, &subProcess, &SMSubProcess::killProcess);
|
||||||
|
QObject::connect(&subRemote, &SMSubServer::stopRequested, &subProcess, &SMSubProcess::stopProcess);
|
||||||
|
}
|
||||||
|
|
||||||
subProcess.start();
|
subProcess.start();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue