All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.home1.tools.maven.SettingsDecoder Maven / Gradle / Ivy

package cn.home1.tools.maven;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.maven.settings.Settings;
import org.apache.maven.settings.io.xpp3.SettingsXpp3Reader;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import org.sonatype.plexus.components.cipher.DefaultPlexusCipher;
import org.sonatype.plexus.components.cipher.PlexusCipherException;
import org.w3c.dom.Document;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

public class SettingsDecoder {

  private static final String SETTINGS_SECURITY_FILE_SHORT_OPT = "ss";
  private static final String SETTINGS_SECURITY_FILE_LONG_OPT = "settings-security";
  private static final String SETTINGS_FILE_LONG_OPT = "settings";
  private static final String SETTINGS_FILE_SHORT_OPT = "s";
  private static final String XPATH_SHORT_OPT = "x";
  private static final String XPATH_LONG_OPT = "xml-path";
  private static final String DEBUG_SHORT_OPT = "X";
  private static final String DEBUG_LONG_OPT = "debug";

  private static final int MISSING_OR_INVALID_ARGUMENTS_EXIT_CODE = 1;

  private final boolean debug;
  private final String plainTextMasterPassword;
  private final Settings settings;
  private final File settingsFile;

  public SettingsDecoder(
      final String settingsFileOpt, //
      final String securityFileOpt, //
      final boolean debug //
  ) throws Exception {
    this.debug = debug;

    final String envMavenSettings = System.getenv("MAVEN_SETTINGS");
    final String userHome = System.getProperty("user.home");

    final String settingsFilePath;
    if (settingsFileOpt == null) {
      if (envMavenSettings != null && envMavenSettings.contains("-s ")) {
        final Matcher matcher = Pattern.compile("-s[ ]+([^\\s]+)").matcher(envMavenSettings);
        matcher.find();
        settingsFilePath = matcher.group(1).replace("${HOME}", userHome);
      } else {
        settingsFilePath = userHome + "/.m2/settings.xml";
      }
    } else {
      settingsFilePath = settingsFileOpt;
    }

    this.settingsFile = new File(settingsFilePath);
    if (!this.settingsFile.exists()) {
      throw new IllegalArgumentException( //
          String.format("Settings file : %s does not exist%n", this.settingsFile.getAbsolutePath()));
    }

    final String securityFilePath;
    if (securityFileOpt == null) {
      if (envMavenSettings != null && envMavenSettings.contains("-ss ")) {
        final Matcher matcher = Pattern.compile("-ss[ ]+([^\\s]+)").matcher(envMavenSettings);
        matcher.find();
        securityFilePath = matcher.group(1).replace("${HOME}", userHome);
      } else {
        securityFilePath = userHome + "/.m2/settings-security.xml";
      }
    } else {
      securityFilePath = securityFileOpt;
    }
    this.settings = readSettings(this.settingsFile);

    final File securityFile = new File(securityFilePath);
    if (!securityFile.exists()) {
      //throw new IllegalArgumentException( //
      //    String.format("Security file : %s does not exist%n", securityFile.getAbsolutePath()));
      this.plainTextMasterPassword = null;
    } else {
      final String encodedMasterPassword = encodedMasterPassword(securityFile);
      this.plainTextMasterPassword = decodeMasterPassword(encodedMasterPassword, this.debug);
    }
    if (this.debug) {
      System.err.printf("masterPassword:%s%n", this.plainTextMasterPassword);
    }
  }

  public SettingsDecoder() throws Exception {
    this(null, null, false);
  }

  public String getText(final String xpathExpression) throws Exception {
    //final List servers = this.settings.getServers();

    final String nodeText = xmlNodeText(this.settingsFile, xpathExpression);
    if (this.debug) {
      System.err.printf("nodeText:%s%n", nodeText);
    }

    final String plainText = decodeText(nodeText, this.plainTextMasterPassword, this.debug);

    return plainText;
  }

  public static void main(final String... args) throws Exception {
    final Options options = createOptions();

    final CommandLine commandLine = new DefaultParser().parse(options, args);
    final String settingsFileOpt = commandLine.getOptionValue(SETTINGS_FILE_SHORT_OPT);
    final String securityFileOpt = commandLine.getOptionValue(SETTINGS_SECURITY_FILE_SHORT_OPT);
    final String xpathOpt = commandLine.getOptionValue(XPATH_SHORT_OPT);
    final boolean debug = commandLine.getOptionValue(DEBUG_SHORT_OPT) != null;

    if (debug) {
      System.err.printf("xpathOpt:%s%n", xpathOpt);
    }

    try {
      final String plainText = new SettingsDecoder(settingsFileOpt, securityFileOpt, debug).getText(xpathOpt);
      System.out.printf("%s", plainText);
    } catch (final IllegalArgumentException ignored) {
      printHelp(options);
      System.exit(MISSING_OR_INVALID_ARGUMENTS_EXIT_CODE);
    }
  }

  private static Options createOptions() {
    Options options = new Options();
    options.addOption( //
        SETTINGS_SECURITY_FILE_SHORT_OPT, SETTINGS_SECURITY_FILE_LONG_OPT, true, "location of settings-security.xml.");
    options.addOption(SETTINGS_FILE_SHORT_OPT, SETTINGS_FILE_LONG_OPT, true, "location of settings.xml file.");
    options.addOption(XPATH_SHORT_OPT, XPATH_LONG_OPT, true, "xml-path in settings.xml, only node text is supported.");
    options.addOption(DEBUG_SHORT_OPT, DEBUG_LONG_OPT, true, "produce execution debug output.");
    return options;
  }

  private static void printHelp(final Options options) {
    new HelpFormatter().printHelp("maven-settings-decoder", options);
  }

  static Settings readSettings(final File file) throws IOException, XmlPullParserException {
    return new SettingsXpp3Reader().read(new FileInputStream(file));
  }

  private static String decodeText( //
      final String encodedText, //
      final String key, //
      final boolean debug //
  ) throws PlexusCipherException {
    final String result;

    final Boolean envVar = encodedText != null && encodedText.startsWith("${env.") && encodedText.endsWith("}");
    if (debug) {
      System.err.printf("envVar: %s%n", envVar);
    }

    if (envVar) {
      final String envVarName = encodedText.substring(6, encodedText.length() - 1);
      if (debug) {
        System.err.printf("envVarName: %s%n", envVarName);
        final Map env = System.getenv();
        for (Map.Entry entry : env.entrySet()) {
          System.err.printf("env name: %s, value: *secret* %n", entry.getKey());
        }
      }
      result = System.getenv(envVarName);
    } else {
      if (key != null) {
        if (debug) {
          System.err.printf("key not null%n");
        }

        final Boolean encoded = encodedText != null && encodedText.startsWith("{") && encodedText.endsWith("}");
        if (debug) {
          System.err.printf("encoded: %s%n", encoded);
        }

        if (encoded) {
          result = new DefaultPlexusCipher().decryptDecorated(encodedText, key);
        } else {
          result = encodedText;
        }
      } else {
        if (debug) {
          System.err.printf("key is null%n");
        }

        result = encodedText;
      }
    }

    return result;
  }

  static String decodeMasterPassword( //
      final String encodedMasterPassword, //
      final boolean debug //
  ) throws PlexusCipherException {
    // key = org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION;
    final String key = "settings.security";
    return decodeText(encodedMasterPassword, key, debug);
  }

  private static String xmlNodeText(final File file, final String xpathExpression) throws Exception {
    // see: http://www.ibm.com/developerworks/cn/xml/x-javaxpathapi.html
    final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    factory.setNamespaceAware(false); // Note: never forget this !
    final DocumentBuilder builder = factory.newDocumentBuilder();
    final Document doc = builder.parse(file);

    final Object result = XPathFactory.newInstance().newXPath() //
        .compile(xpathExpression) //
        .evaluate(doc, XPathConstants.STRING);
    return result != null ? result.toString() : null;
  }

  static String encodedMasterPassword(final File file) throws Exception {
    return xmlNodeText(file, "/settingsSecurity/master/text()");
  }

  //  private static String encodedMasterPassword( //
  //      final File file //
  //  ) throws org.sonatype.plexus.components.sec.dispatcher.SecDispatcherException { //
  //    final org.sonatype.plexus.components.sec.dispatcher.model.SettingsSecurity settingsSecurity = //
  //        org.sonatype.plexus.components.sec.dispatcher.SecUtil.read(file.getAbsolutePath(), true);
  //    return settingsSecurity.getMaster();
  //  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy