Merge pull request 'Log out user if extension's pubkey and auth's pubkey are different' (#295) from 290-user-ext-log-missmatch into staging
All checks were successful
Release to Staging / build_and_release (push) Successful in 1m42s
All checks were successful
Release to Staging / build_and_release (push) Successful in 1m42s
Reviewed-on: #295 Reviewed-by: s <s@noreply.git.nostrdev.com>
This commit is contained in:
commit
3fefcc5a98
@ -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
|
||||
|
@ -1,9 +1,12 @@
|
||||
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 { 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
|
||||
@ -11,13 +14,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) {
|
||||
@ -72,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<string> => {
|
||||
@ -97,23 +108,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<string> => {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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<UserAppData | null> => {
|
||||
// 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<UserAppData | null> => {
|
||||
}
|
||||
}
|
||||
|
||||
// Get an instance of the NostrController
|
||||
const nostrController = NostrController.getInstance()
|
||||
|
||||
// Decrypt the encrypted content
|
||||
const decrypted = await nostrController
|
||||
.nip04Decrypt(usersPubkey, encryptedContent)
|
||||
|
Loading…
Reference in New Issue
Block a user