tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

xdg_desktop_portal_utils.cc (7437B)


      1 /*
      2 *  Copyright 2022 The WebRTC project authors. All Rights Reserved.
      3 *
      4 *  Use of this source code is governed by a BSD-style license
      5 *  that can be found in the LICENSE file in the root of the source
      6 *  tree. An additional intellectual property rights grant can be found
      7 *  in the file PATENTS.  All contributing project authors may
      8 *  be found in the AUTHORS file in the root of the source tree.
      9 */
     10 #include "modules/portal/xdg_desktop_portal_utils.h"
     11 
     12 #include <cstdint>
     13 #include <string>
     14 #include <vector>
     15 
     16 #include "absl/strings/str_replace.h"
     17 #include "absl/strings/string_view.h"
     18 #include "modules/portal/portal_request_response.h"
     19 #include "modules/portal/scoped_glib.h"
     20 #include "rtc_base/logging.h"
     21 #include "rtc_base/strings/str_join.h"
     22 
     23 namespace webrtc {
     24 namespace xdg_portal {
     25 
     26 std::string RequestResponseToString(RequestResponse request) {
     27  switch (request) {
     28    case RequestResponse::kUnknown:
     29      return "kUnknown";
     30    case RequestResponse::kSuccess:
     31      return "kSuccess";
     32    case RequestResponse::kUserCancelled:
     33      return "kUserCancelled";
     34    case RequestResponse::kError:
     35      return "kError";
     36    default:
     37      return "Uknown";
     38  }
     39 }
     40 
     41 RequestResponse RequestResponseFromPortalResponse(uint32_t portal_response) {
     42  // See:
     43  //  https://docs.flatpak.org/en/latest/portal-api-reference.html#gdbus-signal-org-freedesktop-portal-Request.Response
     44  switch (portal_response) {
     45    case 0:
     46      return RequestResponse::kSuccess;
     47    case 1:
     48      return RequestResponse::kUserCancelled;
     49    case 2:
     50      return RequestResponse::kError;
     51    default:
     52      return RequestResponse::kUnknown;
     53  }
     54 }
     55 
     56 std::string PrepareSignalHandle(absl::string_view token,
     57                                GDBusConnection* connection) {
     58  const char* unique_name = g_dbus_connection_get_unique_name(connection);
     59  if (unique_name == nullptr || *unique_name == '\0') {
     60    return std::string();
     61  }
     62 
     63  absl::string_view unique_name_sv = unique_name;
     64  if (!unique_name_sv.empty()) {
     65    unique_name_sv.remove_prefix(1);
     66  }
     67 
     68  std::string sender = absl::StrReplaceAll(unique_name_sv, {{".", "_"}});
     69  std::vector<absl::string_view> parts = {kDesktopRequestObjectPath, sender,
     70                                          token};
     71  return webrtc::StrJoin(parts, "/");
     72 }
     73 
     74 uint32_t SetupRequestResponseSignal(absl::string_view object_path,
     75                                    const GDBusSignalCallback callback,
     76                                    gpointer user_data,
     77                                    GDBusConnection* connection) {
     78  return g_dbus_connection_signal_subscribe(
     79      connection, kDesktopBusName, kRequestInterfaceName, "Response",
     80      std::string(object_path).c_str(), /*arg0=*/nullptr,
     81      G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE, callback, user_data,
     82      /*user_data_free_func=*/nullptr);
     83 }
     84 
     85 void RequestSessionProxy(absl::string_view interface_name,
     86                         const ProxyRequestCallback proxy_request_callback,
     87                         GCancellable* cancellable,
     88                         gpointer user_data) {
     89  g_dbus_proxy_new_for_bus(
     90      G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, /*info=*/nullptr,
     91      kDesktopBusName, kDesktopObjectPath, std::string(interface_name).c_str(),
     92      cancellable,
     93      reinterpret_cast<GAsyncReadyCallback>(proxy_request_callback), user_data);
     94 }
     95 
     96 void SetupSessionRequestHandlers(
     97    absl::string_view portal_prefix,
     98    const SessionRequestCallback session_request_callback,
     99    const SessionRequestResponseSignalHandler request_response_signale_handler,
    100    GDBusConnection* connection,
    101    GDBusProxy* proxy,
    102    GCancellable* cancellable,
    103    std::string& portal_handle,
    104    guint& session_request_signal_id,
    105    gpointer user_data) {
    106  GVariantBuilder builder;
    107  Scoped<char> variant_string;
    108 
    109  g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
    110  variant_string =
    111      g_strdup_printf("%.*s_session%d", static_cast<int>(portal_prefix.size()),
    112                      portal_prefix.data(), g_random_int_range(0, G_MAXINT));
    113  g_variant_builder_add(&builder, "{sv}", "session_handle_token",
    114                        g_variant_new_string(variant_string.get()));
    115 
    116  variant_string =
    117      g_strdup_printf("%.*s_%d", static_cast<int>(portal_prefix.size()),
    118                      portal_prefix.data(), g_random_int_range(0, G_MAXINT));
    119  g_variant_builder_add(&builder, "{sv}", "handle_token",
    120                        g_variant_new_string(variant_string.get()));
    121 
    122  portal_handle = PrepareSignalHandle(variant_string.get(), connection);
    123  session_request_signal_id = SetupRequestResponseSignal(
    124      portal_handle.c_str(), request_response_signale_handler, user_data,
    125      connection);
    126 
    127  RTC_LOG(LS_INFO) << "Desktop session requested.";
    128  g_dbus_proxy_call(
    129      proxy, "CreateSession", g_variant_new("(a{sv})", &builder),
    130      G_DBUS_CALL_FLAGS_NONE, /*timeout=*/-1, cancellable,
    131      reinterpret_cast<GAsyncReadyCallback>(session_request_callback),
    132      user_data);
    133 }
    134 
    135 void StartSessionRequest(
    136    absl::string_view prefix,
    137    absl::string_view session_handle,
    138    const StartRequestResponseSignalHandler signal_handler,
    139    const SessionStartRequestedHandler session_started_handler,
    140    GDBusProxy* proxy,
    141    GDBusConnection* connection,
    142    GCancellable* cancellable,
    143    guint& start_request_signal_id,
    144    std::string& start_handle,
    145    gpointer user_data) {
    146  GVariantBuilder builder;
    147  Scoped<char> variant_string;
    148 
    149  g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
    150  variant_string =
    151      g_strdup_printf("%.*s%d", static_cast<int>(prefix.size()), prefix.data(),
    152                      g_random_int_range(0, G_MAXINT));
    153  g_variant_builder_add(&builder, "{sv}", "handle_token",
    154                        g_variant_new_string(variant_string.get()));
    155 
    156  start_handle = PrepareSignalHandle(variant_string.get(), connection);
    157  start_request_signal_id = SetupRequestResponseSignal(
    158      start_handle.c_str(), signal_handler, user_data, connection);
    159 
    160  // "Identifier for the application window", this is Wayland, so not "x11:...".
    161  const char parent_window[] = "";
    162 
    163  RTC_LOG(LS_INFO) << "Starting the portal session.";
    164  g_dbus_proxy_call(
    165      proxy, "Start",
    166      g_variant_new("(osa{sv})", std::string(session_handle).c_str(),
    167                    parent_window, &builder),
    168      G_DBUS_CALL_FLAGS_NONE, /*timeout=*/-1, cancellable,
    169      reinterpret_cast<GAsyncReadyCallback>(session_started_handler),
    170      user_data);
    171 }
    172 
    173 void TearDownSession(absl::string_view session_handle,
    174                     GDBusProxy* proxy,
    175                     GCancellable* cancellable,
    176                     GDBusConnection* connection) {
    177  if (!session_handle.empty()) {
    178    Scoped<GDBusMessage> message(g_dbus_message_new_method_call(
    179        kDesktopBusName, std::string(session_handle).c_str(),
    180        kSessionInterfaceName, "Close"));
    181    if (message.get()) {
    182      Scoped<GError> error;
    183      g_dbus_connection_send_message(connection, message.get(),
    184                                     G_DBUS_SEND_MESSAGE_FLAGS_NONE,
    185                                     /*out_serial=*/nullptr, error.receive());
    186      if (error.get()) {
    187        RTC_LOG(LS_ERROR) << "Failed to close the session: " << error->message;
    188      }
    189    }
    190  }
    191 
    192  if (cancellable) {
    193    g_cancellable_cancel(cancellable);
    194    g_object_unref(cancellable);
    195  }
    196 
    197  if (proxy) {
    198    g_object_unref(proxy);
    199  }
    200 }
    201 
    202 }  // namespace xdg_portal
    203 }  // namespace webrtc