mirror of
https://github.com/hyprwm/xdg-desktop-portal-hyprland.git
synced 2024-11-21 14:15:58 +01:00
core: move to CProcess from hyprutils
this enhances security, avoids calling the shell when invoking the picker
This commit is contained in:
parent
09b23cef06
commit
8070f36dee
5 changed files with 52 additions and 36 deletions
|
@ -64,7 +64,7 @@ pkg_check_modules(
|
||||||
libdrm
|
libdrm
|
||||||
gbm
|
gbm
|
||||||
hyprlang>=0.2.0
|
hyprlang>=0.2.0
|
||||||
hyprutils
|
hyprutils>=0.2.6
|
||||||
hyprwayland-scanner>=0.4.2)
|
hyprwayland-scanner>=0.4.2)
|
||||||
|
|
||||||
# check whether we can find sdbus-c++ through pkg-config
|
# check whether we can find sdbus-c++ through pkg-config
|
||||||
|
|
|
@ -17,6 +17,13 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
find_package(QT NAMES Qt6 REQUIRED COMPONENTS Widgets)
|
find_package(QT NAMES Qt6 REQUIRED COMPONENTS Widgets)
|
||||||
find_package(Qt6 REQUIRED COMPONENTS Widgets)
|
find_package(Qt6 REQUIRED COMPONENTS Widgets)
|
||||||
|
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
pkg_check_modules(
|
||||||
|
deps
|
||||||
|
REQUIRED
|
||||||
|
IMPORTED_TARGET
|
||||||
|
hyprutils>=0.2.6)
|
||||||
|
|
||||||
set(PROJECT_SOURCES main.cpp mainpicker.cpp mainpicker.h mainpicker.ui
|
set(PROJECT_SOURCES main.cpp mainpicker.cpp mainpicker.h mainpicker.ui
|
||||||
elidedbutton.h elidedbutton.cpp)
|
elidedbutton.h elidedbutton.cpp)
|
||||||
|
|
||||||
|
@ -38,7 +45,7 @@ else()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries(hyprland-share-picker
|
target_link_libraries(hyprland-share-picker
|
||||||
PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
|
PRIVATE Qt${QT_VERSION_MAJOR}::Widgets PkgConfig::deps)
|
||||||
|
|
||||||
set_target_properties(
|
set_target_properties(
|
||||||
hyprland-share-picker
|
hyprland-share-picker
|
||||||
|
|
|
@ -15,21 +15,20 @@
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <hyprutils/os/Process.hpp>
|
||||||
|
using namespace Hyprutils::OS;
|
||||||
|
|
||||||
#include "mainpicker.h"
|
#include "mainpicker.h"
|
||||||
#include "elidedbutton.h"
|
#include "elidedbutton.h"
|
||||||
|
|
||||||
std::string execAndGet(const char* cmd) {
|
std::string execAndGet(const char* cmd) {
|
||||||
std::array<char, 128> buffer;
|
std::string command = cmd + std::string{" 2>&1"};
|
||||||
std::string result;
|
CProcess proc("/bin/sh", {"-c", cmd});
|
||||||
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
|
|
||||||
if (!pipe) {
|
if (!proc.runSync())
|
||||||
throw std::runtime_error("popen() failed!");
|
return "error";
|
||||||
}
|
|
||||||
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
|
return proc.stdOut();
|
||||||
result += buffer.data();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QApplication* pickerPtr = nullptr;
|
QApplication* pickerPtr = nullptr;
|
||||||
|
|
|
@ -8,20 +8,17 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
std::string execAndGet(const char* cmd) {
|
#include <hyprutils/os/Process.hpp>
|
||||||
Debug::log(LOG, "execAndGet: {}", cmd);
|
using namespace Hyprutils::OS;
|
||||||
|
|
||||||
std::array<char, 128> buffer;
|
std::string execAndGet(const char* cmd) {
|
||||||
std::string result;
|
std::string command = cmd + std::string{" 2>&1"};
|
||||||
const std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
|
CProcess proc("/bin/sh", {"-c", cmd});
|
||||||
if (!pipe) {
|
|
||||||
Debug::log(ERR, "execAndGet: failed in pipe");
|
if (!proc.runSync())
|
||||||
return "";
|
return "error";
|
||||||
}
|
|
||||||
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
|
return proc.stdOut();
|
||||||
result += buffer.data();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void addHyprlandNotification(const std::string& icon, float timeMs, const std::string& color, const std::string& message) {
|
void addHyprlandNotification(const std::string& icon, float timeMs, const std::string& color, const std::string& message) {
|
||||||
|
|
|
@ -9,10 +9,15 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include <hyprutils/os/Process.hpp>
|
||||||
|
using namespace Hyprutils::OS;
|
||||||
|
|
||||||
std::string sanitizeNameForWindowList(const std::string& name) {
|
std::string sanitizeNameForWindowList(const std::string& name) {
|
||||||
std::string result = name;
|
std::string result = name;
|
||||||
std::replace(result.begin(), result.end(), '\'', ' ');
|
std::replace(result.begin(), result.end(), '\'', ' ');
|
||||||
std::replace(result.begin(), result.end(), '\"', ' ');
|
std::replace(result.begin(), result.end(), '\"', ' ');
|
||||||
|
std::replace(result.begin(), result.end(), '$', ' ');
|
||||||
|
std::replace(result.begin(), result.end(), '`', ' ');
|
||||||
for (size_t i = 1; i < result.size(); ++i) {
|
for (size_t i = 1; i < result.size(); ++i) {
|
||||||
if (result[i - 1] == '>' && result[i] == ']')
|
if (result[i - 1] == '>' && result[i] == ']')
|
||||||
result[i] = ' ';
|
result[i] = ' ';
|
||||||
|
@ -43,19 +48,28 @@ SSelectionData promptForScreencopySelection() {
|
||||||
static auto* const* PALLOWTOKENBYDEFAULT =
|
static auto* const* PALLOWTOKENBYDEFAULT =
|
||||||
(Hyprlang::INT* const*)g_pPortalManager->m_sConfig.config->getConfigValuePtr("screencopy:allow_token_by_default")->getDataStaticPtr();
|
(Hyprlang::INT* const*)g_pPortalManager->m_sConfig.config->getConfigValuePtr("screencopy:allow_token_by_default")->getDataStaticPtr();
|
||||||
|
|
||||||
// DANGEROUS: we are sending a list of app IDs and titles via env. Make sure it's in 'singlequotes' to avoid something like $(rm -rf /)
|
std::vector<std::string> args;
|
||||||
// TODO: this is dumb, use a pipe or something.
|
if (**PALLOWTOKENBYDEFAULT)
|
||||||
std::string cmd =
|
args.emplace_back("--allow-token");
|
||||||
std::format("WAYLAND_DISPLAY='{}' QT_QPA_PLATFORM='wayland' XCURSOR_SIZE='{}' HYPRLAND_INSTANCE_SIGNATURE='{}' XDPH_WINDOW_SHARING_LIST='{}' hyprland-share-picker{} 2>&1",
|
|
||||||
WAYLAND_DISPLAY ? WAYLAND_DISPLAY : "", XCURSOR_SIZE ? XCURSOR_SIZE : "24", HYPRLAND_INSTANCE_SIGNATURE ? HYPRLAND_INSTANCE_SIGNATURE : "0", buildWindowList(),
|
|
||||||
(**PALLOWTOKENBYDEFAULT ? " --allow-token" : ""));
|
|
||||||
|
|
||||||
const auto RETVAL = execAndGet(cmd.c_str());
|
CProcess proc("hyprland-share-picker", args);
|
||||||
|
proc.addEnv("WAYLAND_DISPLAY", WAYLAND_DISPLAY ? WAYLAND_DISPLAY : "");
|
||||||
|
proc.addEnv("QT_QPA_PLATFORM", "wayland");
|
||||||
|
proc.addEnv("XCURSOR_SIZE", XCURSOR_SIZE ? XCURSOR_SIZE : "24");
|
||||||
|
proc.addEnv("HYPRLAND_INSTANCE_SIGNATURE", HYPRLAND_INSTANCE_SIGNATURE ? HYPRLAND_INSTANCE_SIGNATURE : "0");
|
||||||
|
proc.addEnv("XDPH_WINDOW_SHARING_LIST", buildWindowList()); // buildWindowList will sanitize any shell stuff in case the picker (qt) does something funky? It shouldn't.
|
||||||
|
|
||||||
|
if (!proc.runSync())
|
||||||
|
return data;
|
||||||
|
|
||||||
|
const auto RETVAL = proc.stdOut();
|
||||||
|
const auto RETVALERR = proc.stdErr();
|
||||||
|
|
||||||
if (!RETVAL.contains("[SELECTION]")) {
|
if (!RETVAL.contains("[SELECTION]")) {
|
||||||
// failed
|
// failed
|
||||||
|
constexpr const char* QPA_ERR = "qt.qpa.plugin: Could not find the Qt platform plugin";
|
||||||
|
|
||||||
if (RETVAL.contains("qt.qpa.plugin: Could not find the Qt platform plugin")) {
|
if (RETVAL.contains(QPA_ERR) || RETVALERR.contains(QPA_ERR)) {
|
||||||
// prompt the user to install qt5-wayland and qt6-wayland
|
// prompt the user to install qt5-wayland and qt6-wayland
|
||||||
addHyprlandNotification("3", 7000, "0", "[xdph] Could not open the picker: qt5-wayland or qt6-wayland doesn't seem to be installed.");
|
addHyprlandNotification("3", 7000, "0", "[xdph] Could not open the picker: qt5-wayland or qt6-wayland doesn't seem to be installed.");
|
||||||
}
|
}
|
||||||
|
@ -71,12 +85,11 @@ SSelectionData promptForScreencopySelection() {
|
||||||
const auto SEL = SELECTION.substr(SELECTION.find_first_of('/') + 1);
|
const auto SEL = SELECTION.substr(SELECTION.find_first_of('/') + 1);
|
||||||
|
|
||||||
for (auto& flag : FLAGS) {
|
for (auto& flag : FLAGS) {
|
||||||
if (flag == 'r') {
|
if (flag == 'r')
|
||||||
data.allowToken = true;
|
data.allowToken = true;
|
||||||
} else {
|
else
|
||||||
Debug::log(LOG, "[screencopy] unknown flag from share-picker: {}", flag);
|
Debug::log(LOG, "[screencopy] unknown flag from share-picker: {}", flag);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (SEL.find("screen:") == 0) {
|
if (SEL.find("screen:") == 0) {
|
||||||
data.type = TYPE_OUTPUT;
|
data.type = TYPE_OUTPUT;
|
||||||
|
|
Loading…
Reference in a new issue