Browse Source

[Web][DockerApi] migrate imap acl on mbox rename

FreddleSpl0it 1 year ago
parent
commit
be5a181be5

+ 4 - 4
data/Dockerfiles/dockerapi/main.py

@@ -90,7 +90,7 @@ async def get_container(container_id : str):
         if container._id == container_id:
           container_info = await container.show()
           return Response(content=json.dumps(container_info, indent=4), media_type="application/json")
-     
+
       res = {
         "type": "danger",
         "msg": "no container found"
@@ -130,7 +130,7 @@ async def get_containers():
 async def post_containers(container_id : str, post_action : str, request: Request):
   global dockerapi
 
-  try : 
+  try:
     request_json = await request.json()
   except Exception as err:
     request_json = {}
@@ -191,7 +191,7 @@ async def post_container_update_stats(container_id : str):
 
   stats = json.loads(await dockerapi.redis_client.get(container_id + '_stats'))
   return Response(content=json.dumps(stats, indent=4), media_type="application/json")
-  
+
 
 # PubSub Handler
 async def handle_pubsub_messages(channel: aioredis.client.PubSub):
@@ -244,7 +244,7 @@ async def handle_pubsub_messages(channel: aioredis.client.PubSub):
               dockerapi.logger.error("Unknwon PubSub recieved - %s" % json.dumps(data_json))
           else:
             dockerapi.logger.error("Unknwon PubSub recieved - %s" % json.dumps(data_json))
-              
+
         await asyncio.sleep(0.0)
     except asyncio.TimeoutError:
       pass

+ 79 - 2
data/Dockerfiles/dockerapi/modules/DockerApi.py

@@ -353,14 +353,14 @@ class DockerApi:
       for container in self.sync_docker_client.containers.list(filters=filters):
         vmail_name = request_json['old_maildir'].replace("'", "'\\''")
         new_vmail_name = request_json['new_maildir'].replace("'", "'\\''")
-        cmd_vmail = "if [[ -d '/var/vmail/" + vmail_name + "' ]]; then /bin/mv '/var/vmail/" + vmail_name + "' '/var/vmail/" + new_vmail_name + "'; fi"
+        cmd_vmail = f"if [[ -d '/var/vmail/{vmail_name}' ]]; then /bin/mv '/var/vmail/{vmail_name}' '/var/vmail/{new_vmail_name}'; fi"
 
         index_name = request_json['old_maildir'].split("/")
         new_index_name = request_json['new_maildir'].split("/")
         if len(index_name) > 1 and len(new_index_name) > 1:
           index_name = index_name[1].replace("'", "'\\''") + "@" + index_name[0].replace("'", "'\\''")
           new_index_name = new_index_name[1].replace("'", "'\\''") + "@" + new_index_name[0].replace("'", "'\\''")
-          cmd_vmail_index = "if [[ -d '/var/vmail_index/" + index_name + "' ]]; then /bin/mv '/var/vmail_index/" + index_name + "' '/var/vmail_index/" + new_index_name + "_index'; fi"
+          cmd_vmail_index = f"if [[ -d '/var/vmail_index/{index_name}' ]]; then /bin/mv '/var/vmail_index/{index_name}' '/var/vmail_index/{new_index_name}_index'; fi"
           cmd = ["/bin/bash", "-c", cmd_vmail + " && " + cmd_vmail_index]
         else:
           cmd = ["/bin/bash", "-c", cmd_vmail]
@@ -412,6 +412,83 @@ class DockerApi:
 
         sogo_return = container.exec_run(['sogo-tool', 'rename-user', old_username, new_username], user='sogo')
         return self.exec_run_handler('generic', sogo_return)
+  # api call: container_post - post_action: exec - cmd: dovecot - task: get_acl
+  def container_post__exec__dovecot__get_acl(self, request_json, **kwargs):
+    if 'container_id' in kwargs:
+      filters = {"id": kwargs['container_id']}
+    elif 'container_name' in kwargs:
+      filters = {"name": kwargs['container_name']}
+
+    for container in self.sync_docker_client.containers.list(filters=filters):
+      vmail_name = request_json['maildir'].replace("'", "'\\''")
+      shared_folders = container.exec_run(["/bin/bash", "-c", f"find /var/vmail/{vmail_name}/Maildir/Shared -mindepth 2 -type d | sed 's:^/var/vmail/{vmail_name}/Maildir/Shared/::' | tr '/' '\\\\'"])
+      shared_folders = shared_folders.output.decode('utf-8')
+      formatted_acls = []
+      if shared_folders:
+        shared_folders = shared_folders.splitlines()
+        for shared_folder in shared_folders:
+          if "\\." not in shared_folder:
+            continue
+          shared_folder = shared_folder.split("\\.")
+          acls = container.exec_run(["/bin/bash", "-c", f"doveadm acl get -u {shared_folder[0]} {shared_folder[1]}"])
+          acls = acls.output.decode('utf-8').strip().splitlines()
+          if len(acls) >= 2:
+            for acl in acls[1:]:
+              id, rights = acls[1].split(maxsplit=1)
+              id = id.replace("user=", "")
+              formatted_acls.append({ 'user': shared_folder[0], 'id': id, 'mailbox': shared_folder[1], 'rights': rights.split() })
+
+      return Response(content=json.dumps(formatted_acls, indent=4), media_type="application/json")
+  # api call: container_post - post_action: exec - cmd: dovecot - task: delete_acl
+  def container_post__exec__dovecot__delete_acl(self, request_json, **kwargs):
+    if 'container_id' in kwargs:
+      filters = {"id": kwargs['container_id']}
+    elif 'container_name' in kwargs:
+      filters = {"name": kwargs['container_name']}
+
+    for container in self.sync_docker_client.containers.list(filters=filters):
+      user = request_json['user'].replace("'", "'\\''")
+      mailbox = request_json['mailbox'].replace("'", "'\\''")
+      id = request_json['id'].replace("'", "'\\''")
+
+      if user and mailbox and id:
+        acl_delete_return = container.exec_run(["/bin/bash", "-c", f'doveadm acl delete -u {user} {mailbox} "user={id}"'])
+        return self.exec_run_handler('generic', acl_delete_return)
+  # api call: container_post - post_action: exec - cmd: dovecot - task: set_acl
+  def container_post__exec__dovecot__set_acl(self, request_json, **kwargs):
+    if 'container_id' in kwargs:
+      filters = {"id": kwargs['container_id']}
+    elif 'container_name' in kwargs:
+      filters = {"name": kwargs['container_name']}
+
+    for container in self.sync_docker_client.containers.list(filters=filters):
+      user = request_json['user'].replace("'", "'\\''")
+      mailbox = request_json['mailbox'].replace("'", "'\\''")
+      id = request_json['id'].replace("'", "'\\''")
+      rights = ""
+
+      available_rights = [
+        "admin",
+        "create",
+        "delete",
+        "expunge",
+        "insert",
+        "lookup",
+        "post",
+        "read",
+        "write",
+        "write-deleted",
+        "write-seen"
+      ]
+      for right in request_json['rights']:
+        right = right.replace("'", "'\\''").lower()
+        if right in available_rights:
+          rights += right + " "
+
+      if user and mailbox and id and rights:
+        acl_set_return = container.exec_run(["/bin/bash", "-c", f'doveadm acl set -u {user} {mailbox} "user={id}" {rights}'])
+        return self.exec_run_handler('generic', acl_set_return)
+
 
   # Collect host stats
   async def get_host_stats(self, wait=5):

+ 32 - 0
data/web/inc/functions.mailbox.inc.php

@@ -3247,6 +3247,25 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
             return false;
           }
 
+          // get imap acls
+          $exec_fields = array(
+            'cmd' => 'dovecot',
+            'task' => 'get_acl',
+            'maildir' => $domain . '/' . $old_local_part,
+          );
+          $imap_acls = json_decode(docker('post', 'dovecot-mailcow', 'exec', $exec_fields), true);
+          // delete imap acls
+          foreach ($imap_acls as $imap_acl) {
+            $exec_fields = array(
+              'cmd' => 'dovecot',
+              'task' => 'delete_acl',
+              'user' => $imap_acl['user'],
+              'mailbox' => $imap_acl['mailbox'],
+              'id' => $imap_acl['id']
+            );
+            docker('post', 'dovecot-mailcow', 'exec', $exec_fields);
+          }
+
           // rename username in sql
           try {
             $pdo->beginTransaction();
@@ -3326,6 +3345,19 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
           );
           docker('post', 'sogo-mailcow', 'exec', $exec_fields);
 
+          // set imap acls
+          foreach ($imap_acls as $imap_acl) {
+            $exec_fields = array(
+              'cmd' => 'dovecot',
+              'task' => 'set_acl',
+              'user' => $imap_acl['user'],
+              'mailbox' => $imap_acl['mailbox'],
+              'id' => $new_username,
+              'rights' => $imap_acl['rights']
+            );
+            docker('post', 'dovecot-mailcow', 'exec', $exec_fields);
+          }
+
           // create alias
           if ($create_alias == 1) {
             mailbox("add", "alias", array(