aziendasanitaria-utils 1.2.21 → 1.2.23
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/package.json +2 -1
- package/src/CryptHelper.js +135 -0
- package/src/narTsServices/Nar2.js +2 -2
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"engines": {
|
|
4
4
|
"node": ">=14.0.0"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.2.
|
|
6
|
+
"version": "1.2.23",
|
|
7
7
|
"repository": "deduzzo/aziendasanitaria-utils",
|
|
8
8
|
"description": "Un utility per gestire i flussi sanitari Siciliani e non solo..",
|
|
9
9
|
"main": "index.js",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"chokidar": "^4.0.3",
|
|
34
34
|
"cli-progress": "^3.12.0",
|
|
35
35
|
"cli-progress-footer": "^2.3.3",
|
|
36
|
+
"crypto": "^1.0.1",
|
|
36
37
|
"docx": "^9.1.1",
|
|
37
38
|
"eml-format": "^0.6.1",
|
|
38
39
|
"excel-date-to-js": "^1.1.5",
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
|
|
3
|
+
export const ENVELOPE_VERSION = "V1";
|
|
4
|
+
|
|
5
|
+
export default class CryptHelper {
|
|
6
|
+
|
|
7
|
+
static generateIv() {
|
|
8
|
+
return crypto.randomBytes(16);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
static async RSAGenerateKeyPair() {
|
|
12
|
+
const {publicKey, privateKey} = await crypto.generateKeyPairSync('rsa', {
|
|
13
|
+
modulusLength: 2048,
|
|
14
|
+
publicKeyEncoding: {
|
|
15
|
+
type: 'spki',
|
|
16
|
+
format: 'pem'
|
|
17
|
+
},
|
|
18
|
+
privateKeyEncoding: {
|
|
19
|
+
type: 'pkcs8',
|
|
20
|
+
format: 'pem'
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
return {publicKey, privateKey};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
static RSAEncrypt(data, publicKey) {
|
|
27
|
+
const bufferData = Buffer.from(data, 'utf8'); // Convert string to Buffer
|
|
28
|
+
const encrypted = crypto.publicEncrypt({
|
|
29
|
+
key: publicKey,
|
|
30
|
+
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING
|
|
31
|
+
}, bufferData);
|
|
32
|
+
return encrypted.toString('base64'); // Return as base64 string for easy storage/transfer
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static RSADecrypt(data, privateKey) {
|
|
36
|
+
const bufferData = Buffer.from(data, 'base64'); // Convert base64 string to Buffer
|
|
37
|
+
const decrypted = crypto.privateDecrypt({
|
|
38
|
+
key: privateKey,
|
|
39
|
+
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING
|
|
40
|
+
}, bufferData);
|
|
41
|
+
return decrypted.toString('utf8'); // Convert Buffer back to string
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static RSASign(data, privateKey) {
|
|
45
|
+
const sign = crypto.createSign('SHA256');
|
|
46
|
+
sign.update(data);
|
|
47
|
+
sign.end();
|
|
48
|
+
return sign.sign(privateKey, 'base64');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
static RSASignVerify(data, signature, publicKey) {
|
|
52
|
+
const verify = crypto.createVerify('SHA256');
|
|
53
|
+
verify.update(data);
|
|
54
|
+
verify.end();
|
|
55
|
+
return verify.verify(publicKey, signature, 'base64');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
static AESGenerateKey(keySize = 256) {
|
|
59
|
+
return crypto.randomBytes(keySize / 8).toString('base64');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
static AESEncrypt(data, keyBase64, iv) {
|
|
63
|
+
const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(keyBase64, 'base64'), iv);
|
|
64
|
+
let encrypted = cipher.update(data, 'utf8', 'base64');
|
|
65
|
+
encrypted += cipher.final('base64');
|
|
66
|
+
return encrypted;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
static AESDecrypt(encryptedData, keyBase64, iv) {
|
|
70
|
+
const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(keyBase64, 'base64'), iv);
|
|
71
|
+
let decrypted = decipher.update(encryptedData, 'base64', 'utf8');
|
|
72
|
+
decrypted += decipher.final('utf8');
|
|
73
|
+
return decrypted;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
static convertStringToByte(message) {
|
|
77
|
+
return Buffer.from(message, 'utf8');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
static convertBase64StringToByte(data) {
|
|
81
|
+
return Buffer.from(data, 'base64');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
static convertByteToBase64String(data) {
|
|
85
|
+
return Buffer.from(data).toString('base64');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
static hash(data) {
|
|
89
|
+
return crypto.createHash('md5').update(data).digest('hex');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
static generateHMAC(data, key) {
|
|
93
|
+
const hmac = crypto.createHmac('sha256', key);
|
|
94
|
+
hmac.update(data);
|
|
95
|
+
return hmac.digest('base64');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
static async encryptAndSend(message, newVersion, publicKey = null, privateKey = null,AESKey = null) {
|
|
99
|
+
if (!publicKey) {
|
|
100
|
+
({publicKey, privateKey} = await CryptHelper.RSAGenerateKeyPair());
|
|
101
|
+
}
|
|
102
|
+
if (!AESKey) {
|
|
103
|
+
AESKey = CryptHelper.AESGenerateKey();
|
|
104
|
+
}
|
|
105
|
+
let iv = CryptHelper.generateIv();
|
|
106
|
+
|
|
107
|
+
let encryptedAESKey = CryptHelper.RSAEncrypt(AESKey, publicKey);
|
|
108
|
+
let encryptedMessage = CryptHelper.AESEncrypt(message, AESKey, iv);
|
|
109
|
+
let hmac = CryptHelper.generateHMAC(encryptedMessage, AESKey);
|
|
110
|
+
|
|
111
|
+
let data = {
|
|
112
|
+
message: encryptedMessage,
|
|
113
|
+
key: encryptedAESKey,
|
|
114
|
+
iv: iv.toString('base64'),
|
|
115
|
+
hmac: hmac,
|
|
116
|
+
messageVersion: newVersion,
|
|
117
|
+
envelopeVersion: ENVELOPE_VERSION
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
return {privateKey, publicKey, AESKey, data, originalMessage: message};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
static async receiveAndDecrypt(data, privateKey) {
|
|
124
|
+
let decryptedAESKey = CryptHelper.RSADecrypt(data.key, privateKey);
|
|
125
|
+
let iv = Buffer.from(data.iv, 'base64');
|
|
126
|
+
|
|
127
|
+
// Verify HMAC first
|
|
128
|
+
let recalculatedHmac = CryptHelper.generateHMAC(data.message, decryptedAESKey);
|
|
129
|
+
if (recalculatedHmac !== data.hmac) {
|
|
130
|
+
throw new Error('Data integrity check failed');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return CryptHelper.AESDecrypt(data.message, decryptedAESKey, iv);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -253,10 +253,10 @@ export class Nar2 {
|
|
|
253
253
|
});
|
|
254
254
|
} else {
|
|
255
255
|
out = await axios.get(Nar2.GET_WS_FALLBACK_INTERNAL.replace("{cf}", cf).replace("{token}", Nar2.#token).replace("{type}", "sogei"));
|
|
256
|
-
out = out.sogei;
|
|
256
|
+
out.data = {status: out.data.sogei.status || false, data: out.data.sogei.data};
|
|
257
257
|
}
|
|
258
258
|
|
|
259
|
-
if (out.data === undefined || out.data.status.toString().toLowerCase().includes("token is invalid"))
|
|
259
|
+
if (!out.data || out.data === undefined || (fallback && out.data.status.toString().toLowerCase().includes("token is invalid")))
|
|
260
260
|
await this.getToken(true);
|
|
261
261
|
else if (out.data.status.toString() !== "true" && out.data.listaMessaggi.p801descrizioneMessaggio.includes("errato")) {
|
|
262
262
|
assistito.okTs = false;
|