xades-bes-signer 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Gabriel Acuña
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,34 @@
1
+ # xades-bas-signer
2
+
3
+ XAdES-BES signer for Node/TypeScript — utilities to load certificates and create XAdES-BES XML signatures.
4
+
5
+ A compact TypeScript library that helps you manage certificate files (P12) and produce the canonical building blocks needed for XAdES-BES signatures in Node.js applications.
6
+
7
+ ## Features
8
+
9
+ - Load and manage certificate files using a [FileManager](src/libs/files.ts#L3).
10
+ - Convert hex, bigint, and SHA-1 digests to Base64.
11
+ - Utilities for deterministic formatting of Base64 output.
12
+ - Test suite with example environment-driven cert path to validate file handling.
13
+
14
+ ## Quick Start
15
+
16
+ - Prerequisites: Node.js >= 16 (as declared in package.json), npm install.
17
+ - Set up:
18
+ - Create a .env file in Create a `.env` in repository root with:
19
+ - [CERT_PATH=./credentials/your-cert.p12](./test/libs/files.test.ts#L8)
20
+ - [CERT_KEY=certificate-key](./test/libs/credentials.test.ts#L16)
21
+ - Install:
22
+
23
+ ```sh
24
+ npm install
25
+ ```
26
+
27
+ - Run tests:
28
+
29
+ ````ssh
30
+ npm test
31
+
32
+ ````
33
+ ## Licence
34
+ MIT (see [LICENSE](./LICENSE)).
@@ -0,0 +1,5 @@
1
+ /** @jest-config-loader ts-node */
2
+ /** @jest-config-loader-options {"transpileOnly": true} */
3
+ import type { Config } from 'jest';
4
+ declare const config: Config;
5
+ export default config;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const config = {
4
+ preset: 'ts-jest',
5
+ verbose: true,
6
+ testEnvironment: 'node',
7
+ roots: ['<rootDir>/test'],
8
+ testMatch: ['**/test/**/*.test.ts'],
9
+ moduleFileExtensions: ['ts', 'js', 'json', 'node'],
10
+ transform: {
11
+ '^.+\\.ts$': 'ts-jest'
12
+ }
13
+ };
14
+ exports.default = config;
@@ -0,0 +1,32 @@
1
+ import * as forge from "node-forge";
2
+ import { PKCS88Bags } from "./types";
3
+ export declare function getP12(certificate: Uint8Array<ArrayBufferLike>, certKey: string): forge.pkcs12.Pkcs12Pfx;
4
+ export declare function getIssuerName(cert: forge.pkcs12.Bag): string | undefined;
5
+ export declare function getKeyContainer(pkcs8Bags: PKCS88Bags, friendlyName: string): forge.pkcs12.Bag;
6
+ export declare function getKey(pckcs8: forge.pkcs12.Bag): forge.pki.rsa.PrivateKey;
7
+ export declare function getCertificate(certBag: forge.pkcs12.Bag[]): forge.pkcs12.Bag;
8
+ export declare function isCerticateValid(certficate: forge.pki.Certificate): boolean;
9
+ export declare function certX509ToPem(certificate: forge.pki.Certificate): string;
10
+ export declare function certX509ToASN1(certificate: forge.pki.Certificate): forge.asn1.Asn1;
11
+ export declare function getPCK12CertInfo(certificate: Uint8Array<ArrayBufferLike>, certKey: string): {
12
+ radomValues: {
13
+ certificateNumber: number;
14
+ signatureNumber: number;
15
+ signedPropertiesNumber: number;
16
+ signedInfoNumber: number;
17
+ signedPropertiesIdNumber: number;
18
+ referenceIdNumber: number;
19
+ signatureValueNumber: number;
20
+ objectNumber: number;
21
+ };
22
+ certInfo: {
23
+ digestValue: string;
24
+ issuerName: string | undefined;
25
+ issuerSerialNumber: number;
26
+ signingTime: string;
27
+ certificateX509: string;
28
+ modulus: string | undefined;
29
+ exponent: string;
30
+ key: forge.pki.rsa.PrivateKey;
31
+ };
32
+ };
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.getP12 = getP12;
37
+ exports.getIssuerName = getIssuerName;
38
+ exports.getKeyContainer = getKeyContainer;
39
+ exports.getKey = getKey;
40
+ exports.getCertificate = getCertificate;
41
+ exports.isCerticateValid = isCerticateValid;
42
+ exports.certX509ToPem = certX509ToPem;
43
+ exports.certX509ToASN1 = certX509ToASN1;
44
+ exports.getPCK12CertInfo = getPCK12CertInfo;
45
+ const forge = __importStar(require("node-forge"));
46
+ const security_1 = require("./security");
47
+ function getP12(certificate, certKey) {
48
+ const der = forge.util.decode64(forge.util.binary.base64.encode(new Uint8Array(certificate)));
49
+ const ansi = forge.asn1.fromDer(der);
50
+ return forge.pkcs12.pkcs12FromAsn1(ansi, certKey);
51
+ }
52
+ function getIssuerName(cert) {
53
+ var _a;
54
+ const issuerTributes = (_a = cert.cert) === null || _a === void 0 ? void 0 : _a.issuer.attributes;
55
+ let issuerName = issuerTributes === null || issuerTributes === void 0 ? void 0 : issuerTributes.reverse().map((attr) => {
56
+ return `${attr.shortName}=${attr.value}`;
57
+ }).join(", ");
58
+ return issuerName;
59
+ }
60
+ function getKeyContainer(pkcs8Bags, friendlyName) {
61
+ let pkcs8;
62
+ const oid = forge.pki.oids["pkcs8ShroudedKeyBag"];
63
+ const bags = pkcs8Bags === null || pkcs8Bags === void 0 ? void 0 : pkcs8Bags[oid];
64
+ if (!bags || !Array.isArray(bags) || bags.length === 0) {
65
+ throw new Error("No key bags found in the PKCS#12 certificate.");
66
+ }
67
+ if (friendlyName.includes("BANCO CENTRAL")) {
68
+ const index = bags.findIndex((key) => { var _a, _b, _c; return (_c = (_b = (_a = key === null || key === void 0 ? void 0 : key.attributes) === null || _a === void 0 ? void 0 : _a.friendlyName) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.includes("Signing Key"); });
69
+ if (!index) {
70
+ throw new Error("Unable to find the key bag for BANCO CENTRAL");
71
+ }
72
+ pkcs8 = bags[index];
73
+ }
74
+ else {
75
+ pkcs8 = bags[0];
76
+ }
77
+ return pkcs8;
78
+ }
79
+ function getKey(pckcs8) {
80
+ let key;
81
+ if (pckcs8["key"]) {
82
+ key = pckcs8["key"];
83
+ }
84
+ else if (pckcs8["asn1"]) {
85
+ key = forge.pki.privateKeyFromAsn1(pckcs8["asn1"]);
86
+ }
87
+ else {
88
+ throw new Error("No private key found in the PKCS#12 key bag.");
89
+ }
90
+ return key;
91
+ }
92
+ function getCertificate(certBag) {
93
+ let crt = certBag.reduce((prev, current) => {
94
+ var _a, _b, _c, _d, _e, _f;
95
+ return ((_c = (_b = (_a = current.cert) === null || _a === void 0 ? void 0 : _a.extensions) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0) >
96
+ ((_f = (_e = (_d = prev.cert) === null || _d === void 0 ? void 0 : _d.extensions) === null || _e === void 0 ? void 0 : _e.length) !== null && _f !== void 0 ? _f : 0)
97
+ ? current
98
+ : prev;
99
+ });
100
+ return crt;
101
+ }
102
+ function isCerticateValid(certficate) {
103
+ const notBefore = certficate.validity.notBefore;
104
+ const notAfter = certficate.validity.notAfter;
105
+ const currentDate = new Date();
106
+ return currentDate >= notBefore && currentDate <= notAfter;
107
+ }
108
+ function certX509ToPem(certificate) {
109
+ return forge.pki.certificateToPem(certificate);
110
+ }
111
+ function certX509ToASN1(certificate) {
112
+ return forge.pki.certificateToAsn1(certificate);
113
+ }
114
+ function getPCK12CertInfo(certificate, certKey) {
115
+ var _a, _b;
116
+ const p12 = getP12(certificate, certKey);
117
+ const pkcs8Bags = p12.getBags({
118
+ bagType: forge.pki.oids["pkcs8ShroudedKeyBag"],
119
+ });
120
+ const data = p12.getBags({ bagType: forge.pki.oids.certBag });
121
+ if (!data || !((_a = data === null || data === void 0 ? void 0 : data[forge.pki.oids.certBag]) === null || _a === void 0 ? void 0 : _a[0]))
122
+ throw new Error("Unable to parse certificate. Incorrect Password?");
123
+ const certBags = (_b = data[forge.pki.oids.certBag]) !== null && _b !== void 0 ? _b : [];
124
+ const friendlyName = certBags[1].attributes.friendlyName[0];
125
+ let certBag = getCertificate(certBags);
126
+ if (isCerticateValid(certBag.cert)) {
127
+ throw new Error("Invalid certificate, check the validity");
128
+ }
129
+ const cert = certBag.cert;
130
+ let pckcs8;
131
+ let issuerName = getIssuerName(certBag);
132
+ pckcs8 = getKeyContainer(pkcs8Bags, friendlyName);
133
+ let key = getKey(pckcs8);
134
+ const pem = certX509ToPem(cert);
135
+ let certificateX509 = pem.substring(pem.indexOf("\n") + 1, pem.indexOf("-----END CERTIFICATE-----"));
136
+ certificateX509.replace(/\r?\n|\r/g, "").replace(/([^\0]{76})/g, "$1\n");
137
+ const ISODateTime = new Date().toISOString().slice(0, 19);
138
+ const certificateANS1 = certX509ToASN1(cert);
139
+ const certificateDER = forge.asn1.toDer(certificateANS1).getBytes();
140
+ const hashCErtificateX509DER = (0, security_1.sha1ToBase64)(certificateDER, "utf-8");
141
+ const certificateX509SN = parseInt(hashCErtificateX509DER, 16);
142
+ const exponent = (0, security_1.hexToBase64)(key.e.data[0].toString(16));
143
+ const modulus = (0, security_1.bigintToBase64)(BigInt(key.n.toString()));
144
+ const certificateNumber = (0, security_1.getRandomValues)();
145
+ const signatureNumber = (0, security_1.getRandomValues)();
146
+ const signedPropertiesNumber = (0, security_1.getRandomValues)();
147
+ const signedInfoNumber = (0, security_1.getRandomValues)();
148
+ const signedPropertiesIdNumber = (0, security_1.getRandomValues)();
149
+ const referenceIdNumber = (0, security_1.getRandomValues)();
150
+ const signatureValueNumber = (0, security_1.getRandomValues)();
151
+ const objectNumber = (0, security_1.getRandomValues)();
152
+ return {
153
+ radomValues: {
154
+ certificateNumber,
155
+ signatureNumber,
156
+ signedPropertiesNumber,
157
+ signedInfoNumber,
158
+ signedPropertiesIdNumber,
159
+ referenceIdNumber,
160
+ signatureValueNumber,
161
+ objectNumber,
162
+ },
163
+ certInfo: {
164
+ digestValue: hashCErtificateX509DER,
165
+ issuerName,
166
+ issuerSerialNumber: certificateX509SN,
167
+ signingTime: ISODateTime,
168
+ certificateX509,
169
+ modulus,
170
+ exponent,
171
+ key,
172
+ },
173
+ };
174
+ }
@@ -0,0 +1,6 @@
1
+ export declare class FileManager {
2
+ private data?;
3
+ openFile(path: string): Promise<this>;
4
+ toString(encoding: BufferEncoding): Promise<string>;
5
+ getFile(): Buffer<ArrayBufferLike> | undefined;
6
+ }
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.FileManager = void 0;
13
+ const promises_1 = require("fs/promises");
14
+ class FileManager {
15
+ openFile(path) {
16
+ return __awaiter(this, void 0, void 0, function* () {
17
+ try {
18
+ this.data = yield (0, promises_1.readFile)(path);
19
+ return this;
20
+ }
21
+ catch (err) {
22
+ throw err;
23
+ }
24
+ });
25
+ }
26
+ toString(encoding) {
27
+ return __awaiter(this, void 0, void 0, function* () {
28
+ if (!this.data)
29
+ throw new Error("File data is not loaded. Please call openFile() first.");
30
+ return this.data.toString(encoding);
31
+ });
32
+ }
33
+ getFile() {
34
+ return this.data;
35
+ }
36
+ }
37
+ exports.FileManager = FileManager;
@@ -0,0 +1,9 @@
1
+ import { Encoding } from "node:crypto";
2
+ import * as forge from "node-forge";
3
+ export declare function sha1ToBase64(text: string, encoding: Encoding): string;
4
+ export declare function hexToBase64(hashHex: string): string;
5
+ export declare function bigintToBase64(param: bigint): string | undefined;
6
+ export declare function getRandomValues(min?: number, max?: number): number;
7
+ export declare function isHexString(str: string): boolean;
8
+ export declare function toSha1(content: string, encoding: forge.Encoding): forge.md.sha1.MessageDigest;
9
+ export declare function toBase64String(content: any): string;
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.sha1ToBase64 = sha1ToBase64;
37
+ exports.hexToBase64 = hexToBase64;
38
+ exports.bigintToBase64 = bigintToBase64;
39
+ exports.getRandomValues = getRandomValues;
40
+ exports.isHexString = isHexString;
41
+ exports.toSha1 = toSha1;
42
+ exports.toBase64String = toBase64String;
43
+ const crypto = __importStar(require("node:crypto"));
44
+ const forge = __importStar(require("node-forge"));
45
+ function sha1ToBase64(text, encoding) {
46
+ const HASH = crypto.createHash("sha1").update(text, encoding).digest("hex");
47
+ const BUFFER = Buffer.from(HASH, "hex");
48
+ return BUFFER.toString("base64");
49
+ }
50
+ function hexToBase64(hashHex) {
51
+ if (hashHex.length % 2 !== 0) {
52
+ hashHex = "0" + hashHex;
53
+ }
54
+ if (!isHexString(hashHex)) {
55
+ throw new Error("Invalid hex string");
56
+ }
57
+ const buf = Buffer.from(hashHex, "hex");
58
+ return buf.toString("base64");
59
+ }
60
+ function bigintToBase64(param) {
61
+ var _a;
62
+ let hexString = param.toString(16);
63
+ if (hexString.length % 2 !== 0) {
64
+ hexString = "0" + hexString;
65
+ }
66
+ const buffer = Buffer.from(hexString, "hex");
67
+ const base64 = buffer.toString("base64");
68
+ const formatedBase64 = (_a = base64.match(/.{1,76}/g)) === null || _a === void 0 ? void 0 : _a.join("\n");
69
+ return formatedBase64;
70
+ }
71
+ function getRandomValues(min = 990, max = 9999) {
72
+ return Math.floor(Math.random() * (max - min + 1) + min);
73
+ }
74
+ function isHexString(str) {
75
+ const hexRegEx = /^[0-9a-fA-F]+$/;
76
+ return hexRegEx.test(str);
77
+ }
78
+ function toSha1(content, encoding) {
79
+ const md = forge.md.sha1.create();
80
+ md.update(content, encoding);
81
+ return md;
82
+ }
83
+ function toBase64String(content) {
84
+ const buffer = Buffer.from(content, 'utf-8');
85
+ return buffer.toString('base64');
86
+ }
@@ -0,0 +1,9 @@
1
+ export declare function getP12(path: string): Promise<Buffer<ArrayBufferLike> | undefined>;
2
+ export declare function getXML(path: string): Promise<string>;
3
+ export declare function sign(params: {
4
+ p12Path: string;
5
+ p12Password: string;
6
+ rootElement: string;
7
+ xmlPath?: string;
8
+ xmlString?: string;
9
+ }): Promise<string>;
@@ -0,0 +1,206 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.getP12 = getP12;
13
+ exports.getXML = getXML;
14
+ exports.sign = sign;
15
+ const files_1 = require("./files");
16
+ const credentials_1 = require("./credentials");
17
+ const security_1 = require("./security");
18
+ function getP12(path) {
19
+ return __awaiter(this, void 0, void 0, function* () {
20
+ const fileManager = new files_1.FileManager();
21
+ try {
22
+ yield fileManager.openFile(path);
23
+ return fileManager.getFile();
24
+ }
25
+ catch (error) {
26
+ throw new Error("Error reading P12 file: " + error);
27
+ }
28
+ });
29
+ }
30
+ function getXML(path) {
31
+ return __awaiter(this, void 0, void 0, function* () {
32
+ const fileManager = new files_1.FileManager();
33
+ try {
34
+ yield fileManager.openFile(path);
35
+ }
36
+ catch (error) {
37
+ throw new Error("Error reading XML file: " + error);
38
+ }
39
+ return fileManager.toString("utf-8");
40
+ });
41
+ }
42
+ function getSignedPropertiesNode(params) {
43
+ return (`<etsi:SignedProperties Id="Signature${params.signatureNumber} SignedProperties${params.signedPropertiesNumber}">` +
44
+ `<etsi:SignedSignatureProperties>` +
45
+ `<etsi:SignedTime>${params.signingTime}</etsi:SignedTime>` +
46
+ `<etsi:SigningCertificate>` +
47
+ `<etsi:Cert>` +
48
+ `<etsi:CertDigest><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1">` +
49
+ `<etsi:DigestValue>${params.digestValue}</etsi:DigestValue></etsi:CertDigest>` +
50
+ `<etsi:IssuerSerial>` +
51
+ `<ds:X509IssuerName>${params.issuerName}</ds:X509IssuerName>` +
52
+ `<ds:X509SerialNumber>${params.issuerSerialNumber}</ds:X509SerialNumber>` +
53
+ `</etsi:IssuerSerial>` +
54
+ `</etsi:Cert>` +
55
+ `</etsi:SigningCertificate>` +
56
+ `<etsi:SignedDataObjectProperties>` +
57
+ `<etsi:DataObjectFormat ObjectReference="#Reference-ID=${params.referenceIdNumber}">` +
58
+ `<etsi:Description>contenido comprobante</etsi:Description>` +
59
+ `<etsi:MimeType>text/xml</etsi:MimeType>` +
60
+ `</etsi:DataObjectFormat>` +
61
+ `</etsi:SignedDataObjectProperties>` +
62
+ `</etsi:SignedProperties>`);
63
+ }
64
+ function getKeyInfoNode(params) {
65
+ return (`<ds:KeyInfo Id="Certificate${params.certificateNumber}">` +
66
+ `\n<ds:X509Data>` +
67
+ `\n<ds:X509Certificate>\n${params.certificateX509}\n</ds:X509Certificate>` +
68
+ `\n</ds:X509Data>` +
69
+ `\n</ds:KeyValue>\n<ds:RSAKeyValue>\n<ds:Modulus>\n${params.modulus}\n</ds:Modulus>` +
70
+ `\n<ds:Exponent>\n${params.exponent}</ds:Exponent>` +
71
+ `\n</ds:RSAKeyValue>` +
72
+ `\n</ds:KeyInfo>`);
73
+ }
74
+ function getSignedInfoNode(params) {
75
+ return (`<ds:SignedInfo Id="Signature-SignedInfo${params.signedInfoNumber}">` +
76
+ `\n<ds:CanonicalizationMethod> Algorithm=”http://www.w3.org/TR/2001/REC-xml-c14n20010315”></ds:CanonicalizationMethod>` +
77
+ `\n<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod>` +
78
+ `\n<ds:Reference Id="SignedPropertiedID${params.signedPropertiesIdNumber}"> Type="http://uri.etsi.org/01903#SignedProperties" URI="#Signature${params.signatureNumber}-SignedProperties${params.signedPropertiesNumber}">` +
79
+ `\n<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>` +
80
+ `\n<ds:DigestValue>${params.sha1SignedProperties}</ds:DigestValue>` +
81
+ `\n</ds:Reference>` +
82
+ `\n<ds:Reference URI="Certificate${params.certificateNumber}">` +
83
+ `\n<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>` +
84
+ `\n<ds:DigestValue>${params.sha1KeyInfo}</ds:DigestValue>` +
85
+ `\n</ds:Reference>` +
86
+ `\n<ds:Reference Id="Reference-ID-${params.referenceIdNumber}" URI="#comprobante">` +
87
+ `\n<ds:Transforms>` +
88
+ `\n<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></ds:Transform>` +
89
+ `\n</ds:Transforms>` +
90
+ `\n<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>` +
91
+ `\n<ds:DigestValue>${params.sha1Xml}</ds:DigestValue>` +
92
+ `\n</ds:Reference>` +
93
+ `</ds:SignedInfo`);
94
+ }
95
+ function getSignatureObject(params) {
96
+ const objectSignature = `<ds:Object Id="Signature${params.signatureNumber}-Object${params.objectNumber}">` +
97
+ `<etsi:QualifyingProperties Target="#Signature${params.signatureNumber}">` +
98
+ `${params.signedInfo}` +
99
+ `</etsi:QualifyingProperties></ds:Object>`;
100
+ return objectSignature;
101
+ }
102
+ function getSignatureNode(params) {
103
+ const signatureNode = `\n<ds:Signature ${params.namespaces} Id="Signature${params.signatureNumber}">` +
104
+ `\n${params.signedInfoNode}` +
105
+ `\n${params.signatureValueNode}` +
106
+ `\n${params.keyInfoNode}` +
107
+ `\n${params.objectSignarureNode}` +
108
+ `</ds:Signature>`;
109
+ return signatureNode;
110
+ }
111
+ function nodeCanonicalization(params) {
112
+ return params.content.replace(params.nodeName, `${params.nodeName} ${params.namespaces}`);
113
+ }
114
+ function addSignatureNode(params) {
115
+ const { xml, rootElement, signatureNode } = params;
116
+ return xml.replace(`</${rootElement}>`, `${signatureNode}</${rootElement}>`);
117
+ }
118
+ function sign(params) {
119
+ return __awaiter(this, void 0, void 0, function* () {
120
+ var _a, _b;
121
+ const { p12Path, p12Password, xmlPath, xmlString } = params;
122
+ if (!xmlPath && !xmlString) {
123
+ throw new Error("Either xmlPath or xmlString must be provided.");
124
+ }
125
+ const p12Buffer = yield getP12(p12Path);
126
+ let xmlData = "";
127
+ xmlData += xmlPath ? yield getXML(xmlPath) : xmlString;
128
+ xmlData = xmlData
129
+ .replace(/\s+/g, " ")
130
+ .trim()
131
+ .replace(/(?=<\>)(\r?\n)|(\r?\n)(?=\<\/) /g, "")
132
+ .trim()
133
+ .replace(/(?=<\>)(\s*)/g, "")
134
+ .replace(/\t|\r/g, "");
135
+ const arayuint8 = new Uint8Array(p12Buffer === null || p12Buffer === void 0 ? void 0 : p12Buffer.buffer);
136
+ let certInfo = (0, credentials_1.getPCK12CertInfo)(arayuint8, p12Password);
137
+ const sha1Xml = (0, security_1.sha1ToBase64)(xmlData.replace(`<?xml version="1.0" encoding="UTF-8"?>`, ""), "utf8");
138
+ const namespaces = 'xmlns:ds="http://www.w3.org/2000/09/xmldsig#namespace xmlns:estsi="http://uri.etsi.org/01903/v1.3.2#"';
139
+ let signedProperties = getSignedPropertiesNode({
140
+ signatureNumber: certInfo.radomValues.signatureNumber,
141
+ signedPropertiesNumber: certInfo.radomValues.signedPropertiesNumber,
142
+ signingTime: certInfo.certInfo.signingTime,
143
+ digestValue: certInfo.certInfo.digestValue,
144
+ issuerName: certInfo.certInfo.issuerName,
145
+ issuerSerialNumber: certInfo.certInfo.issuerSerialNumber,
146
+ referenceIdNumber: certInfo.radomValues.referenceIdNumber,
147
+ });
148
+ const signedPropertiesCanonicalized = nodeCanonicalization({
149
+ content: signedProperties,
150
+ nodeName: "<etsi:SignedProperties",
151
+ namespaces,
152
+ });
153
+ const sha1SignedProperties = (0, security_1.sha1ToBase64)(signedPropertiesCanonicalized, "utf8");
154
+ const keyInfo = getKeyInfoNode({
155
+ certificateNumber: certInfo.radomValues.certificateNumber,
156
+ certificateX509: certInfo.certInfo.certificateX509,
157
+ modulus: certInfo.certInfo.modulus,
158
+ exponent: certInfo.certInfo.exponent,
159
+ });
160
+ const keyInfoCanonicalized = nodeCanonicalization({
161
+ content: keyInfo,
162
+ nodeName: "<ds:KeyInfo",
163
+ namespaces,
164
+ });
165
+ const sha1KeyInfo = (0, security_1.sha1ToBase64)(keyInfoCanonicalized, "utf-8");
166
+ const signedInfo = getSignedInfoNode({
167
+ signedInfoNumber: certInfo.radomValues.signedInfoNumber,
168
+ signedPropertiesIdNumber: certInfo.radomValues.signedPropertiesIdNumber,
169
+ sha1SignedProperties,
170
+ certificateNumber: certInfo.radomValues.certificateNumber,
171
+ sha1KeyInfo,
172
+ referenceIdNumber: certInfo.radomValues.referenceIdNumber,
173
+ sha1Xml,
174
+ signatureNumber: certInfo.radomValues.signatureNumber,
175
+ signedPropertiesNumber: certInfo.radomValues.signedPropertiesNumber,
176
+ });
177
+ const signedInfoCanonicalized = nodeCanonicalization({
178
+ content: signedInfo,
179
+ nodeName: "<ds:SignedInfo",
180
+ namespaces,
181
+ });
182
+ const md = (0, security_1.toSha1)(signedInfoCanonicalized, "utf8");
183
+ const signatureValue = (_b = (_a = (0, security_1.toBase64String)(certInfo.certInfo.key.sign(md))
184
+ .match(/.{1,76}/g)) === null || _a === void 0 ? void 0 : _a.join("\n")) !== null && _b !== void 0 ? _b : "";
185
+ const signatureValueNode = `\n<ds:SignatureValue Id="SignatureValue${certInfo.radomValues.signatureValueNumber}">` +
186
+ `${signatureValue}\n</ds:SignatureValue>`;
187
+ const objectSignature = getSignatureObject({
188
+ signatureNumber: certInfo.radomValues.signatureNumber,
189
+ objectNumber: certInfo.radomValues.objectNumber,
190
+ signedInfo,
191
+ });
192
+ const signatureNode = getSignatureNode({
193
+ namespaces,
194
+ signatureNumber: certInfo.radomValues.signatureNumber,
195
+ signedInfoNode: signedInfo,
196
+ signatureValueNode,
197
+ keyInfoNode: keyInfo,
198
+ objectSignarureNode: objectSignature,
199
+ });
200
+ return addSignatureNode({
201
+ xml: xmlData,
202
+ rootElement: params.rootElement,
203
+ signatureNode,
204
+ });
205
+ });
206
+ }
@@ -0,0 +1,2 @@
1
+ import { sign } from "./libs/signer";
2
+ export { sign };
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sign = void 0;
4
+ const signer_1 = require("./libs/signer");
5
+ Object.defineProperty(exports, "sign", { enumerable: true, get: function () { return signer_1.sign; } });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ const files_1 = require("../../src/libs/files");
46
+ const credentials_1 = require("../../src/libs/credentials");
47
+ const globals_1 = require("@jest/globals");
48
+ const dotenv = __importStar(require("dotenv"));
49
+ const forge = __importStar(require("node-forge"));
50
+ dotenv.config();
51
+ const CERT_PATH = process.env.CERT_PATH;
52
+ const CERT_KEY = process.env.CERT_KEY;
53
+ (0, globals_1.describe)("Crdentials", () => {
54
+ let fileManager;
55
+ let arrayuint8;
56
+ (0, globals_1.beforeAll)(() => __awaiter(void 0, void 0, void 0, function* () {
57
+ fileManager = new files_1.FileManager();
58
+ yield fileManager.openFile(CERT_PATH);
59
+ let p12Buffer = fileManager.getFile();
60
+ arrayuint8 = new Uint8Array(p12Buffer);
61
+ }));
62
+ (0, globals_1.afterEach)(() => __awaiter(void 0, void 0, void 0, function* () {
63
+ fileManager = new files_1.FileManager();
64
+ yield fileManager.openFile(CERT_PATH);
65
+ let p12Buffer = fileManager.getFile();
66
+ arrayuint8 = new Uint8Array(p12Buffer);
67
+ }));
68
+ (0, globals_1.describe)("getP12 function", () => {
69
+ (0, globals_1.test)("should successfully return a forge.pkcs12.Pkcs12Pfx object", () => __awaiter(void 0, void 0, void 0, function* () {
70
+ (0, globals_1.expect)(CERT_PATH).toBeDefined();
71
+ (0, globals_1.expect)(CERT_KEY).toBeDefined();
72
+ (0, globals_1.expect)(arrayuint8).toBeDefined();
73
+ let p12 = (0, credentials_1.getP12)(arrayuint8, CERT_KEY);
74
+ (0, globals_1.expect)(p12).toBeInstanceOf(Object);
75
+ console.log(p12);
76
+ }));
77
+ });
78
+ (0, globals_1.describe)("isCerticateValid function", () => {
79
+ (0, globals_1.test)("should return true", () => __awaiter(void 0, void 0, void 0, function* () {
80
+ var _a;
81
+ (0, globals_1.expect)(CERT_PATH).toBeDefined();
82
+ (0, globals_1.expect)(CERT_KEY).toBeDefined();
83
+ (0, globals_1.expect)(arrayuint8).toBeDefined();
84
+ let p12 = (0, credentials_1.getP12)(arrayuint8, CERT_KEY);
85
+ const data = p12.getBags({ bagType: forge.pki.oids["certBag"] });
86
+ const certBags = (_a = data[forge.pki.oids["certBag"]]) !== null && _a !== void 0 ? _a : [];
87
+ const certBag = (0, credentials_1.getCertificate)(certBags);
88
+ const isValid = (0, credentials_1.isCerticateValid)(certBag.cert);
89
+ (0, globals_1.expect)(isValid).toBeTruthy();
90
+ }));
91
+ });
92
+ (0, globals_1.describe)("getIssuerName", () => {
93
+ (0, globals_1.test)("should return issuer name string", () => __awaiter(void 0, void 0, void 0, function* () {
94
+ var _a;
95
+ (0, globals_1.expect)(CERT_PATH).toBeDefined();
96
+ (0, globals_1.expect)(CERT_KEY).toBeDefined();
97
+ (0, globals_1.expect)(arrayuint8).toBeDefined();
98
+ let p12 = (0, credentials_1.getP12)(arrayuint8, CERT_KEY);
99
+ const data = p12.getBags({ bagType: forge.pki.oids["certBag"] });
100
+ const certBags = (_a = data[forge.pki.oids["certBag"]]) !== null && _a !== void 0 ? _a : [];
101
+ const certBag = (0, credentials_1.getCertificate)(certBags);
102
+ const cert = certBag.cert;
103
+ let issuerName = (0, credentials_1.getIssuerName)(certBag);
104
+ (0, globals_1.expect)(typeof issuerName).toBe("string");
105
+ (0, globals_1.expect)(issuerName).toContain("CN=");
106
+ (0, globals_1.expect)(issuerName).toContain("OU=");
107
+ (0, globals_1.expect)(issuerName).toContain("O=");
108
+ (0, globals_1.expect)(issuerName).toContain("C=");
109
+ }));
110
+ });
111
+ (0, globals_1.describe)("getKeyContainer", () => {
112
+ (0, globals_1.test)("should return pkcs8 bag", () => __awaiter(void 0, void 0, void 0, function* () {
113
+ var _a;
114
+ (0, globals_1.expect)(CERT_PATH).toBeDefined();
115
+ (0, globals_1.expect)(CERT_KEY).toBeDefined();
116
+ (0, globals_1.expect)(arrayuint8).toBeDefined();
117
+ let p12 = (0, credentials_1.getP12)(arrayuint8, CERT_KEY);
118
+ const pkcs8Bags = p12.getBags({
119
+ bagType: forge.pki.oids["pkcs8ShroudedKeyBag"],
120
+ });
121
+ (0, globals_1.expect)(pkcs8Bags).toBeDefined();
122
+ const data = p12.getBags({ bagType: forge.pki.oids["certBag"] });
123
+ const certBags = (_a = data[forge.pki.oids["certBag"]]) !== null && _a !== void 0 ? _a : [];
124
+ const friendlyName = certBags[1].attributes.friendlyName[0];
125
+ let pkcs8 = (0, credentials_1.getKeyContainer)(pkcs8Bags, friendlyName);
126
+ (0, globals_1.expect)(pkcs8).toBeDefined();
127
+ }));
128
+ });
129
+ (0, globals_1.describe)("getKey", () => {
130
+ (0, globals_1.test)("should return key", () => __awaiter(void 0, void 0, void 0, function* () {
131
+ var _a;
132
+ (0, globals_1.expect)(CERT_PATH).toBeDefined();
133
+ (0, globals_1.expect)(CERT_KEY).toBeDefined();
134
+ (0, globals_1.expect)(arrayuint8).toBeDefined();
135
+ let p12 = (0, credentials_1.getP12)(arrayuint8, CERT_KEY);
136
+ const pkcs8Bags = p12.getBags({
137
+ bagType: forge.pki.oids["pkcs8ShroudedKeyBag"],
138
+ });
139
+ (0, globals_1.expect)(pkcs8Bags).toBeDefined();
140
+ const data = p12.getBags({ bagType: forge.pki.oids["certBag"] });
141
+ const certBags = (_a = data[forge.pki.oids["certBag"]]) !== null && _a !== void 0 ? _a : [];
142
+ const friendlyName = certBags[1].attributes.friendlyName[0];
143
+ let pkcs8 = (0, credentials_1.getKeyContainer)(pkcs8Bags, friendlyName);
144
+ (0, globals_1.expect)(pkcs8).toBeDefined();
145
+ let key = (0, credentials_1.getKey)(pkcs8);
146
+ (0, globals_1.expect)(key).toBeDefined();
147
+ const properties = Object.getOwnPropertyNames(key);
148
+ (0, globals_1.expect)(properties).toContain("n");
149
+ (0, globals_1.expect)(properties).toContain("e");
150
+ (0, globals_1.expect)(properties).toContain("d");
151
+ (0, globals_1.expect)(properties).toContain("sign");
152
+ }));
153
+ });
154
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ const files_1 = require("../../src/libs/files");
46
+ const globals_1 = require("@jest/globals");
47
+ const dotenv = __importStar(require("dotenv"));
48
+ const path = __importStar(require("path"));
49
+ dotenv.config();
50
+ const CERT_PATH = process.env.CERT_PATH;
51
+ (0, globals_1.describe)("FileManager", () => {
52
+ let fileManager;
53
+ (0, globals_1.beforeAll)(() => {
54
+ fileManager = new files_1.FileManager();
55
+ });
56
+ (0, globals_1.afterEach)(() => {
57
+ fileManager = new files_1.FileManager();
58
+ });
59
+ (0, globals_1.describe)("environment configuration", () => {
60
+ (0, globals_1.test)("CERT_PATH should be defined in environment", () => {
61
+ (0, globals_1.expect)(CERT_PATH).toBeDefined();
62
+ (0, globals_1.expect)(CERT_PATH).not.toBeNull();
63
+ (0, globals_1.expect)(typeof CERT_PATH).toBe("string");
64
+ });
65
+ (0, globals_1.test)("CERT_PATH should have .p12 extension", () => {
66
+ (0, globals_1.expect)(CERT_PATH).toMatch(/\.p12$/i);
67
+ });
68
+ (0, globals_1.test)("CERT_PATH should be a valid path format", () => {
69
+ (0, globals_1.expect)(CERT_PATH.length).toBeGreaterThan(0);
70
+ });
71
+ });
72
+ (0, globals_1.describe)("openFile method", () => {
73
+ (0, globals_1.test)("should successfully open a certificate file", () => __awaiter(void 0, void 0, void 0, function* () {
74
+ (0, globals_1.expect)(CERT_PATH).toBeDefined();
75
+ const result = yield fileManager.openFile(CERT_PATH);
76
+ (0, globals_1.expect)(result).toBe(fileManager);
77
+ }));
78
+ (0, globals_1.test)("should throw error for non-existent file", () => __awaiter(void 0, void 0, void 0, function* () {
79
+ const invalidPath = path.join(__dirname, "non-existent-cert.p12");
80
+ yield (0, globals_1.expect)(fileManager.openFile(invalidPath)).rejects.toThrow();
81
+ }));
82
+ (0, globals_1.test)("should load file as Buffer internally", () => __awaiter(void 0, void 0, void 0, function* () {
83
+ yield fileManager.openFile(CERT_PATH);
84
+ const buffer = fileManager.getFile();
85
+ (0, globals_1.expect)(buffer).toBeInstanceOf(Buffer);
86
+ (0, globals_1.expect)(buffer).not.toBeUndefined();
87
+ }));
88
+ });
89
+ (0, globals_1.describe)("getFile method", () => {
90
+ (0, globals_1.test)("should return undefined when no file is loaded", () => {
91
+ const buffer = fileManager.getFile();
92
+ (0, globals_1.expect)(buffer).toBeUndefined();
93
+ });
94
+ (0, globals_1.test)("should return Buffer after file is loaded", () => __awaiter(void 0, void 0, void 0, function* () {
95
+ yield fileManager.openFile(CERT_PATH);
96
+ const buffer = fileManager.getFile();
97
+ (0, globals_1.expect)(buffer).toBeInstanceOf(Buffer);
98
+ }));
99
+ (0, globals_1.test)("should return non-empty buffer for valid certificate", () => __awaiter(void 0, void 0, void 0, function* () {
100
+ yield fileManager.openFile(CERT_PATH);
101
+ const buffer = fileManager.getFile();
102
+ (0, globals_1.expect)(buffer === null || buffer === void 0 ? void 0 : buffer.length).toBeGreaterThan(0);
103
+ }));
104
+ });
105
+ (0, globals_1.describe)("toString method", () => {
106
+ (0, globals_1.test)("should throw error when file is not loaded", () => __awaiter(void 0, void 0, void 0, function* () {
107
+ const fm = new files_1.FileManager();
108
+ yield (0, globals_1.expect)(fm.toString("utf8")).rejects.toThrow("File data is not loaded. Please call openFile() first.");
109
+ }));
110
+ (0, globals_1.test)("should convert buffer to string with utf8 encoding", () => __awaiter(void 0, void 0, void 0, function* () {
111
+ yield fileManager.openFile(CERT_PATH);
112
+ // P12 files are binary, so this will have special characters
113
+ const result = yield fileManager.toString("utf8");
114
+ (0, globals_1.expect)(typeof result).toBe("string");
115
+ (0, globals_1.expect)(result.length).toBeGreaterThan(0);
116
+ }));
117
+ (0, globals_1.test)("should convert buffer to base64 encoding", () => __awaiter(void 0, void 0, void 0, function* () {
118
+ yield fileManager.openFile(CERT_PATH);
119
+ const base64Result = yield fileManager.toString("base64");
120
+ (0, globals_1.expect)(typeof base64Result).toBe("string");
121
+ // Base64 should only contain valid base64 characters
122
+ (0, globals_1.expect)(base64Result).toMatch(/^[A-Za-z0-9+/=]+$/);
123
+ }));
124
+ });
125
+ (0, globals_1.describe)("chaining and state management", () => {
126
+ (0, globals_1.test)("should allow method chaining with openFile", () => __awaiter(void 0, void 0, void 0, function* () {
127
+ const result = yield fileManager.openFile(CERT_PATH);
128
+ (0, globals_1.expect)(result).toBe(fileManager);
129
+ const buffer = fileManager.getFile();
130
+ (0, globals_1.expect)(buffer).toBeInstanceOf(Buffer);
131
+ }));
132
+ (0, globals_1.test)("should isolate state between instances", () => __awaiter(void 0, void 0, void 0, function* () {
133
+ const fm1 = new files_1.FileManager();
134
+ const fm2 = new files_1.FileManager();
135
+ yield fm1.openFile(CERT_PATH);
136
+ const buffer1 = fm1.getFile();
137
+ const buffer2 = fm2.getFile();
138
+ (0, globals_1.expect)(buffer1).toBeInstanceOf(Buffer);
139
+ (0, globals_1.expect)(buffer2).toBeUndefined();
140
+ }));
141
+ });
142
+ });
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "xades-bes-signer",
3
+ "version": "1.0.0",
4
+ "description": "XAdES-BES signer utilities for Node.js (TypeScript) — certificate handling and XAdES-BES signature helpers.",
5
+ "main": "/dist/src/main.js",
6
+ "types": "/dist/src/main.d.ts",
7
+ "files": ["dist", "README.md"],
8
+ "scripts": {
9
+ "start:dev": "npx nodemon",
10
+ "build": "npx tsc",
11
+ "lint": "eslint '{src,apps,libs,test}/**/*.ts' --fix",
12
+ "test": "jest"
13
+ },
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/gabriel-acuna/xades-bas-siggner.git"
17
+ },
18
+ "keywords": [
19
+ "XAdES-BES",
20
+ "TypeScript",
21
+ "SRI"
22
+ ],
23
+ "author": "Gabriel Acuña R",
24
+ "license": "MIT",
25
+ "bugs": {
26
+ "url": "https://github.com/gabriel-acuna/xades-bas-siggner/issues"
27
+ },
28
+ "homepage": "https://github.com/gabriel-acuna/xades-bas-siggner#readme",
29
+ "devDependencies": {
30
+ "@jest/globals": "^30.2.0",
31
+ "@types/jest": "^30.0.0",
32
+ "@types/node": "^20.8.2",
33
+ "@types/node-forge": "^1.3.6",
34
+ "eslint": "^8.50.0",
35
+ "jest": "^30.2.0",
36
+ "nodemon": "^3.0.1",
37
+ "ts-jest": "^29.4.5",
38
+ "ts-node": "^10.9.1",
39
+ "typescript": "^5.9.3"
40
+ },
41
+ "engines": {
42
+ "node": ">= 16"
43
+ },
44
+ "dependencies": {
45
+ "@types/dotenv": "^6.1.1",
46
+ "dotenv": "^17.2.3",
47
+ "node-forge": "^1.3.1"
48
+ }
49
+ }