[neon/backports-jammy/xdg-desktop-portal/Neon/unstable_jammy] debian: backport to jammy for new xdg-desktop-portal-kde stuffs

Carlos De Maine null at kde.org
Mon Jun 10 09:08:27 BST 2024


Git commit 2ee4407db6227c5927d76c8893ada7660d6038ef by Carlos De Maine.
Committed on 10/06/2024 at 08:07.
Pushed by carlosdem into branch 'Neon/unstable_jammy'.

backport to jammy for new xdg-desktop-portal-kde stuffs

A  +22   -0    debian/NEWS
A  +827  -0    debian/changelog
A  +105  -0    debian/control
A  +76   -0    debian/copyright
A  +8    -0    debian/gbp.conf
A  +1    -0    debian/not-installed
A  +1    -0    debian/patches/series
A  +1758 -0    debian/patches/webextensions-portal.patch
A  +36   -0    debian/rules
A  +7    -0    debian/salsa-ci.yml
A  +1    -0    debian/source/format
A  +5    -0    debian/tests/control
A  +12   -0    debian/tests/gnome-desktop-testing
A  +6    -0    debian/upstream/metadata
A  +9    -0    debian/watch
A  +8    -0    debian/xdg-desktop-portal-dev.doc-base
A  +4    -0    debian/xdg-desktop-portal-dev.install
A  +2    -0    debian/xdg-desktop-portal-tests.install
A  +1    -0    debian/xdg-desktop-portal.docs
A  +8    -0    debian/xdg-desktop-portal.install
A  +2    -0    debian/xdg-desktop-portal.lintian-overrides
A  +1    -0    debian/xdg-desktop-portal.manpages
A  +11   -0    debian/xdg-desktop-portal.postinst

https://invent.kde.org/neon/backports-jammy/xdg-desktop-portal/-/commit/2ee4407db6227c5927d76c8893ada7660d6038ef

diff --git a/debian/NEWS b/debian/NEWS
new file mode 100644
index 0000000..2548b66
--- /dev/null
+++ b/debian/NEWS
@@ -0,0 +1,22 @@
+xdg-desktop-portal (1.17.1-1) experimental; urgency=medium
+
+  Since xdg-desktop-portal 1.17.0, portal implementation backends are
+  selected with a new mechanism documented in portals.conf(5).
+  Each desktop environment should provide a file at
+  /usr/share/xdg-desktop-portal/${DESKTOP}-portals.conf listing the
+  preferred portal implementations to be used in that desktop environment.
+
+  System administrators and users can override this via files named
+  portals.conf or ${DESKTOP}-portals.conf in /etc/xdg-desktop-portal
+  or ~/.config/xdg-desktop-portal, and users of customized or otherwise
+  unsupported desktop environments should also use this mechanism to set
+  up their preferred portals. Please see portals.conf(5) for full details.
+
+  ${DESKTOP} is the desktop environment's entry in $XDG_CURRENT_DESKTOP
+  (also seen in DesktopNames in /usr/share/{x,wayland-}sessions/*.desktop),
+  with ASCII upper case transformed to lower case. For example,
+  the budgie-desktop package sets XDG_CURRENT_DESKTOP=Budgie:GNOME,
+  so Budgie sessions will use budgie-portals.conf if provided, or fall
+  back to GNOME's gnome-portals.conf if not.
+
+ -- Simon McVittie <smcv at debian.org>  Mon, 28 Aug 2023 14:50:54 +0100
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..af5e40f
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,827 @@
+xdg-desktop-portal (1.18.4-1ubuntu2) noble; urgency=medium
+
+  * Merge with Debian (LP: #2062394). Remaining change:
+    - Import https://github.com/flatpak/xdg-desktop-portal/pull/705 as a
+      distro-patch to add a portal for managing WebExtensions native messaging
+      servers
+
+ -- Jeremy Bícha <jbicha at ubuntu.com>  Thu, 18 Apr 2024 17:00:47 -0400
+
+xdg-desktop-portal (1.18.4-1) unstable; urgency=medium
+
+  * New upstream stable release
+    - Don't allow sandboxed apps to specify commands starting with '-'
+      when generating .desktop files, mitigating CVE-2024-32462 in Flatpak
+    - Do not store device access permission as "denied by user" if there
+      was an error
+    - Fix a crash when config files don't specify a default backend
+
+ -- Simon McVittie <smcv at debian.org>  Thu, 18 Apr 2024 18:58:16 +0100
+
+xdg-desktop-portal (1.18.3-1ubuntu1) noble; urgency=medium
+
+  * Merge with Debian. Remaining change:
+    - Import https://github.com/flatpak/xdg-desktop-portal/pull/705 as a
+      distro-patch (add a portal for managing WebExtensions native messaging
+      servers, LP: #1968215)
+      + debian/patches/webextensions-portal.patch
+
+ -- Jeremy Bícha <jbicha at ubuntu.com>  Thu, 11 Apr 2024 18:21:31 -0400
+
+xdg-desktop-portal (1.18.3-1) unstable; urgency=medium
+
+  * Team upload
+  * New upstream bugfix release
+
+ -- Jeremy Bícha <jbicha at ubuntu.com>  Thu, 04 Apr 2024 10:53:28 -0400
+
+xdg-desktop-portal (1.18.2-1ubuntu1) noble; urgency=medium
+
+  * Merge with Debian (LP: #2038110). Remaining change:
+    - Import https://github.com/flatpak/xdg-desktop-portal/pull/705 as a
+      distro-patch (add a portal for managing WebExtensions native messaging
+      servers, LP: #1968215)
+      + debian/patches/webextensions-portal.patch
+
+ -- Jeremy Bícha <jbicha at ubuntu.com>  Mon, 27 Nov 2023 13:10:20 -0500
+
+xdg-desktop-portal (1.18.2-1) unstable; urgency=medium
+
+  * Team upload
+  * New upstream stable release
+  * Drop x-d-p-gtk fallback patch: applied in new release
+
+ -- Jeremy Bícha <jbicha at ubuntu.com>  Mon, 27 Nov 2023 13:03:50 -0500
+
+xdg-desktop-portal (1.18.1-1) unstable; urgency=medium
+
+  * New upstream stable release
+  * d/copyright: Update
+  * d/rules: Explicitly enable sandboxed image validation.
+    This is the default, but for a security hardening mechanism, explicit
+    seems better than implicit.
+  * Change packaging branch to debian/latest
+
+ -- Simon McVittie <smcv at debian.org>  Thu, 26 Oct 2023 19:28:38 +0100
+
+xdg-desktop-portal (1.18.0-1ubuntu1) mantic; urgency=medium
+
+  * Merge with Debian (LP: #2038110). Remaining change:
+    - Import https://github.com/flatpak/xdg-desktop-portal/pull/705 as a
+      distro-patch (add a portal for managing WebExtensions native messaging
+      servers, LP: #1968215)
+      + debian/patches/webextensions-portal.patch
+  * Dropped change:
+    - Keep alternative dependency to libgdk-pixbuf2.0-dev for easier backports
+      to Ubuntu 20.04 LTS or 18.04 LTS
+
+ -- Jeremy Bícha <jbicha at ubuntu.com>  Mon, 02 Oct 2023 12:21:53 -0400
+
+xdg-desktop-portal (1.18.0-1) unstable; urgency=medium
+
+  * New upstream stable release
+
+ -- Simon McVittie <smcv at debian.org>  Tue, 19 Sep 2023 12:01:57 +0100
+
+xdg-desktop-portal (1.17.2-1ubuntu1) mantic; urgency=medium
+
+  * Merge from Debian. Remaining changes:
+    - Import https://github.com/flatpak/xdg-desktop-portal/pull/705 as a
+      distro-patch (add a portal for managing WebExtensions native messaging
+      servers, LP: #1968215)
+      + debian/patches/webextensions-portal.patch
+    - Keep alternative dependency to libgdk-pixbuf2.0-dev for easier backports
+      to Ubuntu 20.04 LTS or 18.04 LTS
+  * Update webextension portal patch with latest version proposed upstream
+
+ -- Jeremy Bícha <jbicha at ubuntu.com>  Tue, 05 Sep 2023 13:08:18 -0400
+
+xdg-desktop-portal (1.17.2-1) unstable; urgency=medium
+
+  * New upstream release
+  * Release to unstable
+
+ -- Simon McVittie <smcv at debian.org>  Sat, 02 Sep 2023 10:27:12 +0100
+
+xdg-desktop-portal (1.17.1-1) experimental; urgency=medium
+
+  * New upstream release
+    - d/patches: Drop all patches, applied in new release
+  * d/control, d/x-d-p.manpages: Build and install portals.conf(5)
+  * d/NEWS: Add a NEWS file to direct users to portals.conf(5)
+  * d/p/debian/portal-impl-Hard-code-x-d-p-gtk-as-a-last-resort-fallback.patch:
+    Add patch to fall back to x-d-p-gtk if nothing better can be found.
+    This is a temporary measure to give desktop environment maintainers
+    a chance to add a portals.conf(5) for their desktop, and should be
+    removed later.
+
+ -- Simon McVittie <smcv at debian.org>  Mon, 28 Aug 2023 15:03:12 +0100
+
+xdg-desktop-portal (1.17.0-1) experimental; urgency=medium
+
+  * Team upload
+  * New upstream release
+    - Fixes portal delay with x-d-p-gnome 44 and non-GNOME desktops
+      (LP: #2013116) (Closes: #1032584)
+  * debian/control: Build-Depend on python3-dbusmock & python3-pytest
+    for build tests
+  * Drop all patches: applied in new release
+  * Cherry-pick 3 bug fixes from upstream repo
+
+ -- Jeremy Bícha <jbicha at ubuntu.com>  Mon, 21 Aug 2023 16:33:43 -0400
+
+xdg-desktop-portal (1.16.0-3ubuntu1) mantic; urgency=medium
+
+  * Merge from Debian. Remaining changes:
+    - Import https://github.com/flatpak/xdg-desktop-portal/pull/705 as a
+      distro-patch (add a portal for managing WebExtensions native messaging
+      servers, LP: #1968215)
+      + debian/patches/webextensions-portal.patch
+    - Keep alternative dependency to libgdk-pixbuf2.0-dev for easier backports
+      to Ubuntu 20.04 LTS or 18.04 LTS
+
+ -- Jeremy Bícha <jbicha at ubuntu.com>  Fri, 18 Aug 2023 09:07:20 -0400
+
+xdg-desktop-portal (1.16.0-3) unstable; urgency=medium
+
+  * d/patches: Update to upstream 1.16 branch commit 1.16.0-17-g2a219279
+    - Deal better with backends that are non-functional in desktop
+      environments other than the one they are intended for
+    - Improve handling of incorrect method calls from applications
+    - Extract app IDs from more systemd scope/slice/service names
+    - Update security support status in README
+    - Translation updates: be, gl, ka, oc, tr
+  * Update standards version to 4.6.2 (no changes needed)
+  * Remove version constraints unnecessary since Debian 11
+  * d/xdp.lintian-overrides: Silence some false positives (#1031037)
+
+ -- Simon McVittie <smcv at debian.org>  Sat, 05 Aug 2023 15:33:04 +0100
+
+xdg-desktop-portal (1.16.0-2ubuntu1) lunar; urgency=medium
+
+  * Merge from Debian. Remaining changes:
+    - Import https://github.com/flatpak/xdg-desktop-portal/pull/705 as a
+      distro-patch (add a portal for managing WebExtensions native messaging
+      servers, LP: #1968215)
+      + debian/patches/webextensions-portal.patch
+  * d/p/webextensions-portal.patch: updated
+  * Keep alternative dependency to libgdk-pixbuf2.0-dev for easier backports
+    to Ubuntu 20.04 LTS or 18.04 LTS
+
+ -- Nathan Pratta Teodosio <nathan.teodosio at canonical.com>  Wed, 25 Jan 2023 15:33:03 -0300
+
+xdg-desktop-portal (1.16.0-2) unstable; urgency=medium
+
+  * d/patches: Add post-release bug fixes from upstream
+    - d/p/file-chooser-Set-writable-flag-correctly.patch:
+      Don't allow writing to files if not requested
+    - d/p/tests-List-lists-of-sources-one-per-line-in-alphabetical-.patch,
+      d/p/tests-Add-missing-dependency-on-permission-store-GDBus-he.patch:
+      Fix a race condition that was breaking bullseye-backports builds
+
+ -- Simon McVittie <smcv at debian.org>  Tue, 10 Jan 2023 11:31:45 +0000
+
+xdg-desktop-portal (1.16.0-1ubuntu1) lunar; urgency=medium
+
+  * Merge from Debian. Remaining changes:
+    - Import https://github.com/flatpak/xdg-desktop-portal/pull/705 as a
+      distro-patch (add a portal for managing WebExtensions native messaging
+      servers, LP: #1968215)
+      + debian/patches/webextensions-portal.patch
+  * Update webextensions-portal.patch with latest proposed version
+
+ -- Jeremy Bicha <jbicha at ubuntu.com>  Thu, 15 Dec 2022 10:39:43 -0500
+
+xdg-desktop-portal (1.16.0-1) unstable; urgency=medium
+
+  * New upstream release
+  * d/copyright: Update
+  * d/patches: Drop patches, included in the new release
+  * d/upstream/metadata: Add Security-Contact
+  * d/not-installed: Skip installation of an unnecessary file
+
+ -- Simon McVittie <smcv at debian.org>  Tue, 13 Dec 2022 22:52:21 +0000
+
+xdg-desktop-portal (1.15.0-3) unstable; urgency=medium
+
+  * d/watch: Adapt to Github web page changes
+  * d/control: Canonicalize case of Multi-Arch field
+  * d/p/meson-In-installed-tests-invoke-test-portals-once-per-por.patch:
+    Update patch to the version that was applied upstream
+  * d/p/test-portals-Include-utils-even-if-libportal-is-unavailab.patch,
+    d/p/tests-Don-t-apply-Meson-s-strict-TAP-parsing-for-older-GL.patch,
+    d/p/tests-Include-src-glib-backports.h-where-needed.patch,
+    d/p/glib-backports-Declare-stub-function-as-inline.patch:
+    Add patches from upstream needed for the Debian 11 backport
+  * d/patches: Add selected bug fixes from upstream git
+    - Move xdg-permission-store to the systemd slice appropriate for
+      session services used to support applications
+    - Improve systemd service management so our services do not linger after
+      graphical-session.target has exited
+    - Documentation fixes
+    - Make o.fd.portal.Screenshot.Version mirror
+      o.fd.portal.impl.Screenshot.Version so that clients can discover
+      whether the backend implements PickColor()
+    - Add a missing Qt type annotation to the Request.Response signal
+  * d/patches: Add localization updates from upstream
+  * Build-/test-depend on dbus-daemon instead of dbus
+
+ -- Simon McVittie <smcv at debian.org>  Tue, 22 Nov 2022 10:38:32 +0000
+
+xdg-desktop-portal (1.15.0-2) unstable; urgency=medium
+
+  * Release to unstable.
+    xdg-desktop-portal-gnome needs features of this version, and a 1.16.0
+    stable release is intended to happen before the freeze.
+  * d/control: Drop compatibility with old libgdk-pixbuf2.0-dev package.
+    libgdk-pixbuf-2.0-dev has been available since bullseye.
+
+ -- Simon McVittie <smcv at debian.org>  Thu, 15 Sep 2022 19:20:27 +0100
+
+xdg-desktop-portal (1.15.0-1ubuntu1) kinetic; urgency=medium
+
+  * Merge from Debian. Remaining changes:
+    - Import https://github.com/flatpak/xdg-desktop-portal/pull/705 as a
+      distro-patch (add a portal for managing WebExtensions native messaging
+      servers, LP: #1968215)
+      + debian/patches/webextensions-portal.patch
+  * Update webextensions-portal.patch with latest proposed version
+
+ -- Jeremy Bicha <jbicha at ubuntu.com>  Mon, 15 Aug 2022 06:59:02 -0400
+
+xdg-desktop-portal (1.15.0-1) experimental; urgency=medium
+
+  * New upstream development release
+  * Switch to experimental branch
+    - d/watch: Watch for development releases
+    - d/gbp.conf, d/control: Use debian/experimental packaging branch
+  * d/control, d/rules: Build using Meson
+  * Add patch to split up installed-tests coverage for test-portals.
+    This will make it easier to distinguish between tests that are stable
+    when run as an autopkgtest, and tests that are not.
+
+ -- Simon McVittie <smcv at debian.org>  Sun, 14 Aug 2022 21:08:48 +0100
+
+xdg-desktop-portal (1.14.6-1) unstable; urgency=medium
+
+  * New upstream stable release
+
+ -- Simon McVittie <smcv at debian.org>  Thu, 04 Aug 2022 09:17:19 +0100
+
+xdg-desktop-portal (1.14.5-1) unstable; urgency=medium
+
+  * New upstream stable release
+  * Standards-Version: 4.6.1 (no changes required)
+
+ -- Simon McVittie <smcv at debian.org>  Tue, 19 Jul 2022 18:58:07 +0100
+
+xdg-desktop-portal (1.14.4-1ubuntu1) kinetic; urgency=medium
+
+  * Merge from Debian. Remaining changes:
+    - Import https://github.com/flatpak/xdg-desktop-portal/pull/705 as a
+      distro-patch (add a portal for managing WebExtensions native messaging
+      servers, LP: #1968215)
+      + debian/patches/webextensions-portal.patch
+
+ -- Olivier Tilloy <olivier.tilloy at canonical.com>  Mon, 13 Jun 2022 11:21:47 +0200
+
+xdg-desktop-portal (1.14.4-1) unstable; urgency=medium
+
+  * New upstream stable release
+
+ -- Simon McVittie <smcv at debian.org>  Thu, 05 May 2022 15:14:29 +0100
+
+xdg-desktop-portal (1.14.3-1) unstable; urgency=medium
+
+  * New upstream stable release
+
+ -- Simon McVittie <smcv at debian.org>  Fri, 15 Apr 2022 16:30:43 +0100
+
+xdg-desktop-portal (1.14.3-0ubuntu3) kinetic; urgency=medium
+
+  * Update the native messaging portal patch to pick up a new commit
+    - debian/patches/webextensions-portal.patch
+
+ -- Olivier Tilloy <olivier.tilloy at canonical.com>  Wed, 11 May 2022 11:06:32 +0200
+
+xdg-desktop-portal (1.14.3-0ubuntu2) jammy; urgency=medium
+
+  * New upstream stable release
+    - Fixes crash with Teamviewer's experimental Wayland support
+      (LP: #1966945)
+
+ -- Jeremy Bicha <jbicha at ubuntu.com>  Fri, 15 Apr 2022 15:17:26 -0400
+
+xdg-desktop-portal (1.14.2-1ubuntu2) jammy; urgency=medium
+
+  * Update the native messaging portal patch to pick up new commits
+    - debian/patches/webextensions-portal.patch
+
+ -- Olivier Tilloy <olivier.tilloy at canonical.com>  Mon, 11 Apr 2022 18:47:05 +0200
+
+xdg-desktop-portal (1.14.2-1ubuntu1) jammy; urgency=medium
+
+  * Import https://github.com/flatpak/xdg-desktop-portal/pull/705 as a
+    distro-patch (add a portal for managing WebExtensions native messaging
+    servers, LP: #1968215)
+    - debian/patches/webextensions-portal.patch
+
+ -- Olivier Tilloy <olivier.tilloy at canonical.com>  Fri, 08 Apr 2022 11:16:45 +0200
+
+xdg-desktop-portal (1.14.2-1) unstable; urgency=medium
+
+  * New upstream release
+  * Drop patches, applied upstream
+
+ -- Simon McVittie <smcv at debian.org>  Thu, 31 Mar 2022 12:11:22 +0100
+
+xdg-desktop-portal (1.14.1-2) unstable; urgency=medium
+
+  * d/x-d-p.postinst: Clean up enabled state of x-d-p.service on upgrades.
+    When we upgrade from 1.14.0 to 1.14.1, we want to remove
+    /etc/systemd/user/graphical-session-pre.target.wants/xdg-desktop-portal.service
+    so that it will not cause a deadlock during GNOME login.
+  * d/p/Move-g_string_replace-backport-to-a-separate-translation-.patch,
+    d/p/rewrite-launchers-Provide-backported-g_string_replace.patch:
+    Add patches to fix compilation with GLib 2.66, to make backports more
+    straightforward.
+
+ -- Simon McVittie <smcv at debian.org>  Sun, 27 Mar 2022 13:05:55 +0100
+
+xdg-desktop-portal (1.14.1-1) unstable; urgency=medium
+
+  * New upstream release
+  * d/p/Revert-Make-x-d-p-start-on-session-start.patch:
+    Drop patch, the problem was fixed differently upstream
+  * Package the new xdg-desktop-portal-rewrite-launchers executable
+
+ -- Simon McVittie <smcv at debian.org>  Sat, 19 Mar 2022 14:08:29 +0000
+
+xdg-desktop-portal (1.14.0-2) unstable; urgency=medium
+
+  * d/p/Revert-Make-x-d-p-start-on-session-start.patch:
+    Revert starting xdg-desktop-portal during session start.
+    This causes a new GNOME login after a reboot to deadlock.
+
+ -- Simon McVittie <smcv at debian.org>  Fri, 18 Mar 2022 11:16:06 +0000
+
+xdg-desktop-portal (1.14.0-1) unstable; urgency=medium
+
+  * New upstream release
+  * Drop patches restoring the icon validator.
+    It has been reinstated upstream.
+  * Depend and build-depend on FUSE 3
+  * d/control, d/rules: Build with libsystemd
+
+ -- Simon McVittie <smcv at debian.org>  Fri, 18 Mar 2022 09:17:39 +0000
+
+xdg-desktop-portal (1.12.2-1) unstable; urgency=medium
+
+  * New upstream release
+
+ -- Simon McVittie <smcv at debian.org>  Thu, 17 Mar 2022 23:25:45 +0000
+
+xdg-desktop-portal (1.12.1-1) unstable; urgency=medium
+
+  * New upstream release
+  * Drop patches that were applied upstream
+  * d/copyright: Update
+
+ -- Simon McVittie <smcv at debian.org>  Wed, 22 Dec 2021 15:46:31 +0000
+
+xdg-desktop-portal (1.10.1-4) unstable; urgency=medium
+
+  * Upload to unstable.
+    The libportal-based build-time test coverage passes on all release
+    architectures.
+
+ -- Simon McVittie <smcv at debian.org>  Tue, 16 Nov 2021 10:30:39 +0000
+
+xdg-desktop-portal (1.10.1-3) experimental; urgency=medium
+
+  * d/gbp.conf: Branch for experimental
+  * d/control, d/rules: Enable libportal now that it is available in testing
+
+ -- Simon McVittie <smcv at debian.org>  Mon, 15 Nov 2021 20:37:48 +0000
+
+xdg-desktop-portal (1.10.1-2) unstable; urgency=medium
+
+  * d/p/open-uri-Avoid-calling-into-o.fd.FileManager1-during-star.patch:
+    Add proposed patch to resolve deadlock with some file managers.
+    This avoids a long delay during startup of GtkApplication-based
+    implementations of the o.fd.FileManager1 interface, such as XFCE's
+    Thunar, in a non-GNOME and non-XFCE environment. (Closes: #994865)
+  * d/p/build-Fix-cross-compilation-by-adjusting-pkg-config-use.patch:
+    Add proposed patch to fix cross-compilation.
+    Thanks to Helmut Grohne (Closes: #985411)
+
+ -- Simon McVittie <smcv at debian.org>  Fri, 01 Oct 2021 23:29:32 +0100
+
+xdg-desktop-portal (1.10.1-1) unstable; urgency=medium
+
+  * New upstream release
+  * Standards-Version: 4.6.0 (no changes required)
+  * d/rules: Stop working around wrong permissions on test-document-fuse.py.
+    This was fixed upstream.
+  * Don't let debhelper 13 make installed-tests data executable
+  * Use debhelper compat level 13
+    - No need to override dh_missing any more
+
+ -- Simon McVittie <smcv at debian.org>  Tue, 21 Sep 2021 17:21:24 +0100
+
+xdg-desktop-portal (1.8.1-1) unstable; urgency=medium
+
+  * New upstream release
+    - Fix a fd leak when opening URIs
+    - Fix directory support in filechooser
+    - Improve Snap support
+    - Fix a crash when setting wallpaper fails
+  * Drop fontconfig build-dependency, no longer needed
+  * Define _GNU_SOURCE when compiling the icon validator,
+    avoiding an implicit declaration of execvpe()
+  * Label the icon validator as coming from Flatpak 1.10.1
+    (no actual changes, the code is identical to 1.8.1)
+
+ -- Simon McVittie <smcv at debian.org>  Fri, 19 Feb 2021 10:21:45 +0000
+
+xdg-desktop-portal (1.8.0-3) unstable; urgency=medium
+
+  * debian/rules: Build with pipewire support in ubuntu as well (LP: #1879580)
+
+ -- Marco Trevisan (Treviño) <marco at ubuntu.com>  Thu, 11 Feb 2021 19:08:03 +0100
+
+xdg-desktop-portal (1.8.0-2) unstable; urgency=medium
+
+  * Version the build-dependency on libflatpak-dev.
+    This is significant when backporting to buster.
+  * Preferentially build-depend on libgdk-pixbuf-2.0-dev.
+    We don't need the deprecated Xlib integration that is also pulled in
+    by the older libgdk-pixbuf2.0-dev package (see #974870).
+  * Standards-Version: 4.5.1 (no changes required)
+
+ -- Simon McVittie <smcv at debian.org>  Tue, 24 Nov 2020 12:01:38 +0000
+
+xdg-desktop-portal (1.8.0-1) unstable; urgency=medium
+
+  * New upstream release
+    - Drop most patches, applied upstream
+
+ -- Simon McVittie <smcv at debian.org>  Wed, 16 Sep 2020 10:31:24 +0100
+
+xdg-desktop-portal (1.7.2-2) unstable; urgency=medium
+
+  * d/rules: Don't explicitly use --as-needed linker option.
+    It's the default with bullseye toolchains.
+  * Release to unstable as part of the pipewire 0.3 transition
+
+ -- Simon McVittie <smcv at debian.org>  Thu, 10 Sep 2020 12:32:17 +0100
+
+xdg-desktop-portal (1.7.2-1) experimental; urgency=medium
+
+  * New upstream development release
+  * Drop patch skipping FUSE tests if necessary,
+    upstream made an equivalent change
+  * Update icon validator to the one from Flatpak 1.8.1
+  * Build-Depend on libcap2-bin, for capsh, and add it to test dependencies
+  * tests: Look for capsh in /sbin
+  * Update patches.
+    This includes upstream 1.7.2-37-g089e72b plus merge request
+    <https://github.com/flatpak/xdg-desktop-portal/pull/521>,
+    to make the installed-tests work better.
+  * d/tests/gnome-desktop-testing: Set TEST_IN_CI.
+    Upstream uses this to extend test timeouts and skip flaky tests.
+  * Re-enable pipewire now that 0.3.x is in experimental
+
+ -- Simon McVittie <smcv at debian.org>  Mon, 07 Sep 2020 19:41:23 +0100
+
+xdg-desktop-portal (1.7.1-1) experimental; urgency=medium
+
+  * New upstream development release
+
+ -- Simon McVittie <smcv at debian.org>  Mon, 30 Mar 2020 10:19:22 +0100
+
+xdg-desktop-portal (1.7.0-1) experimental; urgency=medium
+
+  * Switch to experimental branch
+    - d/watch: Watch for development releases
+    - d/gbp.conf, d/control: Use debian/experimental packaging branch
+    - d/gbp.conf: Use upstream/latest branch
+  * New upstream development release
+  * Disable pipewire until 0.3.x is available (#954022)
+  * Drop patches that were applied upstream
+  * Set upstream metadata fields: Repository.
+  * Remove obsolete field Name from debian/upstream/metadata (already
+    present in machine-readable debian/copyright).
+  * Standards-Version: 4.5.0 (no changes required)
+  * d/p/tests-Divert-service-stdout-to-stderr.patch: Simplify
+  * tests: Depend on procps, for /bin/kill
+  * tests: Depend on python3 and python3-gi
+  * Add a patch to skip (more) FUSE tests on buildds
+
+ -- Simon McVittie <smcv at debian.org>  Wed, 25 Mar 2020 16:00:52 +0000
+
+xdg-desktop-portal (1.6.0-1) unstable; urgency=medium
+
+  * New upstream stable release
+    - d/watch: Only watch for stable releases
+    - d/gbp.conf: Use debian/master, upstream/1.6.x branches
+  * Mention #946913 in previous changelog entry
+  * Add "unsafe" pkg.libportal.enable build option to enable extra tests
+    while libportal is not yet API-stable
+  * d/p/Fix-the-build-on-old-glib.patch,
+    d/p/xml-Avoid-fancy-quotes.patch:
+    Add post-release fixes from upstream
+  * d/p/open-uri-Fix-criticals-if-no-default-handler-for-desired-.patch,
+    d/p/tests-Fix-race-condition-in-various-Lockdown-tests.patch,
+    d/p/tests-Skip-Location-tests-if-we-have-no-D-Bus-system-bus.patch,
+    d/p/tests-Install-test-backends.patch,
+    d/p/tests-When-installed-look-for-executables-in-libexecdir.patch,
+    d/p/tests-Install-test.portal-for-installed-tests.patch:
+    Fix some test failures when libportal is enabled
+  * d/p/tests-Divert-service-stdout-to-stderr.patch,
+    d/p/tests-Always-produce-verbose-output-from-subprocesses.patch:
+    Improve test diagnostics
+  * d/p/Replace-the-icon-validator-with-the-one-from-Flatpak-1.6..patch:
+    Relabel the icon validator as coming from Flatpak 1.6.0
+    (it's the same as 1.4.2)
+
+ -- Simon McVittie <smcv at debian.org>  Tue, 24 Dec 2019 14:15:27 +0000
+
+xdg-desktop-portal (1.5.4-1) experimental; urgency=medium
+
+  * Branch for experimental
+  * New upstream development release
+    - d/patches: Rebase
+    - d/rules: Explicitly disable libportal-based tests (ITP: #946605)
+    - Only log one warning if unable to track which apps are "in the
+      background, for example x-d-p-gtk in a non-GNOME environment
+      (Closes: #946913)
+
+ -- Simon McVittie <smcv at debian.org>  Fri, 13 Dec 2019 23:23:14 +0000
+
+xdg-desktop-portal (1.4.2-3) unstable; urgency=medium
+
+  * Standards-Version: 4.4.1 (no changes required)
+  * Re-enable pipewire (screen recording) support now that v0.2.7 is
+    available
+
+ -- Simon McVittie <smcv at debian.org>  Sat, 02 Nov 2019 10:12:41 +0000
+
+xdg-desktop-portal (1.4.2-2) unstable; urgency=medium
+
+  * Release to unstable
+  * d/salsa-ci.yml: Request standard CI on salsa.debian.org
+  * d/p/test-doc-portal-Check-for-FUSE-support-more-thoroughly.patch:
+    Skip tests when FUSE is non-functional, even if we are root
+  * Standards-Version: 4.4.0 (no changes required)
+  * Use debhelper-compat 12
+    - Remove redundant --libexecdir=/usr/libexec, which is the default
+      at this compat level
+  * d/p/Replace-the-icon-validator-with-the-one-from-Flatpak-1.4..patch:
+    Update icon validator to the one from Flatpak 1.4.2
+  * Mark autopkgtest as flaky due to #931726
+
+ -- Simon McVittie <smcv at debian.org>  Tue, 16 Jul 2019 09:19:47 +0100
+
+xdg-desktop-portal (1.4.2-1) experimental; urgency=medium
+
+  * New upstream release
+  * Disable pipewire (screencasting) until 0.2.6 is available in Debian
+  * Build-depend on libjson-glib-dev
+  * d/copyright: Update
+
+ -- Simon McVittie <smcv at debian.org>  Mon, 10 Jun 2019 09:37:22 +0100
+
+xdg-desktop-portal (1.2.0-1) unstable; urgency=medium
+
+  [ Simon McVittie ]
+  * New upstream stable release
+  * d/watch: Only watch for stable releases
+  * d/p/Revert-Stop-building-the-icon-validator.patch,
+    d/p/validate-icon-Add-a-define-for-bwrap.patch,
+    d/p/Replace-the-icon-validator-with-the-one-from-Flatpak-git-.patch:
+    Build a copy of the icon validator from Flatpak git master.
+    We don't want to rely on a version of Flatpak that isn't
+    stable yet.
+    - d/p/notification-Handle-non-existing-directories.patch,
+      d/p/notification-bind-mount-etc-ld.so.cache-to-the-sandbox.patch:
+      Remove, no longer necessary
+  * d/upstream/metadata: Add DEP-12 metadata
+  * Release to unstable
+
+  [ Jeremy Bicha ]
+  * Don't enable remote desktop support on Ubuntu. See LP bug 1802533
+
+ -- Simon McVittie <smcv at debian.org>  Sat, 26 Jan 2019 18:31:50 +0000
+
+xdg-desktop-portal (1.1.1-1) experimental; urgency=medium
+
+  * New upstream development release
+    - Drop patches, applied upstream
+    - Build-Depend on libgdk-pixbuf2.0-dev, for icon validation
+    - Package new xdg-desktop-portal-validate-icon executable
+    - Depend on bubblewrap, for sandboxed icon validation
+  * Enable Location portal (geoclue-2.0)
+  * Standards-Version: 4.3.0 (no changes required)
+  * d/control: Set Vcs-Git branch for experimental
+  * d/p/notification-Handle-non-existing-directories.patch,
+    d/p/notification-bind-mount-etc-ld.so.cache-to-the-sandbox.patch:
+    Make bwrap invocation more reliable, and in particular make it
+    work on purely 32-bit systems with no /lib64 (patches taken from
+    gnome-desktop, thanks to Iain Lane and Mart Raudsepp)
+
+ -- Simon McVittie <smcv at debian.org>  Thu, 17 Jan 2019 09:57:59 +0000
+
+xdg-desktop-portal (1.1.0-1) experimental; urgency=medium
+
+  * New upstream development release
+    - d/copyright: Update
+    - d/control: Build-depend on fontconfig, for fontconfig cache
+      invalidation in Settings portal
+    - d/control: Build-depend on flatpak, for permission-store test
+  * Don't build with Location portal yet, because geoclue-2.0 is
+    currently too old
+  * Drop patch, applied upstream
+  * d/gbp.conf: Use debian/experimental branch
+  * d/patches: Skip another build-time test when FUSE is not supported
+  * d/patches: Don't show a critical warning when a document permissions
+    entry is removed
+  * Enable Pipewire support, for screencasting
+
+ -- Simon McVittie <smcv at debian.org>  Mon, 19 Nov 2018 18:47:57 +0000
+
+xdg-desktop-portal (1.0.3-1) unstable; urgency=medium
+
+  * New upstream release
+  * d/p/desktop-portal-don-t-attempt-to-export-NULL-GDBusInterfac.patch:
+    Add patch from upstream to guard against NULL interface objects
+    (previously applied in Ubuntu, LP: #1691649)
+
+ -- Simon McVittie <smcv at debian.org>  Sat, 13 Oct 2018 11:33:35 +0100
+
+xdg-desktop-portal (1.0.2-1) unstable; urgency=medium
+
+  * New upstream release
+  * d/p/network-monitor-Build-variants-for-GetStatus-correctly.patch:
+    Drop, superseded by upstream changes
+
+ -- Simon McVittie <smcv at debian.org>  Mon, 10 Sep 2018 10:37:46 +0100
+
+xdg-desktop-portal (1.0.1-1) unstable; urgency=medium
+
+  * New upstream release
+  * d/p/network-monitor-Build-variants-for-GetStatus-correctly.patch:
+    Add patch to make NetworkMonitor.GetStatus() work as intended
+  * Standards-Version: 4.2.1 (no changes required)
+
+ -- Simon McVittie <smcv at debian.org>  Fri, 31 Aug 2018 08:55:19 +0100
+
+xdg-desktop-portal (1.0-1) unstable; urgency=medium
+
+  * New upstream release
+  * Install upstream NEWS
+  * Standards-Version: 4.2.0 (no further changes)
+
+ -- Simon McVittie <smcv at debian.org>  Thu, 23 Aug 2018 09:53:13 +0100
+
+xdg-desktop-portal (0.99-1) unstable; urgency=medium
+
+  * New upstream release
+  * Standards-Version: 4.1.5
+  * Install to /usr/libexec
+  * Build in a UTF-8 locale, to avoid FTBFS when gdbus-codegen reads
+    UTF-8
+
+ -- Simon McVittie <smcv at debian.org>  Sat, 28 Jul 2018 12:28:48 +0100
+
+xdg-desktop-portal (0.11-2) unstable; urgency=medium
+
+  [ Jeremy Bicha ]
+  * Update package description to mention Snap
+  * Use github page as homepage
+
+ -- Simon McVittie <smcv at debian.org>  Sun, 24 Jun 2018 22:02:48 +0100
+
+xdg-desktop-portal (0.11-1) unstable; urgency=medium
+
+  * New upstream release
+    - Drop patch, applied upstream
+  * Standards-Version: 4.1.4 (no changes)
+
+ -- Simon McVittie <smcv at debian.org>  Wed, 25 Apr 2018 16:29:22 +0100
+
+xdg-desktop-portal (0.10-4) unstable; urgency=medium
+
+  * Merge from experimental, with autopkgtests included
+  * d/p/build-Run-install-test-data-hook-as-intended.patch:
+    Mark patch as applied upstream
+
+ -- Simon McVittie <smcv at debian.org>  Fri, 16 Feb 2018 14:50:44 +0000
+
+xdg-desktop-portal (0.10-3) experimental; urgency=medium
+
+  * Reinstate xdg-desktop-portal-tests package and autopkgtests
+  * d/p/build-Run-install-test-data-hook-as-intended.patch:
+    Run the tests' install hook to set up enough symlinks that they
+    will pass
+  * Upload to experimental to wait for NEW processing
+
+ -- Simon McVittie <smcv at debian.org>  Thu, 15 Feb 2018 00:30:01 +0000
+
+xdg-desktop-portal (0.10-2) unstable; urgency=medium
+
+  * Really remove xdg-desktop-portal-tests stanza from d/control
+
+ -- Simon McVittie <smcv at debian.org>  Thu, 15 Feb 2018 00:01:42 +0000
+
+xdg-desktop-portal (0.10-1) unstable; urgency=medium
+
+  * New upstream release
+  * Add Breaks/Replaces for flatpak (<< 0.10.4-1~) since this package
+    has taken over the permission store and documents portal
+  * Disable Pipewire support for now (ITP: #874089)
+  * Add new build-dependencies for FUSE
+  * Install the permission store and documents portal
+  * d/copyright: Update
+  * Drop flatpak build-dependency, no longer needed
+  * Remove patches, applied upstream
+  * Depend on FUSE
+  * Build installed-tests, but don't install them for now to avoid the
+    NEW queue
+  * Use dh_missing --fail-missing instead of dh_install --fail-missing
+
+ -- Simon McVittie <smcv at debian.org>  Wed, 14 Feb 2018 17:44:15 +0000
+
+xdg-desktop-portal (0.9-2) unstable; urgency=medium
+
+  * Standards-Version: 4.1.3 (no changes)
+  * Change Vcs-* to point to salsa.debian.org
+  * d/p/0.10/: Update to upstream git commit 0.9-9-g422ecf3 for various
+    bug fixes
+
+ -- Simon McVittie <smcv at debian.org>  Thu, 18 Jan 2018 08:46:29 +0000
+
+xdg-desktop-portal (0.9-1) unstable; urgency=medium
+
+  * New upstream release
+    - Drop all patches, applied upstream
+
+ -- Simon McVittie <smcv at debian.org>  Fri, 24 Nov 2017 10:38:16 +0000
+
+xdg-desktop-portal (0.8-3) unstable; urgency=medium
+
+  * Set Rules-Requires-Root to no
+  * Use https Format URL in d/copyright
+  * Standards-Version: 4.1.1 (no further changes)
+
+ -- Simon McVittie <smcv at debian.org>  Sat, 11 Nov 2017 13:43:41 +0000
+
+xdg-desktop-portal (0.8-2) unstable; urgency=medium
+
+  * Mark patches as applied upstream for 0.9
+  * Upload to unstable
+
+ -- Simon McVittie <smcv at debian.org>  Sat, 10 Jun 2017 10:12:20 +0100
+
+xdg-desktop-portal (0.8-1) experimental; urgency=medium
+
+  * New upstream release
+  * Add patches to make the development files completely
+    architecture-independent (Closes: #864451)
+  * Make xdg-desktop-portal-dev Architecture: all
+
+ -- Simon McVittie <smcv at debian.org>  Fri, 09 Jun 2017 08:04:12 +0100
+
+xdg-desktop-portal (0.6-1) experimental; urgency=medium
+
+  * New upstream release
+    - Run as a systemd user service if dbus-user-session is installed
+    - Add email portal
+  * Move to debhelper compat level 10
+  * Omit unimplemented configure option --enable-installed-tests
+  * Do not explicitly disable quiet Automake output: dh now does this
+    by default
+  * Move API documentation from main package to -dev package
+  * Register API documentation with doc-base
+
+ -- Simon McVittie <smcv at debian.org>  Mon, 03 Apr 2017 15:28:02 +0100
+
+xdg-desktop-portal (0.5-1) unstable; urgency=medium
+
+  * New upstream release
+
+ -- Simon McVittie <smcv at debian.org>  Sat, 21 Jan 2017 16:28:36 +0000
+
+xdg-desktop-portal (0.4-1) unstable; urgency=medium
+
+  * New upstream release
+    - Drop cherry-picked patch for flatpak 0.6.10 container detection,
+      now included in the upstream release
+
+ -- Simon McVittie <smcv at debian.org>  Mon, 05 Dec 2016 10:51:02 +0000
+
+xdg-desktop-portal (0.3-1) unstable; urgency=medium
+
+  * Initial release. (Closes: #831689)
+
+ -- Simon McVittie <smcv at debian.org>  Wed, 21 Sep 2016 22:14:13 +0100
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..7c5afbb
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,105 @@
+Source: xdg-desktop-portal
+Section: admin
+Priority: optional
+Maintainer: Ubuntu Developers <ubuntu-devel-discuss at lists.ubuntu.com>
+XSBC-Original-Maintainer: Utopia Maintenance Team <pkg-utopia-maintainers at lists.alioth.debian.org>
+Uploaders:
+ Simon McVittie <smcv at debian.org>,
+Build-Depends:
+ dbus-daemon,
+ debhelper-compat (= 13),
+ geoclue-2.0 <!nocheck>,
+ fuse3 <!nocheck>,
+ libcap2-bin <!nocheck>,
+ libgdk-pixbuf-2.0-dev,
+ libgeoclue-2-dev,
+ libflatpak-dev,
+ libfuse3-dev,
+ libglib2.0-dev,
+ libjson-glib-dev,
+ libpipewire-0.3-dev,
+ libportal-dev (>= 0.3),
+ libsystemd-dev,
+ meson,
+ pipewire <!nocheck>,
+ procps <!nocheck>,
+ python3 <!nocheck>,
+ python3-dbusmock <!nocheck>,
+ python3-docutils <!nodoc>,
+ python3-gi <!nocheck>,
+ python3-pytest <!nocheck>,
+ xmlto,
+Rules-Requires-Root: no
+Standards-Version: 4.6.2
+Homepage: https://github.com/flatpak/xdg-desktop-portal
+XS-Debian-Vcs-Git: https://salsa.debian.org/debian/xdg-desktop-portal.git
+XS-Debian-Vcs-Browser: https://salsa.debian.org/debian/xdg-desktop-portal
+Vcs-Git: https://salsa.debian.org/debian/xdg-desktop-portal.git -b ubuntu/master
+Vcs-Browser: https://salsa.debian.org/debian/xdg-desktop-portaltree/ubuntu/master
+
+Package: xdg-desktop-portal
+Architecture: linux-any
+Multi-Arch: foreign
+Depends:
+ bubblewrap,
+ default-dbus-session-bus | dbus-session-bus,
+ fuse3,
+ ${misc:Depends},
+ ${shlibs:Depends},
+Description: desktop integration portal for Flatpak and Snap
+ xdg-desktop-portal provides a portal frontend service for Flatpak, Snap,
+ and possibly other desktop containment/sandboxing frameworks. This service
+ is made available to the sandboxed application, and provides mediated
+ D-Bus interfaces for file access, URI opening, printing and similar
+ desktop integration features.
+ .
+ The implementation of these interfaces is expected to require
+ user confirmation before responding to the sandboxed application's
+ requests. For example, when the sandboxed application ask to open a file,
+ the portal implementation will open an "Open" dialog outside the sandbox,
+ and will only make the selected file available to the sandboxed app if
+ that dialog is confirmed.
+ .
+ xdg-desktop-portal is designed to be desktop-agnostic, and uses a
+ desktop-environment-specific GUI backend such as xdg-desktop-portal-gtk
+ to provide its functionality.
+
+Package: xdg-desktop-portal-dev
+Architecture: all
+Multi-Arch: foreign
+Depends:
+ ${misc:Depends},
+ ${shlibs:Depends},
+Description: desktop integration portal - development files
+ xdg-desktop-portal provides a portal frontend service for Flatpak, Snap,
+ and possibly other desktop containment/sandboxing frameworks. This service
+ is made available to the sandboxed application, and provides mediated
+ D-Bus interfaces for file access, URI opening, printing and similar
+ desktop integration features. See the xdg-desktop-portal package's
+ description for more details.
+ .
+ This package contains development files for backends such as
+ xdg-desktop-portal-gtk.
+
+Package: xdg-desktop-portal-tests
+Architecture: any
+Depends:
+ dbus-daemon,
+ geoclue-2.0,
+ libcap2-bin,
+ pipewire,
+ procps,
+ python3,
+ python3-gi,
+ xdg-desktop-portal,
+ ${misc:Depends},
+ ${shlibs:Depends},
+Description: desktop integration portal - automated tests
+ xdg-desktop-portal provides a portal frontend service for Flatpak, Snap,
+ and possibly other desktop containment/sandboxing frameworks. This service
+ is made available to the sandboxed application, and provides mediated
+ D-Bus interfaces for file access, URI opening, printing and similar
+ desktop integration features. See the xdg-desktop-portal package's
+ description for more details.
+ .
+ This package contains automated tests.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..9ec0804
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,76 @@
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: xdg-desktop-portal
+Source: https://github.com/flatpak/xdg-desktop-portal/releases
+
+Files:
+ *
+Copyright:
+ © 2010 Codethink Limited
+ © 2013-2019 Red Hat, Inc
+ © 2016 Free Software Foundation, Inc.
+ © 2016 Piotr Drag
+ © 2016 Aviary.pl
+ © 2017 Jan Alexander Steffens
+ © 2018-2021 Igalia S.L.
+ © 2022 Aleix Pol Gonzalez
+ © 2022 Endless OS Foundation, LLC
+ © 2022 Georges Basile Stavracas Neto
+License: LGPL-2+
+
+Files:
+ doc/website/*
+Copyright: none claimed
+License: CC0-1.0
+
+Files:
+ src/flatpak-instance.*
+Copyright:
+ © 2018 Red Hat, Inc
+License: LGPL-2.1+
+
+Files:
+ debian/*
+Copyright:
+ © 2016-2018 Simon McVittie
+ © 2016-2018 Collabora Ltd.
+License: LGPL-2+
+
+License: CC0-1.0
+ On Debian systems, the full text of the Creative Commons Zero 1.0 Universal
+ public domain grant can be found in '/usr/share/common-licenses/CC0-1.0'.
+
+License: LGPL-2+
+ This library 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 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+Comment:
+ On Debian systems, the full text of the GNU Lesser General Public License
+ version 2.1 can be found in the file '/usr/share/common-licenses/LGPL-2.1'.
+
+License: LGPL-2.1+
+ This library 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+Comment:
+ On Debian systems, the full text of the GNU Lesser General Public License
+ version 2.1 can be found in the file '/usr/share/common-licenses/LGPL-2.1'.
diff --git a/debian/gbp.conf b/debian/gbp.conf
new file mode 100644
index 0000000..40b834b
--- /dev/null
+++ b/debian/gbp.conf
@@ -0,0 +1,8 @@
+[DEFAULT]
+pristine-tar = True
+compression = xz
+debian-branch = ubuntu/latest
+debian-tag = ubuntu/%(version)s
+upstream-branch = upstream/latest
+patch-numbers = False
+upstream-vcs-tag = %(version)s
diff --git a/debian/not-installed b/debian/not-installed
new file mode 100644
index 0000000..7b5d0e4
--- /dev/null
+++ b/debian/not-installed
@@ -0,0 +1 @@
+usr/share/doc/xdg-desktop-portal/redirect.html
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..edf4c72
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1 @@
+webextensions-portal.patch
diff --git a/debian/patches/webextensions-portal.patch b/debian/patches/webextensions-portal.patch
new file mode 100644
index 0000000..bb2f277
--- /dev/null
+++ b/debian/patches/webextensions-portal.patch
@@ -0,0 +1,1758 @@
+From: James Henstridge <james at jamesh.id.au>
+Date: Tue, 1 Feb 2022 20:12:49 +0800
+Subject: webextensions: add a portal for managing WebExtensions native
+ messaging servers.
+
+This is intended to provide a way for a confined web browser to start
+native code helpers for their extensions. At present it can start the
+servers installed on the host system. But in future this could be
+extended to cover sandboxed native messaging servers too.
+
+Origin: https://github.com/flatpak/xdg-desktop-portal/pull/705
+Last-Update: 2023-07-06
+---
+ data/meson.build                                   |   1 +
+ data/org.freedesktop.portal.WebExtensions.xml      | 130 ++++
+ meson.build                                        |   3 +
+ src/meson.build                                    |   1 +
+ src/request.c                                      |  12 +
+ src/web-extensions.c                               | 719 +++++++++++++++++++++
+ src/web-extensions.h                               |  24 +
+ src/xdg-desktop-portal.c                           |  11 +
+ tests/meson.build                                  |   3 +
+ tests/native-messaging-hosts/meson.build           |   6 +
+ .../org.example.testing.json                       |   9 +
+ tests/test-portals.c                               |   7 +
+ tests/web-extensions.c                             | 610 +++++++++++++++++
+ tests/web-extensions.h                             |   2 +
+ 14 files changed, 1538 insertions(+)
+ create mode 100644 data/org.freedesktop.portal.WebExtensions.xml
+ create mode 100644 src/web-extensions.c
+ create mode 100644 src/web-extensions.h
+ create mode 100644 tests/native-messaging-hosts/meson.build
+ create mode 100644 tests/native-messaging-hosts/org.example.testing.json
+ create mode 100644 tests/web-extensions.c
+ create mode 100644 tests/web-extensions.h
+
+diff --git a/data/meson.build b/data/meson.build
+index eea49ad..63ea5fb 100644
+--- a/data/meson.build
++++ b/data/meson.build
+@@ -37,6 +37,7 @@ portal_sources = files(
+   'org.freedesktop.portal.Settings.xml',
+   'org.freedesktop.portal.Trash.xml',
+   'org.freedesktop.portal.Wallpaper.xml',
++  'org.freedesktop.portal.WebExtensions.xml',
+ )
+ 
+ portal_impl_sources = files(
+diff --git a/data/org.freedesktop.portal.WebExtensions.xml b/data/org.freedesktop.portal.WebExtensions.xml
+new file mode 100644
+index 0000000..e4ce12c
+--- /dev/null
++++ b/data/org.freedesktop.portal.WebExtensions.xml
+@@ -0,0 +1,130 @@
++<?xml version="1.0"?>
++<!--
++ Copyright (C) 2022 Canonical Ltd
++
++ This library 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 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 <http://www.gnu.org/licenses/>.
++-->
++
++<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
++  <!--
++      org.freedesktop.portal.WebExtensions:
++      @short_description: WebExtensions portal
++
++      The WebExtensions portal allows sandboxed web browsers to start
++      native messaging servers installed on the host system.
++
++      This documentation describes version 1 of this interface.
++  -->
++  <interface name="org.freedesktop.portal.WebExtensions">
++    <!--
++        CreateSession:
++        @options: Vardict with optional further information
++        @session_handle: Object path for the #org.freedesktop.portal.Session created by this call.
++
++        Create a web extensions session. A successfully created
++        session can at any time be closed using
++        org.freedesktop.portal.Session::Close, or may at any time be
++        closed by the portal implementation, which will be signalled
++        via org.freedesktop.portal.Session::Closed.
++
++        Supported keys in the @options vardict include:
++        <variablelist>
++          <varlistentry>
++            <term>session_handle_token s</term>
++            <listitem><para>
++              A string that will be used as the last element of the session handle. Must be a valid
++              object path element. See the #org.freedesktop.portal.Session documentation for
++              more information about the session handle.
++            </para></listitem>
++          </varlistentry>
++        </variablelist>
++    -->
++    <method name="CreateSession">
++      <arg type="a{sv}" name="options" direction="in"/>
++      <arg type="o" name="session_handle" direction="out"/>
++    </method>
++    <!--
++        GetManifest:
++        @session_handle: Object path for the #org.freedesktop.portal.Session object
++        @name: name of the native messaging server
++        @extension_or_origin: extension ID or origin URI identifying the extension
++        @json_manifest: the JSON manifest for the native messaging server
++
++        Return the JSON manifest of the native messaging server that
++        Start would invoke.
++    -->
++    <method name="GetManifest">
++      <arg type="o" name="session_handle" direction="in"/>
++      <arg type="s" name="name" direction="in"/>
++      <arg type="s" name="extension_or_origin" direction="in"/>
++      <arg type="s" name="json_manifest" direction="out"/>
++    </method>
++    <!--
++        Start:
++        @session_handle: Object path for the #org.freedesktop.portal.Session object
++        @name: name of the native messaging server
++        @extension_or_origin: extension ID or origin URI identifying the extension
++        @options: Vardict with optional further information
++        @handle: Object path for the #org.freedesktop.portal.Request object representing this call
++
++        Start the named native messaging server. The caller must
++        indicate the requesting web extension (either by extension ID
++        for Firefox, or origin URI for Chrome), which will be matched
++        against the server's access control list.
++
++        If the server can't be started, or invalid data is provided,
++        the session will be closed.
++
++        Supported keys in the @options vardict include:
++        <variablelist>
++          <varlistentry>
++            <term>handle_token s</term>
++            <listitem><para>
++              A string that will be used as the last element of the @handle. Must be a valid
++              object path element. See the #org.freedesktop.portal.Request documentation for
++              more information about the @handle.
++            </para></listitem>
++          </varlistentry>
++        </variablelist>
++    -->
++    <method name="Start">
++      <arg type="o" name="session_handle" direction="in"/>
++      <arg type="s" name="name" direction="in"/>
++      <arg type="s" name="extension_or_origin" direction="in"/>
++      <arg type="a{sv}" name="options" direction="in"/>
++      <arg type="o" name="handle" direction="out"/>
++    </method>
++    <!--
++        GetPipes:
++        @session_handle: Object path for the #org.freedesktop.portal.Session object
++        @options: Vardict with optional further information
++        @stdin: File descriptor representing the server's stdin.
++        @stdout: File descriptor representing the server's stdout.
++        @stderr: File descriptor representing the server's stderr.
++
++        Retrieve file descriptors for the native messaging server
++        identified by the session. This method should only be called
++        after the Start request recveives a successful response.
++    -->
++    <method name="GetPipes">
++      <annotation name="org.gtk.GDBus.C.UnixFD" value="true"/>
++      <arg type="o" name="session_handle" direction="in"/>
++      <arg type="a{sv}" name="options" direction="in"/>
++      <arg type="h" name="stdin" direction="out"/>
++      <arg type="h" name="stdout" direction="out"/>
++      <arg type="h" name="stderr" direction="out"/>
++    </method>
++    <property name="version" type="u" access="read"/>
++  </interface>
++</node>
+diff --git a/meson.build b/meson.build
+index b25f9ef..8f95fa2 100644
+--- a/meson.build
++++ b/meson.build
+@@ -11,9 +11,11 @@ project(
+ 
+ prefix = get_option('prefix')
+ datadir = prefix / get_option('datadir')
++libdir = prefix / get_option('libdir')
+ libexecdir = prefix / get_option('libexecdir')
+ sysconfdir = prefix / get_option('sysconfdir')
+ localedir = prefix / get_option('localedir')
++sysconfdir = prefix / get_option('sysconfdir')
+ dbus_service_dir = get_option('dbus-service-dir')
+ if dbus_service_dir == ''
+     dbus_service_dir = prefix /  datadir / 'dbus-1' / 'services'
+@@ -78,6 +80,7 @@ config_h = configuration_data()
+ config_h.set('_GNU_SOURCE', 1)
+ config_h.set_quoted('G_LOG_DOMAIN', 'xdg-desktop-portal')
+ config_h.set_quoted('DATADIR', datadir)
++config_h.set_quoted('LIBDIR', libdir)
+ config_h.set_quoted('LIBEXECDIR', libexecdir)
+ config_h.set_quoted('LOCALEDIR', localedir)
+ config_h.set_quoted('SYSCONFDIR', sysconfdir)
+diff --git a/src/meson.build b/src/meson.build
+index 44d2d51..d01adad 100644
+--- a/src/meson.build
++++ b/src/meson.build
+@@ -84,6 +84,7 @@ xdg_desktop_portal_sources = files(
+   'settings.c',
+   'trash.c',
+   'wallpaper.c',
++  'web-extensions.c',
+   'xdg-desktop-portal.c',
+   'xdp-utils.c',
+ )
+diff --git a/src/request.c b/src/request.c
+index 4216696..73824c8 100644
+--- a/src/request.c
++++ b/src/request.c
+@@ -371,6 +371,18 @@ get_token (GDBusMethodInvocation *invocation)
+                      interface, method, G_STRLOC);
+         }
+     }
++  else if (strcmp (interface, "org.freedesktop.portal.WebExtensions") == 0)
++    {
++      if (strcmp (method, "Start") == 0)
++        {
++          options = g_variant_get_child_value (parameters, 3);
++        }
++      else
++        {
++          g_warning ("Support for %s::%s missing in %s",
++                     interface, method, G_STRLOC);
++        }
++    }
+   else
+     {
+       g_print ("Support for %s missing in " G_STRLOC, interface);
+diff --git a/src/web-extensions.c b/src/web-extensions.c
+new file mode 100644
+index 0000000..181ed21
+--- /dev/null
++++ b/src/web-extensions.c
+@@ -0,0 +1,719 @@
++/*
++ * Copyright © 2022 Canonical Ltd
++ *
++ * 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 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 <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#include "config.h"
++
++#include <stdint.h>
++#include <sys/types.h>
++#include <sys/wait.h>
++#include <glib/gi18n.h>
++#include <gio/gunixfdlist.h>
++#include <json-glib/json-glib.h>
++
++#include "session.h"
++#include "web-extensions.h"
++#include "request.h"
++#include "permissions.h"
++#include "xdp-dbus.h"
++#include "xdp-impl-dbus.h"
++#include "xdp-utils.h"
++
++#define PERMISSION_TABLE "webextensions"
++
++typedef struct _WebExtensions WebExtensions;
++typedef struct _WebExtensionsClass WebExtensionsClass;
++
++struct _WebExtensions
++{
++  XdpDbusWebExtensionsSkeleton parent_instance;
++};
++
++struct _WebExtensionsClass
++{
++  XdpDbusWebExtensionsSkeletonClass parent_class;
++};
++
++static XdpDbusImplAccess *access_impl;
++static WebExtensions *web_extensions;
++
++GType web_extensions_get_type (void);
++static void web_extensions_iface_init (XdpDbusWebExtensionsIface *iface);
++
++G_DEFINE_TYPE_WITH_CODE (WebExtensions, web_extensions, XDP_DBUS_TYPE_WEB_EXTENSIONS_SKELETON,
++                         G_IMPLEMENT_INTERFACE (XDP_DBUS_TYPE_WEB_EXTENSIONS,
++                                                web_extensions_iface_init));
++
++typedef enum _WebExtensionsSessionState
++{
++  WEB_EXTENSIONS_SESSION_STATE_INIT,
++  WEB_EXTENSIONS_SESSION_STATE_STARTING,
++  WEB_EXTENSIONS_SESSION_STATE_STARTED,
++  WEB_EXTENSIONS_SESSION_STATE_CLOSED,
++} WebExtensionsSessionState;
++
++typedef struct _WebExtensionsSession
++{
++  Session parent;
++
++  WebExtensionsSessionState state;
++
++  GPid child_pid;
++  guint child_watch_id;
++
++  int standard_input;
++  int standard_output;
++  int standard_error;
++} WebExtensionsSession;
++
++typedef struct _WebExtensionsSessionClass
++{
++  SessionClass parent_class;
++} WebExtensionsSessionClass;
++
++GType web_extensions_session_get_type (void);
++
++G_DEFINE_TYPE (WebExtensionsSession, web_extensions_session, session_get_type ());
++
++static void
++web_extensions_session_init (WebExtensionsSession *session)
++{
++  session->child_pid = -1;
++  session->child_watch_id = 0;
++
++  session->standard_input = -1;
++  session->standard_output = -1;
++  session->standard_error = -1;
++}
++
++static void
++web_extensions_session_close (Session *session)
++{
++  WebExtensionsSession *web_extensions_session = (WebExtensionsSession *)session;
++
++  if (web_extensions_session->state == WEB_EXTENSIONS_SESSION_STATE_CLOSED) return;
++
++  web_extensions_session->state = WEB_EXTENSIONS_SESSION_STATE_CLOSED;
++  if (web_extensions_session->child_watch_id != 0)
++    {
++      g_source_remove (web_extensions_session->child_watch_id);
++      web_extensions_session->child_watch_id = 0;
++    }
++
++  if (web_extensions_session->child_pid > 0)
++    {
++      kill (web_extensions_session->child_pid, SIGTERM);
++      waitpid (web_extensions_session->child_pid, NULL, 0);
++      g_spawn_close_pid (web_extensions_session->child_pid);
++      web_extensions_session->child_pid = -1;
++    }
++
++  if (web_extensions_session->standard_input >= 0)
++    {
++      close (web_extensions_session->standard_input);
++      web_extensions_session->standard_input = -1;
++    }
++  if (web_extensions_session->standard_output >= 0)
++    {
++      close (web_extensions_session->standard_output);
++      web_extensions_session->standard_output = -1;
++    }
++  if (web_extensions_session->standard_error >= 0)
++    {
++      close (web_extensions_session->standard_error);
++      web_extensions_session->standard_error = -1;
++    }
++}
++
++static void
++web_extensions_session_finalize (GObject *object)
++{
++  Session *session = (Session *)object;
++
++  web_extensions_session_close (session);
++  G_OBJECT_CLASS (web_extensions_session_parent_class)->finalize (object);
++}
++
++static void
++web_extensions_session_class_init (WebExtensionsSessionClass *klass)
++{
++  GObjectClass *object_class;
++  SessionClass *session_class;
++
++  object_class = G_OBJECT_CLASS (klass);
++  object_class->finalize = web_extensions_session_finalize;
++
++  session_class = (SessionClass *)klass;
++  session_class->close = web_extensions_session_close;
++}
++
++static WebExtensionsSession *
++web_extensions_session_new (GVariant *options,
++                            Call *call,
++                            GDBusConnection *connection,
++                            GError **error)
++{
++  Session *session;
++  const char *session_token;
++
++  session_token = lookup_session_token (options);
++  session = g_initable_new (web_extensions_session_get_type (), NULL, error,
++                            "sender", call->sender,
++                            "app-id", xdp_app_info_get_id (call->app_info),
++                            "token", session_token,
++                            "connection", connection,
++                            NULL);
++
++  if (session)
++    g_debug ("webextensions session owned by '%s' created", session->sender);
++
++  return (WebExtensionsSession *)session;
++}
++
++static gboolean
++handle_create_session (XdpDbusWebExtensions *object,
++                       GDBusMethodInvocation *invocation,
++                       GVariant *arg_options)
++{
++  Call *call = call_from_invocation (invocation);
++  GDBusConnection *connection = g_dbus_method_invocation_get_connection (invocation);
++  g_autoptr(GError) error = NULL;
++  Session *session;
++
++  session = (Session *)web_extensions_session_new (arg_options, call, connection, &error);
++  if (!session)
++    {
++      g_dbus_method_invocation_return_gerror (invocation, error);
++      return TRUE;
++    }
++  if (!session_export (session, &error))
++    {
++      g_dbus_method_invocation_return_gerror (invocation, error);
++      session_close (session, FALSE);
++      return TRUE;
++    }
++  session_register (session);
++
++  xdp_dbus_web_extensions_complete_create_session (object, invocation, session->id);
++
++  return TRUE;
++}
++
++static void
++on_server_exited (GPid pid,
++                  gint status,
++                  gpointer user_data)
++{
++  Session *session = user_data;
++  WebExtensionsSession *web_extensions_session = (WebExtensionsSession *)session;
++
++  SESSION_AUTOLOCK (session);
++  web_extensions_session->child_pid = -1;
++  web_extensions_session->child_watch_id = 0;
++  session_close (session, TRUE);
++}
++
++static gboolean
++array_contains (JsonArray *array,
++                const char *value)
++{
++  guint length, i;
++
++  if (array == NULL)
++    return FALSE;
++
++  length = json_array_get_length (array);
++  for (i = 0; i < length; i++)
++    {
++      const char *element = json_array_get_string_element (array, i);
++      if (g_strcmp0 (element, value) == 0)
++        return TRUE;
++    }
++  return FALSE;
++}
++
++static gboolean
++is_valid_name (const char *name)
++{
++  /* This regexp comes from the Mozilla documentation on valid native
++     messaging server names:
++
++     https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_manifests#native_messaging_manifests
++
++     That is, one or more dot-separated groups composed of
++     alphanumeric characters and underscores.
++  */
++  return g_regex_match_simple ("^\\w+(\\.\\w+)*$", name, 0, 0);
++}
++
++static GStrv
++get_manifest_search_path (void)
++{
++  const char *hosts_path_str;
++  g_autoptr(GPtrArray) search_path = NULL;
++
++  hosts_path_str = g_getenv ("XDG_DESKTOP_PORTAL_WEB_EXTENSIONS_PATH");
++  if (hosts_path_str != NULL)
++    return g_strsplit (hosts_path_str, ":", -1);
++
++  /* By default, use the native messaging search paths of Firefox,
++   * Chrome, and Chromium, as documented here:
++   *
++   * https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_manifests#manifest_location
++   * https://developer.chrome.com/docs/apps/nativeMessaging/#native-messaging-host-location
++   */
++
++  search_path = g_ptr_array_new_with_free_func (g_free);
++  /* Add per-user directories */
++  g_ptr_array_add (search_path, g_build_filename (g_get_home_dir (), ".mozilla", "native-messaging-hosts", NULL));
++  g_ptr_array_add (search_path, g_build_filename (g_get_user_config_dir (), "google-chrome", "NativeMessagingHosts", NULL));
++  g_ptr_array_add (search_path, g_build_filename (g_get_user_config_dir (), "chromium", "NativeMessagingHosts", NULL));
++
++  /* Add system wide directories */
++  g_ptr_array_add (search_path, g_strdup ("/usr/lib/mozilla/native-messaging-hosts"));
++  g_ptr_array_add (search_path, g_strdup ("/usr/lib64/mozilla/native-messaging-hosts"));
++  g_ptr_array_add (search_path, g_strdup ("/etc/opt/chrome/native-messaging-hosts"));
++  g_ptr_array_add (search_path, g_strdup ("/etc/chromium/native-messaging-hosts"));
++
++  /* And the same for xdg-desktop-portal's configured prefix */
++  g_ptr_array_add (search_path, g_strdup (LIBDIR "mozilla/native-messaging-hosts"));
++  g_ptr_array_add (search_path, g_strdup (SYSCONFDIR "opt/chrome/native-messaging-hosts"));
++  g_ptr_array_add (search_path, g_strdup (SYSCONFDIR "chromium/native-messaging-hosts"));
++
++  g_ptr_array_add (search_path, NULL);
++  return (GStrv)g_ptr_array_free (g_steal_pointer (&search_path), FALSE);
++}
++
++static char *
++find_server (const char *server_name,
++             const char *extension_or_origin,
++             char **out_server_description,
++             char **out_json_manifest,
++             GError **error)
++{
++  g_auto(GStrv) search_path = NULL;
++  g_autoptr(JsonParser) parser = NULL;
++  g_autofree char *metadata_basename = NULL;
++  int i;
++
++  /* Check that the we have a valid native messaging host name */
++  if (!is_valid_name (server_name))
++    {
++      g_set_error (error,
++                   XDG_DESKTOP_PORTAL_ERROR,
++                   XDG_DESKTOP_PORTAL_ERROR_INVALID_ARGUMENT,
++                   "Invalid native messaging server name");
++      return NULL;
++    }
++
++  search_path = get_manifest_search_path ();
++  parser = json_parser_new ();
++  metadata_basename = g_strconcat (server_name, ".json", NULL);
++
++  for (i = 0; search_path[i] != NULL; i++)
++    {
++      g_autofree char *metadata_filename = NULL;
++      g_autoptr(GError) load_error = NULL;
++      JsonObject *metadata_root;
++
++      metadata_filename = g_build_filename (search_path[i], metadata_basename, NULL);
++      if (!json_parser_load_from_file (parser, metadata_filename, &load_error))
++        {
++          /* If the file doesn't exist, continue searching. Error out
++             on anything else. */
++          if (g_error_matches (load_error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
++            continue;
++          g_propagate_error (error, g_steal_pointer (&load_error));
++          return NULL;
++        }
++
++      metadata_root = json_node_get_object (json_parser_get_root (parser));
++
++      /* Skip if metadata contains an unexpected name */
++      if (g_strcmp0 (json_object_get_string_member (metadata_root, "name"), server_name) != 0)
++        continue;
++
++      /* Skip if this is not a "stdio" type native messaging server */
++      if (g_strcmp0 (json_object_get_string_member (metadata_root, "type"), "stdio") != 0)
++        continue;
++
++      /* Skip if this server isn't available to the extension. Note
++       * that this ID is provided by the sandboxed browser, so this
++       * check is just to help implement its security policy. */
++      if (!array_contains (json_object_get_array_member (metadata_root, "allowed_extensions"), extension_or_origin) &&
++          !array_contains (json_object_get_array_member (metadata_root, "allowed_origins"), extension_or_origin))
++        continue;
++
++      /* Server matches: return its executable path and description */
++      if (out_server_description != NULL)
++          *out_server_description = g_strdup (json_object_get_string_member (metadata_root, "description"));
++      if (out_json_manifest != NULL)
++          *out_json_manifest = json_to_string (json_parser_get_root (parser), FALSE);
++      return g_strdup (json_object_get_string_member (metadata_root, "path"));
++    }
++
++  g_set_error (error,
++               XDG_DESKTOP_PORTAL_ERROR,
++               XDG_DESKTOP_PORTAL_ERROR_NOT_FOUND,
++               "Could not find native messaging server");
++  return NULL;
++}
++
++static gboolean
++handle_get_manifest (XdpDbusWebExtensions *object,
++                     GDBusMethodInvocation *invocation,
++                     const char *arg_session_handle,
++                     const char *arg_name,
++                     const char *arg_extension_or_origin)
++{
++  Call *call = call_from_invocation (invocation);
++  Session *session;
++  WebExtensionsSession *web_extensions_session;
++  g_autofree char *server_path = NULL;
++  g_autofree char *json_manifest = NULL;
++  g_autoptr(GError) error = NULL;
++
++  session = acquire_session_from_call (arg_session_handle, call);
++  if (!session)
++    {
++      g_dbus_method_invocation_return_error (invocation,
++                                             G_DBUS_ERROR,
++                                             G_DBUS_ERROR_ACCESS_DENIED,
++                                             "Invalid session");
++      return TRUE;
++    }
++
++  SESSION_AUTOLOCK_UNREF (session);
++  web_extensions_session = (WebExtensionsSession *)session;
++
++  if (web_extensions_session->state != WEB_EXTENSIONS_SESSION_STATE_INIT)
++    {
++      g_dbus_method_invocation_return_error (invocation,
++                                             G_DBUS_ERROR,
++                                             G_DBUS_ERROR_FAILED,
++                                             "Session already started");
++      return TRUE;
++    }
++
++  server_path = find_server (arg_name, arg_extension_or_origin,
++                             NULL, &json_manifest, &error);
++  if (!server_path)
++    {
++      g_dbus_method_invocation_return_gerror (invocation, error);
++      return TRUE;
++    }
++
++  xdp_dbus_web_extensions_complete_get_manifest (object, invocation, json_manifest);
++  return TRUE;
++}
++
++static void
++handle_start_in_thread (GTask *task,
++                        gpointer source_object,
++                        gpointer task_data,
++                        GCancellable *cancellable)
++{
++  Request *request = (Request *)task_data;
++  Session *session;
++  WebExtensionsSession *web_extensions_session;
++  const char *arg_name;
++  const char *arg_extension_or_origin;
++  const char *app_id;
++  g_autofree char *server_path = NULL;
++  g_autofree char *server_description = NULL;
++  guint response = XDG_DESKTOP_PORTAL_RESPONSE_OTHER;
++  gboolean should_close_session;
++  Permission permission;
++  gboolean allowed;
++  char *argv[] = {NULL, NULL};
++  g_autoptr(GError) error = NULL;
++
++  REQUEST_AUTOLOCK (request);
++  session = g_object_get_data (G_OBJECT (request), "session");
++  SESSION_AUTOLOCK_UNREF (g_object_ref (session));
++  g_object_set_data (G_OBJECT (request), "session", NULL);
++  web_extensions_session = (WebExtensionsSession *)session;
++
++  if (!request->exported || web_extensions_session->state != WEB_EXTENSIONS_SESSION_STATE_STARTING)
++    goto out;
++
++  arg_name = g_object_get_data (G_OBJECT (request), "name");
++  arg_extension_or_origin = g_object_get_data (G_OBJECT (request), "extension-or-origin");
++
++  server_path = find_server (arg_name, arg_extension_or_origin, &server_description, NULL, &error);
++  if (server_path == NULL)
++    {
++      g_warning ("Could not find WebExtensions backend: %s", error->message);
++      fflush(stderr);
++      fflush(stdout);
++      goto out;
++    }
++
++  app_id = xdp_app_info_get_id (request->app_info);
++  permission = get_permission_sync (app_id, PERMISSION_TABLE, arg_name);
++  if (permission == PERMISSION_ASK || permission == PERMISSION_UNSET)
++    {
++      guint access_response = 2;
++      g_autoptr(GVariant) access_results = NULL;
++      GVariantBuilder opt_builder;
++      g_autoptr(GAppInfo) info = NULL;
++      const char *display_name;
++      g_autofree gchar *app_info_id = NULL;
++      g_autofree gchar *title = NULL;
++      g_autofree gchar *subtitle = NULL;
++      g_autofree gchar *body = NULL;
++
++      info = xdp_app_info_load_app_info (request->app_info);
++      if (info)
++        {
++          g_auto(GStrv) app_id_components = g_strsplit (g_app_info_get_id (info), ".desktop", 2);
++          app_info_id = g_strdup (app_id_components[0]);
++        }
++      display_name = info ? g_app_info_get_display_name (info) : app_id;
++      title = g_strdup_printf (_("Allow %s to start WebExtension backend?"), display_name);
++      subtitle = g_strdup_printf (_("%s is requesting to launch \"%s\" (%s)."), display_name, server_description, arg_name);
++      body = g_strdup (_("This permission can be changed at any time from the privacy settings."));
++
++      g_variant_builder_init (&opt_builder, G_VARIANT_TYPE_VARDICT);
++      g_variant_builder_add (&opt_builder, "{sv}", "deny_label", g_variant_new_string (_("Don't allow")));
++      g_variant_builder_add (&opt_builder, "{sv}", "grant_label", g_variant_new_string (_("Allow")));
++      if (!xdp_dbus_impl_access_call_access_dialog_sync (access_impl,
++                                                         request->id,
++                                                         app_info_id ? app_info_id : app_id,
++                                                         "",
++                                                         title,
++                                                         subtitle,
++                                                         body,
++                                                         g_variant_builder_end (&opt_builder),
++                                                         &access_response,
++                                                         &access_results,
++                                                         NULL,
++                                                         &error))
++        {
++          g_warning ("AccessDialog call failed: %s", error->message);
++          g_clear_error (&error);
++        }
++      allowed = access_response == 0;
++
++      if (permission == PERMISSION_UNSET)
++        set_permission_sync (app_id, PERMISSION_TABLE, arg_name, allowed ? PERMISSION_YES : PERMISSION_NO);
++    }
++  else
++    {
++      allowed = permission == PERMISSION_YES ? TRUE : FALSE;
++    }
++
++  if (!allowed)
++    {
++      response = XDG_DESKTOP_PORTAL_RESPONSE_CANCELLED;
++      goto out;
++    }
++
++  argv[0] = server_path;
++  if (!g_spawn_async_with_pipes (NULL, /* working_directory */
++                                 argv,
++                                 NULL, /* envp */
++                                 G_SPAWN_DO_NOT_REAP_CHILD,
++                                 NULL, /* child_setup */
++                                 NULL, /* user_data */
++                                 &web_extensions_session->child_pid,
++                                 &web_extensions_session->standard_input,
++                                 &web_extensions_session->standard_output,
++                                 &web_extensions_session->standard_error,
++                                 &error))
++    {
++      web_extensions_session->child_pid = -1;
++      goto out;
++    }
++
++  web_extensions_session->child_watch_id = g_child_watch_add_full (G_PRIORITY_DEFAULT,
++                                                                   web_extensions_session->child_pid,
++                                                                   on_server_exited,
++                                                                   g_object_ref (web_extensions_session),
++                                                                   g_object_unref);
++  web_extensions_session->state = WEB_EXTENSIONS_SESSION_STATE_STARTED;
++
++  response = XDG_DESKTOP_PORTAL_RESPONSE_SUCCESS;
++
++out:
++  should_close_session = !request->exported || response != XDG_DESKTOP_PORTAL_RESPONSE_SUCCESS;
++
++  if (request->exported)
++    {
++      GVariantBuilder results;
++
++      g_variant_builder_init (&results, G_VARIANT_TYPE_VARDICT);
++      xdp_dbus_request_emit_response (XDP_DBUS_REQUEST (request), response, g_variant_builder_end (&results));
++      request_unexport (request);
++    }
++
++  if (should_close_session)
++    session_close (session, TRUE);
++}
++
++static gboolean
++handle_start (XdpDbusWebExtensions *object,
++              GDBusMethodInvocation *invocation,
++              const char *arg_session_handle,
++              const char *arg_name,
++              const char *arg_extension_or_origin,
++              GVariant *arg_options)
++{
++  Request *request = request_from_invocation (invocation);
++  Session *session;
++  WebExtensionsSession *web_extensions_session;
++  g_autoptr(GTask) task = NULL;
++
++  REQUEST_AUTOLOCK (request);
++
++  session = acquire_session (arg_session_handle, request);
++  if (!session)
++    {
++      g_dbus_method_invocation_return_error (invocation,
++                                             G_DBUS_ERROR,
++                                             G_DBUS_ERROR_ACCESS_DENIED,
++                                             "Invalid session");
++      return TRUE;
++    }
++
++  SESSION_AUTOLOCK_UNREF (session);
++  web_extensions_session = (WebExtensionsSession *)session;
++
++  if (web_extensions_session->state != WEB_EXTENSIONS_SESSION_STATE_INIT)
++    {
++      g_dbus_method_invocation_return_error (invocation,
++                                             G_DBUS_ERROR,
++                                             G_DBUS_ERROR_FAILED,
++                                             "Session already started");
++      return TRUE;
++    }
++
++  web_extensions_session->state = WEB_EXTENSIONS_SESSION_STATE_STARTING;
++  g_object_set_data_full (G_OBJECT (request), "session", g_object_ref (session), g_object_unref);
++  g_object_set_data_full (G_OBJECT (request), "name", g_strdup (arg_name), g_free);
++  g_object_set_data_full (G_OBJECT (request), "extension-or-origin", g_strdup (arg_extension_or_origin), g_free);
++
++  request_export (request, g_dbus_method_invocation_get_connection (invocation));
++  xdp_dbus_web_extensions_complete_start (object, invocation, request->id);
++
++  task = g_task_new (object, NULL, NULL, NULL);
++  g_task_set_task_data (task, g_object_ref (request), g_object_unref);
++  g_task_run_in_thread (task, handle_start_in_thread);
++
++  return TRUE;
++}
++
++
++static gboolean
++handle_get_pipes (XdpDbusWebExtensions *object,
++                  GDBusMethodInvocation *invocation,
++                  GUnixFDList *fd_list,
++                  const char *arg_session_handle,
++                  GVariant *arg_options)
++{
++  Call *call = call_from_invocation (invocation);
++  Session *session;
++  WebExtensionsSession *web_extensions_session;
++  int fds[3];
++  g_autoptr(GUnixFDList) out_fd_list = NULL;
++
++  session = acquire_session_from_call (arg_session_handle, call);
++  if (!session)
++    {
++      g_dbus_method_invocation_return_error (invocation,
++                                             G_DBUS_ERROR,
++                                             G_DBUS_ERROR_ACCESS_DENIED,
++                                             "Invalid session");
++      return TRUE;
++    }
++
++  SESSION_AUTOLOCK_UNREF (session);
++  web_extensions_session = (WebExtensionsSession *)session;
++
++  if (web_extensions_session->state != WEB_EXTENSIONS_SESSION_STATE_STARTED)
++    {
++      g_dbus_method_invocation_return_error (invocation,
++                                             G_DBUS_ERROR,
++                                             G_DBUS_ERROR_FAILED,
++                                             "Session not started");
++      return TRUE;
++    }
++
++  if (web_extensions_session->standard_input < 0 ||
++      web_extensions_session->standard_output < 0 ||
++      web_extensions_session->standard_error < 0)
++    {
++      g_dbus_method_invocation_return_error (invocation,
++                                             G_DBUS_ERROR,
++                                             G_DBUS_ERROR_FAILED,
++                                             "GetPipes already called");
++      return TRUE;
++    }
++
++  fds[0] = web_extensions_session->standard_input;
++  fds[1] = web_extensions_session->standard_output;
++  fds[2] = web_extensions_session->standard_error;
++  out_fd_list = g_unix_fd_list_new_from_array (fds, G_N_ELEMENTS (fds));
++  /* out_fd_list now owns the file descriptors */
++  web_extensions_session->standard_input = -1;
++  web_extensions_session->standard_output = -1;
++  web_extensions_session->standard_error = -1;
++
++  xdp_dbus_web_extensions_complete_get_pipes (object, invocation, out_fd_list,
++                                              g_variant_new_handle (0),
++                                              g_variant_new_handle (1),
++                                              g_variant_new_handle (2));
++  return TRUE;
++}
++
++static void
++web_extensions_iface_init (XdpDbusWebExtensionsIface *iface)
++{
++  iface->handle_create_session = handle_create_session;
++  iface->handle_get_manifest = handle_get_manifest;
++  iface->handle_start = handle_start;
++  iface->handle_get_pipes = handle_get_pipes;
++}
++
++static void
++web_extensions_init (WebExtensions *web_extensions)
++{
++  xdp_dbus_web_extensions_set_version (XDP_DBUS_WEB_EXTENSIONS (web_extensions), 1);
++}
++
++static void
++web_extensions_class_init (WebExtensionsClass *klass)
++{
++}
++
++GDBusInterfaceSkeleton *
++web_extensions_create (GDBusConnection *connection,
++                       const char *dbus_name_access)
++{
++  g_autoptr(GError) error = NULL;
++
++  web_extensions = g_object_new (web_extensions_get_type (), NULL);
++
++  access_impl = xdp_dbus_impl_access_proxy_new_sync (connection,
++                                                     G_DBUS_PROXY_FLAGS_NONE,
++                                                     dbus_name_access,
++                                                     DESKTOP_PORTAL_OBJECT_PATH,
++                                                     NULL,
++                                                     &error);
++
++  return G_DBUS_INTERFACE_SKELETON (web_extensions);
++}
+diff --git a/src/web-extensions.h b/src/web-extensions.h
+new file mode 100644
+index 0000000..72b947a
+--- /dev/null
++++ b/src/web-extensions.h
+@@ -0,0 +1,24 @@
++/*
++ * Copyright © 2022 Canonical Ltd
++ *
++ * 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 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 <http://www.gnu.org/licenses/>.
++ *
++ */
++
++#pragma once
++
++#include <gio/gio.h>
++
++GDBusInterfaceSkeleton *web_extensions_create (GDBusConnection *connection,
++                                               const char *access_dbus_name);
+diff --git a/src/xdg-desktop-portal.c b/src/xdg-desktop-portal.c
+index 1577525..4ac2238 100644
+--- a/src/xdg-desktop-portal.c
++++ b/src/xdg-desktop-portal.c
+@@ -63,6 +63,7 @@
+ #include "settings.h"
+ #include "trash.h"
+ #include "wallpaper.h"
++#include "web-extensions.h"
+ 
+ static GMainLoop *loop = NULL;
+ 
+@@ -162,6 +163,13 @@ method_needs_request (GDBusMethodInvocation *invocation)
+       else
+         return TRUE;
+     }
++  else if (strcmp (interface, "org.freedesktop.portal.WebExtensions") == 0)
++    {
++      if (strcmp (method, "Start") == 0)
++        return TRUE;
++      else
++        return FALSE;
++    }
+   else
+     {
+       return TRUE;
+@@ -307,6 +315,9 @@ on_bus_acquired (GDBusConnection *connection,
+                                     device_create (connection,
+                                                    access_impl->dbus_name,
+                                                    lockdown));
++      export_portal_implementation (connection,
++                                    web_extensions_create (connection,
++                                                           access_impl->dbus_name));
+ #ifdef HAVE_GEOCLUE
+       export_portal_implementation (connection,
+                                     location_create (connection,
+diff --git a/tests/meson.build b/tests/meson.build
+index b91800f..5693db8 100644
+--- a/tests/meson.build
++++ b/tests/meson.build
+@@ -15,6 +15,7 @@ subdir('dbs')
+ subdir('portals')
+ subdir('services')
+ subdir('share')
++subdir('native-messaging-hosts')
+ 
+ test_db = executable(
+   'testdb',
+@@ -114,6 +115,7 @@ if have_libportal
+     'screenshot.c',
+     'trash.c',
+     'wallpaper.c',
++    'web-extensions.c',
+     'glib-backports.c',
+   )
+ 
+@@ -177,6 +179,7 @@ portal_tests = [
+   'screenshot',
+   'trash',
+   'wallpaper',
++  'webextensions',
+ ]
+ 
+ test_env = env_tests
+diff --git a/tests/native-messaging-hosts/meson.build b/tests/native-messaging-hosts/meson.build
+new file mode 100644
+index 0000000..726f54f
+--- /dev/null
++++ b/tests/native-messaging-hosts/meson.build
+@@ -0,0 +1,6 @@
++test_portal = configure_file(input: 'org.example.testing.json',
++    output: '@PLAINNAME@',
++    copy: true,
++    install: enable_installed_tests,
++    install_dir: installed_tests_dir / 'native-messaging-hosts',
++)
+diff --git a/tests/native-messaging-hosts/org.example.testing.json b/tests/native-messaging-hosts/org.example.testing.json
+new file mode 100644
+index 0000000..93b2f11
+--- /dev/null
++++ b/tests/native-messaging-hosts/org.example.testing.json
+@@ -0,0 +1,9 @@
++{
++  "name": "org.example.testing",
++  "description": "Test native messaging host",
++  "path": "/bin/cat",
++  "type": "stdio",
++  "allowed_extensions": [
++    "some-extension at example.org"
++  ]
++}
+diff --git a/tests/test-portals.c b/tests/test-portals.c
+index bae93a5..d9b9435 100644
+--- a/tests/test-portals.c
++++ b/tests/test-portals.c
+@@ -23,6 +23,7 @@
+ #include "screenshot.h"
+ #include "trash.h"
+ #include "wallpaper.h"
++#include "web-extensions.h"
+ #endif
+ 
+ #include "utils.h"
+@@ -136,6 +137,7 @@ global_setup (void)
+   g_autofree gchar *backends_executable = NULL;
+   g_autofree gchar *services = NULL;
+   g_autofree gchar *portal_dir = NULL;
++  g_autofree gchar *web_extensions_dir = NULL;
+   g_autofree gchar *argv0 = NULL;
+   g_autoptr(GSubprocessLauncher) launcher = NULL;
+   g_autoptr(GSubprocess) subprocess = NULL;
+@@ -266,12 +268,14 @@ global_setup (void)
+                                           NULL);
+ 
+   portal_dir = g_test_build_filename (G_TEST_BUILT, "portals", "test", NULL);
++  web_extensions_dir = g_test_build_filename (G_TEST_DIST, "native-messaging-hosts", NULL);
+ 
+   g_clear_object (&launcher);
+   launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE);
+   g_subprocess_launcher_setenv (launcher, "G_DEBUG", "fatal-criticals", TRUE);
+   g_subprocess_launcher_setenv (launcher, "DBUS_SESSION_BUS_ADDRESS", g_test_dbus_get_bus_address (dbus), TRUE);
+   g_subprocess_launcher_setenv (launcher, "XDG_DESKTOP_PORTAL_DIR", portal_dir, TRUE);
++  g_subprocess_launcher_setenv (launcher, "XDG_DESKTOP_PORTAL_WEB_EXTENSIONS_PATH", web_extensions_dir, TRUE);
+   g_subprocess_launcher_setenv (launcher, "XDG_DATA_HOME", outdir, TRUE);
+   g_subprocess_launcher_setenv (launcher, "PATH", g_getenv ("PATH"), TRUE);
+   g_subprocess_launcher_take_stdout_fd (launcher, xdup (STDERR_FILENO));
+@@ -584,6 +588,9 @@ main (int argc, char **argv)
+   g_test_add_func ("/portal/notification/bad-arg", test_notification_bad_arg);
+   g_test_add_func ("/portal/notification/bad-priority", test_notification_bad_priority);
+   g_test_add_func ("/portal/notification/bad-button", test_notification_bad_button);
++
++  g_test_add_func ("/portal/webextensions/basic", test_web_extensions_basic);
++  g_test_add_func ("/portal/webextensions/bad-name", test_web_extensions_bad_name);
+ #endif
+ 
+   global_setup ();
+diff --git a/tests/web-extensions.c b/tests/web-extensions.c
+new file mode 100644
+index 0000000..761f6d5
+--- /dev/null
++++ b/tests/web-extensions.c
+@@ -0,0 +1,610 @@
++#include <config.h>
++
++#include "web-extensions.h"
++#include "xdp-utils.h"
++
++#include <gio/gio.h>
++#include <gio/gunixfdlist.h>
++#include "xdp-impl-dbus.h"
++
++// TODO: convert these simple client wrappers to proper libportal APIs
++
++static void
++create_session_returned (GObject *object,
++                         GAsyncResult *result,
++                         gpointer data)
++{
++  g_autoptr(GTask) task = data;
++  g_autoptr(GVariant) ret = NULL;
++  GError *error = NULL;
++  g_autofree char *session_handle = NULL;
++
++  ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (object), result, &error);
++  if (!ret)
++    {
++      g_task_return_error (task, error);
++      return;
++    }
++  g_variant_get (ret, "(o)", &session_handle);
++  g_task_return_pointer (task, g_steal_pointer (&session_handle), g_free);
++}
++
++static void
++create_session (GCancellable *cancellable,
++                GAsyncReadyCallback callback,
++                gpointer data)
++{
++  g_autoptr(GTask) task = NULL;
++  g_autoptr(GDBusConnection) session_bus = NULL;
++  GError *error = NULL;
++  g_autofree char *session_token = NULL;
++  GVariantBuilder options;
++
++  task = g_task_new (NULL, cancellable, callback, data);
++
++  session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
++  if (session_bus == NULL)
++    {
++      g_task_return_error (task, error);
++      return;
++    }
++
++  session_token = g_strdup_printf ("portal%d", g_random_int_range (0, G_MAXINT));
++  g_variant_builder_init (&options, G_VARIANT_TYPE_VARDICT);
++  g_variant_builder_add (&options, "{sv}", "session_handle_token", g_variant_new_string (session_token));
++  g_dbus_connection_call (session_bus,
++                          "org.freedesktop.portal.Desktop",
++                          "/org/freedesktop/portal/desktop",
++                          "org.freedesktop.portal.WebExtensions",
++                          "CreateSession",
++                          g_variant_new ("(a{sv})", &options),
++                          NULL,
++                          G_DBUS_CALL_FLAGS_NONE,
++                          -1,
++                          cancellable,
++                          create_session_returned,
++                          g_steal_pointer (&task));
++}
++
++static char *
++create_session_finish (GAsyncResult *result, GError **error)
++{
++  return g_task_propagate_pointer (G_TASK (result), error);
++}
++
++static void
++get_manifest_returned (GObject *object,
++                       GAsyncResult *result,
++                       gpointer data)
++{
++  g_autoptr(GTask) task = data;
++  g_autoptr(GVariant) ret = NULL;
++  GError *error = NULL;
++  g_autofree char *json_manifest = NULL;
++
++  ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (object), result, &error);
++  if (!ret)
++    {
++      g_task_return_error (task, error);
++      return;
++    }
++  g_variant_get (ret, "(s)", &json_manifest);
++  g_task_return_pointer (task, g_steal_pointer (&json_manifest), g_free);
++}
++
++static void
++get_manifest (const char *session_handle,
++              const char *name,
++              const char *extension_or_origin,
++              GCancellable *cancellable,
++              GAsyncReadyCallback callback,
++              gpointer data)
++{
++  g_autoptr(GTask) task = NULL;
++  g_autoptr(GDBusConnection) session_bus = NULL;
++  GError *error = NULL;
++
++  task = g_task_new (NULL, cancellable, callback, data);
++
++  session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
++  if (session_bus == NULL)
++    {
++      g_task_return_error (task, error);
++      return;
++    }
++
++  g_dbus_connection_call (session_bus,
++                          "org.freedesktop.portal.Desktop",
++                          "/org/freedesktop/portal/desktop",
++                          "org.freedesktop.portal.WebExtensions",
++                          "GetManifest",
++                          g_variant_new ("(oss)", session_handle, name, extension_or_origin),
++                          NULL,
++                          G_DBUS_CALL_FLAGS_NONE,
++                          -1,
++                          cancellable,
++                          get_manifest_returned,
++                          g_steal_pointer (&task));
++}
++
++static char *
++get_manifest_finish (GAsyncResult *result, GError **error)
++{
++  return g_task_propagate_pointer (G_TASK (result), error);
++}
++
++static void
++start_returned (GObject *object,
++                GAsyncResult *result,
++                gpointer data)
++{
++  g_autoptr(GTask) task = data;
++  g_autoptr(GVariant) ret = NULL;
++  GError *error = NULL;
++
++  ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (object), result, &error);
++  if (!ret)
++    {
++      guint signal_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (task), "response-signal-id"));
++      g_dbus_connection_signal_unsubscribe (G_DBUS_CONNECTION (object), signal_id);
++      g_task_return_error (task, error);
++      return;
++    }
++}
++
++static void
++start_completed (GDBusConnection *session_bus,
++                 const char *sender_name,
++                 const char *object_path,
++                 const char *interface_name,
++                 const char *signal_name,
++                 GVariant *parameters,
++                 gpointer data)
++{
++  g_autoptr(GTask) task = g_object_ref (data);
++  guint signal_id;
++  guint32 response;
++  g_autoptr(GVariant) ret = NULL;
++
++  signal_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (task), "response-signal-id"));
++  g_dbus_connection_signal_unsubscribe (session_bus, signal_id);
++
++  g_variant_get (parameters, "(u at a{sv})", &response, &ret);
++  switch (response)
++    {
++    case 0:
++      g_task_return_boolean (task, TRUE);
++      break;
++    case 1:
++      g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Start cancelled");
++      break;
++    case 2:
++    default:
++      g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "Start failed");
++      break;
++    }
++}
++
++static void
++start (const char *session_handle,
++       const char *name,
++       const char *extension_or_origin,
++       GCancellable *cancellable,
++       GAsyncReadyCallback callback,
++       gpointer data)
++{
++  g_autoptr(GTask) task = NULL;
++  g_autoptr(GDBusConnection) session_bus = NULL;
++  GError *error = NULL;
++  g_autofree char *token = NULL;
++  g_autofree char *sender = NULL;
++  g_autofree char *request_path = NULL;
++  int i;
++  guint signal_id;
++  GVariantBuilder options;
++
++  task = g_task_new (NULL, cancellable, callback, data);
++
++  session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
++  if (session_bus == NULL)
++    {
++      g_task_return_error (task, error);
++      return;
++    }
++
++  token = g_strdup_printf ("portal%d", g_random_int_range (0, G_MAXINT));
++  sender = g_strdup (g_dbus_connection_get_unique_name (session_bus) + 1);
++  for (i = 0; sender[i]; i++)
++    if (sender[i] == '.')
++      sender[i] = '_';
++  request_path = g_strconcat ("/org/freedesktop/portal/desktop/request/", sender, "/", token, NULL);
++  signal_id = g_dbus_connection_signal_subscribe (session_bus,
++                                                  "org.freedesktop.portal.Desktop",
++                                                  "org.freedesktop.portal.Request",
++                                                  "Response",
++                                                  request_path,
++                                                  NULL,
++                                                  G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
++                                                  start_completed,
++                                                  g_object_ref (task),
++                                                  g_object_unref);
++  g_object_set_data (G_OBJECT (task), "response-signal-id", GUINT_TO_POINTER (signal_id));
++
++  g_variant_builder_init (&options, G_VARIANT_TYPE_VARDICT);
++  g_variant_builder_add (&options, "{sv}", "handle_token", g_variant_new_string (token));
++  g_dbus_connection_call (session_bus,
++                          "org.freedesktop.portal.Desktop",
++                          "/org/freedesktop/portal/desktop",
++                          "org.freedesktop.portal.WebExtensions",
++                          "Start",
++                          g_variant_new ("(ossa{sv})", session_handle, name, extension_or_origin, &options),
++                          NULL,
++                          G_DBUS_CALL_FLAGS_NONE,
++                          -1,
++                          cancellable,
++                          start_returned,
++                          g_steal_pointer (&task));
++}
++
++static gboolean
++start_finish (GAsyncResult *result, GError **error)
++{
++  return g_task_propagate_boolean (G_TASK (result), error);
++}
++
++static void
++get_pipes_returned (GObject *object,
++                    GAsyncResult *result,
++                    gpointer data)
++{
++  g_autoptr(GTask) task = data;
++  g_autoptr(GVariant) ret = NULL;
++  g_autoptr(GUnixFDList) fd_list = NULL;
++  GError *error = NULL;
++
++  ret = g_dbus_connection_call_with_unix_fd_list_finish (G_DBUS_CONNECTION (object), &fd_list, result, &error);
++  if (!ret)
++    {
++      g_task_return_error (task, error);
++      return;
++    }
++  g_task_return_pointer (task, g_steal_pointer (&fd_list), g_object_unref);
++}
++
++static void
++get_pipes (const char *session_handle,
++           GCancellable *cancellable,
++           GAsyncReadyCallback callback,
++           gpointer data)
++{
++  g_autoptr(GTask) task = NULL;
++  g_autoptr(GDBusConnection) session_bus = NULL;
++  GError *error = NULL;
++
++  task = g_task_new (NULL, cancellable, callback, data);
++
++  session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
++  if (session_bus == NULL)
++    {
++      g_task_return_error (task, error);
++      return;
++    }
++
++  g_dbus_connection_call_with_unix_fd_list (session_bus,
++                                            "org.freedesktop.portal.Desktop",
++                                            "/org/freedesktop/portal/desktop",
++                                            "org.freedesktop.portal.WebExtensions",
++                                            "GetPipes",
++                                            g_variant_new ("(oa{sv})", session_handle, NULL),
++                                            NULL,
++                                            G_DBUS_CALL_FLAGS_NONE,
++                                            -1,
++                                            NULL,
++                                            cancellable,
++                                            get_pipes_returned,
++                                            g_steal_pointer (&task));
++}
++
++static gboolean
++get_pipes_finish (int *stdin_fileno, int *stdout_fileno, int *stderr_fileno, GAsyncResult *result, GError **error)
++{
++  g_autoptr(GUnixFDList) fd_list = NULL;
++
++  fd_list = g_task_propagate_pointer (G_TASK (result), error);
++  if (fd_list == NULL)
++    return FALSE;
++
++  if (stdin_fileno != NULL)
++    {
++      *stdin_fileno = g_unix_fd_list_get (fd_list, 0, error);
++      if (*stdin_fileno < 0)
++        return FALSE;
++    }
++  if (stdout_fileno != NULL)
++    {
++      *stdout_fileno = g_unix_fd_list_get (fd_list, 1, error);
++      if (*stdout_fileno < 0)
++        return FALSE;
++    }
++  if (stderr_fileno != NULL)
++    {
++      *stderr_fileno = g_unix_fd_list_get (fd_list, 2, error);
++      if (*stderr_fileno < 0)
++        return FALSE;
++    }
++  return TRUE;
++}
++
++static void
++close_session_returned (GObject *object,
++                        GAsyncResult *result,
++                        gpointer data)
++{
++  g_autoptr(GTask) task = data;
++  g_autoptr(GVariant) ret = NULL;
++  GError *error = NULL;
++
++  ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (object), result, &error);
++  if (!ret)
++    {
++      g_task_return_error (task, error);
++      return;
++    }
++  g_task_return_boolean (task, TRUE);
++}
++
++static void
++close_session (const char *session_handle,
++               GCancellable *cancellable,
++               GAsyncReadyCallback callback,
++               gpointer data)
++{
++  g_autoptr(GTask) task = NULL;
++  g_autoptr(GDBusConnection) session_bus = NULL;
++  GError *error = NULL;
++
++  task = g_task_new (NULL, cancellable, callback, data);
++
++  session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
++  if (session_bus == NULL)
++    {
++      g_task_return_error (task, error);
++      return;
++    }
++
++  g_dbus_connection_call (session_bus,
++                          "org.freedesktop.portal.Desktop",
++                          session_handle,
++                          "org.freedesktop.portal.Session",
++                          "Close",
++                          NULL,
++                          NULL,
++                          G_DBUS_CALL_FLAGS_NONE,
++                          -1,
++                          cancellable,
++                          close_session_returned,
++                          g_steal_pointer (&task));
++}
++
++static gboolean
++close_session_finish (GAsyncResult *result, GError **error)
++{
++  return g_task_propagate_boolean (G_TASK (result), error);
++}
++
++
++static int got_info = 0;
++
++extern XdpDbusImplPermissionStore *permission_store;
++
++static void
++set_web_extensions_permissions (const char *permission)
++{
++  const char *permissions[2] = { NULL, NULL };
++  g_autoptr(GError) error = NULL;
++
++  permissions[0] = permission;
++  xdp_dbus_impl_permission_store_call_set_permission_sync (permission_store,
++                                                           "webextensions",
++                                                           TRUE,
++                                                           "org.example.testing",
++                                                           "",
++                                                           permissions,
++                                                           NULL,
++                                                           &error);
++  g_assert_no_error (error);
++}
++
++static gboolean
++cancel_call (gpointer data)
++{
++  GCancellable *cancellable = data;
++
++  g_debug ("cancel call");
++  g_cancellable_cancel (cancellable);
++
++  return G_SOURCE_REMOVE;
++}
++
++typedef struct {
++  GCancellable *cancellable;
++  char *session_handle;
++  const char *server_name;
++} TestData;
++
++static void
++close_session_cb (GObject *object, GAsyncResult *result, gpointer data)
++{
++  g_autoptr(GError) error = NULL;
++  gboolean ret;
++
++  ret = close_session_finish (result, &error);
++  if (ret)
++    {
++      g_assert_no_error (error);
++    }
++  else
++    {
++      /* The native messaging host may have closed before we tried to
++         close it. */
++      g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD);
++    }
++
++  got_info++;
++  g_main_context_wakeup (NULL);
++}
++
++static void
++get_pipes_cb (GObject *object, GAsyncResult *result, gpointer data)
++{
++  TestData *test_data = data;
++  g_autoptr(GError) error = NULL;
++  gboolean ret;
++  int stdin_fileno = -1, stdout_fileno = -1, stderr_fileno = -1;
++
++  ret = get_pipes_finish (&stdin_fileno, &stdout_fileno, &stderr_fileno, result, &error);
++  g_assert_no_error (error);
++  g_assert_true (ret);
++  g_assert_cmpint (stdin_fileno, >, 0);
++  g_assert_cmpint (stdout_fileno, >, 0);
++  g_assert_cmpint (stderr_fileno, >, 0);
++
++  close (stdin_fileno);
++  close (stdout_fileno);
++  close (stderr_fileno);
++
++  close_session (test_data->session_handle,
++                 test_data->cancellable,
++                 close_session_cb,
++                 test_data);
++}
++
++static void
++start_cb (GObject *object, GAsyncResult *result, gpointer data)
++{
++  TestData *test_data = data;
++  g_autoptr(GError) error = NULL;
++  gboolean ret;
++
++  ret = start_finish (result, &error);
++  g_assert_no_error (error);
++  g_assert_true (ret);
++
++  get_pipes (test_data->session_handle,
++             test_data->cancellable,
++             get_pipes_cb,
++             test_data);
++}
++
++
++static void
++get_manifest_cb (GObject *object, GAsyncResult *result, gpointer data)
++{
++  TestData *test_data = data;
++  g_autoptr(GError) error = NULL;
++  g_autofree char *json_manifest = NULL;
++
++  json_manifest = get_manifest_finish (result, &error);
++  g_assert_no_error (error);
++  g_assert_cmpstr (json_manifest, ==, "{\"name\":\"org.example.testing\",\"description\":\"Test native messaging host\",\"path\":\"/bin/cat\",\"type\":\"stdio\",\"allowed_extensions\":[\"some-extension at example.org\"]}");
++
++  start (test_data->session_handle,
++         "org.example.testing",
++         "some-extension at example.org",
++         test_data->cancellable,
++         start_cb,
++         test_data);
++}
++
++static void
++create_session_cb (GObject *object, GAsyncResult *result, gpointer data)
++{
++  TestData *test_data = data;
++  g_autoptr(GError) error = NULL;
++
++  test_data->session_handle = create_session_finish (result, &error);
++  g_assert_no_error (error);
++  g_assert_nonnull (test_data->session_handle);
++
++  get_manifest (test_data->session_handle,
++                "org.example.testing",
++                "some-extension at example.org",
++                test_data->cancellable,
++                get_manifest_cb,
++                test_data);
++}
++
++void
++test_web_extensions_basic (void)
++{
++  g_autoptr(GCancellable) cancellable = NULL;
++  TestData test_data = { cancellable, NULL };
++
++  got_info = 0;
++
++  set_web_extensions_permissions ("yes");
++  create_session (cancellable, create_session_cb, &test_data);
++
++  g_timeout_add (100, cancel_call, cancellable);
++  while (!got_info)
++    g_main_context_iteration (NULL, TRUE);
++  g_free (test_data.session_handle);
++}
++
++static void
++start_bad_name_cb (GObject *object, GAsyncResult *result, gpointer data)
++{
++  g_autoptr(GError) error = NULL;
++  gboolean ret;
++
++  ret = start_finish (result, &error);
++  g_assert_false (ret);
++  g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
++
++  got_info++;
++  g_main_context_wakeup (NULL);
++}
++
++static void
++create_session_bad_name_cb (GObject *object, GAsyncResult *result, gpointer data)
++{
++  TestData *test_data = data;
++  g_autoptr(GError) error = NULL;
++
++  test_data->session_handle = create_session_finish (result, &error);
++  g_assert_no_error (error);
++  g_assert_nonnull (test_data->session_handle);
++
++  start (test_data->session_handle,
++         test_data->server_name,
++         "some-extension at example.org",
++         test_data->cancellable,
++         start_bad_name_cb,
++         test_data);
++}
++
++void
++test_web_extensions_bad_name (void)
++{
++    const char *server_name[] = {
++        "no-dashes",
++        "../foo",
++        "no_trailing_dot.",
++    };
++    int i;
++
++    for (i = 0; i < G_N_ELEMENTS (server_name); i++)
++      {
++        g_autoptr(GCancellable) cancellable = NULL;
++        TestData test_data = { cancellable, NULL, server_name[i] };
++
++        got_info = 0;
++        set_web_extensions_permissions ("yes");
++        create_session (cancellable, create_session_bad_name_cb, &test_data);
++
++        g_timeout_add (100, cancel_call, cancellable);
++        while (!got_info)
++          g_main_context_iteration (NULL, TRUE);
++        g_free (test_data.session_handle);
++    }
++}
+diff --git a/tests/web-extensions.h b/tests/web-extensions.h
+new file mode 100644
+index 0000000..0090184
+--- /dev/null
++++ b/tests/web-extensions.h
+@@ -0,0 +1,2 @@
++void test_web_extensions_basic (void);
++void test_web_extensions_bad_name (void);
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..32e383e
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,36 @@
+#!/usr/bin/make -f
+
+export DEB_BUILD_MAINT_OPTIONS = hardening=+all
+export LC_ALL=C.UTF-8
+
+include /usr/share/dpkg/default.mk
+
+built_binaries := $(shell dh_listpackages)
+
+CONFFLAGS :=
+
+%:
+	dh $@ --buildsystem=meson
+
+override_dh_auto_configure:
+	dh_auto_configure -- \
+		-Dauto_features=enabled \
+		-Dinstalled-tests=true \
+		-Dsandboxed-image-validation=true \
+		$(CONFFLAGS)
+		$(NULL)
+
+override_dh_auto_test:
+ifeq ($(filter nocheck,$(DEB_BUILD_OPTIONS)),)
+	G_MESSAGES_DEBUG=all \
+	TEST_IN_CI=1 \
+	dh_auto_test --no-parallel
+endif
+
+# debhelper >= 13.4 makes all of /usr/libexec executable, which is not
+# quite right for installed-tests
+override_dh_fixperms:
+	dh_fixperms -Xusr/libexec/installed-tests
+ifneq ($(filter %-tests,$(built_binaries)),)
+	chmod --recursive --changes a+rX,u+w,og-w debian/*-tests/usr/libexec/installed-tests
+endif
diff --git a/debian/salsa-ci.yml b/debian/salsa-ci.yml
new file mode 100644
index 0000000..5241034
--- /dev/null
+++ b/debian/salsa-ci.yml
@@ -0,0 +1,7 @@
+include:
+  - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml
+  - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml
+
+variables:
+  RELEASE: 'unstable'
+  SALSA_CI_LINTIAN_SUPPRESS_TAGS: 'bad-distribution-in-changes-file,mail-address-loops-or-bounces'
diff --git a/debian/source/format b/debian/source/format
new file mode 100644
index 0000000..163aaf8
--- /dev/null
+++ b/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/debian/tests/control b/debian/tests/control
new file mode 100644
index 0000000..8094e12
--- /dev/null
+++ b/debian/tests/control
@@ -0,0 +1,5 @@
+Tests: gnome-desktop-testing
+Restrictions: flaky, isolation-machine
+Depends:
+ gnome-desktop-testing,
+ xdg-desktop-portal-tests,
diff --git a/debian/tests/gnome-desktop-testing b/debian/tests/gnome-desktop-testing
new file mode 100755
index 0000000..27ca6f9
--- /dev/null
+++ b/debian/tests/gnome-desktop-testing
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+set -e
+exec 2>&1
+
+# capsh is in /sbin
+export PATH="$PATH:/sbin:/usr/sbin"
+
+# Some tests are skipped or have longer timeouts in CI
+export TEST_IN_CI=1
+
+exec gnome-desktop-testing-runner xdg-desktop-portal
diff --git a/debian/upstream/metadata b/debian/upstream/metadata
new file mode 100644
index 0000000..24ff072
--- /dev/null
+++ b/debian/upstream/metadata
@@ -0,0 +1,6 @@
+---
+Repository: https://github.com/flatpak/xdg-desktop-portal.git
+Repository-Browse: https://github.com/flatpak/xdg-desktop-portal
+Bug-Database: https://github.com/flatpak/xdg-desktop-portal/issues
+Bug-Submit: https://github.com/flatpak/xdg-desktop-portal/issues/new
+Security-Contact: https://github.com/flatpak/xdg-desktop-portal/tree/HEAD/SECURITY.md
diff --git a/debian/watch b/debian/watch
new file mode 100644
index 0000000..28c5196
--- /dev/null
+++ b/debian/watch
@@ -0,0 +1,9 @@
+version=4
+# Upstream releases official Autotools 'make dist' tarballs, so we use
+# those in preference to git tags
+opts="\
+    compression=xz, \
+    dversionmangle=s/\+(?:git)?[0-9]*(?:\+g[0-9a-f]*)//, \
+    downloadurlmangle=s#/tag/#/download/#;s#(v?@ANY_VERSION@)$#$1/@PACKAGE at -$2.tar.xz#, \
+    filenamemangle=s#v?@ANY_VERSION@#@PACKAGE at -$1.tar.xz#" \
+https://github.com/flatpak/@PACKAGE@/tags .*/releases/tag/v?@ANY_VERSION@
diff --git a/debian/xdg-desktop-portal-dev.doc-base b/debian/xdg-desktop-portal-dev.doc-base
new file mode 100644
index 0000000..bcbb95b
--- /dev/null
+++ b/debian/xdg-desktop-portal-dev.doc-base
@@ -0,0 +1,8 @@
+Document: xdg-desktop-portal-dev
+Title: Portal API Reference
+Author: Matthias Clasen
+Section: Programming
+
+Format: HTML
+Index: /usr/share/doc/xdg-desktop-portal/portal-docs.html
+Files: /usr/share/doc/xdg-desktop-portal/portal-docs.html /usr/share/doc/xdg-desktop-portal/docbook.css
diff --git a/debian/xdg-desktop-portal-dev.install b/debian/xdg-desktop-portal-dev.install
new file mode 100644
index 0000000..62e5ec5
--- /dev/null
+++ b/debian/xdg-desktop-portal-dev.install
@@ -0,0 +1,4 @@
+usr/share/dbus-1/interfaces
+usr/share/doc/xdg-desktop-portal/docbook.css
+usr/share/doc/xdg-desktop-portal/portal-docs.html
+usr/share/pkgconfig/xdg-desktop-portal.pc
diff --git a/debian/xdg-desktop-portal-tests.install b/debian/xdg-desktop-portal-tests.install
new file mode 100644
index 0000000..6d3b245
--- /dev/null
+++ b/debian/xdg-desktop-portal-tests.install
@@ -0,0 +1,2 @@
+usr/libexec/installed-tests/xdg-desktop-portal
+usr/share/installed-tests/xdg-desktop-portal
diff --git a/debian/xdg-desktop-portal.docs b/debian/xdg-desktop-portal.docs
new file mode 100644
index 0000000..edc0071
--- /dev/null
+++ b/debian/xdg-desktop-portal.docs
@@ -0,0 +1 @@
+NEWS
diff --git a/debian/xdg-desktop-portal.install b/debian/xdg-desktop-portal.install
new file mode 100644
index 0000000..8d8fa5d
--- /dev/null
+++ b/debian/xdg-desktop-portal.install
@@ -0,0 +1,8 @@
+usr/lib/systemd/user
+usr/libexec/xdg-desktop-portal
+usr/libexec/xdg-desktop-portal-rewrite-launchers
+usr/libexec/xdg-desktop-portal-validate-icon
+usr/libexec/xdg-document-portal
+usr/libexec/xdg-permission-store
+usr/share/dbus-1/services
+usr/share/locale/*/*/xdg-desktop-portal.mo
diff --git a/debian/xdg-desktop-portal.lintian-overrides b/debian/xdg-desktop-portal.lintian-overrides
new file mode 100644
index 0000000..b6add39
--- /dev/null
+++ b/debian/xdg-desktop-portal.lintian-overrides
@@ -0,0 +1,2 @@
+# https://bugs.debian.org/1031037
+no-manual-page [usr/libexec/*]
diff --git a/debian/xdg-desktop-portal.manpages b/debian/xdg-desktop-portal.manpages
new file mode 100644
index 0000000..ad8f70a
--- /dev/null
+++ b/debian/xdg-desktop-portal.manpages
@@ -0,0 +1 @@
+usr/share/man/man5/portals.conf.5
diff --git a/debian/xdg-desktop-portal.postinst b/debian/xdg-desktop-portal.postinst
new file mode 100644
index 0000000..01d0b6a
--- /dev/null
+++ b/debian/xdg-desktop-portal.postinst
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+set -e
+
+if [ -n "$2" ] && dpkg --compare-versions "$2" ge 1.14.0 && dpkg --compare-versions "$2" lt 1.14.1-1~bpo11+1; then
+    deb-systemd-helper --user disable xdg-desktop-portal.service
+fi
+
+#DEBHELPER#
+
+# vim:set sw=4 sts=4 et:


More information about the Neon-commits mailing list