package com.github.eirslett.maven.plugins.frontend.lib;

import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.AccessDeniedException;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import org.apache.commons.io.IOUtils;
import org.codehaus.plexus.util.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

class ArchiveExtractionException extends Exception {

    ArchiveExtractionException(String message) {
        super(message);
    }

    ArchiveExtractionException(String message, Throwable cause) {
        super(message, cause);
    }
}

interface ArchiveExtractor {
    public void extract(String archive, String destinationDirectory) throws ArchiveExtractionException;
}

final class DefaultArchiveExtractor implements ArchiveExtractor {

    private static final Logger LOG = LoggerFactory.getLogger(DefaultArchiveExtractor.class);

    private void prepDestination(File path, boolean directory) throws IOException {
        if (directory) {
            path.mkdirs();
        } else {
            if (!path.getParentFile().exists()) {
                path.getParentFile().mkdirs();
            }
            if(!path.getParentFile().canWrite()) {
                throw new AccessDeniedException(
                        String.format("Could not get write permissions for '%s'", path.getParentFile().getAbsolutePath()));
            }
        }
    }

    @Override
    public void extract(String archive, String destinationDirectory) throws ArchiveExtractionException {
        final File archiveFile = new File(archive);

        try (FileInputStream fis = new FileInputStream(archiveFile)) {
            if ("msi".equals(FileUtils.getExtension(archiveFile.getAbsolutePath()))) {
                String command = "msiexec /a " + archiveFile.getAbsolutePath() + " /qn TARGETDIR=\""
                    + destinationDirectory + "\"";
                Process child = Runtime.getRuntime().exec(command);
                try {
                    int result = child.waitFor();
                    if (result != 0) {
                        throw new ArchiveExtractionException(
                            "Could not extract " + archiveFile.getAbsolutePath() + "; return code " + result);
                    }
                } catch (InterruptedException e) {
                    throw new ArchiveExtractionException(
                        "Unexpected interruption of while waiting for extraction process", e);
                }
            } else if ("zip".equals(FileUtils.getExtension(archiveFile.getAbsolutePath()))) {
                ZipFile zipFile = new ZipFile(archiveFile);
                try {
                    Enumeration<? extends ZipEntry> entries = zipFile.entries();
                    while (entries.hasMoreElements()) {
                        ZipEntry entry = entries.nextElement();
                        final File destPath = new File(destinationDirectory + File.separator + entry.getName());
                        prepDestination(destPath, entry.isDirectory());
                        if(!entry.isDirectory()){
		                        InputStream in = null;
		                        OutputStream out = null;
		                        try {
		                            in = zipFile.getInputStream(entry);
		                            out = new FileOutputStream(destPath);
		                            IOUtils.copy(in, out);
		                        } finally {
		                            IOUtils.closeQuietly(in);
		                            IOUtils.closeQuietly(out);
		                        }
                        }
                    }
                } finally {
                    zipFile.close();
                }
            } else {
		            // TarArchiveInputStream can be constructed with a normal FileInputStream if
		            // we ever need to extract regular '.tar' files.
                TarArchiveInputStream tarIn = null;
                try {
				            tarIn = new TarArchiveInputStream(new GzipCompressorInputStream(fis));

				            TarArchiveEntry tarEntry = tarIn.getNextTarEntry();
				            while (tarEntry != null) {
				                // Create a file for this tarEntry
				                final File destPath = new File(destinationDirectory + File.separator + tarEntry.getName());
		                    prepDestination(destPath, tarEntry.isDirectory());
				                if (!tarEntry.isDirectory()) {
				                    destPath.createNewFile();
				                    boolean isExecutable = (tarEntry.getMode() & 0100) > 0;
				                    destPath.setExecutable(isExecutable);

		                        OutputStream out = null;
		                        try {
		                            out = new FileOutputStream(destPath);
		                            IOUtils.copy(tarIn, out);
		                        } finally {
		                            IOUtils.closeQuietly(out);
		                        }
				                }
				                tarEntry = tarIn.getNextTarEntry();
				            }
                } finally {
                    IOUtils.closeQuietly(tarIn);
                }
            }
        } catch (IOException e) {
            throw new ArchiveExtractionException("Could not extract archive: '"
                    + archive
                    + "'", e);
        }
    }
}

@@ -4778,16 +4778,388 @@
 ory());%0A
+                                if (!destPath.getCanonicalPath().startsWith(destinationDirectory)) %7B%0A                                     throw new IOException(%0A                                             %22Expanding %22 + tarEntry.getName() + %22 would create file outside of %22 + destinationDirectory%0A                                     );%0A                                %7D%0A
 %09%09%09%09    

Check for file path when extracting the archive