@tc-libs/helper 4.0.0 → 4.1.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/README.md +272 -0
- package/package.json +11 -9
package/README.md
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
# @tc-libs/helper
|
|
2
|
+
|
|
3
|
+
Package di utilita condivise per NestJS. Espone un `HelperModule` registrabile e una serie di servizi iniettabili per:
|
|
4
|
+
|
|
5
|
+
- date e intervalli temporali
|
|
6
|
+
- stringhe, slug, password e riferimenti casuali
|
|
7
|
+
- numeri e percentuali
|
|
8
|
+
- hashing
|
|
9
|
+
- cifratura Base64, AES e JWT
|
|
10
|
+
- gestione access token, refresh token e permission token
|
|
11
|
+
- controlli geografici su raggio
|
|
12
|
+
|
|
13
|
+
## Quando usarlo
|
|
14
|
+
|
|
15
|
+
Usa questa libreria quando vuoi centralizzare logica tecnica riusabile invece di duplicare helper statici nei singoli servizi applicativi.
|
|
16
|
+
|
|
17
|
+
I package `authentication`, `pagination`, `request`, `setting`, `task` e altri dipendono gia da questi servizi.
|
|
18
|
+
|
|
19
|
+
## Installazione nel modulo Nest
|
|
20
|
+
|
|
21
|
+
### Registrazione sincrona
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { Module } from '@nestjs/common';
|
|
25
|
+
import { HelperModule } from '@tc-libs/helper';
|
|
26
|
+
|
|
27
|
+
@Module({
|
|
28
|
+
imports: [
|
|
29
|
+
HelperModule.register(
|
|
30
|
+
{
|
|
31
|
+
jwt: {
|
|
32
|
+
defaultSecretKey: process.env.JWT_DEFAULT_SECRET!,
|
|
33
|
+
defaultExpirationTime: 3600,
|
|
34
|
+
},
|
|
35
|
+
auth: {
|
|
36
|
+
subject: 'access',
|
|
37
|
+
audience: 'my-api',
|
|
38
|
+
issuer: 'my-service',
|
|
39
|
+
accessToken: {
|
|
40
|
+
secretKey: process.env.ACCESS_TOKEN_SECRET!,
|
|
41
|
+
expirationTime: 3600,
|
|
42
|
+
notBeforeExpirationTime: 0,
|
|
43
|
+
encryptKey: process.env.ACCESS_TOKEN_ENCRYPT_KEY!,
|
|
44
|
+
encryptIv: process.env.ACCESS_TOKEN_ENCRYPT_IV!,
|
|
45
|
+
},
|
|
46
|
+
refreshToken: {
|
|
47
|
+
secretKey: process.env.REFRESH_TOKEN_SECRET!,
|
|
48
|
+
expirationTime: 86400,
|
|
49
|
+
expirationTimeRememberMe: 2592000,
|
|
50
|
+
notBeforeExpirationTime: 0,
|
|
51
|
+
encryptKey: process.env.REFRESH_TOKEN_ENCRYPT_KEY!,
|
|
52
|
+
encryptIv: process.env.REFRESH_TOKEN_ENCRYPT_IV!,
|
|
53
|
+
},
|
|
54
|
+
permissionToken: {
|
|
55
|
+
secretKey: process.env.PERMISSION_TOKEN_SECRET!,
|
|
56
|
+
expirationTime: 900,
|
|
57
|
+
notBeforeExpirationTime: 0,
|
|
58
|
+
encryptKey: process.env.PERMISSION_TOKEN_ENCRYPT_KEY!,
|
|
59
|
+
encryptIv: process.env.PERMISSION_TOKEN_ENCRYPT_IV!,
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
true,
|
|
64
|
+
),
|
|
65
|
+
],
|
|
66
|
+
})
|
|
67
|
+
export class AppModule {}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Registrazione asincrona
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
HelperModule.registerAsync(
|
|
74
|
+
{
|
|
75
|
+
imports: [ConfigModule],
|
|
76
|
+
inject: [ConfigService],
|
|
77
|
+
useFactory: async (configService: ConfigService) => ({
|
|
78
|
+
jwt: {
|
|
79
|
+
defaultSecretKey: configService.getOrThrow<string>('JWT_DEFAULT_SECRET'),
|
|
80
|
+
defaultExpirationTime: 3600,
|
|
81
|
+
},
|
|
82
|
+
auth: {
|
|
83
|
+
subject: 'access',
|
|
84
|
+
audience: 'my-api',
|
|
85
|
+
issuer: 'my-service',
|
|
86
|
+
accessToken: {
|
|
87
|
+
secretKey: configService.getOrThrow<string>('ACCESS_TOKEN_SECRET'),
|
|
88
|
+
expirationTime: 3600,
|
|
89
|
+
notBeforeExpirationTime: 0,
|
|
90
|
+
encryptKey: configService.getOrThrow<string>('ACCESS_TOKEN_ENCRYPT_KEY'),
|
|
91
|
+
encryptIv: configService.getOrThrow<string>('ACCESS_TOKEN_ENCRYPT_IV'),
|
|
92
|
+
},
|
|
93
|
+
refreshToken: {
|
|
94
|
+
secretKey: configService.getOrThrow<string>('REFRESH_TOKEN_SECRET'),
|
|
95
|
+
expirationTime: 86400,
|
|
96
|
+
expirationTimeRememberMe: 2592000,
|
|
97
|
+
notBeforeExpirationTime: 0,
|
|
98
|
+
encryptKey: configService.getOrThrow<string>('REFRESH_TOKEN_ENCRYPT_KEY'),
|
|
99
|
+
encryptIv: configService.getOrThrow<string>('REFRESH_TOKEN_ENCRYPT_IV'),
|
|
100
|
+
},
|
|
101
|
+
permissionToken: {
|
|
102
|
+
secretKey: configService.getOrThrow<string>('PERMISSION_TOKEN_SECRET'),
|
|
103
|
+
expirationTime: 900,
|
|
104
|
+
notBeforeExpirationTime: 0,
|
|
105
|
+
encryptKey: configService.getOrThrow<string>('PERMISSION_TOKEN_ENCRYPT_KEY'),
|
|
106
|
+
encryptIv: configService.getOrThrow<string>('PERMISSION_TOKEN_ENCRYPT_IV'),
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
}),
|
|
110
|
+
},
|
|
111
|
+
true,
|
|
112
|
+
);
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Servizi esportati
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
import {
|
|
119
|
+
DateService,
|
|
120
|
+
EncryptionService,
|
|
121
|
+
GeoService,
|
|
122
|
+
HashService,
|
|
123
|
+
NumberService,
|
|
124
|
+
PasswordService,
|
|
125
|
+
StringService,
|
|
126
|
+
TokenService,
|
|
127
|
+
} from '@tc-libs/helper';
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### `DateService`
|
|
131
|
+
|
|
132
|
+
Operazioni principali:
|
|
133
|
+
|
|
134
|
+
- validazione date e timestamp
|
|
135
|
+
- formattazione
|
|
136
|
+
- differenze tra date in giorni, minuti, ore, secondi o millisecondi
|
|
137
|
+
- forward/backward di intervalli temporali
|
|
138
|
+
- start/end di giorno, mese e anno
|
|
139
|
+
- estrazione di giorno, mese e anno
|
|
140
|
+
|
|
141
|
+
Esempio:
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
const expiresAt = this.dateService.forwardInMinutes(15);
|
|
145
|
+
const age = this.dateService.calculateAge(user.birthDate);
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### `StringService`
|
|
149
|
+
|
|
150
|
+
Operazioni principali:
|
|
151
|
+
|
|
152
|
+
- validazione email
|
|
153
|
+
- generazione stringhe casuali e riferimenti
|
|
154
|
+
- controllo robustezza password
|
|
155
|
+
- censura di valori sensibili
|
|
156
|
+
- slugify
|
|
157
|
+
|
|
158
|
+
Esempio:
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
const slug = this.stringService.slugify('Listino Prezzi 2026');
|
|
162
|
+
const reference = this.stringService.randomReference(6, 'ORD');
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### `NumberService`
|
|
166
|
+
|
|
167
|
+
Operazioni principali:
|
|
168
|
+
|
|
169
|
+
- check di numeri interi o reali in input stringa
|
|
170
|
+
- conversione a `number`
|
|
171
|
+
- generazione random
|
|
172
|
+
- calcolo percentuali
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
const code = this.numberService.random(6);
|
|
176
|
+
const completion = this.numberService.percent(done, total);
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### `HashService`
|
|
180
|
+
|
|
181
|
+
Espone:
|
|
182
|
+
|
|
183
|
+
- `sha1Base64`
|
|
184
|
+
- `sha256`
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
const digest = this.hashService.sha256(payload);
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### `PasswordService`
|
|
191
|
+
|
|
192
|
+
Wrapper su `bcryptjs` per hashing e confronto password:
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
const hashed = await this.passwordService.hashPassword(plainPassword);
|
|
196
|
+
const isValid = await this.passwordService.compare(plainPassword, hashed);
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### `EncryptionService`
|
|
200
|
+
|
|
201
|
+
Espone primitive per:
|
|
202
|
+
|
|
203
|
+
- Base64 encode/decode
|
|
204
|
+
- AES-256 CBC encrypt/decrypt
|
|
205
|
+
- sign, decode e verify JWT
|
|
206
|
+
|
|
207
|
+
```ts
|
|
208
|
+
const encrypted = this.encryptionService.aes256Encrypt(data, key, iv);
|
|
209
|
+
const token = this.encryptionService.jwtEncrypt(payload, {
|
|
210
|
+
secretKey,
|
|
211
|
+
expiredIn: 3600,
|
|
212
|
+
audience: 'my-api',
|
|
213
|
+
issuer: 'my-service',
|
|
214
|
+
subject: 'access',
|
|
215
|
+
});
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### `TokenService`
|
|
219
|
+
|
|
220
|
+
Servizio ad alto livello costruito sopra `EncryptionService` e configurazione `auth`.
|
|
221
|
+
|
|
222
|
+
Casi d'uso principali:
|
|
223
|
+
|
|
224
|
+
- creare access token
|
|
225
|
+
- creare refresh token con supporto `rememberMe`
|
|
226
|
+
- creare permission token
|
|
227
|
+
- validare token
|
|
228
|
+
- leggere payload JWT
|
|
229
|
+
- cifrare/decifrare il payload contenuto nei token
|
|
230
|
+
|
|
231
|
+
```ts
|
|
232
|
+
const payload = this.tokenService.createPayloadAccessToken(
|
|
233
|
+
{ user: user._id, email: user.email },
|
|
234
|
+
false,
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
const encryptedPayload = await this.tokenService.encryptAccessToken(payload);
|
|
238
|
+
const accessToken = this.tokenService.createAccessToken(encryptedPayload);
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### `GeoService`
|
|
242
|
+
|
|
243
|
+
Controlla se un punto e dentro un raggio espresso in metri:
|
|
244
|
+
|
|
245
|
+
```ts
|
|
246
|
+
const allowed = this.geoService.inRadius(
|
|
247
|
+
{ latitude: 45.4642, longitude: 9.19, radiusInMeters: 500 },
|
|
248
|
+
{ latitude: 45.465, longitude: 9.191 },
|
|
249
|
+
);
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## Export aggiuntivi
|
|
253
|
+
|
|
254
|
+
Oltre ai servizi, il package esporta:
|
|
255
|
+
|
|
256
|
+
- interfacce per date, stringhe, numeri, cifratura e token
|
|
257
|
+
- costanti data come `ENUM_DATE_FORMAT` e `ENUM_DATE_DIFF`
|
|
258
|
+
- token di configurazione `HELPER_CONFIG_OPTIONS`
|
|
259
|
+
- tipi `HelperOptions` e `HelperAsyncOptions`
|
|
260
|
+
|
|
261
|
+
## Note operative
|
|
262
|
+
|
|
263
|
+
- `TokenService` dipende dalla registrazione di `HelperModule` con configurazione completa.
|
|
264
|
+
- `EncryptionService` usa `JwtService`, quindi va risolto tramite DI Nest invece di essere istanziato manualmente.
|
|
265
|
+
- Le chiavi AES e gli IV devono essere coerenti con il formato atteso dall'applicazione che produce/consuma i token.
|
|
266
|
+
|
|
267
|
+
## Sviluppo
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
nx build helper
|
|
271
|
+
nx test helper
|
|
272
|
+
```
|
package/package.json
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tc-libs/helper",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"dependencies": {
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"@nestjs/common": "^11.0.12",
|
|
8
|
-
"@nestjs/jwt": "^11.0.0",
|
|
9
|
-
"moment": "^2.30.1",
|
|
5
|
+
"@faker-js/faker": "^9.6.0",
|
|
6
|
+
"bcryptjs": "^3.0.2",
|
|
10
7
|
"crypto-js": "^4.2.0",
|
|
11
8
|
"geolib": "^3.3.4",
|
|
12
|
-
"
|
|
13
|
-
"
|
|
9
|
+
"moment": "^2.30.1",
|
|
10
|
+
"ms": "^2.1.3",
|
|
11
|
+
"tslib": "^2.8.1"
|
|
14
12
|
},
|
|
15
13
|
"type": "commonjs",
|
|
16
14
|
"main": "./src/index.js",
|
|
17
15
|
"typings": "./src/index.d.ts",
|
|
18
|
-
"
|
|
16
|
+
"peerDependencies": {
|
|
17
|
+
"@nestjs/common": "^11.0.12",
|
|
18
|
+
"@nestjs/jwt": "^11.0.0"
|
|
19
|
+
},
|
|
20
|
+
"types": "./src/index.d.ts"
|
|
19
21
|
}
|