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 <QTimer>
|
||||
#include <QUuid>
|
||||
#include "SMSubServer.h"
|
||||
#include "smsub.h"
|
||||
|
||||
SMSubServer::SMSubServer(const QString &socket)
|
||||
SMSubServer::SMSubServer(SMSubServerSettings *serverSettings, const QString &socket) : serverSettings(serverSettings)
|
||||
{
|
||||
setSocketOptions(QLocalServer::UserAccessOption | QLocalServer::GroupAccessOption);
|
||||
listen(socket);
|
||||
|
@ -30,9 +32,17 @@ void SMSubServer::incomingConnection(quintptr socketDescriptor)
|
|||
{
|
||||
QLocalSocket *socket = new QLocalSocket();
|
||||
socket->setSocketDescriptor(socketDescriptor);
|
||||
QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
|
||||
QObject::connect(socket, SIGNAL(disconnected()), this, SLOT(deleteSocket()));
|
||||
sockets << socket;
|
||||
QObject::connect(socket, &QLocalSocket::readyRead, this, &SMSubServer::readyRead);
|
||||
QObject::connect(socket, &QLocalSocket::disconnected, this, &SMSubServer::deleteSocket);
|
||||
|
||||
// Set authentication state
|
||||
if (serverSettings->isLocal) {
|
||||
socket->setProperty("Authenticated", true);
|
||||
sockets << socket;
|
||||
}
|
||||
else {
|
||||
socket->setProperty("Authenticated", false);
|
||||
}
|
||||
|
||||
// Initial open writing
|
||||
socket->write(QString("SMSub Version %1\n").arg(QCoreApplication::applicationVersion()).toUtf8());
|
||||
|
@ -42,41 +52,70 @@ void SMSubServer::readyRead()
|
|||
{
|
||||
// Manage client input
|
||||
QLocalSocket *socket = (QLocalSocket*)sender();
|
||||
bool isAuthenticated = socket->property("Authenticated").toBool();
|
||||
while (socket->canReadLine()) {
|
||||
const QByteArray readData = socket->readLine().trimmed();
|
||||
if (readData.startsWith("+dbg")) {
|
||||
socket->setProperty("ReceiveDbgMsg", true);
|
||||
socket->write("Debug messages enabled!\n");
|
||||
if (likely(isAuthenticated)) {
|
||||
if (readData.startsWith("+dbg")) {
|
||||
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")) {
|
||||
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("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 (unlikely(tokens.contains(QString::fromUtf8(readData)))) {
|
||||
socket->setProperty("Authenticated", true);
|
||||
socket->write("Login successful!\n");
|
||||
isAuthenticated = true;
|
||||
sockets << socket;
|
||||
}
|
||||
else {
|
||||
// Stop receiving data and disconnect socket
|
||||
QObject::disconnect(socket, &QLocalSocket::readyRead, this, &SMSubServer::readyRead);
|
||||
socket->write("Incorrect token!\n");
|
||||
socket->disconnectFromServer();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -117,3 +156,11 @@ void SMSubServer::writeOutput(const QByteArray &output)
|
|||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
void SMSubServer::registerToken(const QString &token)
|
||||
{
|
||||
tokens << token;
|
||||
QTimer::singleShot(30000, [this, token]() {
|
||||
tokens.removeAll(token);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -23,14 +23,21 @@
|
|||
#include <QLocalSocket>
|
||||
#include <QObject>
|
||||
|
||||
struct SMSubServerSettings
|
||||
{
|
||||
bool canRegister;
|
||||
bool isLocal;
|
||||
};
|
||||
|
||||
class SMSubServer : public QLocalServer
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SMSubServer(const QString &socket);
|
||||
SMSubServer(SMSubServerSettings *serverSettings, const QString &socket);
|
||||
|
||||
public slots:
|
||||
void writeOutput(const QByteArray &output);
|
||||
void registerToken(const QString &token);
|
||||
|
||||
private slots:
|
||||
void incomingConnection(quintptr socketDescriptor);
|
||||
|
@ -39,9 +46,12 @@ private slots:
|
|||
|
||||
private:
|
||||
inline void debugOutput(QLocalSocket *socket, const QByteArray &message);
|
||||
SMSubServerSettings *serverSettings;
|
||||
QVector<QLocalSocket*> sockets;
|
||||
QVector<QString> tokens;
|
||||
|
||||
signals:
|
||||
void tokenRegistered(const QString &password);
|
||||
void inputWritten(const QByteArray &input);
|
||||
void killRequested();
|
||||
void stopRequested();
|
||||
|
|
81
main.cpp
81
main.cpp
|
@ -45,7 +45,7 @@ void catchUnixSignals(std::initializer_list<int> quitSignals) {
|
|||
|
||||
sigset_t blocking_mask;
|
||||
sigemptyset(&blocking_mask);
|
||||
for (auto sig : quitSignals)
|
||||
for (int sig : quitSignals)
|
||||
sigaddset(&blocking_mask, sig);
|
||||
|
||||
struct sigaction sa;
|
||||
|
@ -53,7 +53,7 @@ void catchUnixSignals(std::initializer_list<int> quitSignals) {
|
|||
sa.sa_mask = blocking_mask;
|
||||
sa.sa_flags = 0;
|
||||
|
||||
for (auto sig : quitSignals)
|
||||
for (int sig : quitSignals)
|
||||
sigaction(sig, &sa, nullptr);
|
||||
}
|
||||
#endif
|
||||
|
@ -62,7 +62,7 @@ int main(int argc, char *argv[])
|
|||
{
|
||||
QCoreApplication a(argc, argv);
|
||||
a.setApplicationName("Server Manager Subprocess");
|
||||
a.setApplicationVersion("0.1");
|
||||
a.setApplicationVersion("0.2");
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
catchUnixSignals({SIGQUIT, SIGINT, SIGTERM, SIGHUP});
|
||||
|
@ -82,12 +82,19 @@ int main(int argc, char *argv[])
|
|||
commandLineParser.addOption(processArguments);
|
||||
|
||||
#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
|
||||
QCommandLineOption subprocessSocket(QStringList() << "sock" << "socket", "Unix socket used for communication.", "sock");
|
||||
QCommandLineOption subprocessSocket(QStringList() << "sock" << "socket", "Unix socket used for local communication.", "sock");
|
||||
#endif
|
||||
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);
|
||||
|
||||
if (unlikely(commandLineParser.isSet(processManifest) && commandLineParser.isSet(processExecutable))) {
|
||||
|
@ -163,24 +170,68 @@ int main(int argc, char *argv[])
|
|||
if (likely(commandLineParser.isSet(subprocessSocket))) {
|
||||
socket = commandLineParser.value(subprocessSocket);
|
||||
}
|
||||
|
||||
SMSubServer subServer(socket);
|
||||
if (unlikely(!subServer.isListening())) {
|
||||
else {
|
||||
#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
|
||||
QTextStream(stderr) << "Failed to start Unix socket!" << endl;
|
||||
QTextStream(stderr) << "You must define at least a local Unix socket!" << endl;
|
||||
#endif
|
||||
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);
|
||||
|
||||
QObject::connect(&subProcess, SIGNAL(outputWritten(QByteArray)), &subServer, SLOT(writeOutput(QByteArray)));
|
||||
QObject::connect(&subServer, SIGNAL(inputWritten(QByteArray)), &subProcess, SLOT(writeInput(QByteArray)));
|
||||
QObject::connect(&subServer, SIGNAL(killRequested()), &subProcess, SLOT(killProcess()));
|
||||
QObject::connect(&subServer, SIGNAL(stopRequested()), &subProcess, SLOT(stopProcess()));
|
||||
QObject::connect(&a, SIGNAL(aboutToQuit()), &subProcess, SLOT(aboutToQuit()));
|
||||
QObject::connect(&subProcess, &SMSubProcess::outputWritten, &subLocal, &SMSubServer::writeOutput);
|
||||
QObject::connect(&subLocal, &SMSubServer::inputWritten, &subProcess, &SMSubProcess::writeInput);
|
||||
QObject::connect(&subLocal, &SMSubServer::killRequested, &subProcess, &SMSubProcess::killProcess);
|
||||
QObject::connect(&subLocal, &SMSubServer::stopRequested, &subProcess, &SMSubProcess::stopProcess);
|
||||
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();
|
||||
|
||||
|
|
Loading…
Reference in a new issue