hibp 0.0.0-dev.9896b89a → 0.0.0-dev.d74e2ad2
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/API.md +275 -198
- package/CHANGELOG.md +70 -0
- package/README.md +20 -22
- package/dist/browser/hibp.module.js +1 -1
- package/dist/browser/hibp.module.js.map +1 -1
- package/dist/browser/hibp.umd.js +1 -1
- package/dist/browser/hibp.umd.js.map +1 -1
- package/dist/cjs/api/fetch-polyfill.cjs +27 -0
- package/dist/cjs/api/fetch-polyfill.cjs.map +1 -0
- package/dist/cjs/api/haveibeenpwned/{fetchFromApi.js → fetch-from-api.cjs} +43 -38
- package/dist/cjs/api/haveibeenpwned/fetch-from-api.cjs.map +1 -0
- package/dist/cjs/api/haveibeenpwned/{responses.js → responses.cjs} +1 -7
- package/dist/cjs/api/haveibeenpwned/responses.cjs.map +1 -0
- package/dist/cjs/api/haveibeenpwned/types.cjs +2 -0
- package/dist/cjs/api/haveibeenpwned/types.cjs.map +1 -0
- package/dist/cjs/api/pwnedpasswords/fetch-from-api.cjs +53 -0
- package/dist/cjs/api/pwnedpasswords/fetch-from-api.cjs.map +1 -0
- package/dist/cjs/api/pwnedpasswords/{responses.js → responses.cjs} +1 -6
- package/dist/cjs/api/pwnedpasswords/responses.cjs.map +1 -0
- package/dist/cjs/{breach.js → breach.cjs} +14 -13
- package/dist/cjs/breach.cjs.map +1 -0
- package/dist/cjs/{breachedAccount.js → breached-account.cjs} +56 -56
- package/dist/cjs/breached-account.cjs.map +1 -0
- package/dist/cjs/{breaches.js → breaches.cjs} +29 -26
- package/dist/cjs/breaches.cjs.map +1 -0
- package/dist/cjs/{dataClasses.js → data-classes.cjs} +11 -12
- package/dist/cjs/data-classes.cjs.map +1 -0
- package/dist/cjs/hibp.cjs +23 -0
- package/dist/cjs/hibp.cjs.map +1 -0
- package/dist/cjs/hibp.d.cts +663 -0
- package/dist/cjs/{package.json.js → package.json.cjs} +2 -2
- package/dist/cjs/package.json.cjs.map +1 -0
- package/dist/cjs/{pasteAccount.js → paste-account.cjs} +28 -22
- package/dist/cjs/paste-account.cjs.map +1 -0
- package/dist/cjs/{pwnedPasswordRange.js → pwned-password-range.cjs} +44 -25
- package/dist/cjs/pwned-password-range.cjs.map +1 -0
- package/dist/cjs/{pwnedPassword.js → pwned-password.cjs} +20 -15
- package/dist/cjs/pwned-password.cjs.map +1 -0
- package/dist/cjs/{search.js → search.cjs} +51 -49
- package/dist/cjs/search.cjs.map +1 -0
- package/dist/cjs/subscription-status.cjs +56 -0
- package/dist/cjs/subscription-status.cjs.map +1 -0
- package/dist/esm/api/fetch-polyfill.js +25 -0
- package/dist/esm/api/fetch-polyfill.js.map +1 -0
- package/dist/esm/api/haveibeenpwned/{fetchFromApi.mjs → fetch-from-api.js} +43 -38
- package/dist/esm/api/haveibeenpwned/fetch-from-api.js.map +1 -0
- package/dist/esm/api/haveibeenpwned/{responses.mjs → responses.js} +2 -7
- package/dist/esm/api/haveibeenpwned/responses.js.map +1 -0
- package/dist/esm/api/haveibeenpwned/types.js +2 -0
- package/dist/esm/api/haveibeenpwned/types.js.map +1 -0
- package/dist/esm/api/pwnedpasswords/fetch-from-api.js +51 -0
- package/dist/esm/api/pwnedpasswords/fetch-from-api.js.map +1 -0
- package/dist/esm/api/pwnedpasswords/{responses.mjs → responses.js} +2 -6
- package/dist/esm/api/pwnedpasswords/responses.js.map +1 -0
- package/dist/esm/{breach.mjs → breach.js} +14 -13
- package/dist/esm/breach.js.map +1 -0
- package/dist/esm/{breachedAccount.mjs → breached-account.js} +56 -56
- package/dist/esm/breached-account.js.map +1 -0
- package/dist/esm/{breaches.mjs → breaches.js} +29 -26
- package/dist/esm/breaches.js.map +1 -0
- package/dist/esm/{dataClasses.mjs → data-classes.js} +11 -12
- package/dist/esm/data-classes.js.map +1 -0
- package/dist/esm/hibp.d.ts +663 -0
- package/dist/esm/hibp.js +11 -0
- package/dist/{cjs → esm}/hibp.js.map +1 -1
- package/dist/esm/package.json.js +4 -0
- package/dist/{cjs → esm}/package.json.js.map +1 -1
- package/dist/esm/{pasteAccount.mjs → paste-account.js} +28 -22
- package/dist/esm/paste-account.js.map +1 -0
- package/dist/esm/{pwnedPasswordRange.mjs → pwned-password-range.js} +44 -25
- package/dist/esm/pwned-password-range.js.map +1 -0
- package/dist/esm/{pwnedPassword.mjs → pwned-password.js} +20 -15
- package/dist/esm/pwned-password.js.map +1 -0
- package/dist/esm/{search.mjs → search.js} +51 -49
- package/dist/esm/search.js.map +1 -0
- package/dist/esm/subscription-status.js +54 -0
- package/dist/esm/subscription-status.js.map +1 -0
- package/example/runkit.js +13 -14
- package/package.json +57 -64
- package/dist/cjs/api/haveibeenpwned/fetchFromApi.js.map +0 -1
- package/dist/cjs/api/haveibeenpwned/index.js +0 -6
- package/dist/cjs/api/haveibeenpwned/index.js.map +0 -1
- package/dist/cjs/api/haveibeenpwned/responses.js.map +0 -1
- package/dist/cjs/api/pwnedpasswords/fetchFromApi.js +0 -44
- package/dist/cjs/api/pwnedpasswords/fetchFromApi.js.map +0 -1
- package/dist/cjs/api/pwnedpasswords/index.js +0 -5
- package/dist/cjs/api/pwnedpasswords/index.js.map +0 -1
- package/dist/cjs/api/pwnedpasswords/responses.js.map +0 -1
- package/dist/cjs/breach.js.map +0 -1
- package/dist/cjs/breachedAccount.js.map +0 -1
- package/dist/cjs/breaches.js.map +0 -1
- package/dist/cjs/dataClasses.js.map +0 -1
- package/dist/cjs/hibp.js +0 -21
- package/dist/cjs/pasteAccount.js.map +0 -1
- package/dist/cjs/pwnedPassword.js.map +0 -1
- package/dist/cjs/pwnedPasswordRange.js.map +0 -1
- package/dist/cjs/search.js.map +0 -1
- package/dist/esm/api/haveibeenpwned/fetchFromApi.mjs.map +0 -1
- package/dist/esm/api/haveibeenpwned/index.mjs +0 -2
- package/dist/esm/api/haveibeenpwned/index.mjs.map +0 -1
- package/dist/esm/api/haveibeenpwned/responses.mjs.map +0 -1
- package/dist/esm/api/pwnedpasswords/fetchFromApi.mjs +0 -42
- package/dist/esm/api/pwnedpasswords/fetchFromApi.mjs.map +0 -1
- package/dist/esm/api/pwnedpasswords/index.mjs +0 -2
- package/dist/esm/api/pwnedpasswords/index.mjs.map +0 -1
- package/dist/esm/api/pwnedpasswords/responses.mjs.map +0 -1
- package/dist/esm/breach.mjs.map +0 -1
- package/dist/esm/breachedAccount.mjs.map +0 -1
- package/dist/esm/breaches.mjs.map +0 -1
- package/dist/esm/dataClasses.mjs.map +0 -1
- package/dist/esm/hibp.mjs +0 -10
- package/dist/esm/hibp.mjs.map +0 -1
- package/dist/esm/package.json.mjs +0 -4
- package/dist/esm/package.json.mjs.map +0 -1
- package/dist/esm/pasteAccount.mjs.map +0 -1
- package/dist/esm/pwnedPassword.mjs.map +0 -1
- package/dist/esm/pwnedPasswordRange.mjs.map +0 -1
- package/dist/esm/search.mjs.map +0 -1
- package/dist/hibp.d.ts +0 -502
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var fetchFromApi = /*#__PURE__*/require('./api/haveibeenpwned/
|
|
3
|
+
var fetchFromApi = /*#__PURE__*/require('./api/haveibeenpwned/fetch-from-api.cjs');
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* An object representing a paste.
|
|
@@ -15,18 +15,16 @@ var fetchFromApi = /*#__PURE__*/require('./api/haveibeenpwned/fetchFromApi.js');
|
|
|
15
15
|
/**
|
|
16
16
|
* Fetches paste data for a specific account (email address).
|
|
17
17
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* `haveibeenpwned.com` now requires an API key from
|
|
18
|
+
* 🔑 `haveibeenpwned.com` requires an API key from
|
|
21
19
|
* https://haveibeenpwned.com/API/Key for the `pasteaccount` endpoint. The
|
|
22
20
|
* `apiKey` option here is not explicitly required, but direct requests made
|
|
23
|
-
* without it (
|
|
24
|
-
* valid API key on your behalf)
|
|
21
|
+
* without it will fail (unless you specify a `baseUrl` to a proxy that inserts
|
|
22
|
+
* a valid API key on your behalf).
|
|
25
23
|
*
|
|
26
24
|
* @param {string} email the email address to query
|
|
27
25
|
* @param {object} [options] a configuration object
|
|
28
26
|
* @param {string} [options.apiKey] an API key from
|
|
29
|
-
* https://haveibeenpwned.com/API/Key
|
|
27
|
+
* https://haveibeenpwned.com/API/Key (default: undefined)
|
|
30
28
|
* @param {string} [options.baseUrl] a custom base URL for the
|
|
31
29
|
* haveibeenpwned.com API endpoints (default:
|
|
32
30
|
* `https://haveibeenpwned.com/api/v3`)
|
|
@@ -36,24 +34,32 @@ var fetchFromApi = /*#__PURE__*/require('./api/haveibeenpwned/fetchFromApi.js');
|
|
|
36
34
|
* array of paste objects (or null if no pastes were found), or rejects with an
|
|
37
35
|
* Error
|
|
38
36
|
* @example
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* // ...
|
|
45
|
-
* }
|
|
46
|
-
* })
|
|
47
|
-
* .catch(err => {
|
|
37
|
+
* try {
|
|
38
|
+
* const data = await pasteAccount("foo@bar.com", { apiKey: "my-api-key" });
|
|
39
|
+
* if (data) {
|
|
40
|
+
* // ...
|
|
41
|
+
* } else {
|
|
48
42
|
* // ...
|
|
43
|
+
* }
|
|
44
|
+
* } catch (err) {
|
|
45
|
+
* // ...
|
|
46
|
+
* }
|
|
47
|
+
* @example
|
|
48
|
+
* try {
|
|
49
|
+
* const data = await pasteAccount("foo@bar.com", {
|
|
50
|
+
* baseUrl: "https://my-hibp-proxy:8080",
|
|
49
51
|
* });
|
|
52
|
+
* if (data) {
|
|
53
|
+
* // ...
|
|
54
|
+
* } else {
|
|
55
|
+
* // ...
|
|
56
|
+
* }
|
|
57
|
+
* } catch (err) {
|
|
58
|
+
* // ...
|
|
59
|
+
* }
|
|
50
60
|
*/
|
|
51
61
|
function pasteAccount(email, options = {}) {
|
|
52
|
-
return fetchFromApi.fetchFromApi(`/pasteaccount/${encodeURIComponent(email)}`,
|
|
53
|
-
apiKey: options.apiKey,
|
|
54
|
-
baseUrl: options.baseUrl,
|
|
55
|
-
userAgent: options.userAgent
|
|
56
|
-
});
|
|
62
|
+
return fetchFromApi.fetchFromApi(`/pasteaccount/${encodeURIComponent(email)}`, options);
|
|
57
63
|
}
|
|
58
64
|
exports.pasteAccount = pasteAccount;
|
|
59
|
-
//# sourceMappingURL=
|
|
65
|
+
//# sourceMappingURL=paste-account.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paste-account.cjs","sources":["../../src/paste-account.ts"],"sourcesContent":["import type { Paste } from './api/haveibeenpwned/types.js';\nimport { fetchFromApi } from './api/haveibeenpwned/fetch-from-api.js';\n\n/**\n * An object representing a paste.\n *\n * @typedef {object} Paste\n * @property {string} Id\n * @property {string} Source\n * @property {string} Title\n * @property {string} Date\n * @property {number} EmailCount\n */\n\n/**\n * Fetches paste data for a specific account (email address).\n *\n * 🔑 `haveibeenpwned.com` requires an API key from\n * https://haveibeenpwned.com/API/Key for the `pasteaccount` endpoint. The\n * `apiKey` option here is not explicitly required, but direct requests made\n * without it will fail (unless you specify a `baseUrl` to a proxy that inserts\n * a valid API key on your behalf).\n *\n * @param {string} email the email address to query\n * @param {object} [options] a configuration object\n * @param {string} [options.apiKey] an API key from\n * https://haveibeenpwned.com/API/Key (default: undefined)\n * @param {string} [options.baseUrl] a custom base URL for the\n * haveibeenpwned.com API endpoints (default:\n * `https://haveibeenpwned.com/api/v3`)\n * @param {string} [options.userAgent] a custom string to send as the User-Agent\n * field in the request headers (default: `hibp <version>`)\n * @returns {(Promise<Paste[]> | Promise<null>)} a Promise which resolves to an\n * array of paste objects (or null if no pastes were found), or rejects with an\n * Error\n * @example\n * try {\n * const data = await pasteAccount(\"foo@bar.com\", { apiKey: \"my-api-key\" });\n * if (data) {\n * // ...\n * } else {\n * // ...\n * }\n * } catch (err) {\n * // ...\n * }\n * @example\n * try {\n * const data = await pasteAccount(\"foo@bar.com\", {\n * baseUrl: \"https://my-hibp-proxy:8080\",\n * });\n * if (data) {\n * // ...\n * } else {\n * // ...\n * }\n * } catch (err) {\n * // ...\n * }\n */\nexport function pasteAccount(\n email: string,\n options: {\n /**\n * an API key from https://haveibeenpwned.com/API/Key (default: undefined)\n */\n apiKey?: string;\n /**\n * a custom base URL for the haveibeenpwned.com API endpoints (default:\n * `https://haveibeenpwned.com/api/v3`)\n */\n baseUrl?: string;\n /**\n * a custom string to send as the User-Agent field in the request headers\n * (default: `hibp <version>`)\n */\n userAgent?: string;\n } = {},\n): Promise<Paste[] | null> {\n return fetchFromApi(\n `/pasteaccount/${encodeURIComponent(email)}`,\n options,\n ) as Promise<Paste[] | null>;\n}\n"],"names":["pasteAccount","email","options","fetchFromApi","encodeURIComponent"],"mappings":";;;;AAGA;;;;;;;;;AASG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CG;SACaA,YAAYA,CAC1BC,KAAa,EACbC,UAeI,EAAE,EAAA;EAEN,OAAOC,YAAAA,CAAAA,YAAY,CACjB,iBAAiBC,kBAAkB,CAACH,KAAK,CAAG,EAAA,EAC5CC,OAAO,CACmB;AAC9B;"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var fetchFromApi = /*#__PURE__*/require('./api/pwnedpasswords/
|
|
3
|
+
var fetchFromApi = /*#__PURE__*/require('./api/pwnedpasswords/fetch-from-api.cjs');
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* An object mapping an exposed password hash suffix (corresponding to a given
|
|
@@ -9,7 +9,8 @@ var fetchFromApi = /*#__PURE__*/require('./api/pwnedpasswords/fetchFromApi.js');
|
|
|
9
9
|
* @typedef {Object.<string, number>} PwnedPasswordSuffixes
|
|
10
10
|
*/
|
|
11
11
|
/**
|
|
12
|
-
* Fetches the SHA-1 hash suffixes for the given 5-character
|
|
12
|
+
* Fetches the SHA-1 or NTLM hash suffixes for the given 5-character hash
|
|
13
|
+
* prefix.
|
|
13
14
|
*
|
|
14
15
|
* When a password hash with the same first 5 characters is found in the Pwned
|
|
15
16
|
* Passwords repository, the API will respond with an HTTP 200 and include the
|
|
@@ -17,9 +18,13 @@ var fetchFromApi = /*#__PURE__*/require('./api/pwnedpasswords/fetchFromApi.js');
|
|
|
17
18
|
* of how many times it appears in the data set. This function parses the
|
|
18
19
|
* response and returns a more structured format.
|
|
19
20
|
*
|
|
20
|
-
* @param {string} prefix the first 5 characters of a
|
|
21
|
+
* @param {string} prefix the first 5 characters of a password hash (case
|
|
21
22
|
* insensitive)
|
|
22
23
|
* @param {object} [options] a configuration object
|
|
24
|
+
* @param {boolean} [options.addPadding] ask the remote API to add padding to
|
|
25
|
+
* the response to obscure the password prefix (default: `false`)
|
|
26
|
+
* @param {'sha1' | 'ntlm'} [options.mode] return SHA-1 or NTLM hashes
|
|
27
|
+
* (default: `sha1`)
|
|
23
28
|
* @param {string} [options.baseUrl] a custom base URL for the
|
|
24
29
|
* pwnedpasswords.com API endpoints (default: `https://api.pwnedpasswords.com`)
|
|
25
30
|
* @param {string} [options.userAgent] a custom string to send as the User-Agent
|
|
@@ -30,34 +35,48 @@ var fetchFromApi = /*#__PURE__*/require('./api/pwnedpasswords/fetchFromApi.js');
|
|
|
30
35
|
* password data set, or rejects with an Error
|
|
31
36
|
*
|
|
32
37
|
* @example
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
38
|
+
* try {
|
|
39
|
+
* const results = await pwnedPasswordRange("5BAA6");
|
|
40
|
+
* // results will have the following shape:
|
|
41
|
+
* // {
|
|
42
|
+
* // "003D68EB55068C33ACE09247EE4C639306B": 3,
|
|
43
|
+
* // "012C192B2F16F82EA0EB9EF18D9D539B0DD": 1,
|
|
44
|
+
* // ...
|
|
45
|
+
* // }
|
|
46
|
+
* } catch (err) {
|
|
47
|
+
* // ...
|
|
48
|
+
* }
|
|
42
49
|
* @example
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
50
|
+
* try {
|
|
51
|
+
* const suffix = "1E4C9B93F3F0682250B6CF8331B7EE68FD8";
|
|
52
|
+
* const results = await pwnedPasswordRange("5BAA6");
|
|
53
|
+
* const numPwns = results[suffix] || 0;
|
|
54
|
+
* } catch (err) {
|
|
55
|
+
* // ...
|
|
56
|
+
* }
|
|
49
57
|
* @see https://haveibeenpwned.com/api/v3#SearchingPwnedPasswordsByRange
|
|
50
58
|
*/
|
|
51
|
-
function pwnedPasswordRange(prefix, options = {}) {
|
|
52
|
-
|
|
59
|
+
async function pwnedPasswordRange(prefix, options = {}) {
|
|
60
|
+
const {
|
|
61
|
+
baseUrl,
|
|
62
|
+
userAgent,
|
|
63
|
+
addPadding = false,
|
|
64
|
+
mode = 'sha1'
|
|
65
|
+
} = options;
|
|
66
|
+
const data = await fetchFromApi.fetchFromApi(`/range/${encodeURIComponent(prefix)}`, {
|
|
67
|
+
baseUrl,
|
|
68
|
+
userAgent,
|
|
69
|
+
addPadding,
|
|
70
|
+
mode
|
|
71
|
+
});
|
|
53
72
|
// create array from lines of text in response body
|
|
54
|
-
|
|
73
|
+
const results = data.split('\n').filter(Boolean);
|
|
55
74
|
// convert into an object mapping suffix to count for each line
|
|
56
|
-
|
|
75
|
+
return results.reduce((acc, row) => {
|
|
57
76
|
const [suffix, countString] = row.split(':');
|
|
58
|
-
acc[suffix] = parseInt(countString, 10);
|
|
77
|
+
acc[suffix] = Number.parseInt(countString, 10);
|
|
59
78
|
return acc;
|
|
60
|
-
}, {})
|
|
79
|
+
}, {});
|
|
61
80
|
}
|
|
62
81
|
exports.pwnedPasswordRange = pwnedPasswordRange;
|
|
63
|
-
//# sourceMappingURL=
|
|
82
|
+
//# sourceMappingURL=pwned-password-range.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pwned-password-range.cjs","sources":["../../src/pwned-password-range.ts"],"sourcesContent":["import { fetchFromApi } from './api/pwnedpasswords/fetch-from-api.js';\n\nexport type PwnedPasswordSuffixes = Record<string, number>;\n\n/**\n * An object mapping an exposed password hash suffix (corresponding to a given\n * hash prefix) to how many times it occurred in the Pwned Passwords repository.\n *\n * @typedef {Object.<string, number>} PwnedPasswordSuffixes\n */\n\n/**\n * Fetches the SHA-1 or NTLM hash suffixes for the given 5-character hash\n * prefix.\n *\n * When a password hash with the same first 5 characters is found in the Pwned\n * Passwords repository, the API will respond with an HTTP 200 and include the\n * suffix of every hash beginning with the specified prefix, followed by a count\n * of how many times it appears in the data set. This function parses the\n * response and returns a more structured format.\n *\n * @param {string} prefix the first 5 characters of a password hash (case\n * insensitive)\n * @param {object} [options] a configuration object\n * @param {boolean} [options.addPadding] ask the remote API to add padding to\n * the response to obscure the password prefix (default: `false`)\n * @param {'sha1' | 'ntlm'} [options.mode] return SHA-1 or NTLM hashes\n * (default: `sha1`)\n * @param {string} [options.baseUrl] a custom base URL for the\n * pwnedpasswords.com API endpoints (default: `https://api.pwnedpasswords.com`)\n * @param {string} [options.userAgent] a custom string to send as the User-Agent\n * field in the request headers (default: `hibp <version>`)\n * @returns {Promise<PwnedPasswordSuffixes>} a Promise which resolves to an\n * object mapping the `suffix` that when matched with the prefix composes the\n * complete hash, to the `count` of how many times it appears in the breached\n * password data set, or rejects with an Error\n *\n * @example\n * try {\n * const results = await pwnedPasswordRange(\"5BAA6\");\n * // results will have the following shape:\n * // {\n * // \"003D68EB55068C33ACE09247EE4C639306B\": 3,\n * // \"012C192B2F16F82EA0EB9EF18D9D539B0DD\": 1,\n * // ...\n * // }\n * } catch (err) {\n * // ...\n * }\n * @example\n * try {\n * const suffix = \"1E4C9B93F3F0682250B6CF8331B7EE68FD8\";\n * const results = await pwnedPasswordRange(\"5BAA6\");\n * const numPwns = results[suffix] || 0;\n * } catch (err) {\n * // ...\n * }\n * @see https://haveibeenpwned.com/api/v3#SearchingPwnedPasswordsByRange\n */\nexport async function pwnedPasswordRange(\n prefix: string,\n options: {\n /**\n * ask the remote API to add padding to the response to obscure the password\n * prefix (default: `false`)\n */\n addPadding?: boolean;\n /**\n * return SHA-1 or NTLM hashes (default: `sha1`)\n */\n mode?: 'sha1' | 'ntlm';\n /**\n * a custom base URL for the haveibeenpwned.com API endpoints (default:\n * `https://haveibeenpwned.com/api/v3`)\n */\n baseUrl?: string;\n /**\n * a custom string to send as the User-Agent field in the request headers\n * (default: `hibp <version>`)\n */\n userAgent?: string;\n } = {},\n): Promise<PwnedPasswordSuffixes> {\n const { baseUrl, userAgent, addPadding = false, mode = 'sha1' } = options;\n\n const data = await fetchFromApi(`/range/${encodeURIComponent(prefix)}`, {\n baseUrl,\n userAgent,\n addPadding,\n mode,\n });\n\n // create array from lines of text in response body\n const results = data.split('\\n').filter(Boolean);\n\n // convert into an object mapping suffix to count for each line\n return results.reduce<PwnedPasswordSuffixes>((acc, row) => {\n const [suffix, countString] = row.split(':');\n acc[suffix] = Number.parseInt(countString, 10);\n return acc;\n }, {});\n}\n"],"names":["pwnedPasswordRange","prefix","options","baseUrl","userAgent","addPadding","mode","data","fetchFromApi","encodeURIComponent","results","split","filter","Boolean","reduce","acc","row","suffix","countString","Number","parseInt"],"mappings":";;;;AAIA;;;;;AAKG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+CG;AACI,eAAeA,kBAAkBA,CACtCC,MAAc,EACdC,UAoBI,EAAE,EAAA;EAEN,MAAM;IAAEC,OAAO;IAAEC,SAAS;IAAEC,UAAU,GAAG,KAAK;IAAEC,IAAI,GAAG;EAAQ,CAAA,GAAGJ,OAAO;EAEzE,MAAMK,IAAI,GAAG,MAAMC,yBAAY,CAAW,UAAAC,kBAAkB,CAACR,MAAM,CAAC,EAAE,EAAE;IACtEE,OAAO;IACPC,SAAS;IACTC,UAAU;IACVC;EACD,CAAA,CAAC;;EAGF,MAAMI,OAAO,GAAGH,IAAI,CAACI,KAAK,CAAC,IAAI,CAAC,CAACC,MAAM,CAACC,OAAO,CAAC;;EAGhD,OAAOH,OAAO,CAACI,MAAM,CAAwB,CAACC,GAAG,EAAEC,GAAG,KAAI;IACxD,MAAM,CAACC,MAAM,EAAEC,WAAW,CAAC,GAAGF,GAAG,CAACL,KAAK,CAAC,GAAG,CAAC;IAC5CI,GAAG,CAACE,MAAM,CAAC,GAAGE,MAAM,CAACC,QAAQ,CAACF,WAAW,EAAE,EAAE,CAAC;IAC9C,OAAOH,GAAG;EACX,CAAA,EAAE,CAAE,CAAA,CAAC;AACR;"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var JSSHA = /*#__PURE__*/require('jssha/dist/sha1');
|
|
4
|
-
var pwnedPasswordRange = /*#__PURE__*/require('./
|
|
4
|
+
var pwnedPasswordRange = /*#__PURE__*/require('./pwned-password-range.cjs');
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Fetches the number of times the the given password has been exposed in a
|
|
@@ -10,6 +10,8 @@ var pwnedPasswordRange = /*#__PURE__*/require('./pwnedPasswordRange.js');
|
|
|
10
10
|
*
|
|
11
11
|
* @param {string} password a password in plain text
|
|
12
12
|
* @param {object} [options] a configuration object
|
|
13
|
+
* @param {boolean} [options.addPadding] ask the remote API to add padding to
|
|
14
|
+
* the response to obscure the password prefix (default: `false`)
|
|
13
15
|
* @param {string} [options.baseUrl] a custom base URL for the
|
|
14
16
|
* pwnedpasswords.com API endpoints (default: `https://api.pwnedpasswords.com`)
|
|
15
17
|
* @param {string} [options.userAgent] a custom string to send as the User-Agent
|
|
@@ -17,21 +19,22 @@ var pwnedPasswordRange = /*#__PURE__*/require('./pwnedPasswordRange.js');
|
|
|
17
19
|
* @returns {Promise<number>} a Promise which resolves to the number of times
|
|
18
20
|
* the password has been exposed in a breach, or rejects with an Error
|
|
19
21
|
* @example
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* // ...
|
|
25
|
-
* } else {
|
|
26
|
-
* // ...
|
|
27
|
-
* }
|
|
28
|
-
* })
|
|
29
|
-
* .catch(err => {
|
|
22
|
+
* try {
|
|
23
|
+
* const numPwns = await pwnedPassword("f00b4r");
|
|
24
|
+
* // truthy check or numeric condition
|
|
25
|
+
* if (numPwns) {
|
|
30
26
|
* // ...
|
|
31
|
-
* }
|
|
27
|
+
* } else {
|
|
28
|
+
* // ...
|
|
29
|
+
* }
|
|
30
|
+
* } catch (err) {
|
|
31
|
+
* // ...
|
|
32
|
+
* }
|
|
32
33
|
* @see https://haveibeenpwned.com/api/v3#PwnedPasswords
|
|
33
34
|
*/
|
|
34
|
-
function pwnedPassword(password, options = {}) {
|
|
35
|
+
async function pwnedPassword(password, options = {}) {
|
|
36
|
+
/* eslint-disable */
|
|
37
|
+
// @ts-expect-error: JSSHA types are busted
|
|
35
38
|
const sha1 = new JSSHA('SHA-1', 'TEXT');
|
|
36
39
|
sha1.update(password);
|
|
37
40
|
const hash = sha1.getHash('HEX', {
|
|
@@ -39,7 +42,9 @@ function pwnedPassword(password, options = {}) {
|
|
|
39
42
|
});
|
|
40
43
|
const prefix = hash.slice(0, 5);
|
|
41
44
|
const suffix = hash.slice(5);
|
|
42
|
-
|
|
45
|
+
const range = await pwnedPasswordRange.pwnedPasswordRange(prefix, options);
|
|
46
|
+
return range[suffix] || 0;
|
|
47
|
+
/* eslint-enable */
|
|
43
48
|
}
|
|
44
49
|
exports.pwnedPassword = pwnedPassword;
|
|
45
|
-
//# sourceMappingURL=
|
|
50
|
+
//# sourceMappingURL=pwned-password.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pwned-password.cjs","sources":["../../src/pwned-password.ts"],"sourcesContent":["import JSSHA from 'jssha/dist/sha1';\nimport { pwnedPasswordRange } from './pwned-password-range.js';\n\n/**\n * Fetches the number of times the the given password has been exposed in a\n * breach (0 indicating no exposure). The password is given in plain text, but\n * only the first 5 characters of its SHA-1 hash will be submitted to the API.\n *\n * @param {string} password a password in plain text\n * @param {object} [options] a configuration object\n * @param {boolean} [options.addPadding] ask the remote API to add padding to\n * the response to obscure the password prefix (default: `false`)\n * @param {string} [options.baseUrl] a custom base URL for the\n * pwnedpasswords.com API endpoints (default: `https://api.pwnedpasswords.com`)\n * @param {string} [options.userAgent] a custom string to send as the User-Agent\n * field in the request headers (default: `hibp <version>`)\n * @returns {Promise<number>} a Promise which resolves to the number of times\n * the password has been exposed in a breach, or rejects with an Error\n * @example\n * try {\n * const numPwns = await pwnedPassword(\"f00b4r\");\n * // truthy check or numeric condition\n * if (numPwns) {\n * // ...\n * } else {\n * // ...\n * }\n * } catch (err) {\n * // ...\n * }\n * @see https://haveibeenpwned.com/api/v3#PwnedPasswords\n */\nexport async function pwnedPassword(\n password: string,\n options: {\n /**\n * ask the remote API to add padding to the response to obscure the password\n * prefix (default: `false`)\n */\n addPadding?: boolean;\n /**\n * a custom base URL for the haveibeenpwned.com API endpoints (default:\n * `https://haveibeenpwned.com/api/v3`)\n */\n baseUrl?: string;\n /**\n * a custom string to send as the User-Agent field in the request headers\n * (default: `hibp <version>`)\n */\n userAgent?: string;\n } = {},\n): Promise<number> {\n /* eslint-disable */\n // @ts-expect-error: JSSHA types are busted\n const sha1 = new JSSHA('SHA-1', 'TEXT');\n sha1.update(password);\n const hash = sha1.getHash('HEX', { outputUpper: true });\n const prefix = hash.slice(0, 5);\n const suffix = hash.slice(5);\n\n const range = await pwnedPasswordRange(prefix, options);\n return range[suffix] || 0;\n /* eslint-enable */\n}\n"],"names":["pwnedPassword","password","options","sha1","JSSHA","update","hash","getHash","outputUpper","prefix","slice","suffix","range","pwnedPasswordRange"],"mappings":";;;;;AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BG;AACI,eAAeA,aAAaA,CACjCC,QAAgB,EAChBC,UAgBI,EAAE,EAAA;;;EAIN,MAAMC,IAAI,GAAG,IAAIC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC;EACvCD,IAAI,CAACE,MAAM,CAACJ,QAAQ,CAAC;EACrB,MAAMK,IAAI,GAAGH,IAAI,CAACI,OAAO,CAAC,KAAK,EAAE;IAAEC,WAAW,EAAE;EAAI,CAAE,CAAC;EACvD,MAAMC,MAAM,GAAGH,IAAI,CAACI,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;EAC/B,MAAMC,MAAM,GAAGL,IAAI,CAACI,KAAK,CAAC,CAAC,CAAC;EAE5B,MAAME,KAAK,GAAG,MAAMC,kBAAAA,CAAAA,kBAAkB,CAACJ,MAAM,EAAEP,OAAO,CAAC;EACvD,OAAOU,KAAK,CAACD,MAAM,CAAC,IAAI,CAAC;;AAE3B;"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var breachedAccount = /*#__PURE__*/require('./
|
|
4
|
-
var pasteAccount = /*#__PURE__*/require('./
|
|
3
|
+
var breachedAccount = /*#__PURE__*/require('./breached-account.cjs');
|
|
4
|
+
var pasteAccount = /*#__PURE__*/require('./paste-account.cjs');
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* An object representing search results.
|
|
@@ -19,79 +19,81 @@ var pasteAccount = /*#__PURE__*/require('./pasteAccount.js');
|
|
|
19
19
|
* exactly how searching via the current web interface behaves, which this
|
|
20
20
|
* convenience method is designed to mimic.
|
|
21
21
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* `haveibeenpwned.com` now requires an API key from
|
|
22
|
+
* 🔑 `haveibeenpwned.com` requires an API key from
|
|
25
23
|
* https://haveibeenpwned.com/API/Key for the `breachedaccount` and
|
|
26
|
-
* `pasteaccount` endpoints. The
|
|
27
|
-
* required, but direct requests made without it (
|
|
28
|
-
* `baseUrl` to a proxy that inserts a valid API key on your behalf)
|
|
24
|
+
* `pasteaccount` endpoints. The `apiKey` option here is not explicitly
|
|
25
|
+
* required, but direct requests made without it will fail (unless you specify a
|
|
26
|
+
* `baseUrl` to a proxy that inserts a valid API key on your behalf).
|
|
29
27
|
*
|
|
30
28
|
* @param {string} account an email address or username
|
|
31
|
-
* @param {object} [
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* @param {string} [breachOptions.domain] a domain by which to filter the
|
|
29
|
+
* @param {object} [options] a configuration object
|
|
30
|
+
* @param {string} [options.apiKey] an API key from
|
|
31
|
+
* https://haveibeenpwned.com/API/Key (default: undefined)
|
|
32
|
+
* @param {string} [options.domain] a domain by which to filter the breach
|
|
36
33
|
* results (default: all domains)
|
|
37
|
-
* @param {boolean} [
|
|
34
|
+
* @param {boolean} [options.truncate] truncate the breach results to only
|
|
38
35
|
* include the name of each breach (default: true)
|
|
39
|
-
* @param {string} [
|
|
36
|
+
* @param {string} [options.baseUrl] a custom base URL for the
|
|
40
37
|
* haveibeenpwned.com API endpoints (default:
|
|
41
38
|
* `https://haveibeenpwned.com/api/v3`)
|
|
42
|
-
* @param {string} [
|
|
39
|
+
* @param {string} [options.userAgent] a custom string to send as the
|
|
43
40
|
* User-Agent field in the request headers (default: `hibp <version>`)
|
|
44
41
|
* @returns {Promise<SearchResults>} a Promise which resolves to an object
|
|
45
42
|
* containing a "breaches" key (which can be null or an array of breach objects)
|
|
46
43
|
* and a "pastes" key (which can be null or an array of paste objects), or
|
|
47
44
|
* rejects with an Error
|
|
48
45
|
* @example
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* // ...
|
|
53
|
-
* } else {
|
|
54
|
-
* // ...
|
|
55
|
-
* }
|
|
56
|
-
* })
|
|
57
|
-
* .catch(err => {
|
|
46
|
+
* try {
|
|
47
|
+
* const data = await search("foo", { apiKey: "my-api-key" });
|
|
48
|
+
* if (data.breaches || data.pastes) {
|
|
58
49
|
* // ...
|
|
59
|
-
* }
|
|
60
|
-
* @example
|
|
61
|
-
* search('nobody@nowhere.com', { apiKey: 'my-api-key', truncate: false })
|
|
62
|
-
* .then(data => {
|
|
63
|
-
* if (data.breaches || data.pastes) {
|
|
64
|
-
* // ...
|
|
65
|
-
* } else {
|
|
66
|
-
* // ...
|
|
67
|
-
* }
|
|
68
|
-
* })
|
|
69
|
-
* .catch(err => {
|
|
50
|
+
* } else {
|
|
70
51
|
* // ...
|
|
52
|
+
* }
|
|
53
|
+
* } catch (err) {
|
|
54
|
+
* // ...
|
|
55
|
+
* }
|
|
56
|
+
* @example
|
|
57
|
+
* try {
|
|
58
|
+
* const data = await search("nobody@nowhere.com", {
|
|
59
|
+
* baseUrl: "https://my-hibp-proxy:8080",
|
|
60
|
+
* truncate: false,
|
|
71
61
|
* });
|
|
72
|
-
*
|
|
62
|
+
* if (data.breaches || data.pastes) {
|
|
63
|
+
* // ...
|
|
64
|
+
* } else {
|
|
65
|
+
* // ...
|
|
66
|
+
* }
|
|
67
|
+
* } catch (err) {
|
|
68
|
+
* // ...
|
|
69
|
+
* }
|
|
73
70
|
* @see https://haveibeenpwned.com/
|
|
74
71
|
*/
|
|
75
|
-
function search(account,
|
|
76
|
-
truncate: true
|
|
77
|
-
}) {
|
|
72
|
+
async function search(account, options = {}) {
|
|
78
73
|
const {
|
|
79
74
|
apiKey,
|
|
75
|
+
domain,
|
|
76
|
+
truncate = true,
|
|
77
|
+
baseUrl,
|
|
78
|
+
userAgent
|
|
79
|
+
} = options;
|
|
80
|
+
const [breaches, pastes] = await Promise.all([breachedAccount.breachedAccount(account, {
|
|
81
|
+
apiKey,
|
|
82
|
+
domain,
|
|
83
|
+
truncate,
|
|
80
84
|
baseUrl,
|
|
81
85
|
userAgent
|
|
82
|
-
}
|
|
83
|
-
return Promise.all([breachedAccount.breachedAccount(account, breachOptions),
|
|
86
|
+
}),
|
|
84
87
|
// This email regex is garbage but it seems to be what the API uses:
|
|
85
88
|
/^.+@.+$/.test(account) ? pasteAccount.pasteAccount(account, {
|
|
86
89
|
apiKey,
|
|
87
90
|
baseUrl,
|
|
88
91
|
userAgent
|
|
89
|
-
}) : null])
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}));
|
|
92
|
+
}) : null]);
|
|
93
|
+
return {
|
|
94
|
+
breaches,
|
|
95
|
+
pastes
|
|
96
|
+
};
|
|
95
97
|
}
|
|
96
98
|
exports.search = search;
|
|
97
|
-
//# sourceMappingURL=search.
|
|
99
|
+
//# sourceMappingURL=search.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.cjs","sources":["../../src/search.ts"],"sourcesContent":["import type { Breach, Paste } from './api/haveibeenpwned/types.js';\nimport { breachedAccount } from './breached-account.js';\nimport { pasteAccount } from './paste-account.js';\n\nexport interface SearchResults {\n breaches: Breach[] | null;\n pastes: Paste[] | null;\n}\n\n/**\n * An object representing search results.\n *\n * @typedef {object} SearchResults\n * @property {(Breach[] | null)} breaches\n * @property {(Paste[] | null)} pastes\n */\n\n/**\n * Fetches all breaches and all pastes associated with the provided account\n * (email address or username). Note that the remote API does not support\n * querying pastes by username (only email addresses), so in the event the\n * provided account is not a valid email address, only breach data is queried\n * and the \"pastes\" field of the resulting object will always be null. This is\n * exactly how searching via the current web interface behaves, which this\n * convenience method is designed to mimic.\n *\n * 🔑 `haveibeenpwned.com` requires an API key from\n * https://haveibeenpwned.com/API/Key for the `breachedaccount` and\n * `pasteaccount` endpoints. The `apiKey` option here is not explicitly\n * required, but direct requests made without it will fail (unless you specify a\n * `baseUrl` to a proxy that inserts a valid API key on your behalf).\n *\n * @param {string} account an email address or username\n * @param {object} [options] a configuration object\n * @param {string} [options.apiKey] an API key from\n * https://haveibeenpwned.com/API/Key (default: undefined)\n * @param {string} [options.domain] a domain by which to filter the breach\n * results (default: all domains)\n * @param {boolean} [options.truncate] truncate the breach results to only\n * include the name of each breach (default: true)\n * @param {string} [options.baseUrl] a custom base URL for the\n * haveibeenpwned.com API endpoints (default:\n * `https://haveibeenpwned.com/api/v3`)\n * @param {string} [options.userAgent] a custom string to send as the\n * User-Agent field in the request headers (default: `hibp <version>`)\n * @returns {Promise<SearchResults>} a Promise which resolves to an object\n * containing a \"breaches\" key (which can be null or an array of breach objects)\n * and a \"pastes\" key (which can be null or an array of paste objects), or\n * rejects with an Error\n * @example\n * try {\n * const data = await search(\"foo\", { apiKey: \"my-api-key\" });\n * if (data.breaches || data.pastes) {\n * // ...\n * } else {\n * // ...\n * }\n * } catch (err) {\n * // ...\n * }\n * @example\n * try {\n * const data = await search(\"nobody@nowhere.com\", {\n * baseUrl: \"https://my-hibp-proxy:8080\",\n * truncate: false,\n * });\n * if (data.breaches || data.pastes) {\n * // ...\n * } else {\n * // ...\n * }\n * } catch (err) {\n * // ...\n * }\n * @see https://haveibeenpwned.com/\n */\nexport async function search(\n account: string,\n options: {\n /**\n * an API key from https://haveibeenpwned.com/API/Key (default: undefined)\n */\n apiKey?: string;\n /**\n * a domain by which to filter the results (default: all domains)\n */\n domain?: string;\n /**\n * truncate the results to only include the name of each breach (default:\n * true)\n */\n truncate?: boolean;\n /**\n * a custom base URL for the haveibeenpwned.com API endpoints (default:\n * `https://haveibeenpwned.com/api/v3`)\n */\n baseUrl?: string;\n /**\n * a custom string to send as the User-Agent field in the request headers\n * (default: `hibp <version>`)\n */\n userAgent?: string;\n } = {},\n): Promise<SearchResults> {\n const { apiKey, domain, truncate = true, baseUrl, userAgent } = options;\n\n const [breaches, pastes] = await Promise.all([\n breachedAccount(account, { apiKey, domain, truncate, baseUrl, userAgent }),\n // This email regex is garbage but it seems to be what the API uses:\n /^.+@.+$/.test(account)\n ? pasteAccount(account, { apiKey, baseUrl, userAgent })\n : null,\n ]);\n\n return { breaches, pastes };\n}\n"],"names":["search","account","options","apiKey","domain","truncate","baseUrl","userAgent","breaches","pastes","Promise","all","breachedAccount","test","pasteAccount"],"mappings":";;;;;AASA;;;;;;AAMG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0DG;AACI,eAAeA,MAAMA,CAC1BC,OAAe,EACfC,UAwBI,EAAE,EAAA;EAEN,MAAM;IAAEC,MAAM;IAAEC,MAAM;IAAEC,QAAQ,GAAG,IAAI;IAAEC,OAAO;IAAEC;EAAW,CAAA,GAAGL,OAAO;EAEvE,MAAM,CAACM,QAAQ,EAAEC,MAAM,CAAC,GAAG,MAAMC,OAAO,CAACC,GAAG,CAAC,CAC3CC,eAAe,CAAAA,eAAA,CAACX,OAAO,EAAE;IAAEE,MAAM;IAAEC,MAAM;IAAEC,QAAQ;IAAEC,OAAO;IAAEC;GAAW,CAAC;;EAE1E,SAAS,CAACM,IAAI,CAACZ,OAAO,CAAC,GACnBa,YAAAA,CAAAA,YAAY,CAACb,OAAO,EAAE;IAAEE,MAAM;IAAEG,OAAO;IAAEC;EAAS,CAAE,CAAC,GACrD,IAAI,CACT,CAAC;EAEF,OAAO;IAAEC,QAAQ;IAAEC;GAAQ;AAC7B;"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var fetchFromApi = /*#__PURE__*/require('./api/haveibeenpwned/fetch-from-api.cjs');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* An object representing the status of your HIBP subscription.
|
|
7
|
+
*
|
|
8
|
+
* @typedef {object} SubscriptionStatus
|
|
9
|
+
* @property {string} SubscriptionName
|
|
10
|
+
* @property {string} Description
|
|
11
|
+
* @property {string} SubscribedUntil
|
|
12
|
+
* @property {number} Rpm
|
|
13
|
+
* @property {number} DomainSearchMaxBreachedAccounts
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Fetches the current status of your HIBP subscription (API key).
|
|
17
|
+
*
|
|
18
|
+
* 🔑 `haveibeenpwned.com` requires an API key from
|
|
19
|
+
* https://haveibeenpwned.com/API/Key for the `subscription/status` endpoint.
|
|
20
|
+
* The `apiKey` option here is not explicitly required, but direct requests made
|
|
21
|
+
* without it will fail (unless you specify a `baseUrl` to a proxy that inserts
|
|
22
|
+
* a valid API key on your behalf).
|
|
23
|
+
*
|
|
24
|
+
* @param {object} [options] a configuration object
|
|
25
|
+
* @param {string} [options.apiKey] an API key from
|
|
26
|
+
* https://haveibeenpwned.com/API/Key (default: undefined)
|
|
27
|
+
* @param {string} [options.baseUrl] a custom base URL for the
|
|
28
|
+
* haveibeenpwned.com API endpoints (default:
|
|
29
|
+
* `https://haveibeenpwned.com/api/v3`)
|
|
30
|
+
* @param {string} [options.userAgent] a custom string to send as the User-Agent
|
|
31
|
+
* field in the request headers (default: `hibp <version>`)
|
|
32
|
+
* @returns {Promise<SubscriptionStatus>} a Promise which resolves to a
|
|
33
|
+
* subscription status object, or rejects with an Error
|
|
34
|
+
* @example
|
|
35
|
+
* try {
|
|
36
|
+
* const data = await subscriptionStatus({ apiKey: "my-api-key" });
|
|
37
|
+
* // ...
|
|
38
|
+
* } catch (err) {
|
|
39
|
+
* // ...
|
|
40
|
+
* }
|
|
41
|
+
* @example
|
|
42
|
+
* try {
|
|
43
|
+
* const data = await subscriptionStatus({
|
|
44
|
+
* baseUrl: "https://my-hibp-proxy:8080",
|
|
45
|
+
* });
|
|
46
|
+
* // ...
|
|
47
|
+
* } catch (err) {
|
|
48
|
+
* // ...
|
|
49
|
+
* }
|
|
50
|
+
*/
|
|
51
|
+
async function subscriptionStatus(options = {}) {
|
|
52
|
+
const endpoint = '/subscription/status';
|
|
53
|
+
return fetchFromApi.fetchFromApi(endpoint, options);
|
|
54
|
+
}
|
|
55
|
+
exports.subscriptionStatus = subscriptionStatus;
|
|
56
|
+
//# sourceMappingURL=subscription-status.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscription-status.cjs","sources":["../../src/subscription-status.ts"],"sourcesContent":["import type { SubscriptionStatus } from './api/haveibeenpwned/types.js';\nimport { fetchFromApi } from './api/haveibeenpwned/fetch-from-api.js';\n\n/**\n * An object representing the status of your HIBP subscription.\n *\n * @typedef {object} SubscriptionStatus\n * @property {string} SubscriptionName\n * @property {string} Description\n * @property {string} SubscribedUntil\n * @property {number} Rpm\n * @property {number} DomainSearchMaxBreachedAccounts\n */\n\n/**\n * Fetches the current status of your HIBP subscription (API key).\n *\n * 🔑 `haveibeenpwned.com` requires an API key from\n * https://haveibeenpwned.com/API/Key for the `subscription/status` endpoint.\n * The `apiKey` option here is not explicitly required, but direct requests made\n * without it will fail (unless you specify a `baseUrl` to a proxy that inserts\n * a valid API key on your behalf).\n *\n * @param {object} [options] a configuration object\n * @param {string} [options.apiKey] an API key from\n * https://haveibeenpwned.com/API/Key (default: undefined)\n * @param {string} [options.baseUrl] a custom base URL for the\n * haveibeenpwned.com API endpoints (default:\n * `https://haveibeenpwned.com/api/v3`)\n * @param {string} [options.userAgent] a custom string to send as the User-Agent\n * field in the request headers (default: `hibp <version>`)\n * @returns {Promise<SubscriptionStatus>} a Promise which resolves to a\n * subscription status object, or rejects with an Error\n * @example\n * try {\n * const data = await subscriptionStatus({ apiKey: \"my-api-key\" });\n * // ...\n * } catch (err) {\n * // ...\n * }\n * @example\n * try {\n * const data = await subscriptionStatus({\n * baseUrl: \"https://my-hibp-proxy:8080\",\n * });\n * // ...\n * } catch (err) {\n * // ...\n * }\n */\nexport async function subscriptionStatus(\n options: {\n /**\n * an API key from https://haveibeenpwned.com/API/Key (default: undefined)\n */\n apiKey?: string;\n /**\n * a custom base URL for the haveibeenpwned.com API endpoints (default:\n * `https://haveibeenpwned.com/api/v3`)\n */\n baseUrl?: string;\n /**\n * a custom string to send as the User-Agent field in the request headers\n * (default: `hibp <version>`)\n */\n userAgent?: string;\n } = {},\n) {\n const endpoint = '/subscription/status';\n\n return fetchFromApi(endpoint, options) as Promise<SubscriptionStatus>;\n}\n"],"names":["subscriptionStatus","options","endpoint","fetchFromApi"],"mappings":";;;;AAGA;;;;;;;;;AASG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCG;AACI,eAAeA,kBAAkBA,CACtCC,UAeI,EAAE,EAAA;EAEN,MAAMC,QAAQ,GAAG,sBAAsB;EAEvC,OAAOC,YAAY,CAAAA,YAAA,CAACD,QAAQ,EAAED,OAAO,CAAgC;AACvE;"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/* eslint-disable global-require */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
3
|
+
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
4
|
+
// This can probably be removed in favor of Node's native fetch once we drop
|
|
5
|
+
// support for v18. https://x.com/ebey_jacob/status/1709975146939973909?s=20
|
|
6
|
+
function installUndiciOnNode18() {
|
|
7
|
+
if (typeof process !== 'undefined' && process.versions.node.startsWith('18.')) {
|
|
8
|
+
const {
|
|
9
|
+
File: UndiciFile,
|
|
10
|
+
fetch: undiciFetch,
|
|
11
|
+
FormData: UndiciFormData,
|
|
12
|
+
Headers: UndiciHeaders,
|
|
13
|
+
Request: UndiciRequest,
|
|
14
|
+
Response: UndiciResponse
|
|
15
|
+
} = require('undici');
|
|
16
|
+
global.File = UndiciFile;
|
|
17
|
+
global.Headers = UndiciHeaders;
|
|
18
|
+
global.Request = UndiciRequest;
|
|
19
|
+
global.Response = UndiciResponse;
|
|
20
|
+
global.fetch = undiciFetch;
|
|
21
|
+
global.FormData = UndiciFormData;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export { installUndiciOnNode18 };
|
|
25
|
+
//# sourceMappingURL=fetch-polyfill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch-polyfill.js","sources":["../../../src/api/fetch-polyfill.ts"],"sourcesContent":["/* eslint-disable global-require */\n/* eslint-disable @typescript-eslint/no-var-requires */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n\n// This can probably be removed in favor of Node's native fetch once we drop\n// support for v18. https://x.com/ebey_jacob/status/1709975146939973909?s=20\n\nexport function installUndiciOnNode18() {\n if (\n typeof process !== 'undefined' &&\n process.versions.node.startsWith('18.')\n ) {\n const {\n File: UndiciFile,\n fetch: undiciFetch,\n FormData: UndiciFormData,\n Headers: UndiciHeaders,\n Request: UndiciRequest,\n Response: UndiciResponse,\n } = require('undici');\n global.File = UndiciFile as unknown as typeof File;\n global.Headers = UndiciHeaders;\n global.Request = UndiciRequest;\n global.Response = UndiciResponse;\n global.fetch = undiciFetch;\n global.FormData = UndiciFormData;\n }\n}\n"],"names":["installUndiciOnNode18","process","versions","node","startsWith","File","UndiciFile","fetch","undiciFetch","FormData","UndiciFormData","Headers","UndiciHeaders","Request","UndiciRequest","Response","UndiciResponse","require","global"],"mappings":"AAAA;AACA;AACA;AAEA;AACA;SAEgBA,qBAAqBA,CAAA,EAAA;EACnC,IACE,OAAOC,OAAO,KAAK,WAAW,IAC9BA,OAAO,CAACC,QAAQ,CAACC,IAAI,CAACC,UAAU,CAAC,KAAK,CAAC,EACvC;IACA,MAAM;MACJC,IAAI,EAAEC,UAAU;MAChBC,KAAK,EAAEC,WAAW;MAClBC,QAAQ,EAAEC,cAAc;MACxBC,OAAO,EAAEC,aAAa;MACtBC,OAAO,EAAEC,aAAa;MACtBC,QAAQ,EAAEC;IAAc,CACzB,GAAGC,OAAO,CAAC,QAAQ,CAAC;IACrBC,MAAM,CAACb,IAAI,GAAGC,UAAoC;IAClDY,MAAM,CAACP,OAAO,GAAGC,aAAa;IAC9BM,MAAM,CAACL,OAAO,GAAGC,aAAa;IAC9BI,MAAM,CAACH,QAAQ,GAAGC,cAAc;IAChCE,MAAM,CAACX,KAAK,GAAGC,WAAW;IAC1BU,MAAM,CAACT,QAAQ,GAAGC,cAAc;EACjC;AACH;"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import { TOO_MANY_REQUESTS, NOT_FOUND, FORBIDDEN, UNAUTHORIZED, BAD_REQUEST } from './responses.
|
|
4
|
-
|
|
1
|
+
import { name, version } from '../../package.json.js';
|
|
2
|
+
import { installUndiciOnNode18 } from '../fetch-polyfill.js';
|
|
3
|
+
import { TOO_MANY_REQUESTS, NOT_FOUND, FORBIDDEN, UNAUTHORIZED, BAD_REQUEST } from './responses.js';
|
|
4
|
+
installUndiciOnNode18();
|
|
5
5
|
/**
|
|
6
6
|
* Custom error thrown when the haveibeenpwned.com API responds with 429 Too
|
|
7
7
|
* Many Requests. See the `retryAfterSeconds` property for the number of seconds
|
|
@@ -19,10 +19,9 @@ class RateLimitError extends Error {
|
|
|
19
19
|
constructor(retryAfter, message, options) {
|
|
20
20
|
super(message, options);
|
|
21
21
|
this.name = this.constructor.name;
|
|
22
|
-
this.retryAfterSeconds = typeof retryAfter === 'string' ? Number.parseInt(retryAfter, 10) /* c8 ignore start */ : undefined;
|
|
22
|
+
this.retryAfterSeconds = typeof retryAfter === 'string' ? Number.parseInt(retryAfter, 10) /* c8 ignore start */ : undefined; /* c8 ignore stop */
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
-
/* c8 ignore stop */
|
|
26
25
|
function blockedWithRayId(rayId) {
|
|
27
26
|
return `Request blocked, contact haveibeenpwned.com if this continues (Ray ID: ${rayId})`;
|
|
28
27
|
}
|
|
@@ -51,11 +50,12 @@ function blockedWithRayId(rayId) {
|
|
|
51
50
|
* from the query (or null for 404 Not Found responses), or rejects with an
|
|
52
51
|
* Error
|
|
53
52
|
*/
|
|
54
|
-
function fetchFromApi(endpoint, {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
async function fetchFromApi(endpoint, options = {}) {
|
|
54
|
+
const {
|
|
55
|
+
apiKey,
|
|
56
|
+
baseUrl = 'https://haveibeenpwned.com/api/v3',
|
|
57
|
+
userAgent
|
|
58
|
+
} = options;
|
|
59
59
|
const headers = {};
|
|
60
60
|
if (apiKey) {
|
|
61
61
|
headers['HIBP-API-Key'] = apiKey;
|
|
@@ -71,34 +71,39 @@ function fetchFromApi(endpoint, {
|
|
|
71
71
|
headers
|
|
72
72
|
};
|
|
73
73
|
const url = `${baseUrl.replace(/\/$/g, '')}${endpoint}`;
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
const response = await fetch(url, config);
|
|
75
|
+
if (response.ok) return response.json();
|
|
76
|
+
switch (response.status) {
|
|
77
|
+
case BAD_REQUEST.status:
|
|
78
|
+
{
|
|
78
79
|
throw new Error(BAD_REQUEST.statusText);
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
80
|
+
}
|
|
81
|
+
case UNAUTHORIZED.status:
|
|
82
|
+
{
|
|
83
|
+
const body = await response.json();
|
|
84
|
+
throw new Error(body.message);
|
|
85
|
+
}
|
|
86
|
+
case FORBIDDEN.status:
|
|
87
|
+
{
|
|
88
|
+
const rayId = response.headers.get('cf-ray');
|
|
89
|
+
if (rayId) throw new Error(blockedWithRayId(rayId));
|
|
90
|
+
throw new Error(FORBIDDEN.statusText);
|
|
91
|
+
}
|
|
92
|
+
case NOT_FOUND.status:
|
|
93
|
+
{
|
|
92
94
|
return null;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
95
|
+
}
|
|
96
|
+
case TOO_MANY_REQUESTS.status:
|
|
97
|
+
{
|
|
98
|
+
const body = await response.json();
|
|
99
|
+
const retryAfter = response.headers.get('retry-after');
|
|
100
|
+
throw new RateLimitError(retryAfter, body.message);
|
|
101
|
+
}
|
|
102
|
+
default:
|
|
103
|
+
{
|
|
104
|
+
throw new Error(response.statusText);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
102
107
|
}
|
|
103
108
|
export { RateLimitError, fetchFromApi };
|
|
104
|
-
//# sourceMappingURL=
|
|
109
|
+
//# sourceMappingURL=fetch-from-api.js.map
|