@lumjs/encode 2.4.0 → 2.5.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 +24 -1
- package/lib/base64.js +40 -27
- package/lib/base91.js +3 -5
- package/lib/hash.js +16 -11
- package/lib/hotp.js +52 -23
- package/lib/index.js +21 -7
- package/lib/polyfill.js +135 -0
- package/lib/sets/_inc.js +18 -0
- package/lib/sets/all.js +14 -0
- package/lib/sets/base.js +20 -0
- package/lib/sets/digest.js +16 -0
- package/lib/sets/otp.js +18 -0
- package/lib/sets/sign.js +20 -0
- package/lib/totp.js +10 -1
- package/lib/util.js +103 -84
- package/package.json +7 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [2.5.0] - 2026-02-20
|
|
10
|
+
### Added
|
|
11
|
+
- A bunch of extra exports that are _module-sets_.
|
|
12
|
+
- `util.bytesToHex()` to be the inverse of `hexToBytes()`.
|
|
13
|
+
- A new `polyfill` sub-module that is not part of the default exports.
|
|
14
|
+
Currently just has polyfills for a few newer Uint8Array methods.
|
|
15
|
+
### Changed
|
|
16
|
+
- Added options to `util.hexToBytes()` for returning a Uint8Array.
|
|
17
|
+
- Added options to `base64.fromBytes()` and `base64.toBytes()`.
|
|
18
|
+
|
|
19
|
+
## [2.4.1] - 2026-02-09
|
|
20
|
+
### Changed
|
|
21
|
+
- Refactored hashifier a bit to make resetting progressive digests simpler.
|
|
22
|
+
- Made all the debugging info in hotp/totp modules optional.
|
|
23
|
+
- Added `expires` to compiled options for totp module; provides the number
|
|
24
|
+
of seconds until the _current_ code expires.
|
|
25
|
+
- Added a getExpiry() method to totp class that calculates and returns
|
|
26
|
+
just the current expiry information (useful for countdown displays).
|
|
27
|
+
- Muted an expected error message in a test file.
|
|
28
|
+
- Some other minor cleanups.
|
|
29
|
+
|
|
9
30
|
## [2.4.0] - 2026-01-19
|
|
10
31
|
### Added
|
|
11
32
|
- A new `pem` module (which exports a `PEM` class) for parsing PEM strings.
|
|
@@ -85,7 +106,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
85
106
|
### Added
|
|
86
107
|
- Initial release.
|
|
87
108
|
|
|
88
|
-
[Unreleased]: https://github.com/supernovus/lum.encode.js/compare/v2.
|
|
109
|
+
[Unreleased]: https://github.com/supernovus/lum.encode.js/compare/v2.5.0...HEAD
|
|
110
|
+
[2.5.0]: https://github.com/supernovus/lum.encode.js/compare/v2.4.1...v2.5.0
|
|
111
|
+
[2.4.1]: https://github.com/supernovus/lum.encode.js/compare/v2.4.0...v2.4.1
|
|
89
112
|
[2.4.0]: https://github.com/supernovus/lum.encode.js/compare/v2.3.2...v2.4.0
|
|
90
113
|
[2.3.2]: https://github.com/supernovus/lum.encode.js/compare/v2.3.1...v2.3.2
|
|
91
114
|
[2.3.1]: https://github.com/supernovus/lum.encode.js/compare/v2.3.0...v2.3.1
|
package/lib/base64.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
const {
|
|
2
|
+
const { isObj } = require('@lumjs/core/types');
|
|
3
3
|
|
|
4
4
|
const D_MIME = 'application/octet-stream';
|
|
5
5
|
const D_ENC = 'utf-8';
|
|
@@ -8,7 +8,7 @@ const P_B64 = ';base64,';
|
|
|
8
8
|
const R_PRE = /^data\:(.*?);base64,/;
|
|
9
9
|
const B_64U = 'base64url';
|
|
10
10
|
|
|
11
|
-
const UI8_FB64 = (typeof Uint8Array.fromBase64 ===
|
|
11
|
+
const UI8_FB64 = (typeof Uint8Array.fromBase64 === 'function');
|
|
12
12
|
const URL_CHARS = /_-/;
|
|
13
13
|
|
|
14
14
|
/**
|
|
@@ -67,18 +67,24 @@ function deurlize(string)
|
|
|
67
67
|
*
|
|
68
68
|
* This is a low-level function with minimal options.
|
|
69
69
|
* See `decodeText()` for a more full-featured function.
|
|
70
|
-
*
|
|
71
|
-
* This now checks to see if `Uint8Array.fromBase64()` exists,
|
|
72
|
-
* and if it does, will use it. Otherwise it uses the original
|
|
73
|
-
* encoding algorithm.
|
|
74
70
|
*
|
|
75
|
-
* @param {string} base64 - Base64 encoded-string
|
|
76
|
-
* @param {object} [options]
|
|
71
|
+
* @param {string} base64 - Base64 encoded-string.
|
|
72
|
+
* @param {object} [options] Options.
|
|
73
|
+
* @param {boolean} [options.native=true] Use fromBase64() if it exists?
|
|
74
|
+
*
|
|
75
|
+
* When enabled, this checks to see if `Uint8Array.fromBase64()` exists,
|
|
76
|
+
* and if it does, will use it, passing the options to it.
|
|
77
|
+
*
|
|
78
|
+
* If this is disabled, the original toBytes algorithm will be used.
|
|
79
|
+
*
|
|
80
|
+
* This option is enabled by default, the only reason I could think of to
|
|
81
|
+
* disable it is if you are using this function as a polyfill.
|
|
82
|
+
*
|
|
77
83
|
* @returns {Uint8Array}
|
|
78
84
|
*/
|
|
79
85
|
function toBytes(base64, options={})
|
|
80
86
|
{
|
|
81
|
-
if (UI8_FB64)
|
|
87
|
+
if (UI8_FB64 && (options.native ?? true))
|
|
82
88
|
{
|
|
83
89
|
return Uint8Array.fromBase64(base64, options);
|
|
84
90
|
}
|
|
@@ -92,18 +98,24 @@ function toBytes(base64, options={})
|
|
|
92
98
|
*
|
|
93
99
|
* This is a low-level function with no options.
|
|
94
100
|
* See `encodeText()` for a more full-featured function.
|
|
95
|
-
*
|
|
96
|
-
* This now checks to see if `bytes.toBase64()` exists,
|
|
97
|
-
* and if it does, will use it. Otherwise it uses the original
|
|
98
|
-
* decoding algorithm.
|
|
99
101
|
*
|
|
100
|
-
* @param {Uint8Array} bytes - Byte array to convert
|
|
101
|
-
* @param {object} [options]
|
|
102
|
+
* @param {Uint8Array} bytes - Byte array to convert.
|
|
103
|
+
* @param {object} [options] Options.
|
|
104
|
+
* @param {boolean} [options.native=true] Use toBase64() if it exists?
|
|
105
|
+
*
|
|
106
|
+
* When enabled, this checks to see if `bytes.toBase64()` exists,
|
|
107
|
+
* and if it does, will use it, passing the options to it.
|
|
108
|
+
*
|
|
109
|
+
* If this is disabled, the original fromBytes algorithm will be used.
|
|
110
|
+
*
|
|
111
|
+
* This option is enabled by default, the only reason I could think of to
|
|
112
|
+
* disable it is if you are using this function as a polyfill.
|
|
113
|
+
*
|
|
102
114
|
* @returns {string}
|
|
103
115
|
*/
|
|
104
116
|
function fromBytes(bytes, options={})
|
|
105
117
|
{
|
|
106
|
-
if (typeof bytes.toBase64 ===
|
|
118
|
+
if ((options.native ?? true) && typeof bytes.toBase64 === 'function')
|
|
107
119
|
{
|
|
108
120
|
return bytes.toBase64(options);
|
|
109
121
|
}
|
|
@@ -127,10 +139,11 @@ function fromBytes(bytes, options={})
|
|
|
127
139
|
*
|
|
128
140
|
* If this is a Uint8Array, we can skip the TextEncoder part.
|
|
129
141
|
*
|
|
130
|
-
* @param {(object|boolean)} [options] Options
|
|
142
|
+
* @param {(object|boolean)} [options] Options.
|
|
131
143
|
*
|
|
132
|
-
* - If
|
|
133
|
-
* - Passed to
|
|
144
|
+
* - If boolean, used as `options.url`.
|
|
145
|
+
* - Passed to urlize() if `options.url` is true.
|
|
146
|
+
* - Always passed to fromBytes().
|
|
134
147
|
*
|
|
135
148
|
* @param {boolean} [options.url=false] Urlize the output?
|
|
136
149
|
* If true, converts `+`, `/`, and `=` to URL-friendly alternatives.
|
|
@@ -139,7 +152,7 @@ function fromBytes(bytes, options={})
|
|
|
139
152
|
*/
|
|
140
153
|
function encodeText(data, options={})
|
|
141
154
|
{
|
|
142
|
-
if (typeof options ===
|
|
155
|
+
if (typeof options === 'boolean')
|
|
143
156
|
{ // Assume the 'url' option.
|
|
144
157
|
options = {url: options};
|
|
145
158
|
}
|
|
@@ -149,15 +162,15 @@ function encodeText(data, options={})
|
|
|
149
162
|
const encoder = new TextEncoder();
|
|
150
163
|
data = encoder.encode(data);
|
|
151
164
|
}
|
|
152
|
-
const toB64 = (typeof data.toBase64 ===
|
|
165
|
+
const toB64 = (typeof data.toBase64 === 'function');
|
|
153
166
|
|
|
154
167
|
if (toB64 && options.url)
|
|
155
168
|
{
|
|
156
|
-
if (typeof options.alphabet !==
|
|
169
|
+
if (typeof options.alphabet !== 'string')
|
|
157
170
|
{
|
|
158
171
|
options.alphabet = B_64U;
|
|
159
172
|
}
|
|
160
|
-
if (!options.useTildes && typeof options.omitPadding !==
|
|
173
|
+
if (!options.useTildes && typeof options.omitPadding !== 'boolean')
|
|
161
174
|
{
|
|
162
175
|
options.omitPadding = true;
|
|
163
176
|
}
|
|
@@ -192,7 +205,7 @@ function encodeText(data, options={})
|
|
|
192
205
|
*/
|
|
193
206
|
function decodeText(base64, options={})
|
|
194
207
|
{
|
|
195
|
-
if (typeof options ===
|
|
208
|
+
if (typeof options === 'boolean')
|
|
196
209
|
{ // Assume the 'url' option.
|
|
197
210
|
options = {url: options};
|
|
198
211
|
}
|
|
@@ -201,7 +214,7 @@ function decodeText(base64, options={})
|
|
|
201
214
|
{ // Unless explicitly disabled, use deurlize() first.
|
|
202
215
|
if (UI8_FB64)
|
|
203
216
|
{
|
|
204
|
-
if (typeof options.alphabet !==
|
|
217
|
+
if (typeof options.alphabet !== 'string')
|
|
205
218
|
{
|
|
206
219
|
if (URL_CHARS.test(base64))
|
|
207
220
|
{
|
|
@@ -365,7 +378,7 @@ async function decodeData(base64, options={})
|
|
|
365
378
|
{ // Unless explicitly disabled, use deurlize() first.
|
|
366
379
|
base64 = deurlize(base64);
|
|
367
380
|
}
|
|
368
|
-
const type = (typeof options.type ===
|
|
381
|
+
const type = (typeof options.type === 'string') ? options.type : D_MIME;
|
|
369
382
|
base64 = P_DATA+type+P_B64+base64;
|
|
370
383
|
}
|
|
371
384
|
|
|
@@ -392,7 +405,7 @@ async function decodeData(base64, options={})
|
|
|
392
405
|
*/
|
|
393
406
|
function encode(data, options={})
|
|
394
407
|
{
|
|
395
|
-
if (options.blob || options.file || (typeof data !==
|
|
408
|
+
if (options.blob || options.file || (typeof data !== 'string'))
|
|
396
409
|
{
|
|
397
410
|
return encodeData(data, options);
|
|
398
411
|
}
|
package/lib/base91.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
const {S,B} = require('@lumjs/core/types');
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* A pure-Javascript base91 library.
|
|
5
3
|
*
|
|
@@ -33,7 +31,7 @@ exports.encode = function(data)
|
|
|
33
31
|
{
|
|
34
32
|
let output = '';
|
|
35
33
|
let len = data.length,
|
|
36
|
-
isStr = (typeof data ===
|
|
34
|
+
isStr = (typeof data === 'string'),
|
|
37
35
|
queue = 0,
|
|
38
36
|
numbits = 0,
|
|
39
37
|
value = 0;
|
|
@@ -131,7 +129,7 @@ exports.decode = function(data, opts={})
|
|
|
131
129
|
{
|
|
132
130
|
const output = [];
|
|
133
131
|
let len = data.length,
|
|
134
|
-
isStr = (typeof data ===
|
|
132
|
+
isStr = (typeof data === 'string'),
|
|
135
133
|
queue = 0,
|
|
136
134
|
numbits = 0,
|
|
137
135
|
value = -1,
|
|
@@ -164,7 +162,7 @@ exports.decode = function(data, opts={})
|
|
|
164
162
|
output.push(queue | (value << numbits));
|
|
165
163
|
}
|
|
166
164
|
|
|
167
|
-
if (typeof opts ===
|
|
165
|
+
if (typeof opts === 'boolean')
|
|
168
166
|
{
|
|
169
167
|
opts = {string: opts};
|
|
170
168
|
}
|
package/lib/hash.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const { isObj, isNil } = require('@lumjs/core/types');
|
|
4
4
|
|
|
5
5
|
const util = require('./util');
|
|
6
6
|
const base32 = require('./base32');
|
|
@@ -130,7 +130,7 @@ module.exports = class
|
|
|
130
130
|
*/
|
|
131
131
|
constructor(options={})
|
|
132
132
|
{
|
|
133
|
-
if (typeof options ===
|
|
133
|
+
if (typeof options === 'string')
|
|
134
134
|
{
|
|
135
135
|
options = {algo: options};
|
|
136
136
|
}
|
|
@@ -146,7 +146,7 @@ module.exports = class
|
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
this.algo = this.getAlgorithm(
|
|
149
|
-
(typeof options.algo ===
|
|
149
|
+
(typeof options.algo === 'string')
|
|
150
150
|
? options.algo
|
|
151
151
|
: D_ALGO);
|
|
152
152
|
|
|
@@ -243,11 +243,11 @@ module.exports = class
|
|
|
243
243
|
|
|
244
244
|
const joiner = this.current.joiner;
|
|
245
245
|
|
|
246
|
-
if (typeof joiner ===
|
|
246
|
+
if (typeof joiner === 'function')
|
|
247
247
|
{
|
|
248
248
|
input = joiner.call(this, this.current.hash);
|
|
249
249
|
}
|
|
250
|
-
else if (typeof joiner ===
|
|
250
|
+
else if (typeof joiner === 'string')
|
|
251
251
|
{
|
|
252
252
|
input = this.current.hash.join(joiner);
|
|
253
253
|
}
|
|
@@ -258,10 +258,10 @@ module.exports = class
|
|
|
258
258
|
}
|
|
259
259
|
|
|
260
260
|
// Now clear the current hash values.
|
|
261
|
-
this.
|
|
261
|
+
this.reset();
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
-
if (typeof input ===
|
|
264
|
+
if (typeof input === 'string')
|
|
265
265
|
{ // This is super simple.
|
|
266
266
|
const encoder = new TextEncoder();
|
|
267
267
|
input = encoder.encode(input);
|
|
@@ -377,12 +377,12 @@ module.exports = class
|
|
|
377
377
|
*/
|
|
378
378
|
add(input, opts={})
|
|
379
379
|
{
|
|
380
|
-
if (typeof input !==
|
|
380
|
+
if (typeof input !== 'string')
|
|
381
381
|
{
|
|
382
382
|
let enc = this.current.encoder,
|
|
383
383
|
eopts = null;
|
|
384
384
|
|
|
385
|
-
if (typeof enc ===
|
|
385
|
+
if (typeof enc === 'string')
|
|
386
386
|
{
|
|
387
387
|
enc = DATA_ENCODERS[enc];
|
|
388
388
|
eopts = this.defaults[enc];
|
|
@@ -391,11 +391,11 @@ module.exports = class
|
|
|
391
391
|
// Compile the options for the encoder.
|
|
392
392
|
eopts = Object.assign({hashifier: this}, eopts, opts);
|
|
393
393
|
|
|
394
|
-
if (typeof enc ===
|
|
394
|
+
if (typeof enc === 'function')
|
|
395
395
|
{ // Call the function, using the hashifier instance as `this`.
|
|
396
396
|
input = enc.call(this, input, eopts);
|
|
397
397
|
}
|
|
398
|
-
else if (isObj(enc) && typeof enc.encode ===
|
|
398
|
+
else if (isObj(enc) && typeof enc.encode === 'function')
|
|
399
399
|
{ // Using an encoder object/instance.
|
|
400
400
|
input = enc.encode(input, eopts);
|
|
401
401
|
}
|
|
@@ -432,6 +432,11 @@ module.exports = class
|
|
|
432
432
|
return this;
|
|
433
433
|
}
|
|
434
434
|
|
|
435
|
+
reset() {
|
|
436
|
+
this.current.hash.length = 0;
|
|
437
|
+
return this;
|
|
438
|
+
}
|
|
439
|
+
|
|
435
440
|
static new(opts={})
|
|
436
441
|
{
|
|
437
442
|
return new this(opts);
|
package/lib/hotp.js
CHANGED
|
@@ -3,11 +3,17 @@
|
|
|
3
3
|
const HmacEncoder = require('./hmac');
|
|
4
4
|
const { intToBytes } = require('./util');
|
|
5
5
|
|
|
6
|
+
const DEBUG = Object.freeze({
|
|
7
|
+
LOG: 1,
|
|
8
|
+
INFO: 2,
|
|
9
|
+
});
|
|
10
|
+
|
|
6
11
|
const DEF_OPTS = {
|
|
7
12
|
algorithm: 'SHA-1',
|
|
8
13
|
checkSize: 7,
|
|
9
|
-
counter: 0,
|
|
10
|
-
|
|
14
|
+
counter: 0,
|
|
15
|
+
debug: 0,
|
|
16
|
+
window: 50
|
|
11
17
|
};
|
|
12
18
|
|
|
13
19
|
const cp = Object.assign;
|
|
@@ -21,6 +27,9 @@ function needKey(key) {
|
|
|
21
27
|
|
|
22
28
|
/**
|
|
23
29
|
* HMAC-based One-Time-Passwords.
|
|
30
|
+
*
|
|
31
|
+
* TODO: this needs documentation!
|
|
32
|
+
*
|
|
24
33
|
* @exports module:@lumjs/encode/hotp
|
|
25
34
|
*/
|
|
26
35
|
class HOTP {
|
|
@@ -50,9 +59,11 @@ class HOTP {
|
|
|
50
59
|
return [DEF_OPTS];
|
|
51
60
|
}
|
|
52
61
|
|
|
53
|
-
async generate(key = this.defaultKey, opts) {
|
|
54
|
-
|
|
55
|
-
|
|
62
|
+
async generate(key = this.defaultKey, opts, fromVerify=false) {
|
|
63
|
+
if (!fromVerify) {
|
|
64
|
+
needKey(key);
|
|
65
|
+
opts = this.getOptions(opts);
|
|
66
|
+
}
|
|
56
67
|
|
|
57
68
|
let encoder = new HmacEncoder(key, opts);
|
|
58
69
|
let data = new Uint8Array(intToBytes(opts.counter));
|
|
@@ -70,20 +81,27 @@ class HOTP {
|
|
|
70
81
|
let code = Array(opts.checkSize - v2.length).join('0') + v2;
|
|
71
82
|
|
|
72
83
|
let res = {
|
|
73
|
-
opts,
|
|
74
|
-
data,
|
|
75
|
-
hash,
|
|
76
|
-
hashBytes: hb,
|
|
77
|
-
offset,
|
|
78
|
-
v1,
|
|
79
|
-
v2,
|
|
80
84
|
code,
|
|
85
|
+
opts,
|
|
81
86
|
toString() {
|
|
82
87
|
return this.code;
|
|
83
88
|
},
|
|
84
89
|
}
|
|
85
90
|
|
|
86
|
-
if (opts.debug
|
|
91
|
+
if (opts.debug & DEBUG.INFO) {
|
|
92
|
+
cp(res, {
|
|
93
|
+
data,
|
|
94
|
+
hash,
|
|
95
|
+
hashBytes: hb,
|
|
96
|
+
offset,
|
|
97
|
+
v1,
|
|
98
|
+
v2,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (!fromVerify && (opts.debug & DEBUG.LOG)) {
|
|
103
|
+
console.debug(res.code, res);
|
|
104
|
+
}
|
|
87
105
|
|
|
88
106
|
return res;
|
|
89
107
|
}
|
|
@@ -95,25 +113,36 @@ class HOTP {
|
|
|
95
113
|
let win = opts.window;
|
|
96
114
|
let cnt = opts.counter;
|
|
97
115
|
let info = { ok: false };
|
|
116
|
+
let di = (opts.debug & DEBUG.INFO);
|
|
98
117
|
|
|
99
|
-
|
|
118
|
+
let done = (add) => {
|
|
119
|
+
if (add) cp(info, add); // add final info
|
|
120
|
+
if (opts.debug & DEBUG.LOG) console.debug(info);
|
|
121
|
+
|
|
122
|
+
if (!info.ok && opts.throw) {
|
|
123
|
+
let EClass = isError(opts.throw) ? opts.throw : Error;
|
|
124
|
+
throw new EClass("OTP verification failure");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return info;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (di) info.stack = [];
|
|
100
131
|
|
|
101
132
|
for (let i = cnt - win; i <= cnt + win; ++i) {
|
|
102
133
|
opts.counter = i;
|
|
103
|
-
let res = this.generate(key, opts);
|
|
104
|
-
if (
|
|
134
|
+
let res = this.generate(key, opts, true);
|
|
135
|
+
if (di) info.stack.push(res);
|
|
105
136
|
if (res.code === token) {
|
|
106
|
-
return
|
|
137
|
+
return done({ ok: true, delta: i - cnt });
|
|
107
138
|
}
|
|
108
139
|
}
|
|
109
140
|
|
|
110
|
-
|
|
111
|
-
let EClass = isError(opts.throw) ? opts.throw : Error;
|
|
112
|
-
throw new EClass("OTP verification failure");
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return info;
|
|
141
|
+
return done();
|
|
116
142
|
}
|
|
117
143
|
}
|
|
118
144
|
|
|
145
|
+
HOTP.DEBUG = DEBUG;
|
|
146
|
+
HOTP.prototype.DEBUG = DEBUG;
|
|
147
|
+
|
|
119
148
|
module.exports = HOTP;
|
package/lib/index.js
CHANGED
|
@@ -1,26 +1,40 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* A full set of encoding utilities.
|
|
3
|
+
*
|
|
4
|
+
* This module includes alias properties for all sub-modules except `polyfill`.
|
|
5
|
+
*
|
|
6
|
+
* This currently uses lazy-loading for everything other than `util`,
|
|
7
|
+
* but in version 3.0 I will be rewriting this package into ESM format,
|
|
8
|
+
* and the default module will become an alias for the `all` sub-module.
|
|
9
|
+
*
|
|
10
|
+
* I'd suggest using one of the named sub-modules or module-sets if you
|
|
11
|
+
* want to load only specific components.
|
|
12
|
+
*
|
|
3
13
|
* @module @lumjs/encode
|
|
4
14
|
*/
|
|
5
15
|
|
|
6
|
-
const {
|
|
7
|
-
|
|
8
|
-
const E = def.e;
|
|
9
|
-
|
|
16
|
+
const {df,lazy} = require('@lumjs/core');
|
|
17
|
+
const E = {enumerable: true};
|
|
10
18
|
const util = require('./util');
|
|
11
19
|
|
|
12
20
|
/**
|
|
13
21
|
* @alias module:@lumjs/encode.util
|
|
14
22
|
* @see {@link module:@lumjs/encode/util}
|
|
15
23
|
*/
|
|
16
|
-
|
|
24
|
+
df(exports, 'Util', {value: util}, E);
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @alias module:@lumjs/encode.util
|
|
28
|
+
* @see {@link module:@lumjs/encode/util}
|
|
29
|
+
*/
|
|
30
|
+
df(exports, 'util', {value: util}, E);
|
|
17
31
|
|
|
18
32
|
/**
|
|
19
33
|
* @alias module:@lumjs/encode.ord
|
|
20
34
|
* @deprecated this alias to `util.ord` will be removed in 3.x.
|
|
21
35
|
* @see {@link module:@lumjs/encode/util.ord}
|
|
22
36
|
*/
|
|
23
|
-
|
|
37
|
+
df(exports, 'ord', util.ord, E);
|
|
24
38
|
|
|
25
39
|
/**
|
|
26
40
|
* @name module:@lumjs/encode.numByteArray
|
|
@@ -28,7 +42,7 @@ def(exports, 'ord', util.ord, E);
|
|
|
28
42
|
* @deprecated this alias to `util.numByteArray` will be removed in 3.x.
|
|
29
43
|
* @see {@link module:@lumjs/encode/util.numByteArray}
|
|
30
44
|
*/
|
|
31
|
-
|
|
45
|
+
df(exports, 'numByteArray', util.numByteArray, E);
|
|
32
46
|
|
|
33
47
|
/**
|
|
34
48
|
* @name module:@lumjs/encode.Base32
|
package/lib/polyfill.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Some simple polyfills.
|
|
3
|
+
* @module @lumjs/encode/polyfill
|
|
4
|
+
*/
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const cp = Object.assign;
|
|
8
|
+
const { isComplex, isObj } = require('@lumjs/core/types');
|
|
9
|
+
const { bytesToHex, hexToBytes } = require('./util.js');
|
|
10
|
+
const { fromBytes: bytesToB64, toBytes: b64ToBytes } = require('./base64.js');
|
|
11
|
+
|
|
12
|
+
const NON = { native: false };
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Polyfills for Uint8Array.
|
|
16
|
+
*
|
|
17
|
+
* This is an array of two ruleset objects:
|
|
18
|
+
*
|
|
19
|
+
* - Uint8Array
|
|
20
|
+
* - fromBase64()
|
|
21
|
+
* - fromHex()
|
|
22
|
+
* - Uint8Array.prototype
|
|
23
|
+
* - toBase64()
|
|
24
|
+
* - toHex()
|
|
25
|
+
*
|
|
26
|
+
* @alias module:@lumjs/encode/polyfill.UI8
|
|
27
|
+
* @type {PolyfillRuleset[]}
|
|
28
|
+
*/
|
|
29
|
+
const UI8 = [
|
|
30
|
+
{
|
|
31
|
+
into: Uint8Array,
|
|
32
|
+
fill: {
|
|
33
|
+
fromBase64(string, options) {
|
|
34
|
+
return b64ToBytes(string, cp({}, options, NON));
|
|
35
|
+
},
|
|
36
|
+
fromHex(string) {
|
|
37
|
+
return hexToBytes(string, true, false);
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
into: Uint8Array.prototype,
|
|
43
|
+
fill: {
|
|
44
|
+
toBase64(options) {
|
|
45
|
+
return bytesToB64(this, cp({}, options, NON))
|
|
46
|
+
},
|
|
47
|
+
toHex() {
|
|
48
|
+
return bytesToHex(this, false);
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
const isPolyfill = v => (isObj(v)
|
|
55
|
+
&& isComplex(v.into)
|
|
56
|
+
&& isObj(v.fill)
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Process one or more polyfill definitions.
|
|
61
|
+
* @param {(PolyfillRuleset|PolyfillRuleset[])} rules - Rulesets to apply.
|
|
62
|
+
*
|
|
63
|
+
* You can pass a single Ruleset object, or an array of associated Rulesets.
|
|
64
|
+
*
|
|
65
|
+
* @returns {Map}
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
*
|
|
69
|
+
* For these examples I'll be applying the `UI8` polyfills.
|
|
70
|
+
*
|
|
71
|
+
* **Usage if using *ESModules***:
|
|
72
|
+
*
|
|
73
|
+
* ```js
|
|
74
|
+
* import { polyfill, UI8 } from '@lumjs/encode/polyfill';
|
|
75
|
+
* polyfill(UI8);
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
78
|
+
* **OR if using *CommonJS***:
|
|
79
|
+
*
|
|
80
|
+
* ```js
|
|
81
|
+
* const { polyfill, UI8 } = require('@lumjs/encode/polyfill');
|
|
82
|
+
* polyfill(UI8);
|
|
83
|
+
* ```
|
|
84
|
+
*
|
|
85
|
+
* @alias module:@lumjs/encode/polyfill.polyfill
|
|
86
|
+
*/
|
|
87
|
+
function polyfill(rules) {
|
|
88
|
+
let filled = new Map();
|
|
89
|
+
|
|
90
|
+
if (!Array.isArray(rules)) {
|
|
91
|
+
rules = [rules];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
for (let rule of rules) {
|
|
95
|
+
|
|
96
|
+
if (Array.isArray(rule)) {
|
|
97
|
+
polyfill(...rule);
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
else if (!isPolyfill(rule)) {
|
|
101
|
+
console.error('invalid polyfill definition', rule);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
let target = rule.into;
|
|
106
|
+
for (let meth in rule.fill) {
|
|
107
|
+
if (target[meth] === undefined) {
|
|
108
|
+
target[meth] = rule.fill[meth];
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return filled;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
module.exports = {NON, UI8, isPolyfill, polyfill}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Polyfill Ruleset
|
|
120
|
+
* @typedef {object} PolyfillRuleset
|
|
121
|
+
*
|
|
122
|
+
* @prop {(object|function)} into - The target to polyfill.
|
|
123
|
+
*
|
|
124
|
+
* Class constructors are functions, class prototypes are objects.
|
|
125
|
+
* Each Ruleset may only have one target, so if you need to polyfill
|
|
126
|
+
* both static and instance methods you'll need to use an array with
|
|
127
|
+
* a Ruleset for the constructor, and a Ruleset for the prototype.
|
|
128
|
+
*
|
|
129
|
+
* @prop {object} fill - An object containing the polyfill methods.
|
|
130
|
+
*
|
|
131
|
+
* Any method in this object that doesn't exist in the `for` target,
|
|
132
|
+
* will be added to it. As these are expected to be methods respecting
|
|
133
|
+
* the `this` context variable they should NOT be arrow (`=>`) closures.
|
|
134
|
+
*
|
|
135
|
+
*/
|
package/lib/sets/_inc.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Make lowercase aliases for every key in an object.
|
|
3
|
+
* @param {object} obj - Target object.
|
|
4
|
+
* @returns {object} `obj`
|
|
5
|
+
*/
|
|
6
|
+
function makeSet(obj) {
|
|
7
|
+
for (let key in obj) {
|
|
8
|
+
let lc = key.toLowerCase();
|
|
9
|
+
if (key !== lc) {
|
|
10
|
+
obj[lc] = obj[key];
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return obj;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
module.exports = {
|
|
17
|
+
makeSet,
|
|
18
|
+
}
|
package/lib/sets/all.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const { makeSet } = require('./_inc.js');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A module-set that includes all sub-modules except `polyfill`.
|
|
5
|
+
*
|
|
6
|
+
* More specifically this composes together the `digest` and `otp`
|
|
7
|
+
* module-sets (which in turn compose `base` and `sign` respectively).
|
|
8
|
+
*
|
|
9
|
+
* @alias module:@lumjs/encode/all
|
|
10
|
+
*/
|
|
11
|
+
module.exports = makeSet({
|
|
12
|
+
...(require('./digest')),
|
|
13
|
+
...(require('./otp')),
|
|
14
|
+
});
|
package/lib/sets/base.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const { makeSet } = require('./_inc.js');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A module-set for working with encodings.
|
|
5
|
+
*
|
|
6
|
+
* Includes:
|
|
7
|
+
* - Base32
|
|
8
|
+
* - Base64
|
|
9
|
+
* - Base91
|
|
10
|
+
* - Util
|
|
11
|
+
* As well as lowercase aliases for all of those.
|
|
12
|
+
*
|
|
13
|
+
* @module @lumjs/encode/base
|
|
14
|
+
*/
|
|
15
|
+
module.exports = makeSet({
|
|
16
|
+
Base32: require('../base32'),
|
|
17
|
+
Base64: require('../base64'),
|
|
18
|
+
Base91: require('../base91'),
|
|
19
|
+
Util: require('../util'),
|
|
20
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const { makeSet } = require('./_inc.js');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A module-set for working with digests (aka data hashes).
|
|
5
|
+
*
|
|
6
|
+
* Includes:
|
|
7
|
+
* - Hash
|
|
8
|
+
* As well as lowercase aliases for all of those,
|
|
9
|
+
* and everything from the `base` set.
|
|
10
|
+
*
|
|
11
|
+
* @module @lumjs/encode/digest
|
|
12
|
+
*/
|
|
13
|
+
module.exports = makeSet({
|
|
14
|
+
...(require('./base.js')),
|
|
15
|
+
Hash: require('../hash.js'),
|
|
16
|
+
});
|
package/lib/sets/otp.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const { makeSet } = require('./_inc.js');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A module-set for working with One-Time-Passwords (OTP).
|
|
5
|
+
*
|
|
6
|
+
* Includes:
|
|
7
|
+
* - HOTP
|
|
8
|
+
* - TOTP
|
|
9
|
+
* As well as lowercase aliases for all of those,
|
|
10
|
+
* and everything from the `sign` set.
|
|
11
|
+
*
|
|
12
|
+
* @module @lumjs/encode/otp
|
|
13
|
+
*/
|
|
14
|
+
module.exports = makeSet({
|
|
15
|
+
...(require('./sign')),
|
|
16
|
+
HOTP: require('../hotp'),
|
|
17
|
+
TOTP: require('../totp'),
|
|
18
|
+
});
|
package/lib/sets/sign.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const { makeSet } = require('./_inc.js');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A module-set for working with digital signatures.
|
|
5
|
+
*
|
|
6
|
+
* Includes:
|
|
7
|
+
* - HMAC
|
|
8
|
+
* - PEM
|
|
9
|
+
* - Signature
|
|
10
|
+
* - Util
|
|
11
|
+
* As well as lowercase aliases for all of those.
|
|
12
|
+
*
|
|
13
|
+
* @module @lumjs/encode/sign
|
|
14
|
+
*/
|
|
15
|
+
module.exports = makeSet({
|
|
16
|
+
HMAC: require('../hmac.js'),
|
|
17
|
+
PEM: require('../pem.js'),
|
|
18
|
+
Signature: require('../signature.js'),
|
|
19
|
+
Util: require('../util.js'),
|
|
20
|
+
});
|
package/lib/totp.js
CHANGED
|
@@ -5,6 +5,9 @@ const DEF_OPTS = {step: 30};
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Time-based One-Time-Passwords.
|
|
8
|
+
*
|
|
9
|
+
* TODO: this needs documentation!
|
|
10
|
+
*
|
|
8
11
|
* @exports module:@lumjs/encode/totp
|
|
9
12
|
*/
|
|
10
13
|
class TOTP extends HOTP {
|
|
@@ -12,10 +15,16 @@ class TOTP extends HOTP {
|
|
|
12
15
|
return [...super.defaultOptions, DEF_OPTS];
|
|
13
16
|
}
|
|
14
17
|
|
|
18
|
+
getExpiry(opts) {
|
|
19
|
+
return this.getOptions(opts).expires;
|
|
20
|
+
}
|
|
21
|
+
|
|
15
22
|
getOptions() {
|
|
16
23
|
let opts = super.getOptions(...arguments);
|
|
17
24
|
if (!opts.time) opts.time = Date.now();
|
|
18
|
-
|
|
25
|
+
let ts = opts.time / 1000;
|
|
26
|
+
opts.counter = Math.floor(ts / opts.step);
|
|
27
|
+
opts.expires = 30 - Math.floor(ts) % 30;
|
|
19
28
|
return opts;
|
|
20
29
|
}
|
|
21
30
|
}
|
package/lib/util.js
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
const { TypedArray } = require('@lumjs/core/types');
|
|
8
8
|
|
|
9
|
+
const UI8_FHEX = (typeof Uint8Array.fromHex === 'function');
|
|
10
|
+
|
|
9
11
|
/**
|
|
10
12
|
* Return the ASCII/Unicode number for a character.
|
|
11
13
|
*
|
|
@@ -18,8 +20,7 @@ const { TypedArray } = require('@lumjs/core/types');
|
|
|
18
20
|
* @param {string} string
|
|
19
21
|
* @returns {number}
|
|
20
22
|
*/
|
|
21
|
-
exports.ord = function (string)
|
|
22
|
-
{
|
|
23
|
+
exports.ord = function (string) {
|
|
23
24
|
// discuss at: https://locutus.io/php/ord/
|
|
24
25
|
// original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
|
|
25
26
|
// bugfixed by: Onno Marsman
|
|
@@ -32,12 +33,10 @@ exports.ord = function (string)
|
|
|
32
33
|
|
|
33
34
|
var str = string + '',
|
|
34
35
|
code = str.charCodeAt(0);
|
|
35
|
-
if (0xD800 <= code && code <= 0xDBFF)
|
|
36
|
-
{
|
|
36
|
+
if (0xD800 <= code && code <= 0xDBFF) {
|
|
37
37
|
// High surrogate (could change last hex to 0xDB7F to treat high private surrogates as single characters)
|
|
38
38
|
var hi = code;
|
|
39
|
-
if (str.length === 1)
|
|
40
|
-
{
|
|
39
|
+
if (str.length === 1) {
|
|
41
40
|
// This is just a high surrogate with no following low surrogate, so we return its value;
|
|
42
41
|
return code;
|
|
43
42
|
// we could also throw an error as it is not a complete character, but someone may want to know
|
|
@@ -45,8 +44,7 @@ exports.ord = function (string)
|
|
|
45
44
|
var low = str.charCodeAt(1);
|
|
46
45
|
return ((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000;
|
|
47
46
|
}
|
|
48
|
-
if (0xDC00 <= code && code <= 0xDFFF)
|
|
49
|
-
{
|
|
47
|
+
if (0xDC00 <= code && code <= 0xDFFF) {
|
|
50
48
|
// Low surrogate
|
|
51
49
|
// This is just a low surrogate with no preceding high surrogate, so we return its value;
|
|
52
50
|
return code;
|
|
@@ -94,67 +92,56 @@ exports.ord = function (string)
|
|
|
94
92
|
*
|
|
95
93
|
* @returns {Array} An array of integers.
|
|
96
94
|
*/
|
|
97
|
-
exports.numByteArray = function (numStr, options={})
|
|
98
|
-
{
|
|
99
|
-
|
|
100
|
-
{
|
|
101
|
-
options = {size: options};
|
|
95
|
+
exports.numByteArray = function (numStr, options = {}) {
|
|
96
|
+
if (typeof options === 'number') {
|
|
97
|
+
options = { size: options };
|
|
102
98
|
}
|
|
103
99
|
|
|
104
|
-
const numOpt = (name, defval, min, max) =>
|
|
105
|
-
{
|
|
100
|
+
const numOpt = (name, defval, min, max) => {
|
|
106
101
|
const optval = options[name];
|
|
107
|
-
if (typeof optval !== 'number')
|
|
108
|
-
{ // Was not a number, skip it.
|
|
102
|
+
if (typeof optval !== 'number') { // Was not a number, skip it.
|
|
109
103
|
return defval;
|
|
110
104
|
}
|
|
111
|
-
if (optval < min)
|
|
112
|
-
{ // Value was lower than minimum.
|
|
105
|
+
if (optval < min) { // Value was lower than minimum.
|
|
113
106
|
throw new RangeError(`${name} value ${optval} is less than ${min}`);
|
|
114
107
|
}
|
|
115
|
-
if (max !== 0 && optval > max)
|
|
116
|
-
{ // Value was higher than maximum.
|
|
108
|
+
if (max !== 0 && optval > max) { // Value was higher than maximum.
|
|
117
109
|
throw new RangeError(`${name} value ${optval} is more than ${max}`);
|
|
118
110
|
}
|
|
119
111
|
|
|
120
112
|
return optval;
|
|
121
113
|
}
|
|
122
114
|
|
|
123
|
-
const len
|
|
115
|
+
const len = numOpt('size', 2, 1, 0);
|
|
124
116
|
const base = numOpt('base', 16, 2, 36);
|
|
125
117
|
|
|
126
118
|
let strLen = numStr.length;
|
|
127
119
|
let remainder = strLen % len;
|
|
128
120
|
|
|
129
|
-
if (options.strict && remainder !== 0)
|
|
130
|
-
{
|
|
121
|
+
if (options.strict && remainder !== 0) {
|
|
131
122
|
throw new RangeError(`string length ${strLen} is not divisible by ${len}`);
|
|
132
123
|
}
|
|
133
|
-
else if (options.pad && remainder !== 0)
|
|
134
|
-
{
|
|
124
|
+
else if (options.pad && remainder !== 0) {
|
|
135
125
|
const padSize = len - remainder;
|
|
136
|
-
numStr = numStr.padStart(strLen+padSize, '0');
|
|
126
|
+
numStr = numStr.padStart(strLen + padSize, '0');
|
|
137
127
|
strLen = numStr.length;
|
|
138
128
|
remainder = strLen % len;
|
|
139
|
-
if (remainder !== 0)
|
|
140
|
-
|
|
141
|
-
console.debug({numStr, strLen, len, remainder, arguments});
|
|
129
|
+
if (remainder !== 0) { // Something is wrong in the universe...
|
|
130
|
+
console.error({ numStr, strLen, len, remainder, arguments });
|
|
142
131
|
throw new Error("string has remainder after padding");
|
|
143
132
|
}
|
|
144
133
|
}
|
|
145
134
|
|
|
146
|
-
const endOf = strLen - (len-1);
|
|
135
|
+
const endOf = strLen - (len - 1);
|
|
147
136
|
const bytes = [];
|
|
148
137
|
|
|
149
|
-
const getBytes = (a,b) => bytes.push(parseInt(numStr.substring(a, b), base));
|
|
138
|
+
const getBytes = (a, b) => bytes.push(parseInt(numStr.substring(a, b), base));
|
|
150
139
|
|
|
151
|
-
for(let i=0; i < endOf; i+=len)
|
|
152
|
-
|
|
153
|
-
getBytes(i, i+len);
|
|
140
|
+
for (let i = 0; i < endOf; i += len) {
|
|
141
|
+
getBytes(i, i + len);
|
|
154
142
|
}
|
|
155
143
|
|
|
156
|
-
if (remainder !== 0)
|
|
157
|
-
{
|
|
144
|
+
if (remainder !== 0) {
|
|
158
145
|
getBytes(strLen - remainder, strLen);
|
|
159
146
|
}
|
|
160
147
|
|
|
@@ -167,27 +154,26 @@ exports.numByteArray = function (numStr, options={})
|
|
|
167
154
|
* @param {WordArray} wordArray
|
|
168
155
|
* @returns {Uint8Array}
|
|
169
156
|
*/
|
|
170
|
-
exports.wordArrayToUint8Array = function(wordArray)
|
|
171
|
-
|
|
172
|
-
const
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
result[i++] = (w & 0x000000ff);
|
|
157
|
+
exports.wordArrayToUint8Array = function (wordArray) {
|
|
158
|
+
const l = wordArray.sigBytes;
|
|
159
|
+
const words = wordArray.words;
|
|
160
|
+
const result = new Uint8Array(l);
|
|
161
|
+
var i = 0 /*dst*/, j = 0 /*src*/;
|
|
162
|
+
while (true) {
|
|
163
|
+
// here i is a multiple of 4
|
|
164
|
+
if (i == l)
|
|
165
|
+
break;
|
|
166
|
+
var w = words[j++];
|
|
167
|
+
result[i++] = (w & 0xff000000) >>> 24;
|
|
168
|
+
if (i == l)
|
|
169
|
+
break;
|
|
170
|
+
result[i++] = (w & 0x00ff0000) >>> 16;
|
|
171
|
+
if (i == l)
|
|
172
|
+
break;
|
|
173
|
+
result[i++] = (w & 0x0000ff00) >>> 8;
|
|
174
|
+
if (i == l)
|
|
175
|
+
break;
|
|
176
|
+
result[i++] = (w & 0x000000ff);
|
|
191
177
|
}
|
|
192
178
|
return result;
|
|
193
179
|
}
|
|
@@ -199,35 +185,70 @@ exports.wordArrayToUint8Array = function(wordArray)
|
|
|
199
185
|
* and was borrowed from the `notp` package.
|
|
200
186
|
*
|
|
201
187
|
* @param {Integer} num
|
|
202
|
-
* @
|
|
188
|
+
* @returns {Array} bytes
|
|
203
189
|
*/
|
|
204
|
-
exports.intToBytes = function(num)
|
|
205
|
-
|
|
206
|
-
let bytes = [];
|
|
190
|
+
exports.intToBytes = function (num) {
|
|
191
|
+
let bytes = [];
|
|
207
192
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
193
|
+
for (let i = 7; i >= 0; --i) {
|
|
194
|
+
bytes[i] = num & (255);
|
|
195
|
+
num = num >> 8;
|
|
196
|
+
}
|
|
213
197
|
|
|
214
|
-
|
|
198
|
+
return bytes;
|
|
215
199
|
}
|
|
216
200
|
|
|
217
201
|
/**
|
|
218
|
-
* Convert a hex
|
|
202
|
+
* Convert a hex string to a byte array.
|
|
219
203
|
*
|
|
220
|
-
*
|
|
204
|
+
* Original version was also from the `notp` package,
|
|
205
|
+
* with some of my own enhancements added.
|
|
221
206
|
*
|
|
222
|
-
* @param {
|
|
223
|
-
* @
|
|
207
|
+
* @param {string} hex - Hex string to convert to a byte array.
|
|
208
|
+
* @param {boolean} [uint8=false] Return a Uint8Array?
|
|
209
|
+
* @param {boolean} [native=true] Use Uint8Array.fromHex() if it exists?
|
|
210
|
+
*
|
|
211
|
+
* Obviously only applicable if `unit8` is true, this will use the native
|
|
212
|
+
* method if it exists. The only reason I could think of to disable this
|
|
213
|
+
* is if you are using this function as a polyfill.
|
|
214
|
+
*
|
|
215
|
+
* @returns {(number[]|Uint8Array)}
|
|
216
|
+
*/
|
|
217
|
+
exports.hexToBytes = function (hex, uint8 = false, native = true) {
|
|
218
|
+
|
|
219
|
+
if (uint8 && native && UI8_FHEX) {
|
|
220
|
+
// A shortcut for modern JS runtimes.
|
|
221
|
+
return Uint8Array.fromHex(hex);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
let bytes = [];
|
|
225
|
+
for (let c = 0, C = hex.length; c < C; c += 2) {
|
|
226
|
+
bytes.push(parseInt(hex.substring(c, c+2), 16));
|
|
227
|
+
}
|
|
228
|
+
return uint8 ? new Uint8Array(bytes) : bytes;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Converts a byte array to a hex string.
|
|
233
|
+
*
|
|
234
|
+
* @param {(Uint8Array|number[])} bytes - Byte array.
|
|
235
|
+
* @param {boolean} [native=true] Use bytes.toHex() if it exists?
|
|
236
|
+
*
|
|
237
|
+
* Like the same-named option in hexToBytes, the only reason I could
|
|
238
|
+
* think of to disable this is if you are using this as a polyfill
|
|
239
|
+
* for the `Uint8Array.prototype.toHex` method.
|
|
240
|
+
*
|
|
241
|
+
* @returns {string}
|
|
224
242
|
*/
|
|
225
|
-
exports.
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
243
|
+
exports.bytesToHex = function (bytes, native = true) {
|
|
244
|
+
|
|
245
|
+
if (native && typeof bytes.toHex === 'function') {
|
|
246
|
+
return bytes.toHex();
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return Array.from(bytes, function (byte) {
|
|
250
|
+
return ('0' + (byte & 0xFF).toString(16)).slice(-2);
|
|
251
|
+
}).join('');
|
|
231
252
|
}
|
|
232
253
|
|
|
233
254
|
/**
|
|
@@ -248,21 +269,19 @@ exports.hexToBytes = function(hex) {
|
|
|
248
269
|
* @returns {TypedArray} Will be an instance of `typeClass`.
|
|
249
270
|
* @throws {TypeError} If invalid arguments were passed.
|
|
250
271
|
*/
|
|
251
|
-
function str2ta(str, typeClass=Uint8Array)
|
|
252
|
-
{
|
|
272
|
+
function str2ta(str, typeClass = Uint8Array) {
|
|
253
273
|
let valid = {
|
|
254
274
|
str: (typeof str === 'string'),
|
|
255
275
|
typeClass: (TypedArray.isPrototypeOf(typeClass)),
|
|
256
276
|
}
|
|
257
277
|
if (!valid.str || !valid.typeClass) {
|
|
258
|
-
console.error('str2ab valid:', valid, 'values: ', {str, typeClass});
|
|
278
|
+
console.error('str2ab valid:', valid, 'values: ', { str, typeClass });
|
|
259
279
|
throw new TypeError("invalid arguments");
|
|
260
280
|
}
|
|
261
281
|
|
|
262
|
-
let buf = new ArrayBuffer(str.length*typeClass.BYTES_PER_ELEMENT);
|
|
282
|
+
let buf = new ArrayBuffer(str.length * typeClass.BYTES_PER_ELEMENT);
|
|
263
283
|
let bufView = new typeClass(buf);
|
|
264
|
-
for (let i = 0, strLen = str.length; i < strLen; i++)
|
|
265
|
-
{
|
|
284
|
+
for (let i = 0, strLen = str.length; i < strLen; i++) {
|
|
266
285
|
bufView[i] = str.charCodeAt(i);
|
|
267
286
|
}
|
|
268
287
|
|
package/package.json
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lumjs/encode",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.0",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"exports":
|
|
6
6
|
{
|
|
7
7
|
".": "./lib/index.js",
|
|
8
|
+
"./all": "./lib/sets/all.js",
|
|
9
|
+
"./base": "./lib/sets/base.js",
|
|
8
10
|
"./base32": "./lib/base32.js",
|
|
9
11
|
"./base64": "./lib/base64.js",
|
|
10
12
|
"./base91": "./lib/base91.js",
|
|
13
|
+
"./digest": "./lib/sets/digest.js",
|
|
11
14
|
"./hash": "./lib/hash.js",
|
|
12
15
|
"./hmac": "./lib/hmac.js",
|
|
13
16
|
"./hotp": "./lib/hotp.js",
|
|
17
|
+
"./otp": "./lib/sets/otp.js",
|
|
14
18
|
"./pem": "./lib/pem.js",
|
|
19
|
+
"./polyfill": "./lib/polyfill.js",
|
|
20
|
+
"./sign": "./lib/sets/sign.js",
|
|
15
21
|
"./signature": "./lib/signature.js",
|
|
16
22
|
"./totp": "./lib/totp.js",
|
|
17
23
|
"./util": "./lib/util.js",
|