/*Copyright 2011 Jan Scheithauer

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package de.jingx.net.main;

import java.io.IOException;
import java.security.GeneralSecurityException;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;

import de.jingx.net.main.Base32String.DecodingException;

public class Main {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) {
		CommandLineParser parser = new PosixParser();
		Options options = new Options();
		options.addOption("s", true, "generate secret key (input is the configuration key from google)");
		options.addOption("g", true, "generate passcode (input is the secret key)");
		options.addOption(new Option( "help", "print this message"));
		try{
			CommandLine line = parser.parse( options, args );
			if(line.hasOption("s")){
				String confKey = line.getOptionValue("s");
				String secret  = generateSecret(confKey);
				System.out.println("Your secret to generate pins: " + secret);
			}else if(line.hasOption("g")){
				String secret = line.getOptionValue("g");
				String pin    = computePin(secret, null);
				System.out.println(pin);
			}else{
				HelpFormatter formatter = new HelpFormatter();
				formatter.printHelp( "Google Authenticator", options );
			}
			System.out.println("Press any key to exit");
			System.in.read();
		}catch (Exception e) {
			System.out.println( "Unexpected exception:" + e.getMessage() );
		}		
		System.exit(0);
	}
	
	public static String computePin(String secret, Long counter) {
		if (secret == null || secret.length() == 0) {
			return "Null or empty secret";
		}
		try {
			final byte[] keyBytes = Base32String.decode(secret);
			Mac mac = Mac.getInstance("HMACSHA1");
			mac.init(new SecretKeySpec(keyBytes, ""));
			PasscodeGenerator pcg = new PasscodeGenerator(mac);
			if (counter == null) { // time-based totp
				return pcg.generateTimeoutCode();
			} else { // counter-based hotp
				return pcg.generateResponseCode(counter);
			}
		} catch (GeneralSecurityException e) {
			return "General security exception";
		} catch (DecodingException e) {
			return "Decoding exception";
		}
	}
	
	private static String generateSecret(String key){
		return key.replaceAll("1", "I").replaceAll("0", "O");
	}

}

@@ -1063,16 +1063,114 @@
 s Main %7B
+%0A%09%0A%09private static final String CLI_SECRET = %22s%22;%0A%09private static final String CLI_PASSCODE = %22p%22;
 %0A%0A%09/**%0A%09
@@ -1359,19 +1359,26 @@
 dOption(
-%22s%22
+CLI_SECRET
 , true, 
@@ -1466,19 +1466,28 @@
 dOption(
-%22g%22
+CLI_PASSCODE
 , true, 
@@ -1679,19 +1679,26 @@
 sOption(
-%22s%22
+CLI_SECRET
 ))%7B%0A%09%09%09%09
@@ -1734,19 +1734,26 @@
 onValue(
-%22s%22
+CLI_SECRET
 );%0A%09%09%09%09S
@@ -1887,19 +1887,28 @@
 sOption(
-%22g%22
+CLI_PASSCODE
 ))%7B%0A%09%09%09%09
@@ -1947,11 +1947,20 @@
 lue(
-%22g%22
+CLI_PASSCODE
 );%0A%09
@@ -2125,27 +2125,15 @@
 ( %22G
-oogle Authenticator
+AuthCli
 %22, o
@@ -3075,18 +3075,60 @@
 %7B%0A%09%09
-return key
+String s = key;%0A%09%09s = s.replaceAll(%22 %22, %22%22);%0A%09%09s = s
 .rep
@@ -3144,16 +3144,25 @@
 1%22, %22I%22)
+;%0A%09%09s = s
 .replace
@@ -3176,14 +3176,26 @@
 , %22O%22);%0A
+%09%09return s;%0A
 %09%7D%0A%0A%7D%0A

Replace spaces, refactoring