@lumjs/encode 1.2.0 → 2.1.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.
@@ -1,466 +0,0 @@
1
- const {S,B,isObj} = require('@lumjs/core/types');
2
- const Base64 = require('../base64');
3
- const Utf8 = Base64.Utf8;
4
- const {FORMAT,TYPE,VERSION} = require('./common');
5
- const Header = require('./header');
6
- const Settings = require('./settings');
7
-
8
- const PLUGINS =
9
- {
10
- [FORMAT.JSON]: 'json',
11
- [FORMAT.PHP]: 'php',
12
- [FORMAT.UBJSON]: 'ubjson',
13
- }
14
-
15
- // Internal function. Really simplistic at the moment.
16
- // When we have more than one version, it'll need updating.
17
- function detectHeader(str)
18
- {
19
- return str.startsWith('SV03');
20
- }
21
-
22
- /**
23
- * URL-safe variant of the Base64 algorithm, with extras.
24
- *
25
- * Version 3 header format is: `SVvvFfTt`
26
- *
27
- * - Uppercase letters are *literal* characters.
28
- * - Lowercase letters are hexidecimal integers:
29
- * - `vv` = *version* (mandatory)
30
- * - `f` = *format* (optional if `FORMAT.NONE`)
31
- * - `t` = *type* (optional if `TYPE.RAW` or `FORMAT.PHP`)
32
- *
33
- * Examples:
34
- *
35
- * - `SV03F1T1` (ver = 3, format = JSON, type = ARR_OBJ)
36
- * - `SV03F2` (ver = 3, format = PHP, type = *)
37
- * - `SV03` (ver = 3, format = NONE, type = RAW)
38
- *
39
- * @exports module:@lumjs/encode/safe64
40
- */
41
- module.exports = class
42
- {
43
- /**
44
- * Encode data to Safe64 format.
45
- *
46
- * @param {(string|WordArray)} data - The data to encode
47
- *
48
- * This **does not** do any serialization of data.
49
- * If you need to serialize data, see the
50
- * [encode()]{@link module:@lumjs/encode/safe64#encode}
51
- * instance method or the
52
- * [encodeData()]{@link module:@lumjs/encode/safe64.encodeData}
53
- * static method.
54
- *
55
- * @param {(object|boolean)} [opts] Encoding options
56
- *
57
- * In addition to the options specific to this method, any option
58
- * for [urlize()]{@link module:@lumjs/encode/safe64.urlize} may be passed
59
- * here as well.
60
- *
61
- * @param {object} [opts.stringFormat] Format for string parsing
62
- *
63
- * Can be any *encoding plugin* from the `crypto-js` library.
64
- * The *default* is `CryptoJS.enc.Utf8`.
65
- *
66
- * See [base64.encode()]{@link module:@lumjs/encode/base64.encode}
67
- * for details.
68
- *
69
- * @return {string} The encoded string.
70
- */
71
- static encode(rawdata, opts={})
72
- {
73
- let b64 = Base64.encode(rawdata, opts.stringFormat);
74
- return this.urlize(b64, opts);
75
- }
76
-
77
- /**
78
- * Convert a Base64 string into a Safe64 string.
79
- *
80
- * @param {string} string - The Base64 string to convert.
81
- * @param {object} [opts] Options
82
- * @param {boolean} [opts.addHeader=false] Add a `v3` header?
83
- * @param {number} [opts.format=NONE] The `format` field for the header.
84
- *
85
- * See [FORMAT]{@link module:@lumjs/encode/safe64.FORMAT} for a list.
86
- *
87
- * @param {number} [opts.type=RAW] The `type` field for the header.
88
- *
89
- * See [TYPE]{@link module:@lumjs/encode/safe64.TYPE} for a list.
90
- *
91
- * @param {number} [opts.version=VERSION] The Safe64 version number.
92
- * @param {boolean} [opts.fullHeader=false] Always include full header?
93
- *
94
- * Include all header fields, even if optional ones aren't required.
95
- *
96
- * @return {string} A Safe64 string.
97
- */
98
- static urlize(string, opts={})
99
- {
100
- if (typeof opts === B)
101
- {
102
- opts = {useTildes: opts};
103
- }
104
- else if (!isObj(opts))
105
- {
106
- throw new TypeError("invalid opts parameter");
107
- }
108
-
109
- string = string.replaceAll('+', '-');
110
- string = string.replaceAll('/', '_');
111
- string = string.replaceAll('=', opts.useTildes ? '~' : '');
112
-
113
- if (opts.addHeader)
114
- { // Build a header.
115
- const header
116
- = Header.build(
117
- opts.format ?? FORMAT.NONE,
118
- opts.type ?? TYPE.RAW,
119
- opts.version ?? VERSION,
120
- opts.fullHeader ?? false
121
- );
122
- return header + string;
123
- }
124
- return string;
125
- }
126
-
127
- /**
128
- * Convert a Safe64 string back into a Base64 string.
129
- *
130
- * @param {string} string - The Safe64 string to convert
131
- * @param {object} [opts] Options
132
- * @param {boolean} [opts.stripHeader=false] Strip `v3` headers?
133
- * @return {string} A Base64 string.
134
- */
135
- static deurlize(string, opts={})
136
- {
137
- if (!isObj(opts))
138
- {
139
- throw new TypeError("invalid opts parameter");
140
- }
141
-
142
- string = string.replaceAll('-', '+');
143
- string = string.replaceAll('_', '/');
144
- string = string.replaceAll('~', '=');
145
- string += "===".substring((string.length+3)%4);
146
-
147
- const stripHeader = opts.stripHeader ?? detectHeader(string);
148
-
149
- return stripHeader ? this.stripHeader(string) : string;
150
- }
151
-
152
- /**
153
- * Decode a Safe64 string into raw data.
154
- *
155
- * @param {string} string The Base64 string to decode.
156
- * @param {object} [opts] Decoding options
157
- *
158
- * In addition to the options specific to this method, any
159
- * options supported by {@link module:@lumjs/encode/safe64.deurlize}
160
- * may be passed as well.
161
- *
162
- * @param {(object|false)} [opts.stringFormat] Output string format
163
- *
164
- * Can be any *encoding plugin* from the `crypto-js` library.
165
- * The *default* is `CryptoJS.enc.Utf8`.
166
- *
167
- * See [base64.decode()]{@link module:@lumjs/encode/base64.decode}
168
- * for details.
169
- *
170
- * @return {(string|object)} The decoded output.
171
- *
172
- * The output of this is the value returned from the
173
- * [Base64.decode()]{@link module:@lumjs/encode/base64.decode}
174
- * method.
175
- *
176
- * This **does not** do anything with data that was
177
- * serialized using the Data extension.
178
- * If you are working with serialized data, see the
179
- * [decode()]{@link module:@lumjs/encode/safe64#decode}
180
- * instance method or the
181
- * [decodeData()]{@link module:@lumjs/encode/safe64.decodeData}
182
- * static method.
183
- *
184
- */
185
- static decode(string, opts={})
186
- {
187
- const b64 = this.deurlize(string, opts);
188
- return Base64.decode(b64, opts.stringFormat);
189
- }
190
-
191
- /**
192
- * Strip off a `v3` header from a string.
193
- *
194
- * @param {string} string
195
- * @returns {string}
196
- */
197
- static stripHeader(string)
198
- {
199
- return Header.parse(string).string;
200
- }
201
-
202
- // Now for the instance methods.
203
-
204
- /**
205
- * Build a Safe64 instance.
206
- *
207
- * Building a `Safe64` instance allows for a more flexible API,
208
- * and enables the `v3` data extensions.
209
- *
210
- * @param {object} [opts] Options
211
- *
212
- * @param {number} [opts.format=JSON] Default data format.
213
- *
214
- * See {@link module:@lumjs/encode/safe64.FORMAT} for a list.
215
- *
216
- * @param {number} [opts.type=ARR_OBJ] Default return type.
217
- *
218
- * See {@link module:@lumjs/encode/safe64.TYPE} for a list.
219
- *
220
- * @param {boolean} [opts.addHeader=true] Add a `v3` header to output?
221
- *
222
- * The headers are generally only needed for the Data extension,
223
- * but they're safe to use in any encoded string.
224
- *
225
- * @param {boolean} [opts.fullHeader=false] Always include full header?
226
- *
227
- * If this option is `true`, all optional header fields will always
228
- * be included, even if they aren't necessary.
229
- *
230
- * @param {object} [opts.stringFormat] String format.
231
- *
232
- * Can be any *encoding plugin* from the `crypto-js` library.
233
- *
234
- * @param {function} [opts.jsonReplacer] Replacer function for JSON
235
- *
236
- * When using `FORMAT.JSON` this will be used by `encode()` when it
237
- * passes the data to `JSON.stringify()`.
238
- *
239
- * @param {function} [opts.jsonReviver] Reviver function for JSON
240
- *
241
- * When using `FORMAT.JSON` this will be used by `decode()` when it
242
- * passes the string to `JSON.parse()`.
243
- *
244
- * @param {object} [opts.phpEncodeScope] Scope for `serialize()`
245
- *
246
- * When using `FORMAT.PHP`, a map of custom `class` definitions
247
- * to use when `encode()` calls `serialize()`.
248
- *
249
- * @param {object} [opts.phpDecodeScope] Scope for `unserialize()`
250
- *
251
- * When using `FORMAT.PHP`, a map of custom `class` definitions
252
- * to use when `decode()` calls `unserialize()`.
253
- *
254
- * @param {object} [opts.phpScope] Default PHP scope
255
- *
256
- * If this is set, it will be used as the default for both the
257
- * `opts.phpEncodeScope` and `opts.phpDecodeScope`. It's basically
258
- * a quick way to set both at the same time.
259
- *
260
- * @param {object} [opts.phpEncodeOpts] Options for `serialize()`
261
- *
262
- * Passed by `encode()` when using `FORMAT.PHP`.
263
- *
264
- * @param {object} [opts.phpDecodeOpts] Options for `unserialize()`
265
- *
266
- * Passed by `decode()` when using `FORMAT.PHP`.
267
- *
268
- * @param {object} [opts.phpOpts] Default PHP options
269
- *
270
- * If this is set, it will be used as the default for both the
271
- * `opts.phpEncodeOpts` and `opts.phpDecodeOpts`. It's basically
272
- * a quick way to set both at the same time.
273
- *
274
- * @param {object} [opts.ubEncoderOpts] Options for `UBJSON.encode()`
275
- *
276
- * @param {object} [opts.ubDecoderOpts] Options for `UBJSON.decode()`
277
- *
278
- * @param {boolean} [opts.encodeStrings=false] Encode `string` values?
279
- *
280
- * Normally we assume strings are already serialized, and we simply
281
- * encode them with the url-safe Base64 variant.
282
- *
283
- * If this is `true` we'll serialize `string` values with whatever
284
- * serialization format is selected. This is probably not useful.
285
- *
286
- * @param {boolean} [opts.useTildes=false] Enable legacy `v1` output?
287
- *
288
- * You probably don't want or need this.
289
- * The original Safe64 replaced `=` symbols with `~` symbols, while the
290
- * `v2` and higher simply strip them from the output entirely.
291
- * Unless you *really* have a reason for needing this, don't use it!
292
- *
293
- */
294
- constructor(opts={})
295
- {
296
- this.encFormat = opts.format ?? FORMAT.JSON;
297
- this.encType = opts.type ?? TYPE.ARR_OBJ;
298
- this.addHeader = opts.addHeader ?? true;
299
- this.fullHeader = opts.fullHeader ?? false;
300
- this.stringFormat = opts.stringFormat ?? Utf8;
301
- this.encodeStrings = opts.encodeStrings ?? false;
302
- this.useTildes = opts.useTildes ?? false;
303
- this.version = opts.version ?? VERSION;
304
-
305
- this.phpEncOpts = opts.phpEncodeOpts ?? opts.phpOpts;
306
- this.phpDecOpts = opts.phpDecodeOpts ?? opts.phpOpts;
307
- this.phpEncScope = opts.phpEncodeScope ?? opts.phpScope;
308
- this.phpDecScope = opts.phpDecodeScope ?? opts.phpScope;
309
-
310
- this.jsonReviver = opts.jsonReviver;
311
- this.jsonReplacer = opts.jsonReplacer;
312
-
313
- this.ubEncOpts = opts.ubEncoderOpts;
314
- this.ubDecOpts = opts.ubDecoderOpts;
315
- }
316
-
317
- getPlugin(fmt=this.encFormat)
318
- {
319
- const name = PLUGINS[fmt];
320
-
321
- if (typeof name !== S)
322
- {
323
- throw new TypeError("invalid format value");
324
- }
325
-
326
- const plugin = require('./'+name);
327
-
328
- if (!isObj(plugin))
329
- {
330
- throw new TypeError("invalid format plugin");
331
- }
332
-
333
- return plugin;
334
- }
335
-
336
- $parseHeader(string)
337
- {
338
- const settings = new Settings(this.encFormat, this.encType);
339
- return Header.parse(string, settings);
340
- }
341
-
342
- $encodeValue(data)
343
- {
344
- const opts =
345
- { // Options built from our instance properties.
346
- stringFormat: this.stringFormat,
347
- useTildes: this.useTildes,
348
- addHeader: this.addHeader,
349
- fullHeader: this.fullHeader,
350
- format: this.encFormat,
351
- type: this.encType,
352
- version: this.version,
353
- }
354
- return exports.encode(data, opts);
355
- }
356
-
357
- $decodeValue(input, stringFormat=this.stringFormat)
358
- {
359
- if (typeof input === S)
360
- {
361
- input = this.$parseHeader(input);
362
- }
363
- else if (!(input instanceof Settings))
364
- {
365
- throw new TypeError("input must be a string or Safe64 Settings instance");
366
- }
367
- return exports.decode(input.string, {stringFormat});
368
- }
369
-
370
- /**
371
- * Transform data into a Safe64 string.
372
- *
373
- * @param {*} data - The data to serialize and encode
374
- *
375
- * Generally this should only be either:
376
- *
377
- * - An `object` in which case it'll be serialized using the current
378
- * *format*, then encoded in Safe64.
379
- * - A string, which we generally assume is already serialized and simply
380
- * encode it as a Safe64 directly.
381
- *
382
- * If the `addHeader` property is `true` (the default setting), then
383
- * a header will always be added to every Safe64 string returned by
384
- * this method.
385
- *
386
- * @returns {string}
387
- */
388
- encode(data)
389
- {
390
- if (typeof data === S && !this.encodeStrings)
391
- { // It's a string already, forward it onwards.
392
- return this.$encodeValue(data);
393
- }
394
- else if (this.format === FORMAT.NONE)
395
- { // We don't want to format it.
396
- return this.$encodeValue(data.toString());
397
- }
398
-
399
- const encoded = this.getPlugin().encode.call(this, data);
400
-
401
- if (typeof encoded !== S && !isObj(encoded))
402
- {
403
- throw new Error("serialization did not return a string or object");
404
- }
405
-
406
- return this.$encodeValue(encoded);
407
- } // encode()
408
-
409
- /**
410
- * Decode a Safe64-encoded object.
411
- *
412
- * @param {string} string - The Safe64 string to decode and unserialize
413
- *
414
- * If there is no header, we will attempt to decode the string with
415
- * our current `format` and `type`, but that is not guaranteed to work.
416
- *
417
- * You should always send a Safe64 string *with a header* to this method.
418
- *
419
- * @returns {mixed} The original data value.
420
- */
421
- decode(string)
422
- {
423
- const opts = this.$parseHeader(string);
424
-
425
- if (opts.format === FORMAT.NONE || opts.type === TYPE.RAW)
426
- { // Nothing further to do.
427
- return this.$decodeValue(opts);
428
- }
429
-
430
- return this.getPlugin(opts.format).decode.call(this, opts);
431
- } // decode()
432
-
433
- /**
434
- * Create a new `Safe64` instance, then call its `encode()` method.
435
- *
436
- * @param {*} data - Data to pass to `instance.encode()`
437
- * @param {object} [opts] - Options for constructor.
438
- * @returns {string} The Safe64 string.
439
- */
440
- static encodeData(data, opts={})
441
- {
442
- const s64 = new exports(opts);
443
- return s64.encode(data);
444
- }
445
-
446
- /**
447
- * Create a new `Safe64` instance, then call its `decode()` method.
448
- *
449
- * @param {string} string - String to pass to `instance.decode()`
450
- * @param {object} [opts] - Options for constructor.
451
- * @returns {mixed} The decoded data.
452
- */
453
- static decodeData(string, opts={})
454
- {
455
- const s64 = new exports(opts);
456
- return s64.decode(string);
457
- }
458
-
459
- } // Safe64 class
460
-
461
- // Now let's add some static references.
462
- exports = module.exports;
463
-
464
- exports.VERSION = VERSION;
465
- exports.FORMAT = FORMAT;
466
- exports.TYPE = TYPE;
@@ -1,12 +0,0 @@
1
- // JSON plugin
2
- module.exports =
3
- {
4
- encode(data)
5
- {
6
- return JSON.stringify(data, this.jsonReplacer);
7
- },
8
- decode(opts)
9
- {
10
- return JSON.parse(this.$decodeValue(opts), this.jsonReviver);
11
- }
12
- }
package/lib/safe64/php.js DELETED
@@ -1,15 +0,0 @@
1
- // PHP Serialize plugin
2
- const PHP = require('php-serialize');
3
-
4
- module.exports =
5
- {
6
- encode(data)
7
- {
8
- return PHP.serialize(data, this.phpEncScope, this.phpEncOpts);
9
- },
10
- decode(opts)
11
- {
12
- const string = this.$decodeValue(opts);
13
- return PHP.unserialize(string, this.phpDecScope, this.phpDecOpts);
14
- }
15
- }
@@ -1,85 +0,0 @@
1
- const {S,N,needType} = require('@lumjs/core/types');
2
-
3
- /**
4
- * Safe64 Encoding Settings object
5
- *
6
- * Not meant for use outside of the package itself.
7
- * @alias module:@lumjs/encode/safe64~Settings
8
- */
9
- class Settings
10
- {
11
- constructor(format, type)
12
- {
13
- this.format = format;
14
- this.type = type;
15
-
16
- this.$version = 0;
17
- this.$offset = 0;
18
- this.$string = '';
19
- }
20
-
21
- get string()
22
- {
23
- if (this.$offset === 0)
24
- {
25
- return this.$string;
26
- }
27
- else
28
- {
29
- return this.$string.substring(this.$offset);
30
- }
31
- }
32
-
33
- setValue(string, offset)
34
- {
35
- needType(S, string);
36
- needType(N, offset);
37
- this.$string = string;
38
- this.$offset = offset;
39
- }
40
-
41
- set version(ver)
42
- {
43
- if (typeof ver === S)
44
- {
45
- ver = parseInt(ver, 16);
46
- }
47
- else if (typeof ver !== N)
48
- {
49
- throw new TypeError("version must be a hex string or a decimal number");
50
- }
51
-
52
- if (ver < 0) throw new RangeError("version cannot be lower than 0");
53
- if (ver > 255) throw new RangeError("version cannot be higher than 255");
54
-
55
- this.$version = ver;
56
- }
57
-
58
- get version()
59
- {
60
- return Header.hex(this.$version, Header.VL);
61
- }
62
-
63
- makeHeader(full=false)
64
- {
65
- return Header.build(this.format, this.type, this.$version, full);
66
- }
67
-
68
- get header()
69
- {
70
- if (this.$string == '' || this.$offset == 0)
71
- {
72
- return this.makeHeader();
73
- }
74
- else
75
- {
76
- return this.$string.substring(0, this.$offset);
77
- }
78
- }
79
-
80
- }
81
-
82
- module.exports = Settings;
83
-
84
- // Require Header after exporting Settings.
85
- const Header = require('./header');
@@ -1,23 +0,0 @@
1
- // UBJSON plugin
2
- const UB = require('@shelacek/ubjson');
3
- const WordArray = require('../crypto').WordArray;
4
- const w2b = require('../util').wordArrayToUint8Array;
5
-
6
- module.exports =
7
- {
8
- encode(data)
9
- {
10
- const buffer = UB.encode(data, this.ubEncOpts);
11
- return WordArray.create(buffer);
12
- },
13
- decode(opts)
14
- {
15
- const wordArray = this.$decodeValue(opts, false);
16
- const byteArray = w2b(wordArray);
17
- //console.debug({wordArray,byteArray});
18
- const arrayBuffer = byteArray.buffer;
19
- const decoded = UB.decode(arrayBuffer, this.ubDecOpts);
20
- return decoded;
21
- }
22
- }
23
-