From a83916537afb8c13fbbcfac1c86c85eb82111f79 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 15 Mar 2024 15:15:53 -0500 Subject: [PATCH] Git Nostr signer from currently-logged-in account --- src/actions/accounts.ts | 11 +------- src/actions/nostr.ts | 11 ++++++-- src/contexts/nostr-context.tsx | 8 +++++- src/features/nostr/SoapboxSigner.ts | 44 ----------------------------- src/features/nostr/sign.ts | 13 --------- 5 files changed, 17 insertions(+), 70 deletions(-) delete mode 100644 src/features/nostr/SoapboxSigner.ts delete mode 100644 src/features/nostr/sign.ts diff --git a/src/actions/accounts.ts b/src/actions/accounts.ts index 37dea3cc77..f1d0f6c32b 100644 --- a/src/actions/accounts.ts +++ b/src/actions/accounts.ts @@ -1,8 +1,5 @@ -import { nip19 } from 'nostr-tools'; - import { importEntities } from 'soapbox/entity-store/actions'; import { Entities } from 'soapbox/entity-store/entities'; -import { signer } from 'soapbox/features/nostr/sign'; import { selectAccount } from 'soapbox/selectors'; import { isLoggedIn } from 'soapbox/utils/auth'; import { getFeatures, parseVersion, PLEROMA } from 'soapbox/utils/features'; @@ -132,14 +129,8 @@ const noOp = () => new Promise(f => f(undefined)); const createAccount = (params: Record) => async (dispatch: AppDispatch, getState: () => RootState) => { - const { instance } = getState(); - const { nostrSignup } = getFeatures(instance); - const pubkey = (signer && nostrSignup) ? await signer.getPublicKey() : undefined; - dispatch({ type: ACCOUNT_CREATE_REQUEST, params }); - return api(getState, 'app').post('/api/v1/accounts', params, { - headers: pubkey ? { authorization: `Bearer ${nip19.npubEncode(pubkey)}` } : undefined, - }).then(({ data: token }) => { + return api(getState, 'app').post('/api/v1/accounts', params).then(({ data: token }) => { return dispatch({ type: ACCOUNT_CREATE_SUCCESS, params, token }); }).catch(error => { dispatch({ type: ACCOUNT_CREATE_FAIL, error, params }); diff --git a/src/actions/nostr.ts b/src/actions/nostr.ts index ab7dfb8e05..82e1006e34 100644 --- a/src/actions/nostr.ts +++ b/src/actions/nostr.ts @@ -5,6 +5,14 @@ import { type AppDispatch } from 'soapbox/store'; import { verifyCredentials } from './auth'; import { closeModal } from './modals'; +/** Log in with a Nostr pubkey. */ +function logInNostr(pubkey: string) { + return (dispatch: AppDispatch) => { + const npub = nip19.npubEncode(pubkey); + return dispatch(verifyCredentials(npub)); + }; +} + /** Log in with a Nostr extension. */ function nostrExtensionLogIn() { return async (dispatch: AppDispatch) => { @@ -13,10 +21,9 @@ function nostrExtensionLogIn() { } const pubkey = await window.nostr.getPublicKey(); - const npub = nip19.npubEncode(pubkey); dispatch(closeModal('NOSTR_SIGNIN')); - return dispatch(verifyCredentials(npub)); + return dispatch(logInNostr(pubkey)); }; } diff --git a/src/contexts/nostr-context.tsx b/src/contexts/nostr-context.tsx index de02a0a854..4664068c6c 100644 --- a/src/contexts/nostr-context.tsx +++ b/src/contexts/nostr-context.tsx @@ -1,7 +1,8 @@ import { NRelay, NRelay1, NostrSigner } from '@soapbox/nspec'; import React, { createContext, useContext, useState, useEffect } from 'react'; -import { signer } from 'soapbox/features/nostr/sign'; +import { NKeys } from 'soapbox/features/nostr/keys'; +import { useOwnAccount } from 'soapbox/hooks'; import { useInstance } from 'soapbox/hooks/useInstance'; interface NostrContextType { @@ -20,8 +21,13 @@ export const NostrProvider: React.FC = ({ children }) => { const instance = useInstance(); const [relay, setRelay] = useState(); + const { account } = useOwnAccount(); + const url = instance.nostr?.relay; const pubkey = instance.nostr?.pubkey; + const accountPubkey = account?.nostr.pubkey; + + const signer = (accountPubkey ? NKeys.get(accountPubkey) : undefined) ?? window.nostr; useEffect(() => { if (url) { diff --git a/src/features/nostr/SoapboxSigner.ts b/src/features/nostr/SoapboxSigner.ts deleted file mode 100644 index 1b1d8bb81a..0000000000 --- a/src/features/nostr/SoapboxSigner.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { hexToBytes } from '@noble/hashes/utils'; -import { type NostrSigner, type NostrEvent, NSecSigner } from '@soapbox/nspec'; - -/** Use key from `localStorage` if available, falling back to NIP-07. */ -export class SoapboxSigner implements NostrSigner { - - #signer: NostrSigner; - - constructor() { - const privateKey = localStorage.getItem('soapbox:nostr:privateKey'); - const signer = privateKey ? new NSecSigner(hexToBytes(privateKey)) : window.nostr; - - if (!signer) { - throw new Error('No Nostr signer available'); - } - - this.#signer = signer; - } - - async getPublicKey(): Promise { - return this.#signer.getPublicKey(); - } - - async signEvent(event: Omit): Promise { - return this.#signer.signEvent(event); - } - - nip04 = { - encrypt: (pubkey: string, plaintext: string): Promise => { - if (!this.#signer.nip04) { - throw new Error('NIP-04 not supported by signer'); - } - return this.#signer.nip04.encrypt(pubkey, plaintext); - }, - - decrypt: (pubkey: string, ciphertext: string): Promise => { - if (!this.#signer.nip04) { - throw new Error('NIP-04 not supported by signer'); - } - return this.#signer.nip04.decrypt(pubkey, ciphertext); - }, - }; - -} \ No newline at end of file diff --git a/src/features/nostr/sign.ts b/src/features/nostr/sign.ts deleted file mode 100644 index e036678ca2..0000000000 --- a/src/features/nostr/sign.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { type NostrSigner } from '@soapbox/nspec'; - -import { SoapboxSigner } from './SoapboxSigner'; - -let signer: NostrSigner | undefined; - -try { - signer = new SoapboxSigner(); -} catch (_) { - // No signer available -} - -export { signer }; \ No newline at end of file