Repository navigation
Expand file tree
/
Copy pathllms-full.txt
More file actions
268 lines (210 loc) · 11.8 KB
/
Copy pathllms-full.txt
File metadata and controls
268 lines (210 loc) · 11.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# Bark — Complete Reference
> Bark is a browser extension (Chromium, Firefox, and Safari) that implements
> NIP-07 (window.nostr) and delegates all signing to a remote NIP-46 bunker.
> No private keys ever exist in the browser.
---
## Project overview
Bark sits between Nostr web apps and a remote signing device. Web apps call the
standard `window.nostr` interface; Bark forwards every request over a NIP-46
relay connection to a hardware or software signer and returns the result.
**Who it is for:**
- Nostr users who want browser-based signing without trusting the browser with
their private key.
- Heartwood device owners who want persona switching (multiple derived
identities) from any browser tab.
- Developers building or testing NIP-07-dependent web apps against a real
signing backend.
**What it is not:**
- A key manager. Bark stores zero key material.
- An Alby replacement. No Lightning, no wallet, no zaps.
- Amber-only. Bark works with any NIP-46-compliant bunker.
**Package:** `@forgesworn/bark` (private, not published to npm)
**Licence:** MIT
**Source:** https://github.com/forgesworn/bark
**Part of:** ForgeSworn open-source ecosystem
---
## Architecture
### Source files
Bark has eight core source files in `src/`, plus `i18n.js` (loads the 53
`_locales/*/messages.json` UI translations) and `diagnostic.html` (an
extension-internal page used by e2e for storage seeding).
| File | Role |
|------|------|
| `provider.js` | MAIN-world content script (Chromium/Firefox; Safari falls back to script-tag injection). Implements `window.nostr`. Posts `bark-request` messages to the content script and resolves pending promises on `bark-response`. `signEvent` gets a 180-second timeout (it can traverse an approval window, a cold NIP-46 reconnect, and a hardware button press); other methods get 120 seconds. Shows a stale-extension banner on a version-mismatch response. |
| `content-script.js` | Bridge between the page and the extension. Relays `postMessage` to `chrome.runtime.sendMessage`, validates message origin and structure, retries MV3 service-worker wakeups, and shows the temporary in-page approval notice without reading page content. |
| `background.js` | Service worker. Holds the NIP-46 connection via `nostr-tools` `BunkerSigner`. Routes requests, validates methods, applies policies, manages multi-instance storage, and sanitises errors before returning them to the page. |
| `popup.js` | Popup UI. Two-tier rendering: standard bunker mode and Heartwood mode. Shows relay health, active persona, and connection controls. |
| `popup.html` | Popup markup and styles. Dark theme, 320 px wide. |
| `policy.js` | Stateless policy evaluation engine. Evaluates allow/ask/deny for each signing request against a layered rule set: site-specific kind rule, site-specific method deny, global kind rule, site-specific method default, global method default, fallback deny. |
| `approve.js` | Approval popup logic. Queries the background for pending request details, renders them, and sends the user's allow/deny decision back. |
| `approve.html` | Approval popup markup. 420 x 520 px on desktop; a foreground tab on Firefox for Android, which has no `windows` API. |
### Message flow
```
Web page
└─ window.nostr.signEvent(event)
└─ provider.js [postMessage: bark-request]
└─ content-script.js [chrome.runtime.sendMessage: bark-request]
└─ background.js [policy check → BunkerSigner → NIP-46 relay]
└─ Heartwood / nsecBunker / Amber
response back through the same chain
```
### Message types (chrome.runtime)
| Type | Direction | Purpose |
|------|-----------|---------|
| `bark-request` | Page to background | NIP-07, NIP-04, NIP-44, or Heartwood RPC call |
| `bark-response` | Background to page | Result or error for a `bark-request` |
| `bark-reset` | Popup to background | Tear down connection (disconnect or URI change) |
| `bark-status` | Popup to background | Query connection state, relay health, Heartwood mode, auth_url |
| `bark-pair` / `bark-switch` / `bark-remove` | Popup to background | Instance management |
| `bark-nostrconnect-start` / `-status` / `-cancel` | Popup to background | QR (nostrconnect) pairing flow |
| `bark-approval-query` | Approve popup to background | Fetch pending approval details |
| `bark-approval-response` | Approve popup to background | User's allow/trust/deny decision |
| `bark-heartwood-import-confirm` | Popup to background | Confirm or discard a staged identity import |
| `bark-prime-signer` | Popup to background | Signer health check (signs a kind 22242 probe) |
### Storage layout
Bark uses `chrome.storage.local`. The multi-instance format:
```jsonc
{
"instances": [
{
"id": "work-deadbeef",
"name": "work",
"address": "http://heartwood.local",
"bunkerUri": "bunker://deadbeef...?relay=wss://relay.example",
"clientSecret": "<hex>",
"npub": "npub1...",
"signingPubkey": "<hex>",
"isHeartwood": true
}
],
"activeInstanceId": "work-deadbeef",
"policies": { /* PolicySet */ }
}
```
Legacy single-connection storage is automatically migrated on first load.
---
## Installation and setup
### Install from release
1. Download the package for your browser from the
[latest GitHub release](https://github.com/forgesworn/bark/releases/latest).
2. Extract the zip.
3. Open `chrome://extensions/`, enable Developer mode.
4. Click "Load unpacked", select the extracted directory.
5. Click the Bark icon, enter a Heartwood/bridge address or paste your
`bunker://` URI.
### Build from source
```bash
git clone https://github.com/forgesworn/bark.git
cd bark && npm install && npm run build:all
```
Load the relevant output as an unpacked extension: `dist/` for Chromium,
Chrome, Brave and Edge; `dist-firefox/` for Firefox; `dist-safari/` for
Safari, through Apple's Safari Web Extension conversion flow.
**Scripts:**
| Command | Effect |
|---------|--------|
| `npm run build` | One-shot Chromium build via esbuild |
| `npm run build:firefox` / `build:safari` / `build:all` | Build the other targets |
| `npm run watch` | Incremental build on file change |
| `npm test` | Run vitest unit tests |
| `npm run e2e:chromium` | Playwright e2e (builds first) |
| `npm run package:all` | Build and zip all three browser targets |
---
## API surface
### NIP-07 (window.nostr)
All methods delegate to the active NIP-46 bunker. They are async and reject with
an `Error` on failure or timeout.
```js
// Returns the active signing pubkey as a 64-char lowercase hex string.
const pubkey = await window.nostr.getPublicKey()
// Returns the active signer's relay list.
const relays = await window.nostr.getRelays()
// Signs a Nostr event. Returns the event with .sig and .id populated.
const signed = await window.nostr.signEvent(event)
// NIP-04 encryption/decryption (legacy; requires bunker support).
const legacyCiphertext = await window.nostr.nip04.encrypt(recipientPubkey, plaintext)
const legacyPlaintext = await window.nostr.nip04.decrypt(senderPubkey, legacyCiphertext)
// NIP-44 encryption/decryption (requires bunker support).
const ciphertext = await window.nostr.nip44.encrypt(recipientPubkey, plaintext)
const plaintext = await window.nostr.nip44.decrypt(senderPubkey, ciphertext)
```
Request timeout: 180 seconds for `signEvent` (it can traverse an approval
window, a cold NIP-46 reconnect, and a hardware button press), 120 seconds for
other methods.
### Heartwood RPC extensions
Available under `window.nostr.heartwood` only when connected to a Heartwood
signer (`isHeartwood: true`). Each call is sent as a standard NIP-46 request
via `BunkerSigner.sendRequest()`.
**`window.nostr.heartwood.listIdentities()`** calls `heartwood_list_identities`.
Returns all derived identities on the device.
- Params: none
- Returns: `Array<{ pubkey: string, name?: string, purpose?: string }>`
**`window.nostr.heartwood.derivePersona(name, index = 0)`** calls
`heartwood_derive_persona`. Derives a new identity from the device mnemonic.
- `name`: alphanumeric/hyphens/dots label, 1 to 64 chars (e.g. `"nostr"`, `"twitter"`)
- `index`: integer, `0` to `1000`
- Returns: `{ pubkey: string, purpose: string, index: number }`
**`window.nostr.heartwood.switch(target)`** calls `heartwood_switch`.
Switches the active signing identity. Current Heartwood signers select
identity per bunker connection instead, so this call is kept for older
Heartwood builds and third-party callers.
- `target`: npub, persona name, purpose, or `"master"`
- Returns: Heartwood-specific status for the current connection
### Policy system
Background enforces a layered allow/ask/deny policy before forwarding requests:
1. Site-specific kind rule (highest priority)
2. Site-specific method deny (a blocked site stays blocked)
3. Global kind rule
4. Site-specific method default
5. Global method default
6. Fallback: deny
Default policy: `getPublicKey`, `getRelays`, `signEvent`, `nip04.encrypt`,
`nip04.decrypt`, `nip44.encrypt`, `nip44.decrypt`, and every `heartwood_*`
method are all `ask`. Event kinds 0 (profile), 3 (contact list), and 10002
(relay list) remain protected on trusted sites unless explicitly overridden.
Heartwood identity operations are deliberately excluded from the set a
trusted site is granted: trusting a site for signing must not also grant
identity management.
When a request is `ask`, Bark opens an approval popup for the user to allow
once, trust the site, or deny. The requesting page also receives a temporary
Bark notice whose action foregrounds the approval popup. The notice clears
when the request settles.
---
## Security model
- **No local key material.** Bark never generates, stores, or touches private
keys. The browser extension has no access to the user's nsec.
- **Bunker-backed signing.** All cryptographic operations happen inside the
remote signer (Heartwood hardware, nsecBunker, Amber, or any NIP-46 signer).
- **Origin validation.** Content script only relays messages from the same
window and origin. Request IDs are validated as positive integers.
- **Error sanitisation.** Background sanitises errors before returning them to
the page. Internal stack traces and connection details are never exposed.
- **Client secret.** Bark generates a random NIP-46 client secret per instance
and stores it in `chrome.storage.local`. It is used for the NIP-46 handshake
only; it is not the user's signing key.
- **Policy enforcement.** Sensitive event kinds require explicit user approval
before being forwarded to the signer.
- **Privacy mode.** Optionally hides `window.nostr` from every site except an
explicit allowlist, so pages that do not have a site rule cannot detect the
extension.
- **No data collection.** No analytics, no third-party services, no telemetry.
See PRIVACY.md.
---
## Dependencies
| Package | Version | Purpose |
|---------|---------|---------|
| `nostr-tools` | `^2.24.1` | `BunkerSigner`, `parseBunkerInput`, `SimplePool`, crypto utilities |
| `esbuild` (dev) | `^0.28.2` | Bundler |
| `vitest` (dev) | `^5.0.1` | Unit test runner |
| `@playwright/test` (dev) | `^1.63.0` | End-to-end test runner |
---
## Related projects
| Project | URL | Relationship |
|---------|-----|-------------|
| Heartwood | https://github.com/forgesworn/heartwood | Hardware NIP-46 signing appliance; enables persona features |
| Sapwood | https://github.com/forgesworn/sapwood | Provisions and manages Heartwood signers, bunker slots, and policies |
| Cambium | https://github.com/forgesworn/cambium | NIP-55 signer for Android that proxies to Heartwood; Bark's counterpart for native apps |
| nsec-tree | https://github.com/forgesworn/nsec-tree | Sub-identity derivation library used by Heartwood |
| ForgeSworn | https://github.com/forgesworn | Parent ecosystem |
| NIP-07 spec | https://github.com/nostr-protocol/nips/blob/master/07.md | Browser signer interface |
| NIP-46 spec | https://github.com/nostr-protocol/nips/blob/master/46.md | Remote signing protocol |