ecwt 0.2.0-beta.3 → 0.2.0-beta.5
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 +26 -2
- package/dist/ecwt.cjs +22 -12
- package/package.json +3 -3
- package/src/factory.js +37 -16
- package/src/main.js +2 -0
- package/src/token.js +2 -0
- package/src/utils/base62.js +2 -0
- package/src/utils/errors.js +2 -0
- package/src/utils/time.js +2 -0
package/README.md
CHANGED
|
@@ -76,7 +76,8 @@ In our example, we use [valibot](https://valibot.dev) library.
|
|
|
76
76
|
```javascript
|
|
77
77
|
import * as v from 'valibot';
|
|
78
78
|
|
|
79
|
-
const schema =
|
|
79
|
+
const schema = v.parse.bind(
|
|
80
|
+
null,
|
|
80
81
|
v.object({
|
|
81
82
|
user_id: v.number([
|
|
82
83
|
v.maxValue(10),
|
|
@@ -85,7 +86,6 @@ const schema = (value) => v.parse(
|
|
|
85
86
|
v.maxLength(10),
|
|
86
87
|
]),
|
|
87
88
|
}),
|
|
88
|
-
value,
|
|
89
89
|
);
|
|
90
90
|
```
|
|
91
91
|
|
|
@@ -197,6 +197,30 @@ If the token is invalid, throws `EcwtInvalidError` which contains `Ecwt` instanc
|
|
|
197
197
|
const ecwt = await ecwtFactory.verify(token);
|
|
198
198
|
```
|
|
199
199
|
|
|
200
|
+
#### Class method `safeVerify`
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
safeVerify(
|
|
204
|
+
token: string,
|
|
205
|
+
): Promise<{
|
|
206
|
+
success: boolean,
|
|
207
|
+
ecwt: Ecwt | null,
|
|
208
|
+
}>
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
The same method as `verify`, but does not throw an error if the token is invalid, expired or revoked.
|
|
212
|
+
|
|
213
|
+
Property `success` is `true` if the token is valid.
|
|
214
|
+
|
|
215
|
+
Property `ecwt` is `null` if the token cannot be parsed, otherwise it contains `Ecwt` instance.
|
|
216
|
+
|
|
217
|
+
```javascript
|
|
218
|
+
const {
|
|
219
|
+
success,
|
|
220
|
+
ecwt,
|
|
221
|
+
} = await ecwtFactory.safeVerify(token);
|
|
222
|
+
```
|
|
223
|
+
|
|
200
224
|
### `Ecwt`
|
|
201
225
|
|
|
202
226
|
Represents the token. Its counstructor cannot be called by the user.
|
package/dist/ecwt.cjs
CHANGED
|
@@ -229,17 +229,17 @@ var EcwtFactory = class {
|
|
|
229
229
|
* @param {{ [key: string]: number }} [param0.options.senml_key_map] Payload object keys mapped for their SenML keys.
|
|
230
230
|
*/
|
|
231
231
|
constructor({
|
|
232
|
-
redisClient: redisClient2
|
|
233
|
-
lruCache
|
|
232
|
+
redisClient: redisClient2,
|
|
233
|
+
lruCache,
|
|
234
234
|
snowflakeFactory,
|
|
235
235
|
options: {
|
|
236
|
-
namespace
|
|
236
|
+
namespace,
|
|
237
237
|
key,
|
|
238
238
|
validator,
|
|
239
239
|
senml_key_map
|
|
240
240
|
}
|
|
241
241
|
}) {
|
|
242
|
-
if (redisClient2 !==
|
|
242
|
+
if (redisClient2 !== void 0 && (redisClient2.constructor.name !== redis_client_constructor_name || getAllKeysList(redisClient2) !== redis_client_keys)) {
|
|
243
243
|
throw new InvalidPackageInstanceError(
|
|
244
244
|
"redisClient",
|
|
245
245
|
"Commander extends RedisClient",
|
|
@@ -247,7 +247,7 @@ var EcwtFactory = class {
|
|
|
247
247
|
);
|
|
248
248
|
}
|
|
249
249
|
this.#redisClient = redisClient2;
|
|
250
|
-
if (lruCache !==
|
|
250
|
+
if (lruCache !== void 0 && lruCache instanceof import_lru_cache.LRUCache !== true) {
|
|
251
251
|
throw new InvalidPackageInstanceError(
|
|
252
252
|
"lruCache",
|
|
253
253
|
"LRUCache",
|
|
@@ -277,11 +277,11 @@ var EcwtFactory = class {
|
|
|
277
277
|
* @async
|
|
278
278
|
* @param {object} data Data to be stored in token.
|
|
279
279
|
* @param {object} [options] -
|
|
280
|
-
* @param {number} [options.ttl] Time to live in seconds. By default, token will never expire.
|
|
280
|
+
* @param {number | null} [options.ttl] Time to live in seconds. By default, token will never expire.
|
|
281
281
|
* @returns {Promise<Ecwt>} -
|
|
282
282
|
*/
|
|
283
283
|
async create(data, {
|
|
284
|
-
ttl
|
|
284
|
+
ttl = null
|
|
285
285
|
} = {}) {
|
|
286
286
|
if (typeof this.#validator === "function") {
|
|
287
287
|
data = this.#validator(data);
|
|
@@ -319,6 +319,11 @@ var EcwtFactory = class {
|
|
|
319
319
|
}
|
|
320
320
|
);
|
|
321
321
|
}
|
|
322
|
+
/**
|
|
323
|
+
* Sets data to cache.
|
|
324
|
+
* @param {string} token String representation of token.
|
|
325
|
+
* @param {object} data Data to be stored in cache.
|
|
326
|
+
*/
|
|
322
327
|
#setCache(token, data) {
|
|
323
328
|
this.#lruCache?.set(
|
|
324
329
|
token,
|
|
@@ -414,10 +419,10 @@ var EcwtFactory = class {
|
|
|
414
419
|
* Parses token without throwing errors.
|
|
415
420
|
* @async
|
|
416
421
|
* @param {string} token String representation of token.
|
|
417
|
-
* @returns {Promise<{ success:
|
|
422
|
+
* @returns {Promise<{ success: true, ecwt: Ecwt } | { success: false, ecwt: Ecwt | null }>} Returns whether token was parsed and verified successfully and Ecwt if parsed.
|
|
418
423
|
*/
|
|
419
424
|
async safeVerify(token) {
|
|
420
|
-
let ecwt;
|
|
425
|
+
let ecwt = null;
|
|
421
426
|
try {
|
|
422
427
|
ecwt = await this.verify(token);
|
|
423
428
|
return {
|
|
@@ -446,7 +451,7 @@ var EcwtFactory = class {
|
|
|
446
451
|
* @param {object} options -
|
|
447
452
|
* @param {string} options.token_id -
|
|
448
453
|
* @param {number} options.ts_ms_created -
|
|
449
|
-
* @param {number} options.ttl_initial -
|
|
454
|
+
* @param {number | null} options.ttl_initial -
|
|
450
455
|
* @returns {Promise<void>} -
|
|
451
456
|
*/
|
|
452
457
|
async _revoke({
|
|
@@ -458,12 +463,17 @@ var EcwtFactory = class {
|
|
|
458
463
|
ttl_initial = ttl_initial ?? Number.MAX_SAFE_INTEGER;
|
|
459
464
|
const ts_ms_expired = ts_ms_created + ttl_initial * 1e3;
|
|
460
465
|
if (ts_ms_expired > Date.now()) {
|
|
461
|
-
await this.#redisClient.
|
|
466
|
+
await this.#redisClient.MULTI().addCommand([
|
|
462
467
|
"ZADD",
|
|
463
468
|
this.#redis_keys.revoked,
|
|
464
469
|
String(ts_ms_expired),
|
|
465
470
|
token_id
|
|
466
|
-
])
|
|
471
|
+
]).addCommand([
|
|
472
|
+
"ZREMRANGEBYSCORE",
|
|
473
|
+
this.#redis_keys.revoked,
|
|
474
|
+
"-inf",
|
|
475
|
+
String(Date.now())
|
|
476
|
+
]).EXEC();
|
|
467
477
|
}
|
|
468
478
|
} else {
|
|
469
479
|
console.warn("[ecwt] Redis client is not provided. Tokens cannot be revoked.");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ecwt",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.5",
|
|
4
4
|
"description": "Encrypted CBOR-encoded Web Token",
|
|
5
5
|
"main": "src/main.js",
|
|
6
6
|
"type": "module",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"eslint-plugin-node": "11.1.0",
|
|
33
33
|
"eslint-plugin-promise": "6.1.1",
|
|
34
34
|
"eslint-plugin-unicorn": "47.0.0",
|
|
35
|
-
"valibot": "
|
|
36
|
-
"vitest": "1.
|
|
35
|
+
"valibot": "0.33",
|
|
36
|
+
"vitest": "1.6"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
39
|
"test": "bun run redis-up && bun test && npm run test-node",
|
package/src/factory.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
|
|
2
|
+
// @ts-check
|
|
3
|
+
|
|
2
4
|
import { SnowflakeFactory } from '@kirick/snowflake';
|
|
3
5
|
import {
|
|
4
6
|
Encoder as CborEncoder,
|
|
@@ -58,18 +60,18 @@ export class EcwtFactory {
|
|
|
58
60
|
* @param {{ [key: string]: number }} [param0.options.senml_key_map] Payload object keys mapped for their SenML keys.
|
|
59
61
|
*/
|
|
60
62
|
constructor({
|
|
61
|
-
redisClient
|
|
62
|
-
lruCache
|
|
63
|
+
redisClient,
|
|
64
|
+
lruCache,
|
|
63
65
|
snowflakeFactory,
|
|
64
66
|
options: {
|
|
65
|
-
namespace
|
|
67
|
+
namespace,
|
|
66
68
|
key,
|
|
67
69
|
validator,
|
|
68
70
|
senml_key_map,
|
|
69
71
|
},
|
|
70
72
|
}) {
|
|
71
73
|
if (
|
|
72
|
-
redisClient !==
|
|
74
|
+
redisClient !== undefined
|
|
73
75
|
&& (
|
|
74
76
|
redisClient.constructor.name !== redis_client_constructor_name
|
|
75
77
|
|| getAllKeysList(redisClient) !== redis_client_keys
|
|
@@ -84,7 +86,7 @@ export class EcwtFactory {
|
|
|
84
86
|
this.#redisClient = redisClient;
|
|
85
87
|
|
|
86
88
|
if (
|
|
87
|
-
lruCache !==
|
|
89
|
+
lruCache !== undefined
|
|
88
90
|
&& lruCache instanceof LRUCache !== true
|
|
89
91
|
) {
|
|
90
92
|
throw new InvalidPackageInstanceError(
|
|
@@ -122,13 +124,13 @@ export class EcwtFactory {
|
|
|
122
124
|
* @async
|
|
123
125
|
* @param {object} data Data to be stored in token.
|
|
124
126
|
* @param {object} [options] -
|
|
125
|
-
* @param {number} [options.ttl] Time to live in seconds. By default, token will never expire.
|
|
127
|
+
* @param {number | null} [options.ttl] Time to live in seconds. By default, token will never expire.
|
|
126
128
|
* @returns {Promise<Ecwt>} -
|
|
127
129
|
*/
|
|
128
130
|
async create(
|
|
129
131
|
data,
|
|
130
132
|
{
|
|
131
|
-
ttl,
|
|
133
|
+
ttl = null,
|
|
132
134
|
} = {},
|
|
133
135
|
) {
|
|
134
136
|
if (typeof this.#validator === 'function') {
|
|
@@ -181,6 +183,11 @@ export class EcwtFactory {
|
|
|
181
183
|
);
|
|
182
184
|
}
|
|
183
185
|
|
|
186
|
+
/**
|
|
187
|
+
* Sets data to cache.
|
|
188
|
+
* @param {string} token String representation of token.
|
|
189
|
+
* @param {object} data Data to be stored in cache.
|
|
190
|
+
*/
|
|
184
191
|
#setCache(token, data) {
|
|
185
192
|
this.#lruCache?.set(
|
|
186
193
|
token,
|
|
@@ -304,10 +311,10 @@ export class EcwtFactory {
|
|
|
304
311
|
* Parses token without throwing errors.
|
|
305
312
|
* @async
|
|
306
313
|
* @param {string} token String representation of token.
|
|
307
|
-
* @returns {Promise<{ success:
|
|
314
|
+
* @returns {Promise<{ success: true, ecwt: Ecwt } | { success: false, ecwt: Ecwt | null }>} Returns whether token was parsed and verified successfully and Ecwt if parsed.
|
|
308
315
|
*/
|
|
309
316
|
async safeVerify(token) {
|
|
310
|
-
let ecwt;
|
|
317
|
+
let ecwt = null;
|
|
311
318
|
try {
|
|
312
319
|
ecwt = await this.verify(token);
|
|
313
320
|
|
|
@@ -341,7 +348,7 @@ export class EcwtFactory {
|
|
|
341
348
|
* @param {object} options -
|
|
342
349
|
* @param {string} options.token_id -
|
|
343
350
|
* @param {number} options.ts_ms_created -
|
|
344
|
-
* @param {number} options.ttl_initial -
|
|
351
|
+
* @param {number | null} options.ttl_initial -
|
|
345
352
|
* @returns {Promise<void>} -
|
|
346
353
|
*/
|
|
347
354
|
async _revoke({
|
|
@@ -354,12 +361,26 @@ export class EcwtFactory {
|
|
|
354
361
|
|
|
355
362
|
const ts_ms_expired = ts_ms_created + (ttl_initial * 1000);
|
|
356
363
|
if (ts_ms_expired > Date.now()) {
|
|
357
|
-
await this.#redisClient.sendCommand([
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
]);
|
|
364
|
+
// await this.#redisClient.sendCommand([
|
|
365
|
+
// 'ZADD',
|
|
366
|
+
// this.#redis_keys.revoked,
|
|
367
|
+
// String(ts_ms_expired),
|
|
368
|
+
// token_id,
|
|
369
|
+
// ]);
|
|
370
|
+
await this.#redisClient.MULTI()
|
|
371
|
+
.addCommand([
|
|
372
|
+
'ZADD',
|
|
373
|
+
this.#redis_keys.revoked,
|
|
374
|
+
String(ts_ms_expired),
|
|
375
|
+
token_id,
|
|
376
|
+
])
|
|
377
|
+
.addCommand([
|
|
378
|
+
'ZREMRANGEBYSCORE',
|
|
379
|
+
this.#redis_keys.revoked,
|
|
380
|
+
'-inf',
|
|
381
|
+
String(Date.now()),
|
|
382
|
+
])
|
|
383
|
+
.EXEC();
|
|
363
384
|
}
|
|
364
385
|
}
|
|
365
386
|
else {
|
package/src/main.js
CHANGED
package/src/token.js
CHANGED
package/src/utils/base62.js
CHANGED
package/src/utils/errors.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
|
|
2
|
+
// @ts-check
|
|
3
|
+
|
|
2
4
|
export class InvalidPackageInstanceError extends TypeError {
|
|
3
5
|
constructor(property, class_name, package_name) {
|
|
4
6
|
super(`Value ${property} must be an instance of ${class_name} from package "${package_name}". That error is probably caused by two separate installations of "${package_name}". Please, make sure that "${package_name}" in your project is matches "peerDependencies" of "ecwt" package.`);
|