From 35bb8c5348ead682534072278bd8ce7540bf459c Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Thu, 7 Aug 2014 19:06:41 +0000
Subject: [PATCH] Plugins: partial SU3 support

---
 .../i2p/router/update/PluginUpdateRunner.java | 94 ++++++++++++++-----
 1 file changed, 70 insertions(+), 24 deletions(-)

diff --git a/apps/routerconsole/java/src/net/i2p/router/update/PluginUpdateRunner.java b/apps/routerconsole/java/src/net/i2p/router/update/PluginUpdateRunner.java
index 65df785db2..0025436a54 100644
--- a/apps/routerconsole/java/src/net/i2p/router/update/PluginUpdateRunner.java
+++ b/apps/routerconsole/java/src/net/i2p/router/update/PluginUpdateRunner.java
@@ -175,27 +175,9 @@ class PluginUpdateRunner extends UpdateRunner {
                 to.delete();
                 return;
             }
-            File tempDir = new File(_context.getTempDir(), "tmp" + _context.random().nextInt() + "-unzip");
-            if (!FileUtil.extractZip(to, tempDir, Log.ERROR)) {
-                f.delete();
-                to.delete();
-                FileUtil.rmdir(tempDir, false);
-                statusDone("<b>" + _("Plugin from {0} is corrupt", url) + "</b>");
+            Properties props = getPluginConfig(f, to, url);
+            if (props == null)
                 return;
-            }
-            File installProps = new File(tempDir, "plugin.config");
-            Properties props = new OrderedProperties();
-            try {
-                DataHelper.loadProps(props, installProps);
-            } catch (IOException ioe) {
-                f.delete();
-                to.delete();
-                FileUtil.rmdir(tempDir, false);
-                statusDone("<b>" + _("Plugin from {0} does not contain the required configuration file", url) + "</b>");
-                return;
-            }
-            // we don't need this anymore, we will unzip again
-            FileUtil.rmdir(tempDir, false);
 
             // ok, now we check sigs and deal with a bad sig
             String pubkey = props.getProperty("key");
@@ -259,20 +241,85 @@ class PluginUpdateRunner extends UpdateRunner {
 
             String sudVersion = TrustedUpdate.getVersionString(f);
             f.delete();
-            processFinal(to, appDir, tempDir, url, props, sudVersion, pubkey, signer);
+            processFinal(to, appDir, url, props, sudVersion, pubkey, signer);
         }
 
         /**
          *  @since 0.9.15
          */
         private void processSU3(File f, File appDir, String url) {
-            // TODO
+            SU3File su3 = new SU3File(_context, f);
+            File to = new File(_context.getTempDir(), "tmp" + _context.random().nextInt() + ZIP);
+            String sudVersion;
+            String signingKeyName;
+            try {
+                su3.verifyAndMigrate(to);
+                sudVersion = su3.getVersionString();
+                signingKeyName = su3.getSignerString();
+            } catch (IOException ioe) {
+                statusDone("<b>" + ioe + ' ' + _("from {0}", url) + " </b>");
+                f.delete();
+                to.delete();
+                return;
+            }
+            Properties props = getPluginConfig(f, to, url);
+            if (props == null)
+                return;
+            String pubkey = props.getProperty("key");
+            String signer = props.getProperty("signer");
+            if (pubkey == null || signer == null || pubkey.length() != 172 || signer.length() <= 0) {
+                f.delete();
+                to.delete();
+                statusDone("<b>" + _("Plugin from {0} contains an invalid key", url) + "</b>");
+                return;
+            }
+            if (!signer.equals(signingKeyName)) {
+                f.delete();
+                to.delete();
+                if (signingKeyName == null)
+                    _log.error("Failed to verify plugin signature, corrupt plugin or bad signature, signed by: " + signer);
+                else
+                    // shouldn't happen
+                    _log.error("Plugin signer \"" + signer + "\" does not match new signer in plugin.config file \"" + signingKeyName + "\"");
+                statusDone("<b>" + _("Plugin signature verification of {0} failed", url) + "</b>");
+                return;
+            }
+            processFinal(to, appDir, url, props, sudVersion, pubkey, signer);
+        }
+
+        /**
+         *  @since 0.9.15
+         *  @return null on error
+         */
+        private Properties getPluginConfig(File f, File to, String url) {
+            File tempDir = new File(_context.getTempDir(), "tmp" + _context.random().nextInt() + "-unzip");
+            if (!FileUtil.extractZip(to, tempDir, Log.ERROR)) {
+                f.delete();
+                to.delete();
+                FileUtil.rmdir(tempDir, false);
+                statusDone("<b>" + _("Plugin from {0} is corrupt", url) + "</b>");
+                return null;
+            }
+            File installProps = new File(tempDir, "plugin.config");
+            Properties props = new OrderedProperties();
+            try {
+                DataHelper.loadProps(props, installProps);
+            } catch (IOException ioe) {
+                f.delete();
+                to.delete();
+                statusDone("<b>" + _("Plugin from {0} does not contain the required configuration file", url) + "</b>");
+                return null;
+            } finally {
+                // we don't need this anymore, we will unzip again
+                FileUtil.rmdir(tempDir, false);
+            }
+            return props;
         }
 
         /**
          *  @since 0.9.15
          */
-        private void processFinal(File to, File appDir, File tempDir, String url, Properties props, String sudVersion, String pubkey, String signer) {
+        private void processFinal(File to, File appDir, String url, Properties props, String sudVersion, String pubkey, String signer) {
             boolean update = false;
             String appName = props.getProperty("name");
             String version = props.getProperty("version");
@@ -324,7 +371,6 @@ class PluginUpdateRunner extends UpdateRunner {
                     DataHelper.loadProps(oldProps, oldPropFile);
                 } catch (IOException ioe) {
                     to.delete();
-                    FileUtil.rmdir(tempDir, false);
                     statusDone("<b>" + _("Installed plugin does not contain the required configuration file", url) + "</b>");
                     return;
                 }
-- 
GitLab