All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.dataliquid.maven.distribution.verifier.service.VerifierService Maven / Gradle / Ivy

There is a newer version: 1.0.3
Show newest version
/**
 * Copyright © 2019 dataliquid GmbH | www.dataliquid.com
 *
 * 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 com.dataliquid.maven.distribution.verifier.service;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FilenameUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.DOMException;
import org.zeroturnaround.zip.ZipUtil;

import com.dataliquid.maven.distribution.verifier.domain.Entry;
import com.dataliquid.maven.distribution.verifier.domain.VerificationStatus;

public class VerifierService
{
    private static final String EMPTY = "";
    private final Logger logger = LoggerFactory.getLogger(getClass());

    public boolean verify(File distributionArchiveFile, File workDirectory, File whitelist, String reportFile,
            Map properties)
    {

        Boolean verificationStatus = null;
        try
        {
            File destinationDirectory = null;
            if (workDirectory != null)
            {
                String distributionWorkDirectory = distributionArchiveFile.getName().concat("-unzipped");
                destinationDirectory = new File(workDirectory, distributionWorkDirectory);
            }
            else
            {
                String name = distributionArchiveFile.getName().concat("-unzipped");
                destinationDirectory = new File(distributionArchiveFile.getParentFile(), name);
            }

            logger.info("Unzip distribution archive file " + distributionArchiveFile.getPath() + " to " + destinationDirectory);

            ZipUtil.unpack(distributionArchiveFile, destinationDirectory);

            logger.info("File unzipped successfully");

            logger.info("Loading whitelist " + whitelist);
            List entries = loadWhitelist(whitelist, properties);
            logger.info("Whitelist file loaded successfully - Entries: " + entries.size());

            logger.info("Verifying whitelist files against distribution archive");

            verificationStatus = verifyDistributionArchive(destinationDirectory, entries, reportFile, destinationDirectory);

            logger.info("Verification completed. See the generate report at " + reportFile);

        }
        catch (Exception e)
        {
            e.printStackTrace();
            logger.error("Error occurred : {}", e.getMessage(), e);
            verificationStatus = false;
        }

        return verificationStatus;

    }

    private boolean verifyDistributionArchive(File directory, List entries, String reportFile, File originalDirectory)
            throws Exception
    {
        boolean verificationStatus = true;

        Document document = DocumentHelper.createDocument();
        Element report = document.addElement("report");

        for (Entry entry : entries)
        {
            Element reportEntry = report.addElement("entry");
            reportEntry.addAttribute("path", entry.getPath());
            reportEntry.addAttribute("md5", entry.getMd5());

            File currentFile = new File(directory.getPath().concat(entry.getPath()));
            if (currentFile.exists())
            {
                logger.debug("Defined entry found " + entry.getPath());

                if (entry.getMd5() != null && !entry.getMd5().isEmpty())
                {
                    String fileMd5Checksum = getFileChecksum(currentFile);
                    if (fileMd5Checksum.equals(entry.getMd5()))
                    {
                        logger.debug("MD5 Checksum of file " + currentFile.getPath() + " is identical to " + entry.getPath());

                        Element result = reportEntry.addElement("result");
                        result.addAttribute("status", VerificationStatus.SUCCESS.name());
                        result.addAttribute("message", "Validation passed successfully");
                    }
                    else
                    {
                        verificationStatus = false;

                        logger.debug("MD5 checksum of file " + currentFile.getPath() + " is different to " + entry.getPath());

                        Element result = reportEntry.addElement("result");
                        result.addAttribute("status", VerificationStatus.FAILED.name());
                        result.addAttribute("message", "File found but with a different MD5 Checksum " + fileMd5Checksum);
                    }
                }
                else
                {
                    Element result = reportEntry.addElement("result");
                    result.addAttribute("status", VerificationStatus.SUCCESS.name());
                    result.addAttribute("message", "Validation passed successfully");
                }
            }
            else
            {
                verificationStatus = false;

                logger.debug("Defined file is not found " + entry.getPath() + EMPTY);

                Element result = reportEntry.addElement("result");
                result.addAttribute("status", VerificationStatus.FAILED.name());
                result.addAttribute("message", "Defined file not found");
            }

        }

        verifyAllFilesInWhitelist(directory, entries, originalDirectory, report);

        try (FileWriter writer = new FileWriter(reportFile))
        {
            OutputFormat format = OutputFormat.createPrettyPrint();
            XMLWriter xmlWriter = new XMLWriter(writer, format);
            xmlWriter.write(document);
        }
        catch (Exception e)
        {
            throw e;
        }

        return verificationStatus;
    }

    public void verifyAllFilesInWhitelist(File directory, List whitelistEntries, File originalDirectory, Element report)
            throws Exception
    {
        File[] directoryEntries = directory.listFiles();
        for (File directoryEntry : directoryEntries)
        {
            if (directoryEntry.isDirectory())
            {
                verifyAllFilesInWhitelist(directoryEntry, whitelistEntries, originalDirectory, report);
            }
            else
            {
                verifyFileInWhitelist(directoryEntry, whitelistEntries, originalDirectory, report);
            }
        }
    }

    private void verifyFileInWhitelist(File subDirectory, List entries, File originalDirectory, Element report)
            throws DOMException, NoSuchAlgorithmException, IOException
    {
        boolean exists = false;
        String strippedDirectory = FilenameUtils.normalize(subDirectory.getPath().replace(originalDirectory.getPath(), EMPTY), true);
        for (Entry entry : entries)
        {
            if (FilenameUtils.equalsNormalized(strippedDirectory, entry.getPath()))
            {
                exists = true;
                break;
            }
        }
        if (!exists)
        {
            Element reportEntry = report.addElement("entry");
            reportEntry.addAttribute("path", strippedDirectory);
            reportEntry.addAttribute("md5", getFileChecksum(subDirectory));

            Element result = reportEntry.addElement("result");
            result.addAttribute("status", VerificationStatus.FAILED.name());
            result.addAttribute("message", "File is not defined in whitelist");
        }

    }

    public List loadWhitelist(File whitelist, Map properties) throws Exception
    {
        SAXReader reader = new SAXReader();
        Document document = reader.read(whitelist);

        List entries = new ArrayList();
        List nodes = document.selectNodes("//whitelist/entry");
        for (Node node : nodes)
        {
            if (node.getNodeType() == Node.ELEMENT_NODE)
            {
                Element element = (Element) node;

                Entry entry = new Entry();
                entry.setPath(element.attributeValue("path"));
                entry.setMd5(element.attributeValue("md5"));
                evaluate(entry, properties);
                entries.add(entry);
                logger.debug(" properties)
    {
        String path = evaluateString(entry.getPath(), properties);
        entry.setPath(path);
    }

    /**
     * Evaluate variable within given string value
     * 
     * @param value
     *            lorem ${var} elit
     * @param variables
     *            Map vars; vars.put("var", "ipsum");
     * @return
     */
    private String evaluateString(String value, Map variables)
    {
        final Matcher matcher = Pattern.compile("\\$\\{(.*?)\\}").matcher(value);
        final StringBuffer buffer = new StringBuffer(value.length());
        while (matcher.find())
        {
            if (variables.containsKey(matcher.group(1)))
            {
                matcher.appendReplacement(buffer, variables.get(matcher.group(1)));
            }
            else
            {
                logger.warn("Variable '" + matcher.group(1) +  "' is defined but could not resolved by the given variables.");
            }
        }
        matcher.appendTail(buffer);
        return buffer.toString();
    }

    private String getFileChecksum(File file) throws IOException, NoSuchAlgorithmException
    {
        return DigestUtils.md5Hex(new FileInputStream(file));
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy