package scotty;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import scotty.crypto.CryptoException;
import scotty.crypto.KeyManager;
import scotty.event.EventDispatcher;
import scotty.event.EventObserver;
import scotty.event.Events;
/**
* Main class CLI facade. scotty, transporter of freedom.
*
* Usage: scotty [-g <Gateway-URL>] [-p <Local-Port>] [ -d ] [ -proxyHost
* <proxyHost> -proxyPort <Port> ]<br />
* <br />
* CLI Params: <br />
* <br />
* -g Gateway-url wg. http://my.gatew.ay/gate.php <br />
* -p local Port eg. 8008 <br />
* -d disables gateway usage, no value<br />
* -proxyHost proxy Host (eg. my.pro.xy)<br />
* -proxyPort proxy Port (eg. 8080)
*
* @author flo
*
*/
public class ScottyCli implements EventObserver {
private static final String HELP_CMDLINE_PARAM = "h";
private static Logger log = Logger.getLogger(ScottyCli.class);
/**
* CLI to disable the gateway usage
*/
private static final String DONT_USE_GATEWAY = "d";
/**
* CLI to specify gateway.
*/
private static final String GATEWAY_CMDLINE_PARAM = "g";
/**
* CLI to specify the local port
*/
private static final String LOCALPORT_CMDLINE_PARAM = "p";
/**
* CLI for creating a new key pair
*/
private static final String CREATEKEY_CMDLINE_PARAM = "c";
/**
* CLI for proxy host
*/
private static final String PROXY_HOST_CMDLINE_PARAM = "proxyHost";
/**
* CLI for proxy port
*/
private static final String PROXY_PORT_CMDLINE_PARAM = "proxyPort";
/**
* CLI for creating a new key pair
*/
private static final String TOKENTIMEOUT_CMDLINE_PARAM = "timeout";
/**
* CLI to specify gateway.
*/
private static final String DISABLE_ENCRYPTION_CMDLINE_PARAM = "disableencryption";
/**
* CLI for private key
*/
private static final String PRIVATEKEY_CMDLINE_PARAM = "privatekey";
/**
* CLI for public key
*/
private static final String PUBLICKEY_CMDLINE_PARAM = "publickey";
/**
* CLI for gateways public key
*/
private static final String GATEWAYSPUBLICKEY_CMDLINE_PARAM = "gatewayspublickey";
/**
* CLI password for private key
*/
private static final String PRIVATEKEYPASS_CMDLINE_PARAM = "privatekeypassword";
/**
* default private key
*/
private static final String DEFAULT_PRIVATEKEY = "resources:defaultprivatekey";
/**
* default public key
*/
private static final String DEFAULT_PUBLICKEY = "resources:defaultpublickey";
/**
* default gateways key
*/
private static final String DEFAULT_GATEWAYSPUBLICKEY = "resources:gatewaydefaultpublickey";
/**
* Cmdline Param to enable debug logging.
*/
private static final String LOG_CMDLINE = "log";
/**
* Instance of scotty.
*/
private Scotty scotty;
/**
* Default local port.
*/
private String defaultLocalPort = "8008";
/**
* Default Gateway URL of the scotty-gateway to use.
*/
private String defaultGatewayUrl = "http://localhost:9000";
public ScottyCli() {
EventDispatcher.add(this);
}
/**
* Initialize Scotty.
*
* @param args
* Arguments
* @throws Exception
* Exception.
*/
public static void main(String[] args) throws Exception {
ScottyCli cli = new ScottyCli();
Scotty scotty = new Scotty();
cli.scotty = scotty;
CommandLine commandLine = cli.handleCommandline(args);
// generate keys
if (commandLine.hasOption(CREATEKEY_CMDLINE_PARAM)) {
generateKeyPair();
// start scotty
} else {
// load keys
cli.loadKeys(commandLine);
// start server
scotty.init();
}
}
private static void generateKeyPair() throws IOException, Exception,
CryptoException {
BufferedReader commandLineInput = new BufferedReader(
new InputStreamReader(System.in));
System.out.print("filename of private key: ");
String privateKeyFile = commandLineInput.readLine();
System.out.print("filename of public key: ");
String publicKeyFile = commandLineInput.readLine();
System.out.print("password for private key: ");
String privateKeyPassword = new String(System.console().readPassword());
KeyManager keyManager = KeyManager.getInstance();
keyManager.generateKeyPair();
System.out.println("key pair successfully generated");
keyManager.writePrivateKey(privateKeyFile, privateKeyPassword);
System.out.println("private key successfully saved");
keyManager.writePublicKey(publicKeyFile);
System.out.println("public key successfully saved");
// check parsing files
KeyManager checkKeyManager = KeyManager.getInstance();
checkKeyManager.readPrivateKey(privateKeyFile, privateKeyPassword);
if (checkKeyManager.getPrivateKey() != null)
System.out.println("private key successfully read");
else
System.err.println("can't read generated private key file");
checkKeyManager.readPublicKey(publicKeyFile);
if (checkKeyManager.getPublicKey() != null)
System.out.println("public key successfully read");
else
System.err.println("can't read generated public key file");
}
/**
* Load Keys for RSA Encryption, either from commandline or default keys.
*
* @param commandLine
* @throws CryptoException
*/
public void loadKeys(CommandLine commandLine) throws CryptoException {
KeyManager keyManager = KeyManager.getInstance();
if (commandLine.hasOption(PRIVATEKEY_CMDLINE_PARAM)) {
String password = commandLine.hasOption(PRIVATEKEYPASS_CMDLINE_PARAM) ? commandLine.getOptionValue(PRIVATEKEYPASS_CMDLINE_PARAM) : "";
if(password==null) {
System.out.print("password for private key: ");
password = new String(System.console().readPassword());
}
keyManager.readPrivateKey(commandLine.getOptionValue(PRIVATEKEY_CMDLINE_PARAM), password);
log.info("Use given private key " + commandLine.getOptionValue(PRIVATEKEY_CMDLINE_PARAM));
} else {
keyManager.readPrivateKey(DEFAULT_PRIVATEKEY, "");
}
if (commandLine.hasOption(PUBLICKEY_CMDLINE_PARAM)) {
keyManager.readPublicKey(commandLine.getOptionValue(PUBLICKEY_CMDLINE_PARAM));
log.info("Use given public key " + commandLine.getOptionValue(PUBLICKEY_CMDLINE_PARAM));
} else {
keyManager.readPublicKey(DEFAULT_PUBLICKEY);
}
if (commandLine.hasOption(GATEWAYSPUBLICKEY_CMDLINE_PARAM)) {
keyManager.readGatewaysPublicKey(commandLine.getOptionValue(GATEWAYSPUBLICKEY_CMDLINE_PARAM));
log.info("Use given gateway public key " + commandLine.getOptionValue(GATEWAYSPUBLICKEY_CMDLINE_PARAM));
} else {
keyManager.readGatewaysPublicKey(DEFAULT_GATEWAYSPUBLICKEY);
}
if (commandLine.hasOption(TOKENTIMEOUT_CMDLINE_PARAM)) {
long tokenTimeout = Long.parseLong(commandLine.getOptionValue(TOKENTIMEOUT_CMDLINE_PARAM));
keyManager.setMaxValidityOfToken(tokenTimeout);
log.info("Use given token timeout " + commandLine.getOptionValue(TOKENTIMEOUT_CMDLINE_PARAM));
}
}
/**
* Parses the commandline and sets the configs.
*
* @param args
* args.
* @throws Exception
* exc.
*/
private CommandLine handleCommandline(String[] args) throws Exception {
Options opts = new Options();
opts.addOption(GATEWAY_CMDLINE_PARAM, true, "URL of the gateway. e.g. http://yourpxory.somewhere. Default: http://localhost:" + defaultLocalPort);
opts.addOption(LOCALPORT_CMDLINE_PARAM, true,
"Local port, where scotty listens for requests. Default: " + defaultLocalPort);
opts.addOption(CREATEKEY_CMDLINE_PARAM, false, "Create new KeyPair");
opts.addOption(PRIVATEKEY_CMDLINE_PARAM, true, "Private key");
opts.addOption(OptionBuilder.hasOptionalArg().withDescription("private key password (if one was set)").create(PRIVATEKEYPASS_CMDLINE_PARAM));
opts.addOption(PUBLICKEY_CMDLINE_PARAM, true, "Public key");
opts.addOption(GATEWAYSPUBLICKEY_CMDLINE_PARAM, true, "Gateways public key");
opts.addOption(DISABLE_ENCRYPTION_CMDLINE_PARAM, false,
"Disable encryption.");
opts.addOption(TOKENTIMEOUT_CMDLINE_PARAM, true,
"Timeout for the RSA token. Default: 1.5 hours");
opts.addOption(DONT_USE_GATEWAY, false,
"Don't use gateway - direct connection.");
opts.addOption(PROXY_HOST_CMDLINE_PARAM, true, "Proxy host");
opts.addOption(PROXY_PORT_CMDLINE_PARAM, true, "Proxy port");
opts.addOption(HELP_CMDLINE_PARAM, false, "Print help message and exit");
opts.addOption(LOG_CMDLINE, false, "Enables debug logging");
CommandLineParser cmd = new PosixParser();
CommandLine line = cmd.parse(opts, args);
if ( line.hasOption(HELP_CMDLINE_PARAM) ) {
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp("scotty", opts, true);
System.exit(0);
}
if ( line.hasOption(LOG_CMDLINE)) {
LogManager.resetConfiguration();
PropertyConfigurator.configure(ScottyCli.class.getResourceAsStream("/log4j-trace.properties"));
}
if (line.hasOption(PROXY_HOST_CMDLINE_PARAM)
&& line.hasOption(PROXY_PORT_CMDLINE_PARAM)) {
scotty.setHttpProxy(line.getOptionValue(PROXY_HOST_CMDLINE_PARAM),
Integer.valueOf(line
.getOptionValue(PROXY_PORT_CMDLINE_PARAM)));
scotty.setHttpsProxy(line.getOptionValue(PROXY_HOST_CMDLINE_PARAM),
Integer.valueOf(line
.getOptionValue(PROXY_PORT_CMDLINE_PARAM)));
}
scotty.setGatewayUrl(line.getOptionValue(GATEWAY_CMDLINE_PARAM, defaultGatewayUrl ));
scotty.setLocalPort(line.getOptionValue(LOCALPORT_CMDLINE_PARAM,
defaultLocalPort));
if (line.hasOption(DONT_USE_GATEWAY)) {
scotty.setUseGateway(false);
}
if (line.hasOption(DISABLE_ENCRYPTION_CMDLINE_PARAM)) {
scotty.setDisableEncryption(true);
}
validateParamsAndExitOnFailure();
return line;
}
private void validateParamsAndExitOnFailure() {
String gatewayUrl = scotty.getGatewayUrl();
int exit = -1;
if ( gatewayUrl != null && gatewayUrl.length() > 0 ) {
try {
URL url = new URL(gatewayUrl);
} catch (MalformedURLException e) {
System.err.println("Gateway URL not valid. Specified: [" + gatewayUrl +"]. Exit.");
e.printStackTrace();
exit = 1;
}
}else if (scotty.isUseGateway()) {
System.err.println("Gateway URL not specified. Exit.");
exit = 2;
}
if ( exit > -1 ) {
System.err.println("Use -h to see help.");
System.exit(exit);
}
}
/**
* Eventhandler for Systray Icon
*
* @param event
* exit event
* @param o
* optional param
*/
@Override
public void eventReceived(Events event, Object o) {
if (event.equals(Events.EXIT)) {
try {
scotty.stop();
} catch (Exception e) {
log.warn("Exception while stopping:", e);
} finally {
System.exit(0);
}
}
}
}