@agnostack/verifyd 2.4.1-alpha.1 → 2.5.0-alpha.2
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 +75 -64
- package/dist/esm/lib/index.js +3 -0
- package/dist/esm/lib/types.js +1 -0
- package/dist/esm/lib/utils/index.js +1 -0
- package/dist/esm/lib/utils/rawbody.js +35 -0
- package/dist/esm/lib/verification.js +94 -0
- package/dist/esm/react/hooks/index.js +1 -0
- package/dist/esm/react/hooks/useVerification.js +47 -0
- package/dist/esm/react/index.js +2 -0
- package/dist/esm/react/types.js +0 -0
- package/dist/esm/shared/WebCrypto.js +350 -0
- package/dist/esm/shared/authorization.js +26 -0
- package/dist/esm/shared/display.js +429 -0
- package/dist/esm/shared/errors.js +37 -0
- package/dist/esm/shared/index.js +6 -0
- package/dist/esm/shared/request.js +60 -0
- package/dist/esm/shared/types.js +0 -0
- package/dist/esm/shared/verification.js +94 -0
- package/package.json +21 -7
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
/* eslint-disable no-use-before-define */
|
|
2
|
+
// #region lib-core
|
|
3
|
+
// TODO!!!: keep in sync between next-shopify and lib-core (AND lib-utils-js at bottom)
|
|
4
|
+
const REACT_SYMBOL = Symbol.for('react.element');
|
|
5
|
+
export const random = (max = 100, min = 1) => {
|
|
6
|
+
const floor = Math.min(max, min);
|
|
7
|
+
return Math.floor(Math.random() * (max - floor + 1)) + floor;
|
|
8
|
+
};
|
|
9
|
+
export const nextRandom = (max = 100, min = 1) => {
|
|
10
|
+
const maximum = Math.max(max, 0);
|
|
11
|
+
const minimum = Math.max(min, 0);
|
|
12
|
+
let randomNumber = maximum;
|
|
13
|
+
if (maximum > minimum) {
|
|
14
|
+
do {
|
|
15
|
+
randomNumber = random(maximum, minimum);
|
|
16
|
+
} while (randomNumber === nextRandom.last);
|
|
17
|
+
nextRandom.last = randomNumber;
|
|
18
|
+
}
|
|
19
|
+
return randomNumber;
|
|
20
|
+
};
|
|
21
|
+
export const arrayRandom = (_values, _max = 1) => {
|
|
22
|
+
const values = ensureArray(_values);
|
|
23
|
+
const valuesLength = values.length;
|
|
24
|
+
const maxLength = Math.min(_max, valuesLength);
|
|
25
|
+
if (valuesLength <= maxLength) {
|
|
26
|
+
return values;
|
|
27
|
+
}
|
|
28
|
+
const arrayLength = valuesLength - 1;
|
|
29
|
+
const randomValues = [];
|
|
30
|
+
do {
|
|
31
|
+
const newVal = values[nextRandom(arrayLength, 0)];
|
|
32
|
+
if (!randomValues.includes(newVal)) {
|
|
33
|
+
randomValues.push(newVal);
|
|
34
|
+
}
|
|
35
|
+
} while (randomValues.length < maxLength);
|
|
36
|
+
return randomValues;
|
|
37
|
+
};
|
|
38
|
+
export const arrayRandomItem = (_values) => (arrayRandom(_values)[0]);
|
|
39
|
+
export const isArray = (value) => (
|
|
40
|
+
// eslint-disable-next-line eqeqeq
|
|
41
|
+
(value != undefined) && Array.isArray(value));
|
|
42
|
+
export const isSet = (value) => (
|
|
43
|
+
// eslint-disable-next-line eqeqeq
|
|
44
|
+
(value != undefined) && (value instanceof Set));
|
|
45
|
+
export const isType = (value, type) => (
|
|
46
|
+
// eslint-disable-next-line eqeqeq, valid-typeof
|
|
47
|
+
(value != undefined) && (typeof value === type));
|
|
48
|
+
export const isString = (value) => (isType(value, 'string') ||
|
|
49
|
+
(value instanceof String));
|
|
50
|
+
const isReact = (value) => (isType(value, 'object') &&
|
|
51
|
+
((value === null || value === void 0 ? void 0 : value.$$typeof) === REACT_SYMBOL));
|
|
52
|
+
const isClass = (value) => (isType(value, 'object') &&
|
|
53
|
+
(Object.getPrototypeOf(value) !== Object.prototype) &&
|
|
54
|
+
!isReact(value));
|
|
55
|
+
export const isTypeEnhanced = (value, type) => {
|
|
56
|
+
switch (true) {
|
|
57
|
+
case (type === 'boolean'): {
|
|
58
|
+
return isType(value, type) || ['true', 'false'].includes(value);
|
|
59
|
+
}
|
|
60
|
+
case (type === 'string'): {
|
|
61
|
+
return isString(value);
|
|
62
|
+
}
|
|
63
|
+
case (type === 'set'): {
|
|
64
|
+
return isSet(value);
|
|
65
|
+
}
|
|
66
|
+
case (type === 'react'): {
|
|
67
|
+
return isReact(value);
|
|
68
|
+
}
|
|
69
|
+
case (type === 'class'): {
|
|
70
|
+
return isClass(value);
|
|
71
|
+
}
|
|
72
|
+
case (type === 'array'): {
|
|
73
|
+
return (isArray(value) &&
|
|
74
|
+
!isSet(value));
|
|
75
|
+
}
|
|
76
|
+
case (type === 'object'): {
|
|
77
|
+
return (isType(value, type) &&
|
|
78
|
+
!isArray(value) &&
|
|
79
|
+
!isClass(value) &&
|
|
80
|
+
!isString(value) &&
|
|
81
|
+
!isReact(value));
|
|
82
|
+
}
|
|
83
|
+
default: {
|
|
84
|
+
return isType(value, type);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
export const safeTrim = (value) => {
|
|
89
|
+
if (isTypeEnhanced(value, 'string')) {
|
|
90
|
+
// eslint-disable-next-line no-param-reassign
|
|
91
|
+
value = value.trim();
|
|
92
|
+
}
|
|
93
|
+
return value;
|
|
94
|
+
};
|
|
95
|
+
export const isParseable = (value, trim, matchQuoted) => {
|
|
96
|
+
if (!isTypeEnhanced(value, 'string')) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
if (trim) {
|
|
100
|
+
// eslint-disable-next-line no-param-reassign
|
|
101
|
+
value = safeTrim(value);
|
|
102
|
+
}
|
|
103
|
+
return isTrue(value.startsWith('{') || value.startsWith('[') || (matchQuoted && value.startsWith('"')));
|
|
104
|
+
};
|
|
105
|
+
export const safeParse = (value, trim) => {
|
|
106
|
+
switch (true) {
|
|
107
|
+
case isTypeEnhanced(value, 'object'):
|
|
108
|
+
case isTypeEnhanced(value, 'array'): {
|
|
109
|
+
return value;
|
|
110
|
+
}
|
|
111
|
+
case isParseable(value, trim, true): {
|
|
112
|
+
if (trim) {
|
|
113
|
+
// eslint-disable-next-line no-param-reassign
|
|
114
|
+
value = safeTrim(value);
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
return JSON.parse(value);
|
|
118
|
+
}
|
|
119
|
+
catch (_ignore) {
|
|
120
|
+
console.info('Ignoring error parsing', _ignore);
|
|
121
|
+
// TODO: should this be value ?? {}
|
|
122
|
+
return value;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
default: {
|
|
126
|
+
// TODO: should this be value ?? {}
|
|
127
|
+
return value;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
export const ensureString = (string) => (string ? `${string}` : '');
|
|
132
|
+
// HMMM: what if 'string' is an object?
|
|
133
|
+
export const ensureStringOnly = (string) => (
|
|
134
|
+
// eslint-disable-next-line eqeqeq
|
|
135
|
+
(string != undefined) ? `${string}` : '');
|
|
136
|
+
export const ensureStringAscii = (string) => (
|
|
137
|
+
// eslint-disable-next-line no-control-regex
|
|
138
|
+
ensureStringOnly(string).replace(/[^\x00-\x7F]/g, ''));
|
|
139
|
+
export const ensureStringClean = (string) => (
|
|
140
|
+
// eslint-disable-next-line no-control-regex
|
|
141
|
+
ensureStringOnly(string).replace(/[^a-z0-9_-]/gi, ''));
|
|
142
|
+
export const ensureAlphaNumeric = (string) => (
|
|
143
|
+
// eslint-disable-next-line no-control-regex
|
|
144
|
+
ensureStringOnly(string).replace(/[^a-z0-9]/gi, ''));
|
|
145
|
+
export const isNumericOnly = (value) => {
|
|
146
|
+
var _a;
|
|
147
|
+
const [matched] = (_a = `${value}`.match(/^([0-9]+)$/)) !== null && _a !== void 0 ? _a : [];
|
|
148
|
+
// eslint-disable-next-line eqeqeq
|
|
149
|
+
return (matched != undefined);
|
|
150
|
+
};
|
|
151
|
+
export const isNumericNegatable = (value) => {
|
|
152
|
+
var _a;
|
|
153
|
+
const [matched] = (_a = `${value}`.match(/^(-?[0-9]+(\.[0-9]+)?)?$/)) !== null && _a !== void 0 ? _a : [];
|
|
154
|
+
// eslint-disable-next-line eqeqeq
|
|
155
|
+
return (matched != undefined);
|
|
156
|
+
};
|
|
157
|
+
// TODO: explore places using ensureNumeric to move to isNumericNegatable
|
|
158
|
+
export const ensureNumeric = (string) => (Number(ensureString(string).replace(/[^0-9.]/gi, '')));
|
|
159
|
+
export const ensureNumericOnly = (string) => (Number(ensureString(string).replace(/[^0-9]/gi, '')));
|
|
160
|
+
// TODO: update regex to handle negative number returns negative. Something like (?!\d\.)(-?\d+(\.\d)?)
|
|
161
|
+
export const ensureNumericNegatable = (string) => (Number(ensureString(string).replace(/[^0-9.-]/gi, '')));
|
|
162
|
+
export const ensureNumericConstrained = (value, { min: _min = 0, max: _max = 100 } = {}) => {
|
|
163
|
+
const min = ensureNumericNegatable(_min);
|
|
164
|
+
const max = ensureNumericNegatable(_max);
|
|
165
|
+
return Math.max(min, Math.min(ensureNumeric(value), max));
|
|
166
|
+
};
|
|
167
|
+
export const ensureArray = (array = []) => (
|
|
168
|
+
// eslint-disable-next-line no-nested-ternary
|
|
169
|
+
!array ? [] : Array.isArray(array) ? array : [array]);
|
|
170
|
+
export const ensureArraySet = (arrayOrSet) => (ensureArray(isSet(arrayOrSet) ? [...arrayOrSet] : arrayOrSet));
|
|
171
|
+
export const arrayEmpty = (array, disableEmptyString = false) => (
|
|
172
|
+
// eslint-disable-next-line eqeqeq
|
|
173
|
+
!array || !array.length || (array.length === 1 && (array[0] == undefined || (disableEmptyString && stringEmpty(array[0])))));
|
|
174
|
+
export const arrayNotEmpty = (array, disableEmptyString = false) => (
|
|
175
|
+
// eslint-disable-next-line eqeqeq
|
|
176
|
+
!arrayEmpty(array) && array[0] != undefined && (!disableEmptyString || stringNotEmpty(array[0])));
|
|
177
|
+
export const findLastMatch = (array, filterCallback = (value) => (value)) => (ensureArray(array).filter(filterCallback).slice(-1)[0]);
|
|
178
|
+
export const ensureObject = (object) => (object !== null && object !== void 0 ? object : {});
|
|
179
|
+
// NOTE: this does not ensure !isType(string)
|
|
180
|
+
export const objectEmpty = (object) => (!object || !Object.keys(object).length);
|
|
181
|
+
export const objectNotEmpty = (object) => (!objectEmpty(object));
|
|
182
|
+
export const nullable = (object) => ((!object || (object === 'null') || (object === undefined) || (object === null))
|
|
183
|
+
? null // TODO: explore undefined here??
|
|
184
|
+
: object);
|
|
185
|
+
export const objectContainsAnyValue = (object) => (Object.values(ensureObject(object)).some((value) => nullable(value)));
|
|
186
|
+
const isUndefined = (value) => (
|
|
187
|
+
// eslint-disable-next-line eqeqeq
|
|
188
|
+
value == undefined);
|
|
189
|
+
export const cleanObjectKeys = (object, _removeKeyNames) => {
|
|
190
|
+
const removeKeyNames = ensureArray(_removeKeyNames);
|
|
191
|
+
return Object.fromEntries(Object.entries(ensureObject(object)).filter(([key]) => !removeKeyNames.includes(key)));
|
|
192
|
+
};
|
|
193
|
+
export const cleanObject = (object, allowEmptyLeafs, isEmptyCallback) => (Object.entries(ensureObject(object)).reduce((_cleanedObject, [key, _value]) => {
|
|
194
|
+
var _a, _b;
|
|
195
|
+
if (!allowEmptyLeafs && ((_a = isEmptyCallback === null || isEmptyCallback === void 0 ? void 0 : isEmptyCallback(_value)) !== null && _a !== void 0 ? _a : isUndefined(_value))) {
|
|
196
|
+
return _cleanedObject; // skip key if null or undefined
|
|
197
|
+
}
|
|
198
|
+
const value = !Array.isArray(_value)
|
|
199
|
+
? cleanObjectValue(_value, allowEmptyLeafs, isEmptyCallback)
|
|
200
|
+
: _value.reduce((_data, __value) => ([
|
|
201
|
+
..._data,
|
|
202
|
+
cleanObjectValue(__value, allowEmptyLeafs, isEmptyCallback)
|
|
203
|
+
]), []);
|
|
204
|
+
if (!allowEmptyLeafs && ((_b = isEmptyCallback === null || isEmptyCallback === void 0 ? void 0 : isEmptyCallback(value)) !== null && _b !== void 0 ? _b : isUndefined(value))) {
|
|
205
|
+
return _cleanedObject; // skip key if null or undefined
|
|
206
|
+
}
|
|
207
|
+
return Object.assign(Object.assign({}, _cleanedObject), { [key]: value });
|
|
208
|
+
}, {}));
|
|
209
|
+
const cleanObjectValue = (value, allowEmptyLeafs, isEmptyCallback) => {
|
|
210
|
+
switch (true) {
|
|
211
|
+
case isClass(value): {
|
|
212
|
+
return undefined;
|
|
213
|
+
}
|
|
214
|
+
case isTypeEnhanced(value, 'object'): {
|
|
215
|
+
return cleanObject(value, allowEmptyLeafs, isEmptyCallback);
|
|
216
|
+
}
|
|
217
|
+
default: {
|
|
218
|
+
return value;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
export const stringNotEmptyOnly = (stringable) => {
|
|
223
|
+
const string = ensureStringOnly(stringable);
|
|
224
|
+
return ((string.length > 0) && !['null', 'undefined'].includes(string));
|
|
225
|
+
};
|
|
226
|
+
export const stringEmptyOnly = (stringable) => (!stringNotEmptyOnly(stringable));
|
|
227
|
+
export const stringNotEmpty = (stringable) => {
|
|
228
|
+
const string = ensureString(stringable);
|
|
229
|
+
return ((string.length > 0) && !['null', 'undefined'].includes(string));
|
|
230
|
+
};
|
|
231
|
+
export const stringEmpty = (stringable) => (!stringNotEmpty(stringable));
|
|
232
|
+
const splitString = (splitting, index = splitting.length) => {
|
|
233
|
+
const string = ensureString(splitting);
|
|
234
|
+
return [string.slice(0, index), string.slice(index)];
|
|
235
|
+
};
|
|
236
|
+
export const compareNumber = (number1 = 0, number2 = 0) => (number1 - number2);
|
|
237
|
+
export const compareString = (string1, string2) => {
|
|
238
|
+
if (stringEmpty(string1)) {
|
|
239
|
+
return 1;
|
|
240
|
+
}
|
|
241
|
+
if (stringEmpty(string2)) {
|
|
242
|
+
return -1;
|
|
243
|
+
}
|
|
244
|
+
return ensureString(string1).localeCompare(string2);
|
|
245
|
+
};
|
|
246
|
+
export const compareEntryKeys = ([string1], [string2]) => (compareString(string1, string2));
|
|
247
|
+
export const objectToSortedString = (object, separator = '') => (Object.entries(ensureObject(object))
|
|
248
|
+
.sort(compareEntryKeys)
|
|
249
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
250
|
+
.join(separator));
|
|
251
|
+
export const isHTML = (string) => {
|
|
252
|
+
var _a, _b, _c;
|
|
253
|
+
return ((_c = (((_a = string === null || string === void 0 ? void 0 : string.startsWith) === null || _a === void 0 ? void 0 : _a.call(string, '<')) || ((_b = string === null || string === void 0 ? void 0 : string.startsWith) === null || _b === void 0 ? void 0 : _b.call(string, '\n<')))) !== null && _c !== void 0 ? _c : false);
|
|
254
|
+
};
|
|
255
|
+
export const freeze = (logMessage, object, type = 'log') => {
|
|
256
|
+
console[type](logMessage, !object ? object : JSON.parse(JSON.stringify(ensureObject(object))));
|
|
257
|
+
};
|
|
258
|
+
export const replaceSpaces = (string, replacement = '') => (!isType(string, 'string')
|
|
259
|
+
? ''
|
|
260
|
+
: string.replace(/\s/g, replacement));
|
|
261
|
+
const recase = (string, replacement = '') => (!isType(string, 'string')
|
|
262
|
+
? ''
|
|
263
|
+
: string
|
|
264
|
+
.replace(/[^a-zA-Z0-9]+/g, replacement)
|
|
265
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1-$2')
|
|
266
|
+
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
|
267
|
+
.replace(/([0-9])([^0-9])/g, '$1-$2')
|
|
268
|
+
.replace(/([^0-9])([0-9])/g, '$1-$2')
|
|
269
|
+
.replace(/[-_]+/g, replacement)
|
|
270
|
+
.replace(new RegExp(`${replacement}$`), '')
|
|
271
|
+
.toLowerCase());
|
|
272
|
+
export const zencase = (string, replacement = '-') => (!isType(string, 'string')
|
|
273
|
+
? ''
|
|
274
|
+
: replaceSpaces(string, replacement)
|
|
275
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1-$2')
|
|
276
|
+
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
|
277
|
+
.replace(new RegExp(`${replacement}$`), '')
|
|
278
|
+
.toLowerCase());
|
|
279
|
+
export const dashcase = (string) => (recase(string, '-'));
|
|
280
|
+
export const undashcase = (string, replacement = ' ') => (ensureString(string).replace(/-/g, replacement).trim());
|
|
281
|
+
export const snakecase = (string) => (recase(string, '_'));
|
|
282
|
+
export const unsnakecase = (string, replacement = ' ') => (ensureString(string).replace(/_/g, replacement).trim());
|
|
283
|
+
export const uppercase = (string) => (ensureString(string).toUpperCase());
|
|
284
|
+
export const lowercase = (string, defaultValue = '') => (!stringNotEmpty(string)
|
|
285
|
+
? defaultValue
|
|
286
|
+
: ensureString(string).toLowerCase());
|
|
287
|
+
export const isLowercase = (string) => (stringNotEmpty(string) && /^[^A-Z]*$/.test(string));
|
|
288
|
+
export const slugify = (string) => (lowercase(dashcase(string)));
|
|
289
|
+
export const capitalize = (string) => {
|
|
290
|
+
const parts = splitString(string, 1);
|
|
291
|
+
return `${uppercase(parts[0])}${parts[1]}`;
|
|
292
|
+
};
|
|
293
|
+
export const camelCase = (string) => (stringEmpty(string)
|
|
294
|
+
? ''
|
|
295
|
+
: unsnakecase(undashcase(string)).replace(/\w\S*/g, (word, charIndex) => {
|
|
296
|
+
if (charIndex === 0) {
|
|
297
|
+
return lowercase(word);
|
|
298
|
+
}
|
|
299
|
+
return `${uppercase(word.charAt(0))}${lowercase(word.substr(1))}`;
|
|
300
|
+
}).split(' ').join(''));
|
|
301
|
+
export const titleCase = (_string, _overrides) => {
|
|
302
|
+
if (stringEmpty(_string)) {
|
|
303
|
+
return '';
|
|
304
|
+
}
|
|
305
|
+
const overrides = Object.assign({ ach: 'ACH', 'add-ons': 'Add-Ons', agnostack: 'agnoStack', ai: 'AI', 'ai for commerce': 'AI for Commerce', "'ai for commerce'": "'AI For Commerce'", b2b: 'B2B', b2c: 'B2C', cartcollab: 'CartCollab', 'cartcollab(sm)': 'CartCollab(SM)', chatgpt: 'ChatGPT', covid: 'COVID', covid19: 'COVID-19', 'covid-19': 'COVID-19', crm: 'CRM', elasticpath: 'Elastic Path', ecommerce: 'eCommerce', 'e-commerce': 'eCommerce', faqs: 'FAQs', gpt: 'GPT', ipaas: 'iPaaS', 'ltv.ai': 'LTV.ai', 'smile.io': 'Smile.io', 'stamped.io': 'Stamped.io', 'judge.me': 'Judge.me', 'influence.io': 'Influence.io', keepsmallstrong: 'KeepSmallStrong', loyaltylion: 'LoyaltyLion', 'mach alliance': 'MACH Alliance', openai: 'OpenAI', paypal: 'PayPal', 'postscript.io': 'Postscript.io', recharge: 'Recharge', 'stay.ai': 'Stay Ai', 'stay ai': 'Stay Ai', shipengine: 'ShipEngine', shipperhq: 'ShipperHQ', shipstation: 'ShipStation', taxjar: 'TaxJar', vs: 'vs', 'vs.': 'vs.', yotpo: 'YotPo', "zendesk 'ai for commerce'": "Zendesk 'AI For Commerce'" }, _overrides);
|
|
306
|
+
const string = lowercase(_string);
|
|
307
|
+
if (overrides[string]) {
|
|
308
|
+
return overrides[string];
|
|
309
|
+
}
|
|
310
|
+
const stringParts = string
|
|
311
|
+
.split(' ')
|
|
312
|
+
.reduce((_stringParts, _stringPart) => {
|
|
313
|
+
var _a;
|
|
314
|
+
const stringPart = (_a = overrides[_stringPart]) !== null && _a !== void 0 ? _a : _stringPart
|
|
315
|
+
.replace(/([A-Z]+)/g, ' $1')
|
|
316
|
+
.replace(/\s\s+/g, ' ')
|
|
317
|
+
.replace(/(\b[a-z](?!\s)*)/g, (firstChar) => uppercase(firstChar));
|
|
318
|
+
return [
|
|
319
|
+
..._stringParts,
|
|
320
|
+
...stringNotEmpty(stringPart) ? [stringPart] : []
|
|
321
|
+
];
|
|
322
|
+
}, []);
|
|
323
|
+
return stringParts.join(' ');
|
|
324
|
+
};
|
|
325
|
+
export const removeLeadingSlash = (string) => (ensureString(string).replace(/^\//, ''));
|
|
326
|
+
export const removeLeadingTrailingQuotes = (string) => (ensureString(string).replace(/^"|"$/g, ''));
|
|
327
|
+
// TODO: not sure if this should remove multipel at end or just one (as it does now)?
|
|
328
|
+
export const removeTrailingSlash = (string) => (ensureString(string).replace(/\/$/, ''));
|
|
329
|
+
export const removeLeadingTrailingSlash = (string) => (removeTrailingSlash(removeLeadingSlash(string)));
|
|
330
|
+
export const ensureLeadingSlash = (string) => (`/${removeLeadingSlash(string)}`);
|
|
331
|
+
export const ensureTrailingSlash = (string) => (`${removeTrailingSlash(string)}/`);
|
|
332
|
+
export const ensureTrailingQuestion = (string) => {
|
|
333
|
+
if (!isString(string)) {
|
|
334
|
+
return string;
|
|
335
|
+
}
|
|
336
|
+
return string.endsWith('?') ? string : `${string}?`;
|
|
337
|
+
};
|
|
338
|
+
export const ensureExtension = (string, extension) => {
|
|
339
|
+
var _a, _b;
|
|
340
|
+
if (stringEmpty(extension)) {
|
|
341
|
+
return string;
|
|
342
|
+
}
|
|
343
|
+
const filePath = (_b = (_a = string.match(/(.*)\..+$/)) === null || _a === void 0 ? void 0 : _a[1]) !== null && _b !== void 0 ? _b : string;
|
|
344
|
+
return `${filePath}.${extension}`;
|
|
345
|
+
};
|
|
346
|
+
export const wrappedEncode = (basePath, _wrappingPath) => {
|
|
347
|
+
const wrappingPath = ensureString(_wrappingPath);
|
|
348
|
+
if (stringEmpty(basePath)) {
|
|
349
|
+
return wrappingPath;
|
|
350
|
+
}
|
|
351
|
+
return `${basePath}${encodeURIComponent(wrappingPath)}`;
|
|
352
|
+
};
|
|
353
|
+
export const splitCommas = (value) => (ensureString(value)
|
|
354
|
+
.replace(/, /g, ',')
|
|
355
|
+
.split(',')
|
|
356
|
+
.reduce((_values, _value) => {
|
|
357
|
+
const __value = safeTrim(_value);
|
|
358
|
+
return [
|
|
359
|
+
..._values,
|
|
360
|
+
...stringNotEmpty(__value) ? [__value] : [] // TODO: explore stringEmptyOnly?
|
|
361
|
+
];
|
|
362
|
+
}, []));
|
|
363
|
+
export const combineCommas = (values) => ([...new Set(ensureArray(values).reduce((_combined, value) => ([
|
|
364
|
+
..._combined,
|
|
365
|
+
...splitCommas(value)
|
|
366
|
+
]), []))]);
|
|
367
|
+
export const normalizeArray = (input, separator = ' ') => {
|
|
368
|
+
const inputArray = ensureArray(input);
|
|
369
|
+
return inputArray.reduce((normalized, _ignore, index) => ([
|
|
370
|
+
...normalized,
|
|
371
|
+
inputArray.slice(0, index + 1).join(separator)
|
|
372
|
+
]), []).reverse();
|
|
373
|
+
};
|
|
374
|
+
export const arrayToObject = (arrayable, key) => (ensureArray(arrayable).reduce((_object, item) => (Object.assign(Object.assign({}, _object), { [item === null || item === void 0 ? void 0 : item[key]]: item })), {}));
|
|
375
|
+
export const isTrue = (value, falsy) => {
|
|
376
|
+
if ((value === false) ||
|
|
377
|
+
isUndefined(value) ||
|
|
378
|
+
ensureArray(falsy).includes(value)) {
|
|
379
|
+
return false;
|
|
380
|
+
}
|
|
381
|
+
return ![...ensureArray(falsy), '', 'false'].includes(lowercase(value));
|
|
382
|
+
};
|
|
383
|
+
export const isUndefinedOrTrue = (value, falsy) => (isUndefined(value) || isTrue(value, falsy));
|
|
384
|
+
export const isBoolean = (value) => ([true, false].includes(value) ||
|
|
385
|
+
['true', 'false'].includes(lowercase(value)));
|
|
386
|
+
export const getBaseDomain = (baseUrl) => ((baseUrl === null || baseUrl === void 0 ? void 0 : baseUrl.match(/^(?:https?:\/\/)?([^/:]+)(?::(\d+))?/).slice(1, 3).filter(stringNotEmpty).join(':')) || undefined);
|
|
387
|
+
// TODO: move all uses of parseKeywords to parseKeywordGroups
|
|
388
|
+
export const parseKeywords = (keywordGroup, previous) => ([...new Set(ensureArray(keywordGroup).reduce((_parsedKeywords, keyword) => {
|
|
389
|
+
const keywords = splitCommas(keyword);
|
|
390
|
+
return [
|
|
391
|
+
..._parsedKeywords,
|
|
392
|
+
...keywords.filter((_keyword) => stringNotEmpty(_keyword))
|
|
393
|
+
];
|
|
394
|
+
}, ensureArray(previous)))].join(', '));
|
|
395
|
+
export const parseCommaGroups = (commaGroups) => {
|
|
396
|
+
const parsedGroups = ensureArray(commaGroups).reduce((_parsedGroups, commaGroup) => ([
|
|
397
|
+
..._parsedGroups,
|
|
398
|
+
...ensureArray(commaGroup).reduce((_parsedCommaKeywords, keyword) => {
|
|
399
|
+
const keywords = splitCommas(keyword);
|
|
400
|
+
return [
|
|
401
|
+
..._parsedCommaKeywords,
|
|
402
|
+
...keywords.filter((_keyword) => stringNotEmpty(_keyword))
|
|
403
|
+
];
|
|
404
|
+
}, [])
|
|
405
|
+
]), []);
|
|
406
|
+
return [...new Set(parsedGroups)];
|
|
407
|
+
};
|
|
408
|
+
export const parseKeywordGroups = (keywordGroups) => (parseCommaGroups(keywordGroups).join(', '));
|
|
409
|
+
// #endregion lib-core
|
|
410
|
+
// #region lib-utils-js
|
|
411
|
+
export const querystringToParams = (queryString) => {
|
|
412
|
+
const urlParams = new URLSearchParams(ensureString(queryString));
|
|
413
|
+
return [Object.fromEntries(urlParams), urlParams];
|
|
414
|
+
};
|
|
415
|
+
export const querystringToObject = (queryString) => (querystringToParams(queryString)[0]);
|
|
416
|
+
export const arrayIncludesAll = (_values, comparison) => {
|
|
417
|
+
const values = ensureArray(_values);
|
|
418
|
+
return ensureArray(comparison).every((value) => (stringNotEmpty(value) && values.includes(value)));
|
|
419
|
+
};
|
|
420
|
+
export const arraysMatch = (array1, array2) => (arrayIncludesAll(array1, array2) && arrayIncludesAll(array2, array1));
|
|
421
|
+
export const appendQuery = (_basePath, queryString) => {
|
|
422
|
+
const basePath = ensureString(_basePath);
|
|
423
|
+
if (stringEmpty(queryString)) {
|
|
424
|
+
return basePath;
|
|
425
|
+
}
|
|
426
|
+
return `${basePath}${basePath.includes('?') ? '&' : '?'}${queryString}`;
|
|
427
|
+
};
|
|
428
|
+
export const appendParams = (basePath, params) => (appendQuery(basePath, ensureArray(params).join('&')));
|
|
429
|
+
// #endregion lib-utils-js
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
export class PreconditionError extends Error {
|
|
13
|
+
constructor(message, _data) {
|
|
14
|
+
super(message);
|
|
15
|
+
const _a = _data !== null && _data !== void 0 ? _data : {}, { code = 412 } = _a, data = __rest(_a, ["code"]);
|
|
16
|
+
this.code = code;
|
|
17
|
+
this.data = data;
|
|
18
|
+
this.name = 'PreconditionError';
|
|
19
|
+
Object.setPrototypeOf(this, PreconditionError.prototype);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export class CryptoError extends PreconditionError {
|
|
23
|
+
constructor(message, _data) {
|
|
24
|
+
const _a = _data !== null && _data !== void 0 ? _data : {}, { code = 500 } = _a, data = __rest(_a, ["code"]);
|
|
25
|
+
super(message, Object.assign({ code }, data));
|
|
26
|
+
this.name = 'CryptoError';
|
|
27
|
+
Object.setPrototypeOf(this, CryptoError.prototype);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export class VerificationError extends PreconditionError {
|
|
31
|
+
constructor(message, _data) {
|
|
32
|
+
const _a = _data !== null && _data !== void 0 ? _data : {}, { code = 500 } = _a, data = __rest(_a, ["code"]);
|
|
33
|
+
super(message, Object.assign({ code }, data));
|
|
34
|
+
this.name = 'VerificationError';
|
|
35
|
+
Object.setPrototypeOf(this, VerificationError.prototype);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
import { ensureLeadingSlash, stringEmpty, uppercase, safeParse, } from './display';
|
|
13
|
+
const TEMP_HOSTNAME = 'xyz.com';
|
|
14
|
+
const REMOVABLE_KEYS = ['shop', 'host'];
|
|
15
|
+
export const VERIFYD_HEADERS = {
|
|
16
|
+
PUBLIC_KEY: 'X-Public-Key',
|
|
17
|
+
EPHEMERAL_KEY: 'X-Ephemeral-Key',
|
|
18
|
+
AUTHORIZATION: 'X-Authorization',
|
|
19
|
+
AUTHORIZATION_TIMESTAMP: 'X-Authorization-Timestamp',
|
|
20
|
+
};
|
|
21
|
+
const CONTENT_TYPE_HEADER = 'Content-Type';
|
|
22
|
+
export const CONTENT_TYPES = {
|
|
23
|
+
APPLICATION_JSON: 'application/json',
|
|
24
|
+
};
|
|
25
|
+
export const getRequestMethod = (body, _method) => {
|
|
26
|
+
const method = _method !== null && _method !== void 0 ? _method : (body ? 'POST' : 'GET');
|
|
27
|
+
return uppercase(method);
|
|
28
|
+
};
|
|
29
|
+
export const prepareRequestOptions = (_a = {}) => {
|
|
30
|
+
var { method: _method, body: _body, headers: _headers } = _a, requestOptions = __rest(_a, ["method", "body", "headers"]);
|
|
31
|
+
const method = getRequestMethod(_body, _method);
|
|
32
|
+
const _contentType = _headers === null || _headers === void 0 ? void 0 : _headers[CONTENT_TYPE_HEADER.toLowerCase()];
|
|
33
|
+
const headers = Object.assign({ [CONTENT_TYPE_HEADER]: _contentType || CONTENT_TYPES.APPLICATION_JSON }, _headers);
|
|
34
|
+
let body = _body;
|
|
35
|
+
if (body && headers[CONTENT_TYPE_HEADER].startsWith(CONTENT_TYPES.APPLICATION_JSON)) {
|
|
36
|
+
body = JSON.stringify(safeParse(body));
|
|
37
|
+
}
|
|
38
|
+
return Object.assign(Object.assign({ method,
|
|
39
|
+
headers }, (body && (method !== 'GET')) && { body }), requestOptions);
|
|
40
|
+
};
|
|
41
|
+
const convertToURL = (uri) => {
|
|
42
|
+
if (stringEmpty(uri)) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
const protocolRegex = /^(https?:\/\/).+/i;
|
|
46
|
+
if (!protocolRegex.test(uri)) {
|
|
47
|
+
return new URL(`https://${TEMP_HOSTNAME}${ensureLeadingSlash(uri)}`);
|
|
48
|
+
}
|
|
49
|
+
return new URL(uri);
|
|
50
|
+
};
|
|
51
|
+
export const normalizeURIParts = (uri) => {
|
|
52
|
+
const urlObject = convertToURL(uri);
|
|
53
|
+
if (!urlObject) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
REMOVABLE_KEYS.forEach((key) => urlObject.searchParams.delete(key));
|
|
57
|
+
return Object.assign(Object.assign({}, (urlObject.hostname !== TEMP_HOSTNAME) && {
|
|
58
|
+
origin: urlObject.origin,
|
|
59
|
+
}), { pathname: urlObject.pathname, search: urlObject.search });
|
|
60
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
11
|
+
var t = {};
|
|
12
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
13
|
+
t[p] = s[p];
|
|
14
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
15
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
16
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
17
|
+
t[p[i]] = s[p[i]];
|
|
18
|
+
}
|
|
19
|
+
return t;
|
|
20
|
+
};
|
|
21
|
+
import { VerificationError } from './errors';
|
|
22
|
+
import { normalizeURIParts, prepareRequestOptions, getRequestMethod, } from './request';
|
|
23
|
+
import { isTrue, safeParse, stringEmpty, objectToSortedString, } from './display';
|
|
24
|
+
import { WebCrypto } from './WebCrypto';
|
|
25
|
+
const getUnixString = () => {
|
|
26
|
+
const currentDate = new Date();
|
|
27
|
+
const unixTimestamp = currentDate.getTime();
|
|
28
|
+
return Math.floor(unixTimestamp / 1000).toString();
|
|
29
|
+
};
|
|
30
|
+
export const getVerificationKeysData = (publicKey_1, ...args_1) => __awaiter(void 0, [publicKey_1, ...args_1], void 0, function* (publicKey, { crypto: _crypto, util: _util } = {}) {
|
|
31
|
+
if (stringEmpty(publicKey)) {
|
|
32
|
+
return {};
|
|
33
|
+
}
|
|
34
|
+
const webCrypto = new WebCrypto({ crypto: _crypto, util: _util });
|
|
35
|
+
const _ephemeralStoreableKeyPair = yield webCrypto.getStorableKeyPair(yield webCrypto.generateKeyPair());
|
|
36
|
+
const _verificationKeyPair = yield webCrypto.getVerificationKeys({
|
|
37
|
+
publicKey,
|
|
38
|
+
privateKey: _ephemeralStoreableKeyPair.privateKey,
|
|
39
|
+
});
|
|
40
|
+
return {
|
|
41
|
+
publicKey,
|
|
42
|
+
ephemeral: _ephemeralStoreableKeyPair,
|
|
43
|
+
verification: _verificationKeyPair,
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
// eslint-disable-next-line arrow-body-style
|
|
47
|
+
export const prepareVerificationRequest = ({ keysData: _keysData, disableRecryption: _disableRecryption, crypto: _crypto, util: _util } = {}) => {
|
|
48
|
+
const webCrypto = new WebCrypto({ crypto: _crypto, util: _util });
|
|
49
|
+
const disableRecryption = isTrue(_disableRecryption);
|
|
50
|
+
return (requestPath_1, ...args_1) => __awaiter(void 0, [requestPath_1, ...args_1], void 0, function* (requestPath, _a = {}) {
|
|
51
|
+
var { method: rawMethod, body: rawBody, headers: rawHeaders } = _a, requestOptions = __rest(_a, ["method", "body", "headers"]);
|
|
52
|
+
let parsedBody = safeParse(rawBody);
|
|
53
|
+
const method = getRequestMethod(parsedBody, rawMethod);
|
|
54
|
+
if (disableRecryption || stringEmpty(_keysData === null || _keysData === void 0 ? void 0 : _keysData.publicKey)) {
|
|
55
|
+
return [
|
|
56
|
+
requestPath,
|
|
57
|
+
prepareRequestOptions(Object.assign({ method, body: parsedBody, headers: rawHeaders }, requestOptions), requestPath)
|
|
58
|
+
];
|
|
59
|
+
}
|
|
60
|
+
const { verification: { derivedHMACKey, derivedSecretKey, } = {}, ephemeral: { publicKey: ephemeralPublicKey, } = {}, } = _keysData !== null && _keysData !== void 0 ? _keysData : {};
|
|
61
|
+
if (!derivedHMACKey || !ephemeralPublicKey) {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
if (parsedBody && derivedSecretKey) {
|
|
65
|
+
parsedBody = yield webCrypto.encryptMessage(JSON.stringify(parsedBody), derivedSecretKey);
|
|
66
|
+
}
|
|
67
|
+
const timestamp = getUnixString();
|
|
68
|
+
const computedHMAC = yield webCrypto.generateHMAC(objectToSortedString(Object.assign({ body: parsedBody, method,
|
|
69
|
+
timestamp }, normalizeURIParts(requestPath))), derivedHMACKey);
|
|
70
|
+
return [
|
|
71
|
+
requestPath,
|
|
72
|
+
prepareRequestOptions(Object.assign({ method, body: parsedBody, headers: Object.assign({ 'X-Authorization': `HMAC-SHA256 ${computedHMAC}`, 'X-Authorization-Timestamp': timestamp, 'X-Ephemeral-Key': ephemeralPublicKey, 'X-Public-Key': _keysData.publicKey }, rawHeaders) }, requestOptions), requestPath),
|
|
73
|
+
derivedSecretKey
|
|
74
|
+
];
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
export const processVerificationResponse = ({ keysData, disableRecryption: _disableRecryption, crypto: _crypto, util: _util } = {}) => {
|
|
78
|
+
const webCrypto = new WebCrypto({ crypto: _crypto, util: _util });
|
|
79
|
+
const disableRecryption = isTrue(_disableRecryption);
|
|
80
|
+
return (encryptedResponse, _derivedSecretKey) => __awaiter(void 0, void 0, void 0, function* () {
|
|
81
|
+
var _a;
|
|
82
|
+
const derivedSecretKey = _derivedSecretKey !== null && _derivedSecretKey !== void 0 ? _derivedSecretKey : (_a = keysData.verification) === null || _a === void 0 ? void 0 : _a.derivedSecretKey;
|
|
83
|
+
if (disableRecryption || !encryptedResponse || !derivedSecretKey) {
|
|
84
|
+
return encryptedResponse;
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
const decryptedMessage = yield webCrypto.decryptMessage(encryptedResponse, derivedSecretKey);
|
|
88
|
+
return safeParse(decryptedMessage);
|
|
89
|
+
}
|
|
90
|
+
catch (_b) {
|
|
91
|
+
throw new VerificationError('Error decrypting response', { code: 400 });
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
};
|