nhb-toolbox 4.27.11 → 4.28.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/CHANGELOG.md +8 -0
- package/dist/cjs/date/constants.js +62 -2
- package/dist/cjs/date/guards.js +10 -3
- package/dist/cjs/date/parse.js +33 -0
- package/dist/cjs/hash/Cipher.js +73 -0
- package/dist/cjs/hash/Signet.js +168 -0
- package/dist/cjs/hash/core.js +89 -0
- package/dist/cjs/hash/helpers.js +21 -3
- package/dist/cjs/hash/index.js +34 -252
- package/dist/cjs/hash/utils.js +252 -0
- package/dist/cjs/hash/uuid.js +168 -0
- package/dist/cjs/index.js +12 -6
- package/dist/cjs/string/basics.js +16 -16
- package/dist/cjs/utils/index.js +27 -0
- package/dist/dts/date/constants.d.ts +18 -3
- package/dist/dts/date/guards.d.ts +3 -1
- package/dist/dts/date/parse.d.ts +14 -0
- package/dist/dts/date/types.d.ts +7 -1
- package/dist/dts/hash/Cipher.d.ts +45 -0
- package/dist/dts/hash/Signet.d.ts +444 -0
- package/dist/dts/hash/core.d.ts +66 -0
- package/dist/dts/hash/helpers.d.ts +10 -3
- package/dist/dts/hash/index.d.ts +7 -149
- package/dist/dts/hash/types.d.ts +90 -1
- package/dist/dts/hash/utils.d.ts +348 -0
- package/dist/dts/hash/uuid.d.ts +91 -0
- package/dist/dts/index.d.ts +3 -2
- package/dist/dts/string/basics.d.ts +48 -3
- package/dist/dts/string/types.d.ts +3 -3
- package/dist/dts/utils/index.d.ts +26 -0
- package/dist/esm/date/constants.js +61 -1
- package/dist/esm/date/guards.js +10 -4
- package/dist/esm/date/parse.js +30 -0
- package/dist/esm/hash/Cipher.js +69 -0
- package/dist/esm/hash/Signet.js +164 -0
- package/dist/esm/hash/core.js +84 -0
- package/dist/esm/hash/helpers.js +16 -2
- package/dist/esm/hash/index.js +7 -240
- package/dist/esm/hash/utils.js +239 -0
- package/dist/esm/hash/uuid.js +156 -0
- package/dist/esm/index.js +3 -2
- package/dist/esm/string/basics.js +14 -13
- package/dist/esm/utils/index.js +26 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,14 @@ All notable changes to the package will be documented here.
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
+
## [4.28.0] - 2025-12-01
|
|
10
|
+
|
|
11
|
+
- **Added** *new* class `Cipher` to *encrypt/decrypt* string with *secret key*.
|
|
12
|
+
- **Added** *new* class `Signet` to *sign*, *decode* and *verify* **token** like `JWT`.
|
|
13
|
+
- **Added** *new* `sha256` hash function. **Updated** `sha1` *encoding algorithm*. Now it avoids depending on `TextEncoder`.
|
|
14
|
+
- **Added** *new* utility `parseMSec` to convert time value to *milliseconds* or *seconds* along with new *type guard* `isTimeWithUnit`.
|
|
15
|
+
- **Added** *new* `JSON` utilities: `stableStringify` for *stable, deterministic stringifying* and `stripJsonEdgeGarbage` for stripping `JSON` string.
|
|
16
|
+
|
|
9
17
|
## [4.27.11] - 2025-11-29
|
|
10
18
|
|
|
11
19
|
- **Updated** *core algorithms* of `md5` and `sha1` utilities to fix *incorrect hash digest generation*.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.MS_MAP = exports.TIME_UNIT_REGEX = exports.TIME_UNIT_VARIANTS = exports.ZODIAC_PRESETS = exports.VEDIC_ZODIAC_SIGNS = exports.WESTERN_ZODIAC_SIGNS = exports.DATE_PART_RANGES = exports.SORTED_TIME_FORMATS = exports.TIME_FORMATS = exports.MILLISECOND_FORMATS = exports.ZONE_FORMATS = exports.SECOND_FORMATS = exports.MINUTE_FORMATS = exports.HOUR_FORMATS = exports.DAY_FORMATS = exports.DATE_FORMATS = exports.MONTH_FORMATS = exports.YEAR_FORMATS = exports.MONTHS = exports.DAYS = exports.INTERNALS = void 0;
|
|
4
|
+
exports.INTERNALS = Symbol('Internals');
|
|
4
5
|
exports.DAYS = /* @__PURE__ */ Object.freeze([
|
|
5
6
|
'Sunday',
|
|
6
7
|
'Monday',
|
|
@@ -95,4 +96,63 @@ exports.ZODIAC_PRESETS = /* @__PURE__ */ Object.freeze({
|
|
|
95
96
|
tropical: exports.WESTERN_ZODIAC_SIGNS,
|
|
96
97
|
sidereal: exports.VEDIC_ZODIAC_SIGNS,
|
|
97
98
|
});
|
|
98
|
-
exports.
|
|
99
|
+
exports.TIME_UNIT_VARIANTS = /* @__PURE__ */ Object.freeze({
|
|
100
|
+
year: ['y', 'yr', 'yrs', 'year', 'years'],
|
|
101
|
+
month: ['mo', 'month', 'months'],
|
|
102
|
+
week: ['w', 'week', 'weeks'],
|
|
103
|
+
day: ['d', 'day', 'days'],
|
|
104
|
+
hour: ['h', 'hr', 'hrs', 'hour', 'hours'],
|
|
105
|
+
minute: ['m', 'min', 'mins', 'minute', 'minutes'],
|
|
106
|
+
second: ['s', 'sec', 'secs', 'second', 'seconds'],
|
|
107
|
+
millisecond: ['ms', 'msec', 'msecs', 'millisecond', 'milliseconds'],
|
|
108
|
+
});
|
|
109
|
+
const TIME_UNIT_REGEX_STR = /* @__PURE__ */ Object.freeze(Object.values(exports.TIME_UNIT_VARIANTS)
|
|
110
|
+
.flat()
|
|
111
|
+
.sort((a, b) => b.length - a.length)
|
|
112
|
+
.join('|'));
|
|
113
|
+
exports.TIME_UNIT_REGEX = /* @__PURE__ */ Object.freeze(new RegExp(`^(?<value>-?\\d*\\.?\\d+) *(?<unit>${TIME_UNIT_REGEX_STR})?$`, 'i'));
|
|
114
|
+
exports.MS_MAP = /* @__PURE__ */ Object.freeze((() => {
|
|
115
|
+
const s = 1000;
|
|
116
|
+
const m = s * 60;
|
|
117
|
+
const h = m * 60;
|
|
118
|
+
const d = h * 24;
|
|
119
|
+
const w = d * 7;
|
|
120
|
+
const y = d * 365.25;
|
|
121
|
+
const mo = y / 12;
|
|
122
|
+
return {
|
|
123
|
+
y,
|
|
124
|
+
yr: y,
|
|
125
|
+
yrs: y,
|
|
126
|
+
year: y,
|
|
127
|
+
years: y,
|
|
128
|
+
mo,
|
|
129
|
+
month: mo,
|
|
130
|
+
months: mo,
|
|
131
|
+
w,
|
|
132
|
+
week: w,
|
|
133
|
+
weeks: w,
|
|
134
|
+
d,
|
|
135
|
+
day: d,
|
|
136
|
+
days: d,
|
|
137
|
+
h,
|
|
138
|
+
hr: h,
|
|
139
|
+
hrs: h,
|
|
140
|
+
hour: h,
|
|
141
|
+
hours: h,
|
|
142
|
+
m,
|
|
143
|
+
min: m,
|
|
144
|
+
mins: m,
|
|
145
|
+
minute: m,
|
|
146
|
+
minutes: m,
|
|
147
|
+
s,
|
|
148
|
+
sec: s,
|
|
149
|
+
secs: s,
|
|
150
|
+
second: s,
|
|
151
|
+
seconds: s,
|
|
152
|
+
ms: 1,
|
|
153
|
+
msec: 1,
|
|
154
|
+
msecs: 1,
|
|
155
|
+
millisecond: 1,
|
|
156
|
+
milliseconds: 1,
|
|
157
|
+
};
|
|
158
|
+
})());
|
package/dist/cjs/date/guards.js
CHANGED
|
@@ -6,12 +6,14 @@ exports.isValidTimeZoneId = isValidTimeZoneId;
|
|
|
6
6
|
exports.isNativeTimeZoneId = isNativeTimeZoneId;
|
|
7
7
|
exports.isLeapYear = isLeapYear;
|
|
8
8
|
exports.isDateLike = isDateLike;
|
|
9
|
+
exports.isTimeWithUnit = isTimeWithUnit;
|
|
9
10
|
const primitives_1 = require("../guards/primitives");
|
|
10
11
|
const specials_1 = require("../guards/specials");
|
|
11
12
|
const utilities_1 = require("../number/utilities");
|
|
13
|
+
const constants_1 = require("./constants");
|
|
12
14
|
const timezone_1 = require("./timezone");
|
|
13
15
|
function isValidTime(value) {
|
|
14
|
-
if (!(0, primitives_1.
|
|
16
|
+
if (!(0, primitives_1.isNonEmptyString)(value))
|
|
15
17
|
return false;
|
|
16
18
|
const [hourStr, minuteStr] = value.split(':');
|
|
17
19
|
if (!(0, specials_1.isNumericString)(hourStr) || !(0, specials_1.isNumericString)(minuteStr))
|
|
@@ -24,10 +26,12 @@ function isValidUTCOffset(value) {
|
|
|
24
26
|
return (0, primitives_1.isString)(value) ? /^UTC[+-]?\d{1,2}:\d{2}$/.test(value) : false;
|
|
25
27
|
}
|
|
26
28
|
function isValidTimeZoneId(value) {
|
|
27
|
-
return (0, primitives_1.
|
|
29
|
+
return (0, primitives_1.isNonEmptyString)(value) ? new Set([...timezone_1.IANA_TZ_IDS]).has(value) : false;
|
|
28
30
|
}
|
|
29
31
|
function isNativeTimeZoneId(value) {
|
|
30
|
-
return (0, primitives_1.
|
|
32
|
+
return (0, primitives_1.isNonEmptyString)(value) ?
|
|
33
|
+
new Set(Intl.supportedValuesOf('timeZone')).has(value)
|
|
34
|
+
: false;
|
|
31
35
|
}
|
|
32
36
|
function isLeapYear(year) {
|
|
33
37
|
const $year = (0, utilities_1.normalizeNumber)(year);
|
|
@@ -62,3 +66,6 @@ function isDateLike(value) {
|
|
|
62
66
|
}
|
|
63
67
|
return false;
|
|
64
68
|
}
|
|
69
|
+
function isTimeWithUnit(value) {
|
|
70
|
+
return (0, primitives_1.isNonEmptyString)(value) && constants_1.TIME_UNIT_REGEX.test(value);
|
|
71
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseMSec = parseMSec;
|
|
4
|
+
const primitives_1 = require("../guards/primitives");
|
|
5
|
+
const specials_1 = require("../guards/specials");
|
|
6
|
+
const constants_1 = require("./constants");
|
|
7
|
+
const guards_1 = require("./guards");
|
|
8
|
+
function parseMSec(value, sec = false) {
|
|
9
|
+
if ((0, specials_1.isNumericString)(value)) {
|
|
10
|
+
return _parse(`${value}s`, sec);
|
|
11
|
+
}
|
|
12
|
+
else if ((0, guards_1.isTimeWithUnit)(value)) {
|
|
13
|
+
return _parse(value, sec);
|
|
14
|
+
}
|
|
15
|
+
else if ((0, primitives_1.isNumber)(value)) {
|
|
16
|
+
return _parse(`${value}s`, sec);
|
|
17
|
+
}
|
|
18
|
+
return NaN;
|
|
19
|
+
}
|
|
20
|
+
function _parse(str, sec = false) {
|
|
21
|
+
if (!(0, primitives_1.isNonEmptyString)(str) || str.length > 100) {
|
|
22
|
+
throw new RangeError(`Value must be a string with length between 1 and 99!`);
|
|
23
|
+
}
|
|
24
|
+
const match = constants_1.TIME_UNIT_REGEX.exec(str);
|
|
25
|
+
if (!match?.groups)
|
|
26
|
+
return NaN;
|
|
27
|
+
const unit = (match.groups.unit ?? 'ms').toLowerCase();
|
|
28
|
+
const multiplier = constants_1.MS_MAP[unit];
|
|
29
|
+
if (!multiplier)
|
|
30
|
+
throw new RangeError(`Unknown unit "${unit}"!`);
|
|
31
|
+
const ms = parseFloat(match.groups.value) * multiplier;
|
|
32
|
+
return sec ? ms / 1000 : ms;
|
|
33
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Cipher = void 0;
|
|
4
|
+
const primitives_1 = require("../guards/primitives");
|
|
5
|
+
const specials_1 = require("../guards/specials");
|
|
6
|
+
const helpers_1 = require("./helpers");
|
|
7
|
+
const utils_1 = require("./utils");
|
|
8
|
+
class Cipher {
|
|
9
|
+
#secretBytes;
|
|
10
|
+
#encKey;
|
|
11
|
+
#macKey;
|
|
12
|
+
constructor(secret) {
|
|
13
|
+
if (!(0, primitives_1.isNonEmptyString)(secret)) {
|
|
14
|
+
throw new Error('Secret must be non-empty string!');
|
|
15
|
+
}
|
|
16
|
+
this.#secretBytes = (0, utils_1.utf8ToBytes)(secret);
|
|
17
|
+
this.#encKey = (0, utils_1.hmacSha256)(this.#secretBytes, (0, utils_1.utf8ToBytes)('enc'));
|
|
18
|
+
this.#macKey = (0, utils_1.hmacSha256)(this.#secretBytes, (0, utils_1.utf8ToBytes)('mac'));
|
|
19
|
+
}
|
|
20
|
+
#genKeystream(target, iv) {
|
|
21
|
+
const blocks = Math.ceil(target.length / 32);
|
|
22
|
+
const keystreamParts = [];
|
|
23
|
+
for (let counter = 0; counter < blocks; counter++) {
|
|
24
|
+
keystreamParts.push((0, utils_1.hmacSha256)(this.#encKey, (0, utils_1.concatBytes)(iv, (0, utils_1.intTo4BytesBE)(counter))));
|
|
25
|
+
}
|
|
26
|
+
return (0, utils_1.concatBytes)(...keystreamParts).subarray(0, target.length);
|
|
27
|
+
}
|
|
28
|
+
encrypt(text) {
|
|
29
|
+
const plain = (0, utils_1.utf8ToBytes)(text);
|
|
30
|
+
const seed = (0, utils_1.utf8ToBytes)(String(Date.now()) + '-' + String(Math.random()));
|
|
31
|
+
const ivFull = (0, utils_1.sha256Bytes)(seed);
|
|
32
|
+
const iv = ivFull.subarray(0, 16);
|
|
33
|
+
const keystream = this.#genKeystream(plain, iv);
|
|
34
|
+
const ct = new Uint8Array(plain.length);
|
|
35
|
+
for (let i = 0; i < plain.length; i++)
|
|
36
|
+
ct[i] = plain[i] ^ keystream[i];
|
|
37
|
+
const tag = (0, utils_1.hmacSha256)(this.#macKey, (0, utils_1.concatBytes)(iv, ct));
|
|
38
|
+
const blob = (0, utils_1.concatBytes)(iv, ct, tag);
|
|
39
|
+
return (0, utils_1.bytesToBase64)(blob);
|
|
40
|
+
}
|
|
41
|
+
isValid(token) {
|
|
42
|
+
if (!(0, specials_1.isBase64)(token))
|
|
43
|
+
return false;
|
|
44
|
+
const blob = (0, utils_1.base64ToBytes)(token);
|
|
45
|
+
if (blob.length < 48)
|
|
46
|
+
return false;
|
|
47
|
+
const iv = blob.subarray(0, 16);
|
|
48
|
+
const tag = blob.subarray(blob.length - 32);
|
|
49
|
+
const ct = blob.subarray(16, blob.length - 32);
|
|
50
|
+
const expectedTag = (0, utils_1.hmacSha256)(this.#macKey, (0, utils_1.concatBytes)(iv, ct));
|
|
51
|
+
return (0, helpers_1._constantTimeEquals)(expectedTag, tag);
|
|
52
|
+
}
|
|
53
|
+
decrypt(token) {
|
|
54
|
+
if (!(0, specials_1.isBase64)(token))
|
|
55
|
+
throw new Error('Token must be a base64 string!');
|
|
56
|
+
const blob = (0, utils_1.base64ToBytes)(token);
|
|
57
|
+
if (blob.length < 48)
|
|
58
|
+
throw new Error('Malformed or tampered token!');
|
|
59
|
+
const iv = blob.subarray(0, 16);
|
|
60
|
+
const tag = blob.subarray(blob.length - 32);
|
|
61
|
+
const ct = blob.subarray(16, blob.length - 32);
|
|
62
|
+
const expectedTag = (0, utils_1.hmacSha256)(this.#macKey, (0, utils_1.concatBytes)(iv, ct));
|
|
63
|
+
if (!(0, helpers_1._constantTimeEquals)(expectedTag, tag)) {
|
|
64
|
+
throw new Error('Key in the token is tampered or invalid!)');
|
|
65
|
+
}
|
|
66
|
+
const keystream = this.#genKeystream(ct, iv);
|
|
67
|
+
const pt = new Uint8Array(ct.length);
|
|
68
|
+
for (let i = 0; i < ct.length; i++)
|
|
69
|
+
pt[i] = ct[i] ^ keystream[i];
|
|
70
|
+
return (0, utils_1.bytesToUtf8)(pt);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
exports.Cipher = Cipher;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Signet = void 0;
|
|
4
|
+
const parse_1 = require("../date/parse");
|
|
5
|
+
const non_primitives_1 = require("../guards/non-primitives");
|
|
6
|
+
const primitives_1 = require("../guards/primitives");
|
|
7
|
+
const index_1 = require("../utils/index");
|
|
8
|
+
const helpers_1 = require("./helpers");
|
|
9
|
+
const utils_1 = require("./utils");
|
|
10
|
+
class Signet {
|
|
11
|
+
#secretBytes;
|
|
12
|
+
constructor(secret) {
|
|
13
|
+
if (!(0, primitives_1.isNonEmptyString)(secret)) {
|
|
14
|
+
throw new Error('Secret must be a non-empty string!');
|
|
15
|
+
}
|
|
16
|
+
this.#secretBytes = (0, utils_1.utf8ToBytes)(secret);
|
|
17
|
+
}
|
|
18
|
+
#decode(token) {
|
|
19
|
+
if (!(0, primitives_1.isNonEmptyString)(token)) {
|
|
20
|
+
throw new Error('Token must be a non-empty string!');
|
|
21
|
+
}
|
|
22
|
+
const parts = token.split('.');
|
|
23
|
+
if (parts.length !== 3) {
|
|
24
|
+
throw new Error('Token is tampered or malformed!');
|
|
25
|
+
}
|
|
26
|
+
const [hdr, pld, signature] = parts;
|
|
27
|
+
const headerBytes = (0, utils_1.base64ToBytes)(hdr);
|
|
28
|
+
const payloadBytes = (0, utils_1.base64ToBytes)(pld);
|
|
29
|
+
const headerStr = (0, index_1.stripJsonEdgeGarbage)((0, utils_1.bytesToUtf8)(headerBytes));
|
|
30
|
+
const payloadStr = (0, index_1.stripJsonEdgeGarbage)((0, utils_1.bytesToUtf8)(payloadBytes));
|
|
31
|
+
let header;
|
|
32
|
+
try {
|
|
33
|
+
header = JSON.parse(headerStr);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
throw new Error('Cannot parse header!');
|
|
37
|
+
}
|
|
38
|
+
let payload;
|
|
39
|
+
try {
|
|
40
|
+
const { iat, iatDate, exp, expDate, nbf, nbfDate, aud, sub, iss, ...rest } = JSON.parse(payloadStr);
|
|
41
|
+
payload = {
|
|
42
|
+
iat,
|
|
43
|
+
iatDate: iatDate ? new Date(iatDate) : (0, helpers_1._secToDate)(iat),
|
|
44
|
+
...(exp && { exp }),
|
|
45
|
+
...(exp && { expDate: expDate ? new Date(expDate) : (0, helpers_1._secToDate)(exp) }),
|
|
46
|
+
...(nbf && { nbf }),
|
|
47
|
+
...(nbf && { nbfDate: nbfDate ? new Date(nbfDate) : (0, helpers_1._secToDate)(nbf) }),
|
|
48
|
+
...(aud && { aud }),
|
|
49
|
+
...(sub && { sub }),
|
|
50
|
+
...(iss && { iss }),
|
|
51
|
+
...rest,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
throw new Error('Cannot parse payload!');
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
header,
|
|
59
|
+
payload,
|
|
60
|
+
signature,
|
|
61
|
+
signingInput: `${hdr}.${pld}`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
sign(payload, options) {
|
|
65
|
+
if (!(0, non_primitives_1.isNotEmptyObject)(payload))
|
|
66
|
+
throw new Error('Payload must be a valid object!');
|
|
67
|
+
const { expiresIn, notBefore, audience, issuer, subject } = options || {};
|
|
68
|
+
const iat = (0, helpers_1._toSeconds)(Date.now());
|
|
69
|
+
const $payload = {
|
|
70
|
+
iat,
|
|
71
|
+
iatDate: (0, helpers_1._secToDate)(iat),
|
|
72
|
+
...(expiresIn && { exp: iat + (0, helpers_1._toSeconds)((0, parse_1.parseMSec)(expiresIn)) }),
|
|
73
|
+
...(expiresIn && { expDate: (0, helpers_1._secToDate)(iat + (0, helpers_1._toSeconds)((0, parse_1.parseMSec)(expiresIn))) }),
|
|
74
|
+
...(notBefore && { nbf: iat + (0, helpers_1._toSeconds)((0, parse_1.parseMSec)(notBefore)) }),
|
|
75
|
+
...(notBefore && { nbfDate: (0, helpers_1._secToDate)(iat + (0, helpers_1._toSeconds)((0, parse_1.parseMSec)(notBefore))) }),
|
|
76
|
+
...(audience && { aud: audience }),
|
|
77
|
+
...(subject && { sub: subject }),
|
|
78
|
+
...(issuer && { iss: issuer }),
|
|
79
|
+
...payload,
|
|
80
|
+
};
|
|
81
|
+
const header = { alg: 'HS256', typ: 'SIGNET+JWT' };
|
|
82
|
+
const headerJson = (0, index_1.stableStringify)(header);
|
|
83
|
+
const payloadJson = (0, index_1.stableStringify)($payload);
|
|
84
|
+
const headerB = (0, utils_1.utf8ToBytes)(headerJson);
|
|
85
|
+
const payloadB = (0, utils_1.utf8ToBytes)(payloadJson);
|
|
86
|
+
const signingInput = `${(0, utils_1.bytesToBase64)(headerB)}.${(0, utils_1.bytesToBase64)(payloadB)}`;
|
|
87
|
+
const mac = (0, utils_1.hmacSha256)(this.#secretBytes, (0, utils_1.utf8ToBytes)(signingInput));
|
|
88
|
+
const signature = (0, utils_1.bytesToBase64)(mac);
|
|
89
|
+
return `${signingInput}.${signature}`;
|
|
90
|
+
}
|
|
91
|
+
decode(token) {
|
|
92
|
+
return this.#decode(token);
|
|
93
|
+
}
|
|
94
|
+
hasExpired(token) {
|
|
95
|
+
const { exp } = this.#decode(token).payload;
|
|
96
|
+
return exp ? (0, helpers_1._toSeconds)(Date.now()) > exp : false;
|
|
97
|
+
}
|
|
98
|
+
isTooEarly(token) {
|
|
99
|
+
const { nbf } = this.#decode(token).payload;
|
|
100
|
+
return nbf ? (0, helpers_1._toSeconds)(Date.now()) < nbf : false;
|
|
101
|
+
}
|
|
102
|
+
isInvalidIssuer(token, expected) {
|
|
103
|
+
if (!expected)
|
|
104
|
+
return false;
|
|
105
|
+
const { iss } = this.#decode(token).payload;
|
|
106
|
+
return iss ? iss !== expected : false;
|
|
107
|
+
}
|
|
108
|
+
isInvalidAudience(token, expected) {
|
|
109
|
+
if (!expected)
|
|
110
|
+
return false;
|
|
111
|
+
const { aud } = this.#decode(token).payload;
|
|
112
|
+
if (!aud)
|
|
113
|
+
return false;
|
|
114
|
+
const payloadAud = Array.isArray(aud) ? aud : [aud];
|
|
115
|
+
const expectedAud = Array.isArray(expected) ? expected : [expected];
|
|
116
|
+
return payloadAud.some((tokenAud) => expectedAud.includes(tokenAud));
|
|
117
|
+
}
|
|
118
|
+
isInvalidSubject(token, expected) {
|
|
119
|
+
if (!expected)
|
|
120
|
+
return false;
|
|
121
|
+
const { sub } = this.#decode(token).payload;
|
|
122
|
+
return sub ? sub !== expected : false;
|
|
123
|
+
}
|
|
124
|
+
verify(token, options) {
|
|
125
|
+
try {
|
|
126
|
+
const { signature, signingInput, payload } = this.#decode(token);
|
|
127
|
+
const { audience, issuer, subject } = options || {};
|
|
128
|
+
const expectedMac = (0, utils_1.hmacSha256)(this.#secretBytes, (0, utils_1.utf8ToBytes)(signingInput));
|
|
129
|
+
const expectedSig = (0, utils_1.bytesToBase64)(expectedMac);
|
|
130
|
+
if (!(0, helpers_1._constantTimeEquals)(signature, expectedSig)) {
|
|
131
|
+
throw new Error('Invalid or tampered signature!');
|
|
132
|
+
}
|
|
133
|
+
if (this.hasExpired(token)) {
|
|
134
|
+
throw new Error('Token has expired!');
|
|
135
|
+
}
|
|
136
|
+
if (this.isTooEarly(token)) {
|
|
137
|
+
throw new Error('Token is not active yet!');
|
|
138
|
+
}
|
|
139
|
+
if (this.isInvalidIssuer(token, issuer)) {
|
|
140
|
+
throw new Error('Invalid token issuer!');
|
|
141
|
+
}
|
|
142
|
+
if (this.isInvalidAudience(token, audience)) {
|
|
143
|
+
throw new Error('Invalid token audience(s!');
|
|
144
|
+
}
|
|
145
|
+
if (this.isInvalidSubject(token, subject)) {
|
|
146
|
+
throw new Error('Invalid token subject!');
|
|
147
|
+
}
|
|
148
|
+
return { isValid: true, payload };
|
|
149
|
+
}
|
|
150
|
+
catch (e) {
|
|
151
|
+
return {
|
|
152
|
+
isValid: false,
|
|
153
|
+
error: e instanceof Error ? e.message : String(e),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
verifyOrThrow(token, options) {
|
|
158
|
+
const res = this.verify(token, options);
|
|
159
|
+
if (!res.isValid) {
|
|
160
|
+
throw new Error(res.error || 'Invalid, malformed or expired token!');
|
|
161
|
+
}
|
|
162
|
+
return res;
|
|
163
|
+
}
|
|
164
|
+
decodePayload(token) {
|
|
165
|
+
return this.#decode(token).payload;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
exports.Signet = Signet;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.md5 = md5;
|
|
4
|
+
exports.sha1 = sha1;
|
|
5
|
+
exports.sha256 = sha256;
|
|
6
|
+
const helpers_1 = require("./helpers");
|
|
7
|
+
const utils_1 = require("./utils");
|
|
8
|
+
function md5(str) {
|
|
9
|
+
const state = [1732584193, -271733879, -1732584194, 271733878];
|
|
10
|
+
const len = str.length;
|
|
11
|
+
let i;
|
|
12
|
+
for (i = 64; i <= len; i += 64) {
|
|
13
|
+
(0, helpers_1._md5cycle)(state, (0, helpers_1._stringToNumbers)(str.substring(i - 64, i)));
|
|
14
|
+
}
|
|
15
|
+
const $str = str.substring(i - 64);
|
|
16
|
+
const tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
|
17
|
+
for (i = 0; i < $str.length; i++) {
|
|
18
|
+
tail[i >> 2] |= $str.charCodeAt(i) << (i % 4 << 3);
|
|
19
|
+
}
|
|
20
|
+
tail[i >> 2] |= 0x80 << (i % 4 << 3);
|
|
21
|
+
if (i > 55) {
|
|
22
|
+
(0, helpers_1._md5cycle)(state, tail);
|
|
23
|
+
for (let j = 0; j < 16; j++) {
|
|
24
|
+
tail[j] = 0;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
tail[14] = len * 8;
|
|
28
|
+
(0, helpers_1._md5cycle)(state, tail);
|
|
29
|
+
return state.map(helpers_1._numToHex).join('');
|
|
30
|
+
}
|
|
31
|
+
function sha1(msg) {
|
|
32
|
+
const K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6];
|
|
33
|
+
const utf8 = (0, utils_1.utf8ToBytes)(msg);
|
|
34
|
+
const rotl = (n, bits) => (n << bits) | (n >>> (32 - bits));
|
|
35
|
+
const toHex = (n) => (n >>> 0).toString(16).padStart(8, '0');
|
|
36
|
+
const len = utf8.length;
|
|
37
|
+
const padBytes = (len + 9) % 64 ? 64 - ((len + 9) % 64) : 0;
|
|
38
|
+
const total = len + 1 + padBytes + 8;
|
|
39
|
+
const words = new Uint32Array(total >>> 2);
|
|
40
|
+
for (let i = 0; i < utf8.length; i++) {
|
|
41
|
+
words[i >> 2] |= utf8[i] << (24 - (i % 4) * 8);
|
|
42
|
+
}
|
|
43
|
+
words[utf8.length >> 2] |= 0x80 << (24 - (utf8.length % 4) * 8);
|
|
44
|
+
words[words.length - 1] = utf8.length * 8;
|
|
45
|
+
const h = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0];
|
|
46
|
+
const W = new Uint32Array(80);
|
|
47
|
+
for (let i = 0; i < words.length; i += 16) {
|
|
48
|
+
for (let j = 0; j < 16; j++)
|
|
49
|
+
W[j] = words[i + j] | 0;
|
|
50
|
+
for (let j = 16; j < 80; j++) {
|
|
51
|
+
W[j] = rotl(W[j - 3] ^ W[j - 8] ^ W[j - 14] ^ W[j - 16], 1);
|
|
52
|
+
}
|
|
53
|
+
let a = h[0], b = h[1], c = h[2], d = h[3], e = h[4];
|
|
54
|
+
for (let j = 0; j < 80; j++) {
|
|
55
|
+
let f, k;
|
|
56
|
+
if (j < 20) {
|
|
57
|
+
f = (b & c) | (~b & d);
|
|
58
|
+
k = K[0];
|
|
59
|
+
}
|
|
60
|
+
else if (j < 40) {
|
|
61
|
+
f = b ^ c ^ d;
|
|
62
|
+
k = K[1];
|
|
63
|
+
}
|
|
64
|
+
else if (j < 60) {
|
|
65
|
+
f = (b & c) | (b & d) | (c & d);
|
|
66
|
+
k = K[2];
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
f = b ^ c ^ d;
|
|
70
|
+
k = K[3];
|
|
71
|
+
}
|
|
72
|
+
const temp = (rotl(a, 5) + f + e + k + W[j]) | 0;
|
|
73
|
+
e = d;
|
|
74
|
+
d = c;
|
|
75
|
+
c = rotl(b, 30);
|
|
76
|
+
b = a;
|
|
77
|
+
a = temp;
|
|
78
|
+
}
|
|
79
|
+
h[0] = (h[0] + a) | 0;
|
|
80
|
+
h[1] = (h[1] + b) | 0;
|
|
81
|
+
h[2] = (h[2] + c) | 0;
|
|
82
|
+
h[3] = (h[3] + d) | 0;
|
|
83
|
+
h[4] = (h[4] + e) | 0;
|
|
84
|
+
}
|
|
85
|
+
return h.map(toHex).join('');
|
|
86
|
+
}
|
|
87
|
+
function sha256(msg) {
|
|
88
|
+
return (0, utils_1.bytesToHex)((0, utils_1.sha256Bytes)((0, utils_1.utf8ToBytes)(msg)));
|
|
89
|
+
}
|
package/dist/cjs/hash/helpers.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports._secToDate = exports._toSeconds = void 0;
|
|
3
4
|
exports._numToHex = _numToHex;
|
|
4
5
|
exports._stringToNumbers = _stringToNumbers;
|
|
5
6
|
exports._md5cycle = _md5cycle;
|
|
@@ -9,10 +10,11 @@ exports._clockSeq14 = _clockSeq14;
|
|
|
9
10
|
exports._formatUUID = _formatUUID;
|
|
10
11
|
exports._isOptionV3V5 = _isOptionV3V5;
|
|
11
12
|
exports._checkUUIDVersion = _checkUUIDVersion;
|
|
13
|
+
exports._constantTimeEquals = _constantTimeEquals;
|
|
12
14
|
const non_primitives_1 = require("../guards/non-primitives");
|
|
13
15
|
const primitives_1 = require("../guards/primitives");
|
|
14
16
|
const specials_1 = require("../guards/specials");
|
|
15
|
-
const
|
|
17
|
+
const utils_1 = require("./utils");
|
|
16
18
|
function _add32(x, y) {
|
|
17
19
|
return (x + y) & 0xffffffff;
|
|
18
20
|
}
|
|
@@ -127,13 +129,13 @@ function _uuidTimestamp() {
|
|
|
127
129
|
return uuidMs * 10000n;
|
|
128
130
|
}
|
|
129
131
|
function _randomNode48() {
|
|
130
|
-
const node = (0,
|
|
132
|
+
const node = (0, utils_1.randomHex)(12).split('');
|
|
131
133
|
const firstByte = parseInt(node.slice(0, 2).join(''), 16);
|
|
132
134
|
const modified = (firstByte | 0b00000001).toString(16).padStart(2, '0');
|
|
133
135
|
return modified + node.slice(2).join('');
|
|
134
136
|
}
|
|
135
137
|
function _clockSeq14() {
|
|
136
|
-
const seq = parseInt((0,
|
|
138
|
+
const seq = parseInt((0, utils_1.randomHex)(4), 16) & 0x3fff;
|
|
137
139
|
return seq.toString(16).padStart(4, '0');
|
|
138
140
|
}
|
|
139
141
|
function _formatUUID(h, v, up) {
|
|
@@ -155,3 +157,19 @@ function _isOptionV3V5(opt) {
|
|
|
155
157
|
function _checkUUIDVersion(value, v) {
|
|
156
158
|
return (0, specials_1.isUUID)(value) && value[14] === v;
|
|
157
159
|
}
|
|
160
|
+
function _constantTimeEquals(a, b) {
|
|
161
|
+
if (a.length !== b.length)
|
|
162
|
+
return false;
|
|
163
|
+
const _getRes = (x, idx) => {
|
|
164
|
+
return (0, primitives_1.isString)(x) ? x.charCodeAt(idx) : x[idx];
|
|
165
|
+
};
|
|
166
|
+
let res = 0;
|
|
167
|
+
for (let i = 0; i < a.length; i++) {
|
|
168
|
+
res |= _getRes(a, i) ^ _getRes(b, i);
|
|
169
|
+
}
|
|
170
|
+
return res === 0;
|
|
171
|
+
}
|
|
172
|
+
const _toSeconds = (ms) => Math.floor(ms / 1000);
|
|
173
|
+
exports._toSeconds = _toSeconds;
|
|
174
|
+
const _secToDate = (sec) => new Date(sec * 1000);
|
|
175
|
+
exports._secToDate = _secToDate;
|