Package freenet.clients.http.wizardsteps

Source Code of freenet.clients.http.wizardsteps.SECURITY_PHYSICAL

package freenet.clients.http.wizardsteps;

import java.io.IOException;

import freenet.clients.http.ExternalLinkToadlet;
import freenet.clients.http.FirstTimeWizardToadlet;
import freenet.clients.http.SecurityLevelsToadlet;
import freenet.l10n.NodeL10n;
import freenet.node.MasterKeysFileSizeException;
import freenet.node.MasterKeysWrongPasswordException;
import freenet.node.Node;
import freenet.node.NodeClientCore;
import freenet.node.SecurityLevels;
import freenet.support.HTMLNode;
import freenet.support.Logger;
import freenet.support.api.HTTPRequest;
import freenet.support.io.FileUtil;
import freenet.support.io.FileUtil.OperatingSystem;

/**
* Allows the user to set the physical security level.
*/
public class SECURITY_PHYSICAL implements Step {

  private final NodeClientCore core;

  private enum PASSWORD_PROMPT {
    SET_BLANK, //Requested new password was blank
    DECRYPT_WRONG, //Decryption password was wrong
    DECRYPT_BLANK  //Decryption password was blank
  }

  /**
   * Constructs a new SECURITY_PHYSICAL GET handler.
   * @param core used to check or set the current security level and password.
   */
  public SECURITY_PHYSICAL(NodeClientCore core) {
    this.core = core;
  }

  @Override
  public void getStep(HTTPRequest request, PageHelper helper) {

    if (request.isParameterSet("error")) {
      if (errorHandler(request, helper)) {
        //Error page generated successfully.
        return;
      }
      //Problem generating error page; generate default.
    }

    HTMLNode contentNode = helper.getPageContent(WizardL10n.l10n("physicalSecurityPageTitle"));
    HTMLNode infoboxContent = helper.getInfobox("infobox-normal",
            WizardL10n.l10nSec("physicalThreatLevelShort"), contentNode, null, false);
    infoboxContent.addChild("p", WizardL10n.l10nSec("physicalThreatLevel"));

    HTMLNode form = helper.addFormChild(infoboxContent, ".", "physicalSecurityForm");
    HTMLNode div = form.addChild("div", "class", "opennetDiv");
    String controlName = "security-levels.physicalThreatLevel";
    HTMLNode swapWarning = div.addChild("p").addChild("i");
    NodeL10n.getBase().addL10nSubstitution(swapWarning, "SecurityLevels.physicalThreatLevelTruecrypt",
            new String[]{"bold", "truecrypt"},
            new HTMLNode[]{HTMLNode.STRONG,
                    HTMLNode.linkInNewWindow(ExternalLinkToadlet.escape("http://www.truecrypt.org/"))});
    OperatingSystem os = FileUtil.detectedOS;
    div.addChild("p", NodeL10n.getBase().getString("SecurityLevels.physicalThreatLevelSwapfile",
            "operatingSystem",
            NodeL10n.getBase().getString("OperatingSystemName."+os.name())));
    if(os == FileUtil.OperatingSystem.Windows) {
      swapWarning.addChild("#", " " + WizardL10n.l10nSec("physicalThreatLevelSwapfileWindows"));
    }
    for(SecurityLevels.PHYSICAL_THREAT_LEVEL level : SecurityLevels.PHYSICAL_THREAT_LEVEL.values()) {
      HTMLNode input;
      input = div.addChild("p").addChild("input",
              new String[] { "type", "name", "value" },
              new String[] { "radio", controlName, level.name() });
      input.addChild("b", WizardL10n.l10nSec("physicalThreatLevel.name." + level));
      input.addChild("#", ": ");
      NodeL10n.getBase().addL10nSubstitution(input, "SecurityLevels.physicalThreatLevel.choice."+level, new String[] { "bold" }, new HTMLNode[] { HTMLNode.STRONG });
      if(level == SecurityLevels.PHYSICAL_THREAT_LEVEL.HIGH &&
              core.node.securityLevels.getPhysicalThreatLevel() != level) {
        // Add password form on high security if not already at high security.
        HTMLNode p = div.addChild("p");
        p.addChild("label", "for", "passwordBox", WizardL10n.l10nSec("setPasswordLabel")+":");
        p.addChild("input", new String[] { "id", "type", "name" }, new String[] { "passwordBox", "password", "masterPassword" });
      }
    }
    div.addChild("#", WizardL10n.l10nSec("physicalThreatLevelEnd"));
    form.addChild("input",
            new String[] { "type", "name", "value" },
            new String[] { "submit", "back", NodeL10n.getBase().getString("Toadlet.back")});
    form.addChild("input",
            new String[] { "type", "name", "value" },
            new String[] { "submit", "next", NodeL10n.getBase().getString("Toadlet.next")});
  }

  /**
   * Internal error handler wrapper with the hope of making the code more readable.
   * @param request defines which error and information about it
   * @param helper creates page, infoboxes, forms.
   * @return whether an error page was successfully generated.
   */
  private boolean errorHandler(HTTPRequest request, PageHelper helper) {
    String physicalThreatLevel = request.getParam("newThreatLevel");
    SecurityLevels.PHYSICAL_THREAT_LEVEL newThreatLevel = SecurityLevels.parsePhysicalThreatLevel(physicalThreatLevel);
    String error = request.getParam("error");

    if (error.equals("pass")) {
      //Password prompt requested
      PASSWORD_PROMPT type;
      try {
        type = PASSWORD_PROMPT.valueOf(request.getParam("type"));
      catch (IllegalArgumentException e) {
        //Render the default page if unable to parse password prompt type.
        return false;
      }

      final String pageTitleKey;
      final String infoboxTitleKey;
      final boolean forDowngrade;
      final boolean forUpgrade;
      final boolean wasWrong = type == PASSWORD_PROMPT.DECRYPT_WRONG;

      switch (type) {
        case SET_BLANK:
          pageTitleKey = "passwordPageTitle";
          infoboxTitleKey = "enterPasswordTitle";
          forDowngrade = false;
          forUpgrade = true;
          break;
        case DECRYPT_WRONG:
          pageTitleKey ="passwordForDecryptTitle";
          infoboxTitleKey = "passwordWrongTitle";
          forDowngrade = false;
          forUpgrade = false;
          break;
        case DECRYPT_BLANK:
          pageTitleKey = "passwordForDecryptTitle";
          infoboxTitleKey = "passwordForDecryptTitle";
          forDowngrade = true;
          forUpgrade = false;
          break;
        default:
          //Unanticipated value for type!
          return false;
      }

      HTMLNode contentNode = helper.getPageContent(WizardL10n.l10nSec(pageTitleKey));

      HTMLNode content = helper.getInfobox("infobox-error", WizardL10n.l10nSec(infoboxTitleKey),
              contentNode, null, true);

      if (type == PASSWORD_PROMPT.SET_BLANK || type == PASSWORD_PROMPT.DECRYPT_BLANK) {
        content.addChild("p", WizardL10n.l10nSec("passwordNotZeroLength"));
      }

      HTMLNode form = helper.addFormChild(content, ".", "masterPasswordForm");

      SecurityLevelsToadlet.generatePasswordFormPage(wasWrong, form, content, forDowngrade, forUpgrade,
              newThreatLevel.name(), null);

      addBackToPhysicalSeclevelsButton(form);
      return true;
    } else if (error.equals("corrupt")) {
      //Password file corrupt
      SecurityLevelsToadlet.sendPasswordFileCorruptedPageInner(helper, core.node.getMasterPasswordFile().getPath());
      return true;
    } else if (error.equals("delete")) {
      SecurityLevelsToadlet.sendCantDeleteMasterKeysFileInner(helper, core.node.getMasterPasswordFile().getPath(), newThreatLevel.name());
      return true;
    }

    //Error type was not recognized.
    return false;
  }

  public SecurityLevels.PHYSICAL_THREAT_LEVEL getCurrentLevel() {
    return core.node.securityLevels.getPhysicalThreatLevel();
  }

  @Override
  public String postStep(HTTPRequest request) throws IOException {
    final String errorCorrupt = FirstTimeWizardToadlet.WIZARD_STEP.SECURITY_PHYSICAL+"&error=corrupt";
    String pass = request.getPartAsStringFailsafe("masterPassword", SecurityLevelsToadlet.MAX_PASSWORD_LENGTH);
    final boolean passwordIsBlank = pass != null && pass.length() == 0;

    String physicalThreatLevel = request.getPartAsStringFailsafe("security-levels.physicalThreatLevel", 128);
    SecurityLevels.PHYSICAL_THREAT_LEVEL oldThreatLevel = core.node.securityLevels.getPhysicalThreatLevel();
    SecurityLevels.PHYSICAL_THREAT_LEVEL newThreatLevel = SecurityLevels.parsePhysicalThreatLevel(physicalThreatLevel);
    if (FirstTimeWizardToadlet.shouldLogMinor()) {
      Logger.minor(this, "Old threat level: " + oldThreatLevel + " new threat level: " + newThreatLevel);
    }

    /*If the user didn't select a network security level before clicking continue, the selected
    * security level could not be determined, clicked back from a password error page, redirect to the main page.*/
    if (newThreatLevel == null || !request.isPartSet("security-levels.physicalThreatLevel") ||
            request.isPartSet("backToMain")) {
      return FirstTimeWizardToadlet.WIZARD_STEP.SECURITY_PHYSICAL.name();
    }
    //Changing to high physical threat level: set password.
    if (newThreatLevel == SecurityLevels.PHYSICAL_THREAT_LEVEL.HIGH && oldThreatLevel != newThreatLevel) {
      if (passwordIsBlank) {
        // Must set the password to something non-blank.
        return promptPassword(newThreatLevel, PASSWORD_PROMPT.SET_BLANK);
      } else {
        try {
          if(oldThreatLevel == SecurityLevels.PHYSICAL_THREAT_LEVEL.NORMAL ||
                  oldThreatLevel == SecurityLevels.PHYSICAL_THREAT_LEVEL.LOW) {
            core.node.changeMasterPassword("", pass, true);
          } else {
            core.node.setMasterPassword(pass, true);
          }
        } catch (Node.AlreadySetPasswordException e) {
          // Do nothing, already set a password.
        } catch (MasterKeysWrongPasswordException e) {
          throw new IOException("Incorrect password when changing from another level to high", e);
        } catch (MasterKeysFileSizeException e) {
          return errorCorrupt;
        }
      }
    }
    //Decreasing to low or normal from high: remove password.
    if ((newThreatLevel == SecurityLevels.PHYSICAL_THREAT_LEVEL.LOW || newThreatLevel == SecurityLevels.PHYSICAL_THREAT_LEVEL.NORMAL) &&
              oldThreatLevel == SecurityLevels.PHYSICAL_THREAT_LEVEL.HIGH) {
      if (passwordIsBlank) {
        //Prompt for the old password, which is needed to decrypt
        return promptPassword(newThreatLevel, PASSWORD_PROMPT.DECRYPT_BLANK);
      } else if (core.node.getMasterPasswordFile().exists()) {
        //Old password for decryption specified.
        try {
          core.node.changeMasterPassword(pass, "", true);
        } catch (IOException e) {
          if(!core.node.getMasterPasswordFile().exists()) {
            // Ok.
            System.out.println("Master password file no longer exists, assuming this is deliberate");
          } else {
            System.err.println("Cannot change password as cannot write new passwords file: "+e);
            e.printStackTrace();
            throw new IOException("cantWriteNewMasterKeysFile", e);
          }
        } catch (MasterKeysWrongPasswordException e) {
          return promptPassword(newThreatLevel, PASSWORD_PROMPT.DECRYPT_WRONG);
        } catch (MasterKeysFileSizeException e) {
          return errorCorrupt;
        } catch (Node.AlreadySetPasswordException e) {
          System.err.println("Already set a password when changing it - maybe master.keys copied in at the wrong moment???");
        }
      }

    }
    //Maximum threat level: remove master keys file.
    if (newThreatLevel == SecurityLevels.PHYSICAL_THREAT_LEVEL.MAXIMUM) {
      try {
        core.node.killMasterKeysFile();
      } catch (IOException e) {
        return FirstTimeWizardToadlet.WIZARD_STEP.SECURITY_PHYSICAL+
                "&error=delete&newThreatLevel="+newThreatLevel.name();
      }
    }
    setThreatLevel(newThreatLevel, oldThreatLevel);
    return FirstTimeWizardToadlet.WIZARD_STEP.NAME_SELECTION.name();
  }

  /**
   * Internal utility function for displaying a password prompt.
   * @param newThreatLevel the user-selected threat level, to be used in creating the form.
   * @param type what type of prompt needed
   * @return URL to display the requested page
   */
  private String promptPassword(SecurityLevels.PHYSICAL_THREAT_LEVEL newThreatLevel, PASSWORD_PROMPT type) {
    if (type == PASSWORD_PROMPT.DECRYPT_WRONG) {
      System.err.println("Wrong password!");
    }
    StringBuilder destination = new StringBuilder(FirstTimeWizardToadlet.WIZARD_STEP.SECURITY_PHYSICAL+
            "&error=pass&newThreatLevel=").append(newThreatLevel.name()).append("&type=").append(type.name());
    return destination.toString();
  }

  public void setThreatLevel(SecurityLevels.PHYSICAL_THREAT_LEVEL newThreatLevel, SecurityLevels.PHYSICAL_THREAT_LEVEL oldThreatLevel) throws IOException {
    core.node.securityLevels.setThreatLevel(newThreatLevel);
    core.storeConfig();
    try {
      core.node.lateSetupDatabase(null);
    } catch (MasterKeysWrongPasswordException e) {
      // Ignore, impossible???
      System.err.println("Failed starting up database while switching physical security level to "+newThreatLevel+" from "+oldThreatLevel+" : wrong password - this is impossible, it should have been handled by the other cases, suggest you remove master.keys");
    } catch (MasterKeysFileSizeException e) {
      System.err.println("Failed starting up database while switching physical security level to "+newThreatLevel+" from "+oldThreatLevel+" : "+core.node.getMasterPasswordFile()+" is too " + e.sizeToString());
    }
  }

  private void addBackToPhysicalSeclevelsButton(HTMLNode form) {
    form.addChild("p").addChild("input",
            new String[] { "type", "name", "value" },
            new String[] { "submit", "backToMain", WizardL10n.l10n("backToSecurityLevels")});
  }
}
TOP

Related Classes of freenet.clients.http.wizardsteps.SECURITY_PHYSICAL

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.