d58f53525812e9ff5e4790972e4936ceb7dd743c
3 const { common
} = require('@squeep/api-dingus');
5 const { randomBytes
} = require('crypto');
6 const { promisify
} = require('util');
7 const randomBytesAsync
= promisify(randomBytes
);
10 * Pick out useful axios response fields.
14 const axiosResponseLogData
= (res
) => {
15 const data
= common
.pick(res
, [
23 data
.data
= logTruncate(data
.data
, 100);
29 * Limit length of string to keep logs sane
34 const logTruncate
= (str
, len
) => {
35 if (typeof str
!== 'string' || str
.toString().length
<= len
) {
38 return str
.toString().slice(0, len
) + `... (${str.toString().length} bytes)`;
42 * Turn a snake into a camel.
43 * @param {String} snakeCase
44 * @param {String|RegExp} delimiter
47 const camelfy
= (snakeCase
, delimiter
= '_') => {
48 if (!snakeCase
|| typeof snakeCase
.split
!== 'function') {
51 const words
= snakeCase
.split(delimiter
);
54 ...words
.map((word
) => word
.charAt(0).toUpperCase() + word
.slice(1)),
59 * Return an array containing x if x is not an array.
62 const ensureArray
= (x
) => {
63 if (x
=== undefined) {
66 if (!Array
.isArray(x
)) {
73 * Recursively freeze an object.
77 const freezeDeep
= (o
) => {
79 Object
.getOwnPropertyNames(o
).forEach((prop
) => {
80 if (Object
.hasOwnProperty
.call(o
, prop
)
81 && ['object', 'function'].includes(typeof o
[prop
]) // eslint-disable-line security/detect-object-injection
82 && !Object
.isFrozen(o
[prop
])) { // eslint-disable-line security/detect-object-injection
83 return freezeDeep(o
[prop
]); // eslint-disable-line security/detect-object-injection
91 * %x20-21 / %x23-5B / %x5D-7E
92 * @param {String} char
94 const validErrorChar
= (char) => {
95 const value
= char.charCodeAt(0);
96 return value
=== 0x20 || value
=== 0x21
97 || (value
>= 0x23 && value
<= 0x5b)
98 || (value
>= 0x5d && value
<= 0x7e);
103 * Determine if an OAuth error message is valid.
104 * @param {String} error
107 const validError
= (error
) => {
108 return error
&& error
.split('').filter((c
) => !validErrorChar(c
)).length
=== 0 || false;
114 * scope-token = 1*( %x21 / %x23-5B / %x5D-7E )
115 * @param {String} char
117 const validScopeChar
= (char) => {
118 const value
= char.charCodeAt(0);
119 return value
=== 0x21
120 || (value
>= 0x23 && value
<= 0x5b)
121 || (value
>= 0x5d && value
<= 0x7e);
126 * Determine if a scope has a valid name.
127 * @param {String} scope
130 const validScope
= (scope
) => {
131 return scope
&& scope
.split('').filter((c
) => !validScopeChar(c
)).length
=== 0 || false;
137 * @param {Number} bytes
139 const newSecret
= async (bytes
= 64) => {
140 return (await
randomBytesAsync(bytes
* 3 / 4)).toString('base64');
145 * Convert a Date object to epoch seconds.
146 * @param {Date=} date
149 const dateToEpoch
= (date
) => {
150 const dateMs
= date
? date
.getTime() : Date
.now();
151 return Math
.ceil(dateMs
/ 1000);
156 axiosResponseLogData
,