@3sln/create-trove 0.0.2 → 0.0.4

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.
package/src/vapid.js ADDED
@@ -0,0 +1,49 @@
1
+ // A VAPID key pair, made locally.
2
+ //
3
+ // This is a copy of `generateVapidKeys` from @3sln/trove/core, and the duplication is
4
+ // deliberate: create-trove has no dependencies and runs through `npm create`, BEFORE
5
+ // the project it is writing has a node_modules. Pointing someone at a function inside a
6
+ // package they have not installed yet is not a hint, it is a dead end — which is what
7
+ // the first version of the push question did.
8
+ //
9
+ // The format is fixed by RFC 8292 and the Push API, not by us, so this cannot drift in
10
+ // any interesting way. `test/vapid.test.js` checks the pair against core's own
11
+ // implementation anyway, because "cannot drift" is a claim and that test is a fact.
12
+ //
13
+ // Worth being clear about what a VAPID key IS, because it decides how it should be
14
+ // handled: it identifies this application server to a push service. It is self-issued —
15
+ // no account, no registration, no network — which is what makes generating one here
16
+ // legitimate where minting an R2 access key would not be. The public half goes to
17
+ // browsers as `applicationServerKey` and ends up baked into every subscription made
18
+ // against it; the private half signs the JWT that authorises each push.
19
+
20
+ /** base64url, no padding. */
21
+ const b64url = (bytes) => btoa(String.fromCharCode(...bytes))
22
+ .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
23
+
24
+ const unb64url = (s) => {
25
+ const b64 = s.replace(/-/g, '+').replace(/_/g, '/');
26
+ const bin = atob(b64 + '='.repeat((4 - (b64.length % 4)) % 4));
27
+ return Uint8Array.from(bin, (c) => c.charCodeAt(0));
28
+ };
29
+
30
+ /**
31
+ * @returns {Promise<{publicKey: string, privateKey: string}>} both base64url.
32
+ * `publicKey` is the uncompressed EC point (0x04 || X || Y, 65 bytes) that
33
+ * PushManager.subscribe() wants; `privateKey` is the raw 32-byte scalar.
34
+ */
35
+ export async function generateVapidKeys() {
36
+ const pair = await crypto.subtle.generateKey(
37
+ { name: 'ECDSA', namedCurve: 'P-256' },
38
+ true,
39
+ ['sign', 'verify'],
40
+ );
41
+ const jwk = await crypto.subtle.exportKey('jwk', pair.privateKey);
42
+ const x = unb64url(jwk.x);
43
+ const y = unb64url(jwk.y);
44
+ const point = new Uint8Array(65);
45
+ point[0] = 0x04;
46
+ point.set(x, 1);
47
+ point.set(y, 33);
48
+ return { publicKey: b64url(point), privateKey: jwk.d };
49
+ }