diff --git a/README.md b/README.md index 28147cd..7949371 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Plateforme de publication d'articles scientifiques et de science-fiction avec sy ## Features -- **NostrConnect Integration**: Authenticate using NostrConnect (default: use.nsec.app) +- **Nostr Wallet Integration**: Authenticate using nos2x extension (NIP-07) or NostrConnect bridge (NIP-46) - **Free Previews**: Public notes showing article previews - **Paid Content**: Private notes containing full content, unlocked after 800 sats zap - **Lightning Payments**: Integrated Alby/WebLN for Lightning payments (works with Alby and other Lightning wallets) @@ -28,7 +28,7 @@ npm run dev ## Environment Variables - `NEXT_PUBLIC_NOSTR_RELAY_URL`: Nostr relay URL (default: wss://relay.damus.io) -- `NEXT_PUBLIC_NOSTRCONNECT_BRIDGE`: NostrConnect bridge URL (default: https://use.nsec.app) +- `NEXT_PUBLIC_NOSTRCONNECT_BRIDGE`: NostrConnect bridge URL (optional, nos2x extension is used by default) ## Lightning Wallet Setup diff --git a/docs/faq.md b/docs/faq.md index 90342e2..3c4a1df 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -38,7 +38,7 @@ Le sponsoring permet de soutenir directement un auteur avec **0.046 BTC** : ### Comment me connecter ? -Cliquez sur "Connect with Nostr" et autorisez la connexion avec votre portefeuille Nostr. L'application utilise NostrConnect (par défaut via `use.nsec.app`). +Cliquez sur "Connect with Nostr" et autorisez la connexion avec votre portefeuille Nostr. L'application utilise l'extension nos2x (NIP-07) par défaut, ou un pont NostrConnect (NIP-46) si configuré. ### J'ai besoin d'un compte ? diff --git a/docs/rizful-api-setup.md b/docs/rizful-api-setup.md index a90f300..88a287b 100644 --- a/docs/rizful-api-setup.md +++ b/docs/rizful-api-setup.md @@ -57,7 +57,7 @@ RIZFUL_API_URL=https://api.rizful.com # Variables publiques (client-side) NEXT_PUBLIC_NOSTR_RELAY_URL=wss://relay.damus.io -NEXT_PUBLIC_NOSTRCONNECT_BRIDGE=https://use.nsec.app +NEXT_PUBLIC_NOSTRCONNECT_BRIDGE= # Optional: nos2x extension is used by default ``` **⚠️ Important** : diff --git a/docs/user-guide.md b/docs/user-guide.md index b1fd3ef..15b12a1 100644 --- a/docs/user-guide.md +++ b/docs/user-guide.md @@ -62,7 +62,7 @@ Pour effectuer des paiements Lightning, vous devez installer une extension de po 1. Cliquez sur le bouton **"Connect with Nostr"** en haut à droite 2. Une fenêtre s'ouvrira pour vous connecter avec votre portefeuille Nostr -3. Par défaut, l'application utilise `use.nsec.app` comme pont NostrConnect +3. Par défaut, l'application utilise l'extension nos2x (NIP-07). Un pont NostrConnect (NIP-46) peut être configuré via la variable d'environnement `NEXT_PUBLIC_NOSTRCONNECT_BRIDGE` 4. Autorisez la connexion dans votre portefeuille Nostr ### Que se passe-t-il après la connexion ? diff --git a/features/features.md b/features/features.md index 03873a8..698124c 100644 --- a/features/features.md +++ b/features/features.md @@ -7,7 +7,7 @@ ### Nostr Paywall → zapwall4Science - Publication d'articles avec aperçus gratuits et contenu payant - Paiement Lightning via Alby/WebLN (remplacement de Rizful) -- Connexion via NostrConnect (use.nsec.app) +- Connexion via nos2x extension (NIP-07) ou NostrConnect bridge (NIP-46) - Interface TypeScript/Next.js ### Services principaux diff --git a/lib/nostrRemoteSigner.ts b/lib/nostrRemoteSigner.ts index 3447471..0dd9239 100644 --- a/lib/nostrRemoteSigner.ts +++ b/lib/nostrRemoteSigner.ts @@ -4,15 +4,15 @@ import { nostrConnectService } from './nostrconnect' import { nostrService } from './nostr' /** - * Remote signer using NostrConnect - * Supports both direct signing (if private key available) and remote signing via bridge + * Remote signer using nos2x (NIP-07) or NostrConnect (NIP-46) + * Supports nos2x extension (window.nostr) and NostrConnect bridge */ export class NostrRemoteSigner { /** * Sign an event template - * Requires private key to be available + * Uses nos2x (NIP-07) if available, otherwise falls back to private key signing */ - signEvent(eventTemplate: EventTemplate): Event | null { + async signEvent(eventTemplate: EventTemplate): Promise { // Get the event hash first const pubkey = nostrService.getPublicKey() if (!pubkey) { @@ -26,14 +26,28 @@ export class NostrRemoteSigner { } const eventId = getEventHash(unsignedEvent) - // Try to get private key from nostrService (if available from NostrConnect) - const privateKey = nostrService.getPrivateKey() + // Try nos2x (NIP-07) first + if (typeof window !== 'undefined' && window.nostr) { + try { + const signedEvent = await window.nostr.signEvent({ + kind: unsignedEvent.kind, + created_at: unsignedEvent.created_at, + tags: unsignedEvent.tags, + content: unsignedEvent.content, + }) + return signedEvent as Event + } catch (e) { + console.error('Error signing with nos2x:', e) + throw new Error('Failed to sign event with nos2x extension') + } + } + // Fallback to private key signing + const privateKey = nostrService.getPrivateKey() if (!privateKey) { throw new Error( 'Private key required for signing. ' + - 'Please use a NostrConnect wallet that provides signing capabilities, ' + - 'or ensure your wallet is properly connected.' + 'Please install nos2x extension or use a NostrConnect wallet that provides signing capabilities.' ) } diff --git a/lib/nostrconnect.ts b/lib/nostrconnect.ts index c1ed1ec..4830c55 100644 --- a/lib/nostrconnect.ts +++ b/lib/nostrconnect.ts @@ -2,9 +2,10 @@ import type { NostrConnectState } from '@/types/nostr' import { nostrService } from './nostr' import { handleNostrConnectMessage } from './nostrconnectHandler' -// NostrConnect uses NIP-46 protocol -// use.nsec.app provides a bridge for remote signing -const NOSTRCONNECT_BRIDGE = process.env.NEXT_PUBLIC_NOSTRCONNECT_BRIDGE ?? 'https://use.nsec.app' +// Support for nos2x extension (NIP-07) and NostrConnect (NIP-46) +// nos2x uses window.nostr API directly +// NostrConnect uses a bridge for remote signing +const NOSTRCONNECT_BRIDGE = process.env.NEXT_PUBLIC_NOSTRCONNECT_BRIDGE ?? '' export class NostrConnectService { private state: NostrConnectState = { @@ -36,6 +37,9 @@ export class NostrConnectService { } private createConnectUrl(): string { + if (!NOSTRCONNECT_BRIDGE) { + throw new Error('NostrConnect bridge not configured') + } const appName = 'zapwall4Science' const appUrl = window.location.origin diff --git a/lib/nostrconnectMessageHandler.ts b/lib/nostrconnectMessageHandler.ts index 92af5e7..a8e7769 100644 --- a/lib/nostrconnectMessageHandler.ts +++ b/lib/nostrconnectMessageHandler.ts @@ -1,7 +1,7 @@ import type { NostrConnectState } from '@/types/nostr' import { nostrService } from './nostr' -const NOSTRCONNECT_BRIDGE = process.env.NEXT_PUBLIC_NOSTRCONNECT_BRIDGE ?? 'https://use.nsec.app' +const NOSTRCONNECT_BRIDGE = process.env.NEXT_PUBLIC_NOSTRCONNECT_BRIDGE ?? '' interface MessageData { type?: string diff --git a/next.config.js b/next.config.js index 1fa66c2..87b3e2d 100644 --- a/next.config.js +++ b/next.config.js @@ -3,7 +3,7 @@ const nextConfig = { reactStrictMode: true, env: { NOSTR_RELAY_URL: process.env.NEXT_PUBLIC_NOSTR_RELAY_URL || 'wss://relay.damus.io', - NOSTRCONNECT_BRIDGE: process.env.NEXT_PUBLIC_NOSTRCONNECT_BRIDGE || 'https://use.nsec.app', + NOSTRCONNECT_BRIDGE: process.env.NEXT_PUBLIC_NOSTRCONNECT_BRIDGE || '', }, } diff --git a/pages/_app.tsx b/pages/_app.tsx index 6d53573..1e6546e 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -1,7 +1,6 @@ import '@/styles/globals.css' import type { AppProps } from 'next/app' import { useI18n } from '@/hooks/useI18n' -import { getLocale } from '@/lib/i18n' function I18nProvider({ children }: { children: React.ReactNode }) { // Get saved locale from localStorage or default to French diff --git a/types/nostr-window.d.ts b/types/nostr-window.d.ts new file mode 100644 index 0000000..53613ae --- /dev/null +++ b/types/nostr-window.d.ts @@ -0,0 +1,30 @@ +// Type definitions for NIP-07 (nos2x extension) +declare global { + interface Window { + nostr?: { + getPublicKey(): Promise + signEvent(event: { + kind: number + created_at: number + tags: string[][] + content: string + }): Promise<{ + id: string + sig: string + kind: number + created_at: number + tags: string[][] + content: string + pubkey: string + }> + getRelays?(): Promise> + nip04?: { + encrypt(pubkey: string, plaintext: string): Promise + decrypt(pubkey: string, ciphertext: string): Promise + } + } + } +} + +export {} +