Ok, I've switched to another account, but there is still a bug. "signer required". Will fix that.
From 9b84454f53ff248a1390e9ec7a676093f7669697 Mon Sep 17 00:00:00 2001
From: fsociety
Date: Wed, 2 Oct 2024 00:33:36 +0200
Subject: [PATCH] feat: integrate nostr-login for user authentication
This commit integrates nostr-login for user authentication and removes the previous method. It includes changes in the package.json, Navbar.svelte, users.ts and the creation of a new file nostr-login/index.ts. This new method provides a more streamlined and efficient user authentication process.
---
package.json | 1 +
src/lib/components/Navbar.svelte | 45 +++++++++++++++++----------------------------
src/lib/signers/nostr-login/index.ts | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/lib/stores/users.ts | 72 +++++++++++++++++++++++-------------------------------------------------
src/lib/wrappers/Navbar.svelte | 21 ++-------------------
yarn.lock | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
6 files changed, 240 insertions(+), 109 deletions(-)
create mode 100644 src/lib/signers/nostr-login/index.ts
diff --git a/package.json b/package.json
index 8db6542..2539883 100644
--- a/package.json
+++ b/package.json
@@ -34,6 +34,7 @@
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-svelte": "^2.44.0",
+ "nostr-login": "^1.6.6",
"postcss": "^8.4.47",
"prettier": "^3.3.3",
"prettier-plugin-svelte": "^3.2.6",
diff --git a/src/lib/components/Navbar.svelte b/src/lib/components/Navbar.svelte
index e66e96d..d5d3d3c 100644
--- a/src/lib/components/Navbar.svelte
+++ b/src/lib/components/Navbar.svelte
@@ -1,13 +1,28 @@
+ import { onMount } from 'svelte'
import { logout } from '$lib/stores/users'
import Container from './Container.svelte'
import UserHeader from './users/UserHeader.svelte'
import type { User } from './users/type'
export let logged_in_user: User | undefined = undefined
- export let nip07_plugin: boolean | undefined = undefined
export let login_function = () => {}
- export let singup_function = () => {}
+
+ interface NlAuthEvent extends Event {
+ detail: {
+ type: string
+ }
+ }
+
+ onMount(() => {
+ login_function()
+ document.addEventListener('nlAuth', (e: Event) => {
+ const event = e as NlAuthEvent
+ if (event.detail.type === 'logout') {
+ logout()
+ }
+ })
+ })
@@ -35,34 +50,8 @@
class="menu dropdown-content z-[1] -mr-4 rounded-box bg-base-400 p-2 shadow"
>
-
-
-
-
- - on:click={() => { - logout() - }}>Logout
- >
-
- {:else if nip07_plugin === undefined}
-
- {:else if nip07_plugin}
-
- >
- {:else}
-
- >
{/if}
diff --git a/src/lib/signers/nostr-login/index.ts b/src/lib/signers/nostr-login/index.ts
new file mode 100644
index 0000000..563a8db
--- /dev/null
+++ b/src/lib/signers/nostr-login/index.ts
@@ -0,0 +1,111 @@
+import NDK, { NDKUser, NDKRelay } from '@nostr-dev-kit/ndk'
+import type { NDKSigner, NostrEvent } from '@nostr-dev-kit/ndk'
+
+export class NDKNostrLoginSigner implements NDKSigner {
+ private _userPromise: Promise
+
+ blockUntilReady(): Promise
+ return new Promise((resolve) => {
+ const eventHandler = (event: Event) => {
+ document.removeEventListener('nlAuth', eventHandler)
+ const customEvent = event as CustomEvent<{ pubkey: string }>
+ resolve(new NDKUser({ pubkey: customEvent.detail.pubkey }))
+ }
+
+ document.addEventListener('nlAuth', eventHandler)
+ })
+ }
+
+ user(): Promise
+ if (!this._userPromise) {
+ this._userPromise = this.blockUntilReady()
+ }
+
+ return this._userPromise
+ }
+
+ async sign(event: NostrEvent): Promise
+ if (!window.nostr) {
+ throw new Error('window.nostr is undefined')
+ }
+ const signedEvent = await window.nostr.signEvent(event)
+ return signedEvent.sig
+ }
+
+ async relays?(ndk?: NDK): Promise
+ const relays = (await window.nostr?.getRelays?.()) || {}
+
+ const activeRelays: string[] = []
+ for (const url of Object.keys(relays)) {
+ // Currently only respects relays that are both readable and writable.
+ if (relays[url].read && relays[url].write) {
+ activeRelays.push(url)
+ }
+ }
+ return activeRelays.map(
+ (url) => new NDKRelay(url, ndk?.relayAuthDefaultPolicy, ndk)
+ )
+ }
+
+ async encrypt(
+ recipient: NDKUser,
+ value: string,
+ type: string = 'nip04'
+ ): Promise
+ if (type === 'nip44') {
+ return this.nip44Encrypt(recipient, value)
+ } else {
+ return this.nip04Encrypt(recipient, value)
+ }
+ }
+
+ async decrypt(
+ sender: NDKUser,
+ value: string,
+ type: string = 'nip04'
+ ): Promise
+ if (type === 'nip44') {
+ return this.nip44Decrypt(sender, value)
+ } else {
+ return this.nip04Decrypt(sender, value)
+ }
+ }
+
+ private async nip44Encrypt(
+ recipient: NDKUser,
+ value: string
+ ): Promise
+ // @ts-expect-error window.nostr.nip44 is not defined in the type definitions
+ if (!window.nostr || !window.nostr.nip44) {
+ throw new Error('window.nostr or window.nostr.nip44 is undefined')
+ }
+ // @ts-expect-error window.nostr.nip44 is not defined in the type definitions
+ return await window.nostr.nip44.encrypt(recipient.pubkey, value)
+ }
+
+ private async nip04Encrypt(
+ recipient: NDKUser,
+ value: string
+ ): Promise
+ if (!window.nostr || !window.nostr.nip04) {
+ throw new Error('window.nostr or window.nostr.nip04 is undefined')
+ }
+ return await window.nostr.nip04.encrypt(recipient.pubkey, value)
+ }
+
+ private async nip44Decrypt(sender: NDKUser, value: string): Promise
+ // @ts-expect-error window.nostr.nip44 is not defined in the type definitions
+ if (!window.nostr || !window.nostr.nip44) {
+ throw new Error('window.nostr or window.nostr.nip44 is undefined')
+ }
+ // @ts-expect-error window.nostr.nip44 is not defined in the type definitions
+ return await window.nostr.nip44.decrypt(sender.pubkey, value)
+ }
+
+ private async nip04Decrypt(sender: NDKUser, value: string): Promise
+ if (!window.nostr || !window.nostr.nip04) {
+ throw new Error('window.nostr or window.nostr.nip04 is undefined')
+ }
+ return await window.nostr.nip04.decrypt(sender.pubkey, value)
+ }
+}
diff --git a/src/lib/stores/users.ts b/src/lib/stores/users.ts
index 608ffed..40ed744 100644
--- a/src/lib/stores/users.ts
+++ b/src/lib/stores/users.ts
@@ -2,13 +2,12 @@ import {
defaults as user_defaults,
type UserObject,
} from '$lib/components/users/type'
-import {
- getRelayListForUser,
- NDKNip07Signer,
- NDKRelayList,
-} from '@nostr-dev-kit/ndk'
+import { getRelayListForUser, NDKRelayList } from '@nostr-dev-kit/ndk'
import { get, writable, type Unsubscriber, type Writable } from 'svelte/store'
import { ndk } from './ndk'
+import { init as initNostrLogin } from 'nostr-login'
+import { NDKNostrLoginSigner } from '$lib/signers/nostr-login'
+import type { NostrLoginAuthOptions } from 'nostr-login/dist/types'
export const users: { [hexpubkey: string]: Writable
@@ -85,31 +84,7 @@ export const returnUser = async (hexpubkey: string): Promise
})
}
-// nip07_plugin is set in Navbar component
-export const nip07_plugin: Writable
-
-export const checkForNip07Plugin = () => {
- if (window.nostr) {
- nip07_plugin.set(true)
- if (localStorage.getItem('nip07pubkey')) login()
- } else {
- let timerId: NodeJS.Timeout | undefined = undefined
- const intervalId = setInterval(() => {
- if (window.nostr) {
- clearTimeout(timerId)
- clearInterval(intervalId)
- nip07_plugin.set(true)
- if (localStorage.getItem('nip07pubkey')) login()
- }
- }, 100)
- timerId = setTimeout(() => {
- clearInterval(intervalId)
- nip07_plugin.set(false)
- }, 5000)
- }
-}
-
-const signer = new NDKNip07Signer(2000)
+const signer = new NDKNostrLoginSigner()
export const logged_in_user: Writable
writable(undefined)
@@ -118,24 +93,24 @@ export const login = async (): Promise
return new Promise(async (res, rej) => {
const user = get(logged_in_user)
if (user) return res()
- if (get(nip07_plugin)) {
- try {
- const ndk_user = await signer.blockUntilReady()
- localStorage.setItem('nip07pubkey', ndk_user.pubkey)
- logged_in_user.set({
- ...user_defaults,
- hexpubkey: ndk_user.pubkey,
- })
- ndk.signer = signer
- ensureUser(ndk_user.pubkey).subscribe((user) => {
- logged_in_user.set({ ...user })
- })
- return res()
- } catch (e) {
- alert(e)
- rej()
- }
- } else {
+ try {
+ ndk.signer = signer
+ initNostrLogin({
+ onAuth: async (_npub: string, options: NostrLoginAuthOptions) => {
+ const pubkey =
+ typeof options.pubkey === 'string' ? options.pubkey : ''
+ logged_in_user.set({
+ ...user_defaults,
+ hexpubkey: pubkey,
+ })
+ ensureUser(pubkey).subscribe((user) => {
+ logged_in_user.set({ ...user })
+ })
+ return res()
+ },
+ })
+ } catch (e) {
+ alert(e)
rej()
}
})
@@ -143,7 +118,6 @@ export const login = async (): Promise
export const logout = async (): Promise
logged_in_user.set(undefined)
- localStorage.removeItem('nip07pubkey')
ndk.signer = undefined
}
diff --git a/src/lib/wrappers/Navbar.svelte b/src/lib/wrappers/Navbar.svelte
index 4b63bc7..1f7146f 100644
--- a/src/lib/wrappers/Navbar.svelte
+++ b/src/lib/wrappers/Navbar.svelte
@@ -1,23 +1,6 @@
- import {
- checkForNip07Plugin,
- logged_in_user,
- login,
- nip07_plugin,
- } from '$lib/stores/users'
- import { onMount } from 'svelte'
+ import { logged_in_user, login } from '$lib/stores/users'
import Navbar from '$lib/components/Navbar.svelte'
-
- let singup_function = () => {
- alert('a NIP-07 browser extension is required. currently no signup page')
- }
-
- onMount(checkForNip07Plugin)
- - logged_in_user={$logged_in_user} - nip07_plugin={$nip07_plugin} - login_function={login} - {singup_function} -/> + diff --git a/yarn.lock b/yarn.lock index f75be09..f976ab4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -566,6 +566,13 @@ __metadata: languageName: node linkType: hard +"@noble/ciphers@npm:0.2.0": + version: 0.2.0 + resolution: "@noble/ciphers@npm:0.2.0" + checksum: 10c0/57dea65c32741df20a1ac24f365d616a558527109d778c1bec877f20b28875a26b80097bce51ae19529f3792ccf8285fe73839ff404733e32a27a6ebf60edd2c + languageName: node + linkType: hard + "@noble/ciphers@npm:^0.5.1": version: 0.5.3 resolution: "@noble/ciphers@npm:0.5.3" @@ -573,6 +580,15 @@ __metadata: languageName: node linkType: hard +"@noble/curves@npm:1.1.0, @noble/curves@npm:~1.1.0": + version: 1.1.0 + resolution: "@noble/curves@npm:1.1.0" + dependencies: + "@noble/hashes": "npm:1.3.1" + checksum: 10c0/81115c3ebfa7e7da2d7e18d44d686f98dc6d35dbde3964412c05707c92d0994a01545bc265d5c0bc05c8c49333f75b99c9acef6750f5a79b3abcc8e0546acf88 + languageName: node + linkType: hard + "@noble/curves@npm:1.2.0": version: 1.2.0 resolution: "@noble/curves@npm:1.2.0" @@ -582,7 +598,7 @@ __metadata: languageName: node linkType: hard -"@noble/curves@npm:^1.4.0": +"@noble/curves@npm:^1.4.0, @noble/curves@npm:^1.6.0": version: 1.6.0 resolution: "@noble/curves@npm:1.6.0" dependencies: @@ -591,15 +607,6 @@ __metadata: languageName: node linkType: hard -"@noble/curves@npm:~1.1.0": - version: 1.1.0 - resolution: "@noble/curves@npm:1.1.0" - dependencies: - "@noble/hashes": "npm:1.3.1" - checksum: 10c0/81115c3ebfa7e7da2d7e18d44d686f98dc6d35dbde3964412c05707c92d0994a01545bc265d5c0bc05c8c49333f75b99c9acef6750f5a79b3abcc8e0546acf88 - languageName: node - linkType: hard - "@noble/hashes@npm:1.3.1": version: 1.3.1 resolution: "@noble/hashes@npm:1.3.1" @@ -614,7 +621,7 @@ __metadata: languageName: node linkType: hard -"@noble/hashes@npm:1.5.0, @noble/hashes@npm:^1.3.1": +"@noble/hashes@npm:1.5.0, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:^1.5.0": version: 1.5.0 resolution: "@noble/hashes@npm:1.5.0" checksum: 10c0/1b46539695fbfe4477c0822d90c881a04d4fa2921c08c552375b444a48cac9930cb1ee68de0a3c7859e676554d0f3771999716606dc4d8f826e414c11692cdd9 @@ -628,7 +635,7 @@ __metadata: languageName: node linkType: hard -"@noble/secp256k1@npm:^2.0.0": +"@noble/secp256k1@npm:^2.0.0, @noble/secp256k1@npm:^2.1.0": version: 2.1.0 resolution: "@noble/secp256k1@npm:2.1.0" checksum: 10c0/b4c7edd2a5ec5acf294546cd06d08dc2a2a2b2ebe34a6da1f2f5104f56983f81dd31c261ad365c6b9757d1c54017fc3363331ee33bba8715ff94c2bc954313cc @@ -692,6 +699,25 @@ __metadata: languageName: node linkType: hard +"@nostr-dev-kit/ndk@npm:^2.3.1": + version: 2.10.1 + resolution: "@nostr-dev-kit/ndk@npm:2.10.1" + dependencies: + "@noble/curves": "npm:^1.6.0" + "@noble/hashes": "npm:^1.5.0" + "@noble/secp256k1": "npm:^2.1.0" + "@scure/base": "npm:^1.1.9" + debug: "npm:^4.3.6" + light-bolt11-decoder: "npm:^3.2.0" + nostr-tools: "npm:^2.7.1" + tseep: "npm:^1.2.2" + typescript-lru-cache: "npm:^2.0.0" + utf8-buffer: "npm:^1.0.0" + websocket-polyfill: "npm:^0.0.3" + checksum: 10c0/b73cd0e9f036e60893d0470d778c5e672795f93308edca389d42c9487267e95df208b2b2353b20eb766ae606cfd1c328d03a1e43d69351e27159843cdb619cc9 + languageName: node + linkType: hard + "@npmcli/agent@npm:^2.0.0": version: 2.2.2 resolution: "@npmcli/agent@npm:2.2.2" @@ -854,7 +880,7 @@ __metadata: languageName: node linkType: hard -"@scure/base@npm:^1.1.1, @scure/base@npm:~1.1.0": +"@scure/base@npm:^1.1.1, @scure/base@npm:^1.1.9, @scure/base@npm:~1.1.0": version: 1.1.9 resolution: "@scure/base@npm:1.1.9" checksum: 10c0/77a06b9a2db8144d22d9bf198338893d77367c51b58c72b99df990c0a11f7cadd066d4102abb15e3ca6798d1529e3765f55c4355742465e49aed7a0c01fe76e8 @@ -3857,6 +3883,7 @@ __metadata: eslint-plugin-prettier: "npm:^5.2.1" eslint-plugin-svelte: "npm:^2.44.0" highlight.js: "npm:^11.10.0" + nostr-login: "npm:^1.6.6" nostr-tools: "npm:^2.7.2" parse-diff: "npm:^0.11.1" postcss: "npm:^8.4.47" @@ -4492,6 +4519,15 @@ __metadata: languageName: node linkType: hard +"light-bolt11-decoder@npm:^3.2.0": + version: 3.2.0 + resolution: "light-bolt11-decoder@npm:3.2.0" + dependencies: + "@scure/base": "npm:1.1.1" + checksum: 10c0/65c1514b40b3b7fd5f4f0b40412bab35b0135f20f6b4929f5616bc5693f759fa8636d2393ba71fa782b2d9204315015e044628736ee7aea72f71939b0eb486f1 + languageName: node + linkType: hard + "lilconfig@npm:^2.0.5, lilconfig@npm:^2.1.0": version: 2.1.0 resolution: "lilconfig@npm:2.1.0" @@ -5030,6 +5066,36 @@ __metadata: languageName: node linkType: hard +"nostr-login@npm:^1.6.6": + version: 1.6.6 + resolution: "nostr-login@npm:1.6.6" + dependencies: + "@nostr-dev-kit/ndk": "npm:^2.3.1" + nostr-tools: "npm:^1.17.0" + tseep: "npm:^1.2.1" + checksum: 10c0/f521f906eef377321406838d2ab3be314c9755cbbad90328f32cd65fc5b035bb85729116bc5da313445c399aafb9f1bc12833a789f440e58f12619e84d9ff15f + languageName: node + linkType: hard + +"nostr-tools@npm:^1.17.0": + version: 1.17.0 + resolution: "nostr-tools@npm:1.17.0" + dependencies: + "@noble/ciphers": "npm:0.2.0" + "@noble/curves": "npm:1.1.0" + "@noble/hashes": "npm:1.3.1" + "@scure/base": "npm:1.1.1" + "@scure/bip32": "npm:1.3.1" + "@scure/bip39": "npm:1.2.1" + peerDependencies: + typescript: ">=5.0.0" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/b52732df3e403ef3c73a41fe1dea89accbff91597b231d811d577c35a9bd9307651de65ec7fbcc9989aef4c35e9c6b1005200fbbfec45544dcd64f928bbfc476 + languageName: node + linkType: hard + "nostr-tools@npm:^2.7.1, nostr-tools@npm:^2.7.2": version: 2.7.2 resolution: "nostr-tools@npm:2.7.2" @@ -6638,6 +6704,13 @@ __metadata: languageName: node linkType: hard +"tseep@npm:^1.2.1, tseep@npm:^1.2.2": + version: 1.3.1 + resolution: "tseep@npm:1.3.1" + checksum: 10c0/01b68f1f0e1084ff78bed9f28d83a595b4b6256caecd8c245af62716037dc4e87c9916c90d5d5cd4a2935f7d438a1117b2703dbf8abc79f087bc176a6f247ed6 + languageName: node + linkType: hard + "tslib@npm:^2.0.1, tslib@npm:^2.6.2, tslib@npm:^2.7.0": version: 2.7.0 resolution: "tslib@npm:2.7.0" -- libgit2 1.8.1