Update
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
-- WirePlumber
|
||||
--
|
||||
-- Copyright © 2021 Collabora Ltd.
|
||||
-- @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
--
|
||||
-- SPDX-License-Identifier: MIT
|
||||
|
||||
log = Log.open_topic ("s-client")
|
||||
|
||||
config = {}
|
||||
config.rules = Conf.get_section_as_json ("access.rules")
|
||||
|
||||
function getAccess (properties)
|
||||
local access = properties["pipewire.access"]
|
||||
local client_access = properties["pipewire.client.access"]
|
||||
local is_flatpak = properties["pipewire.sec.flatpak"]
|
||||
|
||||
if is_flatpak then
|
||||
client_access = "flatpak"
|
||||
end
|
||||
|
||||
if client_access == nil then
|
||||
return access
|
||||
elseif access == "unrestricted" or access == "default" then
|
||||
if client_access ~= "unrestricted" then
|
||||
return client_access
|
||||
end
|
||||
end
|
||||
|
||||
return access
|
||||
end
|
||||
|
||||
function getDefaultPermissions (properties)
|
||||
local access = properties["access"]
|
||||
local media_category = properties["media.category"]
|
||||
|
||||
if access == "flatpak" and media_category == "Manager" then
|
||||
return "all", "flatpak-manager"
|
||||
elseif access == "flatpak" or access == "restricted" then
|
||||
return "rx", access
|
||||
elseif access == "default" then
|
||||
return "all", access
|
||||
end
|
||||
|
||||
return nil, nil
|
||||
end
|
||||
|
||||
function getPermissions (properties)
|
||||
if config.rules then
|
||||
local mprops, matched = JsonUtils.match_rules_update_properties (
|
||||
config.rules, properties)
|
||||
if (matched > 0 and mprops["default_permissions"]) then
|
||||
return mprops["default_permissions"], mprops["access"]
|
||||
end
|
||||
end
|
||||
|
||||
return nil, nil
|
||||
end
|
||||
|
||||
clients_om = ObjectManager {
|
||||
Interest { type = "client" }
|
||||
}
|
||||
|
||||
clients_om:connect("object-added", function (om, client)
|
||||
local id = client["bound-id"]
|
||||
local properties = client["properties"]
|
||||
local access = getAccess (properties)
|
||||
|
||||
properties["access"] = access
|
||||
|
||||
local perms, effective_access = getPermissions (properties)
|
||||
if perms == nil then
|
||||
perms, effective_access = getDefaultPermissions (properties)
|
||||
end
|
||||
if effective_access == nil then
|
||||
effective_access = access
|
||||
end
|
||||
|
||||
if perms ~= nil then
|
||||
log:info(client, "Granting permissions to client " .. id .. " (access " ..
|
||||
effective_access .. "): " .. perms)
|
||||
client:update_permissions { ["any"] = perms }
|
||||
client:update_properties { ["pipewire.access.effective"] = effective_access }
|
||||
else
|
||||
log:debug(client, "No rule for client " .. id .. " (access " .. access .. ")")
|
||||
end
|
||||
end)
|
||||
|
||||
clients_om:activate()
|
||||
143
pipewire/.config/wireplumber/scripts/client/access-portal.lua
Normal file
143
pipewire/.config/wireplumber/scripts/client/access-portal.lua
Normal file
@@ -0,0 +1,143 @@
|
||||
MEDIA_ROLE_NONE = 0
|
||||
MEDIA_ROLE_CAMERA = 1 << 0
|
||||
|
||||
log = Log.open_topic ("s-client")
|
||||
|
||||
function hasPermission (permissions, app_id, lookup)
|
||||
if permissions then
|
||||
for key, values in pairs(permissions) do
|
||||
if key == app_id then
|
||||
for _, v in pairs(values) do
|
||||
if v == lookup then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function parseMediaRoles (media_roles_str)
|
||||
local media_roles = MEDIA_ROLE_NONE
|
||||
for role in media_roles_str:gmatch('[^,%s]+') do
|
||||
if role == "Camera" then
|
||||
media_roles = media_roles | MEDIA_ROLE_CAMERA
|
||||
end
|
||||
end
|
||||
return media_roles
|
||||
end
|
||||
|
||||
function setPermissions (client, allow_client, allow_nodes)
|
||||
local client_id = client["bound-id"]
|
||||
log:info(client, "Granting ALL access to client " .. client_id)
|
||||
|
||||
-- Update permissions on client
|
||||
client:update_permissions { [client_id] = allow_client and "all" or "-" }
|
||||
|
||||
-- Update permissions on camera source nodes
|
||||
for node in nodes_om:iterate() do
|
||||
local node_id = node["bound-id"]
|
||||
client:update_permissions { [node_id] = allow_nodes and "all" or "-" }
|
||||
end
|
||||
end
|
||||
|
||||
function updateClientPermissions (client, permissions)
|
||||
local client_id = client["bound-id"]
|
||||
local str_prop = nil
|
||||
local app_id = nil
|
||||
local media_roles = nil
|
||||
local allowed = false
|
||||
|
||||
-- Make sure the client is not the portal itself
|
||||
str_prop = client.properties["pipewire.access.portal.is_portal"]
|
||||
if str_prop == "yes" then
|
||||
log:info (client, "client is the portal itself")
|
||||
return
|
||||
end
|
||||
|
||||
-- Make sure the client has a portal app Id
|
||||
str_prop = client.properties["pipewire.access.portal.app_id"]
|
||||
if str_prop == nil then
|
||||
log:info (client, "Portal managed client did not set app_id")
|
||||
return
|
||||
end
|
||||
if str_prop == "" then
|
||||
log:info (client, "Ignoring portal check for non-sandboxed client")
|
||||
setPermissions (client, true, true)
|
||||
return
|
||||
end
|
||||
app_id = str_prop
|
||||
|
||||
-- Make sure the client has portal media roles
|
||||
str_prop = client.properties["pipewire.access.portal.media_roles"]
|
||||
if str_prop == nil then
|
||||
log:info (client, "Portal managed client did not set media_roles")
|
||||
return
|
||||
end
|
||||
media_roles = parseMediaRoles (str_prop)
|
||||
if (media_roles & MEDIA_ROLE_CAMERA) == 0 then
|
||||
log:info (client, "Ignoring portal check for clients without camera role")
|
||||
return
|
||||
end
|
||||
|
||||
-- Update permissions
|
||||
allowed = hasPermission (permissions, app_id, "yes")
|
||||
|
||||
log:info (client, "setting permissions: " .. tostring(allowed))
|
||||
setPermissions (client, allowed, allowed)
|
||||
end
|
||||
|
||||
-- Create portal clients object manager
|
||||
clients_om = ObjectManager {
|
||||
Interest {
|
||||
type = "client",
|
||||
Constraint { "pipewire.access", "=", "portal" },
|
||||
}
|
||||
}
|
||||
|
||||
-- Set permissions to portal clients from the permission store if loaded
|
||||
pps_plugin = Plugin.find("portal-permissionstore")
|
||||
if pps_plugin then
|
||||
nodes_om = ObjectManager {
|
||||
Interest {
|
||||
type = "node",
|
||||
Constraint { "media.role", "=", "Camera" },
|
||||
Constraint { "media.class", "=", "Video/Source" },
|
||||
}
|
||||
}
|
||||
nodes_om:activate()
|
||||
|
||||
clients_om:connect("object-added", function (om, client)
|
||||
local new_perms = pps_plugin:call("lookup", "devices", "camera");
|
||||
updateClientPermissions (client, new_perms)
|
||||
end)
|
||||
|
||||
nodes_om:connect("object-added", function (om, node)
|
||||
local new_perms = pps_plugin:call("lookup", "devices", "camera");
|
||||
for client in clients_om:iterate() do
|
||||
updateClientPermissions (client, new_perms)
|
||||
end
|
||||
end)
|
||||
|
||||
pps_plugin:connect("changed", function (p, table, id, deleted, permissions)
|
||||
if table == "devices" or id == "camera" then
|
||||
for app_id, _ in pairs(permissions) do
|
||||
for client in clients_om:iterate {
|
||||
Constraint { "pipewire.access.portal.app_id", "=", app_id }
|
||||
} do
|
||||
updateClientPermissions (client, permissions)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
else
|
||||
-- Otherwise, just set all permissions to all portal clients
|
||||
clients_om:connect("object-added", function (om, client)
|
||||
local id = client["bound-id"]
|
||||
log:info(client, "Granting ALL access to client " .. id)
|
||||
client:update_permissions { ["any"] = "all" }
|
||||
end)
|
||||
end
|
||||
|
||||
clients_om:activate()
|
||||
87
pipewire/.config/wireplumber/scripts/client/access-snap.lua
Normal file
87
pipewire/.config/wireplumber/scripts/client/access-snap.lua
Normal file
@@ -0,0 +1,87 @@
|
||||
-- Manage snap audio permissions
|
||||
--
|
||||
-- Copyright © 2023 Canonical Ltd.
|
||||
-- @author Sergio Costas Rodriguez <sergio.costas@canonical.com>
|
||||
--
|
||||
-- SPDX-License-Identifier: MIT
|
||||
|
||||
function removeClientPermissionsForOtherClients (client)
|
||||
-- Remove access to any other clients, but allow all the process of the
|
||||
-- same snap to access their elements
|
||||
local client_id = client.properties["pipewire.snap.id"]
|
||||
for snap_client in clients_snap:iterate() do
|
||||
local snap_client_id = snap_client.properties["pipewire.snap.id"]
|
||||
if snap_client_id ~= client_id then
|
||||
client:update_permissions { [snap_client["bound-id"]] = "-" }
|
||||
end
|
||||
end
|
||||
for no_snap_client in clients_no_snap:iterate() do
|
||||
client:update_permissions { [no_snap_client["bound-id"]] = "-" }
|
||||
end
|
||||
end
|
||||
|
||||
function updateClientPermissions (client)
|
||||
-- Remove access to Audio/Sources and Audio/Sinks based on snap permissions
|
||||
for node in nodes_om:iterate() do
|
||||
local node_id = node["bound-id"]
|
||||
local property = "pipewire.snap.audio.playback"
|
||||
|
||||
if node.properties["media.class"] == "Audio/Source" then
|
||||
property = "pipewire.snap.audio.record"
|
||||
end
|
||||
|
||||
if client.properties[property] ~= "true" then
|
||||
client:update_permissions { [node_id] = "-" }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
clients_snap = ObjectManager {
|
||||
Interest {
|
||||
type = "client",
|
||||
Constraint { "pipewire.snap.id", "+", type = "pw"},
|
||||
}
|
||||
}
|
||||
|
||||
clients_no_snap = ObjectManager {
|
||||
Interest {
|
||||
type = "client",
|
||||
Constraint { "pipewire.snap.id", "-", type = "pw"},
|
||||
}
|
||||
}
|
||||
|
||||
nodes_om = ObjectManager {
|
||||
Interest {
|
||||
type = "node",
|
||||
Constraint { "media.class", "matches", "Audio/*"}
|
||||
}
|
||||
}
|
||||
|
||||
clients_snap:connect("object-added", function (om, client)
|
||||
-- If a new snap client is added, adjust its permissions
|
||||
updateClientPermissions (client)
|
||||
removeClientPermissionsForOtherClients (client)
|
||||
end)
|
||||
|
||||
clients_no_snap:connect("object-added", function (om, client)
|
||||
-- If a new, non-snap client is added,
|
||||
-- remove access to it from other snaps
|
||||
client_id = client["bound-id"]
|
||||
for snap_client in clients_snap:iterate() do
|
||||
if client.properties["pipewire.snap.id"] ~= nil then
|
||||
snap_client:update_permissions { [client_id] = "-" }
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
nodes_om:connect("object-added", function (om, node)
|
||||
-- If a new Audio/Sink or Audio/Source node is added,
|
||||
-- adjust the permissions in the snap clients
|
||||
for client in clients_snap:iterate() do
|
||||
updateClientPermissions (client)
|
||||
end
|
||||
end)
|
||||
|
||||
clients_snap:activate()
|
||||
clients_no_snap:activate()
|
||||
nodes_om:activate()
|
||||
Reference in New Issue
Block a user