@lumjs/encode 1.2.0 → 2.0.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/README.md +18 -3
- package/lib/base64.js +350 -29
- package/lib/base91.js +4 -4
- package/lib/hash.js +293 -124
- package/lib/index.js +0 -12
- package/lib/util.js +1 -0
- package/package.json +5 -11
- package/TODO.md +0 -3
- package/lib/crypto/index.js +0 -171
- package/lib/crypto/load.js +0 -344
- package/lib/safe64/common.js +0 -40
- package/lib/safe64/header.js +0 -142
- package/lib/safe64/index.js +0 -466
- package/lib/safe64/json.js +0 -12
- package/lib/safe64/php.js +0 -15
- package/lib/safe64/settings.js +0 -85
- package/lib/safe64/ubjson.js +0 -23
package/README.md
CHANGED
|
@@ -2,9 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
A bunch of encoding libraries.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
## 2.x Release Notes
|
|
6
|
+
|
|
7
|
+
Version `2.0` is pretty much a complete rewrite, and as the major version
|
|
8
|
+
change indicates, is not 100% backwards compatible. I've tried to make the
|
|
9
|
+
migration process as painless as possible, but some changes will be required.
|
|
10
|
+
|
|
11
|
+
- Split the [Safe64] libraries into their own package.
|
|
12
|
+
- Rewrote the `base64` and `hash` libraries to use modern `ES2015+` APIs.
|
|
13
|
+
- Dropped the dependency on the legacy `crypto-js` package.
|
|
14
|
+
- The `base64` libraries now have additional `async` functions for working
|
|
15
|
+
with arbitrary data in addition to the synchronous ones for Unicode text.
|
|
16
|
+
- The `hash` library now uses `async` methods due to the `SubtleCrypto` API
|
|
17
|
+
that we're now using for generating the hashes.
|
|
18
|
+
- Minor cleanups in `base91` and `utils` modules.
|
|
8
19
|
|
|
9
20
|
## Official URLs
|
|
10
21
|
|
|
@@ -20,3 +31,7 @@ Timothy Totten <2010@totten.ca>
|
|
|
20
31
|
## License
|
|
21
32
|
|
|
22
33
|
[MIT](https://spdx.org/licenses/MIT.html)
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
[Safe64]: https://github.com/supernovus/lum.safe64-data.js
|
package/lib/base64.js
CHANGED
|
@@ -1,55 +1,376 @@
|
|
|
1
1
|
|
|
2
|
-
const {S,isObj} = require('@lumjs/core/types');
|
|
3
|
-
|
|
4
|
-
const
|
|
2
|
+
const {S,B,isObj} = require('@lumjs/core/types');
|
|
3
|
+
|
|
4
|
+
const D_MIME = 'application/octet-stream';
|
|
5
|
+
const D_ENC = 'utf-8';
|
|
6
|
+
const P_DATA = 'data:';
|
|
7
|
+
const P_B64 = ';base64,';
|
|
8
|
+
const R_PRE = /^data\:(.*?);base64,/;
|
|
5
9
|
|
|
6
10
|
/**
|
|
7
11
|
* Base64 functions.
|
|
8
12
|
*
|
|
9
|
-
*
|
|
13
|
+
* Several functions based on code from MDN guides:
|
|
14
|
+
* https://developer.mozilla.org/en-US/docs/Glossary/Base64
|
|
10
15
|
*
|
|
11
16
|
* @module @lumjs/encode/base64
|
|
12
17
|
*/
|
|
13
18
|
|
|
14
19
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* @param {(string|WordArray)} rawdata - The data we want to encode.
|
|
20
|
+
* Make a Base64 string URL-safe.
|
|
18
21
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
22
|
+
* Converts `+` to `-` and `/` to `_`.
|
|
23
|
+
* By default it also strips `=` padding characters.
|
|
21
24
|
*
|
|
22
|
-
* @param {
|
|
25
|
+
* @param {string} string - A Base64-encoded string
|
|
26
|
+
* @param {object} [options] Options
|
|
27
|
+
* @param {boolean} [options.useTildes=false] Use tildes?
|
|
23
28
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
29
|
+
* Replaces `=` with `~` characters instead of stripping them.
|
|
30
|
+
* This option is for backwards-compatibility with old code only,
|
|
31
|
+
* and there's no reason to use it these days.
|
|
32
|
+
*
|
|
33
|
+
* @returns {string}
|
|
28
34
|
*/
|
|
29
|
-
|
|
35
|
+
function urlize(string, options={})
|
|
30
36
|
{
|
|
31
|
-
|
|
32
|
-
|
|
37
|
+
string = string.replaceAll('+', '-');
|
|
38
|
+
string = string.replaceAll('/', '_');
|
|
39
|
+
string = string.replaceAll('=', options.useTildes ? '~' : '');
|
|
40
|
+
return string;
|
|
33
41
|
}
|
|
34
42
|
|
|
35
43
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
44
|
+
* Undoes the effects of `urlize()`
|
|
45
|
+
*
|
|
46
|
+
* Doesn't matter if the string has actually been passed to `urlize()`,
|
|
47
|
+
* nor if the obsolete `options.useTildes` option was used when encoding.
|
|
48
|
+
*
|
|
49
|
+
* @param {string} string
|
|
50
|
+
* @returns {string}
|
|
51
|
+
*/
|
|
52
|
+
function deurlize(string)
|
|
53
|
+
{
|
|
54
|
+
string = string.replaceAll('-', '+');
|
|
55
|
+
string = string.replaceAll('_', '/');
|
|
56
|
+
string = string.replaceAll('~', '=');
|
|
57
|
+
string += "===".substring((string.length+3)%4);
|
|
58
|
+
return string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Convert a Base64-encoded string into a Uint8Array.
|
|
63
|
+
*
|
|
64
|
+
* This is a low-level function with no options.
|
|
65
|
+
* See `decodeText()` for a more full-featured function.
|
|
66
|
+
*
|
|
67
|
+
* @param {string} base64 - Base64 encoded-string
|
|
68
|
+
* @returns {Uint8Array}
|
|
69
|
+
*/
|
|
70
|
+
function toBytes(base64)
|
|
71
|
+
{
|
|
72
|
+
const binString = atob(base64);
|
|
73
|
+
return Uint8Array.from(binString, (m) => m.codePointAt(0));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Convert a Uint8Array into Base64-encoded string.
|
|
78
|
+
*
|
|
79
|
+
* This is a low-level function with no options.
|
|
80
|
+
* See `encodeText()` for a more full-featured function.
|
|
81
|
+
*
|
|
82
|
+
* @param {Uint8Array} bytes - Byte array to convert
|
|
83
|
+
* @returns {string}
|
|
84
|
+
*/
|
|
85
|
+
function fromBytes(bytes)
|
|
86
|
+
{
|
|
87
|
+
const binString = Array.from(bytes, (byte) =>
|
|
88
|
+
String.fromCodePoint(byte),
|
|
89
|
+
).join("");
|
|
90
|
+
return btoa(binString);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Encode a string to Base64.
|
|
95
|
+
*
|
|
96
|
+
* Uses the `TextEncoder` API and `fromBytes()`.
|
|
97
|
+
* May optionally pass the output through `urlize()`.
|
|
98
|
+
*
|
|
99
|
+
* @param {string} data - Any valid (Unicode) string
|
|
100
|
+
* @param {(object|boolean)} [options] Options
|
|
101
|
+
*
|
|
102
|
+
* - If `boolean`, used as `options.url`
|
|
103
|
+
* - Passed to `urlize()` if `options.url` is `true`
|
|
104
|
+
*
|
|
105
|
+
* @param {boolean} [options.url=false] Urlize the output?
|
|
106
|
+
* If true, converts `+`, `/`, and `=` to URL-friendly alternatives.
|
|
107
|
+
*
|
|
108
|
+
* @returns {string} A Base64-encoded string
|
|
109
|
+
*/
|
|
110
|
+
function encodeText(data, options={})
|
|
111
|
+
{
|
|
112
|
+
if (typeof options === B)
|
|
113
|
+
{ // Assume the 'url' option.
|
|
114
|
+
options = {url: options};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const encoder = new TextEncoder();
|
|
118
|
+
const base64 = fromBytes(encoder.encode(data));
|
|
119
|
+
return options.url ? urlize(base64, options) : base64;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Decode a Base64 string into a Unicode string.
|
|
124
|
+
*
|
|
125
|
+
* Uses `toBytes()` and the `TextDecoder` API.
|
|
126
|
+
* Will pass input through `deurlize()` by default.
|
|
127
|
+
*
|
|
128
|
+
* @param {string} base64 - A Base64 string to decode
|
|
129
|
+
* @param {(object|boolean)} [options] Options
|
|
130
|
+
*
|
|
131
|
+
* - If `boolean`, used as `options.url`
|
|
132
|
+
* - Passed to `new TextDecoder()`
|
|
133
|
+
* - Passed to `decoder.decode()`
|
|
134
|
+
*
|
|
135
|
+
* @param {boolean} [options.url=true] Deurlize the output?
|
|
136
|
+
*
|
|
137
|
+
* Unless this is explicitly set as `false`, the `base64`
|
|
138
|
+
* string will be passed to `deurlize()` before being
|
|
139
|
+
* processed further.
|
|
140
|
+
*
|
|
141
|
+
* @returns {string} A Unicode string
|
|
142
|
+
*/
|
|
143
|
+
function decodeText(base64, options={})
|
|
144
|
+
{
|
|
145
|
+
if (typeof options === B)
|
|
146
|
+
{ // Assume the 'url' option.
|
|
147
|
+
options = {url: options};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (options.url !== false)
|
|
151
|
+
{ // Unless explicitly disabled, use deurlize() first.
|
|
152
|
+
base64 = deurlize(base64);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const encoding = options.encoding ?? D_ENC;
|
|
156
|
+
const decoder = new TextDecoder(encoding, options);
|
|
157
|
+
return decoder.decode(toBytes(base64), options);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Encode binary data into a Base64-encoded Data URL.
|
|
162
|
+
*
|
|
163
|
+
* @param {(File|Blob|Array|TypedArray|ArrayBuffer)} data - Data to encode
|
|
164
|
+
*
|
|
165
|
+
* If this is not a `Blob` or `File`, it will be converted into one.
|
|
166
|
+
*
|
|
167
|
+
* @param {object} [options] Options
|
|
168
|
+
*
|
|
169
|
+
* @param {object} [options.blob] Options for Blob instances.
|
|
170
|
+
*
|
|
171
|
+
* If specified, this will be passed to the `Blob()` constructor.
|
|
172
|
+
*
|
|
173
|
+
* Only used if `data` is not already a `Blob` or `File` instance,
|
|
174
|
+
* and `options.file` was not specified or set to `false`.
|
|
175
|
+
*
|
|
176
|
+
* @param {(object|boolean)} [options.file] Options for File instances.
|
|
39
177
|
*
|
|
40
|
-
*
|
|
178
|
+
* If this is any non-false value, and `data` is not already a `Blob`,
|
|
179
|
+
* then we will convert `data` into a `File` instance instead of a `Blob`.
|
|
41
180
|
*
|
|
42
|
-
*
|
|
43
|
-
* Default is `CryptoJS.enc.Utf8`
|
|
181
|
+
* If this is an `object`, it will be passed to the `File()` constructor.
|
|
44
182
|
*
|
|
45
|
-
*
|
|
183
|
+
* @param {string} [options.file.name] Filename for the `File` instance.
|
|
184
|
+
*
|
|
185
|
+
* This is likely never needed, but is kept for completion sake.
|
|
186
|
+
*
|
|
187
|
+
* @returns {Promise<string>} Resolves to the Data URL
|
|
188
|
+
*/
|
|
189
|
+
async function toDataUrl(data, options={})
|
|
190
|
+
{
|
|
191
|
+
if (!(data instanceof Blob))
|
|
192
|
+
{ // Build a Blob or File instance out of the passed data.
|
|
193
|
+
if (!Array.isArray(data))
|
|
194
|
+
{ // Wrap the data in an Array.
|
|
195
|
+
data = [data];
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Sources for our Blob/File options.
|
|
199
|
+
const optsrc = [{type: D_MIME}, options];
|
|
200
|
+
|
|
201
|
+
if (options.file)
|
|
202
|
+
{ // Let's build a File.
|
|
203
|
+
if (isObj(options.file))
|
|
204
|
+
{
|
|
205
|
+
optsrc.push(options.file);
|
|
206
|
+
}
|
|
207
|
+
const fopts = Object.assign(...optsrc);
|
|
208
|
+
const fname = fopts.filename ?? fopts.name ?? '';
|
|
209
|
+
data = new File(data, fname, fopts);
|
|
210
|
+
}
|
|
211
|
+
else
|
|
212
|
+
{ // Let's build a Blob.
|
|
213
|
+
if (isObj(options.blob))
|
|
214
|
+
{
|
|
215
|
+
optsrc.push(options.blob);
|
|
216
|
+
}
|
|
217
|
+
const bopts = Object.assign(...optsrc);
|
|
218
|
+
data = new Blob(data, bopts);
|
|
219
|
+
}
|
|
220
|
+
} // Ensure sufficient Blobiness.
|
|
221
|
+
|
|
222
|
+
return await new Promise((resolve, reject) =>
|
|
223
|
+
{
|
|
224
|
+
const reader = Object.assign(new FileReader(),
|
|
225
|
+
{
|
|
226
|
+
onload: () => resolve(reader.result),
|
|
227
|
+
onerror: () => reject(reader.error),
|
|
228
|
+
});
|
|
229
|
+
reader.readAsDataURL(data);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
} // toDataUrl()
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Decode a Data URL into arbitrary binary data.
|
|
236
|
+
*
|
|
237
|
+
* @param {string} dataUrl - A valid Data URL
|
|
238
|
+
* @param {object} [options] Options
|
|
239
|
+
* @param {boolean} [options.response=false] Return `Response`
|
|
240
|
+
* @param {boolean} [options.buffer=false] Return `ArrayBuffer`
|
|
46
241
|
*
|
|
47
|
-
* @
|
|
242
|
+
* @returns {Promise<(Uint8Array|ArrayBuffer|Response)>} Promise of data
|
|
243
|
+
*
|
|
244
|
+
* By default this resolves to a `Uint8Array` instance.
|
|
245
|
+
*
|
|
246
|
+
* See `options.response` and `options.buffer` for alternative values that
|
|
247
|
+
* this may resolve to if requested.
|
|
248
|
+
*
|
|
249
|
+
*/
|
|
250
|
+
async function fromDataUrl(dataUrl, options={})
|
|
251
|
+
{
|
|
252
|
+
const res = await fetch(dataUrl);
|
|
253
|
+
if (options.response) return res;
|
|
254
|
+
const buf = await res.arrayBuffer();
|
|
255
|
+
if (options.buffer) return buf;
|
|
256
|
+
return new Uint8Array(buf);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* A wrapper around `toDataUrl()` that strips the Data URL header,
|
|
261
|
+
* leaving just the Base64 string, and can emit URL-safe strings.
|
|
262
|
+
*
|
|
263
|
+
* @param {mixed} data - See `toDataUrl()` for valid values
|
|
264
|
+
* @param {object} [options] Options
|
|
265
|
+
*
|
|
266
|
+
* - Passed to `toDataUrl()`
|
|
267
|
+
* - Passed to `urlize()` if `options.url` is `true`
|
|
268
|
+
*
|
|
269
|
+
* @param {boolean} [options.url=false] Use `urlize()` on encoded string?
|
|
270
|
+
*
|
|
271
|
+
* @returns {Promise<string>} Resolves to a Base64 string
|
|
272
|
+
*/
|
|
273
|
+
async function encodeData(data, options={})
|
|
274
|
+
{
|
|
275
|
+
let base64 = await toDataUrl(data, options).replace(R_PRE, '');
|
|
276
|
+
return options.url ? urlize(base64, options) : base64;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* A wrapper around `fromDataUrl()` that adds a Data URL header
|
|
281
|
+
* if necessary, and can handle URL-safe Base64 strings.
|
|
282
|
+
*
|
|
283
|
+
* @param {*} base64
|
|
284
|
+
* @param {*} options
|
|
285
|
+
*
|
|
286
|
+
* - Passed to `fromDataUrl()`
|
|
287
|
+
* - Passed to `deurlize()` if `options.url` is NOT set to `false`
|
|
288
|
+
*
|
|
289
|
+
* @param {boolean} [options.url=true] Use `deurlize()` on decoded string?
|
|
290
|
+
*
|
|
291
|
+
* @returns {Promise} See `fromDataUrl()` for more details
|
|
292
|
+
*/
|
|
293
|
+
async function decodeData(base64, options={})
|
|
294
|
+
{
|
|
295
|
+
if (!R_PRE.test(base64))
|
|
296
|
+
{ // Assume a raw base64 string.
|
|
297
|
+
if (options.url !== false)
|
|
298
|
+
{ // Unless explicitly disabled, use deurlize() first.
|
|
299
|
+
base64 = deurlize(base64);
|
|
300
|
+
}
|
|
301
|
+
const type = (typeof options.type === S) ? options.type : D_MIME;
|
|
302
|
+
base64 = P_DATA+type+P_B64+base64;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return fromDataUrl(base64, options);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Encode data into a base64 string
|
|
310
|
+
*
|
|
311
|
+
* Uses `encodeText()` unless the `data` or `options` have specific
|
|
312
|
+
* values that indicate `encodeData()` should be used instead.
|
|
313
|
+
*
|
|
314
|
+
* @param {*} data - Data to encode
|
|
315
|
+
*
|
|
316
|
+
* If this is anything other than a `string`, `encodeData()` will be used.
|
|
317
|
+
*
|
|
318
|
+
* @param {object} [options] Options
|
|
319
|
+
*
|
|
320
|
+
* If either `options.blob` or `options.file` are specified,
|
|
321
|
+
* `encodeData()` will be used.
|
|
322
|
+
*
|
|
323
|
+
* @returns {(string|Promise<string>)}
|
|
324
|
+
* See `encodeText()` and `encodeData()` for details.
|
|
325
|
+
*/
|
|
326
|
+
function encode(data, options={})
|
|
327
|
+
{
|
|
328
|
+
if (options.blob || options.file || (typeof data !== S))
|
|
329
|
+
{
|
|
330
|
+
return encodeData(data, options);
|
|
331
|
+
}
|
|
332
|
+
else
|
|
333
|
+
{
|
|
334
|
+
return encodeText(data, options);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Decode a base64 string into data
|
|
340
|
+
*
|
|
341
|
+
* Uses `decodeText()` unless the `base64` or `options` have specific
|
|
342
|
+
* values that indicate `decodeData()` should be used.
|
|
343
|
+
*
|
|
344
|
+
* @param {string} base64 - Base64-encoded string (or a Data URL).
|
|
345
|
+
*
|
|
346
|
+
* If this begins with a Data URL header, `decodeData()` will be used.
|
|
347
|
+
*
|
|
348
|
+
* @param {object} [options] Options
|
|
349
|
+
*
|
|
350
|
+
* If either `options.response` or `options.buffer` are true,
|
|
351
|
+
* `decodeData()` will be used.
|
|
352
|
+
*
|
|
353
|
+
* @returns {mixed} See `decodeText()` and `decodeData()` for details;
|
|
354
|
+
* will always be a `Promise` if `decodeData()` was used.
|
|
48
355
|
*/
|
|
49
|
-
|
|
356
|
+
function decode(base64, options={})
|
|
50
357
|
{
|
|
51
|
-
|
|
52
|
-
|
|
358
|
+
if (options.response || options.buffer || R_PRE.test(base64))
|
|
359
|
+
{
|
|
360
|
+
return decodeData(base64, options);
|
|
361
|
+
}
|
|
362
|
+
else
|
|
363
|
+
{
|
|
364
|
+
return decodeText(base64, options);
|
|
365
|
+
}
|
|
53
366
|
}
|
|
54
367
|
|
|
55
|
-
exports
|
|
368
|
+
module.exports =
|
|
369
|
+
{
|
|
370
|
+
urlize, deurlize,
|
|
371
|
+
toBytes, fromBytes,
|
|
372
|
+
encodeText, decodeText,
|
|
373
|
+
toDataUrl, fromDataUrl,
|
|
374
|
+
encodeData, decodeData,
|
|
375
|
+
encode, decode,
|
|
376
|
+
}
|
package/lib/base91.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const {S,
|
|
1
|
+
const {S,B} = require('@lumjs/core/types');
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* A pure-Javascript base91 library.
|
|
@@ -169,17 +169,17 @@ exports.decode = function(data, opts={})
|
|
|
169
169
|
opts = {string: opts};
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
-
if (opts.string
|
|
172
|
+
if (opts.string)
|
|
173
173
|
{
|
|
174
174
|
const uint = Uint8Array.from(output);
|
|
175
175
|
const td = new TextDecoder();
|
|
176
176
|
return td.decode(uint);
|
|
177
177
|
}
|
|
178
|
-
if (opts.uint
|
|
178
|
+
if (opts.uint)
|
|
179
179
|
{
|
|
180
180
|
return Uint8Array.from(output);
|
|
181
181
|
}
|
|
182
|
-
else if (opts.buffer
|
|
182
|
+
else if (opts.buffer)
|
|
183
183
|
{
|
|
184
184
|
return new Buffer.from(output);
|
|
185
185
|
}
|