Repository: paperless-ngx/paperless-ngx

Issue:
[BUG] Redis credentials displayed on the frontend
### Description

Hey everyone, after visiting the brand new System Status modal I was amazed how awesome this new feature is. Thank you for adding this to paperless! But while taking a closer look, I felt some anxiety because suddenly I was looking at my redis credentials. In plain text. And any other user I've given admin status would see it too. 
This was certainly by mistake, which is why I am reporting this as a bug.

This is a rather serious issue for me since I am also hosting instances for other people using the same redis instance. They are not supposed to see my redis credentials. Nobody is supposed to.

### Steps to reproduce

Open the new System Status modal. There are two ways to display the credentials: either by hovering over the icon for the redis status, or by clicking "copy" in the modal footer and then pasting the copied json somewhere. 

### Webserver logs

```bash
not applicable
```


### Browser logs

_No response_

### Paperless-ngx version

2.6.2

### Host OS

Archlinux

### Installation method

Docker - official image

### Browser

_No response_

### Configuration changes

_No response_

### Other

_No response_

### Please confirm the following

- [X] I believe this issue is a bug that affects all users of Paperless-ngx, not something specific to my installation.
- [X] I have already searched for relevant existing issues and discussions before opening this report.
- [X] I have updated the title field above with a concise description.


Discussion:
Im happy to entertain changing this, but this is why it requires admin permissions.

Resolving patch:
diff --git a/src/documents/views.py b/src/documents/views.py
--- a/src/documents/views.py
+++ b/src/documents/views.py
@@ -12,6 +12,7 @@
 from time import mktime
 from unicodedata import normalize
 from urllib.parse import quote
+from urllib.parse import urlparse
 
 import pathvalidate
 from django.apps import apps
@@ -1617,6 +1618,10 @@ def get(self, request, format=None):
         media_stats = os.statvfs(settings.MEDIA_ROOT)
 
         redis_url = settings._CHANNELS_REDIS_URL
+        redis_url_parsed = urlparse(redis_url)
+        redis_constructed_url = f"{redis_url_parsed.scheme}://{redis_url_parsed.path or redis_url_parsed.hostname}"
+        if redis_url_parsed.hostname is not None:
+            redis_constructed_url += f":{redis_url_parsed.port}"
         redis_error = None
         with Redis.from_url(url=redis_url) as client:
             try:
@@ -1728,7 +1733,7 @@ def get(self, request, format=None):
                     },
                 },
                 "tasks": {
-                    "redis_url": redis_url,
+                    "redis_url": redis_constructed_url,
                     "redis_status": redis_status,
                     "redis_error": redis_error,
                     "celery_status": celery_active,


Test patch:
diff --git a/src/documents/tests/test_api_status.py b/src/documents/tests/test_api_status.py
--- a/src/documents/tests/test_api_status.py
+++ b/src/documents/tests/test_api_status.py
@@ -100,6 +100,45 @@ def test_system_status_redis_ping(self, mock_ping):
         self.assertEqual(response.status_code, status.HTTP_200_OK)
         self.assertEqual(response.data["tasks"]["redis_status"], "OK")
 
+    def test_system_status_redis_no_credentials(self):
+        """
+        GIVEN:
+            - Redis URL with credentials
+        WHEN:
+            - The user requests the system status
+        THEN:
+            - The response contains the redis URL but no credentials
+        """
+        with override_settings(
+            _CHANNELS_REDIS_URL="redis://username:password@localhost:6379",
+        ):
+            self.client.force_login(self.user)
+            response = self.client.get(self.ENDPOINT)
+            self.assertEqual(response.status_code, status.HTTP_200_OK)
+            self.assertEqual(
+                response.data["tasks"]["redis_url"],
+                "redis://localhost:6379",
+            )
+
+    def test_system_status_redis_socket(self):
+        """
+        GIVEN:
+            - Redis URL is socket
+        WHEN:
+            - The user requests the system status
+        THEN:
+            - The response contains the redis URL
+        """
+
+        with override_settings(_CHANNELS_REDIS_URL="unix:///path/to/redis.sock"):
+            self.client.force_login(self.user)
+            response = self.client.get(self.ENDPOINT)
+            self.assertEqual(response.status_code, status.HTTP_200_OK)
+            self.assertEqual(
+                response.data["tasks"]["redis_url"],
+                "unix:///path/to/redis.sock",
+            )
+
     @mock.patch("celery.app.control.Inspect.ping")
     def test_system_status_celery_ping(self, mock_ping):
         """