hibp 0.0.0-dev.0e634825

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.
Files changed (81) hide show
  1. package/API.md +508 -0
  2. package/CHANGELOG.md +17 -0
  3. package/LICENSE.txt +22 -0
  4. package/MIGRATION.md +227 -0
  5. package/README.md +255 -0
  6. package/dist/browser/hibp.module.js +2 -0
  7. package/dist/browser/hibp.module.js.map +1 -0
  8. package/dist/browser/hibp.umd.js +2 -0
  9. package/dist/browser/hibp.umd.js.map +1 -0
  10. package/dist/cjs/api/haveibeenpwned/fetchFromApi.js +107 -0
  11. package/dist/cjs/api/haveibeenpwned/fetchFromApi.js.map +1 -0
  12. package/dist/cjs/api/haveibeenpwned/index.js +6 -0
  13. package/dist/cjs/api/haveibeenpwned/index.js.map +1 -0
  14. package/dist/cjs/api/haveibeenpwned/responses.js +79 -0
  15. package/dist/cjs/api/haveibeenpwned/responses.js.map +1 -0
  16. package/dist/cjs/api/pwnedpasswords/fetchFromApi.js +44 -0
  17. package/dist/cjs/api/pwnedpasswords/fetchFromApi.js.map +1 -0
  18. package/dist/cjs/api/pwnedpasswords/index.js +5 -0
  19. package/dist/cjs/api/pwnedpasswords/index.js.map +1 -0
  20. package/dist/cjs/api/pwnedpasswords/responses.js +20 -0
  21. package/dist/cjs/api/pwnedpasswords/responses.js.map +1 -0
  22. package/dist/cjs/api/web-fetch.js +14 -0
  23. package/dist/cjs/api/web-fetch.js.map +1 -0
  24. package/dist/cjs/breach.js +55 -0
  25. package/dist/cjs/breach.js.map +1 -0
  26. package/dist/cjs/breachedAccount.js +101 -0
  27. package/dist/cjs/breachedAccount.js.map +1 -0
  28. package/dist/cjs/breaches.js +55 -0
  29. package/dist/cjs/breaches.js.map +1 -0
  30. package/dist/cjs/dataClasses.js +34 -0
  31. package/dist/cjs/dataClasses.js.map +1 -0
  32. package/dist/cjs/hibp.d.ts +480 -0
  33. package/dist/cjs/hibp.js +21 -0
  34. package/dist/cjs/hibp.js.map +1 -0
  35. package/dist/cjs/package.json.js +7 -0
  36. package/dist/cjs/package.json.js.map +1 -0
  37. package/dist/cjs/pasteAccount.js +59 -0
  38. package/dist/cjs/pasteAccount.js.map +1 -0
  39. package/dist/cjs/pwnedPassword.js +45 -0
  40. package/dist/cjs/pwnedPassword.js.map +1 -0
  41. package/dist/cjs/pwnedPasswordRange.js +63 -0
  42. package/dist/cjs/pwnedPasswordRange.js.map +1 -0
  43. package/dist/cjs/search.js +97 -0
  44. package/dist/cjs/search.js.map +1 -0
  45. package/dist/esm/api/haveibeenpwned/fetchFromApi.mjs +104 -0
  46. package/dist/esm/api/haveibeenpwned/fetchFromApi.mjs.map +1 -0
  47. package/dist/esm/api/haveibeenpwned/index.mjs +2 -0
  48. package/dist/esm/api/haveibeenpwned/index.mjs.map +1 -0
  49. package/dist/esm/api/haveibeenpwned/responses.mjs +71 -0
  50. package/dist/esm/api/haveibeenpwned/responses.mjs.map +1 -0
  51. package/dist/esm/api/pwnedpasswords/fetchFromApi.mjs +42 -0
  52. package/dist/esm/api/pwnedpasswords/fetchFromApi.mjs.map +1 -0
  53. package/dist/esm/api/pwnedpasswords/index.mjs +2 -0
  54. package/dist/esm/api/pwnedpasswords/index.mjs.map +1 -0
  55. package/dist/esm/api/pwnedpasswords/responses.mjs +17 -0
  56. package/dist/esm/api/pwnedpasswords/responses.mjs.map +1 -0
  57. package/dist/esm/api/web-fetch.mjs +10 -0
  58. package/dist/esm/api/web-fetch.mjs.map +1 -0
  59. package/dist/esm/breach.mjs +53 -0
  60. package/dist/esm/breach.mjs.map +1 -0
  61. package/dist/esm/breachedAccount.mjs +99 -0
  62. package/dist/esm/breachedAccount.mjs.map +1 -0
  63. package/dist/esm/breaches.mjs +53 -0
  64. package/dist/esm/breaches.mjs.map +1 -0
  65. package/dist/esm/dataClasses.mjs +32 -0
  66. package/dist/esm/dataClasses.mjs.map +1 -0
  67. package/dist/esm/hibp.d.mts +480 -0
  68. package/dist/esm/hibp.mjs +10 -0
  69. package/dist/esm/hibp.mjs.map +1 -0
  70. package/dist/esm/package.json.mjs +4 -0
  71. package/dist/esm/package.json.mjs.map +1 -0
  72. package/dist/esm/pasteAccount.mjs +57 -0
  73. package/dist/esm/pasteAccount.mjs.map +1 -0
  74. package/dist/esm/pwnedPassword.mjs +43 -0
  75. package/dist/esm/pwnedPassword.mjs.map +1 -0
  76. package/dist/esm/pwnedPasswordRange.mjs +61 -0
  77. package/dist/esm/pwnedPasswordRange.mjs.map +1 -0
  78. package/dist/esm/search.mjs +95 -0
  79. package/dist/esm/search.mjs.map +1 -0
  80. package/example/runkit.js +16 -0
  81. package/package.json +138 -0
@@ -0,0 +1,63 @@
1
+ 'use strict';
2
+
3
+ var fetchFromApi = /*#__PURE__*/require('./api/pwnedpasswords/fetchFromApi.js');
4
+
5
+ /**
6
+ * An object mapping an exposed password hash suffix (corresponding to a given
7
+ * hash prefix) to how many times it occurred in the Pwned Passwords repository.
8
+ *
9
+ * @typedef {Object.<string, number>} PwnedPasswordSuffixes
10
+ */
11
+ /**
12
+ * Fetches the SHA-1 hash suffixes for the given 5-character SHA-1 hash prefix.
13
+ *
14
+ * When a password hash with the same first 5 characters is found in the Pwned
15
+ * Passwords repository, the API will respond with an HTTP 200 and include the
16
+ * suffix of every hash beginning with the specified prefix, followed by a count
17
+ * of how many times it appears in the data set. This function parses the
18
+ * response and returns a more structured format.
19
+ *
20
+ * @param {string} prefix the first 5 characters of a SHA-1 password hash (case
21
+ * insensitive)
22
+ * @param {object} [options] a configuration object
23
+ * @param {string} [options.baseUrl] a custom base URL for the
24
+ * pwnedpasswords.com API endpoints (default: `https://api.pwnedpasswords.com`)
25
+ * @param {string} [options.userAgent] a custom string to send as the User-Agent
26
+ * field in the request headers (default: `hibp <version>`)
27
+ * @returns {Promise<PwnedPasswordSuffixes>} a Promise which resolves to an
28
+ * object mapping the `suffix` that when matched with the prefix composes the
29
+ * complete hash, to the `count` of how many times it appears in the breached
30
+ * password data set, or rejects with an Error
31
+ *
32
+ * @example
33
+ * pwnedPasswordRange('5BAA6')
34
+ * .then(results => {
35
+ * // results will have the following shape:
36
+ * // {
37
+ * // "003D68EB55068C33ACE09247EE4C639306B": 3,
38
+ * // "012C192B2F16F82EA0EB9EF18D9D539B0DD": 1,
39
+ * // ...
40
+ * // }
41
+ * })
42
+ * @example
43
+ * const suffix = '1E4C9B93F3F0682250B6CF8331B7EE68FD8';
44
+ * pwnedPasswordRange('5BAA6')
45
+ * .then(results => (results[suffix] || 0))
46
+ * .catch(err => {
47
+ * // ...
48
+ * });
49
+ * @see https://haveibeenpwned.com/api/v3#SearchingPwnedPasswordsByRange
50
+ */
51
+ function pwnedPasswordRange(prefix, options = {}) {
52
+ return fetchFromApi.fetchFromApi(`/range/${encodeURIComponent(prefix)}`, options)
53
+ // create array from lines of text in response body
54
+ .then(data => data.split('\n').filter(Boolean))
55
+ // convert into an object mapping suffix to count for each line
56
+ .then(results => results.reduce((acc, row) => {
57
+ const [suffix, countString] = row.split(':');
58
+ acc[suffix] = parseInt(countString, 10);
59
+ return acc;
60
+ }, {}));
61
+ }
62
+ exports.pwnedPasswordRange = pwnedPasswordRange;
63
+ //# sourceMappingURL=pwnedPasswordRange.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pwnedPasswordRange.js","sources":["../../src/pwnedPasswordRange.ts"],"sourcesContent":["import { fetchFromApi } from './api/pwnedpasswords';\n\nexport interface PwnedPasswordSuffixes {\n [suffix: string]: number;\n}\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 hash suffixes for the given 5-character SHA-1 hash 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 SHA-1 password hash (case\n * insensitive)\n * @param {object} [options] a configuration object\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 * pwnedPasswordRange('5BAA6')\n * .then(results => {\n * // results will have the following shape:\n * // {\n * // \"003D68EB55068C33ACE09247EE4C639306B\": 3,\n * // \"012C192B2F16F82EA0EB9EF18D9D539B0DD\": 1,\n * // ...\n * // }\n * })\n * @example\n * const suffix = '1E4C9B93F3F0682250B6CF8331B7EE68FD8';\n * pwnedPasswordRange('5BAA6')\n * .then(results => (results[suffix] || 0))\n * .catch(err => {\n * // ...\n * });\n * @see https://haveibeenpwned.com/api/v3#SearchingPwnedPasswordsByRange\n */\nexport function pwnedPasswordRange(\n prefix: string,\n options: { baseUrl?: string; userAgent?: string } = {},\n): Promise<PwnedPasswordSuffixes> {\n return (\n fetchFromApi(`/range/${encodeURIComponent(prefix)}`, options)\n // create array from lines of text in response body\n .then((data) => data.split('\\n').filter(Boolean))\n // convert into an object mapping suffix to count for each line\n .then((results) =>\n results.reduce<PwnedPasswordSuffixes>((acc, row) => {\n const [suffix, countString] = row.split(':');\n acc[suffix] = parseInt(countString, 10);\n return acc;\n }, {}),\n )\n );\n}\n"],"names":["pwnedPasswordRange","prefix","options","fetchFromApi","encodeURIComponent","then","data","split","filter","Boolean","results","reduce","acc","row","suffix","countString","parseInt"],"mappings":";;;;AAMA;;;;;AAKG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCG;SACaA,kBAAkBA,CAChCC,MAAc,EACdC,UAAoD,EAAE,EAAA;EAEtD,OACEC,YAAAA,CAAAA,YAAY,CAAW,UAAAC,kBAAkB,CAACH,MAAM,CAAC,EAAE,EAAEC,OAAO;;GAEzDG,IAAI,CAAEC,IAAI,IAAKA,IAAI,CAACC,KAAK,CAAC,IAAI,CAAC,CAACC,MAAM,CAACC,OAAO,CAAC;;GAE/CJ,IAAI,CAAEK,OAAO,IACZA,OAAO,CAACC,MAAM,CAAwB,CAACC,GAAG,EAAEC,GAAG,KAAI;IACjD,MAAM,CAACC,MAAM,EAAEC,WAAW,CAAC,GAAGF,GAAG,CAACN,KAAK,CAAC,GAAG,CAAC;IAC5CK,GAAG,CAACE,MAAM,CAAC,GAAGE,QAAQ,CAACD,WAAW,EAAE,EAAE,CAAC;IACvC,OAAOH,GAAG;EACZ,CAAC,EAAE,CAAA,CAAE,CAAC,CACP;AAEP;"}
@@ -0,0 +1,97 @@
1
+ 'use strict';
2
+
3
+ var breachedAccount = /*#__PURE__*/require('./breachedAccount.js');
4
+ var pasteAccount = /*#__PURE__*/require('./pasteAccount.js');
5
+
6
+ /**
7
+ * An object representing search results.
8
+ *
9
+ * @typedef {object} SearchResults
10
+ * @property {(Breach[] | null)} breaches
11
+ * @property {(Paste[] | null)} pastes
12
+ */
13
+ /**
14
+ * Fetches all breaches and all pastes associated with the provided account
15
+ * (email address or username). Note that the remote API does not support
16
+ * querying pastes by username (only email addresses), so in the event the
17
+ * provided account is not a valid email address, only breach data is queried
18
+ * and the "pastes" field of the resulting object will always be null. This is
19
+ * exactly how searching via the current web interface behaves, which this
20
+ * convenience method is designed to mimic.
21
+ *
22
+ * ***Warning (July 18, 2019):***
23
+ *
24
+ * `haveibeenpwned.com` now requires an API key from
25
+ * https://haveibeenpwned.com/API/Key for the `breachedaccount` and
26
+ * `pasteaccount` endpoints. The `apiKey` option here is not explicitly
27
+ * required, but direct requests made without it (that is, without specifying a
28
+ * `baseUrl` to a proxy that inserts a valid API key on your behalf) will fail.
29
+ *
30
+ * @param {string} account an email address or username
31
+ * @param {object} [breachOptions] a configuration object pertaining to breach
32
+ * queries
33
+ * @param {string} [breachOptions.apiKey] an API key from
34
+ * https://haveibeenpwned.com/API/Key
35
+ * @param {string} [breachOptions.domain] a domain by which to filter the
36
+ * results (default: all domains)
37
+ * @param {boolean} [breachOptions.truncate] truncate the results to only
38
+ * include the name of each breach (default: true)
39
+ * @param {string} [breachOptions.baseUrl] a custom base URL for the
40
+ * haveibeenpwned.com API endpoints (default:
41
+ * `https://haveibeenpwned.com/api/v3`)
42
+ * @param {string} [breachOptions.userAgent] a custom string to send as the
43
+ * User-Agent field in the request headers (default: `hibp <version>`)
44
+ * @returns {Promise<SearchResults>} a Promise which resolves to an object
45
+ * containing a "breaches" key (which can be null or an array of breach objects)
46
+ * and a "pastes" key (which can be null or an array of paste objects), or
47
+ * rejects with an Error
48
+ * @example
49
+ * search('foo', { apiKey: 'my-api-key' })
50
+ * .then(data => {
51
+ * if (data.breaches || data.pastes) {
52
+ * // ...
53
+ * } else {
54
+ * // ...
55
+ * }
56
+ * })
57
+ * .catch(err => {
58
+ * // ...
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 => {
70
+ * // ...
71
+ * });
72
+ *
73
+ * @see https://haveibeenpwned.com/
74
+ */
75
+ function search(account, breachOptions = {
76
+ truncate: true
77
+ }) {
78
+ const {
79
+ apiKey,
80
+ baseUrl,
81
+ userAgent
82
+ } = breachOptions;
83
+ return Promise.all([breachedAccount.breachedAccount(account, breachOptions),
84
+ // This email regex is garbage but it seems to be what the API uses:
85
+ /^.+@.+$/.test(account) ? pasteAccount.pasteAccount(account, {
86
+ apiKey,
87
+ baseUrl,
88
+ userAgent
89
+ }) : null]).then(
90
+ // Avoid array destructuring here to prevent need for Babel helpers
91
+ promises => ({
92
+ breaches: promises[0],
93
+ pastes: promises[1]
94
+ }));
95
+ }
96
+ exports.search = search;
97
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sources":["../../src/search.ts"],"sourcesContent":["import type { Breach, Paste } from './api/haveibeenpwned/types';\nimport { breachedAccount } from './breachedAccount';\nimport { pasteAccount } from './pasteAccount';\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 * ***Warning (July 18, 2019):***\n *\n * `haveibeenpwned.com` now 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 (that is, without specifying a\n * `baseUrl` to a proxy that inserts a valid API key on your behalf) will fail.\n *\n * @param {string} account an email address or username\n * @param {object} [breachOptions] a configuration object pertaining to breach\n * queries\n * @param {string} [breachOptions.apiKey] an API key from\n * https://haveibeenpwned.com/API/Key\n * @param {string} [breachOptions.domain] a domain by which to filter the\n * results (default: all domains)\n * @param {boolean} [breachOptions.truncate] truncate the results to only\n * include the name of each breach (default: true)\n * @param {string} [breachOptions.baseUrl] a custom base URL for the\n * haveibeenpwned.com API endpoints (default:\n * `https://haveibeenpwned.com/api/v3`)\n * @param {string} [breachOptions.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 * search('foo', { apiKey: 'my-api-key' })\n * .then(data => {\n * if (data.breaches || data.pastes) {\n * // ...\n * } else {\n * // ...\n * }\n * })\n * .catch(err => {\n * // ...\n * });\n * @example\n * search('nobody@nowhere.com', { apiKey: 'my-api-key', truncate: false })\n * .then(data => {\n * if (data.breaches || data.pastes) {\n * // ...\n * } else {\n * // ...\n * }\n * })\n * .catch(err => {\n * // ...\n * });\n *\n * @see https://haveibeenpwned.com/\n */\nexport function search(\n account: string,\n breachOptions: {\n apiKey?: string;\n domain?: string;\n truncate?: boolean;\n baseUrl?: string;\n userAgent?: string;\n } = {\n truncate: true,\n },\n): Promise<SearchResults> {\n const { apiKey, baseUrl, userAgent } = breachOptions;\n\n return Promise.all([\n breachedAccount(account, breachOptions),\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 ]).then(\n // Avoid array destructuring here to prevent need for Babel helpers\n (promises) => ({\n breaches: promises[0],\n pastes: promises[1],\n }),\n );\n}\n"],"names":["search","account","breachOptions","truncate","apiKey","baseUrl","userAgent","Promise","all","breachedAccount","test","pasteAccount","then","promises","breaches","pastes"],"mappings":";;;;;AASA;;;;;;AAMG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6DG;AACa,SAAAA,MAAMA,CACpBC,OAAe,EACfC,aAMI,GAAA;EACFC,QAAQ,EAAE;AACX,CAAA,EAAA;EAED,MAAM;IAAEC,MAAM;IAAEC,OAAO;IAAEC;EAAS,CAAE,GAAGJ,aAAa;EAEpD,OAAOK,OAAO,CAACC,GAAG,CAAC,CACjBC,eAAe,CAAAA,eAAA,CAACR,OAAO,EAAEC,aAAa,CAAC;;EAEvC,SAAS,CAACQ,IAAI,CAACT,OAAO,CAAC,GACnBU,YAAAA,CAAAA,YAAY,CAACV,OAAO,EAAE;IAAEG,MAAM;IAAEC,OAAO;IAAEC;EAAS,CAAE,CAAC,GACrD,IAAI,CACT,CAAC,CAACM,IAAI;;EAEJC,QAAQ,KAAM;IACbC,QAAQ,EAAED,QAAQ,CAAC,CAAC,CAAC;IACrBE,MAAM,EAAEF,QAAQ,CAAC,CAAC;EACnB,CAAA,CAAC,CACH;AACH;"}
@@ -0,0 +1,104 @@
1
+ import fetch from '../web-fetch.mjs';
2
+ import { name, version } from '../../package.json.mjs';
3
+ import { TOO_MANY_REQUESTS, NOT_FOUND, FORBIDDEN, UNAUTHORIZED, BAD_REQUEST } from './responses.mjs';
4
+
5
+ /**
6
+ * Custom error thrown when the haveibeenpwned.com API responds with 429 Too
7
+ * Many Requests. See the `retryAfterSeconds` property for the number of seconds
8
+ * to wait before attempting the request again.
9
+ *
10
+ * @see https://haveibeenpwned.com/API/v3#RateLimiting
11
+ */
12
+ class RateLimitError extends Error {
13
+ /**
14
+ * The number of seconds to wait before attempting the request again. May be
15
+ * `undefined` if the API does not provide a `retry-after` header, but this
16
+ * should never happen.
17
+ */
18
+ retryAfterSeconds;
19
+ constructor(retryAfter, message, options) {
20
+ super(message, options);
21
+ this.name = this.constructor.name;
22
+ this.retryAfterSeconds = typeof retryAfter === 'string' ? Number.parseInt(retryAfter, 10) /* c8 ignore start */ : undefined;
23
+ }
24
+ }
25
+ /* c8 ignore stop */
26
+ function blockedWithRayId(rayId) {
27
+ return `Request blocked, contact haveibeenpwned.com if this continues (Ray ID: ${rayId})`;
28
+ }
29
+ /**
30
+ * Fetches data from the supplied API endpoint.
31
+ *
32
+ * HTTP status code 200 returns an Object (data found).
33
+ * HTTP status code 404 returns null (no data found).
34
+ * HTTP status code 400 throws an Error (bad request).
35
+ * HTTP status code 401 throws an Error (unauthorized).
36
+ * HTTP status code 403 throws an Error (forbidden).
37
+ * HTTP status code 429 throws an Error (too many requests).
38
+ *
39
+ * @internal
40
+ * @private
41
+ * @param {string} endpoint the API endpoint to query
42
+ * @param {object} [options] a configuration object
43
+ * @param {string} [options.apiKey] an API key from
44
+ * https://haveibeenpwned.com/API/Key
45
+ * @param {string} [options.baseUrl] a custom base URL for the
46
+ * haveibeenpwned.com API endpoints (default:
47
+ * `https://haveibeenpwned.com/api/v3`)
48
+ * @param {string} [options.userAgent] a custom string to send as the User-Agent
49
+ * field in the request headers (default: `hibp <version>`)
50
+ * @returns {Promise<ApiData>} a Promise which resolves to the data resulting
51
+ * from the query (or null for 404 Not Found responses), or rejects with an
52
+ * Error
53
+ */
54
+ function fetchFromApi(endpoint, {
55
+ apiKey,
56
+ baseUrl = 'https://haveibeenpwned.com/api/v3',
57
+ userAgent
58
+ } = {}) {
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'] = `${name} ${version}`;
69
+ }
70
+ const config = {
71
+ headers
72
+ };
73
+ const url = `${baseUrl.replace(/\/$/g, '')}${endpoint}`;
74
+ return fetch(url, config).then(res => {
75
+ if (res.ok) return res.json();
76
+ switch (res.status) {
77
+ case BAD_REQUEST.status:
78
+ throw new Error(BAD_REQUEST.statusText);
79
+ case UNAUTHORIZED.status:
80
+ return res.json().then(body => {
81
+ throw new Error(body.message);
82
+ });
83
+ case FORBIDDEN.status:
84
+ {
85
+ const rayId = res.headers.get('cf-ray');
86
+ if (rayId) {
87
+ throw new Error(blockedWithRayId(rayId));
88
+ }
89
+ throw new Error(FORBIDDEN.statusText);
90
+ }
91
+ case NOT_FOUND.status:
92
+ return null;
93
+ case TOO_MANY_REQUESTS.status:
94
+ return res.json().then(body => {
95
+ const retryAfter = res.headers.get('retry-after');
96
+ throw new RateLimitError(retryAfter, body.message);
97
+ });
98
+ default:
99
+ throw new Error(res.statusText);
100
+ }
101
+ });
102
+ }
103
+ export { RateLimitError, fetchFromApi };
104
+ //# sourceMappingURL=fetchFromApi.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetchFromApi.mjs","sources":["../../../../src/api/haveibeenpwned/fetchFromApi.ts"],"sourcesContent":["import fetch from '../web-fetch';\nimport { name, version } from '../../../package.json';\nimport {\n BAD_REQUEST,\n UNAUTHORIZED,\n FORBIDDEN,\n NOT_FOUND,\n TOO_MANY_REQUESTS,\n} from './responses';\nimport type { ApiData, ErrorData } from './types';\n\n/**\n * Custom error thrown when the haveibeenpwned.com API responds with 429 Too\n * Many Requests. See the `retryAfterSeconds` property for the number of seconds\n * to wait before attempting the request again.\n *\n * @see https://haveibeenpwned.com/API/v3#RateLimiting\n */\nexport class RateLimitError extends Error {\n /**\n * The number of seconds to wait before attempting the request again. May be\n * `undefined` if the API does not provide a `retry-after` header, but this\n * should never happen.\n */\n public retryAfterSeconds: number | undefined;\n\n constructor(\n retryAfter: ReturnType<Headers['get']>,\n message: string | undefined,\n options?: ErrorOptions,\n ) {\n super(message, options);\n this.name = this.constructor.name;\n this.retryAfterSeconds =\n typeof retryAfter === 'string'\n ? Number.parseInt(retryAfter, 10) /* c8 ignore start */\n : undefined;\n }\n}\n/* c8 ignore stop */\n\nfunction blockedWithRayId(rayId: string) {\n return `Request blocked, contact haveibeenpwned.com if this continues (Ray ID: ${rayId})`;\n}\n\n/**\n * Fetches data from the supplied API endpoint.\n *\n * HTTP status code 200 returns an Object (data found).\n * HTTP status code 404 returns null (no data found).\n * HTTP status code 400 throws an Error (bad request).\n * HTTP status code 401 throws an Error (unauthorized).\n * HTTP status code 403 throws an Error (forbidden).\n * HTTP status code 429 throws an Error (too many requests).\n *\n * @internal\n * @private\n * @param {string} endpoint the API endpoint to query\n * @param {object} [options] a configuration object\n * @param {string} [options.apiKey] an API key from\n * https://haveibeenpwned.com/API/Key\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<ApiData>} a Promise which resolves to the data resulting\n * from the query (or null for 404 Not Found responses), or rejects with an\n * Error\n */\nexport function fetchFromApi(\n endpoint: string,\n {\n apiKey,\n baseUrl = 'https://haveibeenpwned.com/api/v3',\n userAgent,\n }: { apiKey?: string; baseUrl?: string; userAgent?: string } = {},\n): Promise<ApiData> {\n const headers: Record<string, string> = {};\n\n if (apiKey) {\n headers['HIBP-API-Key'] = apiKey;\n }\n\n if (userAgent) {\n headers['User-Agent'] = userAgent;\n }\n\n // Provide a default User-Agent when running outside the browser\n if (!userAgent && typeof navigator === 'undefined') {\n headers['User-Agent'] = `${name} ${version}`;\n }\n\n const config = { headers };\n const url = `${baseUrl.replace(/\\/$/g, '')}${endpoint}`;\n\n return fetch(url, config).then((res) => {\n if (res.ok) return res.json() as Promise<ApiData>;\n\n switch (res.status) {\n case BAD_REQUEST.status:\n throw new Error(BAD_REQUEST.statusText);\n case UNAUTHORIZED.status:\n return res.json().then((body: ErrorData) => {\n throw new Error(body.message);\n });\n case FORBIDDEN.status: {\n const rayId = res.headers.get('cf-ray');\n if (rayId) {\n throw new Error(blockedWithRayId(rayId));\n }\n throw new Error(FORBIDDEN.statusText);\n }\n case NOT_FOUND.status:\n return null;\n case TOO_MANY_REQUESTS.status:\n return res.json().then((body: ErrorData) => {\n const retryAfter = res.headers.get('retry-after');\n throw new RateLimitError(retryAfter, body.message);\n });\n default:\n throw new Error(res.statusText);\n }\n });\n}\n"],"names":["RateLimitError","Error","retryAfterSeconds","constructor","retryAfter","message","options","name","Number","parseInt","undefined","blockedWithRayId","rayId","fetchFromApi","endpoint","apiKey","baseUrl","userAgent","headers","navigator","version","config","url","replace","fetch","then","res","ok","json","status","BAD_REQUEST","statusText","UNAUTHORIZED","body","FORBIDDEN","get","NOT_FOUND","TOO_MANY_REQUESTS"],"mappings":";;;;AAWA;;;;;;AAMG;AACG,MAAOA,cAAe,SAAQC,KAAK,CAAA;EACvC;;;;AAIG;EACIC,iBAAiB;EAExBC,WAAAA,CACEC,UAAsC,EACtCC,OAA2B,EAC3BC,OAAsB,EAAA;IAEtB,KAAK,CAACD,OAAO,EAAEC,OAAO,CAAC;IACvB,IAAI,CAACC,IAAI,GAAG,IAAI,CAACJ,WAAW,CAACI,IAAI;IACjC,IAAI,CAACL,iBAAiB,GACpB,OAAOE,UAAU,KAAK,QAAQ,GAC1BI,MAAM,CAACC,QAAQ,CAACL,UAAU,EAAE,EAAE,CAAC,CAAA,wBAC/BM,SAAS;EAChB;AACF;AACD;AAEA,SAASC,gBAAgBA,CAACC,KAAa,EAAA;EACrC,OAAO,0EAA0EA,KAAK,GAAG;AAC3F;AAEA;;;;;;;;;;;;;;;;;;;;;;;;AAwBG;AACa,SAAAC,YAAYA,CAC1BC,QAAgB,EAChB;EACEC,MAAM;EACNC,OAAO,GAAG,mCAAmC;EAC7CC;IAC6D,EAAE,EAAA;EAEjE,MAAMC,OAAO,GAA2B,CAAA,CAAE;EAE1C,IAAIH,MAAM,EAAE;IACVG,OAAO,CAAC,cAAc,CAAC,GAAGH,MAAM;EACjC;EAED,IAAIE,SAAS,EAAE;IACbC,OAAO,CAAC,YAAY,CAAC,GAAGD,SAAS;EAClC;;EAGD,IAAI,CAACA,SAAS,IAAI,OAAOE,SAAS,KAAK,WAAW,EAAE;IAClDD,OAAO,CAAC,YAAY,CAAC,MAAMX,IAAI,IAAIa,OAAO,EAAE;EAC7C;EAED,MAAMC,MAAM,GAAG;IAAEH;GAAS;EAC1B,MAAMI,GAAG,GAAM,GAAAN,OAAO,CAACO,OAAO,CAAC,MAAM,EAAE,EAAE,CAAI,GAAAT,UAAU;EAEvD,OAAOU,KAAK,CAACF,GAAG,EAAED,MAAM,CAAC,CAACI,IAAI,CAAEC,GAAG,IAAI;IACrC,IAAIA,GAAG,CAACC,EAAE,EAAE,OAAOD,GAAG,CAACE,IAAI,EAAsB;IAEjD,QAAQF,GAAG,CAACG,MAAM;MAChB,KAAKC,WAAW,CAACD,MAAM;QACrB,MAAM,IAAI5B,KAAK,CAAC6B,WAAW,CAACC,UAAU,CAAC;MACzC,KAAKC,YAAY,CAACH,MAAM;QACtB,OAAOH,GAAG,CAACE,IAAI,EAAE,CAACH,IAAI,CAAEQ,IAAe,IAAI;UACzC,MAAM,IAAIhC,KAAK,CAACgC,IAAI,CAAC5B,OAAO,CAAC;QAC/B,CAAC,CAAC;MACJ,KAAK6B,SAAS,CAACL,MAAM;QAAE;UACrB,MAAMjB,KAAK,GAAGc,GAAG,CAACR,OAAO,CAACiB,GAAG,CAAC,QAAQ,CAAC;UACvC,IAAIvB,KAAK,EAAE;YACT,MAAM,IAAIX,KAAK,CAACU,gBAAgB,CAACC,KAAK,CAAC,CAAC;UACzC;UACD,MAAM,IAAIX,KAAK,CAACiC,SAAS,CAACH,UAAU,CAAC;QACtC;MACD,KAAKK,SAAS,CAACP,MAAM;QACnB,OAAO,IAAI;MACb,KAAKQ,iBAAiB,CAACR,MAAM;QAC3B,OAAOH,GAAG,CAACE,IAAI,EAAE,CAACH,IAAI,CAAEQ,IAAe,IAAI;UACzC,MAAM7B,UAAU,GAAGsB,GAAG,CAACR,OAAO,CAACiB,GAAG,CAAC,aAAa,CAAC;UACjD,MAAM,IAAInC,cAAc,CAACI,UAAU,EAAE6B,IAAI,CAAC5B,OAAO,CAAC;QACpD,CAAC,CAAC;MACJ;QACE,MAAM,IAAIJ,KAAK,CAACyB,GAAG,CAACK,UAAU,CAAC;IAAC;EAEtC,CAAC,CAAC;AACJ;"}
@@ -0,0 +1,2 @@
1
+ export { RateLimitError, fetchFromApi } from './fetchFromApi.mjs';
2
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Known potential responses from the remote API.
3
+ *
4
+ * Unfortunately, the API does not send a decent human-readable message back
5
+ * with each response, but they are documented on the website:
6
+ * https://haveibeenpwned.com/api/v3#ResponseCodes
7
+ *
8
+ * These objects simply provide a mapping between the HTTP response status code
9
+ * and the corresponding human-readable message so we can throw a more
10
+ * descriptive error for the consumer. (They are also leveraged in our tests.)
11
+ */
12
+ const emptyHeaders = /*#__PURE__*/new Map();
13
+ /** @internal */
14
+ const OK = {
15
+ headers: emptyHeaders,
16
+ status: 200
17
+ };
18
+ /** @internal */
19
+ const BAD_REQUEST = {
20
+ headers: emptyHeaders,
21
+ status: 400,
22
+ statusText: 'Bad request — the account does not comply with an acceptable format.'
23
+ };
24
+ /**
25
+ * This response has unique behavior. For some reason, the API includes an
26
+ * object in the response body for this one, containing a human-readable
27
+ * message. Manually populating the message here purely for use in tests.
28
+ *
29
+ * @internal
30
+ */
31
+ const UNAUTHORIZED = {
32
+ headers: emptyHeaders,
33
+ status: 401,
34
+ body: {
35
+ statusCode: 401,
36
+ message: 'Access denied due to missing hibp-api-key.'
37
+ }
38
+ };
39
+ /** @internal */
40
+ const FORBIDDEN = {
41
+ headers: emptyHeaders,
42
+ status: 403,
43
+ statusText: 'Forbidden - access denied.'
44
+ };
45
+ /** @internal */
46
+ const BLOCKED = {
47
+ headers: /*#__PURE__*/new Map([['cf-ray', 'someRayId']]),
48
+ status: 403
49
+ };
50
+ /** @internal */
51
+ const NOT_FOUND = {
52
+ headers: emptyHeaders,
53
+ status: 404
54
+ };
55
+ /**
56
+ * This response has unique behavior. For some reason, the API includes an
57
+ * object in the response body for this one, containing a human-readable
58
+ * message. Manually populating the message here purely for use in tests.
59
+ *
60
+ * @internal
61
+ */
62
+ const TOO_MANY_REQUESTS = {
63
+ headers: /*#__PURE__*/new Map([['retry-after', '2']]),
64
+ status: 429,
65
+ body: {
66
+ statusCode: 429,
67
+ message: 'Rate limit is exceeded. Try again in 2 seconds.'
68
+ }
69
+ };
70
+ export { BAD_REQUEST, BLOCKED, FORBIDDEN, NOT_FOUND, OK, TOO_MANY_REQUESTS, UNAUTHORIZED };
71
+ //# sourceMappingURL=responses.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"responses.mjs","sources":["../../../../src/api/haveibeenpwned/responses.ts"],"sourcesContent":["/**\n * Known potential responses from the remote API.\n *\n * Unfortunately, the API does not send a decent human-readable message back\n * with each response, but they are documented on the website:\n * https://haveibeenpwned.com/api/v3#ResponseCodes\n *\n * These objects simply provide a mapping between the HTTP response status code\n * and the corresponding human-readable message so we can throw a more\n * descriptive error for the consumer. (They are also leveraged in our tests.)\n */\n\nimport type { ResponseBody } from './types';\n\n/** @internal */\nexport interface HaveIBeenPwnedApiResponse {\n headers: Map<string, string>;\n status: number;\n statusText?: string;\n body?: ResponseBody;\n}\n\nconst emptyHeaders = new Map<string, string>();\n\n/** @internal */\nexport const OK: HaveIBeenPwnedApiResponse = {\n headers: emptyHeaders,\n status: 200,\n};\n\n/** @internal */\nexport const BAD_REQUEST: HaveIBeenPwnedApiResponse = {\n headers: emptyHeaders,\n status: 400,\n statusText:\n 'Bad request — the account does not comply with an acceptable format.',\n};\n\n/**\n * This response has unique behavior. For some reason, the API includes an\n * object in the response body for this one, containing a human-readable\n * message. Manually populating the message here purely for use in tests.\n *\n * @internal\n */\nexport const UNAUTHORIZED: HaveIBeenPwnedApiResponse = {\n headers: emptyHeaders,\n status: 401,\n body: {\n statusCode: 401,\n message: 'Access denied due to missing hibp-api-key.',\n },\n};\n\n/** @internal */\nexport const FORBIDDEN: HaveIBeenPwnedApiResponse = {\n headers: emptyHeaders,\n status: 403,\n statusText: 'Forbidden - access denied.',\n};\n\n/** @internal */\nexport const BLOCKED: HaveIBeenPwnedApiResponse = {\n headers: new Map([['cf-ray', 'someRayId']]),\n status: 403,\n};\n\n/** @internal */\nexport const NOT_FOUND: HaveIBeenPwnedApiResponse = {\n headers: emptyHeaders,\n status: 404,\n};\n\n/**\n * This response has unique behavior. For some reason, the API includes an\n * object in the response body for this one, containing a human-readable\n * message. Manually populating the message here purely for use in tests.\n *\n * @internal\n */\nexport const TOO_MANY_REQUESTS: HaveIBeenPwnedApiResponse = {\n headers: new Map([['retry-after', '2']]),\n status: 429,\n body: {\n statusCode: 429,\n message: 'Rate limit is exceeded. Try again in 2 seconds.',\n },\n};\n"],"names":["emptyHeaders","Map","OK","headers","status","BAD_REQUEST","statusText","UNAUTHORIZED","body","statusCode","message","FORBIDDEN","BLOCKED","NOT_FOUND","TOO_MANY_REQUESTS"],"mappings":"AAAA;;;;;;;;;;AAUG;AAYH,MAAMA,YAAY,gBAAG,IAAIC,GAAG,EAAkB;AAE9C;AACa,MAAAC,EAAE,GAA8B;EAC3CC,OAAO,EAAEH,YAAY;EACrBI,MAAM,EAAE;CACR;AAEF;AACa,MAAAC,WAAW,GAA8B;EACpDF,OAAO,EAAEH,YAAY;EACrBI,MAAM,EAAE,GAAG;EACXE,UAAU,EACR;CACF;AAEF;;;;;;AAMG;AACU,MAAAC,YAAY,GAA8B;EACrDJ,OAAO,EAAEH,YAAY;EACrBI,MAAM,EAAE,GAAG;EACXI,IAAI,EAAE;IACJC,UAAU,EAAE,GAAG;IACfC,OAAO,EAAE;EACV;CACD;AAEF;AACa,MAAAC,SAAS,GAA8B;EAClDR,OAAO,EAAEH,YAAY;EACrBI,MAAM,EAAE,GAAG;EACXE,UAAU,EAAE;CACZ;AAEF;AACa,MAAAM,OAAO,GAA8B;EAChDT,OAAO,eAAE,IAAIF,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC;EAC3CG,MAAM,EAAE;CACR;AAEF;AACa,MAAAS,SAAS,GAA8B;EAClDV,OAAO,EAAEH,YAAY;EACrBI,MAAM,EAAE;CACR;AAEF;;;;;;AAMG;AACU,MAAAU,iBAAiB,GAA8B;EAC1DX,OAAO,eAAE,IAAIF,GAAG,CAAC,CAAC,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,CAAC;EACxCG,MAAM,EAAE,GAAG;EACXI,IAAI,EAAE;IACJC,UAAU,EAAE,GAAG;IACfC,OAAO,EAAE;EACV;;"}
@@ -0,0 +1,42 @@
1
+ import fetch from '../web-fetch.mjs';
2
+ import { BAD_REQUEST } from './responses.mjs';
3
+
4
+ /**
5
+ * Fetches data from the supplied API endpoint.
6
+ *
7
+ * HTTP status code 200 returns plain text (data found).
8
+ * HTTP status code 400 throws an Error (bad request).
9
+ *
10
+ * @internal
11
+ * @private
12
+ * @param {string} endpoint the API endpoint to query
13
+ * @param {object} [options] a configuration object
14
+ * @param {string} [options.baseUrl] a custom base URL for the
15
+ * pwnedpasswords.com API endpoints (default: `https://api.pwnedpasswords.com`)
16
+ * @param {string} [options.userAgent] a custom string to send as the User-Agent
17
+ * field in the request headers (default: `hibp <version>`)
18
+ * @returns {Promise<string>} a Promise which resolves to the data resulting
19
+ * from the query, or rejects with an Error
20
+ */
21
+ function fetchFromApi(endpoint, {
22
+ baseUrl = 'https://api.pwnedpasswords.com',
23
+ userAgent
24
+ } = {}) {
25
+ const config = Object.assign({}, userAgent ? {
26
+ headers: {
27
+ 'User-Agent': userAgent
28
+ }
29
+ } : {});
30
+ const url = `${baseUrl.replace(/\/$/g, '')}${endpoint}`;
31
+ return fetch(url, config).then(res => {
32
+ if (res.ok) return res.text();
33
+ if (res.status === BAD_REQUEST.status) {
34
+ return res.text().then(text => {
35
+ throw new Error(text);
36
+ });
37
+ }
38
+ throw new Error(res.statusText);
39
+ });
40
+ }
41
+ export { fetchFromApi };
42
+ //# sourceMappingURL=fetchFromApi.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetchFromApi.mjs","sources":["../../../../src/api/pwnedpasswords/fetchFromApi.ts"],"sourcesContent":["import fetch from '../web-fetch';\nimport { BAD_REQUEST } from './responses';\n\n/**\n * Fetches data from the supplied API endpoint.\n *\n * HTTP status code 200 returns plain text (data found).\n * HTTP status code 400 throws an Error (bad request).\n *\n * @internal\n * @private\n * @param {string} endpoint the API endpoint to query\n * @param {object} [options] a configuration object\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<string>} a Promise which resolves to the data resulting\n * from the query, or rejects with an Error\n */\nexport function fetchFromApi(\n endpoint: string,\n {\n baseUrl = 'https://api.pwnedpasswords.com',\n userAgent,\n }: { baseUrl?: string; userAgent?: string } = {},\n): Promise<string> {\n const config = Object.assign(\n {},\n userAgent\n ? {\n headers: {\n 'User-Agent': userAgent,\n },\n }\n : {},\n );\n\n const url = `${baseUrl.replace(/\\/$/g, '')}${endpoint}`;\n\n return fetch(url, config).then((res) => {\n if (res.ok) return res.text();\n\n if (res.status === BAD_REQUEST.status) {\n return res.text().then((text) => {\n throw new Error(text);\n });\n }\n\n throw new Error(res.statusText);\n });\n}\n"],"names":["fetchFromApi","endpoint","baseUrl","userAgent","config","Object","assign","headers","url","replace","fetch","then","res","ok","text","status","BAD_REQUEST","Error","statusText"],"mappings":";;;AAGA;;;;;;;;;;;;;;;;AAgBG;AACa,SAAAA,YAAYA,CAC1BC,QAAgB,EAChB;EACEC,OAAO,GAAG,gCAAgC;EAC1CC;AAAS,CAAA,GACmC,EAAE,EAAA;EAEhD,MAAMC,MAAM,GAAGC,MAAM,CAACC,MAAM,CAC1B,CAAE,CAAA,EACFH,SAAS,GACL;IACEI,OAAO,EAAE;MACP,YAAY,EAAEJ;IACf;EACF,CAAA,GACD,CAAA,CAAE,CACP;EAED,MAAMK,GAAG,GAAM,GAAAN,OAAO,CAACO,OAAO,CAAC,MAAM,EAAE,EAAE,CAAI,GAAAR,UAAU;EAEvD,OAAOS,KAAK,CAACF,GAAG,EAAEJ,MAAM,CAAC,CAACO,IAAI,CAAEC,GAAG,IAAI;IACrC,IAAIA,GAAG,CAACC,EAAE,EAAE,OAAOD,GAAG,CAACE,IAAI,EAAE;IAE7B,IAAIF,GAAG,CAACG,MAAM,KAAKC,WAAW,CAACD,MAAM,EAAE;MACrC,OAAOH,GAAG,CAACE,IAAI,EAAE,CAACH,IAAI,CAAEG,IAAI,IAAI;QAC9B,MAAM,IAAIG,KAAK,CAACH,IAAI,CAAC;MACvB,CAAC,CAAC;IACH;IAED,MAAM,IAAIG,KAAK,CAACL,GAAG,CAACM,UAAU,CAAC;EACjC,CAAC,CAAC;AACJ;"}
@@ -0,0 +1,2 @@
1
+ export { fetchFromApi } from './fetchFromApi.mjs';
2
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Known potential responses from the remote API.
3
+ *
4
+ * https://haveibeenpwned.com/api/v3#PwnedPasswords
5
+ *
6
+ */
7
+ /** @internal */
8
+ const OK = {
9
+ status: 200
10
+ };
11
+ /** @internal */
12
+ const BAD_REQUEST = {
13
+ status: 400,
14
+ body: 'The hash prefix was not in a valid format'
15
+ };
16
+ export { BAD_REQUEST, OK };
17
+ //# sourceMappingURL=responses.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"responses.mjs","sources":["../../../../src/api/pwnedpasswords/responses.ts"],"sourcesContent":["/**\n * Known potential responses from the remote API.\n *\n * https://haveibeenpwned.com/api/v3#PwnedPasswords\n *\n */\n\n/** @internal */\nexport interface PwnedPasswordsApiResponse {\n status: number;\n body?: string;\n}\n\n/** @internal */\nexport const OK: PwnedPasswordsApiResponse = {\n status: 200,\n};\n\n/** @internal */\nexport const BAD_REQUEST: PwnedPasswordsApiResponse = {\n status: 400,\n body: 'The hash prefix was not in a valid format',\n};\n"],"names":["OK","status","BAD_REQUEST","body"],"mappings":"AAAA;;;;;AAKG;AAQH;AACa,MAAAA,EAAE,GAA8B;EAC3CC,MAAM,EAAE;CACR;AAEF;AACa,MAAAC,WAAW,GAA8B;EACpDD,MAAM,EAAE,GAAG;EACXE,IAAI,EAAE;;"}
@@ -0,0 +1,10 @@
1
+ /* c8 ignore next */
2
+ var fetch = typeof window !== 'undefined' ? window.fetch : fetchWrapper;
3
+ async function fetchWrapper(input, init) {
4
+ const {
5
+ default: webFetch
6
+ } = await import('@remix-run/web-fetch');
7
+ return webFetch(input, init);
8
+ }
9
+ export { fetch as default };
10
+ //# sourceMappingURL=web-fetch.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-fetch.mjs","sources":["../../../src/api/web-fetch.ts"],"sourcesContent":["/* c8 ignore next */\nexport default typeof window !== 'undefined' ? window.fetch : fetchWrapper;\n\nasync function fetchWrapper(\n input: string | URL,\n init?: RequestInit | undefined,\n): Promise<Response> {\n const { default: webFetch } = await import('@remix-run/web-fetch');\n return webFetch(input, init);\n}\n"],"names":["fetch","window","fetchWrapper","input","init","default","webFetch"],"mappings":"AAAA;AACA,IAAeA,KAAA,GAAA,OAAOC,MAAM,KAAK,WAAW,GAAGA,MAAM,CAACD,KAAK,GAAGE,YAAY;AAE1E,eAAeA,YAAYA,CACzBC,KAAmB,EACnBC,IAA8B,EAAA;EAE9B,MAAM;IAAEC,OAAO,EAAEC;EAAU,CAAA,GAAG,MAAM,MAAA,CAAO,sBAAsB,CAAC;EAClE,OAAOA,QAAQ,CAACH,KAAK,EAAEC,IAAI,CAAC;AAC9B;"}
@@ -0,0 +1,53 @@
1
+ import { fetchFromApi } from './api/haveibeenpwned/fetchFromApi.mjs';
2
+
3
+ /**
4
+ * An object representing a breach.
5
+ *
6
+ * @typedef {object} Breach
7
+ * @property {string} Name
8
+ * @property {string} Title
9
+ * @property {string} Domain
10
+ * @property {string} BreachDate
11
+ * @property {string} AddedDate
12
+ * @property {string} ModifiedDate
13
+ * @property {number} PwnCount
14
+ * @property {string} Description
15
+ * @property {string} LogoPath
16
+ * @property {string[]} DataClasses
17
+ * @property {boolean} IsVerified
18
+ * @property {boolean} IsFabricated
19
+ * @property {boolean} IsSensitive
20
+ * @property {boolean} IsRetired
21
+ * @property {boolean} IsSpamList
22
+ */
23
+ /**
24
+ * Fetches data for a specific breach event.
25
+ *
26
+ * @param {string} breachName the name of a breach in the system
27
+ * @param {object} [options] a configuration object
28
+ * @param {string} [options.baseUrl] a custom base URL for the
29
+ * haveibeenpwned.com API endpoints (default:
30
+ * `https://haveibeenpwned.com/api/v3`)
31
+ * @param {string} [options.userAgent] a custom string to send as the User-Agent
32
+ * field in the request headers (default: `hibp <version>`)
33
+ * @returns {(Promise<Breach>|Promise<null>)} a Promise which resolves to an
34
+ * object representing a breach (or null if no breach was found), or rejects
35
+ * with an Error
36
+ * @example
37
+ * breach('Adobe')
38
+ * .then(data => {
39
+ * if (data) {
40
+ * // ...
41
+ * } else {
42
+ * // ...
43
+ * }
44
+ * })
45
+ * .catch(err => {
46
+ * // ...
47
+ * });
48
+ */
49
+ function breach(breachName, options = {}) {
50
+ return fetchFromApi(`/breach/${encodeURIComponent(breachName)}`, options);
51
+ }
52
+ export { breach };
53
+ //# sourceMappingURL=breach.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"breach.mjs","sources":["../../src/breach.ts"],"sourcesContent":["import type { Breach } from './api/haveibeenpwned/types';\nimport { fetchFromApi } from './api/haveibeenpwned';\n\n/**\n * An object representing a breach.\n *\n * @typedef {object} Breach\n * @property {string} Name\n * @property {string} Title\n * @property {string} Domain\n * @property {string} BreachDate\n * @property {string} AddedDate\n * @property {string} ModifiedDate\n * @property {number} PwnCount\n * @property {string} Description\n * @property {string} LogoPath\n * @property {string[]} DataClasses\n * @property {boolean} IsVerified\n * @property {boolean} IsFabricated\n * @property {boolean} IsSensitive\n * @property {boolean} IsRetired\n * @property {boolean} IsSpamList\n */\n\n/**\n * Fetches data for a specific breach event.\n *\n * @param {string} breachName the name of a breach in the system\n * @param {object} [options] a configuration object\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<Breach>|Promise<null>)} a Promise which resolves to an\n * object representing a breach (or null if no breach was found), or rejects\n * with an Error\n * @example\n * breach('Adobe')\n * .then(data => {\n * if (data) {\n * // ...\n * } else {\n * // ...\n * }\n * })\n * .catch(err => {\n * // ...\n * });\n */\nexport function breach(\n breachName: string,\n options: { baseUrl?: string; userAgent?: string } = {},\n): Promise<Breach | null> {\n return fetchFromApi(\n `/breach/${encodeURIComponent(breachName)}`,\n options,\n ) as Promise<Breach | null>;\n}\n"],"names":["breach","breachName","options","fetchFromApi","encodeURIComponent"],"mappings":";;AAGA;;;;;;;;;;;;;;;;;;;AAmBG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;AAyBG;SACaA,MAAMA,CACpBC,UAAkB,EAClBC,UAAoD,EAAE,EAAA;EAEtD,OAAOC,YAAY,CACjB,WAAWC,kBAAkB,CAACH,UAAU,CAAG,EAAA,EAC3CC,OAAO,CACkB;AAC7B;"}
@@ -0,0 +1,99 @@
1
+ import { fetchFromApi } from './api/haveibeenpwned/fetchFromApi.mjs';
2
+
3
+ /**
4
+ * Fetches breach data for a specific account.
5
+ *
6
+ * ***Warning (July 18, 2019):***
7
+ *
8
+ * `haveibeenpwned.com` now requires an API key from
9
+ * https://haveibeenpwned.com/API/Key for the `breachedaccount` endpoint. The
10
+ * `apiKey` option here is not explicitly required, but direct requests made
11
+ * without it (that is, without specifying a `baseUrl` to a proxy that inserts a
12
+ * valid API key on your behalf) will fail.
13
+ *
14
+ * @param {string} account a username or email address
15
+ * @param {object} [options] a configuration object
16
+ * @param {string} [options.apiKey] an API key from
17
+ * https://haveibeenpwned.com/API/Key (default: undefined)
18
+ * @param {string} [options.domain] a domain by which to filter the results
19
+ * (default: all domains)
20
+ * @param {boolean} [options.includeUnverified] include "unverified" breaches in
21
+ * the results (default: true)
22
+ * @param {boolean} [options.truncate] truncate the results to only include
23
+ * the name of each breach (default: true)
24
+ * @param {string} [options.baseUrl] a custom base URL for the
25
+ * haveibeenpwned.com API endpoints (default:
26
+ * `https://haveibeenpwned.com/api/v3`)
27
+ * @param {string} [options.userAgent] a custom string to send as the User-Agent
28
+ * field in the request headers (default: `hibp <version>`)
29
+ * @returns {(Promise<Breach[]> | Promise<null>)} a Promise which resolves to an
30
+ * array of breach objects (or null if no breaches were found), or rejects with
31
+ * an Error
32
+ * @example
33
+ * breachedAccount('foo', { apiKey: 'my-api-key' })
34
+ * .then(data => {
35
+ * if (data) {
36
+ * // ...
37
+ * } else {
38
+ * // ...
39
+ * }
40
+ * })
41
+ * .catch(err => {
42
+ * // ...
43
+ * });
44
+ * @example
45
+ * breachedAccount('bar', {
46
+ * includeUnverified: false,
47
+ * baseUrl: 'https://my-hibp-proxy:8080',
48
+ * })
49
+ * .then(data => {
50
+ * if (data) {
51
+ * // ...
52
+ * } else {
53
+ * // ...
54
+ * }
55
+ * })
56
+ * .catch(err => {
57
+ * // ...
58
+ * });
59
+ * @example
60
+ * breachedAccount('baz', {
61
+ * apiKey: 'my-api-key',
62
+ * domain: 'adobe.com',
63
+ * truncate: false,
64
+ * userAgent: 'my-app 1.0'
65
+ * })
66
+ * .then(data => {
67
+ * if (data) {
68
+ * // ...
69
+ * } else {
70
+ * // ...
71
+ * }
72
+ * })
73
+ * .catch(err => {
74
+ * // ...
75
+ * });
76
+ */
77
+ function breachedAccount(account, options = {
78
+ includeUnverified: true,
79
+ truncate: true
80
+ }) {
81
+ const endpoint = `/breachedaccount/${encodeURIComponent(account)}?`;
82
+ const params = [];
83
+ if (options.domain) {
84
+ params.push(`domain=${encodeURIComponent(options.domain)}`);
85
+ }
86
+ if (options.includeUnverified === false) {
87
+ params.push('includeUnverified=false');
88
+ }
89
+ if (options.truncate === false) {
90
+ params.push('truncateResponse=false');
91
+ }
92
+ return fetchFromApi(`${endpoint}${params.join('&')}`, {
93
+ apiKey: options.apiKey,
94
+ baseUrl: options.baseUrl,
95
+ userAgent: options.userAgent
96
+ });
97
+ }
98
+ export { breachedAccount };
99
+ //# sourceMappingURL=breachedAccount.mjs.map