From 8429629a869bb28b46d26d36240aa482b27a7f00 Mon Sep 17 00:00:00 2001 From: Isaiah Inuwa Date: Fri, 26 Jun 2026 17:38:59 -0500 Subject: [PATCH 1/3] xdp: wip: Enable experimental portals Wires up formatting to allow merging portals in experimental status, requiring a feature flag, supplied by a comma-separated list of feature flag names in the environment variable XDG_DESKTOP_PORTAL_ENABLE_EXPERIMENTAL. Documentation files for exported interfaces also get an experimental icon in the documentation site. This will eventually be split into a separate PR. --- data/meson.build | 14 +++++++++++++- desktop-portal/meson.build | 18 +++++++++++++++++- desktop-portal/xdp-context.c | 11 +++++++++++ doc/fix-rst-dbus.py | 10 +++++++++- doc/meson.build | 4 ++-- shared/xdp-types.h | 3 +++ 6 files changed, 55 insertions(+), 5 deletions(-) diff --git a/data/meson.build b/data/meson.build index af8d30b0b..565bf2348 100644 --- a/data/meson.build +++ b/data/meson.build @@ -42,6 +42,9 @@ portal_sources = files( 'org.freedesktop.portal.Wallpaper.xml', ) +portal_experimental_sources = files( +) + portal_host_sources = files( 'org.freedesktop.host.portal.Registry.xml', ) @@ -73,10 +76,19 @@ portal_impl_sources = files( 'org.freedesktop.impl.portal.Wallpaper.xml', ) +portal_impl_experimental_sources = files( +) + background_monitor_sources = files( 'org.freedesktop.background.Monitor.xml', ) -install_data([portal_sources, portal_host_sources, portal_impl_sources], +install_data([ + portal_sources, + portal_experimental_sources, + portal_host_sources, + portal_impl_sources, + portal_impl_experimental_sources, + ], install_dir: datadir / 'dbus-1' / 'interfaces', ) diff --git a/desktop-portal/meson.build b/desktop-portal/meson.build index 120001338..ff9789ff2 100644 --- a/desktop-portal/meson.build +++ b/desktop-portal/meson.build @@ -13,6 +13,13 @@ portal_built_sources = gnome.gdbus_codegen( docbook: 'portal', extra_args: gdbus_codegen_extra_args, ) +portal_experimental_built_sources = gnome.gdbus_codegen( + 'xdp-experimental-dbus', + sources: portal_experimental_sources, + interface_prefix: 'org.freedesktop.portal.experimental', + namespace: 'XdpDbusExperimental', + docbook: 'portal', +) host_built_sources = gnome.gdbus_codegen( 'xdp-host-dbus', sources: portal_host_sources, @@ -29,6 +36,14 @@ impl_built_sources = gnome.gdbus_codegen( docbook: 'portal', extra_args: gdbus_codegen_extra_args, ) +impl_experimental_built_sources = gnome.gdbus_codegen( + 'xdp-impl-experimental-dbus', + sources: portal_impl_experimental_sources, + interface_prefix: 'org.freedesktop.impl.portal.experimental', + namespace: 'XdpDbusExperimentalImpl', + docbook: 'portal', +) +) background_monitor_built_sources = gnome.gdbus_codegen( 'xdp-background-dbus', sources: background_monitor_sources, @@ -50,7 +65,7 @@ else endif xdp_method_info_built_sources = configure_file( - command: [find_program('generate-method-info.py'), portal_sources], + command: [find_program('generate-method-info.py'), portal_sources, portal_experimental_sources], capture: true, output: 'xdp-method-info-generated.c', ) @@ -105,6 +120,7 @@ xdg_desktop_portal_sources += [ xdp_utils_sources, xdp_method_info_sources, portal_built_sources, + portal_experimental_built_sources, host_built_sources, impl_built_sources, background_monitor_built_sources, diff --git a/desktop-portal/xdp-context.c b/desktop-portal/xdp-context.c index 50b305de4..454197716 100644 --- a/desktop-portal/xdp-context.c +++ b/desktop-portal/xdp-context.c @@ -484,6 +484,17 @@ xdp_context_register (XdpContext *context, #endif init_registry (context); + // Experimental feature flags + char *experimental_flag_env = + getenv ("XDG_DESKTOP_PORTAL_ENABLE_EXPERIMENTAL"); + if (experimental_flag_env != NULL) + { + gchar **flags = g_strsplit (experimental_flag_env, ",", -1); + for (gint i = 0; flags[i] != NULL; i++) + { + } + } + return TRUE; } diff --git a/doc/fix-rst-dbus.py b/doc/fix-rst-dbus.py index 731384679..ed39bee95 100755 --- a/doc/fix-rst-dbus.py +++ b/doc/fix-rst-dbus.py @@ -87,7 +87,15 @@ def split_sections(lines, output_prefix): def adjust_title(lines): title = lines[3].strip() - if title.startswith("org.freedesktop.portal."): + if title.startswith("org.freedesktop.portal.experimental."): + adjusted_title = ( + title.replace("org.freedesktop.portal.experimental.", "") + " 🧪" + ) + elif title.startswith("org.freedesktop.impl.portal.experimental."): + adjusted_title = ( + title.replace("org.freedesktop.impl.portal.experimental.", "") + " 🧪" + ) + elif title.startswith("org.freedesktop.portal."): adjusted_title = title.replace("org.freedesktop.portal.", "") elif title.startswith("org.freedesktop.impl.portal"): adjusted_title = title.replace("org.freedesktop.impl.portal.", "") diff --git a/doc/meson.build b/doc/meson.build index 4a94d984a..5a46b9c85 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -40,13 +40,13 @@ endif if build_documentation # Gather the XML files under data all_interfaces_xml = [] - foreach i: portal_sources + foreach i: portal_sources + portal_experimental_sources all_interfaces_xml += i endforeach foreach i: portal_host_sources all_interfaces_xml += i endforeach - foreach i: portal_impl_sources + foreach i: portal_impl_sources + portal_impl_experimental_sources all_interfaces_xml += i endforeach foreach i: background_monitor_sources diff --git a/shared/xdp-types.h b/shared/xdp-types.h index 8a5709709..fca32ed01 100644 --- a/shared/xdp-types.h +++ b/shared/xdp-types.h @@ -30,6 +30,9 @@ typedef struct _XdpDbusImplAccess XdpDbusImplAccess; #define DESKTOP_DBUS_IFACE "org.freedesktop.portal" #define DESKTOP_DBUS_IMPL_IFACE "org.freedesktop.impl.portal" #define DESKTOP_DBUS_PATH "/org/freedesktop/portal/desktop" +#define DESKTOP_EXPERIMENTAL_DBUS_IFACE DESKTOP_DBUS_IFACE ".experimental" +#define DESKTOP_EXPERIMENTAL_DBUS_IMPL_IFACE \ + DESKTOP_DBUS_IMPL_IFACE ".experimental" #define ACCESS_DBUS_IMPL_IFACE DESKTOP_DBUS_IMPL_IFACE ".Access" From 60253e9225f4bf042eb9f64b75be1eee9d8a908a Mon Sep 17 00:00:00 2001 From: Isaiah Inuwa Date: Fri, 26 Jun 2026 17:38:59 -0500 Subject: [PATCH 2/3] xdp: Enable "handlers" for delegating frontend requests In the upcoming credential portal, we will be delegating much of the frontend request processing to an external service on the host. We are calling this a "handler". This patch allows code generation via gdbus-codegen for handlers. These handler interfaces are not user-facing, whether for app or DE developers; it is an internal dependency. Because of that, they should not appear in documentation. --- data/meson.build | 2 ++ desktop-portal/meson.build | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/data/meson.build b/data/meson.build index 565bf2348..682da9223 100644 --- a/data/meson.build +++ b/data/meson.build @@ -78,6 +78,8 @@ portal_impl_sources = files( portal_impl_experimental_sources = files( ) +portal_handler_experimental_sources = files( +) background_monitor_sources = files( 'org.freedesktop.background.Monitor.xml', diff --git a/desktop-portal/meson.build b/desktop-portal/meson.build index ff9789ff2..9b6d1256e 100644 --- a/desktop-portal/meson.build +++ b/desktop-portal/meson.build @@ -43,6 +43,12 @@ impl_experimental_built_sources = gnome.gdbus_codegen( namespace: 'XdpDbusExperimentalImpl', docbook: 'portal', ) +handler_experimental_built_sources = gnome.gdbus_codegen( + 'xdp-experimental-handler-dbus', + sources: portal_handler_experimental_sources, + interface_prefix: 'org.freedesktop.handler.portal.experimental', + namespace: 'XdpDbusExperimentalHandler', + docbook: 'portal', ) background_monitor_built_sources = gnome.gdbus_codegen( 'xdp-background-dbus', @@ -123,6 +129,7 @@ xdg_desktop_portal_sources += [ portal_experimental_built_sources, host_built_sources, impl_built_sources, + handler_experimental_built_sources, background_monitor_built_sources, geoclue_built_sources, ] From f6884022d1405a6bac3b17dd9bdfeb6c57db2233 Mon Sep 17 00:00:00 2001 From: Isaiah Inuwa Date: Fri, 26 Jun 2026 17:38:59 -0500 Subject: [PATCH 3/3] credential: Introduce experimental Credential portal The Credential portal allows applications to retrieve credentials for web services. It is highly inspired by W3C APIs including the Web Credential Management API and WebAuthn. The bulk of the processing is deferred to credentialsd. In this current form, xdg-desktop-portal is responsible for determining the App ID of the caller, and credentialsd is responsible for granting access to specific origins for that App ID, as well as interacting with the backend for user interaction. In future versions, xdg-desktop-portal will take responsibility for more permissions checking via entitlements and will send requests to the backend, acting as a proxy for credentialsd. --- data/meson.build | 3 + ...handler.portal.experimental.Credential.xml | 152 ++++++ ...op.impl.portal.experimental.Credential.xml | 455 ++++++++++++++++++ ...desktop.portal.experimental.Credential.xml | 273 +++++++++++ desktop-portal/credential.c | 383 +++++++++++++++ desktop-portal/credential.h | 30 ++ desktop-portal/meson.build | 4 + desktop-portal/xdp-context.c | 7 + doc/api-reference.rst | 1 + doc/impl-dbus-interfaces.rst | 1 + shared/xdp-types.h | 5 + 11 files changed, 1314 insertions(+) create mode 100644 data/org.freedesktop.handler.portal.experimental.Credential.xml create mode 100644 data/org.freedesktop.impl.portal.experimental.Credential.xml create mode 100644 data/org.freedesktop.portal.experimental.Credential.xml create mode 100644 desktop-portal/credential.c create mode 100644 desktop-portal/credential.h diff --git a/data/meson.build b/data/meson.build index 682da9223..e3bc6a538 100644 --- a/data/meson.build +++ b/data/meson.build @@ -43,6 +43,7 @@ portal_sources = files( ) portal_experimental_sources = files( + 'org.freedesktop.portal.experimental.Credential.xml', ) portal_host_sources = files( @@ -77,8 +78,10 @@ portal_impl_sources = files( ) portal_impl_experimental_sources = files( + 'org.freedesktop.impl.portal.experimental.Credential.xml', ) portal_handler_experimental_sources = files( + 'org.freedesktop.handler.portal.experimental.Credential.xml', ) background_monitor_sources = files( diff --git a/data/org.freedesktop.handler.portal.experimental.Credential.xml b/data/org.freedesktop.handler.portal.experimental.Credential.xml new file mode 100644 index 000000000..be6acca30 --- /dev/null +++ b/data/org.freedesktop.handler.portal.experimental.Credential.xml @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/org.freedesktop.impl.portal.experimental.Credential.xml b/data/org.freedesktop.impl.portal.experimental.Credential.xml new file mode 100644 index 000000000..89a834e24 --- /dev/null +++ b/data/org.freedesktop.impl.portal.experimental.Credential.xml @@ -0,0 +1,455 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/org.freedesktop.portal.experimental.Credential.xml b/data/org.freedesktop.portal.experimental.Credential.xml new file mode 100644 index 000000000..96f67440b --- /dev/null +++ b/data/org.freedesktop.portal.experimental.Credential.xml @@ -0,0 +1,273 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/desktop-portal/credential.c b/desktop-portal/credential.c new file mode 100644 index 000000000..89bad0cca --- /dev/null +++ b/desktop-portal/credential.c @@ -0,0 +1,383 @@ +/* + * Copyright © 2025 Isaiah Inuwa + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Authors: + * Isaiah Inuwa + */ + +#include "credential.h" + +#include + +#include + +#include "dex-aio.h" +#include "gio/gio.h" +#include "glib.h" +#include "glibconfig.h" +#include "xdp-app-info.h" +#include "xdp-context.h" +#include "xdp-experimental-dbus.h" +#include "xdp-experimental-handler-dbus.h" +#include "xdp-portal-config.h" +#include "xdp-request-dex.h" +#include "xdp-utils.h" + +static gboolean handle_create_credential (XdpDbusExperimentalCredential *object, + GDBusMethodInvocation *invocation, + const gchar *arg_parent_window, + const gchar *arg_origin, + const gchar *arg_type, + GVariant *arg_options); + +static gboolean handle_get_credential (XdpDbusExperimentalCredential *object, + GDBusMethodInvocation *invocation, + const gchar *arg_parent_window, + const gchar *arg_origin, + GVariant *arg_options); +struct _XdpCredential +{ + XdpDbusExperimentalCredentialSkeleton parent_instance; + + XdpContext *context; + XdpDbusExperimentalHandlerCredential *handler; +}; + +#define XDP_TYPE_CREDENTIAL (xdp_dbus_experimental_credential_get_type ()) +G_DECLARE_FINAL_TYPE (XdpCredential, xdp_credential, XDP, CREDENTIAL, XdpDbusExperimentalCredentialSkeleton) + +static void +xdp_credential_iface_init (XdpDbusExperimentalCredentialIface *iface); + +G_DEFINE_FINAL_TYPE_WITH_CODE ( + XdpCredential, + xdp_credential, + XDP_DBUS_EXPERIMENTAL_TYPE_CREDENTIAL_SKELETON, + G_IMPLEMENT_INTERFACE (XDP_DBUS_EXPERIMENTAL_TYPE_CREDENTIAL, xdp_credential_iface_init) + ); + +static void xdp_credential_iface_init (XdpDbusExperimentalCredentialIface *iface) +{ + iface->handle_create_credential = handle_create_credential; + iface->handle_get_credential = handle_get_credential; +} + +static void xdp_credential_dispose (GObject *object) +{ + XdpCredential *credential = XDP_CREDENTIAL (object); + + g_clear_object (&credential->handler); + + G_OBJECT_CLASS (xdp_credential_parent_class)->dispose (object); +} + +static void xdp_credential_init (XdpCredential *credential) {} + +static void xdp_credential_class_init (XdpCredentialClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = xdp_credential_dispose; +} + +static XdpCredential * +xdp_credential_new(XdpContext *context, XdpDbusExperimentalHandlerCredential *handler) +{ + XdpCredential *credential; + + credential = g_object_new(xdp_credential_get_type(), NULL); + credential->context = context; + credential->handler = g_object_ref(handler); + + g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (credential->handler), G_MAXINT); + + xdp_dbus_experimental_credential_set_conditional_create ( + XDP_DBUS_EXPERIMENTAL_CREDENTIAL (credential), FALSE); + xdp_dbus_experimental_credential_set_conditional_get ( + XDP_DBUS_EXPERIMENTAL_CREDENTIAL (credential), FALSE); + xdp_dbus_experimental_credential_set_hybrid_transport ( + XDP_DBUS_EXPERIMENTAL_CREDENTIAL (credential), TRUE); + xdp_dbus_experimental_credential_set_passkey_platform_authenticator ( + XDP_DBUS_EXPERIMENTAL_CREDENTIAL (credential), TRUE); + xdp_dbus_experimental_credential_set_user_verifying_platform_authenticator ( + XDP_DBUS_EXPERIMENTAL_CREDENTIAL (credential), FALSE); + xdp_dbus_experimental_credential_set_related_origins ( + XDP_DBUS_EXPERIMENTAL_CREDENTIAL (credential), TRUE); + xdp_dbus_experimental_credential_set_signal_all_accepted_credentials ( + XDP_DBUS_EXPERIMENTAL_CREDENTIAL (credential), FALSE); + xdp_dbus_experimental_credential_set_signal_current_user_details ( + XDP_DBUS_EXPERIMENTAL_CREDENTIAL (credential), FALSE); + xdp_dbus_experimental_credential_set_signal_unknown_credential ( + XDP_DBUS_EXPERIMENTAL_CREDENTIAL (credential), FALSE); + + xdp_dbus_experimental_credential_set_version ( + XDP_DBUS_EXPERIMENTAL_CREDENTIAL (credential), 1); + + return credential; +} + +const gchar *CREDENTIALSD_HANDLER_DBUS_NAME = + "xyz.iinuwa.credentialsd.Credentials"; + +static XdpOptionKey create_credential_options[] = { + {"handle_token", G_VARIANT_TYPE_STRING, NULL}, + {"origin", G_VARIANT_TYPE_STRING, NULL}, + {"top_origin", G_VARIANT_TYPE_STRING, NULL}, + {"type", G_VARIANT_TYPE_STRING, NULL}, + {"public_key", G_VARIANT_TYPE_STRING, NULL}, +}; + +/** + * create_credential_validate_options: + * @arg_options: (transfer none): options passed to the frontend. + * @error: (transfer none): pointer to an error pointer that will be populated on error. + * Returns: (transfer full): Filtered list of options to pass to the handler. + */ +static GVariant * +create_credential_validate_options (GVariant *arg_options, + GError **error) +{ + g_auto (GVariantBuilder) options = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT); + gboolean validated = xdp_filter_options (arg_options, + &options, + create_credential_options, + G_N_ELEMENTS (create_credential_options), + NULL, + error); + if (!validated) + return NULL; + else + return g_variant_ref_sink (g_variant_builder_end (&options)); +} + +static gboolean handle_create_credential (XdpDbusExperimentalCredential *object, + GDBusMethodInvocation *invocation, + const gchar *arg_parent_window, + const gchar *arg_origin, + const gchar *arg_type, + GVariant *arg_options) +{ + XdpCredential *credential = XDP_CREDENTIAL (object); + g_autoptr (XdpRequestDex) request = NULL; + g_autoptr (GVariant) options = NULL; + g_autoptr (GError) error = NULL; + + XdpAppInfo *app_info = xdp_invocation_get_app_info (invocation); + const gchar *app_id = xdp_app_info_get_id (app_info); + + options = create_credential_validate_options (arg_options, &error); + if (!options) + { + g_dbus_method_invocation_return_gerror (g_steal_pointer (&invocation), error); + return G_DBUS_METHOD_INVOCATION_HANDLED; + } + + request = dex_await_object (xdp_request_dex_new ( + credential->context, + app_info, + G_DBUS_INTERFACE_SKELETON (object), + G_DBUS_PROXY (credential->handler), + options + ), + &error); + if (!request) + { + g_dbus_method_invocation_return_gerror (g_steal_pointer (&invocation), error); + return G_DBUS_METHOD_INVOCATION_HANDLED; + } + + xdp_dbus_experimental_credential_complete_create_credential ( + object, + invocation, + xdp_request_dex_get_object_path (request)); + + { + g_autoptr (XdpDbusExperimentalHandlerCredentialCreateCredentialResult) result = NULL; + result = dex_await_boxed (xdp_dbus_experimental_handler_credential_call_create_credential_future ( + credential->handler, + arg_parent_window, + arg_origin, + arg_type, + options, + app_id + ), + &error); + + if (result) { + xdp_request_dex_emit_response (request, + result->response, + result->results); + } else { + g_dbus_error_strip_remote_error (error); + g_warning ("Handler call failed: %s (%d)", error->message, error->code); + xdp_request_dex_emit_response (request, + XDG_DESKTOP_PORTAL_RESPONSE_OTHER, + NULL); + } + } + + return G_DBUS_METHOD_INVOCATION_HANDLED; +} + +static XdpOptionKey get_credential_options[] = { + {"handle_token", G_VARIANT_TYPE_STRING, NULL}, + {"origin", G_VARIANT_TYPE_STRING, NULL}, + {"top_origin", G_VARIANT_TYPE_STRING, NULL}, + {"public_key", G_VARIANT_TYPE_STRING, NULL}, +}; + +/** + * get_credential_validate_options: + * @arg_options: (transfer none): options passed to the frontend. + * @error: (transfer none): pointer to an error pointer that will be populated on error. + * Returns: (transfer full): Filtered list of options to pass to the handler. + */ +static GVariant * +get_credential_validate_options (GVariant *arg_options, + GError **error) +{ + g_auto (GVariantBuilder) options = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT); + gboolean validated = xdp_filter_options (arg_options, + &options, + get_credential_options, + G_N_ELEMENTS (get_credential_options), + NULL, + error); + if (!validated) + return NULL; + else + return g_variant_ref_sink (g_variant_builder_end (&options)); +} + +static gboolean handle_get_credential (XdpDbusExperimentalCredential *object, + GDBusMethodInvocation *invocation, + const gchar *arg_parent_window, + const gchar *arg_origin, + GVariant *arg_options) +{ + XdpCredential *credential = XDP_CREDENTIAL (object); + g_autoptr (XdpRequestDex) request = NULL; + g_autoptr (GVariant) options = NULL; + g_autoptr (GError) error = NULL; + + XdpAppInfo *app_info = xdp_invocation_get_app_info (invocation); + const gchar *app_id = xdp_app_info_get_id (app_info); + + options = get_credential_validate_options (arg_options, &error); + if (!options) + { + g_dbus_method_invocation_return_gerror (g_steal_pointer (&invocation), error); + return G_DBUS_METHOD_INVOCATION_HANDLED; + } + + request = dex_await_object (xdp_request_dex_new ( + credential->context, + app_info, + G_DBUS_INTERFACE_SKELETON (object), + G_DBUS_PROXY (credential->handler), + options + ), + &error); + if (!request) + { + g_dbus_method_invocation_return_gerror (g_steal_pointer (&invocation), error); + return G_DBUS_METHOD_INVOCATION_HANDLED; + } + + xdp_dbus_experimental_credential_complete_get_credential ( + object, + invocation, + xdp_request_dex_get_object_path (request)); + + { + g_autoptr (XdpDbusExperimentalHandlerCredentialGetCredentialResult) result = NULL; + result = dex_await_boxed (xdp_dbus_experimental_handler_credential_call_get_credential_future ( + credential->handler, + arg_parent_window, + arg_origin, + options, + app_id + ), + &error); + + if (result) { + xdp_request_dex_emit_response (request, + result->response, + result->results); + } else { + g_dbus_error_strip_remote_error (error); + g_warning ("Handler call failed: %s (%d)", error->message, error->code); + xdp_request_dex_emit_response (request, + XDG_DESKTOP_PORTAL_RESPONSE_OTHER, + NULL); + } + } + + return G_DBUS_METHOD_INVOCATION_HANDLED; +} + +DexFuture * +init_credential (gpointer user_data) +{ + g_info ("Initializing Credential Portal"); + + XdpContext *context = XDP_CONTEXT (user_data); + g_autoptr (XdpCredential) credential = NULL; + g_autoptr (XdpDbusExperimentalHandlerCredential) handler = NULL; + g_autoptr (GError) error = NULL; + + GDBusConnection *connection = xdp_context_get_connection (context); + { + XdpPortalConfig *config = xdp_context_get_config (context); + XdpImplConfig *impl_config; + + impl_config = + xdp_portal_config_find (config, CREDENTIAL_EXPERIMENTAL_DBUS_IMPL_IFACE); + + if (impl_config == NULL) { + g_debug ("impl_config is NULL"); + return dex_future_new_true (); + } + + g_debug ("found impl"); + } + + g_debug ("creating handler proxy..."); + + handler = dex_await_object (xdp_dbus_experimental_handler_credential_proxy_new_future ( + connection, + G_DBUS_PROXY_FLAGS_NONE, + CREDENTIALSD_HANDLER_DBUS_NAME, + DESKTOP_DBUS_PATH), + &error); + + if (!handler) + { + g_warning ("Failed to create credential proxy: %s", error->message); + return dex_future_new_false (); + } + g_debug ("created handler proxy."); + + credential = xdp_credential_new (context, g_steal_pointer (&handler)); + + xdp_context_take_and_export_portal (context, + G_DBUS_INTERFACE_SKELETON (g_steal_pointer (&credential)), + XDP_CONTEXT_EXPORT_FLAGS_RUN_IN_FIBER); + + return dex_future_new_true (); +} diff --git a/desktop-portal/credential.h b/desktop-portal/credential.h new file mode 100644 index 000000000..8beb09a93 --- /dev/null +++ b/desktop-portal/credential.h @@ -0,0 +1,30 @@ +/* + * Copyright © 2025 Isaiah Inuwa + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Authors: + * Isaiah Inuwa + */ + + +#pragma once + +#include + +DexFuture * +init_credential (gpointer user_data); + diff --git a/desktop-portal/meson.build b/desktop-portal/meson.build index 9b6d1256e..42c0b0dbf 100644 --- a/desktop-portal/meson.build +++ b/desktop-portal/meson.build @@ -19,6 +19,7 @@ portal_experimental_built_sources = gnome.gdbus_codegen( interface_prefix: 'org.freedesktop.portal.experimental', namespace: 'XdpDbusExperimental', docbook: 'portal', + extra_args: gdbus_codegen_extra_args, ) host_built_sources = gnome.gdbus_codegen( 'xdp-host-dbus', @@ -42,6 +43,7 @@ impl_experimental_built_sources = gnome.gdbus_codegen( interface_prefix: 'org.freedesktop.impl.portal.experimental', namespace: 'XdpDbusExperimentalImpl', docbook: 'portal', + extra_args: gdbus_codegen_extra_args, ) handler_experimental_built_sources = gnome.gdbus_codegen( 'xdp-experimental-handler-dbus', @@ -49,6 +51,7 @@ handler_experimental_built_sources = gnome.gdbus_codegen( interface_prefix: 'org.freedesktop.handler.portal.experimental', namespace: 'XdpDbusExperimentalHandler', docbook: 'portal', + extra_args: gdbus_codegen_extra_args, ) background_monitor_built_sources = gnome.gdbus_codegen( 'xdp-background-dbus', @@ -83,6 +86,7 @@ xdg_desktop_portal_sources = files( 'background.c', 'camera.c', 'clipboard.c', + 'credential.c', 'dynamic-launcher.c', 'email.c', 'file-chooser.c', diff --git a/desktop-portal/xdp-context.c b/desktop-portal/xdp-context.c index 454197716..6f1665bfe 100644 --- a/desktop-portal/xdp-context.c +++ b/desktop-portal/xdp-context.c @@ -10,6 +10,7 @@ #include "background.h" #include "camera.h" #include "clipboard.h" +#include "credential.h" #include "dynamic-launcher.h" #include "email.h" #include "file-chooser.h" @@ -492,6 +493,12 @@ xdp_context_register (XdpContext *context, gchar **flags = g_strsplit (experimental_flag_env, ",", -1); for (gint i = 0; flags[i] != NULL; i++) { + gchar *flag = flags[i]; + if (g_strcmp0 (flag, "credential") == 0) + { + g_debug ("Enabling experimental portal credential"); + init_portal_in_fiber(context, init_credential); + } } } diff --git a/doc/api-reference.rst b/doc/api-reference.rst index 0b192515f..bdb295763 100644 --- a/doc/api-reference.rst +++ b/doc/api-reference.rst @@ -65,3 +65,4 @@ replacement will be documented in :doc:`org.freedesktop.host.portal.Registry doc-org.freedesktop.portal.Trash.rst doc-org.freedesktop.portal.Usb.rst doc-org.freedesktop.portal.Wallpaper.rst + doc-org.freedesktop.portal.experimental.Credential.rst diff --git a/doc/impl-dbus-interfaces.rst b/doc/impl-dbus-interfaces.rst index c78c645be..0133487d4 100644 --- a/doc/impl-dbus-interfaces.rst +++ b/doc/impl-dbus-interfaces.rst @@ -36,3 +36,4 @@ accessible to sandboxed applications. doc-org.freedesktop.impl.portal.Settings.rst doc-org.freedesktop.impl.portal.Usb.rst doc-org.freedesktop.impl.portal.Wallpaper.rst + doc-org.freedesktop.impl.portal.experimental.Credential.rst diff --git a/shared/xdp-types.h b/shared/xdp-types.h index fca32ed01..b0dab411c 100644 --- a/shared/xdp-types.h +++ b/shared/xdp-types.h @@ -55,6 +55,11 @@ typedef struct _XdpDbusImplAccess XdpDbusImplAccess; #define CLIPBOARD_DBUS_IFACE DESKTOP_DBUS_IFACE ".Clipboard" #define CLIPBOARD_DBUS_IMPL_IFACE DESKTOP_DBUS_IMPL_IFACE ".Clipboard" +#define CREDENTIAL_EXPERIMENTAL_DBUS_IFACE \ + DESKTOP_EXPERIMENTAL_DBUS_IFACE ".Credential" +#define CREDENTIAL_EXPERIMENTAL_DBUS_IMPL_IFACE \ + DESKTOP_EXPERIMENTAL_DBUS_IMPL_IFACE ".Credential" + #define DYNAMIC_LAUNCHER_DBUS_IFACE DESKTOP_DBUS_IFACE ".DynamicLauncher" #define DYNAMIC_LAUNCHER_DBUS_IMPL_IFACE DESKTOP_DBUS_IMPL_IFACE ".DynamicLauncher"