feat: scripts

This commit is contained in:
2025-04-05 16:57:26 +08:00
parent bd4fe63cdc
commit 3e996ffab3
62 changed files with 4905 additions and 0 deletions

140
scripts/signpdf.js Normal file
View 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();