aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Reiner <nathan@nathanreiner.xyz>2024-03-03 22:56:04 +0100
committerNathan Reiner <nathan@nathanreiner.xyz>2024-03-03 22:56:04 +0100
commiteb629f8fa6f7edd3ba9f3e76146d71f62dafff57 (patch)
treea7d5264c5e4931d1ff6d6b9d456488b90f3f8553
parent1101c88ac7f5c4fbfbabf7d4206d40736562ed29 (diff)
refractor and add permission manager without save
-rw-r--r--config.mk2
-rw-r--r--src/main.cpp173
-rw-r--r--src/permissionmanager.cpp93
-rw-r--r--src/permissionmanager.hpp28
-rw-r--r--src/tray.cpp136
-rw-r--r--src/tray.hpp46
-rw-r--r--src/webwindow.cpp114
-rw-r--r--src/webwindow.hpp37
8 files changed, 487 insertions, 142 deletions
diff --git a/config.mk b/config.mk
index 4f04f30..1bbe8b3 100644
--- a/config.mk
+++ b/config.mk
@@ -1,4 +1,4 @@
TARGET_DIRECTORY=target
-CPPFLAGS=`pkg-config --cflags Qt6WebEngineWidgets Qt6WebEngineCore Qt6Core Qt6Gui`
+CPPFLAGS=`pkg-config --cflags Qt6WebEngineWidgets Qt6WebEngineCore Qt6Core Qt6Gui` -Wall
LDFLAGS=`pkg-config --libs Qt6WebEngineWidgets Qt6WebEngineCore Qt6Core Qt6Gui Qt6Multimedia` -fPIC
CC=g++
diff --git a/src/main.cpp b/src/main.cpp
index 246d0ad..9c6b3c4 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,168 +1,59 @@
-#include <QtCore/QTimer>
-#include <QtGui/QCloseEvent>
-#include <QtWebEngineCore/QWebEngineNotification>
-#include <QtWebEngineCore/QWebEnginePage>
-#include <QtWebEngineCore/QWebEngineProfile>
-#include <QtWebEngineCore/QWebEngineSettings>
-#include <QtWebEngineWidgets/QWebEngineView>
#include <QtWidgets/QApplication>
-#include <QtWidgets/QLayout>
-#include <QtWidgets/QMainWindow>
-#include <QtWidgets/QMenu>
-#include <QtWidgets/QMessageBox>
-#include <QtWidgets/QSystemTrayIcon>
-#include <QtWidgets/QWidget>
+
#include <iostream>
-class MainWindow : public QMainWindow
+#include "permissionmanager.hpp"
+#include "tray.hpp"
+#include "webwindow.hpp"
+
+QString
+extract_url(const QStringList arguments)
{
-public:
- void closeEvent(QCloseEvent *event)
- {
- this->hide();
- event->ignore();
+ for (const auto &argument : arguments) {
+ if (!argument.endsWith("webtray") && !argument.startsWith("--")) {
+ return argument;
+ }
}
-};
+ return "";
+}
int
main(int argc, char **argv)
{
QApplication app(argc, argv);
- bool start_hidden = true;
- QUrl url;
+ app.setQuitOnLastWindowClosed(false);
- for (auto argument : app.arguments()) {
- if (argument == "--open-at-startup") {
- start_hidden = false;
- } else {
- url = argument;
- }
- }
+ QString url = extract_url(app.arguments());
- if (url.url().toStdString() == argv[0]) {
- std::cerr << "webtray <url> [--open-at-startup]\n";
+ if (url.isEmpty()) {
+ std::cerr << "webtray [--open-at-startup] <url>\n";
return -1;
}
- MainWindow main_window;
-
- QSystemTrayIcon tray;
- QMenu menu;
-
- QWebEngineProfile profile(url.host().toStdString().c_str());
- QWebEnginePage page(&profile);
- QWebEngineView view;
+ WebWindow webwindow(url);
+ Tray tray;
+ bool start_hidden = not app.arguments().contains("--open-at-startup");
- QAction *app_action = menu.addAction("Element");
- menu.addSeparator();
- QAction *quit_action = menu.addAction("Quit");
-
- menu.connect(&menu, &QMenu::triggered, [&](QAction *action) {
- if (action == app_action) {
- main_window.setVisible(!main_window.isVisible());
- } else if (action == quit_action) {
- main_window.close();
- page.windowCloseRequested();
- app.quit();
- }
- });
-
- view.setPage(&page);
- view.setUrl(url);
-
- tray.setContextMenu(&menu);
-
- tray.connect(&tray,
- &QSystemTrayIcon::activated,
- [&](const QSystemTrayIcon::ActivationReason reason) {
- switch (reason) {
- case QSystemTrayIcon::Trigger:
- main_window.setVisible(!main_window.isVisible());
- break;
- default:
- break;
- }
- });
-
- view.connect(&view, &QWebEngineView::iconChanged, [&](const QIcon icon) {
+ webwindow.connect_icon_changed([&](auto icon) {
tray.setIcon(icon);
tray.show();
});
- view.connect(&view, &QWebEngineView::titleChanged, [&](const QString title) {
- tray.setToolTip(title);
- app_action->setText(title);
- });
-
- page.settings()->setAttribute(QWebEngineSettings::ScreenCaptureEnabled, true);
- page.settings()->setAttribute(QWebEngineSettings::WebRTCPublicInterfacesOnly,
- false);
- page.settings()->setAttribute(QWebEngineSettings::ScrollAnimatorEnabled,
- false);
+ webwindow.connect_title_changed([&](auto title) { tray.set_title(title); });
- profile.setPushServiceEnabled(true);
- profile.setNotificationPresenter(
- [&](std::unique_ptr<QWebEngineNotification> notification) {
- tray.showMessage(notification->title(),
- notification->message(),
- QSystemTrayIcon::MessageIcon::Information,
- 3000);
- });
-
- page.connect(&page,
- &QWebEnginePage::featurePermissionRequested,
- [&](const QUrl origin, QWebEnginePage::Feature feature) {
- QString feature_name;
-
- switch (feature) {
- case QWebEnginePage::Feature::MouseLock:
- feature_name = "lock the mouse";
- break;
- case QWebEnginePage::Feature::Geolocation:
- feature_name = "your location information";
- break;
- case QWebEnginePage::Feature::Notifications:
- feature_name = "send notifications";
- break;
- case QWebEnginePage::Feature::MediaAudioCapture:
- feature_name = "capture audio";
- break;
- case QWebEnginePage::Feature::MediaVideoCapture:
- feature_name = "capture video";
- break;
- case QWebEnginePage::Feature::MediaAudioVideoCapture:
- feature_name = "capture audio and video";
- break;
- case QWebEnginePage::Feature::DesktopVideoCapture:
- feature_name = "capture video from your desktop";
- break;
- case QWebEnginePage::Feature::DesktopAudioVideoCapture:
- feature_name = "capture audio and video from your desktop";
- break;
- }
-
- QMessageBox dialog(QMessageBox::Icon::Question,
- "Permission",
- "Do you want to grant permission to " +
- feature_name + "?",
- QMessageBox::StandardButton::Yes |
- QMessageBox::StandardButton::No);
- int res = dialog.exec();
+ webwindow.connect_notification([&](auto notification) {
+ tray.send_notification(std::move(notification));
+ });
- if (res == QMessageBox::Yes) {
- page.setFeaturePermission(
- origin, feature, QWebEnginePage::PermissionGrantedByUser);
- } else {
- page.setFeaturePermission(
- origin, feature, QWebEnginePage::PermissionDeniedByUser);
- }
- });
+ tray.connect_toggle([&]() { webwindow.toggle_visibility(); });
+ tray.connect_quit([&]() { webwindow.quit(); });
+ tray.connect_permission_changed(
+ [&](auto feature, auto value) { webwindow.set_feature(feature, value); });
+ tray.connect_reset_cookies([&]() { webwindow.reset_cookies(); });
- main_window.setCentralWidget(&view);
- main_window.show();
+ webwindow.show();
if (start_hidden) {
- main_window.hide();
+ webwindow.hide();
}
- app.setQuitOnLastWindowClosed(false);
return app.exec();
}
diff --git a/src/permissionmanager.cpp b/src/permissionmanager.cpp
new file mode 100644
index 0000000..0687c8a
--- /dev/null
+++ b/src/permissionmanager.cpp
@@ -0,0 +1,93 @@
+#include "permissionmanager.hpp"
+
+PermissionManager::PermissionManager(std::string path)
+ : path(path)
+{
+ if (std::filesystem::exists(this->path)) {
+ std::ifstream in(path);
+ std::string content;
+ in >> this->_lock_mouse;
+ in >> this->_location;
+ in >> this->_notification;
+ in >> this->_media_audio_capture;
+ in >> this->_media_video_capture;
+ in >> this->_desktop_video_capture;
+ in >> this->_desktop_audio_video_capture;
+ }
+}
+
+PermissionManager::~PermissionManager()
+{
+ this->save();
+}
+
+void
+PermissionManager::save()
+{
+ std::ofstream out(this->path);
+ out << this->_lock_mouse;
+ out << this->_location;
+ out << this->_notification;
+ out << this->_media_audio_capture;
+ out << this->_media_video_capture;
+ out << this->_desktop_video_capture;
+ out << this->_desktop_audio_video_capture;
+}
+
+bool
+PermissionManager::get(QWebEnginePage::Feature feature)
+{
+ switch (feature) {
+ case QWebEnginePage::Feature::MouseLock:
+ return this->_lock_mouse;
+ case QWebEnginePage::Feature::Geolocation:
+ return this->_location;
+ case QWebEnginePage::Feature::Notifications:
+ return this->_notification;
+ case QWebEnginePage::Feature::MediaAudioCapture:
+ return this->_media_audio_capture;
+ case QWebEnginePage::Feature::MediaVideoCapture:
+ return this->_media_video_capture;
+ case QWebEnginePage::Feature::MediaAudioVideoCapture:
+ return this->_media_video_capture && this->_media_audio_capture;
+ case QWebEnginePage::Feature::DesktopVideoCapture:
+ return this->_desktop_video_capture;
+ case QWebEnginePage::Feature::DesktopAudioVideoCapture:
+ return this->_desktop_audio_video_capture;
+ default:
+ /* unreachable except QWebEnginePage::Feature gets new entries */
+ return false;
+ }
+}
+
+void
+PermissionManager::set(QWebEnginePage::Feature feature, bool value)
+{
+ switch (feature) {
+ case QWebEnginePage::Feature::MouseLock:
+ this->_lock_mouse = value;
+ break;
+ case QWebEnginePage::Feature::Geolocation:
+ this->_location = value;
+ break;
+ case QWebEnginePage::Feature::Notifications:
+ this->_notification = value;
+ break;
+ case QWebEnginePage::Feature::MediaAudioCapture:
+ this->_media_audio_capture = value;
+ break;
+ case QWebEnginePage::Feature::MediaVideoCapture:
+ this->_media_video_capture = value;
+ break;
+ case QWebEnginePage::Feature::MediaAudioVideoCapture:
+ this->_media_audio_capture = value;
+ this->_media_video_capture = value;
+ break;
+ case QWebEnginePage::Feature::DesktopVideoCapture:
+ this->_desktop_video_capture = value;
+ break;
+ case QWebEnginePage::Feature::DesktopAudioVideoCapture:
+ this->_desktop_audio_video_capture = value;
+ break;
+ }
+}
diff --git a/src/permissionmanager.hpp b/src/permissionmanager.hpp
new file mode 100644
index 0000000..70c17e9
--- /dev/null
+++ b/src/permissionmanager.hpp
@@ -0,0 +1,28 @@
+#ifndef PERMISSION_MANAGER_HPP
+#define PERMISSION_MANAGER_HPP
+
+#include <QtWebEngineCore/QWebEnginePage>
+#include <filesystem>
+#include <fstream>
+
+class PermissionManager
+{
+private:
+ std::string path;
+ bool _lock_mouse = false;
+ bool _location = false;
+ bool _notification = false;
+ bool _media_audio_capture = false;
+ bool _media_video_capture = false;
+ bool _desktop_video_capture = false;
+ bool _desktop_audio_video_capture = false;
+
+public:
+ PermissionManager(std::string path);
+ ~PermissionManager();
+ void save();
+ bool get(QWebEnginePage::Feature feature);
+ void set(QWebEnginePage::Feature feature, bool value);
+};
+
+#endif
diff --git a/src/tray.cpp b/src/tray.cpp
new file mode 100644
index 0000000..c6e48a8
--- /dev/null
+++ b/src/tray.cpp
@@ -0,0 +1,136 @@
+#include "tray.hpp"
+
+Tray::Tray()
+{
+ this->app_toggle = this->menu.addAction("");
+ this->menu.addSeparator();
+ this->menu.addMenu(&this->settings)->setText("Settings");
+ this->menu.addSeparator();
+ this->quit = this->menu.addAction("Quit");
+
+ this->permissions.camera = this->settings.addAction("Allow Camera");
+ this->permissions.microphone = this->settings.addAction("Allow Microphone");
+ this->permissions.screenshare = this->settings.addAction("Allow Screenshare");
+ this->permissions.system_audio =
+ this->settings.addAction("Allow System Audio Record");
+ this->permissions.notifications =
+ this->settings.addAction("Allow Notifications");
+ this->permissions.location = this->settings.addAction("Allow Location");
+ this->permissions.lock_mouse = this->settings.addAction("Allow Lock Mouse");
+ this->settings.addSeparator();
+ this->reset_storage = this->settings.addAction("Reset Storage");
+
+ this->permissions.camera->setCheckable(true);
+ this->permissions.microphone->setCheckable(true);
+ this->permissions.screenshare->setCheckable(true);
+ this->permissions.system_audio->setCheckable(true);
+ this->permissions.notifications->setCheckable(true);
+ this->permissions.location->setCheckable(true);
+ this->permissions.lock_mouse->setCheckable(true);
+
+ this->connect(this,
+ &QSystemTrayIcon::activated,
+ [&](QSystemTrayIcon::ActivationReason reason) {
+ if (reason == QSystemTrayIcon::ActivationReason::Trigger) {
+ this->toggle_signal();
+ }
+ });
+
+ this->menu.connect(&this->menu, &QMenu::triggered, [&](QAction *action) {
+ if (action == this->app_toggle) {
+ this->toggle_signal();
+ } else if (action == quit) {
+ this->quit_signal();
+ }
+ });
+
+ this->settings.connect(
+ &this->settings, &QMenu::triggered, [&](QAction *action) {
+ if (action == this->reset_storage) {
+ this->reset_cookies_signal();
+
+ } else if (action == this->permissions.camera) {
+ this->permission_changed_signal(
+ QWebEnginePage::Feature::MediaVideoCapture,
+ this->permissions.camera->isChecked());
+
+ } else if (action == this->permissions.microphone) {
+ this->permission_changed_signal(
+ QWebEnginePage::Feature::MediaAudioCapture,
+ this->permissions.microphone->isChecked());
+
+ } else if (action == this->permissions.system_audio) {
+ this->permission_changed_signal(
+ QWebEnginePage::Feature::DesktopAudioVideoCapture,
+ this->permissions.system_audio->isChecked());
+
+ } else if (action == this->permissions.screenshare) {
+ this->permission_changed_signal(
+ QWebEnginePage::Feature::DesktopVideoCapture,
+ this->permissions.screenshare->isChecked());
+
+ } else if (action == this->permissions.notifications) {
+ this->permission_changed_signal(
+ QWebEnginePage::Feature::Notifications,
+ this->permissions.notifications->isChecked());
+
+ } else if (action == this->permissions.location) {
+ this->permission_changed_signal(
+ QWebEnginePage::Feature::Geolocation,
+ this->permissions.location->isChecked());
+
+ } else if (action == this->permissions.lock_mouse) {
+ this->permission_changed_signal(
+ QWebEnginePage::Feature::MouseLock,
+ this->permissions.lock_mouse->isChecked());
+ }
+ });
+
+ this->setContextMenu(&this->menu);
+}
+
+void
+Tray::connect_toggle(std::function<void()> fn)
+{
+ this->toggle_signal = fn;
+}
+
+void
+Tray::connect_quit(std::function<void()> fn)
+{
+ this->quit_signal = fn;
+}
+
+void
+Tray::connect_reset_cookies(std::function<void()> fn)
+{
+ this->reset_cookies_signal = fn;
+}
+
+void
+Tray::connect_permission_changed(
+ std::function<void(QWebEnginePage::Feature, bool)> fn)
+{
+ this->permission_changed_signal = fn;
+}
+
+void
+Tray::set_title(const QString &title)
+{
+ this->setToolTip(title);
+ this->app_toggle->setText(title);
+}
+
+void
+Tray::send_notification(std::unique_ptr<QWebEngineNotification> notification)
+{
+ this->showMessage(notification->title(),
+ notification->message(),
+ QSystemTrayIcon::MessageIcon::Information,
+ 2000);
+}
+
+void
+Tray::set_permission(QWebEnginePage::Feature feature, bool value)
+{
+}
diff --git a/src/tray.hpp b/src/tray.hpp
new file mode 100644
index 0000000..427cdc8
--- /dev/null
+++ b/src/tray.hpp
@@ -0,0 +1,46 @@
+#ifndef TRAY_HPP
+#define TRAY_HPP
+
+#include <QtWidgets/QMenu>
+#include <QtWidgets/QSystemTrayIcon>
+
+#include "webwindow.hpp"
+
+class Tray : public QSystemTrayIcon
+{
+private:
+ QMenu menu;
+ QMenu settings;
+ QAction *app_toggle;
+ QAction *quit;
+
+ struct
+ {
+ QAction *camera;
+ QAction *microphone;
+ QAction *screenshare;
+ QAction *system_audio;
+ QAction *notifications;
+ QAction *location;
+ QAction *lock_mouse;
+ } permissions;
+
+ QAction *reset_storage;
+ std::function<void()> toggle_signal;
+ std::function<void()> quit_signal;
+ std::function<void()> reset_cookies_signal;
+ std::function<void(QWebEnginePage::Feature, bool)> permission_changed_signal;
+
+public:
+ Tray();
+ void connect_toggle(std::function<void()> fn);
+ void connect_quit(std::function<void()> fn);
+ void connect_reset_cookies(std::function<void()> fn);
+ void connect_permission_changed(
+ std::function<void(QWebEnginePage::Feature, bool)> fn);
+ void set_title(const QString &title);
+ void send_notification(std::unique_ptr<QWebEngineNotification> notification);
+ void set_permission(QWebEnginePage::Feature feature, bool value);
+};
+
+#endif
diff --git a/src/webwindow.cpp b/src/webwindow.cpp
new file mode 100644
index 0000000..36e1818
--- /dev/null
+++ b/src/webwindow.cpp
@@ -0,0 +1,114 @@
+#include <QtGui/QCloseEvent>
+#include <QtWebEngineCore/QWebEngineCookieStore>
+
+#include "permissionmanager.hpp"
+#include "webwindow.hpp"
+#include <QtWidgets/QApplication>
+#include <iostream>
+
+WebWindow::WebWindow(const QString &url)
+ : QMainWindow()
+ , _profile(QUrl(url).host())
+ , _page(&_profile)
+ , _permissions((QUrl(url).host() + "/permissions.state").toStdString())
+{
+ this->web_configure();
+
+ this->_profile.setPersistentCookiesPolicy(QWebEngineProfile::ForcePersistentCookies);
+
+ this->_view.setPage(&this->_page);
+ this->_view.setUrl(url);
+
+ this->setCentralWidget(&this->_view);
+}
+
+void
+WebWindow::web_configure()
+{
+ this->_page.settings()->setAttribute(QWebEngineSettings::ScreenCaptureEnabled,
+ true);
+
+ this->_page.settings()->setAttribute(
+ QWebEngineSettings::WebRTCPublicInterfacesOnly, false);
+
+ this->_page.settings()->setAttribute(
+ QWebEngineSettings::ScrollAnimatorEnabled, false);
+
+ this->_profile.setPushServiceEnabled(true);
+
+ this->_page.connect(&this->_page,
+ &QWebEnginePage::featurePermissionRequested,
+ [&](const QUrl origin, QWebEnginePage::Feature feature) {
+ this->permission_requested(origin, feature);
+ });
+}
+
+void
+WebWindow::permission_requested(const QUrl origin,
+ QWebEnginePage::Feature feature)
+{
+ if (this->_permissions.get(feature)) {
+ this->_page.setFeaturePermission(
+ origin, feature, QWebEnginePage::PermissionGrantedByUser);
+ } else {
+ this->_page.setFeaturePermission(
+ origin, feature, QWebEnginePage::PermissionDeniedByUser);
+ }
+ this->_page.setFeaturePermission(
+ origin, feature, QWebEnginePage::PermissionUnknown);
+}
+
+void
+WebWindow::closeEvent(QCloseEvent *event)
+{
+ this->hide();
+ event->ignore();
+}
+
+void
+WebWindow::connect_icon_changed(std::function<void(const QIcon)> fn)
+{
+ this->_view.connect(&this->_view, &QWebEngineView::iconChanged, fn);
+}
+
+void
+WebWindow::connect_notification(
+ std::function<void(std::unique_ptr<QWebEngineNotification>)> fn)
+{
+ this->_profile.setNotificationPresenter(fn);
+}
+
+void
+WebWindow::connect_title_changed(std::function<void(const QString)> fn)
+{
+ this->_view.connect(&this->_view, &QWebEngineView::titleChanged, fn);
+}
+
+void
+WebWindow::set_feature(QWebEnginePage::Feature feature, bool value)
+{
+ this->_permissions.set(feature, value);
+}
+
+void
+WebWindow::reset_cookies()
+{
+ this->_profile.cookieStore()->deleteAllCookies();
+ this->_profile.cookieStore()->loadAllCookies();
+ this->_profile.clearHttpCache();
+ this->_profile.clearAllVisitedLinks();
+ this->_profile.clientCertificateStore();
+ this->_view.reload();
+}
+
+void
+WebWindow::toggle_visibility()
+{
+ this->setVisible(!this->isVisible());
+}
+
+void
+WebWindow::quit()
+{
+ QApplication::instance()->quit();
+}
diff --git a/src/webwindow.hpp b/src/webwindow.hpp
new file mode 100644
index 0000000..49b2394
--- /dev/null
+++ b/src/webwindow.hpp
@@ -0,0 +1,37 @@
+#ifndef MAINWINDOW_HPP
+#define MAINWINDOW_HPP
+
+#include "permissionmanager.hpp"
+#include <QtCore/QUrl>
+#include <QtWebEngineCore/QWebEngineNotification>
+#include <QtWebEngineCore/QWebEnginePage>
+#include <QtWebEngineCore/QWebEngineProfile>
+#include <QtWebEngineCore/QWebEngineSettings>
+#include <QtWebEngineWidgets/QWebEngineView>
+#include <QtWidgets/QMainWindow>
+#include <functional>
+
+class WebWindow : public QMainWindow
+{
+private:
+ QWebEngineProfile _profile;
+ QWebEnginePage _page;
+ QWebEngineView _view;
+ PermissionManager _permissions;
+
+ void web_configure();
+ void permission_requested(const QUrl origin, QWebEnginePage::Feature feature);
+ void closeEvent(QCloseEvent *event);
+
+public:
+ WebWindow(const QString &url);
+ void connect_icon_changed(std::function<void(const QIcon)> fn);
+ void connect_title_changed(std::function<void(const QString)> fn);
+ void connect_notification(std::function<void(std::unique_ptr<QWebEngineNotification>)> fn);
+ void set_feature(QWebEnginePage::Feature feature, bool value);
+ void reset_cookies();
+ void toggle_visibility();
+ void quit();
+};
+
+#endif