/******************************************************************************* * Copyright © 2011, 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * *******************************************************************************/ package org.eclipse.edt.compiler.internal.util; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.util.Properties; /** * <code>Encoder</code> encodes strings to make them difficult to memorize. * For example, this can be used to encode passwords in a file so that someone looking over your shoulder * won't be able to deteremine the password. This is not a substitute for using proper access control for * the file, or encryption. */ public class Encoder { /** the usage string */ public final static String USAGE = "Usage: Encoder [-action encode|decode] [-key <key-name>] [-in <input-file-name>] [-out <output-file-name>]"; //$NON-NLS-1$ /** the encode action */ public final static String ENCODE_ACTION = "encode"; //$NON-NLS-1$ /** the decode action */ public final static String DECODE_ACTION = "decode"; //$NON-NLS-1$ /** the default action is "encode" */ public final static String DEFAULT_ACTION = ENCODE_ACTION; /** the default property key value to encode is "password" */ public final static String DEFAULT_KEY = "password"; //$NON-NLS-1$ /** the option to specify an action name */ public final static String ACTION_OPTION = "-action"; //$NON-NLS-1$ /** the option to specify a key name */ public final static String KEY_OPTION = "-key"; //$NON-NLS-1$ /** the option to specify an input file */ public final static String INPUT_OPTION = "-in"; //$NON-NLS-1$ /** the option to specify an output file */ public final static String OUTPUT_OPTION = "-out"; //$NON-NLS-1$ /** the output file name or null for standard output */ private String outputFileName; /** the input file name or null for standard input */ private String inputFileName; /** the key name */ private String keyName = DEFAULT_KEY; /** the action */ private String action = DEFAULT_ACTION; /** the properties list */ private Properties properties; /** the prefix for encoded text - DO NOT change this value without talking to gen/runtime folks. We want to keep this prefix insynch!!! **/ private final static String ENCODED_PREFIX = "crypto:"; //$NON-NLS-1$ //needed to migrate old encoding to new encoding private final static String OLD_ENCODED_PREFIX = "encoded:"; //$NON-NLS-1$ /** the character encoding */ private final static String CHARACTER_ENCODING = "utf-8"; //$NON-NLS-1$ /** * Decodes an encoded text string. * * @return the decoded text string * @param encodedText the encoded text string to decode * @exception IllegalArgumentException if the input text is not encoded correctly */ public static String decode(String encodedText) throws IllegalArgumentException { return encodedText; // if (!isEncoded(encodedText)) { // // throw new IllegalArgumentException("Text is not encoded."); //$NON-NLS-1$ // } // // //If string was encoded using the old encoding, need to decode using old encoding for migration purposes. // if (encodedText.startsWith(OLD_ENCODED_PREFIX)) { // byte[] data8 = EGLOldDecoder.decode(encodedText.substring(OLD_ENCODED_PREFIX.length())); // int length8 = data8.length; // if (length8 % 8 != 0) { // // throw new IllegalArgumentException("Encoded text has wrong length."); //$NON-NLS-1$ // } // // int length = length8 / 8; // byte[] data = new byte[length]; // int[] mask = {1, 2, 4, 8, 16, 32, 64, 128}; // for (int i = 0; i < length; i++) { // for (int j = 0; j < 8; j++) { // // int k = j * length + i; // byte value = data8[k]; // value ^= k; // if ((value & mask[j]) != value) { // // throw new IllegalArgumentException("Encoded text has illegal value."); //$NON-NLS-1$ // } // data[i] += value; // } // } // // String clearText; // try { // clearText = new String(data, CHARACTER_ENCODING); // } catch (UnsupportedEncodingException uee) { // // throw new IllegalArgumentException(uee.getLocalizedMessage()); // } // return clearText; // } // //Use new encryption // else { // String result = new TeaEncrypter().decrypt(encodedText.substring(ENCODED_PREFIX.length())); // return result; // } } /** * Encodes a clear text string. * * @return the encoded text string * @param clearText the clear text string to encode * @exception IllegalArgumentException if the input text is already encoded */ public static String encode(String clearText) throws IllegalArgumentException { return clearText; // if (isEncoded(clearText)) { // // throw new IllegalArgumentException("Text is already encoded."); //$NON-NLS-1$ // } // // /** // * Don't encode an empty or null string // */ // if (clearText == null || clearText.length() == 0) { // return clearText; // } // // String base64 = new TeaEncrypter().encrypt(clearText); // // return ENCODED_PREFIX + base64; } public String getAction() { return action; } public String getInputFileName() { return inputFileName; } public String getKeyName() { return keyName; } public String getOutputFileName() { return outputFileName; } public Properties getProperties() { return properties; } /** * Tests if a text string is encoded. * * @return true if the text is encoded, false otherwise * @param text the string to test */ public static boolean isEncoded(String text) { return text != null && (text.startsWith(ENCODED_PREFIX)|| text.startsWith(OLD_ENCODED_PREFIX)); } /** * Loads the properties. * * @exception IOException if the input stream cannot be read * @exception FileNotFoundException if the input file does not exist */ public void load() throws IOException, FileNotFoundException { InputStream in; String inputFileName = getInputFileName(); if (inputFileName == null) { in = System.in; } else { in = new FileInputStream(inputFileName); } Properties properties = new Properties(); properties.load(in); in.close(); setProperties(properties); } /** * Encodes or decodes a value in a properties file. * The usage is: * <pre> * Encoder [-action encode|decode] [-key key-name] [-in input-file-name] [-out output-file-name] * </pre> * All arguments are optional. * If the action is not specified then "encode" is used. * If the key name is not specified then "password" is used. * If the input file is not specified then standard input is used. * If the output file is not specified then standard output is used. * The options may appear in any order and may be repeated. * The last value specified is used. * * @param args the string array of arguments */ public static void main(String[] args) { Encoder encoder = new Encoder(); try { encoder.parseArgs(args); } catch (Exception e) { System.err.println(e.getLocalizedMessage()); System.err.println(USAGE); return; } try { encoder.load(); encoder.update(); encoder.store(); } catch (Exception e) { e.printStackTrace(System.err); } } /** * Parses the command line arguments. * * @param args the string array of command line arguments */ public void parseArgs(String[] args) { int n = args.length; if (n % 2 != 0) { throw new IllegalArgumentException("Arguments must be in option-value pairs."); //$NON-NLS-1$ } for (int i = 0; i < n; i += 2) { String option = args[i]; String value = args[i + 1]; if (option.equals(ACTION_OPTION)) { setAction(value); } else if (option.equals(KEY_OPTION)) { setKeyName(value); } else if (option.equals(INPUT_OPTION)) { setInputFileName(value); } else if (option.equals(OUTPUT_OPTION)) { setOutputFileName(value); } else { throw new IllegalArgumentException("Unknown option: " + option); //$NON-NLS-1$ } } } public void setAction(String newAction) { action = newAction; } public void setInputFileName(String newInputFileName) { inputFileName = newInputFileName; } public void setKeyName(String newKeyName) { keyName = newKeyName; } public void setOutputFileName(String newOutputFileName) { outputFileName = newOutputFileName; } public void setProperties(Properties newProperties) { properties = newProperties; } /** * Stores the properties. * * @exception IOException if the properties list cannot be written to the output stream * @exception FileNotFoundException if the output file does not exist */ public void store() throws IOException, FileNotFoundException { String outputFileName = getOutputFileName(); OutputStream out; if (outputFileName == null) { out = System.out; } else { out = new FileOutputStream(outputFileName); } Properties properties = getProperties(); properties.store(out, null); out.close(); } /** * Updates the properties list. * If the key value is missing or empty then no action is taken. * Otherwise, if the key value is encoded and the action is decode, then the key value is decoded, * of if the key value in not encode and te action is encode, then the key value is encoded. */ public void update() { Properties properties = getProperties(); String keyName = getKeyName(); String keyValue = properties.getProperty(this.keyName); if (keyValue == null || keyValue.length() == 0) return; String action = getAction(); if (isEncoded(keyValue)) { if (action.equals(DECODE_ACTION)) { keyValue = decode(keyValue); } } else { if (action.equals(ENCODE_ACTION)) { keyValue = encode(keyValue); } } properties.setProperty(keyName, keyValue); } }