Skip to content

v1.6.0 — Continue with Google, signing consent & cross-client recovery

Latest

Choose a tag to compare

@0ceanSlim 0ceanSlim released this 01 Aug 00:34

MILL 1.6.0 is a big one. It adds a "Continue with Google" onboarding path for non-technical users, a per-event signing consent system for private-key signing, a draft NIP + reference implementation for cross-client key recovery, full header/footer branding, and a real fix for Amber (NIP-55) login — while keeping mill a zero-config, drop-in <script> tag.

Nothing here is breaking for existing integrations. Every new capability is opt-in and off by default; if you don't configure it, the picker looks and behaves as it did in 1.5.


✨ Continue with Google — onboarding for normies

A familiar "Sign in with Google" path for people who don't want to think about keys. Mill generates and holds the key, the user sets a short PIN, and the encrypted key lives in the user's own Google Drive (the hidden appDataFolder — private to the app). Returning users unlock on any device with their PIN.

  • Real Google logo, first-class in the picker and under "I'm new here".
  • Bring your own key — import an existing nsec at setup instead of generating.
  • Take control of my keys — reveal the nsec and export a portable NIP-49 ncryptsec whenever the user chooses. Onboard easy, leave anytime.
  • Manage stored keys — list, remove, and hold multiple accounts on one Google account, with an account chooser when several share a PIN.

Opt-in: it appears only when you deploy the OAuth shim and set oauthShim. See docs/google-login-setup.md and shim/mill-oauth.html.

MILL.open({ oauthShim: 'https://auth.yourdomain.com/mill-oauth.html' });

On the PIN, honestly: a short PIN protects against casual access, not against someone who already has the encrypted blob. The real protection is the user's Google account and its 2FA — and the UI says so. For at-rest security independent of the account, users export a passphrase-protected ncryptsec.


🔐 Per-event signing consent (private key)

When mill holds the key, it's the signer — so it now owns the approval UX, instead of silently signing everything.

  • A consent card shows what is being signed (kind, decoded content, tags) with a remember-my-choice duration — just this time / 5 min / 1 hour / this session / always.
  • Allow / Deny / Ask per event kind, with a permissions manager to review and revoke — reachable from the card (no host wiring) or via MILL.openSettings().
  • Two independent gates, the way Amber works: a session password unlocks the key once; consent approves each event. A remembered grant signs without re-prompting.
  • Fixes a bug where "prompt every time" categories silently signed anyway in the first session.

Human-readable kind labels are adapted from grain's kind table.


🌐 Cross-client key recovery (experimental — draft NIP)

The start of true interoperability: recover the same identity in other Nostr clients from a Google account + a strong recovery phrase.

  • A draft NIP — a passphrase-encrypted key, addressed by the cloud account, stored on relays — hardened by a three-lens adversarial review (cryptography, Nostr-protocol, ops/privacy).
  • A reference implementation in src/nipbackup.js: scrypt + HKDF derivation, NIP-49 ncryptsec payload, signature-verified relay fetch with quorum, a generated ≥70-bit recovery phrase.

Off unless you set backupRelays. Experimental: the kind and relay set are provisional and may change. Mill still forces the user to keep their own key. Read the NIP's Security Considerations before enabling.

MILL.open({ oauthShim: '…', backupRelays: ['wss://your-relay'] });

🎨 Header & footer branding

Make the modal yours.

  • Header — a real brand block: an image logo at natural size (or emoji), a title, a short message, aligned left or center. Set any of these and the header is fully yours; no mill wording leaks in.
  • Footer — your tagline + links (Terms, Privacy, …), plus an optional, on-by-default "Signer by MILL" attribution you can repoint or hide.
  • The hardcoded "Account Access" label and "Not sure? …" tip are now configurable or hideable.
MILL.open({
  header: { logo: 'https://you.com/logo.png', title: 'YourApp', message: 'Your keys, your Nostr.', align: 'center' },
  footer: { links: [{ label: 'Terms', href: '/terms' }, { label: 'Privacy', href: '/privacy' }] },
});

📱 Amber (NIP-55) actually works again

Amber ≥ 6.0.0 broke web callbacks (query strings in callbackUrl get shredded). Mill now defaults to Amber's clipboard return — no server, no callback route, no host code — and if you do pass a callback URL, it's normalized to a fragment that survives modern Amber. returnType is corrected for sign_event.


🧹 Also in this release

  • Mobile permissions screen fixed — no more off-screen overflow; a plain-language summary that expands to the full editor. (The codebase gained its first responsive rules.)
  • Signing-permission vocabulary reworked from "unlock/password" to Auto-approve / Review, matching the new consent model.
  • NIP-46 bunker connections are quiet by default (no console spam; the in-modal diagnostic panel is unaffected).
  • The OAuth shim and docs now ship in the npm package (shim/, docs/), as a clear template.

📦 Install

<script src="https://cdn.jsdelivr.net/npm/nostr-mill@1.6.0/dist/mill.umd.min.js"></script>
npm install nostr-mill@1.6.0

New API options on MILL.open: oauthShim, backupRelays, header, footer, tip. New result.method: google. New MILL.openSettings(). Full docs in the README.

Note: the bundle grew (~244 KB → ~276 KB min) — the cloud-backup crypto pulls in @noble/hashes (scrypt/HKDF) and the @scure/bip39 wordlist. These are only exercised by the opt-in Google/recovery paths.


Full changelog: v1.5.0...v1.6.0