hibp 14.1.3 → 15.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/README.md +15 -39
- package/dist/browser/hibp.module.js +2 -2
- package/dist/esm/api/haveibeenpwned/fetch-from-api.d.ts +16 -0
- package/dist/esm/api/haveibeenpwned/fetch-from-api.js +67 -80
- package/dist/esm/api/haveibeenpwned/fetch-from-api.js.map +1 -1
- package/dist/esm/api/haveibeenpwned/package-info.d.ts +2 -0
- package/dist/esm/api/haveibeenpwned/package-info.js +4 -0
- package/dist/esm/api/haveibeenpwned/package-info.js.map +1 -0
- package/dist/esm/api/haveibeenpwned/responses.d.ts +11 -0
- package/dist/esm/api/haveibeenpwned/responses.js +22 -23
- package/dist/esm/api/haveibeenpwned/responses.js.map +1 -1
- package/dist/esm/api/haveibeenpwned/types.d.ts +38 -0
- package/dist/esm/api/haveibeenpwned/types.js +11 -2
- package/dist/esm/api/haveibeenpwned/types.js.map +1 -1
- package/dist/esm/api/pwnedpasswords/fetch-from-api.d.ts +1 -0
- package/dist/esm/api/pwnedpasswords/fetch-from-api.js +19 -33
- package/dist/esm/api/pwnedpasswords/fetch-from-api.js.map +1 -1
- package/dist/esm/api/pwnedpasswords/responses.d.ts +7 -0
- package/dist/esm/api/pwnedpasswords/responses.js +4 -5
- package/dist/esm/api/pwnedpasswords/responses.js.map +1 -1
- package/dist/{cjs/breach.cjs → esm/breach.d.ts} +17 -9
- package/dist/esm/breach.js +3 -5
- package/dist/esm/breach.js.map +1 -1
- package/dist/{cjs/breached-account.cjs → esm/breached-account.d.ts} +34 -34
- package/dist/esm/breached-account.js +20 -30
- package/dist/esm/breached-account.js.map +1 -1
- package/dist/{cjs/breaches.cjs → esm/breaches.d.ts} +21 -24
- package/dist/esm/breaches.js +13 -20
- package/dist/esm/breaches.js.map +1 -1
- package/dist/{cjs/data-classes.cjs → esm/data-classes.d.ts} +16 -9
- package/dist/esm/data-classes.js +3 -5
- package/dist/esm/data-classes.js.map +1 -1
- package/dist/esm/hibp.d.ts +21 -715
- package/dist/esm/hibp.js +23 -11
- package/dist/esm/hibp.js.map +1 -1
- package/dist/{cjs/paste-account.cjs → esm/paste-account.d.ts} +21 -9
- package/dist/esm/paste-account.js +3 -5
- package/dist/esm/paste-account.js.map +1 -1
- package/dist/{cjs/pwned-password-range.cjs → esm/pwned-password-range.d.ts} +26 -30
- package/dist/esm/pwned-password-range.js +18 -26
- package/dist/esm/pwned-password-range.js.map +1 -1
- package/dist/{cjs/pwned-password.cjs → esm/pwned-password.d.ts} +21 -19
- package/dist/esm/pwned-password.js +20 -15
- package/dist/esm/pwned-password.js.map +1 -1
- package/dist/{cjs/search.cjs → esm/search.d.ts} +34 -36
- package/dist/esm/search.js +18 -31
- package/dist/esm/search.js.map +1 -1
- package/dist/{cjs/subscription-status.cjs → esm/subscription-status.d.ts} +21 -10
- package/dist/esm/subscription-status.js +4 -6
- package/dist/esm/subscription-status.js.map +1 -1
- package/package.json +30 -48
- package/dist/browser/hibp.module.js.map +0 -1
- package/dist/browser/hibp.umd.js +0 -2
- package/dist/browser/hibp.umd.js.map +0 -1
- package/dist/cjs/api/fetch-polyfill.cjs +0 -27
- package/dist/cjs/api/fetch-polyfill.cjs.map +0 -1
- package/dist/cjs/api/haveibeenpwned/fetch-from-api.cjs +0 -123
- package/dist/cjs/api/haveibeenpwned/fetch-from-api.cjs.map +0 -1
- package/dist/cjs/api/haveibeenpwned/responses.cjs +0 -63
- package/dist/cjs/api/haveibeenpwned/responses.cjs.map +0 -1
- package/dist/cjs/api/haveibeenpwned/types.cjs +0 -2
- package/dist/cjs/api/haveibeenpwned/types.cjs.map +0 -1
- package/dist/cjs/api/pwnedpasswords/fetch-from-api.cjs +0 -60
- package/dist/cjs/api/pwnedpasswords/fetch-from-api.cjs.map +0 -1
- package/dist/cjs/api/pwnedpasswords/responses.cjs +0 -15
- package/dist/cjs/api/pwnedpasswords/responses.cjs.map +0 -1
- package/dist/cjs/breach.cjs.map +0 -1
- package/dist/cjs/breached-account.cjs.map +0 -1
- package/dist/cjs/breaches.cjs.map +0 -1
- package/dist/cjs/data-classes.cjs.map +0 -1
- package/dist/cjs/hibp.cjs +0 -23
- package/dist/cjs/hibp.cjs.map +0 -1
- package/dist/cjs/hibp.d.cts +0 -717
- package/dist/cjs/package.json.cjs +0 -7
- package/dist/cjs/package.json.cjs.map +0 -1
- package/dist/cjs/paste-account.cjs.map +0 -1
- package/dist/cjs/pwned-password-range.cjs.map +0 -1
- package/dist/cjs/pwned-password.cjs.map +0 -1
- package/dist/cjs/search.cjs.map +0 -1
- package/dist/cjs/subscription-status.cjs.map +0 -1
- package/dist/esm/api/fetch-polyfill.js +0 -25
- package/dist/esm/api/fetch-polyfill.js.map +0 -1
- package/dist/esm/package.json.js +0 -4
- package/dist/esm/package.json.js.map +0 -1
- package/example/runkit.js +0 -15
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 15.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- [#509](https://github.com/wKovacs64/hibp/pull/509) [`e8d4986`](https://github.com/wKovacs64/hibp/commit/e8d498622020fe0c99847f915839ce382bf4d817) Thanks [@wKovacs64](https://github.com/wKovacs64)! - Drop support for Node 18 and remove the CommonJS and UMD builds:
|
|
8
|
+
|
|
9
|
+
- Drop support for Node.js 18 as it is [end-of-life](https://nodejs.org/en/about/releases/), making the new minimum Node.js runtime v20.19.0. Please upgrade your Node.js environment if necessary, or continue using a previous release if you are unable to upgrade your environment.
|
|
10
|
+
|
|
11
|
+
- This also allowed us to drop the `fetch` polyfill that was only necessary in Node 18, which reduced the bundle size by approximately 33%! 📉 The library now officially has **zero dependencies**. 🎉
|
|
12
|
+
|
|
13
|
+
- Remove the CommonJS build since [you can now `require()` ESM as of Node v20.19.0](https://github.com/nodejs/node/releases/tag/v20.19.0). **Consumers in a CommonJS environment should still be able to use the library as before** (given the appropriate Node.js version).
|
|
14
|
+
- Remove the UMD build as all modern browsers support importing ESM via `<script type="module">` tags. See the "[Using in the browser](https://github.com/wKovacs64/hibp?tab=readme-ov-file#using-in-the-browser)" section of the README for more details.
|
|
15
|
+
|
|
16
|
+
### Minor Changes
|
|
17
|
+
|
|
18
|
+
- [#506](https://github.com/wKovacs64/hibp/pull/506) [`56fdf38`](https://github.com/wKovacs64/hibp/commit/56fdf3829846962231b08026d31ef195cde2fdef) Thanks [@wKovacs64](https://github.com/wKovacs64)! - Drop `JSSHA` dependency in favor of a native Web Crypto API SHA-1 hashing implementation. This change reduces the size of the library by approximately 30%! 📉
|
|
19
|
+
|
|
3
20
|
## 14.1.3
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -46,29 +46,19 @@ browser.
|
|
|
46
46
|
- Search for an account in both breaches and pastes at the same time 🔑
|
|
47
47
|
- Get your subscription status 🔑
|
|
48
48
|
- All queries return a Promise
|
|
49
|
-
- Available server-side (Node.js) and client-side (browser)
|
|
49
|
+
- Available server-side (e.g., Node.js) and client-side (browser)
|
|
50
50
|
- Written in TypeScript, so all modules come fully typed
|
|
51
51
|
|
|
52
52
|
## Usage
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
```javascript
|
|
54
|
+
```typescript
|
|
57
55
|
// import individual modules as needed
|
|
58
56
|
import { dataClasses, search } from 'hibp';
|
|
57
|
+
|
|
59
58
|
// or, import all modules into a local namespace
|
|
60
59
|
import * as hibp from 'hibp';
|
|
61
60
|
```
|
|
62
61
|
|
|
63
|
-
##### CommonJS module syntax:
|
|
64
|
-
|
|
65
|
-
```javascript
|
|
66
|
-
// require individual modules as needed
|
|
67
|
-
const { dataClasses, search } = require('hibp');
|
|
68
|
-
// or, require all modules into a local namespace
|
|
69
|
-
const hibp = require('hibp');
|
|
70
|
-
```
|
|
71
|
-
|
|
72
62
|
The following modules are available:
|
|
73
63
|
|
|
74
64
|
- [breach](API.md#breach)
|
|
@@ -104,7 +94,7 @@ async function main() {
|
|
|
104
94
|
}
|
|
105
95
|
}
|
|
106
96
|
|
|
107
|
-
main();
|
|
97
|
+
void main();
|
|
108
98
|
```
|
|
109
99
|
|
|
110
100
|
#### Rate Limiting
|
|
@@ -117,35 +107,22 @@ happen).
|
|
|
117
107
|
|
|
118
108
|
#### Using in the browser
|
|
119
109
|
|
|
120
|
-
You have
|
|
110
|
+
You have a couple of options for using this library in a browser environment:
|
|
121
111
|
|
|
122
112
|
1. Bundled
|
|
123
113
|
|
|
124
114
|
The most efficient and recommended method is to bundle it with client-side code using a module
|
|
125
|
-
bundler
|
|
126
|
-
hood.
|
|
127
|
-
|
|
128
|
-
1. UMD
|
|
129
|
-
|
|
130
|
-
There is also a Universal Module Definition (UMD) build provided for usage in the browser. When
|
|
131
|
-
using this build, an `hibp` object will be added to the browser's `window` object.
|
|
132
|
-
|
|
133
|
-
The recommended way to include the UMD build (when using a `<script>` tag) is to use the
|
|
134
|
-
[unpkg][unpkg] CDN, specifying the exact version you want. If you don't specify a version, the
|
|
135
|
-
`latest` tag will be used, which could be dangerous if/when there are breaking changes made to
|
|
136
|
-
the API. See [unpkg][unpkg] for details and advanced version specification, but generally you
|
|
137
|
-
will want to do the following (replacing `x.y.z` with the version you want):
|
|
138
|
-
|
|
139
|
-
```html
|
|
140
|
-
<script src="https://unpkg.com/hibp@x.y.z"></script>
|
|
141
|
-
```
|
|
115
|
+
bundler, most likely dictated by your web application framework of choice.
|
|
142
116
|
|
|
143
117
|
1. ESM for Browsers
|
|
144
118
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
[unpkg][unpkg] CDN
|
|
148
|
-
|
|
119
|
+
Alternatively, you can also import the library directly in your HTML via `<script type="module">`
|
|
120
|
+
tags in [modern browsers][caniuse-esm]. The pre-bundled module is available through the
|
|
121
|
+
[unpkg][unpkg] CDN, but you must specify the full path (including the file extension). It's also
|
|
122
|
+
strongly recommended to include the exact version number as well, otherwise the `latest` tag will
|
|
123
|
+
be used, which could be dangerous if/when there are breaking changes made to the API. See
|
|
124
|
+
[unpkg][unpkg] for details and advanced version specification, but you will probably want to do
|
|
125
|
+
the following (replacing `x.y.z` with the version you want):
|
|
149
126
|
|
|
150
127
|
```html
|
|
151
128
|
<script type="module">
|
|
@@ -165,7 +142,7 @@ You have several options for using this library in a browser environment:
|
|
|
165
142
|
|
|
166
143
|
## Try It Out
|
|
167
144
|
|
|
168
|
-
[Test hibp in your browser with
|
|
145
|
+
[Test hibp in your browser with StackBlitz.][stackblitz]
|
|
169
146
|
|
|
170
147
|
## Projects Using hibp
|
|
171
148
|
|
|
@@ -203,8 +180,7 @@ This module is distributed under the [MIT License][license].
|
|
|
203
180
|
[unpkg]: https://unpkg.com
|
|
204
181
|
[caniuse-esm]: https://caniuse.com/#feat=es6-module
|
|
205
182
|
[js-modules]: https://v8.dev/features/modules#browser
|
|
206
|
-
[
|
|
207
|
-
[runkit]: https://runkit.com/npm/hibp
|
|
183
|
+
[stackblitz]: https://stackblitz.com/edit/stackblitz-starters-atyrc52c?file=index.js
|
|
208
184
|
[pwned]: https://github.com/wKovacs64/pwned
|
|
209
185
|
[pulls]: https://github.com/wKovacs64/hibp/pulls
|
|
210
186
|
[pwl]: https://pwl.netlify.com/
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function t(){if("undefined"!=typeof process&&process.versions?.node?.startsWith("18.")){const{File:t,fetch:e,FormData:n,Headers:r,Request:s,Response:o}=require("undici");global.File=t,global.Headers=r,global.Request=s,global.Response=o,global.fetch=e,global.FormData=n}}const e={status:400,statusText:"Bad request — the account does not comply with an acceptable format."},n={status:401,body:'Your request to the API couldn\'t be authorised. Check you have the right value in the "hibp-api-key" header, refer to the documentation for more: https://haveibeenpwned.com/API/v3#Authorisation'},r={status:403,statusText:"Forbidden - access denied."},s={status:404},o={headers:new Map([["retry-after","2"]]),status:429,body:{statusCode:429,message:"Rate limit is exceeded. Try again in 2 seconds."}};t();class i extends Error{retryAfterSeconds;constructor(t,e,n){super(e,n),this.name=this.constructor.name,this.retryAfterSeconds="string"==typeof t?Number.parseInt(t,10):void 0}}async function u(t,u={}){const{apiKey:a,baseUrl:h="https://haveibeenpwned.com/api/v3",timeoutMs:c,userAgent:f}=u,l={};if(a&&(l["HIBP-API-Key"]=a),f&&(l["User-Agent"]=f),!f&&"undefined"==typeof navigator){const{name:t,version:e}=await Promise.resolve().then((function(){return S}));l["User-Agent"]=`${t} ${e}`}const d={headers:l,...c?{signal:AbortSignal.timeout(c)}:{}},p=`${h.replace(/\/$/g,"")}${t}`,m=await fetch(p,d);if(m.ok)return m.json();switch(m.status){case e.status:throw Error(e.statusText);case n.status:{const t=await m.text();throw Error(t)}case r.status:{const t=m.headers.get("cf-ray");if(t)throw Error(function(t){return`Request blocked, contact haveibeenpwned.com if this continues (Ray ID: ${t})`}(t));throw Error(r.statusText)}case s.status:return null;case o.status:{const t=await m.json(),e=m.headers.get("retry-after");throw new i(e,t.message)}default:throw Error(m.statusText)}}function a(t,e={}){return u("/breach/"+encodeURIComponent(t),e)}function h(t,e={}){const{apiKey:n,domain:r,includeUnverified:s=!0,timeoutMs:o,truncate:i=!0,baseUrl:a,userAgent:h}=e,c=`/breachedaccount/${encodeURIComponent(t)}?`,f=[];return r&&f.push("domain="+encodeURIComponent(r)),s||f.push("includeUnverified=false"),i||f.push("truncateResponse=false"),u(`${c}${f.join("&")}`,{apiKey:n,baseUrl:a,timeoutMs:o,userAgent:h})}function c(t={}){const{domain:e,baseUrl:n,timeoutMs:r,userAgent:s}=t,o=[];return e&&o.push("domain="+encodeURIComponent(e)),u("/breaches?"+o.join("&"),{baseUrl:n,timeoutMs:r,userAgent:s})}function f(t={}){return u("/dataclasses",t)}function l(t,e={}){return u("/pasteaccount/"+encodeURIComponent(t),e)}const d="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",p="ARRAYBUFFER not supported by this environment",m="UINT8ARRAY not supported by this environment";function g(t,e,n,r){let s,o,i;const u=e||[0],a=(n=n||0)>>>3,h=-1===r?3:0;for(s=0;t.length>s;s+=1)i=s+a,o=i>>>2,o>=u.length&&u.push(0),u[o]|=t[s]<<8*(h+r*(i%4));return{value:u,binLen:8*t.length+n}}function A(t,e,n){switch(e){case"UTF8":case"UTF16BE":case"UTF16LE":break;default:throw Error("encoding must be UTF8, UTF16BE, or UTF16LE")}switch(t){case"HEX":return function(t,e,r){return function(t,e,n,r){let s,o,i,u;if(0!=t.length%2)throw Error("String of HEX type must be in byte increments");const a=e||[0],h=(n=n||0)>>>3,c=-1===r?3:0;for(s=0;t.length>s;s+=2){if(o=parseInt(t.substr(s,2),16),isNaN(o))throw Error("String of HEX type contains invalid characters");for(u=(s>>>1)+h,i=u>>>2;i>=a.length;)a.push(0);a[i]|=o<<8*(c+r*(u%4))}return{value:a,binLen:4*t.length+n}}(t,e,r,n)};case"TEXT":return function(t,r,s){return function(t,e,n,r,s){let o,i,u,a,h,c,f,l,d=0;const p=n||[0],m=(r=r||0)>>>3;if("UTF8"===e)for(f=-1===s?3:0,u=0;t.length>u;u+=1)for(o=t.charCodeAt(u),i=[],128>o?i.push(o):2048>o?(i.push(192|o>>>6),i.push(128|63&o)):55296>o||o>=57344?i.push(224|o>>>12,128|o>>>6&63,128|63&o):(u+=1,o=65536+((1023&o)<<10|1023&t.charCodeAt(u)),i.push(240|o>>>18,128|o>>>12&63,128|o>>>6&63,128|63&o)),a=0;i.length>a;a+=1){for(c=d+m,h=c>>>2;h>=p.length;)p.push(0);p[h]|=i[a]<<8*(f+s*(c%4)),d+=1}else for(f=-1===s?2:0,l="UTF16LE"===e&&1!==s||"UTF16LE"!==e&&1===s,u=0;t.length>u;u+=1){for(o=t.charCodeAt(u),!0===l&&(a=255&o,o=a<<8|o>>>8),c=d+m,h=c>>>2;h>=p.length;)p.push(0);p[h]|=o<<8*(f+s*(c%4)),d+=2}return{value:p,binLen:8*d+r}}(t,e,r,s,n)};case"B64":return function(t,e,r){return function(t,e,n,r){let s,o,i,u,a,h,c,f=0;const l=e||[0],p=(n=n||0)>>>3,m=-1===r?3:0,g=t.indexOf("=");if(-1===t.search(/^[a-zA-Z0-9=+/]+$/))throw Error("Invalid character in base-64 string");if(t=t.replace(/=/g,""),-1!==g&&t.length>g)throw Error("Invalid '=' found in base-64 string");for(o=0;t.length>o;o+=4){for(a=t.substr(o,4),u=0,i=0;a.length>i;i+=1)s=d.indexOf(a.charAt(i)),u|=s<<18-6*i;for(i=0;a.length-1>i;i+=1){for(c=f+p,h=c>>>2;h>=l.length;)l.push(0);l[h]|=(u>>>16-8*i&255)<<8*(m+r*(c%4)),f+=1}}return{value:l,binLen:8*f+n}}(t,e,r,n)};case"BYTES":return function(t,e,r){return function(t,e,n,r){let s,o,i,u;const a=e||[0],h=(n=n||0)>>>3,c=-1===r?3:0;for(o=0;t.length>o;o+=1)s=t.charCodeAt(o),u=o+h,i=u>>>2,i>=a.length&&a.push(0),a[i]|=s<<8*(c+r*(u%4));return{value:a,binLen:8*t.length+n}}(t,e,r,n)};case"ARRAYBUFFER":try{new ArrayBuffer(0)}catch(t){throw Error(p)}return function(t,e,r){return function(t,e,n,r){return g(new Uint8Array(t),e,n,r)}(t,e,r,n)};case"UINT8ARRAY":try{new Uint8Array(0)}catch(t){throw Error(m)}return function(t,e,r){return g(t,e,r,n)};default:throw Error("format must be HEX, TEXT, B64, BYTES, ARRAYBUFFER, or UINT8ARRAY")}}function b(t,e,n,r){switch(t){case"HEX":return function(t){return function(t,e,n,r){const s="0123456789abcdef";let o,i,u="";const a=e/8,h=-1===n?3:0;for(o=0;a>o;o+=1)i=t[o>>>2]>>>8*(h+n*(o%4)),u+=s.charAt(i>>>4&15)+s.charAt(15&i);return r.outputUpper?u.toUpperCase():u}(t,e,n,r)};case"B64":return function(t){return function(t,e,n,r){let s,o,i,u,a,h="";const c=e/8,f=-1===n?3:0;for(s=0;c>s;s+=3)for(u=c>s+1?t[s+1>>>2]:0,a=c>s+2?t[s+2>>>2]:0,i=(t[s>>>2]>>>8*(f+n*(s%4))&255)<<16|(u>>>8*(f+n*((s+1)%4))&255)<<8|a>>>8*(f+n*((s+2)%4))&255,o=0;4>o;o+=1)h+=8*s+6*o>e?r.b64Pad:d.charAt(i>>>6*(3-o)&63);return h}(t,e,n,r)};case"BYTES":return function(t){return function(t,e,n){let r,s,o="";const i=e/8,u=-1===n?3:0;for(r=0;i>r;r+=1)s=t[r>>>2]>>>8*(u+n*(r%4))&255,o+=String.fromCharCode(s);return o}(t,e,n)};case"ARRAYBUFFER":try{new ArrayBuffer(0)}catch(t){throw Error(p)}return function(t){return function(t,e,n){let r;const s=e/8,o=new ArrayBuffer(s),i=new Uint8Array(o),u=-1===n?3:0;for(r=0;s>r;r+=1)i[r]=t[r>>>2]>>>8*(u+n*(r%4))&255;return o}(t,e,n)};case"UINT8ARRAY":try{new Uint8Array(0)}catch(t){throw Error(m)}return function(t){return function(t,e,n){let r;const s=e/8,o=-1===n?3:0,i=new Uint8Array(s);for(r=0;s>r;r+=1)i[r]=t[r>>>2]>>>8*(o+n*(r%4))&255;return i}(t,e,n)};default:throw Error("format must be HEX, B64, BYTES, ARRAYBUFFER, or UINT8ARRAY")}}function w(t){const e={outputUpper:!1,b64Pad:"=",outputLen:-1},n=t||{},r="Output length must be a multiple of 8";if(e.outputUpper=n.outputUpper||!1,n.b64Pad&&(e.b64Pad=n.b64Pad),n.outputLen){if(n.outputLen%8!=0)throw Error(r);e.outputLen=n.outputLen}else if(n.shakeLen){if(n.shakeLen%8!=0)throw Error(r);e.outputLen=n.shakeLen}if("boolean"!=typeof e.outputUpper)throw Error("Invalid outputUpper formatting option");if("string"!=typeof e.b64Pad)throw Error("Invalid b64Pad formatting option");return e}class U{constructor(t,e,n){const r=n||{};if(this.t=e,this.i=r.encoding||"UTF8",this.numRounds=r.numRounds||1,isNaN(this.numRounds)||this.numRounds!==parseInt(this.numRounds,10)||1>this.numRounds)throw Error("numRounds must a integer >= 1");this.o=t,this.h=[],this.u=0,this.l=!1,this.A=0,this.p=!1,this.U=[],this.R=[]}update(t){let e,n=0;const r=this.T>>>5,s=this.F(t,this.h,this.u),o=s.binLen,i=s.value,u=o>>>5;for(e=0;u>e;e+=r)o>=n+this.T&&(this.m=this.g(i.slice(e,e+r),this.m),n+=this.T);return this.A+=n,this.h=i.slice(n>>>5),this.u=o%this.T,this.l=!0,this}getHash(t,e){let n,r,s=this.B;const o=w(e);if(this.v){if(-1===o.outputLen)throw Error("Output length must be specified in options");s=o.outputLen}const i=b(t,s,this.H,o);if(this.p&&this.C)return i(this.C(o));for(r=this.Y(this.h.slice(),this.u,this.A,this.I(this.m),s),n=1;this.numRounds>n;n+=1)this.v&&s%32!=0&&(r[r.length-1]&=16777215>>>24-s%32),r=this.Y(r,s,0,this.L(this.o),s);return i(r)}setHMACKey(t,e,n){if(!this.M)throw Error("Variant does not support HMAC");if(this.l)throw Error("Cannot set MAC key after calling update");const r=A(e,(n||{}).encoding||"UTF8",this.H);this.N(r(t))}N(t){const e=this.T>>>3,n=e/4-1;let r;if(1!==this.numRounds)throw Error("Cannot set numRounds with MAC");if(this.p)throw Error("MAC key already set");for(t.binLen/8>e&&(t.value=this.Y(t.value,t.binLen,0,this.L(this.o),this.B));n>=t.value.length;)t.value.push(0);for(r=0;n>=r;r+=1)this.U[r]=909522486^t.value[r],this.R[r]=1549556828^t.value[r];this.m=this.g(this.U,this.m),this.A=this.T,this.p=!0}getHMAC(t,e){const n=w(e);return b(t,this.B,this.H,n)(this.S())}S(){let t;if(!this.p)throw Error("Cannot call getHMAC without first setting MAC key");const e=this.Y(this.h.slice(),this.u,this.A,this.I(this.m),this.B);return t=this.g(this.R,this.L(this.o)),t=this.Y(e,this.B,this.T,t,this.B),t}}function E(t,e){return t<<e|t>>>32-e}function y(t,e,n){return t^e^n}function R(t,e,n){return t&e^t&n^e&n}function v(t,e){const n=(65535&t)+(65535&e);return(65535&(t>>>16)+(e>>>16)+(n>>>16))<<16|65535&n}function T(t,e,n,r,s){const o=(65535&t)+(65535&e)+(65535&n)+(65535&r)+(65535&s);return(65535&(t>>>16)+(e>>>16)+(n>>>16)+(r>>>16)+(s>>>16)+(o>>>16))<<16|65535&o}function C(t){return[1732584193,4023233417,2562383102,271733878,3285377520]}function F(t,e){let n,r,s,o,i,u,a;const h=[];for(n=e[0],r=e[1],s=e[2],o=e[3],i=e[4],a=0;80>a;a+=1)h[a]=16>a?t[a]:E(h[a-3]^h[a-8]^h[a-14]^h[a-16],1),u=20>a?T(E(n,5),(c=r)&s^~c&o,i,1518500249,h[a]):40>a?T(E(n,5),y(r,s,o),i,1859775393,h[a]):60>a?T(E(n,5),R(r,s,o),i,2400959708,h[a]):T(E(n,5),y(r,s,o),i,3395469782,h[a]),i=o,o=s,s=E(r,30),r=n,n=u;var c;return e[0]=v(n,e[0]),e[1]=v(r,e[1]),e[2]=v(s,e[2]),e[3]=v(o,e[3]),e[4]=v(i,e[4]),e}function B(t,e,n,r){let s;const o=15+(e+65>>>9<<4),i=e+n;for(;o>=t.length;)t.push(0);for(t[e>>>5]|=128<<24-e%32,t[o]=4294967295&i,t[o-1]=i/4294967296|0,s=0;t.length>s;s+=16)r=F(t.slice(s,s+16),r);return r}class I extends U{constructor(t,e,n){if("SHA-1"!==t)throw Error("Chosen SHA variant is not supported");super(t,e,n);const r=n||{};this.M=!0,this.C=this.S,this.H=-1,this.F=A(this.t,this.i,this.H),this.g=F,this.I=function(t){return t.slice()},this.L=C,this.Y=B,this.m=[1732584193,4023233417,2562383102,271733878,3285377520],this.T=512,this.B=160,this.v=!1,r.hmacKey&&this.N(function(t,e,n,r){const s="hmacKey must include a value and format";if(!e)throw Error(s);if(void 0===e.value||!e.format)throw Error(s);return A(e.format,e.encoding||"UTF8",n)(e.value)}(0,r.hmacKey,this.H))}}const L={status:400,body:"The hash prefix was not in a valid format"};async function H(t,e={}){const{baseUrl:n,timeoutMs:r,userAgent:s,addPadding:o=!1,mode:i="sha1"}=e,u=await async function(t,e={}){const{baseUrl:n="https://api.pwnedpasswords.com",timeoutMs:r,userAgent:s,addPadding:o=!1,mode:i="sha1"}=e,u={headers:{...s?{"User-Agent":s}:{},...o?{"Add-Padding":"true"}:{}},...r?{signal:AbortSignal.timeout(r)}:{}},a=`${n.replace(/\/$/g,"")}${t}?mode=${i}`,h=await fetch(a,u);if(h.ok)return h.text();if(h.status===L.status){const t=await h.text();throw Error(t)}throw Error(h.statusText)}("/range/"+encodeURIComponent(t),{baseUrl:n,timeoutMs:r,userAgent:s,addPadding:o,mode:i});return u.split("\n").filter(Boolean).reduce(((t,e)=>{const[n,r]=e.split(":");return t[n]=Number.parseInt(r,10),t}),{})}async function M(t,e={}){const n=new I("SHA-1","TEXT");n.update(t);const r=n.getHash("HEX",{outputUpper:!0}),s=r.slice(0,5),o=r.slice(5);return(await H(s,e))[o]||0}async function Y(t,e={}){const{apiKey:n,domain:r,truncate:s=!0,baseUrl:o,timeoutMs:i,userAgent:u}=e,[a,c]=await Promise.all([h(t,{apiKey:n,domain:r,truncate:s,baseUrl:o,timeoutMs:i,userAgent:u}),/^.+@.+$/.test(t)?l(t,{apiKey:n,baseUrl:o,timeoutMs:i,userAgent:u}):null]);return{breaches:a,pastes:c}}async function P(t={}){return u("/subscription/status",t)}t();var S=Object.freeze({__proto__:null,name:"hibp",version:"14.1.3"});export{i as RateLimitError,a as breach,h as breachedAccount,c as breaches,f as dataClasses,l as pasteAccount,M as pwnedPassword,H as pwnedPasswordRange,Y as search,P as subscriptionStatus};
|
|
2
|
-
|
|
1
|
+
var w="hibp",y="15.0.0";var h={status:400,statusText:"Bad request \u2014 the account does not comply with an acceptable format."},P={status:401,body:`Your request to the API couldn't be authorised. Check you have the right value in the "hibp-api-key" header, refer to the documentation for more: https://haveibeenpwned.com/API/v3#Authorisation`},g={status:403,statusText:"Forbidden - access denied."};var x={status:404},U={headers:new Map([["retry-after","2"]]),status:429,body:{statusCode:429,message:"Rate limit is exceeded. Try again in 2 seconds."}};var d=class extends Error{retryAfterSeconds;constructor(t,r,n){super(r,n),this.name=this.constructor.name,this.retryAfterSeconds=typeof t=="string"?Number.parseInt(t,10):void 0}};function I(e){return`Request blocked, contact haveibeenpwned.com if this continues (Ray ID: ${e})`}async function u(e,t={}){let{apiKey:r,baseUrl:n="https://haveibeenpwned.com/api/v3",timeoutMs:o,userAgent:a}=t,i={};r&&(i["HIBP-API-Key"]=r),a&&(i["User-Agent"]=a),!a&&typeof navigator>"u"&&(i["User-Agent"]=`${w} ${y}`);let p={headers:i,...o?{signal:AbortSignal.timeout(o)}:{}},m=`${n.replace(/\/$/g,"")}${e}`,s=await fetch(m,p);if(s.ok)return s.json();switch(s.status){case h.status:throw new Error(h.statusText);case P.status:{let c=await s.text();throw new Error(c)}case g.status:{let c=s.headers.get("cf-ray");throw c?new Error(I(c)):new Error(g.statusText)}case x.status:return null;case U.status:{let c=await s.json(),f=s.headers.get("retry-after");throw new d(f,c.message)}default:throw new Error(s.statusText)}}function B(e,t={}){return u(`/breach/${encodeURIComponent(e)}`,t)}function l(e,t={}){let{apiKey:r,domain:n,includeUnverified:o=!0,timeoutMs:a,truncate:i=!0,baseUrl:p,userAgent:m}=t,s=`/breachedaccount/${encodeURIComponent(e)}?`,c=[];return n&&c.push(`domain=${encodeURIComponent(n)}`),o||c.push("includeUnverified=false"),i||c.push("truncateResponse=false"),u(`${s}${c.join("&")}`,{apiKey:r,baseUrl:p,timeoutMs:a,userAgent:m})}function M(e={}){let{domain:t,baseUrl:r,timeoutMs:n,userAgent:o}=e,a="/breaches?",i=[];return t&&i.push(`domain=${encodeURIComponent(t)}`),u(`${a}${i.join("&")}`,{baseUrl:r,timeoutMs:n,userAgent:o})}function T(e={}){return u("/dataclasses",e)}function b(e,t={}){return u(`/pasteaccount/${encodeURIComponent(e)}`,t)}var E={status:400,body:"The hash prefix was not in a valid format"};async function R(e,t={}){let{baseUrl:r="https://api.pwnedpasswords.com",timeoutMs:n,userAgent:o,addPadding:a=!1,mode:i="sha1"}=t,p={headers:{...o?{"User-Agent":o}:{},...a?{"Add-Padding":"true"}:{}},...n?{signal:AbortSignal.timeout(n)}:{}},m=`${r.replace(/\/$/g,"")}${e}?mode=${i}`,s=await fetch(m,p);if(s.ok)return s.text();if(s.status===E.status){let c=await s.text();throw new Error(c)}throw new Error(s.statusText)}async function A(e,t={}){let{baseUrl:r,timeoutMs:n,userAgent:o,addPadding:a=!1,mode:i="sha1"}=t;return(await R(`/range/${encodeURIComponent(e)}`,{baseUrl:r,timeoutMs:n,userAgent:o,addPadding:a,mode:i})).split(`
|
|
2
|
+
`).filter(Boolean).reduce((s,c)=>{let[f,S]=c.split(":");return s[f]=Number.parseInt(S,10),s},{})}async function D(e,t={}){let[r,n]=await $(e);return(await A(r,t))[n]||0}async function $(e){if(typeof crypto=="object"&&crypto.subtle){let t=new TextEncoder().encode(e),r=await crypto.subtle.digest("SHA-1",t),o=Array.from(new Uint8Array(r)).map(a=>a.toString(16).padStart(2,"0")).join("").toUpperCase();return[o.slice(0,5),o.slice(5)]}throw new Error("The Web Crypto API is not available in this environment.")}async function v(e,t={}){let{apiKey:r,domain:n,truncate:o=!0,baseUrl:a,timeoutMs:i,userAgent:p}=t,[m,s]=await Promise.all([l(e,{apiKey:r,domain:n,truncate:o,baseUrl:a,timeoutMs:i,userAgent:p}),/^.+@.+$/.test(e)?b(e,{apiKey:r,baseUrl:a,timeoutMs:i,userAgent:p}):null]);return{breaches:m,pastes:s}}async function C(e={}){return u("/subscription/status",e)}export{d as RateLimitError,B as breach,l as breachedAccount,M as breaches,T as dataClasses,b as pasteAccount,D as pwnedPassword,A as pwnedPasswordRange,v as search,C as subscriptionStatus};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error thrown when the haveibeenpwned.com API responds with 429 Too
|
|
3
|
+
* Many Requests. See the `retryAfterSeconds` property for the number of seconds
|
|
4
|
+
* to wait before attempting the request again.
|
|
5
|
+
*
|
|
6
|
+
* @see https://haveibeenpwned.com/API/v3#RateLimiting
|
|
7
|
+
*/
|
|
8
|
+
export declare class RateLimitError extends Error {
|
|
9
|
+
/**
|
|
10
|
+
* The number of seconds to wait before attempting the request again. May be
|
|
11
|
+
* `undefined` if the API does not provide a `retry-after` header, but this
|
|
12
|
+
* should never happen.
|
|
13
|
+
*/
|
|
14
|
+
retryAfterSeconds: number | undefined;
|
|
15
|
+
constructor(retryAfter: ReturnType<Headers['get']>, message: string | undefined, options?: ErrorOptions);
|
|
16
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
// @ts-ignore - package-info.js is generated and may not exist yet
|
|
2
|
+
import { PACKAGE_NAME, PACKAGE_VERSION } from './package-info.js';
|
|
3
|
+
import { BAD_REQUEST, UNAUTHORIZED, FORBIDDEN, NOT_FOUND, TOO_MANY_REQUESTS } from './responses.js';
|
|
4
4
|
/**
|
|
5
5
|
* Custom error thrown when the haveibeenpwned.com API responds with 429 Too
|
|
6
6
|
* Many Requests. See the `retryAfterSeconds` property for the number of seconds
|
|
@@ -8,21 +8,24 @@ installUndiciOnNode18();
|
|
|
8
8
|
*
|
|
9
9
|
* @see https://haveibeenpwned.com/API/v3#RateLimiting
|
|
10
10
|
*/
|
|
11
|
-
class RateLimitError extends Error {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
11
|
+
export class RateLimitError extends Error {
|
|
12
|
+
/**
|
|
13
|
+
* The number of seconds to wait before attempting the request again. May be
|
|
14
|
+
* `undefined` if the API does not provide a `retry-after` header, but this
|
|
15
|
+
* should never happen.
|
|
16
|
+
*/
|
|
17
|
+
retryAfterSeconds;
|
|
18
|
+
constructor(retryAfter, message, options) {
|
|
19
|
+
super(message, options);
|
|
20
|
+
this.name = this.constructor.name;
|
|
21
|
+
this.retryAfterSeconds =
|
|
22
|
+
typeof retryAfter === 'string'
|
|
23
|
+
? Number.parseInt(retryAfter, 10) /* c8 ignore start */
|
|
24
|
+
: undefined; /* c8 ignore stop */
|
|
25
|
+
}
|
|
23
26
|
}
|
|
24
27
|
function blockedWithRayId(rayId) {
|
|
25
|
-
|
|
28
|
+
return `Request blocked, contact haveibeenpwned.com if this continues (Ray ID: ${rayId})`;
|
|
26
29
|
}
|
|
27
30
|
/**
|
|
28
31
|
* Fetches data from the supplied API endpoint.
|
|
@@ -51,68 +54,52 @@ function blockedWithRayId(rayId) {
|
|
|
51
54
|
* from the query (or null for 404 Not Found responses), or rejects with an
|
|
52
55
|
* Error
|
|
53
56
|
*/
|
|
54
|
-
async function fetchFromApi(endpoint, options = {}) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
case NOT_FOUND.status:
|
|
102
|
-
{
|
|
103
|
-
return null;
|
|
104
|
-
}
|
|
105
|
-
case TOO_MANY_REQUESTS.status:
|
|
106
|
-
{
|
|
107
|
-
const body = await response.json();
|
|
108
|
-
const retryAfter = response.headers.get('retry-after');
|
|
109
|
-
throw new RateLimitError(retryAfter, body.message);
|
|
110
|
-
}
|
|
111
|
-
default:
|
|
112
|
-
{
|
|
113
|
-
throw new Error(response.statusText);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
57
|
+
export async function fetchFromApi(endpoint, options = {}) {
|
|
58
|
+
const { apiKey, baseUrl = 'https://haveibeenpwned.com/api/v3', timeoutMs, userAgent } = options;
|
|
59
|
+
const headers = {};
|
|
60
|
+
if (apiKey) {
|
|
61
|
+
headers['HIBP-API-Key'] = apiKey;
|
|
62
|
+
}
|
|
63
|
+
if (userAgent) {
|
|
64
|
+
headers['User-Agent'] = userAgent;
|
|
65
|
+
}
|
|
66
|
+
// Provide a default User-Agent when running outside the browser
|
|
67
|
+
if (!userAgent && typeof navigator === 'undefined') {
|
|
68
|
+
headers['User-Agent'] = `${PACKAGE_NAME} ${PACKAGE_VERSION}`;
|
|
69
|
+
}
|
|
70
|
+
const config = {
|
|
71
|
+
headers,
|
|
72
|
+
...(timeoutMs ? { signal: AbortSignal.timeout(timeoutMs) } : {}),
|
|
73
|
+
};
|
|
74
|
+
const url = `${baseUrl.replace(/\/$/g, '')}${endpoint}`;
|
|
75
|
+
const response = await fetch(url, config);
|
|
76
|
+
if (response.ok)
|
|
77
|
+
return response.json();
|
|
78
|
+
switch (response.status) {
|
|
79
|
+
case BAD_REQUEST.status: {
|
|
80
|
+
throw new Error(BAD_REQUEST.statusText);
|
|
81
|
+
}
|
|
82
|
+
case UNAUTHORIZED.status: {
|
|
83
|
+
const message = await response.text();
|
|
84
|
+
throw new Error(message);
|
|
85
|
+
}
|
|
86
|
+
case FORBIDDEN.status: {
|
|
87
|
+
const rayId = response.headers.get('cf-ray');
|
|
88
|
+
if (rayId)
|
|
89
|
+
throw new Error(blockedWithRayId(rayId));
|
|
90
|
+
throw new Error(FORBIDDEN.statusText);
|
|
91
|
+
}
|
|
92
|
+
case NOT_FOUND.status: {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
case TOO_MANY_REQUESTS.status: {
|
|
96
|
+
const body = (await response.json());
|
|
97
|
+
const retryAfter = response.headers.get('retry-after');
|
|
98
|
+
throw new RateLimitError(retryAfter, body.message);
|
|
99
|
+
}
|
|
100
|
+
default: {
|
|
101
|
+
throw new Error(response.statusText);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
116
104
|
}
|
|
117
|
-
|
|
118
|
-
//# sourceMappingURL=fetch-from-api.js.map
|
|
105
|
+
//# sourceMappingURL=fetch-from-api.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-from-api.js","sources":["../../../../src/api/haveibeenpwned/fetch-from-api.ts"],"
|
|
1
|
+
{"version":3,"file":"fetch-from-api.js","sourceRoot":"","sources":["../../../../src/api/haveibeenpwned/fetch-from-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-info.js","sourceRoot":"","sources":["../../../../src/api/haveibeenpwned/package-info.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC;AACnC,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Known potential responses from the remote API.
|
|
3
|
+
*
|
|
4
|
+
* Unfortunately, the API does not send a decent human-readable message back with each response, but
|
|
5
|
+
* they are documented on the website: https://haveibeenpwned.com/api/v3#ResponseCodes
|
|
6
|
+
*
|
|
7
|
+
* These objects simply provide a mapping between the HTTP response status code and the
|
|
8
|
+
* corresponding human-readable message so we can throw a more descriptive error for the consumer.
|
|
9
|
+
* (They are also leveraged in our tests.)
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
* (They are also leveraged in our tests.)
|
|
10
10
|
*/
|
|
11
11
|
/** @internal */
|
|
12
|
-
const BAD_REQUEST = {
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
export const BAD_REQUEST = {
|
|
13
|
+
status: 400,
|
|
14
|
+
statusText: 'Bad request — the account does not comply with an acceptable format.',
|
|
15
15
|
};
|
|
16
16
|
/**
|
|
17
17
|
* The API includes a human-readable error message as text in the body of this
|
|
@@ -19,23 +19,23 @@ const BAD_REQUEST = {
|
|
|
19
19
|
*
|
|
20
20
|
* @internal
|
|
21
21
|
*/
|
|
22
|
-
const UNAUTHORIZED = {
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
export const UNAUTHORIZED = {
|
|
23
|
+
status: 401,
|
|
24
|
+
body: `Your request to the API couldn't be authorised. Check you have the right value in the "hibp-api-key" header, refer to the documentation for more: https://haveibeenpwned.com/API/v3#Authorisation`,
|
|
25
25
|
};
|
|
26
26
|
/** @internal */
|
|
27
|
-
const FORBIDDEN = {
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
export const FORBIDDEN = {
|
|
28
|
+
status: 403,
|
|
29
|
+
statusText: 'Forbidden - access denied.',
|
|
30
30
|
};
|
|
31
31
|
/** @internal */
|
|
32
|
-
const BLOCKED = {
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
export const BLOCKED = {
|
|
33
|
+
headers: new Map([['cf-ray', 'someRayId']]),
|
|
34
|
+
status: 403,
|
|
35
35
|
};
|
|
36
36
|
/** @internal */
|
|
37
|
-
const NOT_FOUND = {
|
|
38
|
-
|
|
37
|
+
export const NOT_FOUND = {
|
|
38
|
+
status: 404,
|
|
39
39
|
};
|
|
40
40
|
/**
|
|
41
41
|
* The API includes a JSON object containing a human-readable message in the
|
|
@@ -44,13 +44,12 @@ const NOT_FOUND = {
|
|
|
44
44
|
*
|
|
45
45
|
* @internal
|
|
46
46
|
*/
|
|
47
|
-
const TOO_MANY_REQUESTS = {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
47
|
+
export const TOO_MANY_REQUESTS = {
|
|
48
|
+
headers: new Map([['retry-after', '2']]),
|
|
49
|
+
status: 429,
|
|
50
|
+
body: {
|
|
51
|
+
statusCode: 429,
|
|
52
|
+
message: 'Rate limit is exceeded. Try again in 2 seconds.',
|
|
53
|
+
},
|
|
54
54
|
};
|
|
55
|
-
|
|
56
|
-
//# sourceMappingURL=responses.js.map
|
|
55
|
+
//# sourceMappingURL=responses.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"responses.js","
|
|
1
|
+
{"version":3,"file":"responses.js","sourceRoot":"","sources":["../../../../src/api/haveibeenpwned/responses.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,gBAAgB;AAChB,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,MAAM,EAAE,GAAY;IACpB,UAAU,EAAE,sEAAsE;CACnF,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,MAAM,EAAE,GAAY;IACpB,IAAI,EAAE,mMAAmM;CAC1M,CAAC;AAEF,gBAAgB;AAChB,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,MAAM,EAAE,GAAY;IACpB,UAAU,EAAE,4BAA4B;CACzC,CAAC;AAEF,gBAAgB;AAChB,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,OAAO,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC;IAC3C,MAAM,EAAE,GAAY;CACrB,CAAC;AAEF,gBAAgB;AAChB,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,MAAM,EAAE,GAAY;CACrB,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,OAAO,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,CAAC;IACxC,MAAM,EAAE,GAAY;IACpB,IAAI,EAAE;QACJ,UAAU,EAAE,GAAY;QACxB,OAAO,EAAE,iDAAiD;KAC3D;CACF,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export interface Breach {
|
|
2
|
+
Name: string;
|
|
3
|
+
Title: string;
|
|
4
|
+
Domain: string;
|
|
5
|
+
BreachDate: string;
|
|
6
|
+
AddedDate: string;
|
|
7
|
+
ModifiedDate: string;
|
|
8
|
+
PwnCount: number;
|
|
9
|
+
Description: string;
|
|
10
|
+
DataClasses: string[];
|
|
11
|
+
IsVerified: boolean;
|
|
12
|
+
IsFabricated: boolean;
|
|
13
|
+
IsSensitive: boolean;
|
|
14
|
+
IsRetired: boolean;
|
|
15
|
+
IsSpamList: boolean;
|
|
16
|
+
IsMalware: boolean;
|
|
17
|
+
IsSubscriptionFree: boolean;
|
|
18
|
+
LogoPath: string;
|
|
19
|
+
}
|
|
20
|
+
export interface Paste {
|
|
21
|
+
Id: string;
|
|
22
|
+
Source: string;
|
|
23
|
+
Title: string;
|
|
24
|
+
Date: string;
|
|
25
|
+
EmailCount: number;
|
|
26
|
+
}
|
|
27
|
+
export interface SubscriptionStatus {
|
|
28
|
+
SubscriptionName: string;
|
|
29
|
+
Description: string;
|
|
30
|
+
SubscribedUntil: string;
|
|
31
|
+
Rpm: number;
|
|
32
|
+
DomainSearchMaxBreachedAccounts: number;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* All possible values that can be returned in the response body of an API query
|
|
36
|
+
*
|
|
37
|
+
* @internal
|
|
38
|
+
*/
|
|
@@ -1,2 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
//
|
|
2
|
+
// Data Models from the API
|
|
3
|
+
//
|
|
4
|
+
export {};
|
|
5
|
+
/**
|
|
6
|
+
* All possible values that can be returned in the response body of an API query
|
|
7
|
+
*
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
// export type ResponseBody = ApiData | ErrorData;
|
|
11
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/api/haveibeenpwned/types.ts"],"names":[],"mappings":"AAAA,EAAE;AACF,2BAA2B;AAC3B,EAAE;;AAiEF;;;;GAIG;AACH,kDAAkD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { installUndiciOnNode18 } from '../fetch-polyfill.js';
|
|
2
1
|
import { BAD_REQUEST } from './responses.js';
|
|
3
|
-
installUndiciOnNode18();
|
|
4
2
|
/**
|
|
5
3
|
* Fetches data from the supplied API endpoint.
|
|
6
4
|
*
|
|
@@ -24,35 +22,23 @@ installUndiciOnNode18();
|
|
|
24
22
|
* @returns {Promise<string>} a Promise which resolves to the data resulting
|
|
25
23
|
* from the query, or rejects with an Error
|
|
26
24
|
*/
|
|
27
|
-
async function fetchFromApi(endpoint, options = {}) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
signal: AbortSignal.timeout(timeoutMs)
|
|
46
|
-
} : {})
|
|
47
|
-
};
|
|
48
|
-
const url = `${baseUrl.replace(/\/$/g, '')}${endpoint}?mode=${mode}`;
|
|
49
|
-
const response = await fetch(url, config);
|
|
50
|
-
if (response.ok) return response.text();
|
|
51
|
-
if (response.status === BAD_REQUEST.status) {
|
|
52
|
-
const text = await response.text();
|
|
53
|
-
throw new Error(text);
|
|
54
|
-
}
|
|
55
|
-
throw new Error(response.statusText);
|
|
25
|
+
export async function fetchFromApi(endpoint, options = {}) {
|
|
26
|
+
const { baseUrl = 'https://api.pwnedpasswords.com', timeoutMs, userAgent, addPadding = false, mode = 'sha1', } = options;
|
|
27
|
+
const config = {
|
|
28
|
+
headers: {
|
|
29
|
+
...(userAgent ? { 'User-Agent': userAgent } : {}),
|
|
30
|
+
...(addPadding ? { 'Add-Padding': 'true' } : {}),
|
|
31
|
+
},
|
|
32
|
+
...(timeoutMs ? { signal: AbortSignal.timeout(timeoutMs) } : {}),
|
|
33
|
+
};
|
|
34
|
+
const url = `${baseUrl.replace(/\/$/g, '')}${endpoint}?mode=${mode}`;
|
|
35
|
+
const response = await fetch(url, config);
|
|
36
|
+
if (response.ok)
|
|
37
|
+
return response.text();
|
|
38
|
+
if (response.status === BAD_REQUEST.status) {
|
|
39
|
+
const text = await response.text();
|
|
40
|
+
throw new Error(text);
|
|
41
|
+
}
|
|
42
|
+
throw new Error(response.statusText);
|
|
56
43
|
}
|
|
57
|
-
|
|
58
|
-
//# sourceMappingURL=fetch-from-api.js.map
|
|
44
|
+
//# sourceMappingURL=fetch-from-api.js.map
|