[neon/backports-noble/xdg-desktop-portal-noble/Neon/release] debian: new release, manually merge in salsa debian/latest
Jonathan Riddell
null at kde.org
Thu Oct 31 16:15:38 GMT 2024
Git commit 29cd4813f437e91eedaf97a05ab9828ded043690 by Jonathan Riddell.
Committed on 31/10/2024 at 16:10.
Pushed by jriddell into branch 'Neon/release'.
new release, manually merge in salsa debian/latest
M +29 -141 debian/changelog
M +20 -8 debian/control
M +28 -14 debian/copyright
M +1 -2 debian/gbp.conf
A +38 -0 debian/patches/debian/doc-Use-system-copy-of-Inter-Variable-font.patch
M +3 -1 debian/patches/series
D +0 -1758 debian/patches/webextensions-portal.patch
A +31 -0 debian/patches/xdp_validate_icon-Allow-sandboxing-of-the-validator-to-be.patch
A +46 -0 debian/patches/xdp_validate_icon-Assign-argument-indices-automatically.patch
M +14 -1 debian/rules
M +0 -4 debian/salsa-ci.yml
M +5 -4 debian/watch
M +2 -2 debian/xdg-desktop-portal-dev.doc-base
A +1 -0 debian/xdg-desktop-portal-dev.docs
M +0 -2 debian/xdg-desktop-portal-dev.install
A +1 -0 debian/xdg-desktop-portal-dev.links
D +0 -2 debian/xdg-desktop-portal.lintian-overrides
https://invent.kde.org/neon/backports-noble/xdg-desktop-portal-noble/-/commit/29cd4813f437e91eedaf97a05ab9828ded043690
diff --git a/debian/changelog b/debian/changelog
index af5e40f..bbeb9e4 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,11 +1,33 @@
-xdg-desktop-portal (1.18.4-1ubuntu2) noble; urgency=medium
+xdg-desktop-portal (1.19.0+ds-1) experimental; 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
+ * New upstream development release
+ * d/copyright: Update
+ * Repack tarball to exclude vendored Inter Variable font from
+ documentation
+ * d/p/debian/doc-Use-system-copy-of-Inter-Variable-font.patch:
+ Add a patch to avoid using the vendored Inter Variable font, which
+ we remove
+ * d/copyright, d/watch: Update for exclusion of vendored web font
+ * Remove obsolete Lintian override for #1031037, fixed in
+ Lintian 2.117.0
+ * d/control, d/x-d-p-dev.docs, d/x-d-p-dev.doc-base:
+ Build HTML documentation using Sphinx; enable dh_sphinxdoc
+ * d/rules: Update Meson options.
+ sandboxed-image-validation is now a feature rather than a boolean.
+ * d/p/xdp_validate_icon-Assign-argument-indices-automatically.patch,
+ d/p/xdp_validate_icon-Allow-sandboxing-of-the-validator-to-be.patch,
+ d/rules:
+ Disable sandboxing of icon validation during build-time testing.
+ Some buildds build in a chroot, and bubblewrap can't work in that
+ environment.
+ * d/control: Add librsvg2-common to Recommends, Build-Depends,
+ test Depends. This is needed for SVG icon validation.
+ * d/control: Explicitly build-depend on bubblewrap
+ * d/control, d/rules: Only build documentation in arch-indep builds
+ * d/rules: Disable man pages under nodoc build profile
+ * Standards-Version: 4.7.0 (no changes required)
+
+ -- Simon McVittie <smcv at debian.org> Wed, 30 Oct 2024 19:46:16 +0000
xdg-desktop-portal (1.18.4-1) unstable; urgency=medium
@@ -18,16 +40,6 @@ xdg-desktop-portal (1.18.4-1) unstable; urgency=medium
-- 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
@@ -35,16 +47,6 @@ xdg-desktop-portal (1.18.3-1) unstable; urgency=medium
-- 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
@@ -64,38 +66,12 @@ xdg-desktop-portal (1.18.1-1) unstable; urgency=medium
-- 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
@@ -130,18 +106,6 @@ xdg-desktop-portal (1.17.0-1) experimental; urgency=medium
-- 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
@@ -157,19 +121,6 @@ xdg-desktop-portal (1.16.0-3) unstable; urgency=medium
-- 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
@@ -181,17 +132,6 @@ xdg-desktop-portal (1.16.0-2) unstable; urgency=medium
-- 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
@@ -238,17 +178,6 @@ xdg-desktop-portal (1.15.0-2) unstable; urgency=medium
-- 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
@@ -275,16 +204,6 @@ xdg-desktop-portal (1.14.5-1) unstable; urgency=medium
-- 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
@@ -297,37 +216,6 @@ xdg-desktop-portal (1.14.3-1) unstable; urgency=medium
-- 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
diff --git a/debian/control b/debian/control
index 7c5afbb..9f7e7ac 100644
--- a/debian/control
+++ b/debian/control
@@ -1,11 +1,11 @@
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>
+Maintainer: Utopia Maintenance Team <pkg-utopia-maintainers at lists.alioth.debian.org>
Uploaders:
Simon McVittie <smcv at debian.org>,
Build-Depends:
+ bubblewrap,
dbus-daemon,
debhelper-compat (= 13),
geoclue-2.0 <!nocheck>,
@@ -19,6 +19,7 @@ Build-Depends:
libjson-glib-dev,
libpipewire-0.3-dev,
libportal-dev (>= 0.3),
+ librsvg2-common <!nocheck>,
libsystemd-dev,
meson,
pipewire <!nocheck>,
@@ -28,14 +29,17 @@ Build-Depends:
python3-docutils <!nodoc>,
python3-gi <!nocheck>,
python3-pytest <!nocheck>,
- xmlto,
+Build-Depends-Indep:
+ dh-sequence-sphinxdoc <!nodoc>,
+ furo <!nodoc>,
+ python3-sphinx <!nodoc>,
+ python3-sphinx-copybutton <!nodoc>,
+ python3-sphinxext-opengraph <!nodoc>,
Rules-Requires-Root: no
-Standards-Version: 4.6.2
+Standards-Version: 4.7.0
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
+Vcs-Git: https://salsa.debian.org/debian/xdg-desktop-portal.git
+Vcs-Browser: https://salsa.debian.org/debian/xdg-desktop-portal
Package: xdg-desktop-portal
Architecture: linux-any
@@ -46,6 +50,8 @@ Depends:
fuse3,
${misc:Depends},
${shlibs:Depends},
+Recommends:
+ librsvg2-common,
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
@@ -67,9 +73,14 @@ Description: desktop integration portal for Flatpak and Snap
Package: xdg-desktop-portal-dev
Architecture: all
Multi-Arch: foreign
+Built-Using:
+ ${sphinxdoc:Built-Using},
Depends:
${misc:Depends},
${shlibs:Depends},
+ ${sphinxdoc:Depends},
+Recommends:
+ fonts-inter-variable,
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
@@ -87,6 +98,7 @@ Depends:
dbus-daemon,
geoclue-2.0,
libcap2-bin,
+ librsvg2-common,
pipewire,
procps,
python3,
diff --git a/debian/copyright b/debian/copyright
index 9ec0804..0d55bd6 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -1,21 +1,26 @@
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-Excluded: doc/_static/inter.woff2
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+
+ 2022 Aleix Pol Gonzalez
+ 2016 Aviary.pl
+ 2010 Codethink Limited
+ 2021 Collabora Ltd.
+ 2021-2022 Endless OS Foundation, LLC
+ 2016 Free Software Foundation, Inc.
+ 2022 Georges Basile Stavracas Neto
+ 2023-2024 GNOME Foundation Inc.
+ 2022 Google LLC
+ 2018-2023 Igalia S.L.
+ 2017 Jan Alexander Steffens
+ 2021-2022 Matthew Leeds
+ 2016 Piotr Drag
+ 2013-2024 Red Hat, Inc
+License: LGPL-2.1+
Files:
doc/website/*
@@ -23,10 +28,19 @@ Copyright: none claimed
License: CC0-1.0
Files:
- src/flatpak-instance.*
+ .github/workflows/check-potfiles.sh
Copyright:
- © 2018 Red Hat, Inc
-License: LGPL-2.1+
+ 2020-2023 Florian Müllner
+ 2024 Corey Berla
+ 2024 Matthijs Velsink
+License: probably-GPL-2
+ This file originated in gnome-shell, from which it was copied via
+ nautilus and gnome-control-center into xdg-desktop-portal, with no
+ explicit license specified. The actual license is unclear, but it's
+ either GPL-2 or LGPL-2.1, with or without the "or any later version"
+ clause. On a Debian system, the relevant licenses can be found in
+ <file:///usr/share/common-licenses/GPL-2> and
+ <file:///usr/share/common-licenses/LGPL-2.1>.
Files:
debian/*
diff --git a/debian/gbp.conf b/debian/gbp.conf
index 40b834b..1c8402c 100644
--- a/debian/gbp.conf
+++ b/debian/gbp.conf
@@ -1,8 +1,7 @@
[DEFAULT]
pristine-tar = True
compression = xz
-debian-branch = ubuntu/latest
-debian-tag = ubuntu/%(version)s
+debian-branch = debian/latest
upstream-branch = upstream/latest
patch-numbers = False
upstream-vcs-tag = %(version)s
diff --git a/debian/patches/debian/doc-Use-system-copy-of-Inter-Variable-font.patch b/debian/patches/debian/doc-Use-system-copy-of-Inter-Variable-font.patch
new file mode 100644
index 0000000..510b969
--- /dev/null
+++ b/debian/patches/debian/doc-Use-system-copy-of-Inter-Variable-font.patch
@@ -0,0 +1,38 @@
+From: Simon McVittie <smcv at debian.org>
+Date: Tue, 15 Oct 2024 14:25:07 +0100
+Subject: doc: Use system copy of Inter Variable font
+
+Forwarded: not-needed, Debian-specific
+---
+ doc/_static/xdg.css | 11 +----------
+ 1 file changed, 1 insertion(+), 10 deletions(-)
+
+diff --git a/doc/_static/xdg.css b/doc/_static/xdg.css
+index 59728dd..298b982 100644
+--- a/doc/_static/xdg.css
++++ b/doc/_static/xdg.css
+@@ -6,15 +6,6 @@ https://pypi.org/project/furo/
+
+ /* FONTS */
+
+- at font-face {
+- font-family: "Inter var";
+- font-weight: 100 900;
+- font-display: swap;
+- font-style: normal;
+- font-named-instance: "Regular";
+- src: url("inter.woff2") format("woff2");
+-}
+-
+ :root {
+ --rounded-corner: 12px;
+ --blue1: rgb(153,193,241);
+@@ -97,7 +88,7 @@ html, body {
+ margin: 0;
+ padding: 0;
+ font-size: 16px;
+- font-family: "Inter var", sans-serif;
++ font-family: "Inter Variable", "Inter var", sans-serif;
+ font-weight: 400;
+ line-height: 1.6;
+ }
diff --git a/debian/patches/series b/debian/patches/series
index edf4c72..d110aab 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1 +1,3 @@
-webextensions-portal.patch
+xdp_validate_icon-Assign-argument-indices-automatically.patch
+xdp_validate_icon-Allow-sandboxing-of-the-validator-to-be.patch
+debian/doc-Use-system-copy-of-Inter-Variable-font.patch
diff --git a/debian/patches/webextensions-portal.patch b/debian/patches/webextensions-portal.patch
deleted file mode 100644
index bb2f277..0000000
--- a/debian/patches/webextensions-portal.patch
+++ /dev/null
@@ -1,1758 +0,0 @@
-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/patches/xdp_validate_icon-Allow-sandboxing-of-the-validator-to-be.patch b/debian/patches/xdp_validate_icon-Allow-sandboxing-of-the-validator-to-be.patch
new file mode 100644
index 0000000..8e4fc45
--- /dev/null
+++ b/debian/patches/xdp_validate_icon-Allow-sandboxing-of-the-validator-to-be.patch
@@ -0,0 +1,31 @@
+From: Simon McVittie <smcv at debian.org>
+Date: Wed, 30 Oct 2024 17:41:39 +0000
+Subject: xdp_validate_icon: Allow sandboxing of the validator to be disabled
+
+OS distributions often compile packages and run their build-time tests
+in a chroot environment or an unprivileged container, and bubblewrap
+cannot usually work in either of those environments.
+
+Signed-off-by: Simon McVittie <smcv at debian.org>
+Bug: https://github.com/flatpak/xdg-desktop-portal/issues/1497
+Forwarded: https://github.com/flatpak/xdg-desktop-portal/pull/1498
+---
+ src/xdp-utils.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/src/xdp-utils.c b/src/xdp-utils.c
+index 8ecb84b..3fde49c 100644
+--- a/src/xdp-utils.c
++++ b/src/xdp-utils.c
+@@ -606,7 +606,10 @@ xdp_validate_icon (XdpSealedFd *icon,
+
+ i = 0;
+ args[i++] = icon_validator;
+- args[i++] = "--sandbox";
++
++ if (g_getenv ("XDP_VALIDATE_ICON_INSECURE") == NULL)
++ args[i++] = "--sandbox";
++
+ args[i++] = "--fd";
+ args[i++] = G_STRINGIFY (VALIDATOR_INPUT_FD);
+ args[i++] = "--ruleset";
diff --git a/debian/patches/xdp_validate_icon-Assign-argument-indices-automatically.patch b/debian/patches/xdp_validate_icon-Assign-argument-indices-automatically.patch
new file mode 100644
index 0000000..c5c907b
--- /dev/null
+++ b/debian/patches/xdp_validate_icon-Assign-argument-indices-automatically.patch
@@ -0,0 +1,46 @@
+From: Simon McVittie <smcv at debian.org>
+Date: Wed, 30 Oct 2024 17:40:29 +0000
+Subject: xdp_validate_icon: Assign argument indices automatically
+
+Signed-off-by: Simon McVittie <smcv at debian.org>
+Bug: https://github.com/flatpak/xdg-desktop-portal/issues/1497
+Forwarded: https://github.com/flatpak/xdg-desktop-portal/pull/1498
+---
+ src/xdp-utils.c | 17 ++++++++++-------
+ 1 file changed, 10 insertions(+), 7 deletions(-)
+
+diff --git a/src/xdp-utils.c b/src/xdp-utils.c
+index 2219b36..8ecb84b 100644
+--- a/src/xdp-utils.c
++++ b/src/xdp-utils.c
+@@ -591,6 +591,7 @@ xdp_validate_icon (XdpSealedFd *icon,
+ const char *icon_validator = LIBEXECDIR "/xdg-desktop-portal-validate-icon";
+ const char *args[7];
+ int size;
++ size_t i;
+ g_autofree char *output = NULL;
+ g_autoptr(GKeyFile) key_file = NULL;
+
+@@ -603,13 +604,15 @@ xdp_validate_icon (XdpSealedFd *icon,
+ return FALSE;
+ }
+
+- args[0] = icon_validator;
+- args[1] = "--sandbox";
+- args[2] = "--fd";
+- args[3] = G_STRINGIFY (VALIDATOR_INPUT_FD);
+- args[4] = "--ruleset";
+- args[5] = icon_type_to_string (icon_type);
+- args[6] = NULL;
++ i = 0;
++ args[i++] = icon_validator;
++ args[i++] = "--sandbox";
++ args[i++] = "--fd";
++ args[i++] = G_STRINGIFY (VALIDATOR_INPUT_FD);
++ args[i++] = "--ruleset";
++ args[i++] = icon_type_to_string (icon_type);
++ g_assert (i < G_N_ELEMENTS (args));
++ args[i++] = NULL;
+
+ output = xdp_spawn_full (args, xdp_sealed_fd_dup_fd (icon), VALIDATOR_INPUT_FD, &error);
+ if (!output)
diff --git a/debian/rules b/debian/rules
index 32e383e..9202559 100755
--- a/debian/rules
+++ b/debian/rules
@@ -9,6 +9,18 @@ built_binaries := $(shell dh_listpackages)
CONFFLAGS :=
+ifneq ($(filter %-dev,$(built_binaries)),)
+CONFFLAGS += -Ddocumentation=enabled
+else
+CONFFLAGS += -Ddocumentation=disabled
+endif
+
+ifeq ($(filter nodoc,$(DEB_BUILD_PROFILES)),)
+CONFFLAGS += -Dman-pages=enabled
+else
+CONFFLAGS += -Dman-pages=disabled
+endif
+
%:
dh $@ --buildsystem=meson
@@ -16,7 +28,7 @@ override_dh_auto_configure:
dh_auto_configure -- \
-Dauto_features=enabled \
-Dinstalled-tests=true \
- -Dsandboxed-image-validation=true \
+ -Dsandboxed-image-validation=enabled \
$(CONFFLAGS)
$(NULL)
@@ -24,6 +36,7 @@ override_dh_auto_test:
ifeq ($(filter nocheck,$(DEB_BUILD_OPTIONS)),)
G_MESSAGES_DEBUG=all \
TEST_IN_CI=1 \
+ XDP_VALIDATE_ICON_INSECURE=1 \
dh_auto_test --no-parallel
endif
diff --git a/debian/salsa-ci.yml b/debian/salsa-ci.yml
index 5241034..0c22dc4 100644
--- a/debian/salsa-ci.yml
+++ b/debian/salsa-ci.yml
@@ -1,7 +1,3 @@
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/watch b/debian/watch
index 28c5196..8586049 100644
--- a/debian/watch
+++ b/debian/watch
@@ -1,9 +1,10 @@
version=4
-# Upstream releases official Autotools 'make dist' tarballs, so we use
-# those in preference to git tags
+# Upstream releases official tarballs, so we use those in preference to
+# git tags
opts="\
compression=xz, \
- dversionmangle=s/\+(?:git)?[0-9]*(?:\+g[0-9a-f]*)//, \
+ dversionmangle=s/\+(?:git)?[0-9]*(?:\+g[0-9a-f]*)?(?:[+~](?:dfsg|ds)[0-9]*)?//, \
downloadurlmangle=s#/tag/#/download/#;s#(v?@ANY_VERSION@)$#$1/@PACKAGE at -$2.tar.xz#, \
- filenamemangle=s#v?@ANY_VERSION@#@PACKAGE at -$1.tar.xz#" \
+ filenamemangle=s#v?@ANY_VERSION@#@PACKAGE at -$1.tar.xz#, \
+ repacksuffix=+ds" \
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
index bcbb95b..e3e7ad3 100644
--- a/debian/xdg-desktop-portal-dev.doc-base
+++ b/debian/xdg-desktop-portal-dev.doc-base
@@ -4,5 +4,5 @@ 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
+Index: /usr/share/doc/xdg-desktop-portal-dev/html/index.html
+Files: /usr/share/doc/xdg-desktop-portal-dev/html/*.html
diff --git a/debian/xdg-desktop-portal-dev.docs b/debian/xdg-desktop-portal-dev.docs
new file mode 100644
index 0000000..28fcd6c
--- /dev/null
+++ b/debian/xdg-desktop-portal-dev.docs
@@ -0,0 +1 @@
+obj-*/doc/html
diff --git a/debian/xdg-desktop-portal-dev.install b/debian/xdg-desktop-portal-dev.install
index 62e5ec5..b56a12e 100644
--- a/debian/xdg-desktop-portal-dev.install
+++ b/debian/xdg-desktop-portal-dev.install
@@ -1,4 +1,2 @@
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-dev.links b/debian/xdg-desktop-portal-dev.links
new file mode 100644
index 0000000..68ca494
--- /dev/null
+++ b/debian/xdg-desktop-portal-dev.links
@@ -0,0 +1 @@
+usr/share/doc/xdg-desktop-portal-dev/html usr/share/doc/xdg-desktop-portal/html
diff --git a/debian/xdg-desktop-portal.lintian-overrides b/debian/xdg-desktop-portal.lintian-overrides
deleted file mode 100644
index b6add39..0000000
--- a/debian/xdg-desktop-portal.lintian-overrides
+++ /dev/null
@@ -1,2 +0,0 @@
-# https://bugs.debian.org/1031037
-no-manual-page [usr/libexec/*]
More information about the Neon-commits
mailing list