Merge branch 'nostr-sign-load' into 'main'

Draft: Load the Nostr signer before calling verify_credentials

See merge request soapbox-pub/soapbox!3010
merge-requests/3010/merge
Alex Gleason 2024-04-29 17:49:57 +00:00
commit daa347013e
5 zmienionych plików z 72 dodań i 10 usunięć

Wyświetl plik

@ -15,6 +15,11 @@ interface NostrConnectResponse {
error?: string;
}
let onOpen: () => void;
const open = new Promise<void>((resolve) => {
onOpen = resolve;
});
function useSignerStream() {
const { relay, pubkey, signer } = useNostr();
@ -143,6 +148,18 @@ function useSignerStream() {
};
}, [relay, pubkey, signer]);
useEffect(() => {
if (relay) {
if (relay.socket.readyState === WebSocket.OPEN) {
onOpen();
} else {
relay.socket.addEventListener('open', onOpen, { once: true });
}
}
}, [relay]);
return { open };
}
export { useSignerStream };

Wyświetl plik

@ -1,12 +1,13 @@
import { NRelay, NRelay1, NostrSigner } from '@soapbox/nspec';
import { NRelay1, NostrSigner } from '@soapbox/nspec';
import { getPublicKey, nip19 } from 'nostr-tools';
import React, { createContext, useContext, useState, useEffect, useMemo } from 'react';
import { NKeys } from 'soapbox/features/nostr/keys';
import { useOwnAccount } from 'soapbox/hooks';
import { useAuthToken } from 'soapbox/hooks/useAuthToken';
import { useInstance } from 'soapbox/hooks/useInstance';
interface NostrContextType {
relay?: NRelay;
relay?: NRelay1;
pubkey?: string;
signer?: NostrSigner;
}
@ -21,11 +22,29 @@ export const NostrProvider: React.FC<NostrProviderProps> = ({ children }) => {
const instance = useInstance();
const [relay, setRelay] = useState<NRelay1>();
const { account } = useOwnAccount();
const token = useAuthToken();
const url = instance.nostr?.relay;
const pubkey = instance.nostr?.pubkey;
const accountPubkey = account?.nostr.pubkey;
let accountPubkey: string | undefined;
try {
const result = nip19.decode(token!);
switch (result.type) {
case 'npub':
accountPubkey = result.data;
break;
case 'nsec':
accountPubkey = getPublicKey(result.data);
break;
case 'nprofile':
accountPubkey = result.data.pubkey;
break;
}
} catch (e) {
// Ignore
}
const signer = useMemo(
() => (accountPubkey ? NKeys.get(accountPubkey) : undefined) ?? window.nostr,

Wyświetl plik

@ -13,7 +13,6 @@ import { fetchScheduledStatuses } from 'soapbox/actions/scheduled-statuses';
import { fetchSuggestionsForTimeline } from 'soapbox/actions/suggestions';
import { expandHomeTimeline } from 'soapbox/actions/timelines';
import { useUserStream } from 'soapbox/api/hooks';
import { useSignerStream } from 'soapbox/api/hooks/nostr/useSignerStream';
import SidebarNavigation from 'soapbox/components/sidebar-navigation';
import ThumbNavigation from 'soapbox/components/thumb-navigation';
import { Layout } from 'soapbox/components/ui';
@ -459,7 +458,6 @@ const UI: React.FC<IUI> = ({ children }) => {
}, []);
useUserStream();
useSignerStream();
// The user has logged in
useEffect(() => {

Wyświetl plik

@ -0,0 +1,24 @@
import { selectAccount } from 'soapbox/selectors';
import { RootState } from 'soapbox/store';
import { getAuthUserId, getAuthUserUrl } from 'soapbox/utils/auth';
import { useAppSelector } from './useAppSelector';
export function useAuthToken(): string | undefined {
const getMeId = (state: RootState) => state.me || getAuthUserId(state);
const getMeUrl = (state: RootState) => {
const accountId = getMeId(state);
if (accountId) {
return selectAccount(state, accountId)?.url || getAuthUserUrl(state);
}
};
const getMeToken = (state: RootState) => {
// Fallback for upgrading IDs to URLs
const accountUrl = getMeUrl(state) || state.auth.me;
return state.auth.users.get(accountUrl!)?.access_token;
};
return useAppSelector((state) => getMeToken(state));
}

Wyświetl plik

@ -4,6 +4,7 @@ import { IntlProvider } from 'react-intl';
import { fetchInstance } from 'soapbox/actions/instance';
import { fetchMe } from 'soapbox/actions/me';
import { loadSoapboxConfig } from 'soapbox/actions/soapbox';
import { useSignerStream } from 'soapbox/api/hooks/nostr/useSignerStream';
import LoadingScreen from 'soapbox/components/loading-screen';
import {
useAppSelector,
@ -14,13 +15,14 @@ import {
import MESSAGES from 'soapbox/messages';
/** Load initial data from the backend */
const loadInitial = () => {
const loadInitial = (open: Promise<void>) => {
// @ts-ignore
return async(dispatch, getState) => {
// Await for authenticated fetch
await dispatch(fetchInstance());
await open;
await dispatch(fetchMe());
// Await for feature detection
await dispatch(fetchInstance());
// Await for configuration
await dispatch(loadSoapboxConfig());
};
@ -43,6 +45,8 @@ const SoapboxLoad: React.FC<ISoapboxLoad> = ({ children }) => {
const [localeLoading, setLocaleLoading] = useState(true);
const [isLoaded, setIsLoaded] = useState(false);
const { open } = useSignerStream();
/** Whether to display a loading indicator. */
const showLoading = [
me === null,
@ -62,7 +66,7 @@ const SoapboxLoad: React.FC<ISoapboxLoad> = ({ children }) => {
// Load initial data from the API
useEffect(() => {
dispatch(loadInitial()).then(() => {
dispatch(loadInitial(open)).then(() => {
setIsLoaded(true);
}).catch(() => {
setIsLoaded(true);