Package freenet.clients.http

Source Code of freenet.clients.http.FirstTimeWizardToadlet

/* This code is part of Freenet. It is distributed under the GNU General
* Public License, version 2 (or at your option any later version). See
* http://www.gnu.org/ for further details of the GPL. */
package freenet.clients.http;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.EnumMap;

import freenet.client.HighLevelSimpleClient;
import freenet.clients.http.wizardsteps.BANDWIDTH;
import freenet.clients.http.wizardsteps.BANDWIDTH_MONTHLY;
import freenet.clients.http.wizardsteps.BANDWIDTH_RATE;
import freenet.clients.http.wizardsteps.BROWSER_WARNING;
import freenet.clients.http.wizardsteps.DATASTORE_SIZE;
import freenet.clients.http.wizardsteps.MISC;
import freenet.clients.http.wizardsteps.NAME_SELECTION;
import freenet.clients.http.wizardsteps.OPENNET;
import freenet.clients.http.wizardsteps.PageHelper;
import freenet.clients.http.wizardsteps.PersistFields;
import freenet.clients.http.wizardsteps.SECURITY_NETWORK;
import freenet.clients.http.wizardsteps.SECURITY_PHYSICAL;
import freenet.clients.http.wizardsteps.Step;
import freenet.clients.http.wizardsteps.WELCOME;
import freenet.config.Config;
import freenet.l10n.NodeL10n;
import freenet.node.Node;
import freenet.node.NodeClientCore;
import freenet.node.SecurityLevels;
import freenet.support.LogThresholdCallback;
import freenet.support.Logger;
import freenet.support.Logger.LogLevel;
import freenet.support.api.HTTPRequest;

/**
* A first time wizard aimed to ease the configuration of the node.
*/
public class FirstTimeWizardToadlet extends Toadlet {
  private final NodeClientCore core;
  private final EnumMap<WIZARD_STEP, Step> steps;
  private final MISC stepMISC;
  private final SECURITY_NETWORK stepSECURITY_NETWORK;
  private final SECURITY_PHYSICAL stepSECURITY_PHYSICAL;

        private static volatile boolean logMINOR;
  static {
    Logger.registerLogThresholdCallback(new LogThresholdCallback(){
      @Override
      public void shouldUpdate(){
        logMINOR = Logger.shouldLog(LogLevel.MINOR, this);
      }
    });
  }

  public enum WIZARD_STEP {
    WELCOME,
    BROWSER_WARNING,
    MISC,
    OPENNET,
    SECURITY_NETWORK,
    SECURITY_PHYSICAL,
    NAME_SELECTION,
    DATASTORE_SIZE,
    BANDWIDTH,
    BANDWIDTH_MONTHLY,
    BANDWIDTH_RATE,
    COMPLETE //Redirects to front page
  }

  public enum WIZARD_PRESET {
    LOW,
    HIGH
  }

  FirstTimeWizardToadlet(HighLevelSimpleClient client, Node node, NodeClientCore core) {
    //Generic Toadlet-related initialization.
    super(client);
    this.core = core;
    Config config = node.config;

    //Add step handlers that aren't set by presets
    steps = new EnumMap<WIZARD_STEP, Step>(WIZARD_STEP.class);
    steps.put(WIZARD_STEP.WELCOME, new WELCOME(config));
    steps.put(WIZARD_STEP.BROWSER_WARNING, new BROWSER_WARNING());
    steps.put(WIZARD_STEP.NAME_SELECTION, new NAME_SELECTION(config));
    steps.put(WIZARD_STEP.DATASTORE_SIZE, new DATASTORE_SIZE(core, config));
    steps.put(WIZARD_STEP.OPENNET, new OPENNET());
    steps.put(WIZARD_STEP.BANDWIDTH, new BANDWIDTH());
    steps.put(WIZARD_STEP.BANDWIDTH_MONTHLY, new BANDWIDTH_MONTHLY(core, config));
    steps.put(WIZARD_STEP.BANDWIDTH_RATE, new BANDWIDTH_RATE(core, config));

    //Add step handlers that are set by presets
    stepMISC = new MISC(core, config);
    steps.put(WIZARD_STEP.MISC, stepMISC);

    stepSECURITY_NETWORK = new SECURITY_NETWORK(core);
    steps.put(WIZARD_STEP.SECURITY_NETWORK, stepSECURITY_NETWORK);

    stepSECURITY_PHYSICAL = new SECURITY_PHYSICAL(core);
    steps.put(WIZARD_STEP.SECURITY_PHYSICAL, stepSECURITY_PHYSICAL);
  }

  public static final String TOADLET_URL = "/wizard/";

  public void handleMethodGET(URI uri, HTTPRequest request, ToadletContext ctx) throws ToadletContextClosedException, IOException {
        if(!ctx.checkFullAccess(this))
            return;

    //Read the current step from the URL parameter, defaulting to the welcome page if unset or invalid..
    WIZARD_STEP currentStep;
    try {
      currentStep = WIZARD_STEP.valueOf(request.getParam("step", WIZARD_STEP.WELCOME.toString()));
    } catch (IllegalArgumentException e) {
      currentStep = WIZARD_STEP.WELCOME;
    }

    PersistFields persistFields = new PersistFields(request);

    //Skip the browser warning page if using Chrome in incognito mode
    if (currentStep == WIZARD_STEP.BROWSER_WARNING &&
        request.isChrome() && request.isIncognito()) {
      super.writeTemporaryRedirect(ctx, "Skipping unneeded warning",
              persistFields.appendTo(TOADLET_URL+"?step=MISC"));
      return;
    } else if (currentStep == WIZARD_STEP.MISC && persistFields.isUsingPreset()) {
      /*If using a preset, skip the miscellaneous page as both high and low security set those settings.
       * This overrides the persistence fields.*/
      StringBuilder redirectBase = new StringBuilder(TOADLET_URL+"?step=");
      if (persistFields.preset == WIZARD_PRESET.HIGH) {
        redirectBase.append("SECURITY_NETWORK&preset=HIGH&confirm=true&opennet=false&security-levels.networkThreatLevel=HIGH");
      } else /*if (persistFields.preset == WIZARD_PRESET.LOW)*/ {
        redirectBase.append("DATASTORE_SIZE&preset=LOW&opennet=true");
      }
      //addPersistFields() is not used here because the fields are overridden.
      super.writeTemporaryRedirect(ctx, "Skipping to next necessary step", redirectBase.toString());
      return;
    } else if (currentStep == WIZARD_STEP.SECURITY_NETWORK && !request.isParameterSet("opennet")) {
      //If opennet isn't defined when attempting to set network security level, ask again.
      super.writeTemporaryRedirect(ctx, "Need opennet choice",
              persistFields.appendTo(TOADLET_URL+"?step=OPENNET"));
      return;
    } else if (currentStep == WIZARD_STEP.NAME_SELECTION && core.node.isOpennetEnabled()) {
      //Skip node name selection if not in darknet mode.
      super.writeTemporaryRedirect(ctx, "Skip name selection",
              persistFields.appendTo(stepURL(WIZARD_STEP.DATASTORE_SIZE.name())));
      return;
    } else if (currentStep == WIZARD_STEP.COMPLETE) {
      super.writeTemporaryRedirect(ctx, "Wizard complete", WelcomeToadlet.PATH);
      return;
    }

    Step getStep = steps.get(currentStep);
    PageHelper helper = new PageHelper(ctx, persistFields, currentStep);
    getStep.getStep(request, helper);
    writeHTMLReply(ctx, 200, "OK", helper.getPageOuter().generate());
  }

  /**
   * @return whether wizard steps should log minor events.
   */
  public static boolean shouldLogMinor() {
    return logMINOR;
  }

  public void handleMethodPOST(URI uri, HTTPRequest request, ToadletContext ctx) throws ToadletContextClosedException, IOException {
        if(!ctx.checkFullAccess(this))
            return;

    WIZARD_STEP currentStep;
    try {
      //Attempt to parse the current step, defaulting to WELCOME if unspecified or invalid.
      String currentValue = request.getPartAsStringFailsafe("step", 20);
      currentStep = currentValue.isEmpty() ? WIZARD_STEP.WELCOME : WIZARD_STEP.valueOf(currentValue);
    } catch (IllegalArgumentException e) {
      //Failed to parse enum value, default to welcome.
      //TODO: Should this be an error page instead?
      currentStep = WIZARD_STEP.WELCOME;
    }

    PersistFields persistFields = new PersistFields(request);
    String redirectTarget;

    if (currentStep.equals(WIZARD_STEP.WELCOME) &&
            (request.isPartSet("presetLow") || request.isPartSet("presetHigh") || request.isPartSet("presetNone"))) {

      /*Apply presets and UPnP is enabled first to allow it time to load (and thus enable
        autodetection) before hitting the bandwidth page. This also effectively sets the preset field.*/
      StringBuilder redirectTo = new StringBuilder(TOADLET_URL+"?step=BROWSER_WARNING&incognito=");
      redirectTo.append(request.getPartAsStringFailsafe("incognito", 5));

      //Translate button name to preset value on the query string.
      if (request.isPartSet("presetLow")) {
        //Low security preset
        stepMISC.setUPnP(true);
        stepMISC.setAutoUpdate(true);
        redirectTo.append("&preset=LOW&opennet=true");
        stepSECURITY_NETWORK.setThreatLevel(SecurityLevels.NETWORK_THREAT_LEVEL.LOW);
        stepSECURITY_PHYSICAL.setThreatLevel(SecurityLevels.PHYSICAL_THREAT_LEVEL.NORMAL,
                stepSECURITY_PHYSICAL.getCurrentLevel());
      } else if (request.isPartSet("presetHigh")) {
        //High security preset
        stepMISC.setUPnP(true);
        stepMISC.setAutoUpdate(true);
        redirectTo.append("&preset=HIGH&opennet=false");
      }

      super.writeTemporaryRedirect(ctx, "Wizard set preset", redirectTo.toString());
      return;
    } else if (request.isPartSet("back")) {
      //User chose back, return to previous page.
      redirectTarget = getPreviousStep(currentStep, persistFields.preset).name();
    } else {
      try {
        redirectTarget = steps.get(currentStep).postStep(request);

        //Opennet step can change the persisted value for opennet.
        if (currentStep == WIZARD_STEP.OPENNET) {
          try {
            HTTPRequest newRequest = new HTTPRequestImpl(new URI(
                    stepURL(redirectTarget)), "GET");
            //Only continue if a value for opennet has been selected.
            if (newRequest.isPartSet("opennet")) {
              redirectTarget = WIZARD_STEP.SECURITY_NETWORK.name();
              persistFields = new PersistFields(persistFields.preset, newRequest);
            }
          } catch (URISyntaxException e) {
            Logger.error(this, "Unexpected invalid query string from OPENNET step! "+e, e);
            redirectTarget = WIZARD_STEP.WELCOME.name();
          }
        }
      } catch (IOException e) {
        String title;
        if (e.getMessage().equals("cantWriteNewMasterKeysFile")) {
          //Recognized as being unable to write to the master keys file.
          title = NodeL10n.getBase().getString("SecurityLevels.cantWriteNewMasterKeysFileTitle");
        } else {
          //Some other error.
          title = NodeL10n.getBase().getString("Toadlet.internalErrorPleaseReport");
        }

        //Very loud error message, with descriptive title and header if possible.
        StringBuilder msg = new StringBuilder("<html><head><title>").append(title).
                append("</title></head><body><h1>").append(title).append("</h1><pre>");

        //Print stack trace.
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        e.printStackTrace(pw);
        pw.flush();
        msg.append(sw.toString()).append("</pre>");

        //Include internal exception if one exists.
        Throwable internal = e.getCause();
        if (internal != null) {
          msg.append("<h1>").
                  append(NodeL10n.getBase().getString("Toadlet.internalErrorPleaseReport")).
                  append("</h1>").append("<pre>");

          sw = new StringWriter();
          pw = new PrintWriter(sw);
          internal.printStackTrace(pw);
          pw.flush();
          msg.append(sw.toString()).append("</pre>");
        }
        msg.append("</body></html>");
        writeHTMLReply(ctx, 500, "Internal Error", msg.toString());
        return;
      }
    }
    super.writeTemporaryRedirect(ctx, "Wizard redirect", stepURL(persistFields.appendTo(redirectTarget)));
  }

  private String stepURL(String step) {
    return TOADLET_URL+"?step="+step;
  }

  //FIXME: There really has to be a better way to find the previous step, but with an enum there's no decrement.
  //FIXME: Would a set work better than an enum?
  public static WIZARD_STEP getPreviousStep(WIZARD_STEP currentStep, WIZARD_PRESET preset) {

    //Might be obvious, but still: No breaks needed in cases because their only contents are returns.

    //First pages for the presets
    if (preset == WIZARD_PRESET.HIGH) {
      switch (currentStep) {
        case SECURITY_NETWORK:
        case SECURITY_PHYSICAL:
          //Go back to the beginning from the warning or the physical security page.
          return WIZARD_STEP.WELCOME;
        default:
          //do nothing
      }
    } else  if (preset == WIZARD_PRESET.LOW) {
      switch (currentStep) {
        case DATASTORE_SIZE:
          //Go back to the beginning from the datastore page.
          return WIZARD_STEP.WELCOME;
        default:
          //do nothing
      }
    }

    //Otherwise normal order.
    switch (currentStep) {
      case MISC:
      case BROWSER_WARNING:
        return WIZARD_STEP.WELCOME;
      case OPENNET:
        return WIZARD_STEP.MISC;
      case SECURITY_NETWORK:
        return WIZARD_STEP.OPENNET;
      case SECURITY_PHYSICAL:
        return WIZARD_STEP.SECURITY_NETWORK;
      case NAME_SELECTION:
        return WIZARD_STEP.SECURITY_PHYSICAL;
      case DATASTORE_SIZE:
        return WIZARD_STEP.NAME_SELECTION;
      case BANDWIDTH:
        return WIZARD_STEP.DATASTORE_SIZE;
      case BANDWIDTH_MONTHLY:
      case BANDWIDTH_RATE:
        return WIZARD_STEP.BANDWIDTH;
      default:
        //do nothing
    }

    //Should be matched by this point, unknown step.
    return WIZARD_STEP.WELCOME;
  }

  @Override
  public String path() {
    return TOADLET_URL;
  }
}
TOP

Related Classes of freenet.clients.http.FirstTimeWizardToadlet

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.