use signing service

This commit is contained in:
hzrd149 2023-02-16 10:24:41 -06:00
parent e4c40d4a16
commit fd044878c5
10 changed files with 111 additions and 39 deletions

View File

@ -16,6 +16,7 @@ import { nostrPostAction, PostResult } from "../../classes/nostr-post-action";
import { getReferences } from "../../helpers/nostr-event";
import { useWriteRelayUrls } from "../../hooks/use-client-relays";
import { useIsMobile } from "../../hooks/use-is-mobile";
import { useSigningContext } from "../../providers/signing-provider";
import { DraftNostrEvent, NostrEvent } from "../../types/nostr-event";
import { NoteLink } from "../note-link";
import { PostResults } from "./post-results";
@ -39,6 +40,7 @@ export const PostModal = ({ isOpen, onClose, initialDraft }: PostModalProps) =>
const isMobile = useIsMobile();
const pad = isMobile ? "2" : "4";
const { requestSignature } = useSigningContext();
const writeRelays = useWriteRelayUrls();
const [waiting, setWaiting] = useState(false);
const [signedEvent, setSignedEvent] = useState<NostrEvent | null>(null);
@ -50,19 +52,17 @@ export const PostModal = ({ isOpen, onClose, initialDraft }: PostModalProps) =>
};
const handleSubmit = async () => {
if (window.nostr) {
setWaiting(true);
const updatedDraft: DraftNostrEvent = { ...draft, created_at: moment().unix() };
const event = await window.nostr.signEvent(updatedDraft);
setWaiting(false);
setSignedEvent(event);
setWaiting(true);
const updatedDraft: DraftNostrEvent = { ...draft, created_at: moment().unix() };
const event = await requestSignature(updatedDraft);
setWaiting(false);
if (!event) return;
setSignedEvent(event);
const { results } = nostrPostAction(writeRelays, event);
results.subscribe((result) => {
resultsActions.push(result);
});
}
const { results } = nostrPostAction(writeRelays, event);
results.subscribe((result) => {
resultsActions.push(result);
});
};
const refs = getReferences(draft);

View File

@ -1,9 +1,10 @@
import React from "react";
import { ChakraProvider, localStorageManager } from "@chakra-ui/react";
import theme from "../theme";
import { SigningProvider } from "./signing-provider";
export const Providers = ({ children }: { children: React.ReactNode }) => (
<ChakraProvider theme={theme} colorModeManager={localStorageManager}>
{children}
<SigningProvider>{children}</SigningProvider>
</ChakraProvider>
);

View File

@ -0,0 +1,41 @@
import { useToast } from "@chakra-ui/react";
import React, { useCallback, useContext, useMemo } from "react";
import signingService from "../services/signing";
import { DraftNostrEvent, NostrEvent } from "../types/nostr-event";
export type SigningContextType = {
requestSignature: (draft: DraftNostrEvent) => Promise<NostrEvent | undefined>;
};
export const SigningContext = React.createContext<SigningContextType>({
requestSignature: () => {
throw new Error("not setup yet");
},
});
export function useSigningContext() {
return useContext(SigningContext);
}
export const SigningProvider = ({ children }: { children: React.ReactNode }) => {
const toast = useToast();
const requestSignature = useCallback(
async (draft: DraftNostrEvent) => {
try {
return await signingService.requestSignature(draft);
} catch (e) {
if (e instanceof Error) {
toast({
status: "error",
description: e.message,
});
}
}
},
[toast]
);
const context = useMemo(() => ({ requestSignature }), [requestSignature]);
return <SigningContext.Provider value={context}>{children}</SigningContext.Provider>;
};

View File

@ -5,6 +5,7 @@ import { DraftNostrEvent, PTag } from "../types/nostr-event";
import clientRelaysService from "./client-relays";
import accountService from "./account";
import userContactsService, { UserContacts } from "./user-contacts";
import signingService from "./signing";
export type RelayDirectory = Record<string, { read: boolean; write: boolean }>;
@ -73,18 +74,16 @@ async function savePending() {
const draft = pendingDraft.value;
if (!draft) return;
if (window.nostr) {
savingDraft.next(true);
const event = await window.nostr.signEvent(draft);
savingDraft.next(true);
const event = await signingService.requestSignature(draft);
const results = nostrPostAction(clientRelaysService.getWriteUrls(), event);
await results.onComplete;
const results = nostrPostAction(clientRelaysService.getWriteUrls(), event);
await results.onComplete;
savingDraft.next(false);
savingDraft.next(false);
// pass new event to contact list service
userContactsService.handleEvent(event);
}
// pass new event to contact list service
userContactsService.handleEvent(event);
}
function addContact(pubkey: string, relay?: string) {

View File

@ -6,6 +6,7 @@ import accountService from "./account";
import { RelayConfig, RelayMode } from "../classes/relay";
import userRelaysService, { UserRelays } from "./user-relays";
import { PersistentSubject, Subject } from "../classes/subject";
import signingService from "./signing";
export type RelayDirectory = Record<string, { read: boolean; write: boolean }>;
@ -77,15 +78,13 @@ class ClientRelayService {
const oldRelayUrls = this.relays.value.filter((r) => r.mode & RelayMode.WRITE).map((r) => r.url);
const writeUrls = unique([...oldRelayUrls, ...newRelayUrls]);
if (window.nostr) {
const event = await window.nostr.signEvent(draft);
const event = await signingService.requestSignature(draft);
const results = nostrPostAction(writeUrls, event);
await results.onComplete;
const results = nostrPostAction(writeUrls, event);
await results.onComplete;
// pass new event to the user relay service
userRelaysService.handleEvent(event);
}
// pass new event to the user relay service
userRelaysService.handleEvent(event);
}
getWriteUrls() {

View File

@ -82,7 +82,7 @@ async function pruneCache() {
const keys = await db.getAllKeysFromIndex(
"dnsIdentifiers",
"updated",
IDBKeyRange.upperBound(moment().subtract(1, "hour").unix())
IDBKeyRange.upperBound(moment().subtract(1, "day").unix())
);
for (const pubkey of keys) {

32
src/services/signing.tsx Normal file
View File

@ -0,0 +1,32 @@
import { DraftNostrEvent, NostrEvent } from "../types/nostr-event";
import accountService from "./account";
import { signEvent, getEventHash, getPublicKey } from "nostr-tools";
class SigningService {
async requestSignature(draft: DraftNostrEvent) {
const account = accountService.current.value;
if (account?.readonly) throw new Error("cant sign in readonly mode");
if (account?.useExtension) {
if (window.nostr) {
const signed = await window.nostr.signEvent(draft);
if (signed.pubkey !== account.pubkey) throw new Error("signed with the wrong pubkey!");
return signed;
} else throw new Error("missing nostr extension");
} else if (account?.secKey) {
const tmpDraft = { ...draft, pubkey: getPublicKey(account.secKey) };
const signature = signEvent(tmpDraft, account.secKey);
const event: NostrEvent = {
...tmpDraft,
id: getEventHash(tmpDraft),
sig: signature,
};
return event;
} else throw new Error("no signing method");
}
}
const signingService = new SigningService();
export default signingService;

View File

@ -26,7 +26,7 @@ export const LoginStartView = () => {
relays = Object.keys(extRelays).filter((url) => extRelays[url].read);
}
accountService.addAccount({ pubkey, relays });
accountService.addAccount({ pubkey, relays, useExtension: true });
}
accountService.switchAccount(pubkey);

View File

@ -17,10 +17,8 @@ export const UserCard = ({ pubkey, relay }: { pubkey: string; relay?: string })
<Box>
<Link as={ReactRouterLink} to={`/u/${normalizeToBech32(pubkey, Bech32Prefix.Pubkey)}`}>
<Heading size="sm">{getUserDisplayName(metadata, pubkey)}</Heading>
<Text>
<UserDnsIdentityIcon pubkey={pubkey} />
</Text>
</Link>
<UserDnsIdentityIcon pubkey={pubkey} />
{relay && <Text>{relay}</Text>}
</Box>
</Flex>

View File

@ -16,11 +16,13 @@ export const UserProfileMenu = ({ pubkey, ...props }: { pubkey: string } & Omit<
const loginAsUser = () => {
const readRelays = userRelays?.relays.filter((r) => r.mode === RelayMode.READ).map((r) => r.url) ?? [];
accountService.addAccount({
pubkey,
relays: readRelays,
readonly: true,
});
if (!accountService.hasAccount(pubkey)) {
accountService.addAccount({
pubkey,
relays: readRelays,
readonly: true,
});
}
accountService.switchAccount(pubkey);
};