From 1f980201dde2cf9b4e4ec8a0470e49944f797c5d Mon Sep 17 00:00:00 2001 From: enes Date: Tue, 31 Dec 2024 12:09:12 +0100 Subject: [PATCH 1/5] fix(login): update login method before using nostrController instance --- src/layouts/Main.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/layouts/Main.tsx b/src/layouts/Main.tsx index 3e6be26..5410dec 100644 --- a/src/layouts/Main.tsx +++ b/src/layouts/Main.tsx @@ -58,12 +58,12 @@ export const MainLayout = () => { } const login = useCallback(async () => { + dispatch(updateLoginMethod(LoginMethod.nostrLogin)) + const nostrController = NostrController.getInstance() const authController = new AuthController() const pubkey = await nostrController.capturePublicKey() - dispatch(updateLoginMethod(LoginMethod.nostrLogin)) - const redirectPath = await authController.authAndGetMetadataAndRelaysMap(pubkey) From ec43324caec516ccce92ebd1cbdf86fae1643068 Mon Sep 17 00:00:00 2001 From: enes Date: Tue, 31 Dec 2024 12:10:56 +0100 Subject: [PATCH 2/5] refactor(nostr): capturePublicKey from signedEvent instead of nostr api call --- src/controllers/NostrController.ts | 49 +++++++++++++++++------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/src/controllers/NostrController.ts b/src/controllers/NostrController.ts index c3d2908..a976955 100644 --- a/src/controllers/NostrController.ts +++ b/src/controllers/NostrController.ts @@ -1,9 +1,9 @@ import { EventTemplate, UnsignedEvent } from 'nostr-tools' -import { WindowNostr } from 'nostr-tools/nip07' import { EventEmitter } from 'tseep' import store from '../store/store' import { SignedEvent } from '../types' import { LoginMethodContext } from '../services/LoginMethodStrategy/loginMethodContext' +import { unixNow } from '../utils' export class NostrController extends EventEmitter { private static instance: NostrController @@ -11,13 +11,6 @@ export class NostrController extends EventEmitter { private constructor() { super() } - private getNostrObject = () => { - if (window.nostr) return window.nostr as WindowNostr - - throw new Error( - `window.nostr object not present. Make sure you have an nostr extension installed/working properly.` - ) - } public static getInstance(): NostrController { if (!NostrController.instance) { @@ -97,23 +90,37 @@ export class NostrController extends EventEmitter { } /** - * Function will capture the public key from the nostr extension or if no extension present - * function wil capture the public key from the local storage + * Function will capture the public key from signedEvent */ capturePublicKey = async (): Promise => { - const nostr = this.getNostrObject() - const pubKey = await nostr.getPublicKey().catch((err: unknown) => { - if (err instanceof Error) { - return Promise.reject(err.message) - } else { - return Promise.reject(JSON.stringify(err)) + try { + const timestamp = unixNow() + const { href } = window.location + + const authEvent: EventTemplate = { + kind: 27235, + tags: [ + ['u', href], + ['method', 'GET'] + ], + content: '', + created_at: timestamp } - }) - if (!pubKey) { - return Promise.reject('Error getting public key, user canceled') + const signedAuthEvent = await this.signEvent(authEvent) + const pubkey = signedAuthEvent.pubkey + + if (!pubkey) { + return Promise.reject('Error getting public key, user canceled') + } + + return Promise.resolve(pubkey) + } catch (error) { + if (error instanceof Error) { + return Promise.reject(error.message) + } else { + return Promise.reject(JSON.stringify(error)) + } } - - return Promise.resolve(pubKey) } } From 84062f2ed0e9953c5c3830d792a60577ddb3ebe4 Mon Sep 17 00:00:00 2001 From: enes Date: Tue, 31 Dec 2024 12:59:41 +0100 Subject: [PATCH 3/5] fix(login): redirect to landing instead of login popup page --- src/App.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/App.tsx b/src/App.tsx index 9f58f21..11434af 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -33,7 +33,7 @@ const App = () => { window.location.href.split(`${window.location.origin}/#`)[1] ) - return `${appPublicRoutes.login}?callbackPath=${callbackPathEncoded}` + return `${appPublicRoutes.landingPage}?callbackPath=${callbackPathEncoded}` } // Hide route only if loggedIn and r.hiddenWhenLoggedIn are both true From 8153ef03fbf693f6ec1ecd1425dc03d76d29416f Mon Sep 17 00:00:00 2001 From: enes Date: Tue, 31 Dec 2024 13:01:42 +0100 Subject: [PATCH 4/5] fix: logout user if signEvent's and auth's pubkeys are diff --- src/controllers/NostrController.ts | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/controllers/NostrController.ts b/src/controllers/NostrController.ts index a976955..8e24e91 100644 --- a/src/controllers/NostrController.ts +++ b/src/controllers/NostrController.ts @@ -3,7 +3,10 @@ import { EventEmitter } from 'tseep' import store from '../store/store' import { SignedEvent } from '../types' import { LoginMethodContext } from '../services/LoginMethodStrategy/loginMethodContext' -import { unixNow } from '../utils' +import { clear, unixNow } from '../utils' +import { LoginMethod } from '../store/auth/types' +import { logout as nostrLogout } from 'nostr-login' +import { userLogOutAction } from '../store/actions' export class NostrController extends EventEmitter { private static instance: NostrController @@ -65,7 +68,22 @@ export class NostrController extends EventEmitter { const loginMethod = store.getState().auth.loginMethod const context = new LoginMethodContext(loginMethod) - return await context.signEvent(event) + const authkey = store.getState().auth.usersPubkey + const signedEvent = await context.signEvent(event) + const pubkey = signedEvent.pubkey + + // Forcefully log out the user if we detect missmatch between pubkeys + // Allow undefined authkey, intial log in + if (authkey && authkey !== pubkey) { + if (loginMethod === LoginMethod.nostrLogin) { + nostrLogout() + } + store.dispatch(userLogOutAction()) + clear() + throw new Error('User missmatch.\n\nPlease log in again.') + } + + return signedEvent } nip04Encrypt = async (receiver: string, content: string): Promise => { From c96a7fac4fcf59eacf097be9c39fcc13cd6f04b9 Mon Sep 17 00:00:00 2001 From: enes Date: Tue, 31 Dec 2024 13:02:39 +0100 Subject: [PATCH 5/5] fix: logout user if decryption fails due to diff pubkeys --- src/utils/nostr.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/utils/nostr.ts b/src/utils/nostr.ts index 0ed4054..474e8dc 100644 --- a/src/utils/nostr.ts +++ b/src/utils/nostr.ts @@ -363,11 +363,21 @@ export const createWrap = (unsignedEvent: UnsignedEvent, receiver: string) => { * @returns The user application data or null if an error occurs or no data is found. */ export const getUsersAppData = async (): Promise => { + // Get an instance of the NostrController + const nostrController = NostrController.getInstance() + // Initialize an array to hold relay URLs const relays: string[] = [] // Retrieve the user's public key and relay map from the Redux store const usersPubkey = store.getState().auth.usersPubkey! + + // Decryption can fail down in the code if extension options changed + // Forcefully log out the user if we detect missmatch between pubkeys + if (usersPubkey !== (await nostrController.capturePublicKey())) { + return null + } + const relayMap = store.getState().relays?.map // Check if relayMap is undefined in the Redux store @@ -448,9 +458,6 @@ export const getUsersAppData = async (): Promise => { } } - // Get an instance of the NostrController - const nostrController = NostrController.getInstance() - // Decrypt the encrypted content const decrypted = await nostrController .nip04Decrypt(usersPubkey, encryptedContent)