feat: scripts
This commit is contained in:
140
scripts/signpdf.js
Normal file
140
scripts/signpdf.js
Normal file
@@ -0,0 +1,140 @@
|
||||
#! /usr/bin/env runjs
|
||||
|
||||
requireJAR('bcpkix-jdk15on-154.jar');
|
||||
requireJAR('bcprov-jdk15on-154.jar');
|
||||
requireJAR('bcprov-ext-jdk15on-154.jar');
|
||||
requireJAR('itextpdf-5.5.11.jar');
|
||||
|
||||
var JavaArray = java.lang.reflect.Array;
|
||||
var Security = java.security.Security;
|
||||
var StringReader = java.io.StringReader;
|
||||
var BufferedReader = java.io.BufferedReader;
|
||||
var FileOutputStream = java.io.FileOutputStream;
|
||||
var X509Certificate = java.security.cert.X509Certificate;
|
||||
var Rectangle = Packages.com.itextpdf.text.Rectangle;
|
||||
var PdfName = Packages.com.itextpdf.text.pdf.PdfName;
|
||||
var PdfReader = Packages.com.itextpdf.text.pdf.PdfReader;
|
||||
var PdfStamper = Packages.com.itextpdf.text.pdf.PdfStamper;
|
||||
var PdfPKCS7 = Packages.com.itextpdf.text.pdf.security.PdfPKCS7;
|
||||
var MakeSignature = Packages.com.itextpdf.text.pdf.security.MakeSignature;
|
||||
var DigestAlgorithms = Packages.com.itextpdf.text.pdf.security.DigestAlgorithms;
|
||||
var BouncyCastleDigest = Packages.com.itextpdf.text.pdf.security.BouncyCastleDigest;
|
||||
var PrivateKeySignature = Packages.com.itextpdf.text.pdf.security.PrivateKeySignature;
|
||||
var CryptoStandard = Packages.com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard;
|
||||
var ExternalSignatureContainer = Packages.com.itextpdf.text.pdf.security.ExternalSignatureContainer;
|
||||
var ExternalBlankSignatureContainer = Packages.com.itextpdf.text.pdf.security.ExternalBlankSignatureContainer;
|
||||
var BouncyCastleProvider = Packages.org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
var PrivateKeyParseTool = Packages.me.hatter.tools.commons.security.rsa.PrivateKeyParseTool;
|
||||
var X509CertUtil = Packages.me.hatter.tools.commons.security.cert.X509CertUtil;
|
||||
|
||||
var emptySignature = (src, dest, fieldname, chain, reason, location) => {
|
||||
var reader = new PdfReader(src);
|
||||
var os = new FileOutputStream(dest);
|
||||
var stamper = PdfStamper.createSignature(reader, os, '\0');
|
||||
var appearance = stamper.getSignatureAppearance();
|
||||
appearance.setVisibleSignature(new Rectangle(20, 748, 180, 780), 1, fieldname);
|
||||
appearance.setCertificate(chain[0]);
|
||||
if (reason) {
|
||||
appearance.setReason(reason);
|
||||
}
|
||||
if (location) {
|
||||
appearance.setLocation(location);
|
||||
}
|
||||
var external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
|
||||
MakeSignature.signExternalContainer(appearance, external, 8192);
|
||||
};
|
||||
|
||||
var createSignature = (src, dest, fieldname, pk, chain) => {
|
||||
var reader = new PdfReader(src);
|
||||
var os = new FileOutputStream(dest);
|
||||
var external = new ExternalSignatureContainer({
|
||||
'sign': (is) => {
|
||||
var signature = new PrivateKeySignature(pk, "SHA256", "BC");
|
||||
var hashAlgorithm = signature.getHashAlgorithm();
|
||||
var digest = new BouncyCastleDigest();
|
||||
var sgn = new PdfPKCS7(null, chain, hashAlgorithm, null, digest, false);
|
||||
var hash = DigestAlgorithms.digest(is, digest.getMessageDigest(hashAlgorithm));
|
||||
var sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS);
|
||||
var extSignature = signature.sign(sh);
|
||||
sgn.setExternalDigest(extSignature, null, signature.getEncryptionAlgorithm());
|
||||
return sgn.getEncodedPKCS7(hash, null, null, null, CryptoStandard.CMS);
|
||||
},
|
||||
'modifySigningDictionary': (signDic) => {
|
||||
// DO NOTHING
|
||||
}
|
||||
});
|
||||
MakeSignature.signDeferred(reader, fieldname, os, external);
|
||||
};
|
||||
|
||||
var printConfigFileFormat = () => {
|
||||
println('Format:');
|
||||
println('{');
|
||||
println(' "certs": "<PATH>/certs.pem",');
|
||||
println(' "privKey": "<PATH>/privKey.pem.gpg"');
|
||||
println('}');
|
||||
};
|
||||
|
||||
var main = () => {
|
||||
if ($ARGS == null || $ARGS.length == 0) {
|
||||
println('signpdf.js - Sign PDF.')
|
||||
println();
|
||||
println('ERROR: NO arguments assigned!');
|
||||
println('signpdf.js <file.pdf> [reason [location]]');
|
||||
return;
|
||||
}
|
||||
var reason = ($ARGS.length > 1)? $ARGS[1]: null;
|
||||
var location = ($ARGS.length > 2)? $ARGS[2]: null;
|
||||
var pdf = $$.file($ARGS[0]);
|
||||
if (!pdf.exists()) {
|
||||
println('File not exists: ' + pdf);
|
||||
return;
|
||||
}
|
||||
if (!pdf.getName().toLowerCase().endsWith('.pdf')) {
|
||||
println('File is not PDF: ' + pdf);
|
||||
return;
|
||||
}
|
||||
var configFile = $$.file($$.prop('user.home'), '.signpdf.js.json');
|
||||
if (!configFile.exists()) {
|
||||
println('SignPDF.js config file not found: ' + configFile);
|
||||
printConfigFileFormat();
|
||||
return;
|
||||
}
|
||||
var configObject = JSON.parse($$.rFile(configFile).rReader().stringAndClose());
|
||||
if (!configObject.privKey || !configObject.certs) {
|
||||
println('Config file error: ' + configFile);
|
||||
printConfigFileFormat();
|
||||
return;
|
||||
}
|
||||
if ($$.file($ARGS[0].replace('.pdf', '-signed.pdf')).exists()) {
|
||||
println('Target file exists: ' + $ARGS[0].replace('.pdf', '-signed.pdf'));
|
||||
return;
|
||||
}
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
|
||||
var result = $$.shell().commands('sh', '-c', 'cat ' + configObject.privKey + ' | gpg').start();
|
||||
var out = result[0].rStream().rReader().stringAndClose();
|
||||
var err = result[1].rStream().rReader().stringAndClose();
|
||||
if (err.contains('public key decryption failed')) {
|
||||
println('+ Decrypt file FAILED: ' + configObject.privKey);
|
||||
if (!Packages.me.hatter.tools.jssp.main.StandaloneMain.JSSP_MAIN_MUTE) {
|
||||
println("ERROR detail:\n" + err);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var privateKeyParseTool = new PrivateKeyParseTool(new BufferedReader(new StringReader(out)));
|
||||
var certList = X509CertUtil.parseX509CertificateList($$.rFile(configObject.certs).rStream().bytesAndClose());
|
||||
|
||||
var chain = certList.toArray(JavaArray.newInstance(certList.get(0).getClass(), certList.size()));
|
||||
var pk = privateKeyParseTool.read();
|
||||
var temp = '~' + $$.date().millis() + '.pdf';
|
||||
try {
|
||||
emptySignature(pdf, temp, "sig", chain, reason, location);
|
||||
createSignature(temp, $ARGS[0].replace('.pdf', '-signed.pdf'), "sig", pk, chain);
|
||||
} finally {
|
||||
$$.file(temp).delete();
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
|
||||
Reference in New Issue
Block a user