
org.structr.function.CreateJarFileFunction Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of structr-ui Show documentation
Show all versions of structr-ui Show documentation
Structr is an open source framework based on the popular Neo4j graph database.
The newest version!
/**
* Copyright (C) 2010-2016 Structr GmbH
*
* This file is part of Structr .
*
* Structr is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Structr is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Structr. If not, see .
*/
package org.structr.function;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.math.BigInteger;
import java.security.DigestOutputStream;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.logging.Level;
import javax.security.auth.x500.X500Principal;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.DEROutputStream;
import org.bouncycastle.cert.jcajce.JcaCertStore;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.CMSTypedData;
import org.bouncycastle.cms.SignerInfoGenerator;
import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.x509.X509V3CertificateGenerator;
import org.structr.common.error.FrameworkException;
import org.structr.core.GraphObject;
import org.structr.schema.action.ActionContext;
/**
*
*/
public class CreateJarFileFunction extends UiFunction {
@Override
public String getName() {
return "create_jar_file";
}
@Override
public Object apply(final ActionContext ctx, final GraphObject entity, final Object[] sources) throws FrameworkException {
if (arrayHasMinLengthAndAllElementsNotNull(sources, 2)) {
if (sources[0] instanceof OutputStream) {
try {
final String algorithm = "SHA1";
final String signAlgorithm = "SHA1withRSA";
final String keygenAlgorithm = "RSA";
final String srngAlgorithm = "SHA1PRNG";
final JarOutputStream jos = new JarOutputStream((OutputStream)sources[0]);
final MessageDigest md = MessageDigest.getInstance(algorithm);
final Manifest manifest = new Manifest();
final Attributes mainAttributes = manifest.getMainAttributes();
final PrivateKey privateKey = getOrCreatePrivateKey(keygenAlgorithm, srngAlgorithm, signAlgorithm);
final X509Certificate cert = getOrCreateCertificate(keygenAlgorithm, srngAlgorithm, signAlgorithm);
System.out.println("This is the fingerprint of the keystore: " + hex(cert));
// if (false) {
//
// // this code loads an existing keystore
// final String keystorePath = StructrApp.getConfigurationValue("application.keystore.path", null);
// final String keystorePassword = StructrApp.getConfigurationValue("application.keystore.password", null);
//
// X509Certificate cert = null;
// PrivateKey privateKey = null;
//
// if (StringUtils.isNoneBlank(keystorePath, keystorePassword)) {
//
// try (final FileInputStream fis = new FileInputStream(keystorePath)) {
//
// final KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
//
// keystore.load(fis, keystorePassword.toCharArray());
//
// for (final Enumeration aliases = keystore.aliases(); aliases.hasMoreElements();) {
//
// final String alias = aliases.nextElement();
//
// if (keystore.isCertificateEntry(alias)) {
//
// System.out.println("Using certificate entry " + alias);
// cert = (X509Certificate)keystore.getCertificate(alias);
//
// } else if (keystore.isKeyEntry(alias)) {
//
// System.out.println("Using private key entry " + alias);
// privateKey = (PrivateKey)keystore.getKey(alias, keystorePassword.toCharArray());
//
// }
// }
//
//
// } catch (Throwable t) {
//
// logger.log(Level.WARNING, "", t);
// }
// }
// }
// maximum compression
jos.setLevel(9);
// initialize manifest
mainAttributes.put(Attributes.Name.MANIFEST_VERSION, "1.0");
// add entries from scripting context
for (final Object source : sources) {
if (source != null && source instanceof NameAndContent) {
final NameAndContent content = (NameAndContent)source;
final JarEntry entry = new JarEntry(content.getName());
final byte[] data = content.getContent().getBytes("utf-8");
entry.setTime(System.currentTimeMillis());
// write JarEntry
jos.putNextEntry(entry);
jos.write(data);
jos.closeEntry();
jos.flush();
// update message digest with data
md.update(data);
// create new attribute with the entry's name
Attributes attr = manifest.getAttributes(entry.getName());
if (attr == null) {
attr = new Attributes();
manifest.getEntries().put(entry.getName(), attr);
}
// store SHA1-Digest for the new entry
attr.putValue(algorithm + "-Digest", new String(Base64.encode(md.digest()), "ASCII"));
}
}
// add manifest entry
jos.putNextEntry(new JarEntry(JarFile.MANIFEST_NAME));
manifest.write(jos);
// add signature entry
final byte[] signedData = getSignatureForManifest(manifest, algorithm);
jos.putNextEntry(new JarEntry("META-INF/CERT.SF"));
jos.write(signedData);
if (privateKey != null && cert != null) {
// add certificate entry
jos.putNextEntry(new JarEntry("META-INF/CERT." + privateKey.getAlgorithm()));
writeSignatureBlock(jos, algorithm, new CMSProcessableByteArray(signedData), cert, privateKey);
} else {
System.out.println("No certificate / key found, signinig disabled.");
}
// use finish() here to avoid an "already closed" exception later
jos.flush();
jos.finish();
} catch (Throwable t) {
logException(entity, t, sources);
}
} else {
logger.log(Level.WARNING, "First parameter of create_jar_file() must be an output stream. Parameters: {0}", getParametersAsString(sources));
return "First parameter of create_jar_file() must be an output stream.";
}
} else {
logParameterError(entity, sources, ctx.isJavaScriptContext());
}
return "";
}
@Override
public String usage(boolean inJavaScriptContext) {
return "create_jar_file()";
}
@Override
public String shortDescription() {
return "Creates a signed JAR file from the given contents.";
}
// ----- private methods -----
private byte[] getSignatureForManifest(final Manifest forManifest, final String algorithm) throws IOException, GeneralSecurityException {
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
final Manifest signatureFile = new Manifest();
final Attributes main = signatureFile.getMainAttributes();
final MessageDigest md = MessageDigest.getInstance(algorithm);
final PrintStream print = new PrintStream(new DigestOutputStream(new ByteArrayOutputStream(), md), true, "UTF-8");
main.putValue("Signature-Version", "1.0");
forManifest.write(print);
print.flush();
main.putValue(algorithm + "-Digest-Manifest", new String(Base64.encode(md.digest()), "ASCII"));
final Map entries = forManifest.getEntries();
for (Map.Entry entry : entries.entrySet()) {
// Digest of the manifest stanza for this entry.
print.print("Name: " + entry.getKey() + "\r\n");
for (Map.Entry
© 2015 - 2025 Weber Informatics LLC | Privacy Policy