Skip to content

Commit 4bf85ef

Browse files
committed
Saving progress
0 parents  commit 4bf85ef

14 files changed

+587
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
build
2+
node_modules

package-lock.json

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

package.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "webpush-notification",
3+
"version": "1.0.0",
4+
"description": "Minimal library for sending notifications via the browser Push API",
5+
"main": "build/pushNotification.js",
6+
"dependencies": {
7+
"jose": "^5.8.0"
8+
},
9+
"devDependencies": {
10+
"base64url": "^3.0.1",
11+
"js-crypto-hkdf": "^1.0.7",
12+
"typescript": "^5.5.4"
13+
},
14+
"scripts": {
15+
"test": "echo \"Error: no test specified\" && exit 1",
16+
"build": "tsc"
17+
},
18+
"author": "Cole Crouter",
19+
"license": "ISC",
20+
"type": "module"
21+
}

src/crypto/deriveSharedSecret.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export async function deriveSharedSecret(
2+
publicKey: CryptoKey,
3+
privateKey: CryptoKey,
4+
): Promise<CryptoKey> {
5+
const sharedSecret = await crypto.subtle.deriveKey(
6+
{
7+
name: "ECDH",
8+
public: publicKey,
9+
},
10+
privateKey,
11+
{
12+
name: "AES-GCM",
13+
length: 256,
14+
},
15+
true,
16+
["encrypt", "decrypt"],
17+
);
18+
19+
return sharedSecret;
20+
}

src/crypto/encode.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Uint8Array -> base64url string
2+
export function encode(input: Uint8Array): string {
3+
return btoa(String.fromCharCode(...input));
4+
}

src/crypto/encryptPayload.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import base64url from "base64url";
2+
3+
const encode = base64url.encode;
4+
5+
export async function encryptPayload(
6+
payload: string,
7+
sharedSecret: CryptoKey,
8+
salt: Uint8Array,
9+
) {
10+
const encodedPayload = new TextEncoder().encode(payload);
11+
const encrypted = await crypto.subtle.encrypt(
12+
{
13+
name: "AES-GCM",
14+
iv: salt,
15+
},
16+
sharedSecret,
17+
encodedPayload,
18+
);
19+
return encode(encrypted);
20+
}

src/crypto/generateVapidKeys.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { generateKeyPair, exportJWK } from "jose";
2+
3+
export async function generateVapidKeys() {
4+
const { publicKey, privateKey } = await generateKeyPair("ES256");
5+
6+
return { publicKey, privateKey };
7+
}

src/crypto/signRequest.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { type JWTPayload, SignJWT } from "jose";
2+
3+
export async function signRequest(payload: JWTPayload, privateKey: CryptoKey) {
4+
const jwt = await new SignJWT(payload)
5+
.setProtectedHeader({ alg: "ES256" })
6+
.sign(privateKey);
7+
return jwt;
8+
}

0 commit comments

Comments
 (0)