From 0f93e51a553ea22f74a2cd78750b57a9095cfada Mon Sep 17 00:00:00 2001
From: mwiegand <mwiegand@seibert-media.net>
Date: Thu, 8 Jul 2021 16:02:31 +0200
Subject: [PATCH] wip

---
 bundles/roundcube/items.py    | 38 ++++++++++++++++++++++++-----
 bundles/roundcube/metadata.py |  1 +
 items/download.py             | 46 ++++++++++++++++++++++++++---------
 nodes/htz.mails.py            |  2 +-
 4 files changed, 69 insertions(+), 18 deletions(-)

diff --git a/bundles/roundcube/items.py b/bundles/roundcube/items.py
index aabb2e3..4037dbb 100644
--- a/bundles/roundcube/items.py
+++ b/bundles/roundcube/items.py
@@ -1,6 +1,8 @@
 assert node.has_bundle('php')
 assert node.has_bundle('mailserver')
 
+version = node.metadata.get('roundcube/version')
+
 directories = {
     '/opt/roundcube': {
         'owner': 'www-data',
@@ -8,27 +10,48 @@ directories = {
     '/opt/roundcube/logs': {
         'owner': 'www-data',
         'needs': [
-            'git_deploy:/opt/roundcube',
+            'action:extract_roundcube',
         ],
     },
     '/opt/roundcube/temp': {
         'owner': 'www-data',
         'needs': [
-            'git_deploy:/opt/roundcube',
+            'action:extract_roundcube',
         ],
     }
 }
 
-git_deploy['/opt/roundcube'] = {
-    'repo': "git://github.com/roundcube/roundcubemail.git",
-    'rev': node.metadata.get('roundcube/version'),
+
+downloads[f'/tmp/roundcube-{version}.tar.gz'] = {
+    'url': f'https://github.com/roundcube/roundcubemail/releases/download/{version}/roundcubemail-{version}-complete.tar.gz',
+    'gpg_signature_url': '{url}.asc',
+    'gpg_pubkey_url': 'https://roundcube.net/download/pubkey.asc',
+    'triggered': True,
+}
+actions['delete_roundcube'] = {
+    'command': 'rm -rf /opt/roundcube/*',
+    'triggered': True,
+}
+actions['extract_roundcube'] = {
+    'command': f'tar xfvz /tmp/roundcube-{version}.tar.gz --strip 1 -C /opt/roundcube',
+    'unless': f'grep -q "Version {version}" /opt/roundcube/index.php',
+    'preceded_by': [
+        'action:delete_roundcube',
+        f'download:/tmp/roundcube-{version}.tar.gz',
+    ],
     'needs': [
         'directory:/opt/roundcube',
     ],
     'triggers': [
+        'action:chown_roundcube',
         'action:composer_install',
     ],
 }
+actions['chown_roundcube'] = {
+    'command': 'chown -R www-data /opt/roundcube',
+    'triggered': True,
+}
+
 
 files['/opt/roundcube/config/config.inc.php'] = {
     'content_type': 'mako',
@@ -40,11 +63,14 @@ files['/opt/roundcube/config/config.inc.php'] = {
         'plugins': node.metadata.get('roundcube/plugins'),
     },
     'needs': [
-        'git_deploy:/opt/roundcube',
+        'action:chown_roundcube',
     ],
 }
 
 actions['composer_install'] = {
     'command': "cp /opt/roundcube/composer.json-dist /opt/roundcube/composer.json && su www-data -s /bin/bash -c '/usr/bin/composer -d /opt/roundcube install'",
     'triggered': True,
+    'needs': [
+        'action:chown_roundcube',
+    ],
 }
diff --git a/bundles/roundcube/metadata.py b/bundles/roundcube/metadata.py
index e6ec684..3014194 100644
--- a/bundles/roundcube/metadata.py
+++ b/bundles/roundcube/metadata.py
@@ -22,6 +22,7 @@ defaults = {
             'php-curl': {},
             'php-gd': {},
             'composer': {},
+            'php-ldap': {},
         },
     },
     'roundcube': {
diff --git a/items/download.py b/items/download.py
index 8d52e50..c710f01 100644
--- a/items/download.py
+++ b/items/download.py
@@ -20,14 +20,16 @@ class Download(Item):
         "pkg_zypper:",
     ]
     ITEM_ATTRIBUTES = {
-        'url': "",
-        'sha256': "",
-        'sha256_url': "",
+        'url': None,
+        'sha256': None,
+        'sha256_url': None,
+        'gpg_signature_url': None,
+        'gpg_pubkey_url': None,
         'verifySSL': True,
         'decompress': None,
     }
     ITEM_TYPE_NAME = "download"
-    REQUIRED_ATTRIBUTES = []
+    REQUIRED_ATTRIBUTES = ['url']
 
     def __repr__(self):
         return "<Download name:{}>".format(self.name)
@@ -67,9 +69,15 @@ class Download(Item):
         """This is how the world should be"""
         cdict = {
             'type': 'download',
-            'sha256': self.attributes['sha256'],
         }
 
+        if self.attributes.get('sha256'):
+            cdict['sha256'] = self.attributes['sha256']
+        elif self.attributes.get('gpg_signature_url'):
+            cdict['verified'] = True
+        else:
+            raise
+
         return cdict
 
     def sdict(self):
@@ -81,19 +89,35 @@ class Download(Item):
             sdict = {
                 'type': 'download',
             }
-            if 'sha256' in self.attributes:
+            if self.attributes.get('sha256'):
                 sdict['sha256'] = self.attributes['sha256']
-            elif 'sha256_url' in self.attributes:
-                sha256_url = self.attributes['sha256_url'].format(url=self.attributes['url'])
+            elif self.attributes.get('sha256_url'):
+                full_sha256_url = self.attributes['sha256_url'].format(url=self.attributes['url'])
                 sdict['sha256'] = force_text(
-                    self.node.run(f"curl -L -s -- {quote(sha256_url)}").stdout
+                    self.node.run(f"curl -sL -- {quote(full_sha256_url)}").stdout
                 ).strip().split()[0]
-
+            elif self.attributes.get('gpg_signature_url'):
+                full_signature_url = self.attributes['gpg_signature_url'].format(url=self.attributes['url'])
+                signature_path = f'{self.name}.signature'
+                
+                self.node.run(f"curl -sSL {self.attributes['gpg_pubkey_url']} | gpg --import -")
+                self.node.run(f"curl -L {full_signature_url} -o {quote(signature_path)}")
+                gpg_output = self.node.run(f"gpg --verify {quote(signature_path)} {quote(self.name)}").stderr
+                
+                if b'Good signature' in gpg_output:
+                    sdict['verified'] = True
+                else:
+                    sdict['verified'] = False
+                    
         return sdict
 
     @classmethod
     def validate_attributes(cls, bundle, item_id, attributes):
-        if 'sha256' not in attributes and 'sha256_url' not in attributes:
+        if (
+            'sha256' not in attributes and
+            'sha256_url' not in attributes and
+            'gpg_signature_url'not in attributes
+        ):
             raise BundleError(_(
                 "at least one hash must be set on {item} in bundle '{bundle}'"
             ).format(
diff --git a/nodes/htz.mails.py b/nodes/htz.mails.py
index 27dd41e..17aa7f0 100644
--- a/nodes/htz.mails.py
+++ b/nodes/htz.mails.py
@@ -78,7 +78,7 @@
         },
         'roundcube': {
             'product_name': 'Sublimity Mail',
-            'version': '6466d10339d44a077de4fe094c89ed35ae84da96',
+            'version': '1.5-rc',
             'installer': True,
         },
         'users': {