prevent access to some more commands by non admins
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Tue, 16 Dec 2025 08:49:59 +0000 (09:49 +0100)
committerMarcel van der Veldt <m.vanderveldt@outlook.com>
Tue, 16 Dec 2025 08:49:59 +0000 (09:49 +0100)
music_assistant/controllers/config.py
music_assistant/controllers/players/player_controller.py
music_assistant/controllers/webserver/controller.py
music_assistant/controllers/webserver/remote_access/__init__.py

index 8781fa19649ae8069484cad99e71a5c1610e1f18..9fe45d1e453f7ff5dfddedd5fc9d5e02605d0a18 100644 (file)
@@ -285,7 +285,7 @@ class ConfigController:
         return_type: None = ...,
     ) -> ConfigValueType: ...
 
-    @api_command("config/providers/get_value")
+    @api_command("config/providers/get_value", required_role="admin")
     async def get_provider_config_value(
         self,
         instance_id: str,
@@ -323,7 +323,7 @@ class ConfigController:
         self._value_cache[cache_key] = val
         return val
 
-    @api_command("config/providers/get_entries")
+    @api_command("config/providers/get_entries", required_role="admin")
     async def get_provider_config_entries(  # noqa: PLR0915
         self,
         provider_domain: str,
@@ -487,7 +487,7 @@ class ConfigController:
             return
         self.remove(conf_key)
 
-    @api_command("config/players")
+    @api_command("config/players", required_role="admin")
     async def get_player_configs(
         self, provider: str | None = None, include_values: bool = False
     ) -> list[PlayerConfig]:
@@ -506,7 +506,7 @@ class ConfigController:
             and (provider in (None, raw_conf["provider"]))
         ]
 
-    @api_command("config/players/get")
+    @api_command("config/players/get", required_role="admin")
     async def get_player_config(
         self,
         player_id: str,
@@ -533,7 +533,7 @@ class ConfigController:
         msg = f"No config found for player id {player_id}"
         raise KeyError(msg)
 
-    @api_command("config/players/get_entries")
+    @api_command("config/players/get_entries", required_role="admin")
     async def get_player_config_entries(
         self,
         player_id: str,
@@ -600,7 +600,7 @@ class ConfigController:
         return_type: None = ...,
     ) -> ConfigValueType: ...
 
-    @api_command("config/players/get_value")
+    @api_command("config/players/get_value", required_role="admin")
     async def get_player_config_value(
         self,
         player_id: str,
@@ -732,7 +732,7 @@ class ConfigController:
         conf_key = f"{CONF_PLAYERS}/{player_id}/default_name"
         self.set(conf_key, default_name)
 
-    @api_command("config/players/dsp/get")
+    @api_command("config/players/dsp/get", required_role="admin")
     def get_player_dsp_config(self, player_id: str) -> DSPConfig:
         """
         Return the DSP Configuration for a player.
@@ -812,7 +812,7 @@ class ConfigController:
         )
         return config
 
-    @api_command("config/dsp_presets/get")
+    @api_command("config/dsp_presets/get", required_role="admin")
     async def get_dsp_presets(self) -> list[DSPConfigPreset]:
         """Return all user-defined DSP presets."""
         raw_presets = self.get(CONF_PLAYER_DSP_PRESETS, {})
@@ -950,7 +950,7 @@ class ConfigController:
             for core_controller in CONFIGURABLE_CORE_CONTROLLERS
         ]
 
-    @api_command("config/core/get")
+    @api_command("config/core/get", required_role="admin")
     async def get_core_config(self, domain: str) -> CoreConfig:
         """Return configuration for a single core controller."""
         raw_conf = self.get(f"{CONF_CORE}/{domain}", {"domain": domain})
@@ -987,7 +987,7 @@ class ConfigController:
         return_type: None = ...,
     ) -> ConfigValueType: ...
 
-    @api_command("config/core/get_value")
+    @api_command("config/core/get_value", required_role="admin")
     async def get_core_config_value(
         self,
         domain: str,
@@ -1019,7 +1019,7 @@ class ConfigController:
             else conf.values[key].default_value
         )
 
-    @api_command("config/core/get_entries")
+    @api_command("config/core/get_entries", required_role="admin")
     async def get_core_config_entries(
         self,
         domain: str,
index 3a3704b0bc95e8fdafc1468dae135d2203f86349..611649157d65c096cb96b2e32f141e6523c556a6 100644 (file)
@@ -1206,7 +1206,7 @@ class PlayerController(CoreController):
         for player_id in list(player_ids):
             await self.cmd_ungroup(player_id)
 
-    @api_command("players/create_group_player")
+    @api_command("players/create_group_player", required_role="admin")
     async def create_group_player(
         self, provider: str, name: str, members: list[str], dynamic: bool = True
     ) -> Player:
@@ -1233,7 +1233,7 @@ class PlayerController(CoreController):
             f"Provider {provider} does not support creating group players"
         )
 
-    @api_command("players/remove_group_player")
+    @api_command("players/remove_group_player", required_role="admin")
     async def remove_group_player(self, player_id: str) -> None:
         """
         Remove a group player.
@@ -1418,7 +1418,7 @@ class PlayerController(CoreController):
             self.delete_player_config(player_id)
         self.mass.signal_event(EventType.PLAYER_REMOVED, player_id)
 
-    @api_command("players/remove")
+    @api_command("players/remove", required_role="admin")
     async def remove(self, player_id: str) -> None:
         """
         Remove a player from a provider.
index 01183fcbf234f505ed7b7f316ea09226ac9dcbbb..9cb622633381c1db030872913b0c847847a4f12b 100644 (file)
@@ -218,9 +218,6 @@ class WebserverController(CoreController):
         # add info
         routes.append(("GET", "/info", self._handle_server_info))
         routes.append(("OPTIONS", "/info", self._handle_cors_preflight))
-        # add logging
-        routes.append(("GET", "/music-assistant.log", self._handle_application_log))
-        routes.append(("OPTIONS", "/music-assistant.log", self._handle_cors_preflight))
         # add websocket api
         routes.append(("GET", "/ws", self._handle_ws_client))
         # also host the image proxy on the webserver
@@ -539,19 +536,6 @@ class WebserverController(CoreController):
             self.logger.exception("Error executing command %s: %s", command_msg.command, error)
             return web.Response(status=500, text="Internal server error")
 
-    async def _handle_application_log(self, request: web.Request) -> web.Response:
-        """Handle request to get the application log."""
-        log_data = await self.mass.get_application_log()
-        return web.Response(
-            text=log_data,
-            content_type="text/text",
-            headers={
-                "Access-Control-Allow-Origin": "*",
-                "Access-Control-Allow-Methods": "GET, OPTIONS",
-                "Access-Control-Allow-Headers": "Content-Type, Authorization",
-            },
-        )
-
     async def _handle_api_intro(self, request: web.Request) -> web.Response:
         """Handle request for API introduction/documentation page."""
         intro_html_path = str(RESOURCES_DIR.joinpath("api_docs.html"))
index 0096590d01c30af9abe99dc52183ada697a600d8..c4520aea1a49018e9ff61c8c6e0456553f3c4544 100644 (file)
@@ -272,7 +272,9 @@ class RemoteAccessManager:
             return await get_remote_access_info()
 
         self._on_unload_callbacks.append(
-            self.mass.register_api_command("remote_access/info", get_remote_access_info)
+            self.mass.register_api_command(
+                "remote_access/info", get_remote_access_info, required_role="admin"
+            )
         )
         self._on_unload_callbacks.append(
             self.mass.register_api_command(