GUI: Begin IPC mechanism to open files despite sandboxing

This commit is contained in:
Albert S. 2021-09-28 21:44:09 +02:00
parent 3e387b99f8
commit 890925929a
11 changed files with 235 additions and 36 deletions

View File

@ -4,7 +4,7 @@
#
#-------------------------------------------------
QT += core concurrent gui
QT += core concurrent gui network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++17
@ -23,6 +23,8 @@ DEFINES += QT_DEPRECATED_WARNINGS
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
ipcclient.cpp \
ipcserver.cpp \
main.cpp \
mainwindow.cpp \
pdfworker.cpp \
@ -30,6 +32,9 @@ SOURCES += \
clicklabel.cpp
HEADERS += \
ipc.h \
ipcclient.h \
ipcserver.h \
mainwindow.h \
pdfworker.h \
pdfpreview.h \

9
gui/ipc.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef IPC_H
#define IPC_H
enum IPCCommand
{
DocOpen,
FileOpen
};
#endif // IPC_H

27
gui/ipcclient.cpp Normal file
View File

@ -0,0 +1,27 @@
#include <QDataStream>
#include "ipcclient.h"
IPCClient::IPCClient(QString socketPath)
{
this->socketPath = socketPath;
}
bool IPCClient::sendCommand(IPCCommand command, QStringList args)
{
bool result = false;
QLocalSocket socket;
socket.connectToServer(socketPath);
if(socket.isOpen() && socket.isWritable())
{
QDataStream stream(&socket);
stream << command;
stream << args;
socket.flush();
result = true;
}
else
{
qDebug() << "Not connected to IPC server";
}
return result;
}

18
gui/ipcclient.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef IPCCLIENT_H
#define IPCCLIENT_H
#include <QLocalSocket>
#include <QString>
#include <QStringList>
#include "ipc.h"
class IPCClient
{
private:
QString socketPath;
public:
IPCClient(QString socketPath);
bool sendCommand(IPCCommand command, QStringList args);
};
#endif // IPCCLIENT_H

88
gui/ipcserver.cpp Normal file
View File

@ -0,0 +1,88 @@
#include <QFile>
#include <QDesktopServices>
#include <QSettings>
#include <QProcess>
#include <QUrl>
#include <QLocalSocket>
#include <QDataStream>
#include "ipcserver.h"
IpcServer::IpcServer()
{
connect(&this->spawningServer, &QLocalServer::newConnection, this, &IpcServer::spawnerNewConnection);
}
bool IpcServer::startSpawner(QString socketPath)
{
QFile::remove(socketPath);
return this->spawningServer.listen(socketPath);
}
bool IpcServer::docOpen(QString path, int pagenum)
{
QSettings settings;
QString command = settings.value("pdfviewer").toString();
if(command != "" && command.contains("%p") && command.contains("%f"))
{
QStringList splitted = command.split(" ");
if(splitted.size() > 1)
{
QString cmd = splitted[0];
QStringList args = splitted.mid(1);
args.replaceInStrings("%f", path);
args.replaceInStrings("%p", QString::number(pagenum));
QProcess::startDetached(cmd, args);
}
}
else
{
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
}
return true;
}
bool IpcServer::fileOpen(QString path)
{
return QDesktopServices::openUrl(QUrl::fromLocalFile(path));
}
void IpcServer::spawnerNewConnection()
{
QScopedPointer<QLocalSocket> socket{this->spawningServer.nextPendingConnection()};
if(!socket.isNull())
{
if(!socket->waitForReadyRead())
{
return;
}
QDataStream stream(socket.get());
IPCCommand command;
QStringList args;
stream >> command;
stream >> args;
if(args.size() < 1)
{
stream << "invalid";
return;
}
if(command == DocOpen)
{
if(args.size() < 2)
{
stream << "invalid";
return;
}
docOpen(args[0], args[2].toInt());
}
if(command == FileOpen)
{
if(args.size() < 1)
{
stream << "invalid";
return;
}
fileOpen(args[0]);
}
}
}

21
gui/ipcserver.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef IPCSERVER_H
#define IPCSERVER_H
#include <QString>
#include <QLocalServer>
#include "ipc.h"
class IpcServer : public QObject
{
Q_OBJECT
private:
QLocalServer spawningServer;
bool docOpen(QString path, int pagenum);
bool fileOpen(QString path);
private slots:
void spawnerNewConnection();
public:
IpcServer();
bool startSpawner(QString socketPath);
};
#endif // IPCSERVER_H

View File

@ -2,19 +2,51 @@
#include <QSettings>
#include <QMessageBox>
#include <QStandardPaths>
#include <QProcess>
#include "mainwindow.h"
#include "searchresult.h"
#include "pdfpreview.h"
#include "../shared/common.h"
#include "../submodules/qssb.h/qssb.h"
#include "ipcserver.h"
int main(int argc, char *argv[])
{
QString socketPath = "/tmp/looqs-spawner";
if(argc > 1)
{
QApplication a(argc, argv);
QString arg = argv[1];
if(arg == "ipc")
{
IpcServer *ipcserver = new IpcServer();
qDebug() << "Launching ipc";
if(!ipcserver->startSpawner(socketPath))
{
qDebug() << "Error failed to spawn";
return 1;
}
qDebug() << "Launched";
}
return a.exec();
}
QProcess process;
QStringList args;
args << "ipc";
if(!process.startDetached("/proc/self/exe", args))
{
QString errorMsg = "Failed to start IPC server";
qDebug() << errorMsg;
QMessageBox::critical(nullptr, "Error", errorMsg);
}
struct qssb_policy *policy = qssb_init_policy();
std::string appDataLocation = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation).toStdString();
std::string cacheDataLocation = QStandardPaths::writableLocation(QStandardPaths::CacheLocation).toStdString();
std::string sockPath = socketPath.toStdString();
policy->namespace_options = QSSB_UNSHARE_NETWORK | QSSB_UNSHARE_USER;
qssb_append_path_policy(policy, QSSB_FS_ALLOW_READ | QSSB_FS_ALLOW_REMOVE_FILE, "/");
qssb_append_path_policy(policy, QSSB_FS_ALLOW_READ | QSSB_FS_ALLOW_REMOVE_FILE | QSSB_FS_ALLOW_WRITE,
appDataLocation.c_str());
@ -44,7 +76,9 @@ int main(int argc, char *argv[])
qRegisterMetaType<QVector<SearchResult>>("QVector<SearchResult>");
qRegisterMetaType<QVector<PdfPreview>>("QVector<PdfPreview>");
qRegisterMetaType<PdfPreview>("PdfPreview");
MainWindow w;
IPCClient client{socketPath};
MainWindow w{0, client};
w.showMaximized();
return a.exec();

View File

@ -18,10 +18,11 @@
#include "../shared/looqsgeneralexception.h"
#include "../shared/common.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
MainWindow::MainWindow(QWidget *parent, IPCClient &client) : QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
setWindowTitle(QCoreApplication::applicationName());
this->ipcClient = &client;
QSettings settings;
db = QSqlDatabase::addDatabase("QSQLITE");
@ -136,29 +137,7 @@ void MainWindow::pdfPreviewReceived(PdfPreview preview)
label->setPixmap(QPixmap::fromImage(preview.previewImage));
label->setToolTip(preview.documentPath);
ui->scrollAreaWidgetContents->layout()->addWidget(label);
connect(label, &ClickLabel::leftClick,
[docPath, previewPage]()
{
QSettings settings;
QString command = settings.value("pdfviewer").toString();
if(command != "" && command.contains("%p") && command.contains("%f"))
{
QStringList splitted = command.split(" ");
if(splitted.size() > 1)
{
QString cmd = splitted[0];
QStringList args = splitted.mid(1);
args.replaceInStrings("%f", docPath);
args.replaceInStrings("%p", QString::number(previewPage));
QProcess::startDetached(cmd, args);
}
}
else
{
QDesktopServices::openUrl(QUrl::fromLocalFile(docPath));
}
});
connect(label, &ClickLabel::leftClick, [this, docPath, previewPage]() { ipcDocOpen(docPath, previewPage); });
connect(label, &ClickLabel::rightClick,
[this, docPath, previewPage]()
{
@ -301,17 +280,27 @@ void MainWindow::createSearchResutlMenu(QMenu &menu, const QFileInfo &fileInfo)
[&fileInfo] { QGuiApplication::clipboard()->setText(fileInfo.fileName()); });
menu.addAction("Copy full path to clipboard",
[&fileInfo] { QGuiApplication::clipboard()->setText(fileInfo.absoluteFilePath()); });
menu.addAction("Open containing folder",
[&fileInfo]
{
QString dir = fileInfo.absolutePath();
QDesktopServices::openUrl(QUrl::fromLocalFile(dir));
});
menu.addAction("Open containing folder", [this, &fileInfo] { this->ipcFileOpen(fileInfo.absolutePath()); });
}
void MainWindow::ipcDocOpen(QString path, int num)
{
QStringList args;
args << path;
args << QString::number(num);
this->ipcClient->sendCommand(DocOpen, args);
}
void MainWindow::ipcFileOpen(QString path)
{
QStringList args;
args << path;
this->ipcClient->sendCommand(FileOpen, args);
}
void MainWindow::treeSearchItemActivated(QTreeWidgetItem *item, int i)
{
QDesktopServices::openUrl(QUrl::fromLocalFile(item->text(1)));
ipcFileOpen(item->text(1));
}
void MainWindow::showSearchResultsContextMenu(const QPoint &point)

View File

@ -8,8 +8,10 @@
#include <QKeyEvent>
#include <QFutureWatcher>
#include <QSqlDatabase>
#include <QLocalSocket>
#include "pdfworker.h"
#include "../shared/looqsquery.h"
#include "ipcclient.h"
namespace Ui
{
class MainWindow;
@ -20,7 +22,7 @@ class MainWindow : public QMainWindow
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
explicit MainWindow(QWidget *parent, IPCClient &client);
~MainWindow();
signals:
void beginSearch(const QString &query);
@ -28,6 +30,7 @@ class MainWindow : public QMainWindow
private:
Ui::MainWindow *ui;
IPCClient *ipcClient;
QFileIconProvider iconProvider;
bool pdfDirty;
QSqlDatabase db;
@ -45,6 +48,9 @@ class MainWindow : public QMainWindow
LooqsQuery currentQuery;
int pdfPreviewsPerPage;
void createSearchResutlMenu(QMenu &menu, const QFileInfo &fileInfo);
void ipcDocOpen(QString path, int num);
void ipcFileOpen(QString path);
private slots:
void lineEditReturnPressed();
void treeSearchItemActivated(QTreeWidgetItem *item, int i);

View File

@ -13,6 +13,8 @@ TEMPLATE = lib
CONFIG += staticlib
CONFIG += c++17
INCLUDEPATH += $$PWD/../sandbox/qssb.h/
# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the

@ -1 +1 @@
Subproject commit 75f607bc350354ed31fd0977311917e13241e703
Subproject commit 692c9b54b7b5fdca6a416d91d3f34d15af185c33