Exemplo n.º 1
0
    /**
     *  Modified from LoadClientAppsJob and I2PTunnelHTTPClientBase
     *  All keys are mapped to lower case.
     *
     *  @param args non-null
     *  @since 0.9.4
     */
    private static Map<String, String> parseArgs(String args) {
        Map<String, String> rv = new HashMap<String, String>(8);
        char data[] = args.toCharArray();
        StringBuilder buf = new StringBuilder(32);
        boolean isQuoted = false;
        String key = null;
        for (int i = 0; i < data.length; i++) {
            switch (data[i]) {
                case '\'':
                case '"':
                    if (isQuoted) {
                        // keys never quoted
                        if (key != null) {
                            rv.put(key, buf.toString().trim());
                            key = null;
                        }
                        buf.setLength(0);
                    }
                    isQuoted = !isQuoted;
                    break;

                case ' ':
                case '\r':
                case '\n':
                case '\t':
                case ',':
                    // whitespace - if we're in a quoted section, keep this as part of the quote,
                    // otherwise use it as a delim
                    if (isQuoted) {
                        buf.append(data[i]);
                    } else {
                        if (key != null) {
                            rv.put(key, buf.toString().trim());
                            key = null;
                        }
                        buf.setLength(0);
                    }
                    break;

                case '=':
                    if (isQuoted) {
                        buf.append(data[i]);
                    } else {
                        key = buf.toString().trim().toLowerCase(Locale.US);
                        buf.setLength(0);
                    }
                    break;

                default:
                    buf.append(data[i]);
                    break;
            }
        }
        if (key != null)
            rv.put(key, buf.toString().trim());
        return rv;
    }
Exemplo n.º 2
0
  /**
   * @return true on success
   * @throws just about anything, caller would be wise to catch Throwable
   */
  public static boolean startPlugin(RouterContext ctx, String appName) throws Exception {
    Log log = ctx.logManager().getLog(PluginStarter.class);
    File pluginDir = new File(ctx.getConfigDir(), PLUGIN_DIR + '/' + appName);
    String iconfile = null;
    if ((!pluginDir.exists()) || (!pluginDir.isDirectory())) {
      log.error("Cannot start nonexistent plugin: " + appName);
      disablePlugin(appName);
      return false;
    }

    // Do we need to extract an update?
    File pluginUpdate = new File(ctx.getConfigDir(), PLUGIN_DIR + '/' + appName + "/app.xpi2p.zip");
    if (pluginUpdate.exists()) {
      // Compare the start time of the router with the plugin.
      if (ctx.router().getWhenStarted() > pluginUpdate.lastModified()) {
        if (!FileUtil.extractZip(pluginUpdate, pluginDir)) {
          pluginUpdate.delete();
          String foo =
              "Plugin '"
                  + appName
                  + "' failed to update! File '"
                  + pluginUpdate
                  + "' deleted. You may need to remove and install the plugin again.";
          log.error(foo);
          disablePlugin(appName);
          throw new Exception(foo);
        } else {
          pluginUpdate.delete();
          // Need to always log this, and  log.logAlways() did not work for me.
          System.err.println("INFO: Plugin updated: " + appName);
        }
      } // silently fail to update, because we have not restarted.
    }

    Properties props = pluginProperties(ctx, appName);

    String minVersion = ConfigClientsHelper.stripHTML(props, "min-i2p-version");
    if (minVersion != null && VersionComparator.comp(CoreVersion.VERSION, minVersion) < 0) {
      String foo = "Plugin " + appName + " requires I2P version " + minVersion + " or higher";
      log.error(foo);
      disablePlugin(appName);
      throw new Exception(foo);
    }

    minVersion = ConfigClientsHelper.stripHTML(props, "min-java-version");
    if (minVersion != null
        && VersionComparator.comp(System.getProperty("java.version"), minVersion) < 0) {
      String foo = "Plugin " + appName + " requires Java version " + minVersion + " or higher";
      log.error(foo);
      disablePlugin(appName);
      throw new Exception(foo);
    }

    String jVersion = LogsHelper.jettyVersion();
    minVersion = ConfigClientsHelper.stripHTML(props, "min-jetty-version");
    if (minVersion != null && VersionComparator.comp(minVersion, jVersion) > 0) {
      String foo = "Plugin " + appName + " requires Jetty version " + minVersion + " or higher";
      log.error(foo);
      disablePlugin(appName);
      throw new Exception(foo);
    }

    String maxVersion = ConfigClientsHelper.stripHTML(props, "max-jetty-version");
    if (maxVersion != null && VersionComparator.comp(maxVersion, jVersion) < 0) {
      String foo = "Plugin " + appName + " requires Jetty version " + maxVersion + " or lower";
      log.error(foo);
      disablePlugin(appName);
      throw new Exception(foo);
    }

    if (log.shouldLog(Log.INFO)) log.info("Starting plugin: " + appName);

    // register themes
    File dir = new File(pluginDir, "console/themes");
    File[] tfiles = dir.listFiles();
    if (tfiles != null) {
      for (int i = 0; i < tfiles.length; i++) {
        String name = tfiles[i].getName();
        if (tfiles[i].isDirectory() && (!Arrays.asList(STANDARD_THEMES).contains(tfiles[i])))
          ctx.router()
              .setConfigSetting(ConfigUIHelper.PROP_THEME_PFX + name, tfiles[i].getAbsolutePath());
        // we don't need to save
      }
    }

    // load and start things in clients.config
    File clientConfig = new File(pluginDir, "clients.config");
    if (clientConfig.exists()) {
      Properties cprops = new Properties();
      DataHelper.loadProps(cprops, clientConfig);
      List<ClientAppConfig> clients = ClientAppConfig.getClientApps(clientConfig);
      runClientApps(ctx, pluginDir, clients, "start");
    }

    // start console webapps in console/webapps
    ContextHandlerCollection server = WebAppStarter.getConsoleServer();
    if (server != null) {
      File consoleDir = new File(pluginDir, "console");
      Properties wprops = RouterConsoleRunner.webAppProperties(consoleDir.getAbsolutePath());
      File webappDir = new File(consoleDir, "webapps");
      String fileNames[] = webappDir.list(RouterConsoleRunner.WarFilenameFilter.instance());
      if (fileNames != null) {
        if (!pluginWars.containsKey(appName))
          pluginWars.put(appName, new ConcurrentHashSet<String>());
        for (int i = 0; i < fileNames.length; i++) {
          try {
            String warName = fileNames[i].substring(0, fileNames[i].lastIndexOf(".war"));
            // log.error("Found webapp: " + warName);
            // check for duplicates in $I2P
            if (Arrays.asList(STANDARD_WEBAPPS).contains(warName)) {
              log.error("Skipping duplicate webapp " + warName + " in plugin " + appName);
              continue;
            }
            String enabled = wprops.getProperty(RouterConsoleRunner.PREFIX + warName + ENABLED);
            if (!"false".equals(enabled)) {
              if (log.shouldLog(Log.INFO)) log.info("Starting webapp: " + warName);
              String path = new File(webappDir, fileNames[i]).getCanonicalPath();
              WebAppStarter.startWebApp(ctx, server, warName, path);
              pluginWars.get(appName).add(warName);
            }
          } catch (IOException ioe) {
            log.error("Error resolving '" + fileNames[i] + "' in '" + webappDir, ioe);
          }
        }
        // Check for iconfile in plugin.properties
        String icfile = ConfigClientsHelper.stripHTML(props, "console-icon");
        if (icfile != null && !icfile.contains("..")) {
          StringBuilder buf = new StringBuilder(32);
          buf.append('/').append(appName);
          if (!icfile.startsWith("/")) buf.append('/');
          buf.append(icfile);
          iconfile = buf.toString();
        }
      }
    } else {
      log.error("No console web server to start plugins?");
    }

    // add translation jars in console/locale
    // These will not override existing resource bundles since we are adding them
    // later in the classpath.
    File localeDir = new File(pluginDir, "console/locale");
    if (localeDir.exists() && localeDir.isDirectory()) {
      File[] files = localeDir.listFiles();
      if (files != null) {
        boolean added = false;
        for (int i = 0; i < files.length; i++) {
          File f = files[i];
          if (f.getName().endsWith(".jar")) {
            try {
              addPath(f.toURI().toURL());
              log.error("INFO: Adding translation plugin to classpath: " + f);
              added = true;
            } catch (Exception e) {
              log.error("Plugin " + appName + " bad classpath element: " + f, e);
            }
          }
        }
        if (added) Translate.clearCache();
      }
    }
    // add summary bar link
    String name =
        ConfigClientsHelper.stripHTML(props, "consoleLinkName_" + Messages.getLanguage(ctx));
    if (name == null) name = ConfigClientsHelper.stripHTML(props, "consoleLinkName");
    String url = ConfigClientsHelper.stripHTML(props, "consoleLinkURL");
    if (name != null && url != null && name.length() > 0 && url.length() > 0) {
      String tip =
          ConfigClientsHelper.stripHTML(props, "consoleLinkTooltip_" + Messages.getLanguage(ctx));
      if (tip == null) tip = ConfigClientsHelper.stripHTML(props, "consoleLinkTooltip");
      NavHelper.registerApp(name, url, tip, iconfile);
    }

    return true;
  }
Exemplo n.º 3
0
 /**
  *  Parse the installed (not the temp) news file for the latest version.
  *  TODO: Real XML parsing
  *  TODO: Check minVersion, use backup URLs specified
  */
 void checkForUpdates() {
     FileInputStream in = null;
     try {
         in = new FileInputStream(_newsFile);
         StringBuilder buf = new StringBuilder(128);
         while (DataHelper.readLine(in, buf)) {
             int index = buf.indexOf(VERSION_PREFIX);
             if (index >= 0) {
                 Map<String, String> args = parseArgs(buf.substring(index+VERSION_PREFIX.length()));
                 String ver = args.get(VERSION_KEY);
                 if (ver != null) {
                     if (_log.shouldLog(Log.DEBUG))
                         _log.debug("Found version: [" + ver + "]");
                     if (TrustedUpdate.needsUpdate(RouterVersion.VERSION, ver)) {
                         if (NewsHelper.isUpdateDisabled(_context)) {
                             String msg = _mgr._("In-network updates disabled. Check package manager.");
                             _log.logAlways(Log.WARN, "Cannot update to version " + ver + ": " + msg);
                             _mgr.notifyVersionConstraint(this, _currentURI, ROUTER_SIGNED, "", ver, msg);
                             return;
                         }
                         if (NewsHelper.isBaseReadonly(_context)) {
                             String msg = _mgr._("No write permission for I2P install directory.");
                             _log.logAlways(Log.WARN, "Cannot update to version " + ver + ": " + msg);
                             _mgr.notifyVersionConstraint(this, _currentURI, ROUTER_SIGNED, "", ver, msg);
                             return;
                         }
                         String minRouter = args.get(MIN_VERSION_KEY);
                         if (minRouter != null) {
                             if (VersionComparator.comp(RouterVersion.VERSION, minRouter) < 0) {
                                 String msg = _mgr._("You must first update to version {0}", minRouter);
                                 _log.logAlways(Log.WARN, "Cannot update to version " + ver + ": " + msg);
                                 _mgr.notifyVersionConstraint(this, _currentURI, ROUTER_SIGNED, "", ver, msg);
                                 return;
                             }
                         }
                         String minJava = args.get(MIN_JAVA_VERSION_KEY);
                         if (minJava != null) {
                             String ourJava = System.getProperty("java.version");
                             if (VersionComparator.comp(ourJava, minJava) < 0) {
                                 String msg = _mgr._("Requires Java version {0} but installed Java version is {1}", minJava, ourJava);
                                 _log.logAlways(Log.WARN, "Cannot update to version " + ver + ": " + msg);
                                 _mgr.notifyVersionConstraint(this, _currentURI, ROUTER_SIGNED, "", ver, msg);
                                 return;
                             }
                         }
                         if (_log.shouldLog(Log.DEBUG))
                             _log.debug("Our version is out of date, update!");
                         // TODO if minversion > our version, continue
                         // and look for a second entry with clearnet URLs
                         // TODO clearnet URLs, notify with HTTP_CLEARNET and/or HTTPS_CLEARNET
                         Map<UpdateMethod, List<URI>> sourceMap = new HashMap<UpdateMethod, List<URI>>(4);
                         // Must do su3 first
                         if (ConfigUpdateHandler.USE_SU3_UPDATE) {
                             sourceMap.put(HTTP, _mgr.getUpdateURLs(ROUTER_SIGNED_SU3, "", HTTP));
                             addMethod(TORRENT, args.get(SU3_KEY), sourceMap);
                             addMethod(HTTP_CLEARNET, args.get(CLEARNET_HTTP_SU3_KEY), sourceMap);
                             addMethod(HTTPS_CLEARNET, args.get(CLEARNET_HTTPS_SU3_KEY), sourceMap);
                             // notify about all sources at once
                             _mgr.notifyVersionAvailable(this, _currentURI, ROUTER_SIGNED_SU3,
                                                         "", sourceMap, ver, "");
                             sourceMap.clear();
                         }
                         // now do sud/su2
                         sourceMap.put(HTTP, _mgr.getUpdateURLs(ROUTER_SIGNED, "", HTTP));
                         String key = FileUtil.isPack200Supported() ? SU2_KEY : SUD_KEY;
                         addMethod(TORRENT, args.get(key), sourceMap);
                         // notify about all sources at once
                         _mgr.notifyVersionAvailable(this, _currentURI, ROUTER_SIGNED,
                                                     "", sourceMap, ver, "");
                     } else {
                         if (_log.shouldLog(Log.DEBUG))
                             _log.debug("Our version is current");
                     }
                     return;
                 } else {
                     if (_log.shouldLog(Log.WARN))
                         _log.warn("No version in " + buf.toString());
                 }
             } else {
                 if (_log.shouldLog(Log.DEBUG))
                     _log.debug("No match in " + buf.toString());
             }
             buf.setLength(0);
         }
     } catch (IOException ioe) {
         if (_log.shouldLog(Log.WARN))
             _log.warn("Error checking the news for an update", ioe);
         return;
     } finally {
         if (in != null) try { in.close(); } catch (IOException ioe) {}
     }
     
     if (_log.shouldLog(Log.WARN))
         _log.warn("No version found in news.xml file");
 }