diff --git a/CHANGELOG.md b/CHANGELOG.md index a48819c5..b6c22a5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,8 @@ ## [next] * [utils] Added SIG_FLAGS and ANNOTATION_FLAGS to improve readability; -* [utils] Reworked findByteRange to match in more cases where it was incompatible so far (it didn't allow optional spaces in the array). +* [utils] Reworked findByteRange to match in more cases where it was incompatible so far (it didn't allow optional spaces in the array); +* [utils] Deprecated extractSignature as it was never public-ready. Copied it in internal-utils to be used in tests. Will remove from `utils` in a next major release; * [placeholder-pdfkit010] Uses SIG_FLAGS and ANNOTATION_FLAGS instead of magic numbers; * [placeholder-pdfkit010] Allow passing in widgetRect to override the default [0, 0, 0, 0] one; * [placeholder-plain] Allow passing in widgetRect to override the default [0, 0, 0, 0] one; diff --git a/packages/internal-utils/extractSignature.js b/packages/internal-utils/extractSignature.js new file mode 100644 index 00000000..fe876b6c --- /dev/null +++ b/packages/internal-utils/extractSignature.js @@ -0,0 +1,71 @@ +function getSubstringIndex(str, substring, n) { + var times = 0; + var index = null; + + while (times < n && index !== -1) { + index = str.indexOf(substring, index + 1); + times += 1; + } + + return index; +}; + +/** + * @typedef {Object} ExtractSignatureResult + * @property {number[]} ByteRange + * @property {Buffer} signature + * @property {Buffer} signedData + */ + +/** + * Basic implementation of signature extraction. + * + * Really basic. Would work in the simplest of cases where there is only one signature + * in a document and ByteRange is only used once in it. + * + * @param {Buffer} pdf + * @param {number} signatureCount + * @returns {ExtractSignatureResult} + */ +function extractSignature (pdf, signatureCount) { + if (!(pdf instanceof Buffer)) { + throw new Error('PDF expected as Buffer.'); + } + + // const byteRangePos = pdf.indexOf('/ByteRange ['); + var byteRangePos = getSubstringIndex(pdf, '/ByteRange [', signatureCount || 1); + if (byteRangePos === -1) { + throw new Error('Failed to locate ByteRange.'); + } + + var byteRangeEnd = pdf.indexOf(']', byteRangePos); + if (byteRangeEnd === -1) { + throw new Error('Failed to locate the end of the ByteRange.'); + } + + var byteRange = pdf.subarray(byteRangePos, byteRangeEnd + 1).toString(); + var matches = (/\/ByteRange \[(\d+) +(\d+) +(\d+) +(\d+) *\]/).exec(byteRange); + if (matches === null) { + throw new Error('Failed to parse the ByteRange.'); + } + + var ByteRange = matches.slice(1).map(Number); + var signedData = Buffer.concat([ + pdf.subarray(ByteRange[0], ByteRange[0] + ByteRange[1]), + pdf.subarray(ByteRange[2], ByteRange[2] + ByteRange[3]), + ]); + + var signatureHex = pdf.subarray(ByteRange[0] + ByteRange[1] + 1, ByteRange[2]) + .toString('binary') + .replace(/(?:00|>)+$/, ''); + + var signature = Buffer.from(signatureHex, 'hex').toString('binary'); + + return { + ByteRange: matches.slice(1, 5).map(Number), + signature: signature, + signedData: signedData, + }; +}; + +module.exports = extractSignature; \ No newline at end of file diff --git a/packages/internal-utils/index.js b/packages/internal-utils/index.js index bff02084..879ac2f2 100644 --- a/packages/internal-utils/index.js +++ b/packages/internal-utils/index.js @@ -1,7 +1,9 @@ var readTestResource = require('./readTestResource'); var createPdfkitDocument = require('./createPdfkitDocument'); +var extractSignature = require('./extractSignature'); module.exports = { readTestResource: readTestResource, createPdfkitDocument: createPdfkitDocument, + extractSignature: extractSignature, } \ No newline at end of file diff --git a/packages/signpdf/src/signpdf.test.js b/packages/signpdf/src/signpdf.test.js index 2eade1e8..3d4d5a64 100644 --- a/packages/signpdf/src/signpdf.test.js +++ b/packages/signpdf/src/signpdf.test.js @@ -1,12 +1,8 @@ import {pdfkitAddPlaceholder} from '@signpdf/placeholder-pdfkit010'; import {plainAddPlaceholder} from '@signpdf/placeholder-plain'; import {P12Signer} from '@signpdf/signer-p12'; -import { - extractSignature, - Signer, - SignPdfError, -} from '@signpdf/utils'; -import {readTestResource, createPdfkitDocument} from '@signpdf/internal-utils'; +import {Signer, SignPdfError} from '@signpdf/utils'; +import {readTestResource, createPdfkitDocument, extractSignature} from '@signpdf/internal-utils'; import signpdf from './signpdf'; /** diff --git a/packages/utils/dist/extractSignature.d.ts b/packages/utils/dist/extractSignature.d.ts index 8e5418a9..db791f27 100644 --- a/packages/utils/dist/extractSignature.d.ts +++ b/packages/utils/dist/extractSignature.d.ts @@ -1,2 +1,11 @@ -export function extractSignature(pdf: Buffer, signatureCount?: number): any; +/** + * @type {(pdf: Buffer, signatureCount: number) => ExtractSignatureResult} + * @deprecated Should be used from internal-utils. Will be removed in a major release. + */ +export const extractSignature: (pdf: Buffer, signatureCount: number) => ExtractSignatureResult; +export type ExtractSignatureResult = { + ByteRange: number[]; + signature: Buffer; + signedData: Buffer; +}; //# sourceMappingURL=extractSignature.d.ts.map \ No newline at end of file diff --git a/packages/utils/dist/extractSignature.d.ts.map b/packages/utils/dist/extractSignature.d.ts.map index c78b8650..5f72592d 100644 --- a/packages/utils/dist/extractSignature.d.ts.map +++ b/packages/utils/dist/extractSignature.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"extractSignature.d.ts","sourceRoot":"","sources":["../src/extractSignature.js"],"names":[],"mappings":"AAsBO,sCAHI,MAAM,gCAsDhB"} \ No newline at end of file +{"version":3,"file":"extractSignature.d.ts","sourceRoot":"","sources":["../src/extractSignature.js"],"names":[],"mappings":"AAsFA;;;GAGG;AACH,qCAHgB,MAAM,kBAAkB,MAAM,KAAK,sBAAsB,CAG4F;;eAzEvJ,MAAM,EAAE;eACR,MAAM;gBACN,MAAM"} \ No newline at end of file diff --git a/packages/utils/dist/extractSignature.js b/packages/utils/dist/extractSignature.js index f54dd017..72ea74b4 100644 --- a/packages/utils/dist/extractSignature.js +++ b/packages/utils/dist/extractSignature.js @@ -4,7 +4,9 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.extractSignature = void 0; +var _util = _interopRequireDefault(require("util")); var _SignPdfError = require("./SignPdfError"); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const getSubstringIndex = (str, substring, n) => { let times = 0; let index = null; @@ -14,16 +16,26 @@ const getSubstringIndex = (str, substring, n) => { } return index; }; + +/** + * @typedef {Object} ExtractSignatureResult + * @property {number[]} ByteRange + * @property {Buffer} signature + * @property {Buffer} signedData + */ + /** * Basic implementation of signature extraction. * - * Really basic. Would work in the simplest of cases where there is only one signature - * in a document and ByteRange is only used once in it. + * Really basic. Would work in the simplest of cases. * * @param {Buffer} pdf - * @returns {Object} {ByteRange: Number[], signature: Buffer, signedData: Buffer} + * @param {number} signatureCount + * @returns {ExtractSignatureResult} + * + * @deprecated Should be used internally from internal-utils. Will be removed in a major release. */ -const extractSignature = (pdf, signatureCount = 1) => { +const extractSignatureDeprecated = (pdf, signatureCount = 1) => { if (!(pdf instanceof Buffer)) { throw new _SignPdfError.SignPdfError('PDF expected as Buffer.', _SignPdfError.SignPdfError.TYPE_INPUT); } @@ -52,4 +64,9 @@ const extractSignature = (pdf, signatureCount = 1) => { signedData }; }; -exports.extractSignature = extractSignature; \ No newline at end of file + +/** + * @type {(pdf: Buffer, signatureCount: number) => ExtractSignatureResult} + * @deprecated Should be used from internal-utils. Will be removed in a major release. + */ +const extractSignature = exports.extractSignature = _util.default.deprecate(extractSignatureDeprecated, 'Should be used internally from internal-utils. Will be removed in a major release.'); \ No newline at end of file diff --git a/packages/utils/src/__snapshots__/extractSignature.test.js.snap b/packages/utils/src/__snapshots__/extractSignature.test.js.snap index 92d7feae..40c5f71c 100644 Binary files a/packages/utils/src/__snapshots__/extractSignature.test.js.snap and b/packages/utils/src/__snapshots__/extractSignature.test.js.snap differ diff --git a/packages/utils/src/extractSignature.js b/packages/utils/src/extractSignature.js index 6f47a09b..fd00626c 100644 --- a/packages/utils/src/extractSignature.js +++ b/packages/utils/src/extractSignature.js @@ -1,3 +1,4 @@ +import nodeUtil from 'util'; import {SignPdfError} from './SignPdfError'; const getSubstringIndex = (str, substring, n) => { @@ -11,16 +12,26 @@ const getSubstringIndex = (str, substring, n) => { return index; }; + +/** + * @typedef {Object} ExtractSignatureResult + * @property {number[]} ByteRange + * @property {Buffer} signature + * @property {Buffer} signedData + */ + /** * Basic implementation of signature extraction. * - * Really basic. Would work in the simplest of cases where there is only one signature - * in a document and ByteRange is only used once in it. + * Really basic. Would work in the simplest of cases. * * @param {Buffer} pdf - * @returns {Object} {ByteRange: Number[], signature: Buffer, signedData: Buffer} + * @param {number} signatureCount + * @returns {ExtractSignatureResult} + * + * @deprecated Should be used internally from internal-utils. Will be removed in a major release. */ -export const extractSignature = (pdf, signatureCount = 1) => { +const extractSignatureDeprecated = (pdf, signatureCount = 1) => { if (!(pdf instanceof Buffer)) { throw new SignPdfError( 'PDF expected as Buffer.', @@ -72,3 +83,9 @@ export const extractSignature = (pdf, signatureCount = 1) => { signedData, }; }; + +/** + * @type {(pdf: Buffer, signatureCount: number) => ExtractSignatureResult} + * @deprecated Should be used from internal-utils. Will be removed in a major release. + */ +export const extractSignature = nodeUtil.deprecate(extractSignatureDeprecated, 'Should be used internally from internal-utils. Will be removed in a major release.');