mirror of
https://github.com/PR0M3TH3AN/bitlogin.git
synced 2026-10-27 08:31:21 +00:00
Builds out the v0.3 spec as an npm workspace monorepo any static site can consume for login and Nostr signing: - packages/core: framework-free protocol implementation — Argon2id/HKDF/ ScalarExpand/AES-256-GCM/JCS crypto primitives, NIP-01 event handling and a quorum-aware relay pool, credential/recovery capsule construction and validation, and the full account lifecycle (registration, any-device login with rollback/relay-disagreement detection, phrase recovery with recovery-capsule refresh, password rotation with mandatory tombstone + NIP-09 deletion, replica repair, recovery export, NIP-19 encoding, a NIP-44 v2 implementation, and a NIP-07-shaped signer). 49 tests cover the spec's Phase 0 byte-level vectors plus full create/login/recover/rotate end-to-end scenarios against an in-memory mock relay. - packages/widget: a <bitlogin-auth> custom element with a dedicated crypto Web Worker (private keys never touch the main thread) and a window.nostr NIP-07-compatible provider, so existing Nostr web apps work against it with zero code changes. Built with Vite into two relocatable static files. - packages/demo: a plain static site (no build step of its own) consuming the widget — a branding/landing page, an integration guide, and an account-manager page covering create/login/recover, password rotation, and identity export. All flows were verified twice: protocol-level tests against a mock relay, and the actual built widget driven end-to-end in real Chromium (registration, phrase confirmation, event signing, clean-device login, window.nostr, and phrase recovery all reproduce the identical everyday pubkey). Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01GWJbXXhvTx9wo59jSz57J6
53 lines
1.7 KiB
JavaScript
53 lines
1.7 KiB
JavaScript
/**
|
|
* Static-asset-only cache (§22.3). This service worker never sees relay traffic
|
|
* (Nostr relay I/O is WebSocket, not fetch) and never handles form submissions,
|
|
* so there is nothing sensitive in its fetch path by construction. It precaches
|
|
* a fixed, explicit list of public files and serves them cache-first; anything
|
|
* not on that list passes straight through to the network untouched.
|
|
*/
|
|
const CACHE_NAME = "bitlogin-demo-v1";
|
|
const PRECACHE_URLS = [
|
|
"/",
|
|
"/index.html",
|
|
"/docs.html",
|
|
"/account.html",
|
|
"/assets/site.css",
|
|
"/assets/icon.svg",
|
|
"/manifest.webmanifest",
|
|
"/vendor/bitlogin/bitlogin.js",
|
|
"/vendor/bitlogin/cryptoWorker.js"
|
|
];
|
|
|
|
self.addEventListener("install", (event) => {
|
|
event.waitUntil(
|
|
caches.open(CACHE_NAME).then((cache) => cache.addAll(PRECACHE_URLS)).then(() => self.skipWaiting())
|
|
);
|
|
});
|
|
|
|
self.addEventListener("activate", (event) => {
|
|
event.waitUntil(
|
|
caches
|
|
.keys()
|
|
.then((keys) => Promise.all(keys.filter((key) => key !== CACHE_NAME).map((key) => caches.delete(key))))
|
|
.then(() => self.clients.claim())
|
|
);
|
|
});
|
|
|
|
self.addEventListener("fetch", (event) => {
|
|
const url = new URL(event.request.url);
|
|
if (event.request.method !== "GET" || url.origin !== self.location.origin) return;
|
|
if (!PRECACHE_URLS.includes(url.pathname)) return;
|
|
|
|
event.respondWith(
|
|
caches.match(event.request).then((cached) => {
|
|
const network = fetch(event.request)
|
|
.then((response) => {
|
|
if (response.ok) caches.open(CACHE_NAME).then((cache) => cache.put(event.request, response.clone()));
|
|
return response;
|
|
})
|
|
.catch(() => cached);
|
|
return cached ?? network;
|
|
})
|
|
);
|
|
});
|