ecwt 0.2.5 → 0.3.0-beta.1
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/.oxlintrc.json +17 -0
- package/.vscode/settings.json +8 -0
- package/.zed/settings.json +56 -0
- package/bun.lock +274 -513
- package/dist/main.cjs +59 -66
- package/dist/{main.d.ts → main.d.cts} +52 -68
- package/dist/main.d.mts +144 -0
- package/dist/{main.js → main.mjs} +48 -55
- package/package.json +24 -18
package/dist/main.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
"
|
|
2
|
-
//#region
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
3
|
var __create = Object.create;
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
5
5
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -20,12 +20,35 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
20
20
|
value: mod,
|
|
21
21
|
enumerable: true
|
|
22
22
|
}) : target, mod));
|
|
23
|
-
|
|
24
23
|
//#endregion
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
let cbor_x = require("cbor-x");
|
|
25
|
+
let evilcrypt = require("evilcrypt");
|
|
26
|
+
let base_x = require("base-x");
|
|
27
|
+
base_x = __toESM(base_x, 1);
|
|
28
|
+
//#region src/errors.ts
|
|
29
|
+
/** Error thrown when string token cannot be parsed to Ecwt. */
|
|
30
|
+
var EcwtParseError = class extends Error {
|
|
31
|
+
constructor() {
|
|
32
|
+
super("Cannot parse data to Ecwt token.");
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
/** Error thrown when parsed Ecwt is invalid. */
|
|
36
|
+
var EcwtInvalidError = class extends Error {
|
|
37
|
+
message = "Ecwt token is invalid.";
|
|
38
|
+
constructor(ecwt) {
|
|
39
|
+
super();
|
|
40
|
+
this.ecwt = ecwt;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
/** Error thrown when parsed Ecwt is expired. */
|
|
44
|
+
var EcwtExpiredError = class extends EcwtInvalidError {
|
|
45
|
+
message = "Ecwt is expired.";
|
|
46
|
+
};
|
|
47
|
+
/** Error thrown when parsed Ecwt is revoked. */
|
|
48
|
+
var EcwtRevokedError = class extends EcwtInvalidError {
|
|
49
|
+
message = "Ecwt is revoked.";
|
|
50
|
+
};
|
|
51
|
+
//#endregion
|
|
29
52
|
//#region src/token.ts
|
|
30
53
|
var Ecwt = class {
|
|
31
54
|
/** Token string representation. */
|
|
@@ -39,12 +62,12 @@ var Ecwt = class {
|
|
|
39
62
|
ecwtFactory;
|
|
40
63
|
ttl_initial;
|
|
41
64
|
/**
|
|
42
|
-
* @param
|
|
43
|
-
* @param
|
|
44
|
-
* @param
|
|
45
|
-
* @param
|
|
46
|
-
* @param
|
|
47
|
-
* @param
|
|
65
|
+
* @param ecwtFactory -
|
|
66
|
+
* @param options -
|
|
67
|
+
* @param options.token String representation of token.
|
|
68
|
+
* @param options.snowflake -
|
|
69
|
+
* @param options.ttl_initial Time to live in seconds at the moment of token creation.
|
|
70
|
+
* @param options.data Data stored in token.
|
|
48
71
|
*/
|
|
49
72
|
constructor(ecwtFactory, options) {
|
|
50
73
|
this.token = options.token;
|
|
@@ -70,44 +93,14 @@ var Ecwt = class {
|
|
|
70
93
|
if (this.ttl_initial === null) return null;
|
|
71
94
|
return this.ttl_initial - Math.floor((Date.now() - this.snowflake.timestamp) / 1e3);
|
|
72
95
|
}
|
|
73
|
-
/**
|
|
74
|
-
* Revokes token.
|
|
75
|
-
* @returns {} -
|
|
76
|
-
*/
|
|
96
|
+
/** Revokes token. */
|
|
77
97
|
revoke() {
|
|
78
98
|
return this.ecwtFactory._revoke(this.id, this.snowflake.timestamp, this.ttl_initial);
|
|
79
99
|
}
|
|
80
100
|
};
|
|
81
|
-
|
|
82
101
|
//#endregion
|
|
83
102
|
//#region src/utils.ts
|
|
84
103
|
const base62 = (0, base_x.default)("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
|
|
85
|
-
|
|
86
|
-
//#endregion
|
|
87
|
-
//#region src/errors.ts
|
|
88
|
-
/** Error thrown when string token cannot be parsed to Ecwt. */
|
|
89
|
-
var EcwtParseError = class extends Error {
|
|
90
|
-
constructor() {
|
|
91
|
-
super("Cannot parse data to Ecwt token.");
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
/** Error thrown when parsed Ecwt is invalid. */
|
|
95
|
-
var EcwtInvalidError = class extends Error {
|
|
96
|
-
message = "Ecwt token is invalid.";
|
|
97
|
-
constructor(ecwt) {
|
|
98
|
-
super();
|
|
99
|
-
this.ecwt = ecwt;
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
/** Error thrown when parsed Ecwt is expired. */
|
|
103
|
-
var EcwtExpiredError = class extends EcwtInvalidError {
|
|
104
|
-
message = "Ecwt is expired.";
|
|
105
|
-
};
|
|
106
|
-
/** Error thrown when parsed Ecwt is revoked. */
|
|
107
|
-
var EcwtRevokedError = class extends EcwtInvalidError {
|
|
108
|
-
message = "Ecwt is revoked.";
|
|
109
|
-
};
|
|
110
|
-
|
|
111
104
|
//#endregion
|
|
112
105
|
//#region src/factory.ts
|
|
113
106
|
const REDIS_PREFIX = "@ecwt:";
|
|
@@ -166,7 +159,8 @@ var EcwtFactory = class {
|
|
|
166
159
|
* @param cache_value - Data to be stored in cache.
|
|
167
160
|
*/
|
|
168
161
|
setCache(token, cache_value) {
|
|
169
|
-
|
|
162
|
+
var _this$lruCache;
|
|
163
|
+
(_this$lruCache = this.lruCache) === null || _this$lruCache === void 0 || _this$lruCache.set(token, cache_value, cache_value.ttl_initial === null ? void 0 : { ttl: cache_value.ttl_initial * 1e3 });
|
|
170
164
|
}
|
|
171
165
|
/**
|
|
172
166
|
* Parses token.
|
|
@@ -174,11 +168,12 @@ var EcwtFactory = class {
|
|
|
174
168
|
* @returns -
|
|
175
169
|
*/
|
|
176
170
|
async verify(token) {
|
|
171
|
+
var _this$lruCache2, _this$redisClient;
|
|
177
172
|
if (typeof token !== "string") throw new TypeError("Token must be a string.");
|
|
178
173
|
let snowflake;
|
|
179
174
|
let ttl_initial;
|
|
180
175
|
let data;
|
|
181
|
-
const cached_entry = this.lruCache
|
|
176
|
+
const cached_entry = (_this$lruCache2 = this.lruCache) === null || _this$lruCache2 === void 0 ? void 0 : _this$lruCache2.info(token);
|
|
182
177
|
if (cached_entry === void 0) {
|
|
183
178
|
const token_encrypted = Buffer.from(base62.decode(token));
|
|
184
179
|
let token_raw;
|
|
@@ -209,10 +204,7 @@ var EcwtFactory = class {
|
|
|
209
204
|
data
|
|
210
205
|
});
|
|
211
206
|
if (typeof ttl_initial === "number" && Number.isNaN(ttl_initial) !== true && snowflake.timestamp + ttl_initial * 1e3 < Date.now()) throw new EcwtExpiredError(ecwt);
|
|
212
|
-
if (this.redisClient)
|
|
213
|
-
const score = await this.redisClient.ZSCORE(this.redis_key_revoked, ecwt.id);
|
|
214
|
-
if (score !== null) throw new EcwtRevokedError(ecwt);
|
|
215
|
-
}
|
|
207
|
+
if (await ((_this$redisClient = this.redisClient) === null || _this$redisClient === void 0 ? void 0 : _this$redisClient.HEXISTS(this.redis_key_revoked, ecwt.id))) throw new EcwtRevokedError(ecwt);
|
|
216
208
|
return ecwt;
|
|
217
209
|
}
|
|
218
210
|
/**
|
|
@@ -251,25 +243,26 @@ var EcwtFactory = class {
|
|
|
251
243
|
if (this.redisClient) {
|
|
252
244
|
ttl_initial ??= Number.MAX_SAFE_INTEGER;
|
|
253
245
|
const ts_ms_expired = ts_ms_created + ttl_initial * 1e3;
|
|
254
|
-
if (ts_ms_expired > Date.now()) await this.redisClient.
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
246
|
+
if (ts_ms_expired > Date.now()) await this.redisClient.sendCommand([
|
|
247
|
+
"HSET",
|
|
248
|
+
this.redis_key_revoked,
|
|
249
|
+
token_id,
|
|
250
|
+
"",
|
|
251
|
+
"PX",
|
|
252
|
+
String(ts_ms_expired - Date.now())
|
|
253
|
+
]);
|
|
258
254
|
} else console.warn("[ecwt] Redis client is not provided. Tokens cannot be revoked.");
|
|
259
255
|
}
|
|
260
|
-
/**
|
|
261
|
-
* Purges LRU cache.
|
|
262
|
-
* @returns {void} -
|
|
263
|
-
*/
|
|
256
|
+
/** Purges LRU cache. */
|
|
264
257
|
_purgeCache() {
|
|
265
|
-
|
|
258
|
+
var _this$lruCache3;
|
|
259
|
+
(_this$lruCache3 = this.lruCache) === null || _this$lruCache3 === void 0 || _this$lruCache3.clear();
|
|
266
260
|
}
|
|
267
261
|
};
|
|
268
|
-
|
|
269
262
|
//#endregion
|
|
270
|
-
exports.Ecwt = Ecwt
|
|
271
|
-
exports.EcwtExpiredError = EcwtExpiredError
|
|
272
|
-
exports.EcwtFactory = EcwtFactory
|
|
273
|
-
exports.EcwtInvalidError = EcwtInvalidError
|
|
274
|
-
exports.EcwtParseError = EcwtParseError
|
|
275
|
-
exports.EcwtRevokedError = EcwtRevokedError
|
|
263
|
+
exports.Ecwt = Ecwt;
|
|
264
|
+
exports.EcwtExpiredError = EcwtExpiredError;
|
|
265
|
+
exports.EcwtFactory = EcwtFactory;
|
|
266
|
+
exports.EcwtInvalidError = EcwtInvalidError;
|
|
267
|
+
exports.EcwtParseError = EcwtParseError;
|
|
268
|
+
exports.EcwtRevokedError = EcwtRevokedError;
|
|
@@ -2,48 +2,6 @@ import { Snowflake, SnowflakeFactory } from "@kirick/snowflake";
|
|
|
2
2
|
import { LRUCache } from "lru-cache";
|
|
3
3
|
import { RedisClientType, RedisFunctions, RedisModules, RedisScripts } from "redis";
|
|
4
4
|
|
|
5
|
-
//#region src/token.d.ts
|
|
6
|
-
declare class Ecwt<D extends Record<string, unknown> = Record<string, unknown>> {
|
|
7
|
-
/** Token string representation. */
|
|
8
|
-
readonly token: string;
|
|
9
|
-
/** Token ID. */
|
|
10
|
-
readonly id: string;
|
|
11
|
-
/** Snowflake associated with token. */
|
|
12
|
-
readonly snowflake: Snowflake;
|
|
13
|
-
/** Data stored in token. */
|
|
14
|
-
readonly data: Readonly<D>;
|
|
15
|
-
private ecwtFactory;
|
|
16
|
-
private ttl_initial;
|
|
17
|
-
/**
|
|
18
|
-
* @param {EcwtFactory} ecwtFactory -
|
|
19
|
-
* @param {object} options -
|
|
20
|
-
* @param {string} options.token String representation of token.
|
|
21
|
-
* @param {Snowflake} options.snowflake -
|
|
22
|
-
* @param {number | null} options.ttl_initial Time to live in seconds at the moment of token creation.
|
|
23
|
-
* @param {D} options.data Data stored in token.
|
|
24
|
-
*/
|
|
25
|
-
constructor(ecwtFactory: EcwtFactory, options: {
|
|
26
|
-
token: string;
|
|
27
|
-
snowflake: Snowflake;
|
|
28
|
-
ttl_initial: number | null;
|
|
29
|
-
data: D;
|
|
30
|
-
});
|
|
31
|
-
/**
|
|
32
|
-
* Unix timestamp of token expiration in seconds.
|
|
33
|
-
* @returns -
|
|
34
|
-
*/
|
|
35
|
-
get ts_expired(): number | null;
|
|
36
|
-
/**
|
|
37
|
-
* Actual time to live in seconds.
|
|
38
|
-
* @returns -
|
|
39
|
-
*/
|
|
40
|
-
getTTL(): number | null;
|
|
41
|
-
/**
|
|
42
|
-
* Revokes token.
|
|
43
|
-
* @returns {} -
|
|
44
|
-
*/
|
|
45
|
-
revoke(): Promise<void>;
|
|
46
|
-
} //#endregion
|
|
47
5
|
//#region src/factory.d.ts
|
|
48
6
|
type LRUCacheValue = {
|
|
49
7
|
snowflake: Snowflake;
|
|
@@ -52,24 +10,17 @@ type LRUCacheValue = {
|
|
|
52
10
|
};
|
|
53
11
|
type RedisClient = RedisClientType<RedisModules, RedisFunctions, RedisScripts>;
|
|
54
12
|
type EcwtFactoryArguments<D extends Record<string, unknown>> = {
|
|
55
|
-
/** RedisClient instance. If not provided, tokens can not be revoked and can not be checked for revocation. */
|
|
56
|
-
|
|
57
|
-
/** LRUCache instance. If not provided, tokens will be decrypted every time they are verified. */
|
|
58
|
-
lruCache?: LRUCache<string, LRUCacheValue>;
|
|
59
|
-
/** SnowflakeFactory instance. Generates unique IDs for tokens. */
|
|
13
|
+
/** RedisClient instance. If not provided, tokens can not be revoked and can not be checked for revocation. */redisClient?: RedisClient; /** LRUCache instance. If not provided, tokens will be decrypted every time they are verified. */
|
|
14
|
+
lruCache?: LRUCache<string, LRUCacheValue>; /** SnowflakeFactory instance. Generates unique IDs for tokens. */
|
|
60
15
|
snowflakeFactory: SnowflakeFactory;
|
|
61
16
|
options: {
|
|
62
|
-
/** Namespace for Redis keys. */
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
key: Buffer;
|
|
66
|
-
/** Validator for token data. Should return validated value or throw an error. */
|
|
67
|
-
validator?: (value: unknown) => D;
|
|
68
|
-
/** Payload object keys mapped for their SenML keys. */
|
|
17
|
+
/** Namespace for Redis keys. */namespace?: string; /** Encryption key, 64 bytes. */
|
|
18
|
+
key: Buffer; /** Validator for token data. Should return validated value or throw an error. */
|
|
19
|
+
validator?: (value: unknown) => D; /** Payload object keys mapped for their SenML keys. */
|
|
69
20
|
senml_key_map?: Record<string, number>;
|
|
70
21
|
};
|
|
71
22
|
};
|
|
72
|
-
declare class EcwtFactory<D extends Record<string, unknown> = Record<string, unknown>> {
|
|
23
|
+
declare class EcwtFactory<const D extends Record<string, unknown> = Record<string, unknown>> {
|
|
73
24
|
private redisClient;
|
|
74
25
|
private lruCache;
|
|
75
26
|
private snowflakeFactory;
|
|
@@ -92,8 +43,7 @@ declare class EcwtFactory<D extends Record<string, unknown> = Record<string, unk
|
|
|
92
43
|
* @returns -
|
|
93
44
|
*/
|
|
94
45
|
create(data: D, options?: {
|
|
95
|
-
/** Time to live in seconds. If not defined, token will never expire. */
|
|
96
|
-
ttl?: number;
|
|
46
|
+
/** Time to live in seconds. If not defined, token will never expire. */ttl?: number;
|
|
97
47
|
}): Promise<Ecwt<D>>;
|
|
98
48
|
/**
|
|
99
49
|
* Sets data to cache.
|
|
@@ -127,34 +77,68 @@ declare class EcwtFactory<D extends Record<string, unknown> = Record<string, unk
|
|
|
127
77
|
* @returns -
|
|
128
78
|
*/
|
|
129
79
|
private _revoke;
|
|
80
|
+
/** Purges LRU cache. */
|
|
81
|
+
private _purgeCache;
|
|
82
|
+
}
|
|
83
|
+
//#endregion
|
|
84
|
+
//#region src/token.d.ts
|
|
85
|
+
declare class Ecwt<const D extends Record<string, unknown> = Record<string, unknown>> {
|
|
86
|
+
/** Token string representation. */
|
|
87
|
+
readonly token: string;
|
|
88
|
+
/** Token ID. */
|
|
89
|
+
readonly id: string;
|
|
90
|
+
/** Snowflake associated with token. */
|
|
91
|
+
readonly snowflake: Snowflake;
|
|
92
|
+
/** Data stored in token. */
|
|
93
|
+
readonly data: Readonly<D>;
|
|
94
|
+
private ecwtFactory;
|
|
95
|
+
private ttl_initial;
|
|
130
96
|
/**
|
|
131
|
-
*
|
|
132
|
-
* @
|
|
97
|
+
* @param ecwtFactory -
|
|
98
|
+
* @param options -
|
|
99
|
+
* @param options.token String representation of token.
|
|
100
|
+
* @param options.snowflake -
|
|
101
|
+
* @param options.ttl_initial Time to live in seconds at the moment of token creation.
|
|
102
|
+
* @param options.data Data stored in token.
|
|
133
103
|
*/
|
|
134
|
-
|
|
135
|
-
|
|
104
|
+
constructor(ecwtFactory: EcwtFactory, options: {
|
|
105
|
+
token: string;
|
|
106
|
+
snowflake: Snowflake;
|
|
107
|
+
ttl_initial: number | null;
|
|
108
|
+
data: D;
|
|
109
|
+
});
|
|
110
|
+
/**
|
|
111
|
+
* Unix timestamp of token expiration in seconds.
|
|
112
|
+
* @returns -
|
|
113
|
+
*/
|
|
114
|
+
get ts_expired(): number | null;
|
|
115
|
+
/**
|
|
116
|
+
* Actual time to live in seconds.
|
|
117
|
+
* @returns -
|
|
118
|
+
*/
|
|
119
|
+
getTTL(): number | null;
|
|
120
|
+
/** Revokes token. */
|
|
121
|
+
revoke(): Promise<void>;
|
|
122
|
+
}
|
|
123
|
+
//#endregion
|
|
136
124
|
//#region src/errors.d.ts
|
|
137
125
|
/** Error thrown when string token cannot be parsed to Ecwt. */
|
|
138
126
|
declare class EcwtParseError extends Error {
|
|
139
127
|
constructor();
|
|
140
128
|
}
|
|
141
|
-
|
|
142
129
|
/** Error thrown when parsed Ecwt is invalid. */
|
|
143
130
|
declare class EcwtInvalidError extends Error {
|
|
144
131
|
readonly ecwt: Ecwt;
|
|
145
|
-
message: string;
|
|
132
|
+
override message: string;
|
|
146
133
|
constructor(ecwt: Ecwt);
|
|
147
134
|
}
|
|
148
|
-
|
|
149
135
|
/** Error thrown when parsed Ecwt is expired. */
|
|
150
136
|
declare class EcwtExpiredError extends EcwtInvalidError {
|
|
151
|
-
message: string;
|
|
137
|
+
override message: string;
|
|
152
138
|
}
|
|
153
|
-
|
|
154
139
|
/** Error thrown when parsed Ecwt is revoked. */
|
|
155
140
|
declare class EcwtRevokedError extends EcwtInvalidError {
|
|
156
|
-
message: string;
|
|
141
|
+
override message: string;
|
|
157
142
|
}
|
|
158
|
-
|
|
159
143
|
//#endregion
|
|
160
144
|
export { Ecwt, EcwtExpiredError, EcwtFactory, EcwtInvalidError, EcwtParseError, EcwtRevokedError };
|
package/dist/main.d.mts
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { Snowflake, SnowflakeFactory } from "@kirick/snowflake";
|
|
2
|
+
import { LRUCache } from "lru-cache";
|
|
3
|
+
import { RedisClientType, RedisFunctions, RedisModules, RedisScripts } from "redis";
|
|
4
|
+
|
|
5
|
+
//#region src/factory.d.ts
|
|
6
|
+
type LRUCacheValue = {
|
|
7
|
+
snowflake: Snowflake;
|
|
8
|
+
ttl_initial: number | null;
|
|
9
|
+
data: Record<string, unknown>;
|
|
10
|
+
};
|
|
11
|
+
type RedisClient = RedisClientType<RedisModules, RedisFunctions, RedisScripts>;
|
|
12
|
+
type EcwtFactoryArguments<D extends Record<string, unknown>> = {
|
|
13
|
+
/** RedisClient instance. If not provided, tokens can not be revoked and can not be checked for revocation. */redisClient?: RedisClient; /** LRUCache instance. If not provided, tokens will be decrypted every time they are verified. */
|
|
14
|
+
lruCache?: LRUCache<string, LRUCacheValue>; /** SnowflakeFactory instance. Generates unique IDs for tokens. */
|
|
15
|
+
snowflakeFactory: SnowflakeFactory;
|
|
16
|
+
options: {
|
|
17
|
+
/** Namespace for Redis keys. */namespace?: string; /** Encryption key, 64 bytes. */
|
|
18
|
+
key: Buffer; /** Validator for token data. Should return validated value or throw an error. */
|
|
19
|
+
validator?: (value: unknown) => D; /** Payload object keys mapped for their SenML keys. */
|
|
20
|
+
senml_key_map?: Record<string, number>;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
declare class EcwtFactory<const D extends Record<string, unknown> = Record<string, unknown>> {
|
|
24
|
+
private redisClient;
|
|
25
|
+
private lruCache;
|
|
26
|
+
private snowflakeFactory;
|
|
27
|
+
private redis_key_revoked;
|
|
28
|
+
private encryption_key;
|
|
29
|
+
private validator;
|
|
30
|
+
private cborEncoder;
|
|
31
|
+
constructor({
|
|
32
|
+
redisClient,
|
|
33
|
+
lruCache,
|
|
34
|
+
snowflakeFactory,
|
|
35
|
+
options
|
|
36
|
+
}: EcwtFactoryArguments<D>);
|
|
37
|
+
/**
|
|
38
|
+
* Creates new token.
|
|
39
|
+
* @async
|
|
40
|
+
* @param data - Data to be stored in token.
|
|
41
|
+
* @param options -
|
|
42
|
+
* @param options.ttl - Time to live in seconds. If not defined, token will never expire.
|
|
43
|
+
* @returns -
|
|
44
|
+
*/
|
|
45
|
+
create(data: D, options?: {
|
|
46
|
+
/** Time to live in seconds. If not defined, token will never expire. */ttl?: number;
|
|
47
|
+
}): Promise<Ecwt<D>>;
|
|
48
|
+
/**
|
|
49
|
+
* Sets data to cache.
|
|
50
|
+
* @param token - String representation of token.
|
|
51
|
+
* @param cache_value - Data to be stored in cache.
|
|
52
|
+
*/
|
|
53
|
+
private setCache;
|
|
54
|
+
/**
|
|
55
|
+
* Parses token.
|
|
56
|
+
* @param token String representation of token.
|
|
57
|
+
* @returns -
|
|
58
|
+
*/
|
|
59
|
+
verify(token: string): Promise<Ecwt<D>>;
|
|
60
|
+
/**
|
|
61
|
+
* Parses token without throwing errors.
|
|
62
|
+
* @param token - String representation of token.
|
|
63
|
+
* @returns Returns whether token was parsed and verified successfully and Ecwt if parsed.
|
|
64
|
+
*/
|
|
65
|
+
safeVerify(token: string): Promise<{
|
|
66
|
+
success: true;
|
|
67
|
+
ecwt: Ecwt<D>;
|
|
68
|
+
} | {
|
|
69
|
+
success: false;
|
|
70
|
+
ecwt: Ecwt<D> | null;
|
|
71
|
+
}>;
|
|
72
|
+
/**
|
|
73
|
+
* Revokes token.
|
|
74
|
+
* @param token_id -
|
|
75
|
+
* @param ts_ms_created -
|
|
76
|
+
* @param ttl_initial -
|
|
77
|
+
* @returns -
|
|
78
|
+
*/
|
|
79
|
+
private _revoke;
|
|
80
|
+
/** Purges LRU cache. */
|
|
81
|
+
private _purgeCache;
|
|
82
|
+
}
|
|
83
|
+
//#endregion
|
|
84
|
+
//#region src/token.d.ts
|
|
85
|
+
declare class Ecwt<const D extends Record<string, unknown> = Record<string, unknown>> {
|
|
86
|
+
/** Token string representation. */
|
|
87
|
+
readonly token: string;
|
|
88
|
+
/** Token ID. */
|
|
89
|
+
readonly id: string;
|
|
90
|
+
/** Snowflake associated with token. */
|
|
91
|
+
readonly snowflake: Snowflake;
|
|
92
|
+
/** Data stored in token. */
|
|
93
|
+
readonly data: Readonly<D>;
|
|
94
|
+
private ecwtFactory;
|
|
95
|
+
private ttl_initial;
|
|
96
|
+
/**
|
|
97
|
+
* @param ecwtFactory -
|
|
98
|
+
* @param options -
|
|
99
|
+
* @param options.token String representation of token.
|
|
100
|
+
* @param options.snowflake -
|
|
101
|
+
* @param options.ttl_initial Time to live in seconds at the moment of token creation.
|
|
102
|
+
* @param options.data Data stored in token.
|
|
103
|
+
*/
|
|
104
|
+
constructor(ecwtFactory: EcwtFactory, options: {
|
|
105
|
+
token: string;
|
|
106
|
+
snowflake: Snowflake;
|
|
107
|
+
ttl_initial: number | null;
|
|
108
|
+
data: D;
|
|
109
|
+
});
|
|
110
|
+
/**
|
|
111
|
+
* Unix timestamp of token expiration in seconds.
|
|
112
|
+
* @returns -
|
|
113
|
+
*/
|
|
114
|
+
get ts_expired(): number | null;
|
|
115
|
+
/**
|
|
116
|
+
* Actual time to live in seconds.
|
|
117
|
+
* @returns -
|
|
118
|
+
*/
|
|
119
|
+
getTTL(): number | null;
|
|
120
|
+
/** Revokes token. */
|
|
121
|
+
revoke(): Promise<void>;
|
|
122
|
+
}
|
|
123
|
+
//#endregion
|
|
124
|
+
//#region src/errors.d.ts
|
|
125
|
+
/** Error thrown when string token cannot be parsed to Ecwt. */
|
|
126
|
+
declare class EcwtParseError extends Error {
|
|
127
|
+
constructor();
|
|
128
|
+
}
|
|
129
|
+
/** Error thrown when parsed Ecwt is invalid. */
|
|
130
|
+
declare class EcwtInvalidError extends Error {
|
|
131
|
+
readonly ecwt: Ecwt;
|
|
132
|
+
override message: string;
|
|
133
|
+
constructor(ecwt: Ecwt);
|
|
134
|
+
}
|
|
135
|
+
/** Error thrown when parsed Ecwt is expired. */
|
|
136
|
+
declare class EcwtExpiredError extends EcwtInvalidError {
|
|
137
|
+
override message: string;
|
|
138
|
+
}
|
|
139
|
+
/** Error thrown when parsed Ecwt is revoked. */
|
|
140
|
+
declare class EcwtRevokedError extends EcwtInvalidError {
|
|
141
|
+
override message: string;
|
|
142
|
+
}
|
|
143
|
+
//#endregion
|
|
144
|
+
export { Ecwt, EcwtExpiredError, EcwtFactory, EcwtInvalidError, EcwtParseError, EcwtRevokedError };
|
|
@@ -1,7 +1,30 @@
|
|
|
1
1
|
import { Encoder, decode, encode } from "cbor-x";
|
|
2
2
|
import { decrypt, v2 } from "evilcrypt";
|
|
3
3
|
import basex from "base-x";
|
|
4
|
-
|
|
4
|
+
//#region src/errors.ts
|
|
5
|
+
/** Error thrown when string token cannot be parsed to Ecwt. */
|
|
6
|
+
var EcwtParseError = class extends Error {
|
|
7
|
+
constructor() {
|
|
8
|
+
super("Cannot parse data to Ecwt token.");
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
/** Error thrown when parsed Ecwt is invalid. */
|
|
12
|
+
var EcwtInvalidError = class extends Error {
|
|
13
|
+
message = "Ecwt token is invalid.";
|
|
14
|
+
constructor(ecwt) {
|
|
15
|
+
super();
|
|
16
|
+
this.ecwt = ecwt;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
/** Error thrown when parsed Ecwt is expired. */
|
|
20
|
+
var EcwtExpiredError = class extends EcwtInvalidError {
|
|
21
|
+
message = "Ecwt is expired.";
|
|
22
|
+
};
|
|
23
|
+
/** Error thrown when parsed Ecwt is revoked. */
|
|
24
|
+
var EcwtRevokedError = class extends EcwtInvalidError {
|
|
25
|
+
message = "Ecwt is revoked.";
|
|
26
|
+
};
|
|
27
|
+
//#endregion
|
|
5
28
|
//#region src/token.ts
|
|
6
29
|
var Ecwt = class {
|
|
7
30
|
/** Token string representation. */
|
|
@@ -15,12 +38,12 @@ var Ecwt = class {
|
|
|
15
38
|
ecwtFactory;
|
|
16
39
|
ttl_initial;
|
|
17
40
|
/**
|
|
18
|
-
* @param
|
|
19
|
-
* @param
|
|
20
|
-
* @param
|
|
21
|
-
* @param
|
|
22
|
-
* @param
|
|
23
|
-
* @param
|
|
41
|
+
* @param ecwtFactory -
|
|
42
|
+
* @param options -
|
|
43
|
+
* @param options.token String representation of token.
|
|
44
|
+
* @param options.snowflake -
|
|
45
|
+
* @param options.ttl_initial Time to live in seconds at the moment of token creation.
|
|
46
|
+
* @param options.data Data stored in token.
|
|
24
47
|
*/
|
|
25
48
|
constructor(ecwtFactory, options) {
|
|
26
49
|
this.token = options.token;
|
|
@@ -46,44 +69,14 @@ var Ecwt = class {
|
|
|
46
69
|
if (this.ttl_initial === null) return null;
|
|
47
70
|
return this.ttl_initial - Math.floor((Date.now() - this.snowflake.timestamp) / 1e3);
|
|
48
71
|
}
|
|
49
|
-
/**
|
|
50
|
-
* Revokes token.
|
|
51
|
-
* @returns {} -
|
|
52
|
-
*/
|
|
72
|
+
/** Revokes token. */
|
|
53
73
|
revoke() {
|
|
54
74
|
return this.ecwtFactory._revoke(this.id, this.snowflake.timestamp, this.ttl_initial);
|
|
55
75
|
}
|
|
56
76
|
};
|
|
57
|
-
|
|
58
77
|
//#endregion
|
|
59
78
|
//#region src/utils.ts
|
|
60
79
|
const base62 = basex("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
|
|
61
|
-
|
|
62
|
-
//#endregion
|
|
63
|
-
//#region src/errors.ts
|
|
64
|
-
/** Error thrown when string token cannot be parsed to Ecwt. */
|
|
65
|
-
var EcwtParseError = class extends Error {
|
|
66
|
-
constructor() {
|
|
67
|
-
super("Cannot parse data to Ecwt token.");
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
/** Error thrown when parsed Ecwt is invalid. */
|
|
71
|
-
var EcwtInvalidError = class extends Error {
|
|
72
|
-
message = "Ecwt token is invalid.";
|
|
73
|
-
constructor(ecwt) {
|
|
74
|
-
super();
|
|
75
|
-
this.ecwt = ecwt;
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
/** Error thrown when parsed Ecwt is expired. */
|
|
79
|
-
var EcwtExpiredError = class extends EcwtInvalidError {
|
|
80
|
-
message = "Ecwt is expired.";
|
|
81
|
-
};
|
|
82
|
-
/** Error thrown when parsed Ecwt is revoked. */
|
|
83
|
-
var EcwtRevokedError = class extends EcwtInvalidError {
|
|
84
|
-
message = "Ecwt is revoked.";
|
|
85
|
-
};
|
|
86
|
-
|
|
87
80
|
//#endregion
|
|
88
81
|
//#region src/factory.ts
|
|
89
82
|
const REDIS_PREFIX = "@ecwt:";
|
|
@@ -142,7 +135,8 @@ var EcwtFactory = class {
|
|
|
142
135
|
* @param cache_value - Data to be stored in cache.
|
|
143
136
|
*/
|
|
144
137
|
setCache(token, cache_value) {
|
|
145
|
-
|
|
138
|
+
var _this$lruCache;
|
|
139
|
+
(_this$lruCache = this.lruCache) === null || _this$lruCache === void 0 || _this$lruCache.set(token, cache_value, cache_value.ttl_initial === null ? void 0 : { ttl: cache_value.ttl_initial * 1e3 });
|
|
146
140
|
}
|
|
147
141
|
/**
|
|
148
142
|
* Parses token.
|
|
@@ -150,11 +144,12 @@ var EcwtFactory = class {
|
|
|
150
144
|
* @returns -
|
|
151
145
|
*/
|
|
152
146
|
async verify(token) {
|
|
147
|
+
var _this$lruCache2, _this$redisClient;
|
|
153
148
|
if (typeof token !== "string") throw new TypeError("Token must be a string.");
|
|
154
149
|
let snowflake;
|
|
155
150
|
let ttl_initial;
|
|
156
151
|
let data;
|
|
157
|
-
const cached_entry = this.lruCache
|
|
152
|
+
const cached_entry = (_this$lruCache2 = this.lruCache) === null || _this$lruCache2 === void 0 ? void 0 : _this$lruCache2.info(token);
|
|
158
153
|
if (cached_entry === void 0) {
|
|
159
154
|
const token_encrypted = Buffer.from(base62.decode(token));
|
|
160
155
|
let token_raw;
|
|
@@ -185,10 +180,7 @@ var EcwtFactory = class {
|
|
|
185
180
|
data
|
|
186
181
|
});
|
|
187
182
|
if (typeof ttl_initial === "number" && Number.isNaN(ttl_initial) !== true && snowflake.timestamp + ttl_initial * 1e3 < Date.now()) throw new EcwtExpiredError(ecwt);
|
|
188
|
-
if (this.redisClient)
|
|
189
|
-
const score = await this.redisClient.ZSCORE(this.redis_key_revoked, ecwt.id);
|
|
190
|
-
if (score !== null) throw new EcwtRevokedError(ecwt);
|
|
191
|
-
}
|
|
183
|
+
if (await ((_this$redisClient = this.redisClient) === null || _this$redisClient === void 0 ? void 0 : _this$redisClient.HEXISTS(this.redis_key_revoked, ecwt.id))) throw new EcwtRevokedError(ecwt);
|
|
192
184
|
return ecwt;
|
|
193
185
|
}
|
|
194
186
|
/**
|
|
@@ -227,20 +219,21 @@ var EcwtFactory = class {
|
|
|
227
219
|
if (this.redisClient) {
|
|
228
220
|
ttl_initial ??= Number.MAX_SAFE_INTEGER;
|
|
229
221
|
const ts_ms_expired = ts_ms_created + ttl_initial * 1e3;
|
|
230
|
-
if (ts_ms_expired > Date.now()) await this.redisClient.
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
222
|
+
if (ts_ms_expired > Date.now()) await this.redisClient.sendCommand([
|
|
223
|
+
"HSET",
|
|
224
|
+
this.redis_key_revoked,
|
|
225
|
+
token_id,
|
|
226
|
+
"",
|
|
227
|
+
"PX",
|
|
228
|
+
String(ts_ms_expired - Date.now())
|
|
229
|
+
]);
|
|
234
230
|
} else console.warn("[ecwt] Redis client is not provided. Tokens cannot be revoked.");
|
|
235
231
|
}
|
|
236
|
-
/**
|
|
237
|
-
* Purges LRU cache.
|
|
238
|
-
* @returns {void} -
|
|
239
|
-
*/
|
|
232
|
+
/** Purges LRU cache. */
|
|
240
233
|
_purgeCache() {
|
|
241
|
-
|
|
234
|
+
var _this$lruCache3;
|
|
235
|
+
(_this$lruCache3 = this.lruCache) === null || _this$lruCache3 === void 0 || _this$lruCache3.clear();
|
|
242
236
|
}
|
|
243
237
|
};
|
|
244
|
-
|
|
245
238
|
//#endregion
|
|
246
|
-
export { Ecwt, EcwtExpiredError, EcwtFactory, EcwtInvalidError, EcwtParseError, EcwtRevokedError };
|
|
239
|
+
export { Ecwt, EcwtExpiredError, EcwtFactory, EcwtInvalidError, EcwtParseError, EcwtRevokedError };
|