From 0e5ececfcc03cbc6977c16259f4839349272f34b Mon Sep 17 00:00:00 2001 From: Torkel Niklasson Date: Wed, 29 Apr 2026 21:33:31 +0200 Subject: [PATCH 1/2] docs: document Client and PermissionManager Lua API --- .../rst/scripting/lua_api/lua_proxies_api.rst | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/docs/rst/scripting/lua_api/lua_proxies_api.rst b/docs/rst/scripting/lua_api/lua_proxies_api.rst index 6d5e37f9..6553e1ef 100644 --- a/docs/rst/scripting/lua_api/lua_proxies_api.rst +++ b/docs/rst/scripting/lua_api/lua_proxies_api.rst @@ -175,6 +175,17 @@ contain the following methods: :param self: the proxy :param table perms: the permissions to update for this client +.. function:: Client.attach_permission_manager(self, pm) + + Binds :c:func:`wp_client_attach_permission_manager` + + Attaches a permission manager to handle permissions for this client + automatically. The permission manager will manage per-object permissions + based on its configured rules and default permissions. + + :param self: the client + :param WpPermissionManager pm: the permission manager to attach + PipeWire Metadata ................. @@ -198,3 +209,91 @@ contain the following methods: :param string key: the metadata key to find :returns: the value for this metadata key, the type of the value :rtype: string, string + +Permission Manager +.................. + +The ``PermissionManager`` object manages per-object permissions for clients. +It is created with the global ``PermissionManager()`` constructor and configured +with default permissions, core permissions, and match rules. + +.. function:: PermissionManager() + + Creates a new permission manager. + + :returns: a new permission manager + :rtype: WpPermissionManager + +.. function:: PermissionManager.set_default_permissions(self, perms) + + Binds :c:func:`wp_permission_manager_set_default_permissions` + + Sets the default permissions applied to all objects that don't match any rule. + + :param self: the permission manager + :param perms: a permission string (e.g. "rx") or an integer bitmask (e.g. ``Perm.RX``) + +.. function:: PermissionManager.set_core_permissions(self, perms) + + Binds :c:func:`wp_permission_manager_set_core_permissions` + + Sets the permissions applied specifically to the PipeWire core object (ID 0). + If not set, the core inherits the default permissions. + + :param self: the permission manager + :param perms: a permission string or an integer bitmask + +.. function:: PermissionManager.add_rules_match(self, rules) + + Binds :c:func:`wp_permission_manager_add_rules_match` + + Adds a set of match rules that grant specific permissions to objects + matching the given constraints. + + :param self: the permission manager + :param WpSpaJson rules: a JSON array of match rules + :returns: the match id (can be used with ``remove_match``) + :rtype: integer + +.. function:: PermissionManager.add_interest_match(self, callback, interest) + + Binds :c:func:`wp_permission_manager_add_interest_match_closure` + + Adds a dynamic match that calls the given callback to determine permissions + for objects matching the given interest. + + :param self: the permission manager + :param function callback: a function that returns the permissions for the matched object + :param WpObjectInterest interest: the interest to match + :returns: the match id + :rtype: integer + +.. function:: PermissionManager.add_interest_match_simple(self, perms, interest) + + Binds :c:func:`wp_permission_manager_add_interest_match_simple` + + Adds a static match that grants the given permissions to objects matching + the given interest. + + :param self: the permission manager + :param integer perms: the permissions bitmask to grant + :param WpObjectInterest interest: the interest to match + :returns: the match id + :rtype: integer + +.. function:: PermissionManager.remove_match(self, match_id) + + Binds :c:func:`wp_permission_manager_remove_match` + + Removes a previously added match. + + :param self: the permission manager + :param integer match_id: the match id returned by an ``add_*_match`` method + +.. function:: PermissionManager.update_permissions(self) + + Binds :c:func:`wp_permission_manager_update_permissions` + + Forces a recalculation and update of permissions on all attached clients. + + :param self: the permission manager From 19b6cb0658856de3e0b8b309f5402d80a2f7d0d6 Mon Sep 17 00:00:00 2001 From: Torkel Niklasson Date: Wed, 29 Apr 2026 21:34:22 +0200 Subject: [PATCH 2/2] client, permission-manager: add getters for runtime introspection Add wp_client_get_permission_manager() and wp_permission_manager_get_default_permissions() and expose both as Lua methods. This allows Lua scripts to verify a client's trust level at runtime by inspecting the actual permission bits of its attached PM. --- docs/rst/daemon/configuration/access.rst | 28 +++++++++++++ .../rst/scripting/lua_api/lua_proxies_api.rst | 42 +++++++++++++++++++ lib/wp/client.c | 16 +++++++ lib/wp/client.h | 3 ++ lib/wp/permission-manager.c | 16 +++++++ lib/wp/permission-manager.h | 4 ++ modules/module-lua-scripting/api/api.c | 24 +++++++++++ 7 files changed, 133 insertions(+) diff --git a/docs/rst/daemon/configuration/access.rst b/docs/rst/daemon/configuration/access.rst index 2696a66c..dd75f3a7 100644 --- a/docs/rst/daemon/configuration/access.rst +++ b/docs/rst/daemon/configuration/access.rst @@ -123,3 +123,31 @@ Each permission manager supports the following properties: When both ``default_permissions`` and ``permission_manager_name`` are set in a rule's ``update-props`` action, ``default_permissions`` takes precedence and the permission manager is ignored. + +Introspecting Permissions from Scripts +-------------------------------------- + +Lua scripts can query the permission manager attached to a client at runtime +using ``client:get_permission_manager()``. This returns the +``WpPermissionManager`` object (or ``nil`` if none is attached), which can then +be used to inspect the configured permissions. + +Example: + +.. code-block:: lua + + local client_om = ObjectManager { Interest { type = "client" } } + client_om:activate() + + -- Check if a client has at least read + execute permissions + local pm = client:get_permission_manager() + if pm then + local perms = pm:get_default_permissions() + if (perms & Perm.RX) == Perm.RX then + -- Client has sufficient permissions + end + end + +This is useful for scripts that need to verify a client's trust level before +performing privileged operations on its behalf (e.g. linking nodes into an +audio chain). diff --git a/docs/rst/scripting/lua_api/lua_proxies_api.rst b/docs/rst/scripting/lua_api/lua_proxies_api.rst index 6553e1ef..b54461a0 100644 --- a/docs/rst/scripting/lua_api/lua_proxies_api.rst +++ b/docs/rst/scripting/lua_api/lua_proxies_api.rst @@ -186,6 +186,27 @@ contain the following methods: :param self: the client :param WpPermissionManager pm: the permission manager to attach +.. function:: Client.get_permission_manager(self) + + Binds :c:func:`wp_client_get_permission_manager` + + Returns the permission manager currently attached to this client, or ``nil`` + if no permission manager is attached. + + **Example:** + + .. code-block:: lua + + local pm = client:get_permission_manager() + if pm then + local perms = pm:get_default_permissions() + -- check permission bits + end + + :param self: the client + :returns: the attached permission manager, or nil + :rtype: WpPermissionManager or nil + PipeWire Metadata ................. @@ -233,6 +254,27 @@ with default permissions, core permissions, and match rules. :param self: the permission manager :param perms: a permission string (e.g. "rx") or an integer bitmask (e.g. ``Perm.RX``) +.. function:: PermissionManager.get_default_permissions(self) + + Binds :c:func:`wp_permission_manager_get_default_permissions` + + Returns the default permissions as an integer bitmask. This can be compared + against the ``Perm`` constants using bitwise operators. + + **Example:** + + .. code-block:: lua + + local pm = client:get_permission_manager() + local perms = pm:get_default_permissions() + if (perms & Perm.RX) == Perm.RX then + -- client has at least read + execute + end + + :param self: the permission manager + :returns: the default permissions bitmask + :rtype: integer + .. function:: PermissionManager.set_core_permissions(self, perms) Binds :c:func:`wp_permission_manager_set_core_permissions` diff --git a/lib/wp/client.c b/lib/wp/client.c index 59afcff0..e9d3d70f 100644 --- a/lib/wp/client.c +++ b/lib/wp/client.c @@ -268,3 +268,19 @@ wp_client_attach_permission_manager (WpClient *self, WpPermissionManager *pm) wp_permission_manager_add_client (pm, self); g_weak_ref_set (&self->permission_manager, pm); } + +/*! + * \brief Gets the permission manager attached to this client, if any. + * + * \ingroup wpclient + * \param self the client + * \returns (transfer full) (nullable): the attached permission manager, + * or NULL if no permission manager is attached + */ +WpPermissionManager * +wp_client_get_permission_manager (WpClient *self) +{ + g_return_val_if_fail (WP_IS_CLIENT (self), NULL); + + return g_weak_ref_get (&self->permission_manager); +} diff --git a/lib/wp/client.h b/lib/wp/client.h index 1a878cb2..8f9e39b9 100644 --- a/lib/wp/client.h +++ b/lib/wp/client.h @@ -42,6 +42,9 @@ WP_API void wp_client_attach_permission_manager (WpClient *self, WpPermissionManager *pm); +WP_API +WpPermissionManager * wp_client_get_permission_manager (WpClient *self); + G_END_DECLS #endif diff --git a/lib/wp/permission-manager.c b/lib/wp/permission-manager.c index 0e5a384b..dadd7298 100644 --- a/lib/wp/permission-manager.c +++ b/lib/wp/permission-manager.c @@ -523,6 +523,22 @@ wp_permission_manager_set_default_permissions (WpPermissionManager *self, } } +/*! + * \brief Gets the default permissions that are applied to all objects that + * don't match any interest + * + * \ingroup wppermissionmanager + * \param self the permission manager + * \returns the default permissions + */ +guint32 +wp_permission_manager_get_default_permissions (WpPermissionManager *self) +{ + g_return_val_if_fail (WP_IS_PERMISSION_MANAGER (self), 0); + + return self->default_perms; +} + /*! * \brief Sets the permissions that will be applied to the core object (ID 0). * diff --git a/lib/wp/permission-manager.h b/lib/wp/permission-manager.h index 073dfb66..886baf5d 100644 --- a/lib/wp/permission-manager.h +++ b/lib/wp/permission-manager.h @@ -54,6 +54,10 @@ WP_API void wp_permission_manager_set_default_permissions ( WpPermissionManager *self, guint32 permissions); +WP_API +guint32 wp_permission_manager_get_default_permissions ( + WpPermissionManager *self); + WP_API void wp_permission_manager_set_core_permissions ( WpPermissionManager *self, guint32 permissions); diff --git a/modules/module-lua-scripting/api/api.c b/modules/module-lua-scripting/api/api.c index 3b9dfdde..5b09be83 100644 --- a/modules/module-lua-scripting/api/api.c +++ b/modules/module-lua-scripting/api/api.c @@ -1399,11 +1399,24 @@ client_attach_permission_manager (lua_State *L) return 0; } +static int +client_get_permission_manager (lua_State *L) +{ + WpClient *client = wplua_checkobject (L, 1, WP_TYPE_CLIENT); + WpPermissionManager *pm = wp_client_get_permission_manager (client); + if (pm) + wplua_pushobject (L, pm); + else + lua_pushnil (L); + return 1; +} + static const luaL_Reg client_methods[] = { { "update_permissions", client_update_permissions }, { "update_properties", client_update_properties }, { "send_error", client_send_error }, { "attach_permission_manager", client_attach_permission_manager }, + { "get_permission_manager", client_get_permission_manager }, { NULL, NULL } }; @@ -2660,6 +2673,16 @@ permission_manager_set_default_permissions (lua_State *L) return 0; } +static int +permission_manager_get_default_permissions (lua_State *L) +{ + WpPermissionManager *pm = wplua_checkobject (L, 1, + WP_TYPE_PERMISSION_MANAGER); + guint32 perms = wp_permission_manager_get_default_permissions (pm); + lua_pushinteger (L, perms); + return 1; +} + static int permission_manager_set_core_permissions (lua_State *L) { @@ -2746,6 +2769,7 @@ permission_manager_update_permissions (lua_State *L) static const luaL_Reg permission_manager_funcs[] = { { "set_default_permissions", permission_manager_set_default_permissions }, + { "get_default_permissions", permission_manager_get_default_permissions }, { "set_core_permissions", permission_manager_set_core_permissions }, { "add_interest_match", permission_manager_add_interest_match }, { "add_interest_match_simple", permission_manager_add_interest_match_simple },