Search in sources :

Example 1 with Log

use of net.i2p.util.Log in project i2p.i2p by i2p.

the class SAMHandlerFactory method createSAMHandler.

/**
 * Return the right SAM handler depending on the protocol version
 * required by the client.
 *
 * @param s Socket attached to SAM client
 * @param i2cpProps config options for our i2cp connection
 * @throws SAMException if the connection handshake (HELLO message) was malformed
 * @return A SAM protocol handler, or null if the client closed before the handshake
 */
public static SAMHandler createSAMHandler(SocketChannel s, Properties i2cpProps, SAMBridge parent) throws SAMException {
    String line;
    Log log = I2PAppContext.getGlobalContext().logManager().getLog(SAMHandlerFactory.class);
    try {
        Socket sock = s.socket();
        sock.setKeepAlive(true);
        StringBuilder buf = new StringBuilder(128);
        ReadLine.readLine(sock, buf, HELLO_TIMEOUT);
        sock.setSoTimeout(0);
        line = buf.toString();
    } catch (SocketTimeoutException e) {
        throw new SAMException("Timeout waiting for HELLO VERSION", e);
    } catch (IOException e) {
        throw new SAMException("Error reading from socket", e);
    } catch (RuntimeException e) {
        throw new SAMException("Unexpected error", e);
    }
    if (log.shouldDebug())
        log.debug("New message received: [" + line + ']');
    // Message format: HELLO VERSION [MIN=v1] [MAX=v2]
    Properties props = SAMUtils.parseParams(line);
    if (!"HELLO".equals(props.remove(SAMUtils.COMMAND)) || !"VERSION".equals(props.remove(SAMUtils.OPCODE))) {
        throw new SAMException("Must start with HELLO VERSION");
    }
    String minVer = props.getProperty("MIN");
    if (minVer == null) {
        // throw new SAMException("Missing MIN parameter in HELLO VERSION message");
        // MIN optional as of 0.9.14
        minVer = "1";
    }
    String maxVer = props.getProperty("MAX");
    if (maxVer == null) {
        // throw new SAMException("Missing MAX parameter in HELLO VERSION message");
        // MAX optional as of 0.9.14
        maxVer = "99.99";
    }
    String ver = chooseBestVersion(minVer, maxVer);
    if (ver == null) {
        SAMHandler.writeString("HELLO REPLY RESULT=NOVERSION\n", s);
        return null;
    }
    if (Boolean.parseBoolean(i2cpProps.getProperty(SAMBridge.PROP_AUTH))) {
        String user = props.getProperty("USER");
        String pw = props.getProperty("PASSWORD");
        if (user == null || pw == null) {
            if (user == null)
                log.logAlways(Log.WARN, "SAM authentication failed");
            else
                log.logAlways(Log.WARN, "SAM authentication failed, user: " + user);
            throw new SAMException("USER and PASSWORD required");
        }
        String savedPW = i2cpProps.getProperty(SAMBridge.PROP_PW_PREFIX + user + SAMBridge.PROP_PW_SUFFIX);
        if (savedPW == null) {
            log.logAlways(Log.WARN, "SAM authentication failed, user: " + user);
            throw new SAMException("Authorization failed");
        }
        PasswordManager pm = new PasswordManager(I2PAppContext.getGlobalContext());
        if (!pm.checkHash(savedPW, pw)) {
            log.logAlways(Log.WARN, "SAM authentication failed, user: " + user);
            throw new SAMException("Authorization failed");
        }
    }
    // Let's answer positively
    if (!SAMHandler.writeString("HELLO REPLY RESULT=OK VERSION=" + ver + "\n", s))
        throw new SAMException("Error writing to socket");
    // ...and instantiate the right SAM handler
    int verMajor = getMajor(ver);
    int verMinor = getMinor(ver);
    SAMHandler handler;
    try {
        switch(verMajor) {
            case 1:
                handler = new SAMv1Handler(s, verMajor, verMinor, i2cpProps, parent);
                break;
            case 2:
                handler = new SAMv2Handler(s, verMajor, verMinor, i2cpProps, parent);
                break;
            case 3:
                handler = new SAMv3Handler(s, verMajor, verMinor, i2cpProps, parent);
                break;
            default:
                log.error("BUG! Trying to initialize the wrong SAM version!");
                throw new SAMException("BUG! (in handler instantiation)");
        }
    } catch (IOException e) {
        log.error("Error creating the handler for version " + verMajor, e);
        throw new SAMException("IOException caught during SAM handler instantiation");
    }
    return handler;
}
Also used : Log(net.i2p.util.Log) PasswordManager(net.i2p.util.PasswordManager) IOException(java.io.IOException) Properties(java.util.Properties) SocketTimeoutException(java.net.SocketTimeoutException) Socket(java.net.Socket)

Example 2 with Log

use of net.i2p.util.Log in project i2p.i2p by i2p.

the class HostCheckHandler method handle.

/**
 *  Block by Host header,
 *  redirect HTTP to HTTPS,
 *  pass everything else to the delegate.
 */
public void handle(String pathInContext, Request baseRequest, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException {
    String host = httpRequest.getHeader("Host");
    if (!allowHost(host)) {
        Log log = _context.logManager().getLog(HostCheckHandler.class);
        host = DataHelper.stripHTML(getHost(host));
        String s = "Console request denied.\n" + "    To allow access using the hostname \"" + host + "\",\n" + "    add the line \"" + RouterConsoleRunner.PROP_ALLOWED_HOSTS + '=' + host + "\"\n" + "    to advanced configuration and restart.";
        log.logAlways(Log.WARN, s);
        httpResponse.sendError(403, s);
        baseRequest.setHandled(true);
        return;
    }
    // https://w3c.github.io/webappsec-upgrade-insecure-requests/
    if (!httpRequest.isSecure()) {
        int httpsPort = _portMapper.getPort(PortMapper.SVC_HTTPS_CONSOLE);
        if (httpsPort > 0 && httpRequest.getLocalPort() != httpsPort) {
            String redir = _context.getProperty(PROP_REDIRECT);
            if (Boolean.valueOf(redir) || (redir == null && "1".equals(httpRequest.getHeader("Upgrade-Insecure-Requests")))) {
                sendRedirect(httpsPort, httpRequest, httpResponse);
                baseRequest.setHandled(true);
                return;
            }
        }
    }
    super.handle(pathInContext, baseRequest, httpRequest, httpResponse);
}
Also used : Log(net.i2p.util.Log)

Example 3 with Log

use of net.i2p.util.Log in project i2p.i2p by i2p.

the class PluginStarter method deletePlugin.

/**
 *  @return true on success - caller should call stopPlugin() first
 *  @since public since 0.9.33, was package private
 */
public static boolean deletePlugin(RouterContext ctx, String appName) throws Exception {
    Log log = ctx.logManager().getLog(PluginStarter.class);
    File pluginDir = new File(ctx.getConfigDir(), PLUGIN_DIR + '/' + appName);
    if ((!pluginDir.exists()) || (!pluginDir.isDirectory())) {
        log.error("Cannot delete nonexistent plugin: " + appName);
        return false;
    }
    // uninstall things in clients.config
    File clientConfig = new File(pluginDir, "clients.config");
    if (clientConfig.exists()) {
        Properties props = new Properties();
        DataHelper.loadProps(props, clientConfig);
        List<ClientAppConfig> clients = ClientAppConfig.getClientApps(clientConfig);
        runClientApps(ctx, pluginDir, clients, "uninstall");
    }
    // unregister themes, and switch to default if we are unregistering the current theme
    File dir = new File(pluginDir, "console/themes");
    File[] tfiles = dir.listFiles();
    if (tfiles != null) {
        String current = ctx.getProperty(CSSHelper.PROP_THEME_NAME);
        Map<String, String> changes = new HashMap<String, String>();
        List<String> removes = new ArrayList<String>();
        for (int i = 0; i < tfiles.length; i++) {
            String name = tfiles[i].getName();
            if (tfiles[i].isDirectory() && (!Arrays.asList(STANDARD_THEMES).contains(tfiles[i]))) {
                removes.add(CSSHelper.PROP_THEME_PFX + name);
                if (name.equals(current))
                    changes.put(CSSHelper.PROP_THEME_NAME, CSSHelper.DEFAULT_THEME);
            }
        }
        ctx.router().saveConfig(changes, removes);
    }
    boolean deleted = FileUtil.rmdir(pluginDir, false);
    Properties props = pluginProperties();
    for (Iterator<?> iter = props.keySet().iterator(); iter.hasNext(); ) {
        String name = (String) iter.next();
        if (name.startsWith(PREFIX + appName + '.'))
            iter.remove();
    }
    if (!deleted) {
        // This happens on Windows when there are plugin jars in classpath
        // Mark it as deleted, we will try again after restart
        log.logAlways(Log.WARN, "Deletion of " + pluginDir + " failed, will try again at restart");
        props.setProperty(PREFIX + appName + ENABLED, DELETED);
    }
    storePluginProperties(props);
    return true;
}
Also used : Log(net.i2p.util.Log) HashMap(java.util.HashMap) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) ArrayList(java.util.ArrayList) Properties(java.util.Properties) ClientAppConfig(net.i2p.router.startup.ClientAppConfig) File(java.io.File)

Example 4 with Log

use of net.i2p.util.Log in project i2p.i2p by i2p.

the class PluginStarter method isClientThreadRunning.

/**
 * Returns <code>true</code> if one or more client threads are running in a given plugin.
 * @param pluginName
 * @return true if running
 */
private static boolean isClientThreadRunning(String pluginName, RouterContext ctx) {
    ThreadGroup group = pluginThreadGroups.get(pluginName);
    if (group == null)
        return false;
    boolean rv = group.activeCount() > 0;
    // Ditto HSQLDB Timer (jwebcache)
    if (rv) {
        Log log = ctx.logManager().getLog(PluginStarter.class);
        Thread[] activeThreads = new Thread[128];
        int count = group.enumerate(activeThreads);
        boolean notRollover = false;
        for (int i = 0; i < count; i++) {
            if (activeThreads[i] != null) {
                String name = activeThreads[i].getName();
                if (!"org.eclipse.jetty.util.RolloverFileOutputStream".equals(name) && !name.startsWith("HSQLDB Timer"))
                    notRollover = true;
                if (log.shouldLog(Log.DEBUG))
                    log.debug("Found " + activeThreads[i].getState() + " thread " + name + " for " + pluginName + ": " + name);
            }
        }
        rv = notRollover;
    }
    return rv;
}
Also used : Log(net.i2p.util.Log) I2PAppThread(net.i2p.util.I2PAppThread)

Example 5 with Log

use of net.i2p.util.Log in project i2p.i2p by i2p.

the class PluginStarter method startPlugin.

/**
 *  @return true on success
 *  @throws Exception just about anything, caller would be wise to catch Throwable
 */
@SuppressWarnings("deprecation")
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);
    // For the following, we use the exact same translated strings as in PluginUpdateRunner
    // to avoid duplication
    String minVersion = 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);
        foo = gettext("This plugin requires I2P version {0} or higher", minVersion, ctx);
        throw new Exception(foo);
    }
    minVersion = 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);
        foo = gettext("This plugin requires Java version {0} or higher", minVersion, ctx);
        throw new Exception(foo);
    }
    String jVersion = RouterConsoleRunner.jettyVersion();
    minVersion = 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);
        foo = gettext("Plugin requires Jetty version {0} or higher", minVersion, ctx);
        throw new Exception(foo);
    }
    String blacklistVersion = jetty9Blacklist.get(appName);
    String curVersion = stripHTML(props, "version");
    if (blacklistVersion != null && VersionComparator.comp(curVersion, blacklistVersion) <= 0) {
        String foo = "Plugin " + appName + " requires Jetty version 8.9999 or lower";
        log.error(foo);
        disablePlugin(appName);
        foo = gettext("Plugin requires Jetty version {0} or lower", "8.9999", ctx);
        throw new Exception(foo);
    }
    String maxVersion = 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);
        foo = gettext("Plugin requires Jetty version {0} or lower", maxVersion, ctx);
        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]))) {
                // deprecated
                ctx.router().setConfigSetting(CSSHelper.PROP_THEME_PFX + name, tfiles[i].getAbsolutePath());
            // we don't need to save
            }
        }
    }
    // handle console icons for plugins without web-resources through prop icon-code
    String fullprop = props.getProperty("icon-code");
    if (fullprop != null && fullprop.length() > 1) {
        byte[] decoded = Base64.decode(fullprop);
        if (decoded != null) {
            NavHelper.setBinary(appName, decoded);
            iconfile = "/Plugins/pluginicon?plugin=" + appName;
        } else {
            iconfile = "/themes/console/images/plugin.png";
        }
    }
    // 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");
        File[] files = webappDir.listFiles(RouterConsoleRunner.WAR_FILTER);
        if (files != null) {
            if (!pluginWars.containsKey(appName))
                pluginWars.put(appName, new ConcurrentHashSet<String>());
            for (int i = 0; i < files.length; i++) {
                try {
                    String warName = files[i].getName();
                    warName = warName.substring(0, warName.lastIndexOf(".war"));
                    // 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 = files[i].getCanonicalPath();
                        WebAppStarter.startWebApp(ctx, server, warName, path);
                        pluginWars.get(appName).add(warName);
                    }
                } catch (IOException ioe) {
                    log.error("Error resolving '" + files[i] + "' in '" + webappDir, ioe);
                }
            }
            // Check for iconfile in plugin.properties
            String icfile = 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(new FileSuffixFilter(".jar"));
        if (files != null) {
            boolean added = false;
            for (int i = 0; i < files.length; i++) {
                File f = files[i];
                try {
                    addPath(f.toURI().toURL());
                    log.info("INFO: Adding translation plugin to classpath: " + f);
                    added = true;
                } catch (ClassCastException e) {
                    log.logAlways(Log.WARN, "Java version: " + System.getProperty("java.version") + " does not support adding classpath element: " + f + " for plugin " + appName);
                } catch (RuntimeException e) {
                    log.error("Plugin " + appName + " bad classpath element: " + f, e);
                }
            }
            if (added)
                Translate.clearCache();
        }
    }
    // add summary bar link
    String name = stripHTML(props, "consoleLinkName_" + Messages.getLanguage(ctx));
    if (name == null)
        name = stripHTML(props, "consoleLinkName");
    String url = stripHTML(props, "consoleLinkURL");
    if (name != null && url != null && name.length() > 0 && url.length() > 0) {
        String tip = stripHTML(props, "consoleLinkTooltip_" + Messages.getLanguage(ctx));
        if (tip == null)
            tip = stripHTML(props, "consoleLinkTooltip");
        NavHelper.registerApp(name, url, tip, iconfile);
    }
    return true;
}
Also used : Log(net.i2p.util.Log) ContextHandlerCollection(org.eclipse.jetty.server.handler.ContextHandlerCollection) IOException(java.io.IOException) Properties(java.util.Properties) IOException(java.io.IOException) ConcurrentHashSet(net.i2p.util.ConcurrentHashSet) ClientAppConfig(net.i2p.router.startup.ClientAppConfig) FileSuffixFilter(net.i2p.util.FileSuffixFilter) File(java.io.File)

Aggregations

Log (net.i2p.util.Log)94 IOException (java.io.IOException)30 File (java.io.File)13 Properties (java.util.Properties)11 DataFormatException (net.i2p.data.DataFormatException)11 FileInputStream (java.io.FileInputStream)7 GeneralSecurityException (java.security.GeneralSecurityException)7 ArrayList (java.util.ArrayList)7 Hash (net.i2p.data.Hash)6 HashMap (java.util.HashMap)5 InputStream (java.io.InputStream)4 EventLog (net.i2p.router.util.EventLog)4 ByteArrayOutputStream (java.io.ByteArrayOutputStream)3 Map (java.util.Map)3 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)3 I2PAppContext (net.i2p.I2PAppContext)3 I2PSession (net.i2p.client.I2PSession)3 I2PSessionException (net.i2p.client.I2PSessionException)3 SigType (net.i2p.crypto.SigType)3 RouterInfo (net.i2p.data.router.RouterInfo)3