diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a95606e..0b2cf70 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -137,7 +137,7 @@ jobs:
- name: Record checksums
run: |
printf -- '### Distributable checksums\n' >> "$GITHUB_STEP_SUMMARY"
- for page in index router 0x67 cloud-google-drive; do
+ for page in index local 0x67 cloud-google-drive; do
checksum=$(node --experimental-strip-types tools/build/inliner/src/index.ts "pages/${page}/build.json" | awk '{print $1}')
printf -- '- `%s.html`: `%s`\n' "${page}" "${checksum}" >> "$GITHUB_STEP_SUMMARY"
done
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 9590067..f23f288 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -103,7 +103,7 @@ jobs:
printf '### Distributable checksums\n| File | SHA-256 |\n|------|---------|\n' >> "$GITHUB_STEP_SUMMARY"
- for page in index router 0x67 cloud-google-drive; do
+ for page in index local 0x67 cloud-google-drive; do
checksum=$(node --experimental-strip-types tools/build/inliner/src/index.ts "pages/${page}/build.json" | awk '{print $1}')
printf '| `%s.html` | `%s` |\n' "${page}" "${checksum}" >> "$GITHUB_STEP_SUMMARY"
done
@@ -137,7 +137,7 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if gh attestation verify dist/0x67.html --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1 && \
- gh attestation verify dist/router.html --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1 && \
+ gh attestation verify dist/local.html --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1 && \
gh attestation verify dist/index.html --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1 && \
gh attestation verify dist/cloud-google-drive.html --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1 && \
gh attestation verify dist/CNAME --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
@@ -153,7 +153,7 @@ jobs:
with:
subject-path: |
dist/0x67.html
- dist/router.html
+ dist/local.html
dist/index.html
dist/cloud-google-drive.html
dist/CNAME
@@ -166,14 +166,14 @@ jobs:
notes="### Distributable checksums"$'\n'
notes+="| File | SHA-256 |"$'\n'
notes+="|------|---------|"$'\n'
- for file in dist/index.html dist/router.html dist/0x67.html dist/cloud-google-drive.html dist/CNAME; do
+ for file in dist/index.html dist/local.html dist/0x67.html dist/cloud-google-drive.html dist/CNAME; do
notes+="| \`$(basename "${file}")\` | \`sha256:$(sha256sum "${file}" | awk '{print $1}')\` |"$'\n'
done
gh release create "$GITHUB_REF_NAME" \
--title "$GITHUB_REF_NAME" \
--notes "${notes}" \
dist/0x67.html \
- dist/router.html \
+ dist/local.html \
dist/index.html \
dist/cloud-google-drive.html \
dist/CNAME
diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md
index 0735610..29d2ffb 100644
--- a/docs/CONTRIBUTING.md
+++ b/docs/CONTRIBUTING.md
@@ -33,7 +33,7 @@ All five are what CI runs on every push to `main` and pull request.
packages/argon2/ Argon2d/Argon2id KDF — see its README.md and SPEC.md
packages/chacha20/ ChaCha20/Salsa20 stream ciphers — see its README.md and SPEC.md
packages/kdbx/ KDBX 3.1/4.x parser and serializer — see its README.md and SPEC.md
-pages/ the browser app — index, router, and the KDBX 0x67 app itself
+pages/ the browser app — index, local, and the KDBX 0x67 app itself
tools/build/ the bundler and inliner that assemble each page into its own self-contained distributable, plus the ruleset and dependency policy CI checks
docs/ this document, plus the pipeline, release, and reproducibility docs
```
diff --git a/docs/PAGES.md b/docs/PAGES.md
index 09d7df6..8db1cb2 100644
--- a/docs/PAGES.md
+++ b/docs/PAGES.md
@@ -7,7 +7,7 @@ This document maps `pages/` — what each page does and how a visitor moves betw
| Page | Availability | Description |
|---|---|---|
| `index.html` | GA | Landing page. The entry point; links to every other page. |
-| `router.html` | GA | Detects a database's KDBX format and provides a link to the matching app page. |
+| `local.html` | GA | Local-file connector: reads a dropped file, detects its KDBX format, and embeds the matching app page in an iframe. |
| `0x67.html` | GA | The app — parses, decrypts, and edits KDBX 3.1 and 4.x databases. |
| `cloud-google-drive.html` | GA | Connector for Google Drive. |
| `cloud-microsoft-onedrive.html` | Future | Connector for OneDrive. |
@@ -19,9 +19,8 @@ This document maps `pages/` — what each page does and how a visitor moves betw
flowchart TD
INDEX["index.html
Landing page"]
- INDEX -->|"Link to upload a local database of unknown version"| ROUTER["router.html
Detects KDBX format"]
- INDEX -->|"Link to upload a local KDBX 3.1/4.x database"| APP["0x67.html
Parses and decrypts"]
- ROUTER -->|"Identified as KDBX 3.1/4.x,
link to upload KDBX 3.1/4.x database"| APP
+ INDEX -->|"Link to open a local database"| LOCAL["local.html
① read the file, detect KDBX format
② embed the matching app in an iframe"]
+ LOCAL -->|"Identified as KDBX 3.1/4.x,
embed 0x67.html in an iframe,
hand off bytes in memory"| APP["0x67.html
Parses and decrypts"]
INDEX -->|"Link to open from Google Drive"| DRIVE["cloud-google-drive.html
① Google sign-in (GIS token popup)
② pick a file, fetch bytes"]
INDEX -->|"Link to open from OneDrive"| ONEDRIVE["cloud-microsoft-onedrive.html
① Microsoft sign-in
② pick a file, fetch bytes"]
@@ -32,6 +31,12 @@ flowchart TD
DROPBOX -->|"Embed 0x67.html in an iframe,
hand off bytes in memory"| APP
```
+## How the local-file connector works
+
+`local.html` reads a dropped or chosen file's bytes once, right there in the tab — nothing is uploaded. It identifies the KDBX format from the file's first 8 bytes via the shared `packages/router` package (the same format-detection logic every chooser page uses, so which implementation reads a given format is decided in exactly one place), then embeds the matching implementation (currently only `0x67.html`) in an iframe and hands it the bytes it already read, over the same same-origin message protocol (`packages/embed-protocol`) the cloud connectors use. There is no second file picker: the file is never re-selected on the embedded app's own upload screen, because the app never shows one when opened this way. A file that's recognized but has no implementation yet (KeePass 1.x `.kdb`, a KDBX pre-release) is reported inline instead of embedding anything; a completely unrecognized file gets the same treatment.
+
+On save, since there is nowhere to write back to, the local connector downloads the updated bytes the same way `0x67.html` would if opened standalone — the only piece of this connector that's genuinely local-specific.
+
## How the Google Drive connector works
`cloud-google-drive.html` never parses or decrypts anything itself. It signs in to Google, lets the user pick a `.kdbx` file with the Google Picker, downloads its bytes, then embeds the real `0x67.html` app in an iframe and hands it those bytes. All the unlocking, browsing, and editing is the ordinary, unmodified app; the connector only fetches the file and writes it back.
@@ -42,7 +47,7 @@ flowchart TD
## Local storage
-Opening a database from local disk needs nothing but the file itself: no account, no sign-in, no network connection. `router.html` and `0x67.html` work completely offline, so a vault on a USB drive or a personal laptop opens the same way whether there's an internet connection or not. Nothing about the file goes anywhere — there's no vendor, no OAuth exchange, and no service to trust beyond the browser itself. Opening a local file needs no account of any kind and is open to every visitor.
+Opening a database from local disk needs nothing but the file itself: no account, no sign-in, no network connection. `local.html` and `0x67.html` work completely offline, so a vault on a USB drive or a personal laptop opens the same way whether there's an internet connection or not. Nothing about the file goes anywhere — there's no vendor, no OAuth exchange, and no service to trust beyond the browser itself. Opening a local file needs no account of any kind and is open to every visitor.
## Cloud storage providers
diff --git a/docs/PIPELINE.md b/docs/PIPELINE.md
index 3e051f7..c1e7d85 100644
--- a/docs/PIPELINE.md
+++ b/docs/PIPELINE.md
@@ -99,7 +99,7 @@ flowchart TD
TAG --> AREL["release.yml"]
AREL --> CI3["Lint · type check · test"]
CI3 --> VER2["Verify tag = package.json version"]
- VER2 --> BUILD["Full build from source: compile\npackages and pages, bundle, inline;\ncopy CNAME\nOutputs: 0x67.html · router.html\nindex.html · cloud-google-drive.html\nCNAME\n(version footer: tag + commit date)"]
+ VER2 --> BUILD["Full build from source: compile\npackages and pages, bundle, inline;\ncopy CNAME\nOutputs: 0x67.html · local.html\nindex.html · cloud-google-drive.html\nCNAME\n(version footer: tag + commit date)"]
BUILD --> ATTEST["Attest all five files\nactions/attest-build-provenance\nSigns to Sigstore transparency log"]
ATTEST --> GHREL["Create GitHub release\nUpload all five files\nPublish checksums in release notes"]
GHREL --> TOKEN["Generate short-lived App token\nscoped to the deploy repo"]
@@ -119,7 +119,7 @@ flowchart TD
TRIG --> CKO2["Checkout gh-pages branch"]
CKO2 --> DL["Download all five release assets\nfrom public GitHub release URL\nNo token required"]
DL --> V1["gh attestation verify 0x67.html"]
- V1 --> V2["gh attestation verify router.html"]
+ V1 --> V2["gh attestation verify local.html"]
V2 --> V3["gh attestation verify index.html"]
V3 --> V3b["gh attestation verify cloud-google-drive.html"]
V3b --> V4["gh attestation verify CNAME"]
diff --git a/docs/RELEASES.md b/docs/RELEASES.md
index ee80146..f5161b2 100644
--- a/docs/RELEASES.md
+++ b/docs/RELEASES.md
@@ -5,7 +5,7 @@
| File | Purpose |
|------|---------|
| `index.html` | Landing page |
-| `router.html` | Identifies a database's KDBX format and links to the right app version |
+| `local.html` | Identifies a local database's KDBX format and embeds the right app version in an iframe |
| `0x67.html` | The app itself, for KDBX 3.1 and 4.x database support |
| `cloud-google-drive.html` | Connector that opens and saves a database in the user's Google Drive, embedding `0x67.html` in an iframe |
| `CNAME` | The custom domain GitHub Pages serves the deploy from |
diff --git a/docs/REPRODUCING.md b/docs/REPRODUCING.md
index 502187a..6006665 100644
--- a/docs/REPRODUCING.md
+++ b/docs/REPRODUCING.md
@@ -36,7 +36,7 @@ Any party can reproduce a versioned distributable and verify it against the publ
sh -c "npm ci && npm run build"
```
- `npm run build` builds `argon2`, `chacha20`, and `kdbx`, then bundles and inlines each page. The inliner prints `sha256: