/* * * Copyright (c) 2013 - 2017 Lijun Liao * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License version 3 * as published by the Free Software Foundation with the addition of the * following permission added to Section 15 as permitted in Section 7(a): * * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY * THE AUTHOR LIJUN LIAO. LIJUN LIAO DISCLAIMS THE WARRANTY OF NON INFRINGEMENT * OF THIRD PARTY RIGHTS. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * The interactive user interfaces in modified source and object code versions * of this program must display Appropriate Legal Notices, as required under * Section 5 of the GNU Affero General Public License. * * You can be released from the requirements of the license by purchasing * a commercial license. Buying such a license is mandatory as soon as you * develop commercial activities involving the XiPKI software without * disclosing the source code of your own applications. * * For more information, please contact Lijun Liao at this * address: lijun.liao@gmail.com */ package org.xipki.commons.console.karaf; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.math.BigInteger; import java.security.SecureRandom; import java.util.Collection; import java.util.List; import org.apache.karaf.shell.api.action.Action; import org.apache.karaf.shell.api.action.lifecycle.Reference; import org.apache.karaf.shell.api.console.Session; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xipki.commons.common.util.CollectionUtil; import org.xipki.commons.common.util.IoUtil; import org.xipki.commons.common.util.StringUtil; import org.xipki.commons.password.SecurePasswordInputPanel; /** * @author Lijun Liao * @since 2.0.0 */ public abstract class XipkiCommandSupport implements Action { private static final Logger LOG = LoggerFactory.getLogger(XipkiCommandSupport.class); @Reference protected Session session; protected abstract Object doExecute() throws Exception; @Override public Object execute() throws Exception { try { return doExecute(); } catch (Exception ex) { LOG.debug("Exception caught while executing command", ex); throw new Exception(ex.getClass().getName() + ": " + ex.getMessage()); } } protected boolean isTrue(final Boolean bo) { return bo != null && bo.booleanValue(); } protected void saveVerbose(final String promptPrefix, final File file, final byte[] encoded) throws IOException { File saveTo = expandFilepath(file); boolean randomSaveTo = false; if (saveTo.exists()) { try { boolean bo = true; while (saveTo.exists()) { String answer; if (bo) { answer = readPrompt("A file named '" + saveTo.getPath() + "' already exists. Do you want to replace it [yes/no]? "); } else { answer = session.readLine(null, null); } if (answer == null) { throw new IOException("interrupted"); } if ("yes".equalsIgnoreCase(answer)) { break; } else if ("no".equalsIgnoreCase(answer)) { String newFn; while (true) { newFn = readPrompt("Enter name of file to save to ... "); if (!newFn.trim().isEmpty()) { break; } } saveTo = new File(newFn); } else { readPrompt("Please answer with yes or no. "); bo = false; } } // end while } catch (IOException ex) { saveTo = new File("tmp-" + randomHex(6)); randomSaveTo = true; } } // end if(saveTo.exists()) File parent = file.getParentFile(); if (parent != null && !parent.exists()) { parent.mkdirs(); } try { save(saveTo, encoded); } catch (IOException ex) { if (!randomSaveTo) { saveTo = new File("tmp-" + randomHex(6)); save(saveTo, encoded); } } String tmpPromptPrefix = promptPrefix; if (tmpPromptPrefix == null || tmpPromptPrefix.isEmpty()) { tmpPromptPrefix = "saved to file"; } println(tmpPromptPrefix + " " + saveTo.getPath()); } // method saveVerbose protected void save(final File file, final byte[] encoded) throws IOException { File tmpFile = expandFilepath(file); File parent = tmpFile.getParentFile(); if (parent != null && !parent.exists()) { parent.mkdirs(); } FileOutputStream out = new FileOutputStream(tmpFile); try { out.write(encoded); } finally { out.close(); } } private static String randomHex(final int numOfBytes) { SecureRandom random = new SecureRandom(); byte[] bytes = new byte[numOfBytes]; random.nextBytes(bytes); return new BigInteger(1, bytes).toString(16); } protected static boolean isEnabled(final String enabledS, final boolean defaultEnabled, final String optionName) { return (enabledS == null) ? defaultEnabled : internIsEnabled(enabledS, optionName); } private static boolean internIsEnabled(final String enabledS, final String optionName) { if ("yes".equalsIgnoreCase(enabledS) || "enabled".equalsIgnoreCase(enabledS) || "true".equalsIgnoreCase(enabledS)) { return true; } else if ("no".equalsIgnoreCase(enabledS) || "disabled".equalsIgnoreCase(enabledS) || "false".equalsIgnoreCase(enabledS)) { return false; } else { throw new IllegalArgumentException("invalid option " + optionName + ": " + enabledS); } } protected String readPrompt(final String prompt) throws IOException { String tmpPrompt = prompt; if (StringUtil.isNotBlank(prompt)) { if (!prompt.endsWith(" ")) { tmpPrompt += " "; } } return readLine(tmpPrompt, null); } protected char[] readPasswordIfNotSet(final String password) throws IOException { return readPasswordIfNotSet(null, password); } protected char[] readPasswordIfNotSet(final String prompt, final String password) throws IOException { if (password != null) { return password.toCharArray(); } return readPassword(prompt); } protected char[] readPassword() throws IOException { return readPassword(null); } protected char[] readPassword(final String prompt) throws IOException { String tmpPrompt = (prompt == null) ? "Password:" : prompt.trim(); if (!tmpPrompt.endsWith(":")) { tmpPrompt += ":"; } String passwordUi = System.getProperty("org.xipki.console.passwordui"); return "gui".equalsIgnoreCase(passwordUi) ? SecurePasswordInputPanel.readPassword(tmpPrompt) : readLine(tmpPrompt, '*').toCharArray(); } private String readLine(String prompt, Character ch) throws IOException { Object oldIgnoreInterrupts = session.get(Session.IGNORE_INTERRUPTS); session.put(Session.IGNORE_INTERRUPTS, Boolean.TRUE); try { String line = session.readLine(prompt, ch); if (line == null) { throw new IOException("interrupted"); } return line; } finally { session.put(Session.IGNORE_INTERRUPTS, oldIgnoreInterrupts); } } protected static String expandFilepath(final String path) { return IoUtil.expandFilepath(path); } protected static File expandFilepath(final File file) { return IoUtil.expandFilepath(file); } protected void println(final String message) { System.out.println(message); } protected void print(final String message) { System.out.print(message); } protected static boolean isBlank(final String str) { return StringUtil.isBlank(str); } protected static boolean isNotBlank(final String str) { return StringUtil.isNotBlank(str); } protected static boolean isEmpty(final Collection<?> col) { return CollectionUtil.isEmpty(col); } protected static boolean isNotEmpty(final Collection<?> col) { return CollectionUtil.isNonEmpty(col); } protected static List<String> split(final String str, final String delim) { return StringUtil.split(str, delim); } protected static BigInteger toBigInt(final String str) { return toBigInt(str, false); } protected static BigInteger toBigInt(final String str, boolean defaultHex) { String tmpStr = str.trim(); if (tmpStr.startsWith("0x") || tmpStr.startsWith("0X")) { if (tmpStr.length() > 2) { return new BigInteger(tmpStr.substring(2), 16); } else { throw new NumberFormatException("invalid integer '" + tmpStr + "'"); } } return new BigInteger(tmpStr, defaultHex ? 16 : 10); } protected boolean confirm(final String prompt, final int maxTries) throws IOException { String tmpPrompt; if (prompt == null || prompt.isEmpty()) { tmpPrompt = "[yes/no]? "; } else { if ('?' == prompt.charAt(prompt.length() - 1)) { tmpPrompt = prompt.substring(0, prompt.length() - 1); } else { tmpPrompt = prompt; } tmpPrompt += " [yes/no]? "; } String answer = readLine(tmpPrompt, null); if (answer == null) { throw new IOException("interrupted"); } int tries = 1; while (tries < maxTries) { if ("yes".equalsIgnoreCase(answer)) { return true; } else if ("no".equalsIgnoreCase(answer)) { return false; } else { tries++; } answer = readLine("Please answer with yes or no: ", null); } return false; } }