Skip to content

Commit 764176c

Browse files
authored
fix: remove uncrypto (#13)
1 parent f6fb252 commit 764176c

File tree

10 files changed

+42
-51
lines changed

10 files changed

+42
-51
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Better Auth Utils
22

3-
A simple typescript API for common auth utilities like hashing, encryption, encoding, and OTP generation. Built on top of Web Crypto APIs and it wraps over [uncrypto](https://github.com/unjs/uncrypto) to provide a unified API for both Node.js (using the Crypto module) and web environments (using the Web Crypto API) through Conditional Exports.
3+
A simple typescript API for common auth utilities like hashing, encryption, encoding, and OTP generation. Built on top of Web Crypto APIs to provide a unified API for both Node.js (using the Crypto module) and web environments (using the Web Crypto API) through Conditional Exports.
44

55
```bash
66
pnpm add @better-auth/utils

package.json

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,6 @@
2323
"type": "git",
2424
"url": "https://github.com/better-auth/utils"
2525
},
26-
"dependencies": {
27-
"uncrypto": "^0.1.3"
28-
},
2926
"devDependencies": {
3027
"@biomejs/biome": "^1.9.4",
3128
"@types/node": "^22.10.1",
@@ -81,7 +78,5 @@
8178
"require": "./dist/rsa.cjs"
8279
}
8380
},
84-
"files": [
85-
"dist"
86-
]
87-
}
81+
"files": ["dist"]
82+
}

pnpm-lock.yaml

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

src/ecdsa.ts

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,21 @@ import type {
44
SHAFamily,
55
TypedArray,
66
} from "./type";
7+
import { getWebcryptoSubtle } from "./index";
78

89
export const ecdsa = {
910
generateKeyPair: async (curve: ECDSACurve = "P-256") => {
10-
const keyPair = await crypto.subtle.generateKey(
11+
const subtle = getWebcryptoSubtle();
12+
const keyPair = await subtle.generateKey(
1113
{
1214
name: "ECDSA",
1315
namedCurve: curve,
1416
},
1517
true,
1618
["sign", "verify"],
1719
);
18-
const privateKey = await crypto.subtle.exportKey(
19-
"pkcs8",
20-
keyPair.privateKey,
21-
);
22-
const publicKey = await crypto.subtle.exportKey("spki", keyPair.publicKey);
20+
const privateKey = await subtle.exportKey("pkcs8", keyPair.privateKey);
21+
const publicKey = await subtle.exportKey("spki", keyPair.publicKey);
2322
return { privateKey, publicKey };
2423
},
2524
importPrivateKey: async (
@@ -30,7 +29,7 @@ export const ecdsa = {
3029
if (typeof privateKey === "string") {
3130
privateKey = new TextEncoder().encode(privateKey);
3231
}
33-
return await crypto.subtle.importKey(
32+
return await getWebcryptoSubtle().importKey(
3433
"pkcs8",
3534
privateKey,
3635
{
@@ -49,7 +48,7 @@ export const ecdsa = {
4948
if (typeof publicKey === "string") {
5049
publicKey = new TextEncoder().encode(publicKey);
5150
}
52-
return await crypto.subtle.importKey(
51+
return await getWebcryptoSubtle().importKey(
5352
"spki",
5453
publicKey,
5554
{
@@ -68,7 +67,7 @@ export const ecdsa = {
6867
if (typeof data === "string") {
6968
data = new TextEncoder().encode(data);
7069
}
71-
const signature = await crypto.subtle.sign(
70+
const signature = await getWebcryptoSubtle().sign(
7271
{
7372
name: "ECDSA",
7473
hash: { name: hash },
@@ -97,7 +96,7 @@ export const ecdsa = {
9796
if (typeof data === "string") {
9897
data = new TextEncoder().encode(data);
9998
}
100-
return await crypto.subtle.verify(
99+
return await getWebcryptoSubtle().verify(
101100
{
102101
name: "ECDSA",
103102
hash: { name: hash },
@@ -111,6 +110,6 @@ export const ecdsa = {
111110
key: CryptoKey,
112111
format: E,
113112
): Promise<E extends "jwk" ? JsonWebKey : ArrayBuffer> => {
114-
return (await crypto.subtle.exportKey(format, key)) as any;
113+
return (await getWebcryptoSubtle().exportKey(format, key)) as any;
115114
},
116115
};

src/hash.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { subtle } from "uncrypto";
21
import { base64, base64Url } from "./base64";
32
import type { EncodingFormat, SHAFamily, TypedArray } from "./type";
3+
import { getWebcryptoSubtle } from "./index";
44

55
export function createHash<Encoding extends EncodingFormat = "none">(
66
algorithm: SHAFamily,
@@ -12,7 +12,7 @@ export function createHash<Encoding extends EncodingFormat = "none">(
1212
): Promise<Encoding extends "none" ? ArrayBuffer : string> => {
1313
const encoder = new TextEncoder();
1414
const data = typeof input === "string" ? encoder.encode(input) : input;
15-
const hashBuffer = await subtle.digest(algorithm, data);
15+
const hashBuffer = await getWebcryptoSubtle().digest(algorithm, data);
1616

1717
if (encoding === "hex") {
1818
const hashArray = Array.from(new Uint8Array(hashBuffer));

src/hmac.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { subtle } from "uncrypto";
21
import type { EncodingFormat, SHAFamily, TypedArray } from "./type";
32
import { hex } from "./hex";
43
import { base64, base64Url } from "./base64";
4+
import { getWebcryptoSubtle } from "./index";
55

66
export const createHMAC = <E extends EncodingFormat = "none">(
77
algorithm: SHAFamily = "SHA-256",
@@ -12,7 +12,7 @@ export const createHMAC = <E extends EncodingFormat = "none">(
1212
key: string | ArrayBuffer | TypedArray,
1313
keyUsage: "sign" | "verify",
1414
) => {
15-
return subtle.importKey(
15+
return getWebcryptoSubtle().importKey(
1616
"raw",
1717
typeof key === "string" ? new TextEncoder().encode(key) : key,
1818
{ name: "HMAC", hash: { name: algorithm } },
@@ -27,7 +27,7 @@ export const createHMAC = <E extends EncodingFormat = "none">(
2727
if (typeof hmacKey === "string") {
2828
hmacKey = await hmac.importKey(hmacKey, "sign");
2929
}
30-
const signature = await subtle.sign(
30+
const signature = await getWebcryptoSubtle().sign(
3131
"HMAC",
3232
hmacKey,
3333
typeof data === "string" ? new TextEncoder().encode(data) : data,
@@ -64,7 +64,7 @@ export const createHMAC = <E extends EncodingFormat = "none">(
6464
) {
6565
signature = await base64.decode(signature);
6666
}
67-
return subtle.verify(
67+
return getWebcryptoSubtle().verify(
6868
"HMAC",
6969
hmacKey,
7070
typeof signature === "string"

src/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
1-
export * from "uncrypto";
1+
export function getWebcryptoSubtle(): SubtleCrypto {
2+
const cr = typeof globalThis !== "undefined" && (globalThis as any).crypto;
3+
if (cr && typeof cr.subtle === "object" && cr.subtle != null)
4+
return cr.subtle;
5+
throw new Error("crypto.subtle must be defined");
6+
}

src/random.test.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import { describe, expect, it, vi } from "vitest";
1+
import { afterEach, describe, expect, it, vi } from "vitest";
22
import { createRandomStringGenerator } from "./random";
3-
import { getRandomValues } from "uncrypto";
43

54
// Utility functions for distribution tests
65
function generateLargeRandomSample(
@@ -108,7 +107,7 @@ describe("createRandomStringGenerator", () => {
108107

109108
it("combines multiple alphabets when passed during generation", () => {
110109
// Mock getRandomValues to return sequentially increasing values
111-
vi.mock("uncrypto", () => ({
110+
vi.stubGlobal("crypto", {
112111
getRandomValues: vi.fn(
113112
<T extends ArrayBufferView | null>(array: T): T => {
114113
if (array instanceof Uint8Array) {
@@ -119,7 +118,7 @@ describe("createRandomStringGenerator", () => {
119118
return array;
120119
},
121120
),
122-
}));
121+
});
123122

124123
try {
125124
const generator = createRandomStringGenerator("a-z");
@@ -138,7 +137,7 @@ describe("createRandomStringGenerator", () => {
138137
expect(randomString).toHaveLength(256);
139138
} finally {
140139
// Restore the original implementation
141-
vi.unmock("uncrypto");
140+
vi.unstubAllGlobals();
142141
}
143142
});
144143

src/random.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { getRandomValues } from "uncrypto";
2-
31
type Alphabet = "a-z" | "A-Z" | "0-9" | "-_";
42

53
function expandAlphabet(alphabet: Alphabet): string {
@@ -52,7 +50,7 @@ export function createRandomStringGenerator<A extends Alphabet>(
5250

5351
while (result.length < length) {
5452
if (bufIndex >= bufLength) {
55-
getRandomValues(buf);
53+
crypto.getRandomValues(buf);
5654
bufIndex = 0;
5755
}
5856

src/rsa.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { subtle } from "uncrypto";
1+
import { getWebcryptoSubtle } from "./index";
22

33
type ExportFormat = "jwk" | "spki" | "pkcs8";
44

@@ -7,7 +7,7 @@ export const rsa = {
77
modulusLength: 2048 | 4096 = 2048,
88
hash: "SHA-256" | "SHA-384" | "SHA-512" = "SHA-256",
99
) => {
10-
return await subtle.generateKey(
10+
return await getWebcryptoSubtle().generateKey(
1111
{
1212
name: "RSA-OAEP",
1313
modulusLength,
@@ -22,14 +22,14 @@ export const rsa = {
2222
key: CryptoKey,
2323
format: E,
2424
): Promise<E extends "jwk" ? JsonWebKey : ArrayBuffer> => {
25-
return (await subtle.exportKey(format, key)) as any;
25+
return (await getWebcryptoSubtle().exportKey(format, key)) as any;
2626
},
2727
importKey: async (
2828
key: JsonWebKey,
2929
usage: "encrypt" | "decrypt" = "encrypt",
3030
hash: "SHA-256" | "SHA-384" | "SHA-512" = "SHA-256",
3131
) => {
32-
return await subtle.importKey(
32+
return await getWebcryptoSubtle().importKey(
3333
"jwk",
3434
key,
3535
{
@@ -46,10 +46,14 @@ export const rsa = {
4646
) => {
4747
const encodedData =
4848
typeof data === "string" ? new TextEncoder().encode(data) : data;
49-
return await subtle.encrypt({ name: "RSA-OAEP" }, key, encodedData);
49+
return await getWebcryptoSubtle().encrypt(
50+
{ name: "RSA-OAEP" },
51+
key,
52+
encodedData,
53+
);
5054
},
5155
decrypt: async (key: CryptoKey, data: ArrayBuffer | ArrayBufferView) => {
52-
return await subtle.decrypt({ name: "RSA-OAEP" }, key, data);
56+
return await getWebcryptoSubtle().decrypt({ name: "RSA-OAEP" }, key, data);
5357
},
5458
sign: async (
5559
key: CryptoKey,
@@ -58,7 +62,7 @@ export const rsa = {
5862
) => {
5963
const encodedData =
6064
typeof data === "string" ? new TextEncoder().encode(data) : data;
61-
return await subtle.sign(
65+
return await getWebcryptoSubtle().sign(
6266
{
6367
name: "RSA-PSS",
6468
saltLength,
@@ -84,7 +88,7 @@ export const rsa = {
8488
}
8589
const encodedData =
8690
typeof data === "string" ? new TextEncoder().encode(data) : data;
87-
return await subtle.verify(
91+
return await getWebcryptoSubtle().verify(
8892
{
8993
name: "RSA-PSS",
9094
saltLength,

0 commit comments

Comments
 (0)