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

org.digidoc4j.utils.Helper Maven / Gradle / Ivy

/* DigiDoc4J library
 *
 * This software is released under either the GNU Library General Public
 * License (see LICENSE.LGPL).
 *
 * Note that the only valid version of the LGPL license as far as this
 * project is concerned is the original GNU Library General Public License
 * Version 2.1, February 1999
 */

package org.digidoc4j.utils;

import eu.europa.esig.dss.model.DSSDocument;
import eu.europa.esig.dss.spi.DSSUtils;
import eu.europa.esig.dss.validation.SignaturePolicyProvider;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.filefilter.CanReadFileFilter;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.digidoc4j.Container;
import org.digidoc4j.ContainerBuilder;
import org.digidoc4j.DataFile;
import org.digidoc4j.exceptions.DigiDoc4JException;
import org.digidoc4j.impl.asic.TmSignaturePolicyType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.filechooser.FileNameExtensionFilter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.SecureRandom;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import static java.lang.Math.min;
import static java.nio.file.Files.deleteIfExists;

/**
 * Class of helper methods.
 */
public final class Helper {

  public static final String SPECIAL_CHARACTERS = "[\\\\<>:\"/|?*]";
  private static final Logger logger = LoggerFactory.getLogger(Helper.class);
  private static final int ZIP_VERIFICATION_CODE = 0x504b0304;
  private static final char[] hexArray = "0123456789ABCDEF".toCharArray();
  private static final Random random = new SecureRandom();

  private Helper() {
  }

  /**
   * @param path folder path
   * @return list of files
   */
  public static File[] getFilesFromPath(Path path) {
    return Helper.getFilesFromPath(path, CanReadFileFilter.CAN_READ);
  }

  /**
   * @param path   folder path
   * @param filter file filter
   * @return list of files
   */
  public static File[] getFilesFromPath(Path path, FileFilter filter) {
    File folder = path.toFile();
    if (folder.isDirectory()) {
      return folder.listFiles(filter);
    } else {
      try {
        return Helper.getFilesFromResourcePath(path, CanReadFileFilter.CAN_READ);
      } catch (IllegalArgumentException e) {
        logger.warn(String.format("Unable to load any file from <%s>", path), e);
      }
    }
    return new File[]{};
  }

  /**
   * @param path resource path
   * @return list of files
   */
  public static File[] getFilesFromResourcePath(Path path) {
    return Helper.getFilesFromResourcePath(path, CanReadFileFilter.CAN_READ);
  }

  /**
   * @param path   resource path
   * @param filter file filter
   * @return list of files
   */
  public static File[] getFilesFromResourcePath(Path path, FileFilter filter) {
    URL url = Helper.class.getClassLoader().getResource(path.toString());
    if (url == null) {
      throw new IllegalArgumentException(String.format("No resource <%s> found", path));
    }
    if ("jar".equals(url.getProtocol())) {
      return Helper.getFilesFromJar(url, filter);
    } else {
      File folder;
      try {
        folder = new File(url.toURI());
      } catch (URISyntaxException e) {
        throw new IllegalArgumentException(String.format("Resource path <%s> is malformed", url));
      }
      if (!folder.isDirectory()) {
        throw new IllegalArgumentException(String.format("Resource <%s> is not a folder", path));
      }
      return folder.listFiles(filter);
    }
  }

  /**
   * @param length the length of array
   * @return array of random bytes
   */
  public static byte[] generateRandomBytes(int length) {
    byte[] bytes = new byte[length];
    Helper.random.nextBytes(bytes);
    return bytes;
  }

  /**
   * @param stream aa
   * @return aa
   * @throws IOException aa
   */
  public static boolean isZipFile(InputStream stream) throws IOException {
    DataInputStream in = new DataInputStream(stream);
    if (stream.markSupported())
      stream.mark(Integer.BYTES);
    int test = in.readInt();
    if (stream.markSupported())
      stream.reset();
    return test == ZIP_VERIFICATION_CODE;
  }

  /**
   * @param file aa
   * @return aa
   * @throws IOException aa
   */
  public static boolean isZipFile(File file) throws IOException {
    try (FileInputStream stream = new FileInputStream(file)) {
      return isZipFile(stream);
    }
  }

  /**
   * @param file aa
   * @return aa
   * @throws ParserConfigurationException aa
   */
  public static boolean isXMLFile(File file) throws ParserConfigurationException {
    DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    try {
      builder.parse(file);
    } catch (Exception e) {
      return false;
    }
    return true;
  }

  /**
   * @param file file to be deleted
   * @throws IOException if an IO Exception occurs
   */
  public static void deleteFile(String file) throws IOException {
    deleteIfExists(Paths.get(file));
  }

  /**
   * Get the signature from a file.
   *
   * @param file  file containing the container
   * @param index index of the signature file
   * @return signature
   * @throws IOException when the signature is not found
   */
  public static String extractSignature(String file, int index) throws IOException {
    try (ZipFile zipFile = new ZipFile(file)) {
      String signatureFileName = "META-INF/signatures" + index + ".xml";
      ZipEntry entry = zipFile.getEntry(signatureFileName);

      if (entry == null)
        throw new IOException(signatureFileName + " does not exists in archive: " + file);

      try (InputStream inputStream = zipFile.getInputStream(entry)) {
        return IOUtils.toString(inputStream, StandardCharsets.UTF_8);
      }
    }
  }

  /**
   * Serialize object. NB! Use only for temporal storage. May not be compatible between different product releases
   *
   * @param object object to be serialized
   * @param file   file to store serialized object in
   */
  public static  void serialize(T object, File file) {
    try (
        FileOutputStream fileOut = new FileOutputStream(file);
        ObjectOutputStream out = new ObjectOutputStream(fileOut);
    ) {
      out.writeObject(object);
      out.flush();
    } catch (Exception e) {
      throw new DigiDoc4JException(e);
    }
  }

  /**
   * Serialize object. NB! Use only for temporal storage. May not be compatible between different product releases
   *
   * @param object   object to be serialized
   * @param filename name of file to store serialized object in
   */
  public static  void serialize(T object, String filename) {
    Helper.serialize(object, new File(filename));
  }

  /**
   * Deserialize a previously serialized container. NB! Use only for temporal storage. May not be compatible between
   * different product releases
   *
   * @param file file containing the serialized container
   * @return container
   */
  @SuppressWarnings("unchecked")
  public static  T deserializer(File file) {
    try (
        FileInputStream fileIn = new FileInputStream(file);
        ObjectInputStream in = new ObjectInputStream(fileIn);
    ) {
      return (T) in.readObject();
    } catch (Exception e) {
      throw new DigiDoc4JException(e);
    }
  }

  /**
   * Deserialize a previously serialized container. NB! Use only for temporal storage. May not be compatible between
   * different product releases
   *
   * @param filename name of the file containing the serialized container
   * @return container
   */
  public static  T deserializer(String filename) {
    return Helper.deserializer(new File(filename));
  }

  /**
   * Creates a buffered output stream for a given file.
   *
   * @param file target file.
   * @return stream
   */
  public static OutputStream bufferedOutputStream(File file) {
    try {
      return new BufferedOutputStream(new FileOutputStream(file));
    } catch (FileNotFoundException e) {
      throw new DigiDoc4JException(e);
    }
  }

  /**
   * Loads X509Certificate from the specified location
   * /**
   *
   * @param filePath file location
   * @return X509Certificate
   */
  public static X509Certificate loadCertificate(String filePath) {
    try {
      CertificateFactory factory = CertificateFactory.getInstance("X.509");
      try (FileInputStream is = new FileInputStream(filePath)) {
        return (X509Certificate) factory.generateCertificate(is);
      }
    } catch (Exception e) {
      throw new RuntimeException(String.format("Unable to load certificate from <%s>", filePath), e);
    }
  }

  /**
   * Checks that file name contains special characters
   *
   * @param fileName file name to check
   * @return true if file name contains following symbols: <>:"/\|?*
   */
  public static boolean hasSpecialCharacters(String fileName) {
    Pattern special = Pattern.compile(SPECIAL_CHARACTERS);
    Matcher hasSpecial = special.matcher(fileName);
    return hasSpecial.find();
  }

  public static String getIdentifier(String identifier) {
    String id = identifier.trim();
    if (DSSUtils.isUrnOid(id)) {
      return DSSUtils.getOidCode(id);
    }
    return id;
  }

  public static SignaturePolicyProvider getBdocSignaturePolicyProvider(DSSDocument signature) {
    SignaturePolicyProvider signaturePolicyProvider = new SignaturePolicyProvider();
    Map signaturePoliciesById = new HashMap<>();
    signaturePoliciesById.put(TmSignaturePolicyType.BDOC_2_1_0.getOid(), signature);

    Map signaturePoliciesByUrl = new HashMap<>();
    signaturePoliciesByUrl.put("https://www.sk.ee/repository/bdoc-spec21.pdf", signature);

    signaturePolicyProvider.setSignaturePoliciesById(signaturePoliciesById);
    signaturePolicyProvider.setSignaturePoliciesByUrl(signaturePoliciesByUrl);
    return signaturePolicyProvider;
  }

  /**
   * gets all datafiles as List from Container
   *
   * @param container as Container object
   */
  public static List getAllFilesFromContainerAsBytes(Container container) {
    List files = new ArrayList<>();
    for (DataFile dataFile : container.getDataFiles()) {
      files.add(dataFile.getBytes());
    }
    return files;
  }

  /**
   * gets all datafiles as List from Container path
   *
   * @param pathFrom as String
   */
  public static List getAllFilesFromContainerPathAsBytes(String pathFrom) {
    Container container = ContainerBuilder.
        aContainer().
        fromExistingFile(pathFrom).
        build();

    return getAllFilesFromContainerAsBytes(container);
  }

  /**
   * Saves all datafiles to specified folder
   *
   * @param container as Container object
   * @param path      as String
   */
  public static void saveAllFilesFromContainerToFolder(Container container, String path) {
    for (DataFile dataFile : container.getDataFiles()) {
      dataFile.saveAs(path + File.separator + dataFile.getName());
    }
  }

  /**
   * Saves all datafiles to specified folder
   *
   * @param pathFrom as String
   * @param pathTo   as String
   */
  public static void saveAllFilesFromContainerPathToFolder(String pathFrom, String pathTo) {
    Container container = ContainerBuilder.
        aContainer().
        fromExistingFile(pathFrom).
        build();

    saveAllFilesFromContainerToFolder(container, pathTo);
  }

  /**
   * delete tmp files from temp folder created by StreamDocument
   */
  public static void deleteTmpFiles(long allowedAge) {
    File dir = new File(System.getProperty("java.io.tmpdir"));
    FilenameFilter filenameFilter = (dir1, name) -> name.toLowerCase().startsWith("digidoc4j")
        && name.toLowerCase().endsWith(".tmp");
    for (File f : dir.listFiles(filenameFilter)) {
      if (System.currentTimeMillis() - f.lastModified() < allowedAge) {
        continue;
      }
      if (!f.delete()) {
        f.deleteOnExit();
      }
    }
  }

  /**
   * Checks that it's pades container
   *
   * @param file path
   * @return true in case of pades container
   */
  public static boolean isPdfFile(String file) {
    return FilenameUtils.getExtension(file).equals("pdf");
  }

  /**
   * Method for converting bytes to hex string.
   *
   * @param bytes  Given byte array.
   * @param maxLen Max length of result string.
   * @return String of hex characters.
   */
  public static String bytesToHex(byte[] bytes, int maxLen) {
    char[] hexChars = new char[min(bytes.length, maxLen) * 2];
    for (int j = 0; j < min(bytes.length, maxLen); j++) {
      int v = bytes[j] & 0xFF;
      hexChars[j * 2] = hexArray[v >>> 4];
      hexChars[j * 2 + 1] = hexArray[v & 0x0F];
    }
    return new String(hexChars);
  }

  public static void printWarningSection(Logger logger, String warningMessage) {
    logger.warn(StringUtils.rightPad("-", warningMessage.length(), "-"));
    logger.warn(warningMessage);
    logger.warn(StringUtils.rightPad("-", warningMessage.length(), "-"));
  }

  public static void printErrorSection(Logger logger, String errorMessage) {
    logger.error(StringUtils.rightPad("-", errorMessage.length(), "-"));
    logger.error(errorMessage);
    logger.error(StringUtils.rightPad("-", errorMessage.length(), "-"));
  }

  /*
   * RESTRICTED METHODS
   */

  private static File[] getFilesFromJar(URL jarUrl, FileFilter filter) {
    try {
      String[] fragments = jarUrl.getPath().split("!", 2);
      if (fragments[1].startsWith("/")) {
        fragments[1] = fragments[1].substring(1);
      }
      File file = new File(new URL(fragments[0]).toURI());
      File outputFolder = Paths.get(System.getProperty("java.io.tmpdir"), file.getName(), fragments[1]).toFile();
      if (!outputFolder.exists()) {
        if (outputFolder.mkdirs()) {
          List entries = new ArrayList<>();
          try (ZipFile zipFile = new ZipFile(file)) {
            Enumeration e = zipFile.entries();
            while (e.hasMoreElements()) {
              ZipEntry entry = e.nextElement();
              if (entry.getName().startsWith(fragments[1]) && !entry.isDirectory()) {
                entries.add(entry);
              }
            }
            for (ZipEntry entry : entries) {
              try (InputStream inputStream = zipFile.getInputStream(entry); OutputStream outputStream = new
                  FileOutputStream(Paths.get(outputFolder.getPath(), new File(entry.getName()).getName()).toFile())) {
                IOUtils.copy(inputStream, outputStream);
              }
            }
          }
        } else {
          throw new RuntimeException(String.format("Unable to create output folder <%s>", outputFolder));
        }
      }
      return outputFolder.listFiles(filter);
    } catch (Exception e) {
      logger.error(String.format("Unable to read files from <%s>", jarUrl), e);
    }
    return new File[]{};
  }

  public static class FileExtensionFilter implements FileFilter {

    private final FileNameExtensionFilter filter;

    /**
     * @param extensions extensions
     */
    public FileExtensionFilter(String... extensions) {
      if (ArrayUtils.isEmpty(extensions)) {
        throw new IllegalArgumentException("File extensions can't be unset");
      }
      this.filter = new FileNameExtensionFilter("Missing", extensions);
    }

    @Override
    public boolean accept(File file) {
      return this.filter.accept(file);
    }

  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy