No description
  • TypeScript 74.9%
  • HTML 20.9%
  • JavaScript 4.2%
Find a file
Suite Dark f79368109c feat: add "Fill from Trezor Suite password manager" (getPassword)
Add a second fill source alongside the appSecrets vault: a context-menu item that reads the
user's existing Trezor Suite password-manager entry for the page host via the new getPassword
Connect method and fills it. The appSecrets Save/Fill/Manage flow is unchanged.

- whitelist passwordManager: ['getPassword'] in the connect-common patch
- service-worker: MENU_FILL_LEGACY_ID -> callSuite('getPassword', { domain }) -> TREZOR_FILL
- README: document the two fill sources

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-19 18:49:25 +02:00
.claude/skills docs: add agent skills mapping the extension and the suite-dark fork (#2) 2026-08-18 23:18:19 +02:00
docs feat: add GitHub Pages landing page explaining the extension + linking to the project 2026-08-18 22:27:24 +02:00
patches feat: add "Fill from Trezor Suite password manager" (getPassword) 2026-08-19 18:49:25 +02:00
src feat: add "Fill from Trezor Suite password manager" (getPassword) 2026-08-19 18:49:25 +02:00
.gitignore feat: switch client to appSecrets API — save, fill, and manage passwords 2026-08-19 17:23:29 +02:00
CLAUDE.md docs: add agent skills mapping the extension and the suite-dark fork (#2) 2026-08-18 23:18:19 +02:00
DESIGN.md feat: switch client to appSecrets API — save, fill, and manage passwords 2026-08-19 17:23:29 +02:00
LICENSE feat: scaffold Trezor Suite Dark password-autofill extension 2026-08-14 14:49:17 +02:00
package-lock.json feat: popup with connection status, toolbar badge, deeplink wake, and hardened fill flow 2026-08-17 22:22:11 +02:00
package.json feat: enforce desktop-only transport and harden username autofill 2026-08-14 15:41:08 +02:00
README.md feat: add "Fill from Trezor Suite password manager" (getPassword) 2026-08-19 18:49:25 +02:00
tsconfig.json feat: scaffold Trezor Suite Dark password-autofill extension 2026-08-14 14:49:17 +02:00
webpack.config.js feat: switch client to appSecrets API — save, fill, and manage passwords 2026-08-19 17:23:29 +02:00

Trezor Suite Dark Passwords (browser extension)

An MV3 browser extension that saves and fills passwords secured by your Trezor. You right-click a password field on any web page and either fill it from your Trezor-backed vault or save the current login into it. The encryption and the device confirmation stay inside Trezor Suite; the extension only ever handles the plaintext for the one field being filled or saved.

It talks to Suite through @trezor/connect-webextension over the local suite-desktop app (WebSocket ws://127.0.0.1:21335/connect-ws), using the fork's appSecrets Connect API (getAppSecret / setAppSecret / listAppSecrets / revokeAppSecret).

What it is (and isn't)

appSecrets is a per-origin key→value secret store. Suite scopes every secret to the extension's own verified origin (chrome-extension://<id>, taken from the WebSocket Origin header) — not to the web page. So this extension owns its own Trezor-backed vault:

  • It does not read Suite's built-in password-manager (Dropbox) entries — it can only see secrets it saved here.
  • The vault starts empty. You must save a login before you can fill it.
  • Each secret is name → value; we use name = <site host> and pack { username, password } into the value. The device encrypts it (Suite Sync stores only ciphertext), and every fill requires a physical Trezor confirmation (saving does not).

Two fill sources

The right-click menu offers two ways to fill, from two different stores:

  • Fill password with Trezor Suite → the extension's own appSecrets vault (what you saved via Save password to Trezor Suite). Origin-scoped to this extension.
  • Fill from Trezor Suite password manager → your existing Trezor Suite password-manager entries (the getPassword method, matched by the page host). This reads your real vault, so it works with logins you already have in Suite — no per-extension saving needed. It unlocks the password store on device, then confirms the specific entry.

Status: work in progress. The extension is complete and the Suite side (the appSecrets API, the export_secret consent, the device-confirm read) is implemented on the suite-dark/suite-dark fork. It works end-to-end against a suite-desktop build that includes appSecrets, with a wallet open. Against a Suite build without it, Suite answers Method_Unsupported and the extension shows a note. See DESIGN.md.

How it works

FILL                                          SAVE
Right-click a password field                  Right-click a password field
  │  "Fill password with Trezor Suite"          │  "Save password to Trezor Suite"
  ▼  (service worker)                            ▼  (service worker asks the frame to
TrezorConnect.call({ getAppSecret, name })        capture the current username+password)
  │  connect-ws → suite-desktop                   ▼
  ▼                                             TrezorConnect.call({ setAppSecret, name, value })
Suite: export_secret consent → device            │  connect-ws → suite-desktop
confirm → decrypt → { value }                     ▼
  │  service worker decodes {username,password}  Suite: export_secret consent → device-encrypt
  ▼                                                → Suite Sync persists ciphertext
content script fills the field(s)                 ▼
                                               content script shows "Uloženo do Trezoru"

name is derived from the page host (lowercased, leading www. stripped). value is a small versioned JSON envelope { v, u, p }; a non-JSON value is treated as a bare password for forward/backward compatibility.

Build

npm install           # runs postinstall → patch-package
npm run build         # → build/  (production)
npm run dev           # watch build (development)

Install runs patch-package (postinstall), which applies patches/@trezor+connect-common+*.patch. That patch is required: it whitelists the appSecrets methods in @trezor/connect-webextension's client-side API guard (the published beta predates them) and enforces desktop-only routing (no Suite Web fallback). See DESIGN.md → "Transport".

The toolbar popup can wake a closed Suite Dark via a custom-URL deeplink. The scheme defaults to suitedark:// (what the suite-dark desktop build registers); override it for an upstream Trezor Suite build:

SUITE_DEEPLINK=trezorsuite:// npm run build

Extension identity (important)

src/manifest.json pins a public key, which fixes the extension id — and therefore the chrome-extension://<id> origin that all your saved secrets are scoped to. Do not change or remove it, or Suite will scope secrets under a different origin and previously saved passwords become unreadable. The matching private key is generated into keys/ (gitignored); back it up if you plan to publish. To regenerate (only for a fresh identity):

openssl genrsa -out keys/extension-key.pem 2048
openssl rsa -in keys/extension-key.pem -pubout -outform DER | base64 -w0   # → paste into manifest "key"

Popup, connection status & waking Suite

Clicking the toolbar icon opens a small popup that:

  • shows whether Suite Dark desktop is reachable (a live status dot; the toolbar icon also carries a green badge while connected). Reachability is a lightweight WebSocket probe of ws://127.0.0.1:21335/connect-ws — it opens and immediately closes a socket, so it triggers no Suite popup or device interaction;
  • offers "Otevřít Suite Dark" when the app is closed — this fires the suitedark:// deeplink to launch/focus the desktop app, then polls until connect-ws comes up;
  • links to the project (web, downloads, GitHub) and shows the how-to.

The service worker polls the connection every ~30s (chrome.alarms) and keeps the badge + cached status warm; the popup reads that cache for an instant first paint and re-probes on open.

Website (GitHub Pages)

A self-contained landing page lives in docs/: it explains what the extension is, how the fill flow and the live connection status work, how to install it, and links to the Suite Dark project. It is plain HTML/CSS (no build step) and matches the popup's dark theme.

Publish it by enabling GitHub Pages on this repo → Settings → Pages → Build and deployment → Deploy from a branch → main / /docs. It then serves at https://suite-dark.github.io/suite-extension-dark/ (the URL the popup's Web link points to). The docs/.nojekyll file disables Jekyll so the page is served verbatim.

Load it in the browser

  1. npm run build
  2. Chrome → chrome://extensions → enable Developer modeLoad unpacked → select the build/ folder.
  3. Open Trezor Suite Dark (desktop) with a wallet open — or click the extension icon → Otevřít Suite Dark.
  4. On any page, right-click a password field. Either Fill from Trezor Suite password manager to fill a login you already have in Suite, or Save password to Trezor Suite + Fill password with Trezor Suite to use the extension's own appSecrets vault.
  5. To review or delete what's stored in the extension's vault, open the extension icon → Uložená hesla (the manage view, opens in its own tab). Each action needs a Suite confirmation.

Project layout

File Role
src/manifest.json MV3 manifest (context menus, content script, action popup, pinned key/identity).
src/service-worker.ts Registers the menus, calls getAppSecret/setAppSecret, routes the result; polls connection + updates the badge.
src/content-script.ts Tracks the right-clicked field; fills password (+ nearby username), and captures the current login for saving.
src/popup.html / src/popup.ts Action popup: connection status, wake-via-deeplink, project links, link to manage view.
src/options.html / src/options.ts Manage view (full tab): list saved secret names + revoke them (listAppSecrets/revokeAppSecret).
src/connection.ts Shared connect-ws reachability probe + status types.
webpack.config.js Bundles the entry points; injects __SUITE_WEB_URL__ + __SUITE_DEEPLINK__.
patches/ patch-package patch of @trezor/connect-common (whitelist appSecrets methods + desktop-only).
keys/ Extension signing key (private .pem gitignored; public key is pinned in the manifest).
docs/ GitHub Pages landing page (self-contained index.html).
DESIGN.md Architecture + the appSecrets wire contract.

Security notes

  • Plaintext credentials exist only transiently in the service worker and content script, and are never logged or persisted.
  • The extension performs no encryption itself — Suite + the Trezor device do. Suite stores only ciphertext (Suite Sync); reads require a physical device confirmation.
  • Secrets are isolated per origin by Suite. Note that the local connect-ws server currently trusts the Origin header verbatim, so any local process reaching 127.0.0.1:21335 could present this extension's origin — a known local-trust limitation of the desktop transport.