parent
e1ed49d43f
commit
1f92ca61d7
|
@ -88,9 +88,18 @@ pdfkit.loadZga(globalThis);
|
||||||
```
|
```
|
||||||
npm install zgapdfsigner
|
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
|
2. Import
|
||||||
```js
|
```js
|
||||||
|
// CommonJS Mode
|
||||||
const Zga = require("zgapdfsigner");
|
const Zga = require("zgapdfsigner");
|
||||||
|
// ES Module Mode
|
||||||
|
import { default as Zga } from "zgapdfsigner";
|
||||||
|
// Typescript
|
||||||
|
import * as Zga from "zgapdfsigner";
|
||||||
```
|
```
|
||||||
|
|
||||||
## Let's sign
|
## 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",
|
"name": "zgapdfsigner",
|
||||||
"version": "2.6.0",
|
"version": "2.7.0",
|
||||||
"author": "zboris12",
|
"author": "zboris12",
|
||||||
"description": "A javascript tool to sign a pdf or set protection to a pdf in web browser, Google Apps Script and nodejs.",
|
"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",
|
"homepage": "https://github.com/zboris12/zgapdfsigner",
|
||||||
|
@ -16,6 +16,7 @@
|
||||||
"main": "lib/zganode.js",
|
"main": "lib/zganode.js",
|
||||||
"files": [
|
"files": [
|
||||||
"dist/*.min.js",
|
"dist/*.min.js",
|
||||||
|
"lib/*.d.ts",
|
||||||
"lib/*.js"
|
"lib/*.js"
|
||||||
],
|
],
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
@ -30,7 +31,7 @@
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "./build.sh",
|
"build": "./build.sh",
|
||||||
"test": "node test4node.js"
|
"test": "node test4node.js ${pfxpwd}"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@pdf-lib/fontkit": "^1.1.1",
|
"@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_fs = require("fs");
|
||||||
const m_path = require("path");
|
const m_path = require("path");
|
||||||
const Zga = require("./lib/zganode.js");
|
const Zga = require("./lib/zganode.js");
|
||||||
|
|
Loading…
Reference in New Issue