@agnostack/verifyd 1.0.13 → 1.0.14-beta.1

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.
@@ -22,5 +22,1165 @@
22
22
  * SOFTWARE.
23
23
  */
24
24
 
25
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self)["@agnostack/verifyd/external"]={})}(this,(function(e){"use strict";const t=(e,t)=>null!=e&&typeof e===t,r=(e,r)=>(t(e,"string")&&(r&&(e=(e=>(t(e,"string")&&(e=e.trim()),e))(e)),(e.startsWith("{")||e.startsWith("[")||e.startsWith('"'))&&(e=JSON.parse(e))),e),n=e=>e?`${e}`:"",i=(e=[])=>e?Array.isArray(e)?e:[e]:[],o=e=>!(e=>{const t=n(e);return t.length>0&&!["null","undefined"].includes(t)})(e),a=([e],[t])=>((e,t)=>o(e)?1:o(t)?-1:n(e).localeCompare(t))(e,t),s=(e,t="")=>Object.entries((e=>e??{})(e)).sort(a).map((([e,t])=>`${e}=${t}`)).join(t),c=e=>`/${(e=>n(e).replace(/^\//,""))(e)}`,u=(e,t)=>{const r=n(e);return![...i(t),"","false"].includes(r)},y="xyz.com",l=["shop","host"],d="Content-Type",p={APPLICATION_JSON:"application/json"},f=(e,t)=>n(t??(e?"POST":"GET")).toUpperCase(),h=({method:e,body:t,headers:n,...i}={})=>{const o=f(t,e),a={[d]:p.APPLICATION_JSON,...n};let s=t;return s&&a[d].startsWith(p.APPLICATION_JSON)&&(s=JSON.stringify(r(s))),{method:o,headers:a,...s&&"GET"!==o&&{body:s},...i}},g=e=>{const t=(e=>{if(o(e))return;return/^(https?:\/\/).+/i.test(e)?new URL(e):new URL(`https://${y}${c(e)}`)})(e);if(t)return l.forEach((e=>t.searchParams.delete(e))),{...t.hostname!==y&&{origin:t.origin},pathname:t.pathname,search:t.search}};var m,w=((m=function(){return w}).toString=m.toLocaleString=m[Symbol.toPrimitive]=function(){return""},m.valueOf=function(){return!1},new Proxy(Object.freeze(m),{get:function(e,t){return e.hasOwnProperty(t)?e[t]:w}}));let b=global.window,v=e=>!function(e){return e===w}(e),K=void 0!==b?b:w;class A{constructor({crypto:e,util:t}={}){this._crypto=e??{},this._util=t??{}}get subtle(){return this._crypto?.subtle}async getWebCrypto(){if(!this._crypto?.subtle)try{this._crypto=(await import("isomorphic-webcrypto")).default}catch(e){try{this._crypto=(await import("crypto")).default}catch(e){throw console.error("Failed to import node crypto, ensure 'isomorphic-webcrypto' (or node 'crypto') is installed and/or pass in implementation via 'new WebCrypto({ crypto })'"),e}}if(!this._crypto?.subtle)throw new Error("Invalid crypto, missing subtle");return this._crypto}async getTextDecoder(){if(this._util?.TextDecoder)return this._util.TextDecoder;if(v(K)&&"function"==typeof K?.TextDecoder)return K.TextDecoder;try{const e=(await import("util")).TextDecoder;return this._util.TextDecoder=e,e}catch(e){throw console.error("Failed to import 'utils.TextDecoder', ensure 'util' is available and/or pass in implementation via 'new WebCrypto({ util })'"),e}}async getTextEncoder(){if(this._util?.TextEncoder)return this._util.TextEncoder;if(v(K)&&"function"==typeof K?.TextEncoder)return K.TextEncoder;try{const e=(await import("util")).TextEncoder;return this._util.TextEncoder=e,e}catch(e){throw console.error("Failed to import 'utils.TextEncoder', ensure 'util' is available and/or pass in implementation via 'new WebCrypto({ util })'"),e}}timingSafeEqual(e,t){if(null==e||null==t||e.length!==t.length)return!1;let r=0;for(let n=0;n<e.length;n++)r|=e[n]^t[n];return 0===r}stringToHex(e){return Array.from(n(e),(e=>e.charCodeAt(0).toString(16).padStart(2,"0"))).join("")}hexToString(e){return i(n(e).match(/.{1,2}/g)).map((e=>String.fromCharCode(parseInt(e,16)))).join("")}async arrayBufferToString(e){const t=new Uint8Array(e);return(new(await this.getTextDecoder())).decode(t)}arrayToArrayBuffer(e){return null!=ArrayBuffer.from?ArrayBuffer.from(e):new Uint8Array(e).buffer}ensureArrayBuffer(e){return e instanceof ArrayBuffer?e:this.arrayToArrayBuffer(e)}async generateKeyPair(){const e=await this.getWebCrypto();return await e.subtle.generateKey({name:"ECDH",namedCurve:"P-256"},!0,["deriveKey"])}getKeyOperations(e){switch(e){case"private":case"privateKey":return["deriveKey"];case"secret":case"secretKey":case"sharedSecret":return["encrypt","decrypt"];default:return[]}}getKeyAlgorythm(e){switch(e){case"derivedKey":case"derived":case"secret":case"secretKey":case"sharedSecret":return{name:"AES-GCM"};default:return{name:"ECDH",namedCurve:"P-256"}}}async generateHMAC(e,t){if(!e||!t)return;const r=await this.getWebCrypto(),n=await this.getTextEncoder(),i=await r.subtle.sign("HMAC",t,(new n).encode(e));return this.stringToHex(this.arrayBufferToString(i))}async verifyHMAC(e,t,r){const n=await this.generateHMAC(e,t);return this.timingSafeEqual(n,r)}async getStorableKey(e){const t=await this.getWebCrypto(),r=await t.subtle.exportKey("jwk",e);return this.stringToHex(JSON.stringify(r))}async restoreStorableKey(e,t){if(!t)return;const r=await this.getWebCrypto(),n=JSON.parse(this.hexToString(t)||"{}");var i;return(i=n)&&Object.keys(i).length?r.subtle.importKey("jwk",n,this.getKeyAlgorythm(e),!0,this.getKeyOperations(e)):void 0}async getStorableKeyPair(e){const t={};for(const[r,n]of Object.entries(e))t[r]=await this.getStorableKey(n);return t}async restoreStorableKeyPair(e){const t={};for(const[r,n]of Object.entries(e))t[r]=await this.restoreStorableKey(r,n);return t}async deriveSharedKey({publicKey:e,privateKey:t}){if(!e||!t)return;const r=await this.getWebCrypto();return await r.subtle.deriveKey({name:"ECDH",public:e},t,{name:"AES-GCM",length:256},!0,["encrypt","decrypt"])}async deriveHMACKey({publicKey:e,privateKey:t}){if(!e||!t)return;const r=await this.getWebCrypto();return await r.subtle.deriveKey({name:"ECDH",public:e},t,{name:"HMAC",hash:{name:"SHA-256"},length:256},!0,["sign","verify"])}async getVerificationKeys({publicKey:e,privateKey:t}){if(!e||!t)return{};const r=await this.restoreStorableKeyPair({publicKey:e,privateKey:t}),n=await this.deriveHMACKey(r);return{derivedSecretKey:await this.deriveSharedKey(r),derivedHMACKey:n}}async encryptMessage(e,t){if(!e||!t)return;const r=await this.getWebCrypto(),n=r.getRandomValues(new Uint8Array(12)),i=(new(await this.getTextEncoder())).encode(e),o=await r.subtle.encrypt({name:"AES-GCM",iv:n},t,i),a=new Uint8Array([...n,...new Uint8Array(o)]);return Array.from(a)}async decryptMessage(e,t){if(!e||!t)return;const r=await this.getWebCrypto(),n=this.ensureArrayBuffer(e),i=n.slice(0,12),o=n.slice(12),a=await r.subtle.decrypt({name:"AES-GCM",iv:i},t,o);return(new(await this.getTextDecoder())).decode(a)}}class S extends Error{constructor(e,t){super(e);const{code:r=500,...n}=t??{};this.code=r,this.data=n,this.name="VerificationError",Object.setPrototypeOf(this,S.prototype)}}const T=async e=>(async e=>{if(e?.rawBody)return e.rawBody;try{return(0,(await Promise.resolve().then((function(){return M}))).default)(e)}catch(e){throw console.error("Failed to import 'raw-body', please ensure the dependency is installed"),e}})(e).then((e=>e.toString())).catch((t=>{throw console.error(`Error getting raw body for '${e?.url}'`,t),t}));var C=function(){try{return require("async_hooks")}catch(e){return{}}}(),E=require("bytes"),x=require("http-errors"),P=require("iconv-lite"),O=require("unpipe");module.exports=function(e,t,r){var n=r,i=t||{};if(void 0===e)throw new TypeError("argument stream is required");if("object"!=typeof e||null===e||"function"!=typeof e.on)throw new TypeError("argument stream must be a stream");!0!==t&&"string"!=typeof t||(i={encoding:t});"function"==typeof t&&(n=t,i={});if(void 0!==n&&"function"!=typeof n)throw new TypeError("argument callback must be a function");if(!n&&!global.Promise)throw new TypeError("argument callback is required");var o=!0!==i.encoding?i.encoding:"utf-8",a=E.parse(i.limit),s=null==i.length||isNaN(i.length)?null:parseInt(i.length,10);if(n)return H(e,o,s,a,function(e){var t;C.AsyncResource&&(t=new C.AsyncResource(e.name||"bound-anonymous-fn"));if(!t||!t.runInAsyncScope)return e;return t.runInAsyncScope.bind(t,e,null)}(n));return new Promise((function(t,r){H(e,o,s,a,(function(e,n){if(e)return r(e);t(n)}))}))};var _=/^Encoding not recognized: /;function H(e,t,r,n,i){var o=!1,a=!0;if(null!==n&&null!==r&&r>n)return l(x(413,"request entity too large",{expected:r,length:r,limit:n,type:"entity.too.large"}));var s=e._readableState;if(e._decoder||s&&(s.encoding||s.decoder))return l(x(500,"stream encoding should not be set",{type:"stream.encoding.set"}));if(void 0!==e.readable&&!e.readable)return l(x(500,"stream is not readable",{type:"stream.not.readable"}));var c,u=0;try{c=function(e){if(!e)return null;try{return P.getDecoder(e)}catch(t){if(!_.test(t.message))throw t;throw x(415,"specified encoding unsupported",{encoding:e,type:"encoding.unsupported"})}}(t)}catch(e){return l(e)}var y=c?"":[];function l(){for(var t=new Array(arguments.length),r=0;r<t.length;r++)t[r]=arguments[r];function n(){h(),t[0]&&function(e){O(e),"function"==typeof e.pause&&e.pause()}(e),i.apply(null,t)}o=!0,a?process.nextTick(n):n()}function d(){o||l(x(400,"request aborted",{code:"ECONNABORTED",expected:r,length:r,received:u,type:"request.aborted"}))}function p(e){o||(u+=e.length,null!==n&&u>n?l(x(413,"request entity too large",{limit:n,received:u,type:"entity.too.large"})):c?y+=c.write(e):y.push(e))}function f(e){if(!o){if(e)return l(e);if(null!==r&&u!==r)l(x(400,"request size did not match content length",{expected:r,length:r,received:u,type:"request.size.invalid"}));else l(null,c?y+(c.end()||""):Buffer.concat(y))}}function h(){y=null,e.removeListener("aborted",d),e.removeListener("data",p),e.removeListener("end",f),e.removeListener("error",f),e.removeListener("close",h)}e.on("aborted",d),e.on("close",h),e.on("data",p),e.on("end",f),e.on("error",f),a=!1}var M=Object.freeze({__proto__:null});e.CONTENT_TYPES=p,e.HEADER_CONTENT_TYPE=d,e.VerificationError=S,e.WebCrypto=A,e.ensureRawBody=T,e.generateStorableKeyPairs=async({crypto:e,util:t}={})=>{const r=new A({crypto:e,util:t}),n=await r.generateKeyPair();return r.getStorableKeyPair({publicKey:n.publicKey,privateKey:n.privateKey})},e.getRequestMethod=f,e.getVerificationHelpers=({keyPairs:e,crypto:t,util:i}={})=>{const o=new A({crypto:t,util:i});return async(t,i)=>{const{"x-public-key":a,"x-ephemeral-key":c,"x-authorization-timestamp":y,"x-authorization":l}=t.headers??{},{uri:d,disableRecryption:p}=i??{},h=d??t.url,m=u(p);let w;try{const[i,d]=n(l).split(" ");let p;w=u(a&&c&&e?.shared&&y&&d&&"HMAC-SHA256"===i);const b=await T(t);let v=r(b);if(w){if(!(a&&c&&y&&d&&e?.shared&&a===e.shared.publicKey&&"HMAC-SHA256"===i))throw new S("Invalid or missing authorization",{code:401});if(p=await o.getVerificationKeys({publicKey:c,privateKey:e.shared.privateKey}),!p)throw new S("Invalid or missing verification",{code:412});const n=s({method:f(b,t.method),timestamp:y,body:v,...g(h)});if(!await o.verifyHMAC(n,p.derivedHMACKey,d))throw new S("Invalid or missing verification",{code:412});if(!m&&v){const e=await o.decryptMessage(v,p.derivedSecretKey);v=r(e)}}return{rawBody:b,requestBody:v,processResponse:async e=>e&&!m&&w&&p?.derivedSecretKey?o.encryptMessage(JSON.stringify(e),p.derivedSecretKey):e}}catch(e){throw console.error(`Error handling request verification for '${h}'`,{error:e,isVerifiable:w,disableRecryption:m}),e}}},e.getVerificationKeysData=async(e,{crypto:t,util:r}={})=>{if(o(e))return{};const n=new A({crypto:t,util:r}),i=await n.getStorableKeyPair(await n.generateKeyPair());return{publicKey:e,ephemeral:i,verification:await n.getVerificationKeys({publicKey:e,privateKey:i.privateKey})}},e.normalizeURIParts=g,e.prepareRequestOptions=h,e.prepareVerificationRequest=({keysData:e,disableRecryption:t,crypto:n,util:i}={})=>{const a=new A({crypto:n,util:i}),c=u(t);return async(t,{method:n,body:i,headers:u,...y}={})=>{let l=r(i);const d=f(l,n);if(c||o(e?.publicKey))return[t,h({method:d,body:l,headers:u,...y})];const{verification:{derivedHMACKey:p,derivedSecretKey:m}={},ephemeral:{publicKey:w}={}}=e??{};if(!p||!w)return;l&&m&&(l=await a.encryptMessage(JSON.stringify(l),m));const b=(()=>{const e=(new Date).getTime();return Math.floor(e/1e3).toString()})(),v=await a.generateHMAC(s({body:l,method:d,timestamp:b,...g(t)}),p);return[t,h({method:d,body:l,headers:{"X-Authorization":`HMAC-SHA256 ${v}`,"X-Authorization-Timestamp":b,"X-Ephemeral-Key":w,"X-Public-Key":e.publicKey,...u},...y}),m]}},e.processVerificationResponse=({keysData:e,disableRecryption:t,crypto:n,util:i}={})=>{const o=new A({crypto:n,util:i}),a=u(t);return async(t,n)=>{const i=n??e.verification?.derivedSecretKey;if(a||!t||!i)return t;const s=await o.decryptMessage(t,i);return r(s)}},Object.defineProperty(e,"__esModule",{value:!0})}));
25
+ (function (global, factory) {
26
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
27
+ typeof define === 'function' && define.amd ? define(['exports'], factory) :
28
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["@agnostack/verifyd/external"] = {}));
29
+ })(this, (function (exports) { 'use strict';
30
+
31
+ /* eslint-disable no-use-before-define */
32
+
33
+ const isType = (value, type) => (
34
+ // eslint-disable-next-line eqeqeq, valid-typeof
35
+ (value != undefined) && (typeof value === type)
36
+ );
37
+
38
+ const safeTrim = (value) => {
39
+ if (isType(value, 'string')) {
40
+ // eslint-disable-next-line no-param-reassign
41
+ value = value.trim();
42
+ }
43
+
44
+ return value
45
+ };
46
+
47
+ const safeParse = (value, trim) => {
48
+ if (isType(value, 'string')) {
49
+ if (trim) {
50
+ // eslint-disable-next-line no-param-reassign
51
+ value = safeTrim(value);
52
+ }
53
+
54
+ if (value.startsWith('{') || value.startsWith('[') || value.startsWith('"')) {
55
+ // eslint-disable-next-line no-param-reassign
56
+ value = JSON.parse(value);
57
+ }
58
+ }
59
+
60
+ // TODO: should this be value ?? {}
61
+ return value
62
+ };
63
+
64
+ const ensureString = (string) => (
65
+ string ? `${string}` : ''
66
+ );
67
+
68
+ const ensureArray = (array = []) => (
69
+ // eslint-disable-next-line no-nested-ternary
70
+ !array ? [] : Array.isArray(array) ? array : [array]
71
+ );
72
+
73
+ const ensureObject = (object) => (
74
+ object ?? {}
75
+ );
76
+
77
+ // NOTE: this does not ensure !isType(string)
78
+ const objectEmpty = (object) => (
79
+ !object || !Object.keys(object).length
80
+ );
81
+
82
+ const stringNotEmpty = (stringable) => {
83
+ const string = ensureString(stringable);
84
+ return ((string.length > 0) && !['null', 'undefined'].includes(string))
85
+ };
86
+
87
+ const stringEmpty = (stringable) => (
88
+ !stringNotEmpty(stringable)
89
+ );
90
+
91
+ const compareString = (string1, string2) => {
92
+ if (stringEmpty(string1)) {
93
+ return 1
94
+ }
95
+
96
+ if (stringEmpty(string2)) {
97
+ return -1
98
+ }
99
+
100
+ return ensureString(string1).localeCompare(string2)
101
+ };
102
+
103
+ const compareEntryKeys = ([string1], [string2]) => (
104
+ compareString(string1, string2)
105
+ );
106
+
107
+ const objectToSortedString = (object, separator = '') => (
108
+ Object.entries(ensureObject(object))
109
+ .sort(compareEntryKeys)
110
+ .map(([key, value]) => `${key}=${value}`)
111
+ .join(separator)
112
+ );
113
+
114
+ const uppercase = (string) => (
115
+ ensureString(string).toUpperCase()
116
+ );
117
+
118
+ const removeLeadingSlash = (string) => (
119
+ ensureString(string).replace(/^\//, '')
120
+ );
121
+
122
+ const ensureLeadingSlash = (string) => (
123
+ `/${removeLeadingSlash(string)}`
124
+ );
125
+
126
+ const isTrue = (value, falsy) => {
127
+ const string = ensureString(value);
128
+ return ![...ensureArray(falsy), '', 'false'].includes(string)
129
+ };
130
+
131
+ const TEMP_HOSTNAME = 'xyz.com';
132
+ const REMOVABLE_KEYS = ['shop', 'host'];
133
+
134
+ const HEADER_CONTENT_TYPE = 'Content-Type';
135
+ const CONTENT_TYPES = {
136
+ APPLICATION_JSON: 'application/json',
137
+ };
138
+
139
+ const getRequestMethod = (body, _method) => {
140
+ const method = _method ?? (body ? 'POST' : 'GET');
141
+
142
+ return uppercase(method)
143
+ };
144
+
145
+ const prepareRequestOptions = ({ method: _method, body: _body, headers: _header, ...requestOptions } = {}) => {
146
+ const method = getRequestMethod(_body, _method);
147
+
148
+ const headers = {
149
+ [HEADER_CONTENT_TYPE]: CONTENT_TYPES.APPLICATION_JSON,
150
+ ..._header,
151
+ };
152
+
153
+ let body = _body;
154
+ if (body && headers[HEADER_CONTENT_TYPE].startsWith(CONTENT_TYPES.APPLICATION_JSON)) {
155
+ body = JSON.stringify(safeParse(body));
156
+ }
157
+
158
+ return {
159
+ method,
160
+ headers,
161
+ ...(body && (method !== 'GET')) && { body },
162
+ ...requestOptions,
163
+ }
164
+ };
165
+
166
+ const convertToURL = (uri) => {
167
+ if (stringEmpty(uri)) {
168
+ return undefined
169
+ }
170
+
171
+ const protocolRegex = /^(https?:\/\/).+/i;
172
+
173
+ if (!protocolRegex.test(uri)) {
174
+ return new URL(`https://${TEMP_HOSTNAME}${ensureLeadingSlash(uri)}`)
175
+ }
176
+
177
+ return new URL(uri)
178
+ };
179
+
180
+ const normalizeURIParts = (uri) => {
181
+ const urlObject = convertToURL(uri);
182
+ if (!urlObject) {
183
+ return undefined
184
+ }
185
+
186
+ REMOVABLE_KEYS.forEach((key) => urlObject.searchParams.delete(key));
187
+
188
+ return {
189
+ ...(urlObject.hostname !== TEMP_HOSTNAME) && {
190
+ origin: urlObject.origin,
191
+ },
192
+ pathname: urlObject.pathname,
193
+ search: urlObject.search,
194
+ }
195
+ };
196
+
197
+ var n,r=((n=function(){return r}).toString=n.toLocaleString=n[Symbol.toPrimitive]=function(){return ""},n.valueOf=function(){return !1},new Proxy(Object.freeze(n),{get:function(n,t){return n.hasOwnProperty(t)?n[t]:r}})),u=function(n){return n===r};
198
+
199
+ let win = global.window;
200
+ let exists = (variable) => !u(variable);
201
+ let window = typeof win !== "undefined" ? win : r;
202
+
203
+ class WebCrypto {
204
+ constructor({ crypto: _crypto, util: _util } = {}) {
205
+ this._crypto = _crypto ?? {};
206
+ this._util = _util ?? {};
207
+ }
208
+
209
+ get subtle() {
210
+ return this._crypto?.subtle
211
+ }
212
+
213
+ async getWebCrypto() {
214
+ if (!this._crypto?.subtle) {
215
+ try {
216
+ this._crypto = (await import('isomorphic-webcrypto')).default;
217
+ } catch (_ignore) {
218
+ console.info('Failed to import isomorphic-webcrypto, retrying w/ node crypto');
219
+ try {
220
+ this._crypto = (await import('crypto')).default;
221
+ } catch (error) {
222
+ // eslint-disable-next-line max-len
223
+ console.error(`Failed to import node crypto, ensure 'isomorphic-webcrypto' (or node 'crypto') is installed and/or pass in implementation via 'new WebCrypto({ crypto })'`);
224
+ throw error
225
+ }
226
+ }
227
+ }
228
+
229
+ if (!this._crypto?.subtle) {
230
+ throw new Error('Invalid crypto, missing subtle')
231
+ }
232
+
233
+ return this._crypto
234
+ }
235
+
236
+ async getTextDecoder() {
237
+ if (this._util?.TextDecoder) {
238
+ return this._util.TextDecoder
239
+ }
240
+
241
+ if (exists(window) && typeof window?.TextDecoder === 'function') {
242
+ return window.TextDecoder
243
+ }
244
+
245
+ try {
246
+ const TextDecoder = (await import('util')).TextDecoder;
247
+ this._util.TextDecoder = TextDecoder;
248
+
249
+ return TextDecoder
250
+ } catch (error) {
251
+ console.error(`Failed to import 'utils.TextDecoder', ensure 'util' is available and/or pass in implementation via 'new WebCrypto({ util })'`);
252
+ throw error
253
+ }
254
+ }
255
+
256
+ async getTextEncoder() {
257
+ if (this._util?.TextEncoder) {
258
+ return this._util.TextEncoder
259
+ }
260
+
261
+ if (exists(window) && typeof window?.TextEncoder === 'function') {
262
+ return window.TextEncoder
263
+ }
264
+
265
+ try {
266
+ const TextEncoder = (await import('util')).TextEncoder;
267
+ this._util.TextEncoder = TextEncoder;
268
+
269
+ return TextEncoder
270
+ } catch (error) {
271
+ console.error(`Failed to import 'utils.TextEncoder', ensure 'util' is available and/or pass in implementation via 'new WebCrypto({ util })'`);
272
+ throw error
273
+ }
274
+ }
275
+
276
+ timingSafeEqual(value1, value2) {
277
+ if (
278
+ (value1 == undefined) ||
279
+ (value2 == undefined) ||
280
+ (value1.length !== value2.length)
281
+ ) {
282
+ return false
283
+ }
284
+
285
+ let result = 0;
286
+ // eslint-disable-next-line no-plusplus
287
+ for (let i = 0; i < value1.length; i++) {
288
+ // eslint-disable-next-line no-bitwise
289
+ result |= value1[i] ^ value2[i];
290
+ }
291
+
292
+ return (result === 0)
293
+ }
294
+
295
+ stringToHex(stringValue) {
296
+ return (
297
+ Array.from(ensureString(stringValue), (char) => (
298
+ char.charCodeAt(0).toString(16).padStart(2, '0')
299
+ )).join('')
300
+ )
301
+ }
302
+
303
+ hexToString(hexValue) {
304
+ return (
305
+ ensureArray(
306
+ ensureString(hexValue).match(/.{1,2}/g)
307
+ )
308
+ .map((byte) => String.fromCharCode(parseInt(byte, 16)))
309
+ .join('')
310
+ )
311
+ }
312
+
313
+ async arrayBufferToString(arrayBuffer) {
314
+ const uint8Array = new Uint8Array(arrayBuffer);
315
+ const Decoder = await this.getTextDecoder();
316
+ return new Decoder().decode(uint8Array)
317
+ }
318
+
319
+ arrayToArrayBuffer(array) {
320
+ return (
321
+ (ArrayBuffer.from != undefined)
322
+ ? ArrayBuffer.from(array)
323
+ : new Uint8Array(array).buffer
324
+ )
325
+ }
326
+
327
+ ensureArrayBuffer(arrayOrArrayBuffer) {
328
+ return (
329
+ (arrayOrArrayBuffer instanceof ArrayBuffer)
330
+ ? arrayOrArrayBuffer
331
+ : this.arrayToArrayBuffer(arrayOrArrayBuffer)
332
+ )
333
+ }
334
+
335
+ async generateKeyPair() {
336
+ const crypto = await this.getWebCrypto();
337
+ const keyPair = await crypto.subtle.generateKey(
338
+ {
339
+ name: 'ECDH',
340
+ namedCurve: 'P-256',
341
+ },
342
+ true,
343
+ ['deriveKey']
344
+ );
345
+
346
+ return keyPair
347
+ }
348
+
349
+ getKeyOperations(keyType) {
350
+ switch (keyType) {
351
+ case 'private':
352
+ case 'privateKey': {
353
+ return ['deriveKey']
354
+ }
355
+
356
+ case 'secret':
357
+ case 'secretKey':
358
+ case 'sharedSecret': {
359
+ return ['encrypt', 'decrypt']
360
+ }
361
+
362
+ default: {
363
+ return []
364
+ }
365
+ }
366
+ }
367
+
368
+ getKeyAlgorythm(keyType) {
369
+ switch (keyType) {
370
+ case 'derivedKey':
371
+ case 'derived':
372
+ case 'secret':
373
+ case 'secretKey':
374
+ case 'sharedSecret': {
375
+ return {
376
+ name: 'AES-GCM',
377
+ }
378
+ }
379
+
380
+ default: {
381
+ return {
382
+ name: 'ECDH',
383
+ namedCurve: 'P-256',
384
+ }
385
+ }
386
+ }
387
+ }
388
+
389
+ async generateHMAC(message, derivedKey) {
390
+ if (!message || !derivedKey) {
391
+ return undefined
392
+ }
393
+
394
+ const crypto = await this.getWebCrypto();
395
+ const Encoder = await this.getTextEncoder();
396
+
397
+ const signature = await crypto.subtle.sign(
398
+ 'HMAC',
399
+ derivedKey,
400
+ new Encoder().encode(message)
401
+ );
402
+
403
+ return this.stringToHex(
404
+ this.arrayBufferToString(signature)
405
+ )
406
+ }
407
+
408
+ async verifyHMAC(message, derivedKey, verifiableHMAC) {
409
+ const calculatedHMAC = await this.generateHMAC(message, derivedKey);
410
+
411
+ return this.timingSafeEqual(calculatedHMAC, verifiableHMAC)
412
+ }
413
+
414
+ async getStorableKey(key) {
415
+ const crypto = await this.getWebCrypto();
416
+
417
+ const exportedJWK = await crypto.subtle.exportKey('jwk', key);
418
+ return this.stringToHex(JSON.stringify(exportedJWK))
419
+ }
420
+
421
+ async restoreStorableKey(keyType, storableHex) {
422
+ if (!storableHex) {
423
+ return undefined
424
+ }
425
+ const crypto = await this.getWebCrypto();
426
+
427
+ const exportedJWK = JSON.parse(this.hexToString(storableHex) || '{}');
428
+ if (objectEmpty(exportedJWK)) {
429
+ return undefined
430
+ }
431
+
432
+ return crypto.subtle.importKey(
433
+ 'jwk',
434
+ exportedJWK,
435
+ this.getKeyAlgorythm(keyType),
436
+ true,
437
+ this.getKeyOperations(keyType)
438
+ )
439
+ }
440
+
441
+ async getStorableKeyPair(keyPair) {
442
+ const storableKeys = {};
443
+
444
+ // eslint-disable-next-line no-restricted-syntax
445
+ for (const [keyType, key] of Object.entries(keyPair)) {
446
+ // eslint-disable-next-line no-await-in-loop
447
+ storableKeys[keyType] = await this.getStorableKey(key);
448
+ }
449
+
450
+ return storableKeys
451
+ }
452
+
453
+ async restoreStorableKeyPair(keyPair) {
454
+ const restoredKeys = {};
455
+
456
+ // eslint-disable-next-line no-restricted-syntax
457
+ for (const [keyType, key] of Object.entries(keyPair)) {
458
+ // eslint-disable-next-line no-await-in-loop
459
+ restoredKeys[keyType] = await this.restoreStorableKey(keyType, key);
460
+ }
461
+
462
+ return restoredKeys
463
+ }
464
+
465
+ async deriveSharedKey({ publicKey, privateKey }) {
466
+ if (!publicKey || !privateKey) {
467
+ return undefined
468
+ }
469
+
470
+ const crypto = await this.getWebCrypto();
471
+ const derivedKey = await crypto.subtle.deriveKey(
472
+ {
473
+ name: 'ECDH',
474
+ public: publicKey,
475
+ },
476
+ privateKey,
477
+ {
478
+ name: 'AES-GCM',
479
+ length: 256,
480
+ },
481
+ true,
482
+ ['encrypt', 'decrypt']
483
+ );
484
+ return derivedKey
485
+ }
486
+
487
+ async deriveHMACKey({ publicKey, privateKey }) {
488
+ if (!publicKey || !privateKey) {
489
+ return undefined
490
+ }
491
+
492
+ const crypto = await this.getWebCrypto();
493
+ const derivedKey = await crypto.subtle.deriveKey(
494
+ {
495
+ name: 'ECDH',
496
+ public: publicKey,
497
+ },
498
+ privateKey,
499
+ {
500
+ name: 'HMAC',
501
+ hash: { name: 'SHA-256' },
502
+ length: 256, // Adjusted key length, e.g., 128 bits
503
+ },
504
+ true,
505
+ ['sign', 'verify']
506
+ );
507
+ return derivedKey
508
+ }
509
+
510
+ async getVerificationKeys({ publicKey, privateKey }) {
511
+ if (!publicKey || !privateKey) {
512
+ return {}
513
+ }
514
+
515
+ const sharedKeyPair = await this.restoreStorableKeyPair({ publicKey, privateKey });
516
+ const derivedHMACKey = await this.deriveHMACKey(sharedKeyPair);
517
+ const derivedSecretKey = await this.deriveSharedKey(sharedKeyPair);
518
+
519
+ return {
520
+ derivedSecretKey,
521
+ derivedHMACKey,
522
+ }
523
+ }
524
+
525
+ async encryptMessage(decryptedMessage, derivedKey) {
526
+ if (!decryptedMessage || !derivedKey) {
527
+ return undefined
528
+ }
529
+
530
+ const crypto = await this.getWebCrypto();
531
+ const iv = crypto.getRandomValues(new Uint8Array(12));
532
+ const Encoder = await this.getTextEncoder();
533
+ const encodedMessage = new Encoder().encode(decryptedMessage);
534
+ const ciphertext = await crypto.subtle.encrypt(
535
+ {
536
+ name: 'AES-GCM',
537
+ iv,
538
+ },
539
+ derivedKey,
540
+ encodedMessage
541
+ );
542
+
543
+ const encryptedMessage = new Uint8Array([
544
+ ...iv,
545
+ ...new Uint8Array(ciphertext)
546
+ ]);
547
+ return Array.from(encryptedMessage)
548
+ }
549
+
550
+ async decryptMessage(encryptedMessage, derivedKey) {
551
+ if (!encryptedMessage || !derivedKey) {
552
+ return undefined
553
+ }
554
+
555
+ const crypto = await this.getWebCrypto();
556
+ // NOTE: this presumed an array or arrayBuffer coming in as encryptedMessage (will fail w/ IV error if its a string)
557
+ const encryptedArrayBuffer = this.ensureArrayBuffer(encryptedMessage);
558
+ const iv = encryptedArrayBuffer.slice(0, 12);
559
+ const ciphertext = encryptedArrayBuffer.slice(12);
560
+
561
+ const decryptedArrayBuffer = await crypto.subtle.decrypt(
562
+ {
563
+ name: 'AES-GCM',
564
+ iv,
565
+ },
566
+ derivedKey,
567
+ ciphertext
568
+ );
569
+
570
+ const Decoder = await this.getTextDecoder();
571
+ const decryptedMessage = new Decoder().decode(decryptedArrayBuffer);
572
+ return decryptedMessage
573
+ }
574
+ }
575
+
576
+ const getUnixString = () => {
577
+ const currentDate = new Date();
578
+ const unixTimestamp = currentDate.getTime();
579
+ return Math.floor(unixTimestamp / 1000).toString()
580
+ };
581
+
582
+ const getVerificationKeysData = async (publicKey, { crypto: _crypto, util: _util } = {}) => {
583
+ if (stringEmpty(publicKey)) {
584
+ return {}
585
+ }
586
+
587
+ const webCrypto = new WebCrypto({ crypto: _crypto, util: _util });
588
+
589
+ const _ephemeralStoreableKeyPair = await webCrypto.getStorableKeyPair(
590
+ await webCrypto.generateKeyPair()
591
+ );
592
+
593
+ const _verificationKeyPair = await webCrypto.getVerificationKeys({
594
+ publicKey,
595
+ privateKey: _ephemeralStoreableKeyPair.privateKey,
596
+ });
597
+
598
+ return {
599
+ publicKey,
600
+ ephemeral: _ephemeralStoreableKeyPair,
601
+ verification: _verificationKeyPair,
602
+ }
603
+ };
604
+
605
+ // eslint-disable-next-line arrow-body-style
606
+ const prepareVerificationRequest = ({ keysData: _keysData, disableRecryption: _disableRecryption, crypto: _crypto, util: _util } = {}) => {
607
+ const webCrypto = new WebCrypto({ crypto: _crypto, util: _util });
608
+ const disableRecryption = isTrue(_disableRecryption);
609
+
610
+ return async (requestPath, { method: rawMethod, body: rawBody, headers: rawHeaders, ...requestOptions } = {}) => {
611
+ let parsedBody = safeParse(rawBody);
612
+ const method = getRequestMethod(parsedBody, rawMethod);
613
+
614
+ if (disableRecryption || stringEmpty(_keysData?.publicKey)) {
615
+ return [
616
+ requestPath,
617
+ prepareRequestOptions({
618
+ method,
619
+ body: parsedBody,
620
+ headers: rawHeaders,
621
+ ...requestOptions,
622
+ })
623
+ ]
624
+ }
625
+
626
+ const {
627
+ verification: {
628
+ derivedHMACKey,
629
+ derivedSecretKey,
630
+ } = {},
631
+ ephemeral: {
632
+ publicKey: ephemeralPublicKey,
633
+ } = {},
634
+ } = _keysData ?? {};
635
+
636
+ if (!derivedHMACKey || !ephemeralPublicKey) {
637
+ return undefined
638
+ }
639
+
640
+ if (parsedBody && derivedSecretKey) {
641
+ parsedBody = await webCrypto.encryptMessage(JSON.stringify(parsedBody), derivedSecretKey);
642
+ }
643
+
644
+ const timestamp = getUnixString();
645
+ const computedHMAC = await webCrypto.generateHMAC(
646
+ objectToSortedString({
647
+ body: parsedBody,
648
+ method,
649
+ timestamp,
650
+ ...normalizeURIParts(requestPath),
651
+ }),
652
+ derivedHMACKey
653
+ );
654
+
655
+ return [
656
+ requestPath,
657
+ prepareRequestOptions({
658
+ method,
659
+ body: parsedBody,
660
+ headers: {
661
+ 'X-Authorization': `HMAC-SHA256 ${computedHMAC}`,
662
+ 'X-Authorization-Timestamp': timestamp,
663
+ 'X-Ephemeral-Key': ephemeralPublicKey,
664
+ 'X-Public-Key': _keysData.publicKey,
665
+ ...rawHeaders,
666
+ },
667
+ ...requestOptions,
668
+ }),
669
+ derivedSecretKey
670
+ ]
671
+ }
672
+ };
673
+
674
+ const processVerificationResponse = ({ keysData, disableRecryption: _disableRecryption, crypto: _crypto, util: _util } = {}) => {
675
+ const webCrypto = new WebCrypto({ crypto: _crypto, util: _util });
676
+ const disableRecryption = isTrue(_disableRecryption);
677
+
678
+ return async (encryptedResponse, _derivedSecretKey) => {
679
+ const derivedSecretKey = _derivedSecretKey ?? keysData.verification?.derivedSecretKey;
680
+ if (disableRecryption || !encryptedResponse || !derivedSecretKey) {
681
+ return encryptedResponse
682
+ }
683
+
684
+ const decryptedMessage = await webCrypto.decryptMessage(encryptedResponse, derivedSecretKey);
685
+ return safeParse(decryptedMessage)
686
+ }
687
+ };
688
+
689
+ class VerificationError extends Error {
690
+ constructor(message, _data) {
691
+ super(message);
692
+ const { code = 500, ...data } = _data ?? {};
693
+ this.code = code;
694
+ this.data = data;
695
+ this.name = 'VerificationError';
696
+ Object.setPrototypeOf(this, VerificationError.prototype);
697
+ }
698
+ }
699
+
700
+ const getChunkedRawBody = async (readable) => {
701
+ if (readable?.rawBody) {
702
+ return readable.rawBody
703
+ }
704
+
705
+ // TODO: move to req.text() after next 13.5: https://github.com/vercel/next.js/discussions/13405
706
+ try {
707
+ const getRawBody = (await Promise.resolve().then(function () { return index; })).default;
708
+ return getRawBody(readable)
709
+ } catch (error) {
710
+ console.error(`Failed to import 'raw-body', please ensure the dependency is installed`);
711
+ throw error
712
+ }
713
+ };
714
+
715
+ // TODO: explore returning mutated request object adding on req.rawBody??
716
+ const ensureRawBody = async (req) => (
717
+ getChunkedRawBody(req)
718
+ .then((_rawBody) => _rawBody.toString())
719
+ .catch((error) => {
720
+ console.error(`Error getting raw body for '${req?.url}'`, error);
721
+ throw error
722
+ })
723
+ );
724
+
725
+ const generateStorableKeyPairs = async ({ crypto: _crypto, util: _util } = {}) => {
726
+ const webCrypto = new WebCrypto({ crypto: _crypto, util: _util });
727
+ const sharedKeyPair = await webCrypto.generateKeyPair();
728
+
729
+ return webCrypto.getStorableKeyPair({
730
+ publicKey: sharedKeyPair.publicKey,
731
+ privateKey: sharedKeyPair.privateKey,
732
+ })
733
+ };
734
+
735
+ const getVerificationHelpers = ({ keyPairs, crypto: _crypto, util: _util } = {}) => {
736
+ const webCrypto = new WebCrypto({ crypto: _crypto, util: _util });
737
+
738
+ return async (req, params) => {
739
+ const {
740
+ 'x-public-key': apiKey,
741
+ 'x-ephemeral-key': ephemeralPublicKey,
742
+ 'x-authorization-timestamp': customAuthTimestamp,
743
+ 'x-authorization': customAuth,
744
+ } = req.headers ?? {};
745
+
746
+ const { uri: _uri, disableRecryption: _disableRecryption } = params ?? {};
747
+ const uri = _uri ?? req.url;
748
+ const disableRecryption = isTrue(_disableRecryption);
749
+
750
+ let isVerifiable;
751
+ try {
752
+ const [authProtocol, authSignature] = ensureString(customAuth).split(' ');
753
+ isVerifiable = isTrue(
754
+ apiKey &&
755
+ ephemeralPublicKey &&
756
+ keyPairs?.shared &&
757
+ customAuthTimestamp &&
758
+ authSignature &&
759
+ (authProtocol === 'HMAC-SHA256')
760
+ );
761
+
762
+ let verificationKeys;
763
+ const rawBody = await ensureRawBody(req);
764
+
765
+ // NOTE: requestBody should be wind up decrypted when isVerifiable (unless disableRecryption, then will pass through)
766
+ let requestBody = safeParse(rawBody);
767
+
768
+ // TEMP!!! remove isVerifiable check once webwidget moved to react
769
+ if (isVerifiable) {
770
+ if (
771
+ !apiKey ||
772
+ !ephemeralPublicKey ||
773
+ !customAuthTimestamp ||
774
+ !authSignature ||
775
+ !keyPairs?.shared ||
776
+ (apiKey !== keyPairs.shared.publicKey) ||
777
+ (authProtocol !== 'HMAC-SHA256')
778
+ ) {
779
+ throw new VerificationError('Invalid or missing authorization', { code: 401 })
780
+ }
781
+
782
+ verificationKeys = await webCrypto.getVerificationKeys({
783
+ publicKey: ephemeralPublicKey,
784
+ privateKey: keyPairs.shared.privateKey,
785
+ });
786
+
787
+ if (!verificationKeys) {
788
+ throw new VerificationError('Invalid or missing verification', { code: 412 })
789
+ }
790
+
791
+ const verificationPayload = objectToSortedString({
792
+ method: getRequestMethod(rawBody, req.method),
793
+ timestamp: customAuthTimestamp,
794
+ body: requestBody, // NOTE: requestBody should be encrypted when isVerifiable
795
+ ...normalizeURIParts(uri),
796
+ });
797
+
798
+ const isValid = await webCrypto.verifyHMAC(
799
+ verificationPayload,
800
+ verificationKeys.derivedHMACKey,
801
+ authSignature
802
+ );
803
+
804
+ if (!isValid) {
805
+ throw new VerificationError('Invalid or missing verification', { code: 412 })
806
+ }
807
+
808
+ if (!disableRecryption && requestBody) {
809
+ const decryptedMessage = await webCrypto.decryptMessage(requestBody, verificationKeys.derivedSecretKey);
810
+ requestBody = safeParse(decryptedMessage);
811
+ }
812
+ }
813
+
814
+ const processResponse = async (response) => {
815
+ if (!response || disableRecryption || !isVerifiable || !verificationKeys?.derivedSecretKey) {
816
+ return response
817
+ }
818
+
819
+ return webCrypto.encryptMessage(JSON.stringify(response), verificationKeys.derivedSecretKey)
820
+ };
821
+
822
+ return { rawBody, requestBody, processResponse }
823
+ } catch (error) {
824
+ console.error(`Error handling request verification for '${uri}'`, { error, isVerifiable, disableRecryption });
825
+ throw error
826
+ }
827
+ }
828
+ };
829
+
830
+ /*!
831
+ * raw-body
832
+ * Copyright(c) 2013-2014 Jonathan Ong
833
+ * Copyright(c) 2014-2022 Douglas Christopher Wilson
834
+ * MIT Licensed
835
+ */
836
+
837
+ /**
838
+ * Module dependencies.
839
+ * @private
840
+ */
841
+
842
+ var asyncHooks = tryRequireAsyncHooks();
843
+ var bytes = require('bytes');
844
+ var createError = require('http-errors');
845
+ var iconv = require('iconv-lite');
846
+ var unpipe = require('unpipe');
847
+
848
+ /**
849
+ * Module exports.
850
+ * @public
851
+ */
852
+
853
+ module.exports = getRawBody;
854
+
855
+ /**
856
+ * Module variables.
857
+ * @private
858
+ */
859
+
860
+ var ICONV_ENCODING_MESSAGE_REGEXP = /^Encoding not recognized: /;
861
+
862
+ /**
863
+ * Get the decoder for a given encoding.
864
+ *
865
+ * @param {string} encoding
866
+ * @private
867
+ */
868
+
869
+ function getDecoder (encoding) {
870
+ if (!encoding) return null
871
+
872
+ try {
873
+ return iconv.getDecoder(encoding)
874
+ } catch (e) {
875
+ // error getting decoder
876
+ if (!ICONV_ENCODING_MESSAGE_REGEXP.test(e.message)) throw e
877
+
878
+ // the encoding was not found
879
+ throw createError(415, 'specified encoding unsupported', {
880
+ encoding: encoding,
881
+ type: 'encoding.unsupported'
882
+ })
883
+ }
884
+ }
885
+
886
+ /**
887
+ * Get the raw body of a stream (typically HTTP).
888
+ *
889
+ * @param {object} stream
890
+ * @param {object|string|function} [options]
891
+ * @param {function} [callback]
892
+ * @public
893
+ */
894
+
895
+ function getRawBody (stream, options, callback) {
896
+ var done = callback;
897
+ var opts = options || {};
898
+
899
+ // light validation
900
+ if (stream === undefined) {
901
+ throw new TypeError('argument stream is required')
902
+ } else if (typeof stream !== 'object' || stream === null || typeof stream.on !== 'function') {
903
+ throw new TypeError('argument stream must be a stream')
904
+ }
905
+
906
+ if (options === true || typeof options === 'string') {
907
+ // short cut for encoding
908
+ opts = {
909
+ encoding: options
910
+ };
911
+ }
912
+
913
+ if (typeof options === 'function') {
914
+ done = options;
915
+ opts = {};
916
+ }
917
+
918
+ // validate callback is a function, if provided
919
+ if (done !== undefined && typeof done !== 'function') {
920
+ throw new TypeError('argument callback must be a function')
921
+ }
922
+
923
+ // require the callback without promises
924
+ if (!done && !global.Promise) {
925
+ throw new TypeError('argument callback is required')
926
+ }
927
+
928
+ // get encoding
929
+ var encoding = opts.encoding !== true
930
+ ? opts.encoding
931
+ : 'utf-8';
932
+
933
+ // convert the limit to an integer
934
+ var limit = bytes.parse(opts.limit);
935
+
936
+ // convert the expected length to an integer
937
+ var length = opts.length != null && !isNaN(opts.length)
938
+ ? parseInt(opts.length, 10)
939
+ : null;
940
+
941
+ if (done) {
942
+ // classic callback style
943
+ return readStream(stream, encoding, length, limit, wrap(done))
944
+ }
945
+
946
+ return new Promise(function executor (resolve, reject) {
947
+ readStream(stream, encoding, length, limit, function onRead (err, buf) {
948
+ if (err) return reject(err)
949
+ resolve(buf);
950
+ });
951
+ })
952
+ }
953
+
954
+ /**
955
+ * Halt a stream.
956
+ *
957
+ * @param {Object} stream
958
+ * @private
959
+ */
960
+
961
+ function halt (stream) {
962
+ // unpipe everything from the stream
963
+ unpipe(stream);
964
+
965
+ // pause stream
966
+ if (typeof stream.pause === 'function') {
967
+ stream.pause();
968
+ }
969
+ }
970
+
971
+ /**
972
+ * Read the data from the stream.
973
+ *
974
+ * @param {object} stream
975
+ * @param {string} encoding
976
+ * @param {number} length
977
+ * @param {number} limit
978
+ * @param {function} callback
979
+ * @public
980
+ */
981
+
982
+ function readStream (stream, encoding, length, limit, callback) {
983
+ var complete = false;
984
+ var sync = true;
985
+
986
+ // check the length and limit options.
987
+ // note: we intentionally leave the stream paused,
988
+ // so users should handle the stream themselves.
989
+ if (limit !== null && length !== null && length > limit) {
990
+ return done(createError(413, 'request entity too large', {
991
+ expected: length,
992
+ length: length,
993
+ limit: limit,
994
+ type: 'entity.too.large'
995
+ }))
996
+ }
997
+
998
+ // streams1: assert request encoding is buffer.
999
+ // streams2+: assert the stream encoding is buffer.
1000
+ // stream._decoder: streams1
1001
+ // state.encoding: streams2
1002
+ // state.decoder: streams2, specifically < 0.10.6
1003
+ var state = stream._readableState;
1004
+ if (stream._decoder || (state && (state.encoding || state.decoder))) {
1005
+ // developer error
1006
+ return done(createError(500, 'stream encoding should not be set', {
1007
+ type: 'stream.encoding.set'
1008
+ }))
1009
+ }
1010
+
1011
+ if (typeof stream.readable !== 'undefined' && !stream.readable) {
1012
+ return done(createError(500, 'stream is not readable', {
1013
+ type: 'stream.not.readable'
1014
+ }))
1015
+ }
1016
+
1017
+ var received = 0;
1018
+ var decoder;
1019
+
1020
+ try {
1021
+ decoder = getDecoder(encoding);
1022
+ } catch (err) {
1023
+ return done(err)
1024
+ }
1025
+
1026
+ var buffer = decoder
1027
+ ? ''
1028
+ : [];
1029
+
1030
+ // attach listeners
1031
+ stream.on('aborted', onAborted);
1032
+ stream.on('close', cleanup);
1033
+ stream.on('data', onData);
1034
+ stream.on('end', onEnd);
1035
+ stream.on('error', onEnd);
1036
+
1037
+ // mark sync section complete
1038
+ sync = false;
1039
+
1040
+ function done () {
1041
+ var args = new Array(arguments.length);
1042
+
1043
+ // copy arguments
1044
+ for (var i = 0; i < args.length; i++) {
1045
+ args[i] = arguments[i];
1046
+ }
1047
+
1048
+ // mark complete
1049
+ complete = true;
1050
+
1051
+ if (sync) {
1052
+ process.nextTick(invokeCallback);
1053
+ } else {
1054
+ invokeCallback();
1055
+ }
1056
+
1057
+ function invokeCallback () {
1058
+ cleanup();
1059
+
1060
+ if (args[0]) {
1061
+ // halt the stream on error
1062
+ halt(stream);
1063
+ }
1064
+
1065
+ callback.apply(null, args);
1066
+ }
1067
+ }
1068
+
1069
+ function onAborted () {
1070
+ if (complete) return
1071
+
1072
+ done(createError(400, 'request aborted', {
1073
+ code: 'ECONNABORTED',
1074
+ expected: length,
1075
+ length: length,
1076
+ received: received,
1077
+ type: 'request.aborted'
1078
+ }));
1079
+ }
1080
+
1081
+ function onData (chunk) {
1082
+ if (complete) return
1083
+
1084
+ received += chunk.length;
1085
+
1086
+ if (limit !== null && received > limit) {
1087
+ done(createError(413, 'request entity too large', {
1088
+ limit: limit,
1089
+ received: received,
1090
+ type: 'entity.too.large'
1091
+ }));
1092
+ } else if (decoder) {
1093
+ buffer += decoder.write(chunk);
1094
+ } else {
1095
+ buffer.push(chunk);
1096
+ }
1097
+ }
1098
+
1099
+ function onEnd (err) {
1100
+ if (complete) return
1101
+ if (err) return done(err)
1102
+
1103
+ if (length !== null && received !== length) {
1104
+ done(createError(400, 'request size did not match content length', {
1105
+ expected: length,
1106
+ length: length,
1107
+ received: received,
1108
+ type: 'request.size.invalid'
1109
+ }));
1110
+ } else {
1111
+ var string = decoder
1112
+ ? buffer + (decoder.end() || '')
1113
+ : Buffer.concat(buffer);
1114
+ done(null, string);
1115
+ }
1116
+ }
1117
+
1118
+ function cleanup () {
1119
+ buffer = null;
1120
+
1121
+ stream.removeListener('aborted', onAborted);
1122
+ stream.removeListener('data', onData);
1123
+ stream.removeListener('end', onEnd);
1124
+ stream.removeListener('error', onEnd);
1125
+ stream.removeListener('close', cleanup);
1126
+ }
1127
+ }
1128
+
1129
+ /**
1130
+ * Try to require async_hooks
1131
+ * @private
1132
+ */
1133
+
1134
+ function tryRequireAsyncHooks () {
1135
+ try {
1136
+ return require('async_hooks')
1137
+ } catch (e) {
1138
+ return {}
1139
+ }
1140
+ }
1141
+
1142
+ /**
1143
+ * Wrap function with async resource, if possible.
1144
+ * AsyncResource.bind static method backported.
1145
+ * @private
1146
+ */
1147
+
1148
+ function wrap (fn) {
1149
+ var res;
1150
+
1151
+ // create anonymous resource
1152
+ if (asyncHooks.AsyncResource) {
1153
+ res = new asyncHooks.AsyncResource(fn.name || 'bound-anonymous-fn');
1154
+ }
1155
+
1156
+ // incompatible node.js
1157
+ if (!res || !res.runInAsyncScope) {
1158
+ return fn
1159
+ }
1160
+
1161
+ // return bound function
1162
+ return res.runInAsyncScope.bind(res, fn, null)
1163
+ }
1164
+
1165
+ var index = /*#__PURE__*/Object.freeze({
1166
+ __proto__: null
1167
+ });
1168
+
1169
+ exports.CONTENT_TYPES = CONTENT_TYPES;
1170
+ exports.HEADER_CONTENT_TYPE = HEADER_CONTENT_TYPE;
1171
+ exports.VerificationError = VerificationError;
1172
+ exports.WebCrypto = WebCrypto;
1173
+ exports.ensureRawBody = ensureRawBody;
1174
+ exports.generateStorableKeyPairs = generateStorableKeyPairs;
1175
+ exports.getRequestMethod = getRequestMethod;
1176
+ exports.getVerificationHelpers = getVerificationHelpers;
1177
+ exports.getVerificationKeysData = getVerificationKeysData;
1178
+ exports.normalizeURIParts = normalizeURIParts;
1179
+ exports.prepareRequestOptions = prepareRequestOptions;
1180
+ exports.prepareVerificationRequest = prepareVerificationRequest;
1181
+ exports.processVerificationResponse = processVerificationResponse;
1182
+
1183
+ Object.defineProperty(exports, '__esModule', { value: true });
1184
+
1185
+ }));
26
1186
  //# sourceMappingURL=index.js.map