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

    No problem, that was within my capabilities. It would be nice to get the new methods in, because if I want to use ISSUES to get messages in from plebs, then not everyone has an extension, but rather Amber running.

    Reply to this note

    Please Login to reply.

    Discussion

    No replies yet.