Skip to content

Commit 56fdf38

Browse files
authored
Drop JSSHA in favor of Web Crypto API (#506)
1 parent 74d3ea2 commit 56fdf38

File tree

5 files changed

+29
-23
lines changed

5 files changed

+29
-23
lines changed

.bundlewatch.config.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
{
44
"//": "Pre-bundled for Browser (UMD)",
55
"path": "dist/browser/hibp.umd.js",
6-
"maxSize": "9.3 kB"
6+
"maxSize": "6.3 kB"
77
},
88
{
99
"//": "Pre-bundled for Browser (ESM)",
1010
"path": "dist/browser/hibp.module.js",
11-
"maxSize": "4.9 kB"
11+
"maxSize": "1.9 kB"
1212
},
1313
{
14-
"//": "Bundled with Webpack (CJS)",
14+
"//": "Bundled (CJS)",
1515
"path": "dist/cjs/breach.cjs",
1616
"maxSize": "1 kB"
1717
},
@@ -48,7 +48,7 @@
4848
"maxSize": "1 kB"
4949
},
5050
{
51-
"//": "Bundled with Webpack (ESM)",
51+
"//": "Bundled (ESM)",
5252
"path": "dist/esm/breach.js",
5353
"maxSize": "1 kB"
5454
},
@@ -70,7 +70,7 @@
7070
},
7171
{
7272
"path": "dist/esm/pwned-password.js",
73-
"maxSize": "1 kB"
73+
"maxSize": "1.1 kB"
7474
},
7575
{
7676
"path": "dist/esm/pwned-password-range.js",

.changeset/dry-beds-press.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'hibp': minor
3+
---
4+
5+
Drop `JSSHA` dependency in favor of a native Web Crypto API SHA-1 hashing implementation. This change reduces the size of the library by approximately 30%! 📉

package-lock.json

Lines changed: 0 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@
8181
"node": ">= 18.0.0"
8282
},
8383
"dependencies": {
84-
"jssha": "^3.3.1",
8584
"undici": "^6.14.1"
8685
},
8786
"devDependencies": {

src/pwned-password.ts

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import JSSHA from 'jssha/dist/sha1';
21
import { pwnedPasswordRange } from './pwned-password-range.js';
32

43
/**
@@ -56,13 +55,25 @@ export async function pwnedPassword(
5655
userAgent?: string;
5756
} = {},
5857
): Promise<number> {
59-
// @ts-expect-error: JSSHA types are busted
60-
const sha1 = new JSSHA('SHA-1', 'TEXT');
61-
sha1.update(password);
62-
const hash = sha1.getHash('HEX', { outputUpper: true });
63-
const prefix = hash.slice(0, 5);
64-
const suffix = hash.slice(5);
65-
58+
const [prefix, suffix] = await getPasswordHashParts(password);
6659
const range = await pwnedPasswordRange(prefix, options);
6760
return range[suffix] || 0;
6861
}
62+
63+
async function getPasswordHashParts(password: string) {
64+
if (typeof crypto === 'object' && crypto.subtle) {
65+
const msgUint8 = new TextEncoder().encode(password);
66+
const hashBuffer = await crypto.subtle.digest('SHA-1', msgUint8);
67+
const hashArray = Array.from(new Uint8Array(hashBuffer));
68+
const hashHex = hashArray
69+
.map((byte) => byte.toString(16).padStart(2, '0'))
70+
.join('')
71+
.toUpperCase();
72+
73+
return [hashHex.slice(0, 5), hashHex.slice(5)] as const;
74+
/* c8 ignore start */
75+
}
76+
77+
throw new Error('The Web Crypto API is not available in this environment.');
78+
}
79+
/* c8 ignore end */

0 commit comments

Comments
 (0)