diff --git a/image-recipe/configs/nginx-archipelago.conf b/image-recipe/configs/nginx-archipelago.conf index 8ba41d14..eade7f46 100644 --- a/image-recipe/configs/nginx-archipelago.conf +++ b/image-recipe/configs/nginx-archipelago.conf @@ -537,6 +537,27 @@ server { sub_filter "src='/" "src='/ext/arch-presentation/"; sub_filter '' ''; } + location /ext/nostrudel/ { + proxy_pass https://nostrudel.ninja/; + proxy_http_version 1.1; + proxy_set_header Host nostrudel.ninja; + proxy_set_header Accept-Encoding ""; + proxy_ssl_server_name on; + proxy_hide_header X-Frame-Options; + proxy_hide_header Content-Security-Policy; + proxy_hide_header Cross-Origin-Embedder-Policy; + proxy_hide_header Cross-Origin-Opener-Policy; + proxy_hide_header Cross-Origin-Resource-Policy; + add_header X-Content-Type-Options "nosniff" always; + sub_filter_once off; + sub_filter_types text/css application/javascript; + sub_filter 'href="/' 'href="/ext/nostrudel/'; + sub_filter 'src="/' 'src="/ext/nostrudel/'; + sub_filter 'action="/' 'action="/ext/nostrudel/'; + sub_filter "href='/" "href='/ext/nostrudel/"; + sub_filter "src='/" "src='/ext/nostrudel/"; + sub_filter '' ''; + } # Proxy WebSocket location /ws { @@ -814,6 +835,27 @@ server { sub_filter "src='/" "src='/ext/arch-presentation/"; sub_filter '' ''; } + location /ext/nostrudel/ { + proxy_pass https://nostrudel.ninja/; + proxy_http_version 1.1; + proxy_set_header Host nostrudel.ninja; + proxy_set_header Accept-Encoding ""; + proxy_ssl_server_name on; + proxy_hide_header X-Frame-Options; + proxy_hide_header Content-Security-Policy; + proxy_hide_header Cross-Origin-Embedder-Policy; + proxy_hide_header Cross-Origin-Opener-Policy; + proxy_hide_header Cross-Origin-Resource-Policy; + add_header X-Content-Type-Options "nosniff" always; + sub_filter_once off; + sub_filter_types text/css application/javascript; + sub_filter 'href="/' 'href="/ext/nostrudel/'; + sub_filter 'src="/' 'src="/ext/nostrudel/'; + sub_filter 'action="/' 'action="/ext/nostrudel/'; + sub_filter "href='/" "href='/ext/nostrudel/"; + sub_filter "src='/" "src='/ext/nostrudel/"; + sub_filter '' ''; + } location /ws { proxy_pass http://127.0.0.1:5678; diff --git a/loop/plan.md b/loop/plan.md index 5974099e..98cb04f2 100644 --- a/loop/plan.md +++ b/loop/plan.md @@ -486,7 +486,7 @@ - [x] **NIP07-02** — Add signing consent modal. In `neode-ui/src/components/`, create `NostrSignConsent.vue` — a modal that shows when an iframe app requests a Nostr signature. Display: requesting app name/origin, event kind number, event content preview (truncated to 200 chars), and Approve/Deny buttons. In `neode-ui/src/stores/appLauncher.ts` `handleNostrRequest()`, instead of immediately signing, emit an event that triggers this modal. Only call the backend RPC after user approves. Add a "Remember for this app" checkbox that stores approved origins in localStorage. **Acceptance**: Open a Nostr app in iframe, trigger a sign request — consent modal appears. Approve → signature returned. Deny → error returned to iframe. Deploy and verify. -- [ ] **NIP07-03** — Test NIP-07 with a real Nostr web app. Install `nostr-rs-relay` container if not already running (it's in the app catalog). Deploy a Nostr web client that supports NIP-07 — add Nostrudel (https://nostrudel.ninja) as a web-only app entry in `Marketplace.vue` `getCuratedAppList()` (category: "Social", opens in iframe). Open Nostrudel, verify it detects `window.nostr`, can fetch the pubkey, and can sign events (post a note). **Acceptance**: Can post a signed Nostr note from within the Archipelago iframe using the node's Nostr identity. Verify the note appears on a public Nostr client. +- [x] **NIP07-03** — Test NIP-07 with a real Nostr web app. Install `nostr-rs-relay` container if not already running (it's in the app catalog). Deploy a Nostr web client that supports NIP-07 — add Nostrudel (https://nostrudel.ninja) as a web-only app entry in `Marketplace.vue` `getCuratedAppList()` (category: "Social", opens in iframe). Open Nostrudel, verify it detects `window.nostr`, can fetch the pubkey, and can sign events (post a note). **Acceptance**: Can post a signed Nostr note from within the Archipelago iframe using the node's Nostr identity. Verify the note appears on a public Nostr client. - [ ] **NIP07-04** — Support NIP-04 and NIP-44 encryption in iframe provider. The `nostr-provider.js` already has stubs for `nip04.encrypt`, `nip04.decrypt`, `nip44.encrypt`, `nip44.decrypt`. Add backend RPC endpoints: `identity.nostr-encrypt-nip04`, `identity.nostr-decrypt-nip04`, `identity.nostr-encrypt-nip44`, `identity.nostr-decrypt-nip44`. Each takes the identity ID, peer pubkey, and plaintext/ciphertext. Use `nostr_sdk` for the actual crypto. Register in RPC router. Wire the appLauncher `handleNostrRequest` to route `nip04.*` and `nip44.*` calls to these endpoints. **Acceptance**: From an iframe app, call `window.nostr.nip44.encrypt(peerPubkey, "hello")` — returns ciphertext. Call `nip44.decrypt` with same ciphertext — returns "hello". Deploy and verify. diff --git a/neode-ui/public/assets/img/app-icons/nostrudel.svg b/neode-ui/public/assets/img/app-icons/nostrudel.svg new file mode 100644 index 00000000..864fae1b --- /dev/null +++ b/neode-ui/public/assets/img/app-icons/nostrudel.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/neode-ui/src/stores/appLauncher.ts b/neode-ui/src/stores/appLauncher.ts index e5275f40..cc800a44 100644 --- a/neode-ui/src/stores/appLauncher.ts +++ b/neode-ui/src/stores/appLauncher.ts @@ -17,6 +17,7 @@ const EXTERNAL_PROXY_PATH: Record = { 'botfights.net': '/ext/botfights/', '484.kitchen': '/ext/484-kitchen/', 'present.l484.com': '/ext/arch-presentation/', + 'nostrudel.ninja': '/ext/nostrudel/', } function mustOpenInNewTab(url: string): boolean { diff --git a/neode-ui/src/views/Marketplace.vue b/neode-ui/src/views/Marketplace.vue index 359ffd13..7968a623 100644 --- a/neode-ui/src/views/Marketplace.vue +++ b/neode-ui/src/views/Marketplace.vue @@ -943,6 +943,18 @@ function getCuratedAppList() { manifestUrl: undefined, repoUrl: 'https://github.com/TBD54566975/dwn-server' }, + { + id: 'nostrudel', + title: 'noStrudel', + version: '0.40.0', + description: 'A feature-rich Nostr web client with NIP-07 signer support. Browse your feed, post notes, manage relays, and interact with the Nostr network — all signed with your node\'s Nostr identity.', + icon: '/assets/img/app-icons/nostrudel.svg', + author: 'hzrd149', + dockerImage: '', + manifestUrl: undefined, + repoUrl: 'https://github.com/hzrd149/nostrudel', + webUrl: 'https://nostrudel.ninja' + }, { id: 'nostr-rs-relay', title: 'Nostr Relay',