Skip to content

Commit db5be22

Browse files
fix: remove dependency on tweetnacl
1 parent 9b396aa commit db5be22

File tree

8 files changed

+274
-251
lines changed

8 files changed

+274
-251
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Use `verifyKey` to check a request signature:
2121
```js
2222
const signature = req.get('X-Signature-Ed25519');
2323
const timestamp = req.get('X-Signature-Timestamp');
24-
const isValidRequest = verifyKey(req.rawBody, signature, timestamp, 'MY_CLIENT_PUBLIC_KEY');
24+
const isValidRequest = await verifyKey(req.rawBody, signature, timestamp, 'MY_CLIENT_PUBLIC_KEY');
2525
if (!isValidRequest) {
2626
return res.status(401).end('Bad request signature');
2727
}

package-lock.json

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

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,19 @@
1818
"files": [
1919
"dist/**/*"
2020
],
21-
"prepare": "npm run build",
2221
"types": "dist/index.d.ts",
2322
"keywords": [
2423
"discord"
2524
],
2625
"scripts": {
26+
"prepare": "npm run build",
2727
"build": "tsc",
2828
"build:watch": "tsc --watch",
2929
"fix": "biome check --apply .",
3030
"lint": "biome check .",
3131
"test": "jest --verbose"
3232
},
3333
"dependencies": {
34-
"tweetnacl": "^1.0.3"
3534
},
3635
"devDependencies": {
3736
"@biomejs/biome": "^1.7.3",

src/__tests__/utils/SharedTestUtils.ts

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import nacl from 'tweetnacl';
1+
import { arrayBufferToBase64 } from "../../util";
22

33
// Example PING request body
44
export const pingRequestBody = JSON.stringify({
@@ -51,10 +51,17 @@ export const autocompleteRequestBody = JSON.stringify({
5151
},
5252
});
5353

54-
// Generate a "valid" keypair
55-
export const validKeyPair = nacl.sign.keyPair();
56-
// Generate an "invalid" keypair
57-
export const invalidKeyPair = nacl.sign.keyPair();
54+
export async function generateKeyPair() {
55+
const keyPair = await crypto.subtle.generateKey(
56+
{
57+
name: 'ed25519',
58+
namedCurve: 'ed25519',
59+
},
60+
true,
61+
['sign', 'verify'],
62+
);
63+
return keyPair;
64+
}
5865

5966
export type SignedRequest = {
6067
body: string;
@@ -66,22 +73,22 @@ export type ExampleRequestResponse = {
6673
body: string;
6774
};
6875

69-
export function signRequestWithKeyPair(
76+
export async function signRequestWithKeyPair(
7077
body: string,
71-
privateKey: Uint8Array,
72-
): SignedRequest {
78+
privateKey: CryptoKey,
79+
) {
80+
const encoder = new TextEncoder();
7381
const timestamp = String(Math.round(new Date().getTime() / 1000));
74-
const signature = Buffer.from(
75-
nacl.sign.detached(
76-
Uint8Array.from(
77-
Buffer.concat([Buffer.from(timestamp), Buffer.from(body)]),
78-
),
79-
privateKey,
80-
),
81-
).toString('hex');
82+
const signature = await crypto.subtle.sign(
83+
{
84+
name: 'ed25519',
85+
},
86+
privateKey,
87+
encoder.encode(timestamp + body),
88+
);
8289
return {
8390
body,
84-
signature,
91+
signature: arrayBufferToBase64(signature),
8592
timestamp,
8693
};
8794
}

src/__tests__/verifyKey.ts

Lines changed: 97 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,137 +1,136 @@
11
import { verifyKey } from '../index';
22
import {
3-
invalidKeyPair,
3+
generateKeyPair,
44
pingRequestBody,
55
signRequestWithKeyPair,
6-
validKeyPair,
76
} from './utils/SharedTestUtils';
87

98
describe('verify key method', () => {
10-
it('valid ping request', () => {
9+
let validKeyPair: CryptoKeyPair;
10+
let invalidKeyPair: CryptoKeyPair;
11+
12+
beforeAll(async () => {
13+
validKeyPair = await generateKeyPair();
14+
invalidKeyPair = await generateKeyPair();
15+
});
16+
17+
it('valid ping request', async () => {
1118
// Sign and verify a valid ping request
12-
const signedRequest = signRequestWithKeyPair(
19+
const signedRequest = await signRequestWithKeyPair(
1320
pingRequestBody,
14-
validKeyPair.secretKey,
15-
);
16-
expect(
17-
verifyKey(
18-
signedRequest.body,
19-
signedRequest.signature,
20-
signedRequest.timestamp,
21-
validKeyPair.publicKey,
22-
),
23-
).toBe(true);
21+
validKeyPair.privateKey,
22+
);
23+
const isValid = await verifyKey(
24+
signedRequest.body,
25+
signedRequest.signature,
26+
signedRequest.timestamp,
27+
validKeyPair.publicKey,
28+
);
29+
expect(isValid).toBe(true);
2430
});
2531

26-
it('valid application command', () => {
32+
it('valid application command', async () => {
2733
// Sign and verify a valid application command request
28-
const signedRequest = signRequestWithKeyPair(
34+
const signedRequest = await signRequestWithKeyPair(
2935
pingRequestBody,
30-
validKeyPair.secretKey,
31-
);
32-
expect(
33-
verifyKey(
34-
signedRequest.body,
35-
signedRequest.signature,
36-
signedRequest.timestamp,
37-
validKeyPair.publicKey,
38-
),
39-
).toBe(true);
36+
validKeyPair.privateKey,
37+
);
38+
const isValid = await verifyKey(
39+
signedRequest.body,
40+
signedRequest.signature,
41+
signedRequest.timestamp,
42+
validKeyPair.publicKey,
43+
);
44+
expect(isValid).toBe(true);
4045
});
4146

42-
it('valid message component', () => {
47+
it('valid message component', async () => {
4348
// Sign and verify a valid message component request
44-
const signedRequest = signRequestWithKeyPair(
49+
const signedRequest = await signRequestWithKeyPair(
4550
pingRequestBody,
46-
validKeyPair.secretKey,
47-
);
48-
expect(
49-
verifyKey(
50-
signedRequest.body,
51-
signedRequest.signature,
52-
signedRequest.timestamp,
53-
validKeyPair.publicKey,
54-
),
55-
).toBe(true);
51+
validKeyPair.privateKey,
52+
);
53+
const isValid = await verifyKey(
54+
signedRequest.body,
55+
signedRequest.signature,
56+
signedRequest.timestamp,
57+
validKeyPair.publicKey,
58+
);
59+
expect(isValid).toBe(true);
5660
});
5761

58-
it('valid autocomplete', () => {
62+
it('valid autocomplete', async () => {
5963
// Sign and verify a valid autocomplete request
60-
const signedRequest = signRequestWithKeyPair(
64+
const signedRequest = await signRequestWithKeyPair(
6165
pingRequestBody,
62-
validKeyPair.secretKey,
63-
);
64-
expect(
65-
verifyKey(
66-
signedRequest.body,
67-
signedRequest.signature,
68-
signedRequest.timestamp,
69-
validKeyPair.publicKey,
70-
),
71-
).toBe(true);
66+
validKeyPair.privateKey,
67+
);
68+
const isValid = await verifyKey(
69+
signedRequest.body,
70+
signedRequest.signature,
71+
signedRequest.timestamp,
72+
validKeyPair.publicKey,
73+
);
74+
expect(isValid).toBe(true);
7275
});
7376

74-
it('invalid key', () => {
77+
it('invalid key', async () => {
7578
// Sign a request with a different private key and verify with the valid public key
76-
const signedRequest = signRequestWithKeyPair(
79+
const signedRequest = await signRequestWithKeyPair(
7780
pingRequestBody,
78-
invalidKeyPair.secretKey,
79-
);
80-
expect(
81-
verifyKey(
82-
signedRequest.body,
83-
signedRequest.signature,
84-
signedRequest.timestamp,
85-
validKeyPair.publicKey,
86-
),
87-
).toBe(false);
81+
invalidKeyPair.privateKey,
82+
);
83+
const isValid = await verifyKey(
84+
signedRequest.body,
85+
signedRequest.signature,
86+
signedRequest.timestamp,
87+
validKeyPair.publicKey,
88+
);
89+
expect(isValid).toBe(false);
8890
});
8991

90-
it('invalid body', () => {
92+
it('invalid body', async () => {
9193
// Sign a valid request and verify with an invalid body
92-
const signedRequest = signRequestWithKeyPair(
94+
const signedRequest = await signRequestWithKeyPair(
9395
pingRequestBody,
94-
validKeyPair.secretKey,
95-
);
96-
expect(
97-
verifyKey(
98-
'example invalid body',
99-
signedRequest.signature,
100-
signedRequest.timestamp,
101-
validKeyPair.publicKey,
102-
),
103-
).toBe(false);
96+
validKeyPair.privateKey,
97+
);
98+
const isValid = await verifyKey(
99+
'example invalid body',
100+
signedRequest.signature,
101+
signedRequest.timestamp,
102+
validKeyPair.publicKey,
103+
);
104+
expect(isValid).toBe(false);
104105
});
105106

106-
it('invalid signature', () => {
107+
it('invalid signature', async () => {
107108
// Sign a valid request and verify with an invalid signature
108-
const signedRequest = signRequestWithKeyPair(
109+
const signedRequest = await signRequestWithKeyPair(
109110
pingRequestBody,
110-
validKeyPair.secretKey,
111-
);
112-
expect(
113-
verifyKey(
114-
signedRequest.body,
115-
'example invalid signature',
116-
signedRequest.timestamp,
117-
validKeyPair.publicKey,
118-
),
119-
).toBe(false);
111+
validKeyPair.privateKey,
112+
);
113+
const isValid = await verifyKey(
114+
signedRequest.body,
115+
'example invalid signature',
116+
signedRequest.timestamp,
117+
validKeyPair.publicKey,
118+
);
119+
expect(isValid).toBe(false);
120120
});
121121

122-
it('invalid timestamp', () => {
122+
it('invalid timestamp', async () => {
123123
// Sign a valid request and verify with an invalid timestamp
124-
const signedRequest = signRequestWithKeyPair(
124+
const signedRequest = await signRequestWithKeyPair(
125125
pingRequestBody,
126-
validKeyPair.secretKey,
127-
);
128-
expect(
129-
verifyKey(
130-
'example invalid body',
131-
signedRequest.signature,
132-
String(Math.round(new Date().getTime() / 1000) - 10000),
133-
validKeyPair.publicKey,
134-
),
135-
).toBe(false);
126+
validKeyPair.privateKey,
127+
);
128+
const isValid = await verifyKey(
129+
'example invalid body',
130+
signedRequest.signature,
131+
String(Math.round(new Date().getTime() / 1000) - 10000),
132+
validKeyPair.publicKey,
133+
);
134+
expect(isValid).toBe(false);
136135
});
137136
});

0 commit comments

Comments
 (0)