Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 30 additions & 5 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ src/
│ ├── SaveShare.tsx # Password-encrypt and save shares
│ ├── ShareList.tsx # Detect and list saved shares
│ ├── LoadShare.tsx # Decrypt and load share into memory
│ ├── AddShare.tsx # Import existing share from another device
│ ├── Signer.tsx # Start signing node, handle requests
│ ├── EventLog.tsx # Display signing events
│ ├── Recover.tsx # Reconstruct nsec from threshold shares
Expand All @@ -81,6 +82,8 @@ src/
│ ├── encryption.ts # PBKDF2 password derivation for share files
│ ├── filesystem.ts # Electron app data path utilities
│ ├── validation.ts # Input validation helpers
│ ├── echoRelays.ts # Relay planning and normalization utilities
│ ├── signer-keepalive.ts # Connection persistence and auto-reconnect
│ └── utils.ts # General utilities, cn() for Tailwind
├── types/
│ └── index.ts # Shared TypeScript types
Expand Down Expand Up @@ -115,12 +118,13 @@ src/
### State Management

App-level state in `App.tsx` tracks:
- `currentView`: Which screen is active
- `keyset`: Temporary in-memory keyset (cleared after saving shares)
- `loadedShare`: Currently decrypted share for signing
- `shares`: List of available shares from file system
- `showingCreate`, `showingRecover`, `showingAddShare`: Boolean flags for screen routing
- `keysetData`: Temporary in-memory keyset (cleared after saving shares)
- `signerData`: Currently decrypted share and metadata for signing
- `hasShares`: Whether any shares exist in file system
- `activeTab`: Current tab selection (signer/recovery)

Components communicate via props and callbacks; no Redux or external state library.
Components communicate via props and callbacks; no Redux or external state library. The `Signer` component exposes a ref handle (`SignerHandle`) to allow `App.tsx` to stop the signer when navigating away.

### Cryptographic Operations (via @frostr/igloo-core)

Expand Down Expand Up @@ -153,6 +157,27 @@ Shares are stored as encrypted JSON in `<appData>/igloo/shares/`:

Encryption: PBKDF2 with 600,000 iterations (v1 shares), user-provided password, random salt. Legacy shares (no version field) use 32 iterations.

### Relay Configuration

Relays are configured via `<appData>/igloo/relays.json`:
```json
{
"relays": ["wss://relay1.example.com", "wss://relay2.example.com"]
}
```

The `computeRelayPlan()` function in `echoRelays.ts` merges relays from multiple sources using conditional logic with two distinct paths:

**When `envRelay` is present:**
- Priority: explicit relays > `envRelay` > group relays

**When `envRelay` is absent:**
- Priority: explicit relays > configured relays (`relays.json`) → `baseRelays` parameter → `DEFAULT_ECHO_RELAYS` as fallbacks > group relays
- The `defaults` chain resolves as: if `relays.json` exists and contains relays, use those; otherwise fall back to the `baseRelays` parameter; if that's also absent, use `DEFAULT_ECHO_RELAYS` from `@frostr/igloo-core`
- Group relays are appended after the defaults chain

The function references: `envRelay` (from `IGLOO_RELAY` environment variable or passed parameter), `computeRelayPlan`, `baseRelays`, `DEFAULT_ECHO_RELAYS`, and `relays.json` (read via `readConfiguredRelaysSync()`).

## Testing Strategy

Tests focus on **desktop-specific functionality**:
Expand Down
23 changes: 23 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,29 @@
<html>
<head>
<meta charset="UTF-8" />
<!--
CSP Security Notes:
- 'unsafe-inline' for style-src: Required for Tailwind CSS and some React component
libraries. Nonce-based approach would require build-time or server-side generation
which isn't practical for static Electron HTML. Lower priority since style injection
is less dangerous than script injection.
- wss: wildcard for connect-src: Required because users configure arbitrary nostr
relays and group credentials embed relay URLs. Cannot be restricted without
breaking core app functionality. Note: ws:// (non-TLS) is intentionally blocked;
all relay connections must use secure WebSockets.
-->
<meta http-equiv="Content-Security-Policy" content="
default-src 'self';
script-src 'self';
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
font-src 'self' https://fonts.gstatic.com;
img-src 'self' data:;
connect-src 'self' wss:;
object-src 'none';
base-uri 'self';
form-action 'none';
frame-ancestors 'none';
">
<title>igloo</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
Expand Down
Loading
Loading