DTMBundleDownloadProcess.java 15.8 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.adobe.granite.crypto.CryptoException
 *  com.adobe.granite.crypto.CryptoSupport
 *  com.day.cq.workflow.WorkflowException
 *  com.day.cq.workflow.WorkflowSession
 *  com.day.cq.workflow.exec.Route
 *  com.day.cq.workflow.exec.WorkItem
 *  com.day.cq.workflow.exec.WorkflowData
 *  com.day.cq.workflow.exec.WorkflowProcess
 *  com.day.cq.workflow.metadata.MetaDataMap
 *  javax.jcr.Node
 *  javax.jcr.NodeIterator
 *  javax.jcr.Property
 *  javax.jcr.RepositoryException
 *  javax.jcr.Session
 *  javax.jcr.Value
 *  javax.jcr.nodetype.NodeType
 *  org.apache.commons.io.IOUtils
 *  org.apache.felix.scr.annotations.Component
 *  org.apache.felix.scr.annotations.Property
 *  org.apache.felix.scr.annotations.Reference
 *  org.apache.felix.scr.annotations.Service
 *  org.apache.http.HttpEntity
 *  org.apache.http.client.methods.CloseableHttpResponse
 *  org.apache.http.client.methods.HttpGet
 *  org.apache.http.client.methods.HttpUriRequest
 *  org.apache.http.impl.client.CloseableHttpClient
 *  org.apache.http.impl.client.HttpClientBuilder
 *  org.apache.http.osgi.services.HttpClientBuilderFactory
 *  org.apache.jackrabbit.commons.JcrUtils
 *  org.apache.sling.commons.mime.MimeTypeService
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.adobe.cq.dtm.impl.process;

import com.adobe.cq.dtm.impl.handler.openssl.OpenSSLWrapper;
import com.adobe.granite.crypto.CryptoException;
import com.adobe.granite.crypto.CryptoSupport;
import com.day.cq.workflow.WorkflowException;
import com.day.cq.workflow.WorkflowSession;
import com.day.cq.workflow.exec.Route;
import com.day.cq.workflow.exec.WorkItem;
import com.day.cq.workflow.exec.WorkflowData;
import com.day.cq.workflow.exec.WorkflowProcess;
import com.day.cq.workflow.metadata.MetaDataMap;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
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.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.nodetype.NodeType;
import org.apache.commons.io.IOUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.osgi.services.HttpClientBuilderFactory;
import org.apache.jackrabbit.commons.JcrUtils;
import org.apache.sling.commons.mime.MimeTypeService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component
@Service
@org.apache.felix.scr.annotations.Property(name="process.label", value={"DTM Bundle Download"})
public class DTMBundleDownloadProcess
implements WorkflowProcess {
    private static final Logger LOG = LoggerFactory.getLogger(DTMBundleDownloadProcess.class);
    public static final String DEFAULT_MIME_TYPE = "application/octet-stream";
    public static final String SATELLITE_LIB = "satelliteLib";
    @Reference
    private MimeTypeService mimeTypeService = null;
    @Reference
    private CryptoSupport cryptoSupport = null;
    @Reference
    private HttpClientBuilderFactory clientBuilderFactory = null;
    private byte[] buffer = new byte[1024];

    public void execute(WorkItem workItem, WorkflowSession workflowSession, MetaDataMap metaDataMap) throws WorkflowException {
        WorkflowData workflowData = workItem.getWorkflowData();
        if ("JCR_PATH".equals(workflowData.getPayloadType())) {
            String dtmServerType = (String)workflowData.getMetaDataMap().get("dtmServerType", String.class);
            String dtmConfigPath = workflowData.getPayload().toString();
            try {
                Node dtmConfig;
                String bundleUrlPropName;
                Session jcrSession = workflowSession.getSession();
                if (jcrSession.nodeExists(dtmConfigPath) && (dtmConfig = jcrSession.getNode(dtmConfigPath)).hasProperty(bundleUrlPropName = dtmServerType + "BundleURL")) {
                    Property bundleURLProperty = dtmConfig.getProperty(bundleUrlPropName);
                    String bundleURL = bundleURLProperty.getString();
                    Node unzipTarget = this.getOrCreateUnzipTargetNode(dtmConfig, dtmServerType);
                    String sharedSecretPropName = dtmServerType + "SharedSecret";
                    String sharedSecret = dtmConfig.hasProperty(sharedSecretPropName) ? this.cryptoSupport.unprotect(dtmConfig.getProperty(sharedSecretPropName).getString()) : null;
                    String dtmEntriesPropName = dtmServerType + "Entries";
                    if (dtmConfig.hasProperty(dtmEntriesPropName)) {
                        Property prevEntries = dtmConfig.getProperty(dtmEntriesPropName);
                        dtmConfig.setProperty(dtmServerType + "EntriesPrev", prevEntries.getValues());
                    }
                    List<String> entries = this.downloadAndStoreDTMBundle(bundleURL, unzipTarget, sharedSecret, dtmConfig);
                    dtmConfig.setProperty(dtmEntriesPropName, entries.toArray(new String[0]));
                    dtmConfig.setProperty(dtmServerType + "DTMLibsPath", unzipTarget.getPath());
                    String dtmMainScriptPath = this.getDTMMainScriptPath(unzipTarget);
                    if (dtmMainScriptPath != null) {
                        dtmConfig.setProperty(dtmServerType + "DTMMainScriptPath", dtmMainScriptPath);
                    }
                    if (jcrSession.hasPendingChanges()) {
                        jcrSession.save();
                    }
                    List routes = workflowSession.getRoutes(workItem);
                    workflowSession.complete(workItem, (Route)routes.get(0));
                }
            }
            catch (RepositoryException e) {
                throw new WorkflowException((Throwable)e);
            }
            catch (IOException e) {
                throw new WorkflowException((Throwable)e);
            }
            catch (CryptoException e) {
                throw new WorkflowException((Throwable)e);
            }
        }
    }

    private String getDTMMainScriptPath(Node unzipTarget) throws RepositoryException {
        Node childNode;
        String dtmMainScriptPath = null;
        Node dtmMainScriptFolder = null;
        NodeIterator childNodeIt = unzipTarget.getNodes();
        while (childNodeIt.hasNext()) {
            childNode = childNodeIt.nextNode();
            if (!childNode.getPrimaryNodeType().isNodeType("nt:folder")) continue;
            dtmMainScriptFolder = childNode;
            break;
        }
        if (dtmMainScriptFolder != null) {
            childNodeIt = dtmMainScriptFolder.getNodes();
            while (childNodeIt.hasNext()) {
                childNode = childNodeIt.nextNode();
                if (!childNode.getName().startsWith("satelliteLib") || !childNode.getPrimaryNodeType().isNodeType("nt:file")) continue;
                dtmMainScriptPath = childNode.getPath();
            }
        }
        return dtmMainScriptPath;
    }

    private Node getOrCreateUnzipTargetNode(Node dtmConfig, String dtmServerType) throws RepositoryException {
        Node unzipTarget = null;
        String dtmConfigName = dtmConfig.getParent().getName();
        if (dtmConfig.hasProperty("company") && dtmConfig.hasProperty("property")) {
            Property companyProperty = dtmConfig.getProperty("company");
            Property dtmPropertyProperty = dtmConfig.getProperty("property");
            unzipTarget = JcrUtils.getOrCreateByPath((String)("/etc/clientlibs/dtm/" + dtmConfigName + "/" + companyProperty.getString() + "/" + dtmPropertyProperty.getString()), (String)"nt:folder", (Session)dtmConfig.getSession());
            if (dtmConfig.hasProperty(dtmServerType + "Entries")) {
                Property entries = dtmConfig.getProperty(dtmServerType + "Entries");
                if (entries.isMultiple()) {
                    for (Value v : entries.getValues()) {
                        if (!unzipTarget.hasNode(v.getString())) continue;
                        unzipTarget.getNode(v.getString()).remove();
                    }
                } else if (unzipTarget.getSession().nodeExists(unzipTarget.getPath() + "/" + entries.getString())) {
                    unzipTarget.getNode(entries.getString()).remove();
                }
            }
        }
        return unzipTarget;
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    private List<String> downloadAndStoreDTMBundle(String urlString, Node unzipTarget, String passPhrase, Node dtmConfig) throws IOException, RepositoryException, WorkflowException {
        if (urlString.endsWith("enc") && passPhrase == null) {
            throw new WorkflowException("Unable to store DTM bundle because it is encrypted and the pass phrase is missing.");
        }
        InputStream urlIS = null;
        ZipInputStream zipIS = null;
        File tmpDecryptedZipFile = null;
        CloseableHttpClient httpclient = this.clientBuilderFactory.newBuilder().build();
        ArrayList<String> entries = new ArrayList();
        try {
            HttpGet httpget = new HttpGet(urlString);
            CloseableHttpResponse response = httpclient.execute((HttpUriRequest)httpget);
            InputStream input = urlIS = response.getEntity().getContent();
            if (passPhrase != null) {
                tmpDecryptedZipFile = this.decryptUrlInput(urlIS, passPhrase);
                input = new FileInputStream(tmpDecryptedZipFile);
            }
            zipIS = new ZipInputStream(input);
            entries = this.extractAndStoreZip(zipIS, unzipTarget, dtmConfig);
        }
        finally {
            if (urlIS != null) {
                urlIS.close();
            }
            if (zipIS != null) {
                zipIS.close();
            }
            if (tmpDecryptedZipFile != null && !tmpDecryptedZipFile.delete()) {
                LOG.warn("Could not delete temporary decrypted zip file: ", (Object)tmpDecryptedZipFile.getAbsolutePath());
            }
            if (httpclient != null) {
                httpclient.close();
            }
        }
        return entries;
    }

    private File decryptUrlInput(InputStream urlIS, String passPhrase) throws IOException {
        File decryptedDtmBundle = null;
        File encryptedDtmBundle = this.downloadEncryptedDtmBundle(urlIS);
        if (encryptedDtmBundle != null) {
            decryptedDtmBundle = this.decryptDtmBundle(encryptedDtmBundle, passPhrase);
        }
        return decryptedDtmBundle;
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    private File decryptDtmBundle(File encryptedDtmBundle, String passPhrase) {
        File decryptedDtmBundle;
        decryptedDtmBundle = null;
        try {
            decryptedDtmBundle = File.createTempFile("satelliteLib", null);
            OpenSSLWrapper openSSLWrapper = new OpenSSLWrapper(OpenSSLWrapper.OpenSSLCypher.AES_256_CBC, encryptedDtmBundle, decryptedDtmBundle);
            openSSLWrapper.setPassPhrase(passPhrase);
            if (!openSSLWrapper.decryptFile()) {
                throw new IOException("openssl command execution failed.");
            }
        }
        catch (IOException e) {
            LOG.error("Unable to decrypt DTM encrypted zip file.", (Throwable)e);
            if (decryptedDtmBundle != null) {
                if (!decryptedDtmBundle.delete()) {
                    LOG.warn("Unable to delete temporary file: " + decryptedDtmBundle.getAbsolutePath());
                }
                decryptedDtmBundle = null;
            }
        }
        finally {
            if (!encryptedDtmBundle.delete()) {
                LOG.warn("Unable to delete temporary file: " + encryptedDtmBundle.getAbsolutePath());
            }
        }
        return decryptedDtmBundle;
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    private File downloadEncryptedDtmBundle(InputStream urlIS) {
        File encryptedDtmBundle = null;
        FileOutputStream encryptedDTMBundleOS = null;
        try {
            encryptedDtmBundle = File.createTempFile("encryptedDtmBundle", null);
            encryptedDTMBundleOS = new FileOutputStream(encryptedDtmBundle);
            IOUtils.copy((InputStream)urlIS, (OutputStream)encryptedDTMBundleOS);
        }
        catch (IOException e) {
            LOG.error("Unable to download and save encrypted DTM bundle.", (Throwable)e);
        }
        finally {
            if (encryptedDTMBundleOS != null) {
                IOUtils.closeQuietly((OutputStream)encryptedDTMBundleOS);
            }
        }
        return encryptedDtmBundle;
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    private List<String> extractAndStoreZip(ZipInputStream zipIS, Node unzipTarget, Node dtmConfig) throws IOException, RepositoryException {
        ArrayList<String> entries;
        entries = new ArrayList<String>();
        ByteArrayOutputStream byteOS = null;
        try {
            ZipEntry zipEntry = zipIS.getNextEntry();
            while (zipEntry != null) {
                String entryName = zipEntry.getName();
                if (zipEntry.isDirectory()) {
                    JcrUtils.getOrAddFolder((Node)unzipTarget, (String)entryName);
                } else {
                    int length;
                    byteOS = new ByteArrayOutputStream();
                    while ((length = zipIS.read(this.buffer)) > 0) {
                        byteOS.write(this.buffer, 0, length);
                    }
                    byteOS.flush();
                    String entryMimeType = this.mimeTypeService.getMimeType(entryName);
                    if (entryMimeType == null) {
                        entryMimeType = "application/octet-stream";
                    }
                    JcrUtils.getOrCreateByPath((Node)unzipTarget, (String)entryName, (boolean)false, (String)"nt:folder", (String)"nt:file", (boolean)false);
                    JcrUtils.putFile((Node)unzipTarget, (String)entryName, (String)entryMimeType, (InputStream)new ByteArrayInputStream(byteOS.toByteArray()));
                    entries.add(entryName);
                }
                zipEntry = zipIS.getNextEntry();
            }
        }
        finally {
            if (byteOS != null) {
                byteOS.close();
            }
        }
        return entries;
    }

    protected void bindMimeTypeService(MimeTypeService mimeTypeService) {
        this.mimeTypeService = mimeTypeService;
    }

    protected void unbindMimeTypeService(MimeTypeService mimeTypeService) {
        if (this.mimeTypeService == mimeTypeService) {
            this.mimeTypeService = null;
        }
    }

    protected void bindCryptoSupport(CryptoSupport cryptoSupport) {
        this.cryptoSupport = cryptoSupport;
    }

    protected void unbindCryptoSupport(CryptoSupport cryptoSupport) {
        if (this.cryptoSupport == cryptoSupport) {
            this.cryptoSupport = null;
        }
    }

    protected void bindClientBuilderFactory(HttpClientBuilderFactory httpClientBuilderFactory) {
        this.clientBuilderFactory = httpClientBuilderFactory;
    }

    protected void unbindClientBuilderFactory(HttpClientBuilderFactory httpClientBuilderFactory) {
        if (this.clientBuilderFactory == httpClientBuilderFactory) {
            this.clientBuilderFactory = null;
        }
    }
}