access-portal.lua 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. MEDIA_ROLE_NONE = 0
  2. MEDIA_ROLE_CAMERA = 1 << 0
  3. function hasPermission (permissions, app_id, lookup)
  4. if permissions then
  5. for key, values in pairs(permissions) do
  6. if key == app_id then
  7. for _, v in pairs(values) do
  8. if v == lookup then
  9. return true
  10. end
  11. end
  12. end
  13. end
  14. end
  15. return false
  16. end
  17. function parseMediaRoles (media_roles_str)
  18. local media_roles = MEDIA_ROLE_NONE
  19. for role in media_roles_str:gmatch('[^,%s]+') do
  20. if role == "Camera" then
  21. media_roles = media_roles | MEDIA_ROLE_CAMERA
  22. end
  23. end
  24. return media_roles
  25. end
  26. function setPermissions (client, allow_client, allow_nodes)
  27. local client_id = client["bound-id"]
  28. Log.info(client, "Granting ALL access to client " .. client_id)
  29. -- Update permissions on client
  30. client:update_permissions { [client_id] = allow_client and "all" or "-" }
  31. -- Update permissions on camera source nodes
  32. for node in nodes_om:iterate() do
  33. local node_id = node["bound-id"]
  34. client:update_permissions { [node_id] = allow_nodes and "all" or "-" }
  35. end
  36. end
  37. function updateClientPermissions (client, permissions)
  38. local client_id = client["bound-id"]
  39. local str_prop = nil
  40. local app_id = nil
  41. local media_roles = nil
  42. local allowed = false
  43. -- Make sure the client is not the portal itself
  44. str_prop = client.properties["pipewire.access.portal.is_portal"]
  45. if str_prop == "yes" then
  46. Log.info (client, "client is the portal itself")
  47. return
  48. end
  49. -- Make sure the client has a portal app Id
  50. str_prop = client.properties["pipewire.access.portal.app_id"]
  51. if str_prop == nil then
  52. Log.info (client, "Portal managed client did not set app_id")
  53. return
  54. end
  55. if str_prop == "" then
  56. Log.info (client, "Ignoring portal check for non-sandboxed client")
  57. setPermissions (client, true, true)
  58. return
  59. end
  60. app_id = str_prop
  61. -- Make sure the client has portal media roles
  62. str_prop = client.properties["pipewire.access.portal.media_roles"]
  63. if str_prop == nil then
  64. Log.info (client, "Portal managed client did not set media_roles")
  65. return
  66. end
  67. media_roles = parseMediaRoles (str_prop)
  68. if (media_roles & MEDIA_ROLE_CAMERA) == 0 then
  69. Log.info (client, "Ignoring portal check for clients without camera role")
  70. return
  71. end
  72. -- Update permissions
  73. allowed = hasPermission (permissions, app_id, "yes")
  74. Log.info (client, "setting permissions: " .. tostring(allowed))
  75. setPermissions (client, allowed, allowed)
  76. end
  77. -- Create portal clients object manager
  78. clients_om = ObjectManager {
  79. Interest {
  80. type = "client",
  81. Constraint { "pipewire.access", "=", "portal" },
  82. }
  83. }
  84. -- Set permissions to portal clients from the permission store if loaded
  85. pps_plugin = Plugin.find("portal-permissionstore")
  86. if pps_plugin then
  87. nodes_om = ObjectManager {
  88. Interest {
  89. type = "node",
  90. Constraint { "media.role", "=", "Camera" },
  91. Constraint { "media.class", "=", "Video/Source" },
  92. }
  93. }
  94. nodes_om:activate()
  95. clients_om:connect("object-added", function (om, client)
  96. local new_perms = pps_plugin:call("lookup", "devices", "camera");
  97. updateClientPermissions (client, new_perms)
  98. end)
  99. nodes_om:connect("object-added", function (om, node)
  100. local new_perms = pps_plugin:call("lookup", "devices", "camera");
  101. for client in clients_om:iterate() do
  102. updateClientPermissions (client, new_perms)
  103. end
  104. end)
  105. pps_plugin:connect("changed", function (p, table, id, deleted, permissions)
  106. if table == "devices" or id == "camera" then
  107. for app_id, _ in pairs(permissions) do
  108. for client in clients_om:iterate {
  109. Constraint { "pipewire.access.portal.app_id", "=", app_id }
  110. } do
  111. updateClientPermissions (client, permissions)
  112. end
  113. end
  114. end
  115. end)
  116. else
  117. -- Otherwise, just set all permissions to all portal clients
  118. clients_om:connect("object-added", function (om, client)
  119. local id = client["bound-id"]
  120. Log.info(client, "Granting ALL access to client " .. id)
  121. client:update_permissions { ["any"] = "all" }
  122. end)
  123. end
  124. clients_om:activate()