ecwt 0.1.0-beta.3 → 0.1.1-beta.2

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 CHANGED
@@ -147,19 +147,24 @@ create(
147
147
  [key: string]: any,
148
148
  },
149
149
  options: {
150
- ttl: number?,
150
+ ttl: number | null,
151
151
  }
152
152
  ): Promise<Ecwt>
153
153
  ```
154
154
 
155
155
  Creates a token.
156
156
 
157
- `options.ttl` specifies the time to live of the token in seconds. If not specified, the token will not expire.
157
+ `options.ttl` specifies the time to live of the token in seconds. If set to null, token will never expire.
158
+
159
+ > **Be careful with `ttl = null`!**
160
+ >
161
+ > Revoked tokens are stored in Redis until they expire. Never-expiring tokens will be stored in Redis **forever**, which will lead to uncontrolled Redis database growth.
158
162
 
159
163
  Returns `Ecwt` instance.
160
164
 
161
165
  ```javascript
162
- const ecwt_token = await ecwtFactory.create(
166
+ // Example
167
+ const ecwt = await ecwtFactory.create(
163
168
  {
164
169
  user_id: 1,
165
170
  nick: 'kirick',
@@ -190,40 +195,44 @@ Returns `Ecwt` instance.
190
195
  If the token is invalid, throws `EcwtInvalidError` which contains `Ecwt` instance in the `ecwt` property.
191
196
 
192
197
  ```javascript
193
- const ecwt_token = await ecwtFactory.verify(token);
198
+ const ecwt = await ecwtFactory.verify(token);
194
199
  ```
195
200
 
196
201
  ### `Ecwt`
197
202
 
198
- Represents the token. It cannot be created by the user.
203
+ Represents the token. Its counstructor cannot be called by the user.
199
204
 
200
205
  ```javascript
201
206
  import { Ecwt } from 'ecwt';
202
207
  ```
203
208
 
204
- #### Class property `token: string`
209
+ #### Class property `readonly token: string`
205
210
 
206
211
  The string representation of the token.
207
212
 
208
- #### Class property `id: string`
213
+ #### Class property `readonly id: string`
209
214
 
210
215
  The unique ID of the token.
211
216
 
212
- #### Class property `snowflake: Snowflake`
217
+ #### Class property `readonly snowflake: Snowflake`
213
218
 
214
219
  The `Snowflake` instance of the token. For documentation, see [snowflake-js repository](https://github.com/kirick13/snowflake-js).
215
220
 
216
- #### Class property `ts_expired: number`
221
+ #### Class property `readonly ts_expired: number | null`
217
222
 
218
- The timestamp of the token expiration in seconds. If the token does not expire, it is `Number.POSITIVE_INFINITY`.
223
+ The timestamp of the token expiration in seconds. Equals to `null` if the token does not expire.
219
224
 
220
- #### Class property `ttl: number`
225
+ #### Class property `readonly data: { [key: string]: any }`
221
226
 
222
- Current the time to live of the token in seconds. If the token does not expire, it is `Number.POSITIVE_INFINITY`.
227
+ The payload of the token.
223
228
 
224
- #### Class property `data: { [key: string]: any }`
229
+ #### Class method `getTTL`
225
230
 
226
- The payload of the token.
231
+ ```typescript
232
+ getTTL(): number | null
233
+ ```
234
+
235
+ Returns current the time to live of the token in seconds. If the token does not expire, returns `null`.
227
236
 
228
237
  #### Class method `revoke`
229
238
 
@@ -231,4 +240,4 @@ The payload of the token.
231
240
  revoke(): Promise<void>
232
241
  ```
233
242
 
234
- Revokes the token. It will be impossible to verify it after that.
243
+ Revokes the token. Attempts to verify the revoked token will throw `EcwtRevokedError`.
package/dist/ecwt.cjs CHANGED
@@ -30,7 +30,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  var main_exports = {};
31
31
  __export(main_exports, {
32
32
  Ecwt: () => Ecwt,
33
- EcwtFactory: () => EcwtFactory
33
+ EcwtExpiredError: () => EcwtExpiredError,
34
+ EcwtFactory: () => EcwtFactory,
35
+ EcwtInvalidError: () => EcwtInvalidError,
36
+ EcwtRevokedError: () => EcwtRevokedError
34
37
  });
35
38
  module.exports = __toCommonJS(main_exports);
36
39
 
@@ -47,18 +50,57 @@ function toSeconds(value) {
47
50
  }
48
51
 
49
52
  // src/token.js
53
+ function assign(target, key, value) {
54
+ Object.defineProperty(
55
+ target,
56
+ key,
57
+ {
58
+ value,
59
+ enumerable: true,
60
+ writable: false,
61
+ configurable: false
62
+ }
63
+ );
64
+ }
50
65
  var Ecwt = class {
51
66
  #ecwtFactory;
52
- #token;
53
- #snowflake;
54
67
  #ttl_initial;
55
- #data;
68
+ /**
69
+ * Token string representation.
70
+ * @type {string}
71
+ * @readonly
72
+ */
73
+ token;
74
+ /**
75
+ * Token ID.
76
+ * @type {string}
77
+ * @readonly
78
+ */
79
+ id;
80
+ /**
81
+ * Snowflake associated with token.
82
+ * @type {Snowflake}
83
+ * @readonly
84
+ */
85
+ snowflake;
86
+ /**
87
+ * Timestamp when token expires in seconds.
88
+ * @type {number?}
89
+ * @readonly
90
+ */
91
+ ts_expired;
92
+ /**
93
+ * Data stored in token.
94
+ * @type {{ [key: string]: any }}
95
+ * @readonly
96
+ */
97
+ data;
56
98
  /**
57
99
  * @param {EcwtFactory} ecwtFactory -
58
100
  * @param {object} options -
59
101
  * @param {string} options.token String representation of token.
60
102
  * @param {Snowflake} options.snowflake -
61
- * @param {number | null} options.ttl_initial Time to live in seconds at the moment of token creation.
103
+ * @param {number?} options.ttl_initial Time to live in seconds at the moment of token creation.
62
104
  * @param {object} options.data Data stored in token.
63
105
  */
64
106
  constructor(ecwtFactory, {
@@ -68,45 +110,46 @@ var Ecwt = class {
68
110
  data
69
111
  }) {
70
112
  this.#ecwtFactory = ecwtFactory;
71
- this.#token = token;
72
- this.#snowflake = snowflake;
73
113
  this.#ttl_initial = ttl_initial;
74
- this.#data = Object.freeze(data);
75
- }
76
- get token() {
77
- return this.#token;
78
- }
79
- get id() {
80
- return this.#snowflake.base62;
81
- }
82
- get snowflake() {
83
- return this.#snowflake;
114
+ assign(this, "token", token);
115
+ assign(
116
+ this,
117
+ "id",
118
+ snowflake.toBase62()
119
+ );
120
+ assign(this, "snowflake", snowflake);
121
+ assign(
122
+ this,
123
+ "ts_expired",
124
+ this.#getTimestampExpired()
125
+ );
126
+ assign(
127
+ this,
128
+ "data",
129
+ Object.freeze(data)
130
+ );
84
131
  }
85
- get ts_expired() {
132
+ #getTimestampExpired() {
86
133
  if (this.#ttl_initial === null) {
87
- return Number.POSITIVE_INFINITY;
134
+ return null;
88
135
  }
89
- return toSeconds(this.#snowflake.timestamp) + this.#ttl_initial;
136
+ return toSeconds(this.snowflake.timestamp) + this.#ttl_initial;
90
137
  }
91
138
  /**
92
- * Time to live in seconds.
93
- * @type {number}
94
- * @readonly
139
+ * Actual time to live in seconds.
140
+ * @returns {number | null} -
95
141
  */
96
- get ttl() {
142
+ getTTL() {
97
143
  if (this.#ttl_initial === null) {
98
- return Number.POSITIVE_INFINITY;
144
+ return null;
99
145
  }
100
- return this.#ttl_initial - toSeconds(Date.now() - this.#snowflake.timestamp);
101
- }
102
- get data() {
103
- return this.#data;
146
+ return this.#ttl_initial - toSeconds(Date.now() - this.snowflake.timestamp);
104
147
  }
105
148
  /* async */
106
149
  revoke() {
107
150
  return this.#ecwtFactory._revoke({
108
151
  token_id: this.id,
109
- ts_ms_created: this.#snowflake.timestamp,
152
+ ts_ms_created: this.snowflake.timestamp,
110
153
  ttl_initial: this.#ttl_initial
111
154
  });
112
155
  }
@@ -233,12 +276,12 @@ var EcwtFactory = class {
233
276
  }
234
277
  payload.push(value);
235
278
  }
236
- if (typeof ttl !== "number" && Number.isNaN(ttl) !== true || ttl === Number.POSITIVE_INFINITY) {
237
- ttl = null;
279
+ if (typeof ttl !== "number" && Number.isNaN(ttl) !== true && ttl !== null) {
280
+ throw new TypeError("TTL must be a number or null.");
238
281
  }
239
282
  const snowflake = await this.#snowflakeFactory.createSafe();
240
283
  const token_raw = (0, import_cbor_x.encode)([
241
- snowflake.buffer,
284
+ snowflake.toBuffer(),
242
285
  ttl,
243
286
  payload
244
287
  ]);
@@ -360,6 +403,7 @@ var EcwtFactory = class {
360
403
  ttl_initial
361
404
  }) {
362
405
  if (this.#redisClient) {
406
+ ttl_initial = ttl_initial ?? Number.MAX_SAFE_INTEGER;
363
407
  const ts_ms_expired = ts_ms_created + ttl_initial * 1e3;
364
408
  if (ts_ms_expired > Date.now()) {
365
409
  await this.#redisClient.sendCommand([
@@ -385,5 +429,8 @@ var EcwtFactory = class {
385
429
  // Annotate the CommonJS export names for ESM import in node:
386
430
  0 && (module.exports = {
387
431
  Ecwt,
388
- EcwtFactory
432
+ EcwtExpiredError,
433
+ EcwtFactory,
434
+ EcwtInvalidError,
435
+ EcwtRevokedError
389
436
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ecwt",
3
- "version": "0.1.0-beta.3",
3
+ "version": "0.1.1-beta.2",
4
4
  "description": "Encrypted CBOR-encoded Web Token",
5
5
  "main": "src/main.js",
6
6
  "type": "module",
@@ -19,7 +19,7 @@
19
19
  "evilcrypt": "0.2.0-beta.4"
20
20
  },
21
21
  "peerDependencies": {
22
- "@kirick/snowflake": "^0.2.0-beta.7",
22
+ "@kirick/snowflake": "^0.2.1-beta.1",
23
23
  "lru-cache": "^7 || ^8 || ^9 || ^10",
24
24
  "redis": "^4"
25
25
  },
package/src/factory.js CHANGED
@@ -137,19 +137,17 @@ export class EcwtFactory {
137
137
  }
138
138
 
139
139
  if (
140
- (
141
- typeof ttl !== 'number'
142
- && Number.isNaN(ttl) !== true
143
- )
144
- || ttl === Number.POSITIVE_INFINITY
140
+ typeof ttl !== 'number'
141
+ && Number.isNaN(ttl) !== true
142
+ && ttl !== null
145
143
  ) {
146
- ttl = null;
144
+ throw new TypeError('TTL must be a number or null.');
147
145
  }
148
146
 
149
147
  const snowflake = await this.#snowflakeFactory.createSafe();
150
148
 
151
149
  const token_raw = cborEncode([
152
- snowflake.buffer,
150
+ snowflake.toBuffer(),
153
151
  ttl,
154
152
  payload,
155
153
  ]);
@@ -299,6 +297,8 @@ export class EcwtFactory {
299
297
  ttl_initial,
300
298
  }) {
301
299
  if (this.#redisClient) {
300
+ ttl_initial = ttl_initial ?? Number.MAX_SAFE_INTEGER;
301
+
302
302
  const ts_ms_expired = ts_ms_created + (ttl_initial * 1000);
303
303
  if (ts_ms_expired > Date.now()) {
304
304
  await this.#redisClient.sendCommand([
package/src/main.js CHANGED
@@ -1,3 +1,8 @@
1
1
 
2
2
  export { EcwtFactory } from './factory.js';
3
3
  export { Ecwt } from './token.js';
4
+ export {
5
+ EcwtInvalidError,
6
+ EcwtExpiredError,
7
+ EcwtRevokedError,
8
+ } from './utils/errors.js';
package/src/token.js CHANGED
@@ -2,24 +2,70 @@
2
2
  import { toSeconds } from './utils/time.js';
3
3
 
4
4
  /**
5
- * @typedef {import('@kirick/snowflake/src/snowflake.js').Snowflake} Snowflake
5
+ * @typedef {import('@kirick/snowflake').Snowflake} Snowflake
6
6
  * @typedef {import('./factory.js').EcwtFactory} EcwtFactory
7
7
  */
8
8
 
9
+ /**
10
+ * Assigns property to object.
11
+ * @param {object} target -
12
+ * @param {string} key -
13
+ * @param {any} value -
14
+ */
15
+ function assign(target, key, value) {
16
+ Object.defineProperty(
17
+ target,
18
+ key,
19
+ {
20
+ value,
21
+ enumerable: true,
22
+ writable: false,
23
+ configurable: false,
24
+ },
25
+ );
26
+ }
27
+
9
28
  export class Ecwt {
10
29
  #ecwtFactory;
11
-
12
- #token;
13
- #snowflake;
14
30
  #ttl_initial;
15
- #data;
31
+
32
+ /**
33
+ * Token string representation.
34
+ * @type {string}
35
+ * @readonly
36
+ */
37
+ token;
38
+ /**
39
+ * Token ID.
40
+ * @type {string}
41
+ * @readonly
42
+ */
43
+ id;
44
+ /**
45
+ * Snowflake associated with token.
46
+ * @type {Snowflake}
47
+ * @readonly
48
+ */
49
+ snowflake;
50
+ /**
51
+ * Timestamp when token expires in seconds.
52
+ * @type {number?}
53
+ * @readonly
54
+ */
55
+ ts_expired;
56
+ /**
57
+ * Data stored in token.
58
+ * @type {{ [key: string]: any }}
59
+ * @readonly
60
+ */
61
+ data;
16
62
 
17
63
  /**
18
64
  * @param {EcwtFactory} ecwtFactory -
19
65
  * @param {object} options -
20
66
  * @param {string} options.token String representation of token.
21
67
  * @param {Snowflake} options.snowflake -
22
- * @param {number | null} options.ttl_initial Time to live in seconds at the moment of token creation.
68
+ * @param {number?} options.ttl_initial Time to live in seconds at the moment of token creation.
23
69
  * @param {object} options.data Data stored in token.
24
70
  */
25
71
  constructor(
@@ -33,53 +79,51 @@ export class Ecwt {
33
79
  ) {
34
80
  this.#ecwtFactory = ecwtFactory;
35
81
 
36
- this.#token = token;
37
- this.#snowflake = snowflake;
38
82
  this.#ttl_initial = ttl_initial;
39
- this.#data = Object.freeze(data);
40
- }
41
83
 
42
- get token() {
43
- return this.#token;
84
+ assign(this, 'token', token);
85
+ assign(
86
+ this,
87
+ 'id',
88
+ snowflake.toBase62(),
89
+ );
90
+ assign(this, 'snowflake', snowflake);
91
+ assign(
92
+ this,
93
+ 'ts_expired',
94
+ this.#getTimestampExpired(),
95
+ );
96
+ assign(
97
+ this,
98
+ 'data',
99
+ Object.freeze(data),
100
+ );
44
101
  }
45
102
 
46
- get id() {
47
- return this.#snowflake.base62;
48
- }
49
-
50
- get snowflake() {
51
- return this.#snowflake;
52
- }
53
-
54
- get ts_expired() {
103
+ #getTimestampExpired() {
55
104
  if (this.#ttl_initial === null) {
56
- return Number.POSITIVE_INFINITY;
105
+ return null;
57
106
  }
58
107
 
59
- return toSeconds(this.#snowflake.timestamp) + this.#ttl_initial;
108
+ return toSeconds(this.snowflake.timestamp) + this.#ttl_initial;
60
109
  }
61
110
 
62
111
  /**
63
- * Time to live in seconds.
64
- * @type {number}
65
- * @readonly
112
+ * Actual time to live in seconds.
113
+ * @returns {number | null} -
66
114
  */
67
- get ttl() {
115
+ getTTL() {
68
116
  if (this.#ttl_initial === null) {
69
- return Number.POSITIVE_INFINITY;
117
+ return null;
70
118
  }
71
119
 
72
- return this.#ttl_initial - toSeconds(Date.now() - this.#snowflake.timestamp);
73
- }
74
-
75
- get data() {
76
- return this.#data;
120
+ return this.#ttl_initial - toSeconds(Date.now() - this.snowflake.timestamp);
77
121
  }
78
122
 
79
123
  /* async */ revoke() {
80
124
  return this.#ecwtFactory._revoke({
81
125
  token_id: this.id,
82
- ts_ms_created: this.#snowflake.timestamp,
126
+ ts_ms_created: this.snowflake.timestamp,
83
127
  ttl_initial: this.#ttl_initial,
84
128
  });
85
129
  }