parent
e1ed49d43f
commit
1f92ca61d7
|
@ -88,9 +88,18 @@ pdfkit.loadZga(globalThis);
|
|||
```
|
||||
npm install zgapdfsigner
|
||||
```
|
||||
If using [typescript](https://www.typescriptlang.org/) for development, installation of [definitely typed for node-forge](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node-forge) is necessary.
|
||||
```
|
||||
npm install --save-dev @types/node-forge
|
||||
```
|
||||
2. Import
|
||||
```js
|
||||
// CommonJS Mode
|
||||
const Zga = require("zgapdfsigner");
|
||||
// ES Module Mode
|
||||
import { default as Zga } from "zgapdfsigner";
|
||||
// Typescript
|
||||
import * as Zga from "zgapdfsigner";
|
||||
```
|
||||
|
||||
## Let's sign
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
import * as forge from "node-forge";
|
||||
import * as PDFLib from "pdf-lib";
|
||||
export * as forge from "node-forge";
|
||||
export * as PDFLib from "pdf-lib";
|
||||
|
||||
export declare function u8arrToRaw(uarr: Uint8Array): string;
|
||||
export declare function rawToU8arr(raw: string): Uint8Array;
|
||||
export declare namespace Crypto {
|
||||
enum Mode {
|
||||
RC4_40,
|
||||
RC4_128,
|
||||
AES_128,
|
||||
AES_256,
|
||||
}
|
||||
}
|
||||
export type DSSInfo = {
|
||||
certs?: Array<forge.pki.Certificate>;
|
||||
ocsps?: Array<Uint8Array>;
|
||||
crls?: Array<Uint8Array>;
|
||||
};
|
||||
export type EncryptOption = {
|
||||
mode: Crypto.Mode;
|
||||
permissions?: Array<string>;
|
||||
userpwd?: string;
|
||||
ownerpwd?: string;
|
||||
pubkeys?: Array<PubKeyInfo>;
|
||||
};
|
||||
export type PubKeyInfo = {
|
||||
c?: Array<number> | Uint8Array | ArrayBuffer | string | forge.pki.Certificate;
|
||||
p?: Array<string>;
|
||||
};
|
||||
export type SignAreaInfo = {
|
||||
x: number;
|
||||
y: number;
|
||||
w?: number;
|
||||
h?: number;
|
||||
};
|
||||
export type SignTextInfo = {
|
||||
text: string,
|
||||
fontData?: Array<number> | Uint8Array | ArrayBuffer | string;
|
||||
color?: string;
|
||||
opacity?: number;
|
||||
blendMode?: string;
|
||||
lineHeight?: number;
|
||||
size: number,
|
||||
xOffset?: number;
|
||||
yOffset?: number;
|
||||
wMax?: number;
|
||||
align?: number;
|
||||
noBreaks?: string;
|
||||
};
|
||||
export type SignImageInfo = {
|
||||
imgData: Array<number> | Uint8Array | ArrayBuffer | string;
|
||||
imgType: string;
|
||||
opacity?: number;
|
||||
blendMode?: string;
|
||||
};
|
||||
export type SignDrawInfo = {
|
||||
area: SignAreaInfo;
|
||||
pageidx?: number | string;
|
||||
/** @deprecated use imgInfo instead */
|
||||
imgData?: Array<number> | Uint8Array | ArrayBuffer | string;
|
||||
/** @deprecated use imgInfo instead */
|
||||
imgType?: string;
|
||||
imgInfo?: SignImageInfo;
|
||||
textInfo?: SignTextInfo;
|
||||
};
|
||||
export type SignOption = {
|
||||
p12cert?: Array<number> | Uint8Array | ArrayBuffer | string;
|
||||
pwd?: string;
|
||||
permission?: number;
|
||||
reason?: string;
|
||||
location?: string;
|
||||
contact?: string;
|
||||
signdate?: Date | TsaServiceInfo | string;
|
||||
signame?: string;
|
||||
drawinf?: SignDrawInfo;
|
||||
ltv?: number;
|
||||
debug?: boolean;
|
||||
};
|
||||
export type TsaServiceInfo = {
|
||||
url: string;
|
||||
len?: number;
|
||||
headers?: Record<string, any>;
|
||||
};
|
||||
|
||||
export declare class CertsChain {
|
||||
constructor(certs?: Array<forge.pki.Certificate | forge.asn1.Asn1 | string>);
|
||||
buildChain(cert: forge.pki.Certificate): Promise<boolean>;
|
||||
getAllCerts(): Array<forge.pki.Certificate>;
|
||||
getSignCert(): forge.pki.Certificate;
|
||||
isSelfSignedCert(): boolean;
|
||||
prepareDSSInf(crlOnly?: boolean): Promise<DSSInfo>;
|
||||
}
|
||||
export declare class PdfCryptor {
|
||||
constructor(encopt: EncryptOption);
|
||||
encryptPdf(pdf: PDFLib.PDFDocument | Array<number> | Uint8Array | ArrayBuffer | string, ref?: PDFLib.PDFRef): Promise<PDFLib.PDFDocument>;
|
||||
encryptObject(num: number, val: PDFLib.PDFObject): void;
|
||||
}
|
||||
export declare class PdfSigner {
|
||||
constructor(signopt: SignOption);
|
||||
sign(pdf: PDFLib.PDFDocument | Array<number> | Uint8Array | ArrayBuffer | string, cypopt?: EncryptOption): Promise<Uint8Array>;
|
||||
}
|
||||
export declare class TsaFetcher {
|
||||
constructor(inf: TsaServiceInfo);
|
||||
url: string;
|
||||
len: number;
|
||||
getCertsChain(): CertsChain;
|
||||
getToken(forP7?: boolean): forge.asn1.Asn1;
|
||||
queryTsa(data?: string): Promise<string>;
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "zgapdfsigner",
|
||||
"version": "2.6.0",
|
||||
"version": "2.7.0",
|
||||
"author": "zboris12",
|
||||
"description": "A javascript tool to sign a pdf or set protection to a pdf in web browser, Google Apps Script and nodejs.",
|
||||
"homepage": "https://github.com/zboris12/zgapdfsigner",
|
||||
|
@ -16,6 +16,7 @@
|
|||
"main": "lib/zganode.js",
|
||||
"files": [
|
||||
"dist/*.min.js",
|
||||
"lib/*.d.ts",
|
||||
"lib/*.js"
|
||||
],
|
||||
"keywords": [
|
||||
|
@ -30,7 +31,7 @@
|
|||
],
|
||||
"scripts": {
|
||||
"build": "./build.sh",
|
||||
"test": "node test4node.js"
|
||||
"test": "node test4node.js ${pfxpwd}"
|
||||
},
|
||||
"dependencies": {
|
||||
"@pdf-lib/fontkit": "^1.1.1",
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"editor.tabSize": 2,
|
||||
"editor.formatOnSave": true,
|
||||
"files.eol": "\n"
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"name": "zgapdfsigner-test-ts",
|
||||
"version": "1.0.0",
|
||||
"author": "zboris12",
|
||||
"description": "A typescript program to test zgapdfsigner.",
|
||||
"private": false,
|
||||
"license": "MIT",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "node test/index.js ${pfxpwd}"
|
||||
},
|
||||
"dependencies": {
|
||||
"zgapdfsigner": "^2.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node-forge": "^1.3.11",
|
||||
"typescript": "~4.9"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
import * as m_fs from "node:fs";
|
||||
import * as m_path from "node:path";
|
||||
import * as Zga from "zgapdfsigner";
|
||||
|
||||
const workpath = "./";
|
||||
|
||||
async function sign_protect(pdfPath: string, pfxPath: string, ps: string, perm: number, imgPath?: string, txt?: string, fontPath?: string): Promise<string> {
|
||||
let pdf: Buffer = m_fs.readFileSync(pdfPath);
|
||||
let pfx: Buffer = m_fs.readFileSync(pfxPath);
|
||||
let img: Buffer | undefined = undefined;
|
||||
let imgType: string = "";
|
||||
let font: Buffer | undefined = undefined;
|
||||
|
||||
if (perm == 1) {
|
||||
console.log("\nTest signing pdf with full protection. (permission 1 and password encryption)");
|
||||
} else {
|
||||
console.log("\nTest signing pdf with permission " + perm);
|
||||
}
|
||||
|
||||
if (imgPath) {
|
||||
img = m_fs.readFileSync(imgPath);
|
||||
imgType = m_path.extname(imgPath).slice(1);
|
||||
}
|
||||
if (fontPath) {
|
||||
font = m_fs.readFileSync(fontPath);
|
||||
}
|
||||
let sopt: Zga.SignOption = {
|
||||
p12cert: pfx,
|
||||
pwd: ps,
|
||||
permission: perm,
|
||||
signdate: "1",
|
||||
reason: "I have a test reason " + perm + ".",
|
||||
location: "I am on the earth " + perm + ".",
|
||||
contact: "zga" + perm + "@zga.com",
|
||||
ltv: 1,
|
||||
debug: true,
|
||||
};
|
||||
if (img || txt) {
|
||||
sopt.drawinf = {
|
||||
area: {
|
||||
x: 25, // left
|
||||
y: 50, // top
|
||||
w: txt ? undefined : 60,
|
||||
h: txt ? undefined : 100,
|
||||
},
|
||||
pageidx: "-",
|
||||
imgInfo: img ? {
|
||||
imgData: img,
|
||||
imgType: imgType,
|
||||
} : undefined,
|
||||
textInfo: txt ? {
|
||||
text: txt,
|
||||
fontData: font,
|
||||
color: "00f0f1",
|
||||
lineHeight: 20,
|
||||
size: 16,
|
||||
align: 1,
|
||||
wMax: 80,
|
||||
yOffset: 10,
|
||||
xOffset: 20,
|
||||
noBreaks: "[あいうえおA-Za-z0-9]",
|
||||
} : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
let eopt: Zga.EncryptOption | undefined = undefined;
|
||||
if (perm == 1) {
|
||||
eopt = {
|
||||
mode: Zga.Crypto.Mode.AES_256,
|
||||
permissions: ["copy", "copy-extract", "print-high"],
|
||||
userpwd: "123",
|
||||
};
|
||||
}
|
||||
|
||||
let ser: Zga.PdfSigner = new Zga.PdfSigner(sopt);
|
||||
let u8dat: Uint8Array = await ser.sign(pdf, eopt);
|
||||
let outPath: string = "";
|
||||
if (u8dat) {
|
||||
outPath = m_path.join(__dirname, workpath + "test_perm" + perm + m_path.basename(pdfPath));
|
||||
m_fs.writeFileSync(outPath, u8dat);
|
||||
console.log("Output file: " + outPath);
|
||||
}
|
||||
return outPath;
|
||||
}
|
||||
|
||||
async function addtsa(pdfPath: string): Promise<string> {
|
||||
console.log("\nTest signing pdf by a timestamp.");
|
||||
|
||||
let pdf: Buffer = m_fs.readFileSync(pdfPath);
|
||||
let sopt: Zga.SignOption = {
|
||||
signdate: "2",
|
||||
reason: "I have a test reason tsa.",
|
||||
location: "I am on the earth tsa.",
|
||||
contact: "zgatsa@zga.com",
|
||||
ltv: 1,
|
||||
debug: true,
|
||||
};
|
||||
let ser: Zga.PdfSigner = new Zga.PdfSigner(sopt);
|
||||
let u8dat: Uint8Array = await ser.sign(pdf);
|
||||
let outPath: string = m_path.join(__dirname, workpath + "tsa_" + m_path.basename(pdfPath));
|
||||
m_fs.writeFileSync(outPath, u8dat);
|
||||
console.log("Output file: " + outPath);
|
||||
return outPath;
|
||||
}
|
||||
|
||||
async function main1(angle: number): Promise<void> {
|
||||
let pdfPath: string = m_path.join(__dirname, workpath + "_test" + (angle ? "_" + angle : "") + ".pdf");
|
||||
let pfxPath: string = m_path.join(__dirname, workpath + "_test.pfx");
|
||||
let ps: string = "";
|
||||
let imgPath: string = m_path.join(__dirname, workpath + "_test.png");
|
||||
let fontPath: string = m_path.join(__dirname, workpath + "_test.ttf");
|
||||
|
||||
if (process.argv.length > 3) {
|
||||
pfxPath = process.argv[2];
|
||||
ps = process.argv[3];
|
||||
} else if (process.argv[2]) {
|
||||
ps = process.argv[2];
|
||||
}
|
||||
|
||||
if (!ps) {
|
||||
// throw new Error("The passphrase is not specified.");
|
||||
pfxPath = "";
|
||||
}
|
||||
|
||||
if (pfxPath) {
|
||||
await sign_protect(pdfPath, pfxPath, ps, 1, imgPath, "あいうえおあいうえおか\r\n\nThis is a test of text!\n", fontPath);
|
||||
pdfPath = await sign_protect(pdfPath, pfxPath, ps, 2, undefined, "ありがとうご\r\n\nThis is an another test of text!\n", fontPath);
|
||||
await addtsa(pdfPath);
|
||||
} else {
|
||||
await addtsa(pdfPath);
|
||||
}
|
||||
|
||||
console.log("Done");
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
let arr: Array<number> = [0, 90, 180, 270];
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
await main1(arr[i]);
|
||||
// break;
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2015",
|
||||
"module": "commonjs",
|
||||
"newLine": "LF",
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noImplicitThis": true,
|
||||
"rootDir": "./src",
|
||||
"outDir": "./test",
|
||||
"typeRoots": [
|
||||
"node_modules/@types"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
|
@ -1,3 +1,10 @@
|
|||
// ES Module Mode
|
||||
// import * as m_fs from "node:fs";
|
||||
// import * as m_path from "node:path";
|
||||
// import { fileURLToPath } from "node:url";
|
||||
// import { default as Zga } from "./lib/zganode.js";
|
||||
// const __dirname = m_path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
const m_fs = require("fs");
|
||||
const m_path = require("path");
|
||||
const Zga = require("./lib/zganode.js");
|
||||
|
|
Loading…
Reference in New Issue