mirror of
https://github.com/logos-messaging/examples.waku.org.git
synced 2026-05-22 17:19:58 +00:00
add keystore read logic
This commit is contained in:
parent
eecd6a29b9
commit
4183b2b13f
@ -3,11 +3,15 @@ import { Block, BlockTypes } from "@/components/Block";
|
|||||||
import { Button } from "@/components/Button";
|
import { Button } from "@/components/Button";
|
||||||
import { Subtitle } from "@/components/Subtitle";
|
import { Subtitle } from "@/components/Subtitle";
|
||||||
import { useStore, useWallet } from "@/hooks";
|
import { useStore, useWallet } from "@/hooks";
|
||||||
|
import { useKeystore } from "@/hooks/useKeystore";
|
||||||
|
|
||||||
export const Keystore: React.FunctionComponent<{}> = () => {
|
export const Keystore: React.FunctionComponent<{}> = () => {
|
||||||
const { keystorePassword, setKeystorePassword, keystoreCredentials } =
|
const { keystoreCredentials } = useStore();
|
||||||
useStore();
|
const { onGenerateCredentials } = useWallet();
|
||||||
const { onGenerateCredentials, onRegisterCredentials } = useWallet();
|
const { onReadCredentials, onRegisterCredentials } = useKeystore();
|
||||||
|
|
||||||
|
const { password, onPasswordChanged } = usePassword();
|
||||||
|
const { selectedKeystore, onKeystoreChanged } = useSelectedKeystore();
|
||||||
|
|
||||||
const credentialsNodes = React.useMemo(
|
const credentialsNodes = React.useMemo(
|
||||||
() =>
|
() =>
|
||||||
@ -19,13 +23,6 @@ export const Keystore: React.FunctionComponent<{}> = () => {
|
|||||||
[keystoreCredentials]
|
[keystoreCredentials]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onPasswordChanged = React.useCallback(
|
|
||||||
(event: React.FormEvent<HTMLInputElement>) => {
|
|
||||||
setKeystorePassword(event.currentTarget.value);
|
|
||||||
},
|
|
||||||
[setKeystorePassword]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Block className="mt-10">
|
<Block className="mt-10">
|
||||||
<Block type={BlockTypes.FlexHorizontal}>
|
<Block type={BlockTypes.FlexHorizontal}>
|
||||||
@ -45,8 +42,8 @@ export const Keystore: React.FunctionComponent<{}> = () => {
|
|||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
|
value={password}
|
||||||
id="keystore-input"
|
id="keystore-input"
|
||||||
value={keystorePassword || ""}
|
|
||||||
onChange={onPasswordChanged}
|
onChange={onPasswordChanged}
|
||||||
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm w-full rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm w-full rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
||||||
/>
|
/>
|
||||||
@ -57,7 +54,10 @@ export const Keystore: React.FunctionComponent<{}> = () => {
|
|||||||
<Button onClick={onGenerateCredentials}>
|
<Button onClick={onGenerateCredentials}>
|
||||||
Generate new credentials
|
Generate new credentials
|
||||||
</Button>
|
</Button>
|
||||||
<Button className="ml-5" onClick={onRegisterCredentials}>
|
<Button
|
||||||
|
className="ml-5"
|
||||||
|
onClick={() => onRegisterCredentials(password)}
|
||||||
|
>
|
||||||
Register credentials
|
Register credentials
|
||||||
</Button>
|
</Button>
|
||||||
</Block>
|
</Block>
|
||||||
@ -65,12 +65,43 @@ export const Keystore: React.FunctionComponent<{}> = () => {
|
|||||||
<Block className="mt-4">
|
<Block className="mt-4">
|
||||||
<p className="text-s">Read from Keystore</p>
|
<p className="text-s">Read from Keystore</p>
|
||||||
<Block type={BlockTypes.FlexHorizontal}>
|
<Block type={BlockTypes.FlexHorizontal}>
|
||||||
<select className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-3/4 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
|
<select
|
||||||
|
value={selectedKeystore}
|
||||||
|
onChange={onKeystoreChanged}
|
||||||
|
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-3/4 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
||||||
|
>
|
||||||
{credentialsNodes}
|
{credentialsNodes}
|
||||||
</select>
|
</select>
|
||||||
<Button>Read credentials</Button>
|
<Button onClick={() => onReadCredentials(selectedKeystore, password)}>
|
||||||
|
Read credentials
|
||||||
|
</Button>
|
||||||
</Block>
|
</Block>
|
||||||
</Block>
|
</Block>
|
||||||
</Block>
|
</Block>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function usePassword() {
|
||||||
|
const [password, setPassword] = React.useState<string>("");
|
||||||
|
const onPasswordChanged = (event: React.FormEvent<HTMLInputElement>) => {
|
||||||
|
setPassword(event.currentTarget.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
password,
|
||||||
|
onPasswordChanged,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function useSelectedKeystore() {
|
||||||
|
const [selectedKeystore, setKeystore] = React.useState<string>("");
|
||||||
|
|
||||||
|
const onKeystoreChanged = (event: React.FormEvent<HTMLSelectElement>) => {
|
||||||
|
setKeystore(event.currentTarget.value || "");
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
selectedKeystore,
|
||||||
|
onKeystoreChanged,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
83
examples/rln-js/src/hooks/useKeystore.ts
Normal file
83
examples/rln-js/src/hooks/useKeystore.ts
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { useStore } from "./useStore";
|
||||||
|
import { useRLN } from "./useRLN";
|
||||||
|
import { SEPOLIA_CONTRACT } from "@waku/rln";
|
||||||
|
import { StatusEventPayload } from "@/services/rln";
|
||||||
|
|
||||||
|
type UseKeystoreResult = {
|
||||||
|
onReadCredentials: (hash: string, password: string) => void;
|
||||||
|
onRegisterCredentials: (password: string) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useKeystore = (): UseKeystoreResult => {
|
||||||
|
const { rln } = useRLN();
|
||||||
|
const {
|
||||||
|
credentials,
|
||||||
|
setActiveCredential,
|
||||||
|
setActiveMembershipID,
|
||||||
|
setAppStatus,
|
||||||
|
setCredentials,
|
||||||
|
} = useStore();
|
||||||
|
|
||||||
|
const onRegisterCredentials = React.useCallback(
|
||||||
|
async (password: string) => {
|
||||||
|
if (!credentials || !rln?.rlnContract || !password) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
setAppStatus(StatusEventPayload.CREDENTIALS_REGISTERING);
|
||||||
|
const membershipInfo = await rln.rlnContract.registerWithKey(
|
||||||
|
credentials
|
||||||
|
);
|
||||||
|
const membershipID = membershipInfo!.index.toNumber();
|
||||||
|
const keystoreHash = await rln.keystore.addCredential(
|
||||||
|
{
|
||||||
|
membership: {
|
||||||
|
treeIndex: membershipID,
|
||||||
|
chainId: SEPOLIA_CONTRACT.chainId,
|
||||||
|
address: SEPOLIA_CONTRACT.address,
|
||||||
|
},
|
||||||
|
identity: credentials,
|
||||||
|
},
|
||||||
|
password
|
||||||
|
);
|
||||||
|
setActiveCredential(keystoreHash);
|
||||||
|
setActiveMembershipID(membershipID);
|
||||||
|
rln.saveKeystore();
|
||||||
|
setAppStatus(StatusEventPayload.CREDENTIALS_REGISTERED);
|
||||||
|
} catch (error) {
|
||||||
|
setAppStatus(StatusEventPayload.CREDENTIALS_FAILURE);
|
||||||
|
console.error("Failed to register to RLN Contract: ", error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[credentials, rln, setActiveCredential, setActiveMembershipID, setAppStatus]
|
||||||
|
);
|
||||||
|
|
||||||
|
const onReadCredentials = React.useCallback(
|
||||||
|
async (hash: string, password: string) => {
|
||||||
|
if (!rln || !hash || !password) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const record = await rln.keystore.readCredential(hash, password);
|
||||||
|
if (record) {
|
||||||
|
setCredentials(record.identity);
|
||||||
|
setActiveCredential(hash);
|
||||||
|
setActiveMembershipID(record.membership.treeIndex);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to read credentials from Keystore.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[rln, setActiveCredential, setActiveMembershipID, setCredentials]
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
onRegisterCredentials,
|
||||||
|
onReadCredentials,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -13,8 +13,6 @@ type StoreResult = {
|
|||||||
credentials: undefined | IdentityCredential;
|
credentials: undefined | IdentityCredential;
|
||||||
setCredentials: (v: undefined | IdentityCredential) => void;
|
setCredentials: (v: undefined | IdentityCredential) => void;
|
||||||
|
|
||||||
keystorePassword: undefined | string;
|
|
||||||
setKeystorePassword: (v: string) => void;
|
|
||||||
activeCredential: string;
|
activeCredential: string;
|
||||||
keystoreCredentials: string[];
|
keystoreCredentials: string[];
|
||||||
setKeystoreCredentials: (v: string[]) => void;
|
setKeystoreCredentials: (v: string[]) => void;
|
||||||
@ -52,9 +50,6 @@ export const useStore = create<StoreResult>((set) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const keystoreModule = {
|
const keystoreModule = {
|
||||||
keystorePassword: undefined,
|
|
||||||
setKeystorePassword: (v: string) =>
|
|
||||||
set((state) => ({ ...state, keystorePassword: v })),
|
|
||||||
activeCredential: DEFAULT_VALUE,
|
activeCredential: DEFAULT_VALUE,
|
||||||
setActiveCredential: (v: string) =>
|
setActiveCredential: (v: string) =>
|
||||||
set((state) => ({ ...state, activeCredential: v })),
|
set((state) => ({ ...state, activeCredential: v })),
|
||||||
|
|||||||
@ -3,27 +3,15 @@ import { useStore } from "./useStore";
|
|||||||
import { isEthereumEvenEmitterValid } from "@/utils/ethereum";
|
import { isEthereumEvenEmitterValid } from "@/utils/ethereum";
|
||||||
import { useRLN } from "./useRLN";
|
import { useRLN } from "./useRLN";
|
||||||
import { SIGNATURE_MESSAGE } from "@/constants";
|
import { SIGNATURE_MESSAGE } from "@/constants";
|
||||||
import { SEPOLIA_CONTRACT } from "@waku/rln";
|
|
||||||
import { StatusEventPayload } from "@/services/rln";
|
|
||||||
|
|
||||||
type UseWalletResult = {
|
type UseWalletResult = {
|
||||||
onConnectWallet: () => void;
|
onConnectWallet: () => void;
|
||||||
onGenerateCredentials: () => void;
|
onGenerateCredentials: () => void;
|
||||||
onRegisterCredentials: () => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useWallet = (): UseWalletResult => {
|
export const useWallet = (): UseWalletResult => {
|
||||||
const { rln } = useRLN();
|
const { rln } = useRLN();
|
||||||
const {
|
const { setEthAccount, setChainID, setCredentials } = useStore();
|
||||||
keystorePassword,
|
|
||||||
credentials,
|
|
||||||
setEthAccount,
|
|
||||||
setChainID,
|
|
||||||
setCredentials,
|
|
||||||
setActiveCredential,
|
|
||||||
setActiveMembershipID,
|
|
||||||
setAppStatus,
|
|
||||||
} = useStore();
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const ethereum = window.ethereum;
|
const ethereum = window.ethereum;
|
||||||
@ -81,48 +69,9 @@ export const useWallet = (): UseWalletResult => {
|
|||||||
setCredentials(credentials);
|
setCredentials(credentials);
|
||||||
}, [rln, setCredentials]);
|
}, [rln, setCredentials]);
|
||||||
|
|
||||||
const onRegisterCredentials = React.useCallback(async () => {
|
|
||||||
if (!credentials || !rln?.rlnContract || !keystorePassword) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
setAppStatus(StatusEventPayload.CREDENTIALS_REGISTERING);
|
|
||||||
const membershipInfo = await rln.rlnContract.registerWithKey(credentials);
|
|
||||||
const membershipID = membershipInfo!.index.toNumber();
|
|
||||||
const keystoreHash = await rln.keystore.addCredential(
|
|
||||||
{
|
|
||||||
membership: {
|
|
||||||
treeIndex: membershipID,
|
|
||||||
chainId: SEPOLIA_CONTRACT.chainId,
|
|
||||||
address: SEPOLIA_CONTRACT.address,
|
|
||||||
},
|
|
||||||
identity: credentials,
|
|
||||||
},
|
|
||||||
keystorePassword
|
|
||||||
);
|
|
||||||
setActiveCredential(keystoreHash);
|
|
||||||
setActiveMembershipID(membershipID);
|
|
||||||
rln.saveKeystore();
|
|
||||||
setAppStatus(StatusEventPayload.CREDENTIALS_REGISTERED);
|
|
||||||
} catch (error) {
|
|
||||||
setAppStatus(StatusEventPayload.CREDENTIALS_FAILURE);
|
|
||||||
console.error("Failed to register to RLN Contract: ", error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}, [
|
|
||||||
credentials,
|
|
||||||
rln,
|
|
||||||
keystorePassword,
|
|
||||||
setActiveCredential,
|
|
||||||
setActiveMembershipID,
|
|
||||||
setAppStatus,
|
|
||||||
]);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
onConnectWallet,
|
onConnectWallet,
|
||||||
onGenerateCredentials,
|
onGenerateCredentials,
|
||||||
onRegisterCredentials,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user