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 @@

@@ -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}

    -

    - on:click={() => {

    - login_function()

    - }}

    - class="btn btn-ghost btn-sm normal-case">Login

    - >

    - {:else}

    -

    - on:click={() => {

    - singup_function()

    - }}

    - class="btn btn-ghost btn-sm normal-case">Sign up

    - >

    {/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 | undefined

    +

    + 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 = writable(undefined)

    -

    -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 @@

    -

    - 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

    Avatar

    Because this is not merged. You need to run the branch locally.

    Reply to this note

    Please Login to reply.

    Discussion

    No replies yet.