mirror of
https://github.com/CryptKeeperZK/crypt-keeper-extension.git
synced 2026-01-08 21:47:56 -05:00
feat: demo host connection (#490)
* feat: demo host connection - [x] Add proof output section - [x] Support identity creation with host - [x] Move manifest files to project root - [x] Add license and privacy policy to dist - [x] Rename selected identity to connected - [x] Support search params for popup redirection - [x] Update demo types * fix: create identity request from popup * fix: routing and demo minor fixes * fix: push missing changes --------- Co-authored-by: 0xmad <0xmad@users.noreply.github.com>
This commit is contained in:
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 0xisk
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -2,7 +2,7 @@ import React, { useEffect } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { ToastContainer } from "react-toastify";
|
||||
|
||||
import { useCryptKeeper } from "./useCryptKeeper";
|
||||
import { MerkleProofType, useCryptKeeper } from "./useCryptKeeper";
|
||||
|
||||
import "react-toastify/dist/ReactToastify.css";
|
||||
|
||||
@@ -24,16 +24,7 @@ function NoConnectedIdentityCommitment() {
|
||||
}
|
||||
|
||||
function App() {
|
||||
const {
|
||||
client,
|
||||
isLocked,
|
||||
selectedIdentity,
|
||||
MerkleProofType,
|
||||
connect,
|
||||
createIdentity,
|
||||
getIdentityCommitment,
|
||||
genSemaphoreProof,
|
||||
} = useCryptKeeper();
|
||||
const { client, isLocked, connectedIdentity, proof, connect, createIdentity, genSemaphoreProof } = useCryptKeeper();
|
||||
|
||||
useEffect(() => {
|
||||
connect();
|
||||
@@ -43,24 +34,63 @@ function App() {
|
||||
return <NotConnected onClick={connect} />;
|
||||
}
|
||||
|
||||
if (!selectedIdentity) {
|
||||
if (!connectedIdentity) {
|
||||
return <NoConnectedIdentityCommitment />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<hr />
|
||||
|
||||
<div>
|
||||
<h2>Identity commitment for the connected identity:</h2>
|
||||
|
||||
<p>{connectedIdentity.commitment}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2>Host name for the connected identity:</h2>
|
||||
|
||||
<p>{connectedIdentity.host}</p>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div>
|
||||
<h2>Create a new secret Identity</h2>
|
||||
|
||||
<button data-testid="create-new-identity" onClick={createIdentity}>
|
||||
Create
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div>
|
||||
<h2>Semaphore</h2>
|
||||
|
||||
<button onClick={() => genSemaphoreProof(MerkleProofType.STORAGE_ADDRESS)}>
|
||||
Generate proof from Merkle proof storage address
|
||||
</button>{" "}
|
||||
</button>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<button onClick={() => genSemaphoreProof(MerkleProofType.ARTIFACTS)}>
|
||||
Generate proof from Merkle proof artifacts
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div>
|
||||
<h2>Semaphore Proof output:</h2>
|
||||
|
||||
<div>
|
||||
<pre>{JSON.stringify(proof, null, 2)}</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* <div>
|
||||
<h2>RLN</h2>
|
||||
<button onClick={() => genRLNProof(MerkleProofType.STORAGE_ADDRESS)}>
|
||||
@@ -73,29 +103,6 @@ function App() {
|
||||
</button>
|
||||
</div> */}
|
||||
|
||||
<hr />
|
||||
<div>
|
||||
<h2>Get Identity Commitment</h2>
|
||||
<button onClick={getIdentityCommitment}>Get</button> <br />
|
||||
<br />
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
<div>
|
||||
<h2>Create a new Identity</h2>
|
||||
<button data-testid="create-new-identity" onClick={createIdentity}>
|
||||
Create
|
||||
</button>{" "}
|
||||
<br />
|
||||
<br />
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
<div>
|
||||
<h2>Identity commitment for connected identity:</h2>
|
||||
<p>{selectedIdentity.commitment}</p>
|
||||
</div>
|
||||
|
||||
<ToastContainer newestOnTop={true} />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,27 +1,35 @@
|
||||
// TODO: temp until providers package isn't ready
|
||||
export interface SelectedIdentity {
|
||||
import type { FullProof } from "@semaphore-protocol/proof";
|
||||
import type { RLNFullProof } from "rlnjs";
|
||||
|
||||
export interface ConnectedIdentity {
|
||||
commitment: string;
|
||||
web2Provider?: string;
|
||||
host?: string;
|
||||
}
|
||||
|
||||
export interface SemaphoreProof {
|
||||
fullProof: FullProof;
|
||||
}
|
||||
|
||||
export interface CryptKeeperInjectedProvider {
|
||||
accounts: () => Promise<string[]>;
|
||||
connect: () => Promise<CryptKeeperInjectedProvider>;
|
||||
createIdentity: () => Promise<void>;
|
||||
getConnectedIdentity: () => Promise<SelectedIdentity>;
|
||||
createIdentity: (payload: { host: string }) => Promise<void>;
|
||||
getConnectedIdentity: () => Promise<ConnectedIdentity>;
|
||||
cleanListeners: () => void;
|
||||
semaphoreProof(
|
||||
externalNullifier: string,
|
||||
signal: string,
|
||||
merkleProofArtifactsOrStorageAddress: string | unknown,
|
||||
merkleProof?: unknown,
|
||||
): Promise<unknown>;
|
||||
): Promise<SemaphoreProof>;
|
||||
rlnProof(
|
||||
externalNullifier: string,
|
||||
signal: string,
|
||||
merkleProofArtifactsOrStorageAddress: string | unknown,
|
||||
rlnIdentifier: string,
|
||||
): Promise<unknown>;
|
||||
): Promise<RLNFullProof>;
|
||||
on: (event: string, handler: (...args: unknown[]) => void) => void;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/* eslint-disable no-console */
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
import { RLN } from "rlnjs";
|
||||
import { RLN, RLNFullProof } from "rlnjs";
|
||||
import { bigintToHex } from "bigint-conversion";
|
||||
import { Identity } from "@semaphore-protocol/identity";
|
||||
import { encodeBytes32String } from "ethers";
|
||||
import { toast } from "react-toastify";
|
||||
|
||||
import "react-toastify/dist/ReactToastify.css";
|
||||
import { CryptKeeperInjectedProvider, SelectedIdentity } from "./types";
|
||||
import type { CryptKeeperInjectedProvider, ConnectedIdentity, SemaphoreProof } from "./types";
|
||||
|
||||
const SERVER_URL = "http://localhost:8090";
|
||||
|
||||
@@ -24,19 +24,19 @@ const genMockIdentityCommitments = (): string[] => {
|
||||
return identityCommitments;
|
||||
};
|
||||
|
||||
enum MerkleProofType {
|
||||
export enum MerkleProofType {
|
||||
STORAGE_ADDRESS,
|
||||
ARTIFACTS,
|
||||
}
|
||||
|
||||
interface IUseCryptKeeperData {
|
||||
client?: CryptKeeperInjectedProvider;
|
||||
isLocked: boolean;
|
||||
selectedIdentity: SelectedIdentity;
|
||||
MerkleProofType: typeof MerkleProofType;
|
||||
connectedIdentity: ConnectedIdentity;
|
||||
client?: CryptKeeperInjectedProvider;
|
||||
proof?: SemaphoreProof | RLNFullProof;
|
||||
connect: () => void;
|
||||
createIdentity: () => unknown;
|
||||
getIdentityCommitment: () => void;
|
||||
getConnectedIdentity: () => void;
|
||||
genSemaphoreProof: (proofType: MerkleProofType) => void;
|
||||
genRLNProof: (proofType: MerkleProofType) => void;
|
||||
}
|
||||
@@ -46,9 +46,11 @@ const initializeClient = (): Promise<CryptKeeperInjectedProvider | undefined> =>
|
||||
export const useCryptKeeper = (): IUseCryptKeeperData => {
|
||||
const [client, setClient] = useState<CryptKeeperInjectedProvider>();
|
||||
const [isLocked, setIsLocked] = useState(true);
|
||||
const [selectedIdentity, setSelectedIdentity] = useState<SelectedIdentity>({
|
||||
const [proof, setProof] = useState<SemaphoreProof | RLNFullProof>();
|
||||
const [connectedIdentity, setConnectedIdentity] = useState<ConnectedIdentity>({
|
||||
commitment: "",
|
||||
web2Provider: "",
|
||||
host: "",
|
||||
});
|
||||
const mockIdentityCommitments: string[] = genMockIdentityCommitments();
|
||||
|
||||
@@ -66,12 +68,13 @@ export const useCryptKeeper = (): IUseCryptKeeperData => {
|
||||
const genSemaphoreProof = async (proofType: MerkleProofType = MerkleProofType.STORAGE_ADDRESS) => {
|
||||
const externalNullifier = encodeBytes32String("voting-1");
|
||||
const signal = encodeBytes32String("hello-world");
|
||||
|
||||
let storageAddressOrArtifacts: any = `${merkleStorageAddress}/Semaphore`;
|
||||
|
||||
if (!mockIdentityCommitments.includes(connectedIdentity.commitment)) {
|
||||
mockIdentityCommitments.push(connectedIdentity.commitment);
|
||||
}
|
||||
|
||||
if (proofType === MerkleProofType.ARTIFACTS) {
|
||||
if (!mockIdentityCommitments.includes(selectedIdentity.commitment)) {
|
||||
mockIdentityCommitments.push(selectedIdentity.commitment);
|
||||
}
|
||||
storageAddressOrArtifacts = {
|
||||
leaves: mockIdentityCommitments,
|
||||
depth: 20,
|
||||
@@ -79,25 +82,24 @@ export const useCryptKeeper = (): IUseCryptKeeperData => {
|
||||
};
|
||||
}
|
||||
|
||||
let toastId;
|
||||
try {
|
||||
toastId = toast("Generating semaphore proof...", {
|
||||
type: "info",
|
||||
hideProgressBar: true,
|
||||
closeOnClick: true,
|
||||
pauseOnHover: false,
|
||||
});
|
||||
const toastId = toast("Generating semaphore proof...", {
|
||||
type: "info",
|
||||
hideProgressBar: true,
|
||||
closeOnClick: true,
|
||||
pauseOnHover: false,
|
||||
});
|
||||
|
||||
const proof = await client?.semaphoreProof(externalNullifier, signal, storageAddressOrArtifacts);
|
||||
|
||||
console.log("Semaphore proof generated successfully!", proof);
|
||||
toast("Semaphore proof generated successfully!", { type: "success" });
|
||||
} catch (e) {
|
||||
toast("Error while generating Semaphore proof!", { type: "error" });
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
toast.dismiss(toastId);
|
||||
await client
|
||||
?.semaphoreProof(externalNullifier, signal, storageAddressOrArtifacts)
|
||||
.then((proof) => {
|
||||
setProof(proof);
|
||||
toast("Semaphore proof generated successfully!", { type: "success" });
|
||||
})
|
||||
.catch((error) => {
|
||||
toast("Error while generating Semaphore proof!", { type: "error" });
|
||||
console.error(error);
|
||||
})
|
||||
.finally(() => toast.dismiss(toastId));
|
||||
};
|
||||
|
||||
const genRLNProof = async (proofType: MerkleProofType = MerkleProofType.STORAGE_ADDRESS) => {
|
||||
@@ -105,14 +107,13 @@ export const useCryptKeeper = (): IUseCryptKeeperData => {
|
||||
const signal = encodeBytes32String("hello-world");
|
||||
const rlnIdentifier = RLN._genIdentifier();
|
||||
const rlnIdentifierHex = bigintToHex(rlnIdentifier);
|
||||
|
||||
let storageAddressOrArtifacts: any = `${merkleStorageAddress}/RLN`;
|
||||
|
||||
if (proofType === MerkleProofType.ARTIFACTS) {
|
||||
if (!mockIdentityCommitments.includes(selectedIdentity.commitment)) {
|
||||
mockIdentityCommitments.push(selectedIdentity.commitment);
|
||||
}
|
||||
if (!mockIdentityCommitments.includes(connectedIdentity.commitment)) {
|
||||
mockIdentityCommitments.push(connectedIdentity.commitment);
|
||||
}
|
||||
|
||||
if (proofType === MerkleProofType.ARTIFACTS) {
|
||||
storageAddressOrArtifacts = {
|
||||
leaves: mockIdentityCommitments,
|
||||
depth: 15,
|
||||
@@ -120,66 +121,68 @@ export const useCryptKeeper = (): IUseCryptKeeperData => {
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const toastId = toast("Generating RLN proof...", {
|
||||
type: "info",
|
||||
hideProgressBar: true,
|
||||
closeOnClick: true,
|
||||
pauseOnHover: false,
|
||||
});
|
||||
const toastId = toast("Generating RLN proof...", {
|
||||
type: "info",
|
||||
hideProgressBar: true,
|
||||
closeOnClick: true,
|
||||
pauseOnHover: false,
|
||||
});
|
||||
|
||||
const proof = await client?.rlnProof(externalNullifier, signal, storageAddressOrArtifacts, rlnIdentifierHex);
|
||||
|
||||
console.log("RLN proof generated successfully!", proof);
|
||||
toast("RLN proof generated successfully!", { type: "success" });
|
||||
toast.dismiss(toastId);
|
||||
} catch (e) {
|
||||
toast("Error while generating RLN proof!", { type: "error" });
|
||||
console.error(e);
|
||||
}
|
||||
await client
|
||||
?.rlnProof(externalNullifier, signal, storageAddressOrArtifacts, rlnIdentifierHex)
|
||||
.then((proof) => {
|
||||
setProof(proof);
|
||||
toast("RLN proof generated successfully!", { type: "success" });
|
||||
})
|
||||
.catch((error) => {
|
||||
toast("Error while generating RLN proof!", { type: "error" });
|
||||
console.error(error);
|
||||
})
|
||||
.finally(() => toast.dismiss(toastId));
|
||||
};
|
||||
|
||||
const getIdentityCommitment = useCallback(async () => {
|
||||
const getConnectedIdentity = useCallback(async () => {
|
||||
const payload = await client?.getConnectedIdentity();
|
||||
|
||||
if (!payload) {
|
||||
return;
|
||||
}
|
||||
|
||||
setSelectedIdentity({
|
||||
setConnectedIdentity({
|
||||
commitment: payload.commitment,
|
||||
web2Provider: payload.web2Provider,
|
||||
host: payload.host,
|
||||
});
|
||||
|
||||
toast(`Getting Identity Commitment successfully! ${payload.commitment}`, { type: "success" });
|
||||
}, [client, setSelectedIdentity]);
|
||||
}, [client, setConnectedIdentity]);
|
||||
|
||||
const createIdentity = useCallback(() => {
|
||||
client?.createIdentity();
|
||||
client?.createIdentity({ host: window.location.href });
|
||||
}, [client]);
|
||||
|
||||
const onIdentityChanged = useCallback(
|
||||
(payload: unknown) => {
|
||||
const { commitment, web2Provider } = payload as SelectedIdentity;
|
||||
const { commitment, web2Provider, host } = payload as ConnectedIdentity;
|
||||
|
||||
setSelectedIdentity({ commitment, web2Provider });
|
||||
setConnectedIdentity({ commitment, web2Provider, host });
|
||||
toast(`Identity has changed! ${commitment}`, { type: "success" });
|
||||
},
|
||||
[setSelectedIdentity],
|
||||
[setConnectedIdentity],
|
||||
);
|
||||
|
||||
const onLogin = useCallback(() => {
|
||||
setIsLocked(false);
|
||||
getIdentityCommitment();
|
||||
}, [setIsLocked, getIdentityCommitment]);
|
||||
}, [setIsLocked]);
|
||||
|
||||
const onLogout = useCallback(() => {
|
||||
setSelectedIdentity({
|
||||
setConnectedIdentity({
|
||||
commitment: "",
|
||||
web2Provider: "",
|
||||
host: "",
|
||||
});
|
||||
setIsLocked(true);
|
||||
}, [setSelectedIdentity, setIsLocked]);
|
||||
}, [setConnectedIdentity, setIsLocked]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!client) {
|
||||
@@ -190,17 +193,19 @@ export const useCryptKeeper = (): IUseCryptKeeperData => {
|
||||
client?.on("identityChanged", onIdentityChanged);
|
||||
client?.on("logout", onLogout);
|
||||
|
||||
getConnectedIdentity();
|
||||
|
||||
return () => client?.cleanListeners();
|
||||
}, [client, onLogout, onIdentityChanged, onLogin]);
|
||||
|
||||
return {
|
||||
client,
|
||||
isLocked,
|
||||
selectedIdentity,
|
||||
MerkleProofType,
|
||||
connectedIdentity,
|
||||
proof,
|
||||
connect,
|
||||
createIdentity,
|
||||
getIdentityCommitment,
|
||||
getConnectedIdentity,
|
||||
genSemaphoreProof,
|
||||
genRLNProof,
|
||||
};
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
"content_security_policy": {
|
||||
"extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self';"
|
||||
},
|
||||
"permissions": ["scripting", "clipboardWrite", "activeTab", "storage", "notifications"],
|
||||
"permissions": ["scripting", "clipboardWrite", "activeTab", "storage", "notifications", "unlimitedStorage"],
|
||||
"host_permissions": ["http://*/", "https://*/"],
|
||||
"web_accessible_resources": [
|
||||
{
|
||||
@@ -26,7 +26,7 @@
|
||||
"content_security_policy": {
|
||||
"extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self';"
|
||||
},
|
||||
"permissions": ["scripting", "clipboardWrite", "activeTab", "storage", "notifications"],
|
||||
"permissions": ["scripting", "clipboardWrite", "activeTab", "storage", "notifications", "unlimitedStorage"],
|
||||
"host_permissions": ["http://*/", "https://*/"],
|
||||
"web_accessible_resources": [
|
||||
{
|
||||
@@ -1,9 +1,9 @@
|
||||
import log from "loglevel";
|
||||
import { browser } from "webextension-polyfill-ts";
|
||||
|
||||
import { InjectedMessageData, ReduxAction, SelectedIdentity } from "@src/types";
|
||||
import { InjectedMessageData, ReduxAction, ConnectedIdentity } from "@src/types";
|
||||
import { setStatus } from "@src/ui/ducks/app";
|
||||
import { setSelectedCommitment } from "@src/ui/ducks/identities";
|
||||
import { setConnectedIdentity } from "@src/ui/ducks/identities";
|
||||
|
||||
function injectScript() {
|
||||
const url = browser.runtime.getURL("js/injected.js");
|
||||
@@ -33,11 +33,11 @@ function injectScript() {
|
||||
|
||||
browser.runtime.onMessage.addListener((action: ReduxAction) => {
|
||||
switch (action.type) {
|
||||
case setSelectedCommitment.type: {
|
||||
case setConnectedIdentity.type: {
|
||||
window.postMessage(
|
||||
{
|
||||
target: "injected-injectedscript",
|
||||
payload: [null, action.payload as SelectedIdentity],
|
||||
payload: [null, action.payload as ConnectedIdentity],
|
||||
nonce: "identityChanged",
|
||||
},
|
||||
"*",
|
||||
|
||||
@@ -47,7 +47,7 @@ export default class BrowserUtils {
|
||||
const index = tabs.findIndex((tab) => tab.active && tab.highlighted);
|
||||
const searchParams = params ? `?${new URLSearchParams(params).toString()}` : "";
|
||||
const tab = await this.createTab({
|
||||
url: `popup.html${searchParams}`,
|
||||
url: `popup.html#/${searchParams}`,
|
||||
active: index >= 0,
|
||||
index: index >= 0 ? index : undefined,
|
||||
});
|
||||
|
||||
@@ -92,11 +92,7 @@ export default class CryptKeeperController {
|
||||
this.lockService.ensure,
|
||||
this.zkIdentityService.getConnectedIdentityData,
|
||||
);
|
||||
this.handler.add(
|
||||
RPCAction.SET_CONNECTED_IDENTITY,
|
||||
this.lockService.ensure,
|
||||
this.zkIdentityService.setConnectedIdentity,
|
||||
);
|
||||
this.handler.add(RPCAction.CONNECT_IDENTITY, this.lockService.ensure, this.zkIdentityService.connectIdentity);
|
||||
this.handler.add(RPCAction.SET_IDENTITY_NAME, this.lockService.ensure, this.zkIdentityService.setIdentityName);
|
||||
this.handler.add(RPCAction.SET_IDENTITY_HOST, this.lockService.ensure, this.zkIdentityService.setIdentityHost);
|
||||
this.handler.add(
|
||||
|
||||
@@ -7,7 +7,7 @@ import ZkIdentityService from "@src/background/services/zkIdentity";
|
||||
import { ZERO_ADDRESS } from "@src/config/const";
|
||||
import { getEnabledFeatures } from "@src/config/features";
|
||||
import { CreateIdentityOptions, EWallet, IdentityStrategy } from "@src/types";
|
||||
import { setSelectedCommitment } from "@src/ui/ducks/identities";
|
||||
import { setConnectedIdentity } from "@src/ui/ducks/identities";
|
||||
import pushMessage from "@src/util/pushMessage";
|
||||
|
||||
import { createNewIdentity } from "../factory";
|
||||
@@ -15,7 +15,10 @@ import { createNewIdentity } from "../factory";
|
||||
const mockDefaultIdentityCommitment =
|
||||
bigintToHex(15206603389158210388485662342360617949291660595274505642693885456541816400294n);
|
||||
const mockDefaultIdentities = [
|
||||
[mockDefaultIdentityCommitment, JSON.stringify({ secret: "1234", metadata: { identityStrategy: "interrep" } })],
|
||||
[
|
||||
mockDefaultIdentityCommitment,
|
||||
JSON.stringify({ secret: "1234", metadata: { identityStrategy: "interrep", host: "http://localhost:3000" } }),
|
||||
],
|
||||
];
|
||||
const mockSerializedDefaultIdentities = JSON.stringify(mockDefaultIdentities);
|
||||
|
||||
@@ -116,7 +119,7 @@ describe("background/services/zkIdentity", () => {
|
||||
expect(result).toBe(true);
|
||||
expect(pushMessage).toBeCalledTimes(1);
|
||||
expect(pushMessage).toBeCalledWith(
|
||||
setSelectedCommitment({
|
||||
setConnectedIdentity({
|
||||
commitment: mockDefaultIdentityCommitment,
|
||||
}),
|
||||
);
|
||||
@@ -126,7 +129,7 @@ describe("background/services/zkIdentity", () => {
|
||||
expect(browser.tabs.sendMessage).toHaveBeenNthCalledWith(
|
||||
index + 1,
|
||||
defaultTabs[index].id,
|
||||
setSelectedCommitment({
|
||||
setConnectedIdentity({
|
||||
commitment: mockDefaultIdentityCommitment,
|
||||
}),
|
||||
);
|
||||
@@ -146,7 +149,7 @@ describe("background/services/zkIdentity", () => {
|
||||
|
||||
describe("set connected identity", () => {
|
||||
test("should set connected identity properly", async () => {
|
||||
const result = await zkIdentityService.setConnectedIdentity({
|
||||
const result = await zkIdentityService.connectIdentity({
|
||||
identityCommitment: mockDefaultIdentityCommitment,
|
||||
host: "http://localhost:3000",
|
||||
});
|
||||
@@ -154,7 +157,7 @@ describe("background/services/zkIdentity", () => {
|
||||
expect(result).toBe(true);
|
||||
expect(pushMessage).toBeCalledTimes(1);
|
||||
expect(pushMessage).toBeCalledWith(
|
||||
setSelectedCommitment({
|
||||
setConnectedIdentity({
|
||||
commitment: mockDefaultIdentityCommitment,
|
||||
host: "http://localhost:3000",
|
||||
web2Provider: undefined,
|
||||
@@ -166,7 +169,7 @@ describe("background/services/zkIdentity", () => {
|
||||
expect(browser.tabs.sendMessage).toHaveBeenNthCalledWith(
|
||||
index + 1,
|
||||
defaultTabs[index].id,
|
||||
setSelectedCommitment({
|
||||
setConnectedIdentity({
|
||||
commitment: mockDefaultIdentityCommitment,
|
||||
host: "http://localhost:3000",
|
||||
web2Provider: undefined,
|
||||
@@ -180,7 +183,7 @@ describe("background/services/zkIdentity", () => {
|
||||
instance.get.mockReturnValue(undefined);
|
||||
});
|
||||
|
||||
const result = await zkIdentityService.setConnectedIdentity({
|
||||
const result = await zkIdentityService.connectIdentity({
|
||||
identityCommitment: mockDefaultIdentityCommitment,
|
||||
host: "http://localhost:3000",
|
||||
});
|
||||
@@ -260,7 +263,7 @@ describe("background/services/zkIdentity", () => {
|
||||
|
||||
describe("delete all identities", () => {
|
||||
test("should delete all identities properly", async () => {
|
||||
const isIdentitySet = await zkIdentityService.setConnectedIdentity({
|
||||
const isIdentitySet = await zkIdentityService.connectIdentity({
|
||||
identityCommitment: mockDefaultIdentityCommitment,
|
||||
host: "http://localhost:3000",
|
||||
});
|
||||
@@ -320,6 +323,7 @@ describe("background/services/zkIdentity", () => {
|
||||
expect(data).toStrictEqual({
|
||||
commitment: mockDefaultIdentityCommitment,
|
||||
web2Provider: "",
|
||||
host: "http://localhost:3000",
|
||||
});
|
||||
});
|
||||
|
||||
@@ -331,6 +335,7 @@ describe("background/services/zkIdentity", () => {
|
||||
expect(data).toStrictEqual({
|
||||
commitment: "",
|
||||
web2Provider: "",
|
||||
host: "",
|
||||
});
|
||||
});
|
||||
|
||||
@@ -379,7 +384,7 @@ describe("background/services/zkIdentity", () => {
|
||||
|
||||
describe("create", () => {
|
||||
test("should be able to request a create identity modal", async () => {
|
||||
await zkIdentityService.createIdentityRequest();
|
||||
await zkIdentityService.createIdentityRequest({ host: "http://localhost:3000" });
|
||||
|
||||
expect(browser.tabs.query).toBeCalledWith({ lastFocusedWindow: true });
|
||||
|
||||
|
||||
@@ -17,11 +17,12 @@ import {
|
||||
SetIdentityNameArgs,
|
||||
NewIdentityRequest,
|
||||
OperationType,
|
||||
SelectedIdentity,
|
||||
ConnectedIdentity,
|
||||
SetIdentityHostArgs,
|
||||
SetConnectedIdentityArgs,
|
||||
ConnectIdentityArgs,
|
||||
ICreateIdentityRequestArgs,
|
||||
} from "@src/types";
|
||||
import { setIdentities, setSelectedCommitment } from "@src/ui/ducks/identities";
|
||||
import { setIdentities, setConnectedIdentity } from "@src/ui/ducks/identities";
|
||||
import { ellipsify } from "@src/util/account";
|
||||
import pushMessage from "@src/util/pushMessage";
|
||||
|
||||
@@ -70,12 +71,13 @@ export default class ZkIdentityService implements IBackupable {
|
||||
return ZkIdentityService.INSTANCE;
|
||||
};
|
||||
|
||||
getConnectedIdentityData = async (): Promise<SelectedIdentity> => {
|
||||
getConnectedIdentityData = async (): Promise<ConnectedIdentity> => {
|
||||
const identity = await this.getConnectedIdentity();
|
||||
|
||||
return {
|
||||
commitment: identity ? bigintToHex(identity.genIdentityCommitment()) : "",
|
||||
web2Provider: identity?.metadata.web2Provider || "",
|
||||
host: identity?.metadata.host || "",
|
||||
};
|
||||
};
|
||||
|
||||
@@ -147,7 +149,7 @@ export default class ZkIdentityService implements IBackupable {
|
||||
return identities.size;
|
||||
};
|
||||
|
||||
setConnectedIdentity = async ({ host, identityCommitment }: SetConnectedIdentityArgs): Promise<boolean> => {
|
||||
connectIdentity = async ({ host, identityCommitment }: ConnectIdentityArgs): Promise<boolean> => {
|
||||
const identities = await this.getIdentitiesFromStore();
|
||||
|
||||
return this.updateConnectedIdentity({ identities, identityCommitment, host });
|
||||
@@ -182,7 +184,7 @@ export default class ZkIdentityService implements IBackupable {
|
||||
const [tabs] = await Promise.all([
|
||||
browser.tabs.query({ active: true }),
|
||||
pushMessage(
|
||||
setSelectedCommitment({
|
||||
setConnectedIdentity({
|
||||
commitment,
|
||||
web2Provider: metadata?.web2Provider,
|
||||
host: metadata?.host,
|
||||
@@ -195,7 +197,7 @@ export default class ZkIdentityService implements IBackupable {
|
||||
browser.tabs
|
||||
.sendMessage(
|
||||
tab.id as number,
|
||||
setSelectedCommitment({
|
||||
setConnectedIdentity({
|
||||
commitment,
|
||||
web2Provider: metadata?.web2Provider,
|
||||
host: metadata?.host,
|
||||
@@ -271,8 +273,8 @@ export default class ZkIdentityService implements IBackupable {
|
||||
await this.writeConnectedIdentity("");
|
||||
};
|
||||
|
||||
createIdentityRequest = async (): Promise<void> => {
|
||||
await this.browserController.openPopup({ params: { redirect: Paths.CREATE_IDENTITY } });
|
||||
createIdentityRequest = async ({ host }: ICreateIdentityRequestArgs): Promise<void> => {
|
||||
await this.browserController.openPopup({ params: { redirect: Paths.CREATE_IDENTITY, host } });
|
||||
};
|
||||
|
||||
createIdentity = async ({
|
||||
|
||||
@@ -6,7 +6,7 @@ export enum RPCAction {
|
||||
SETUP_PASSWORD = "rpc/lock/setupPassword",
|
||||
CREATE_IDENTITY = "rpc/identity/createIdentity",
|
||||
CREATE_IDENTITY_REQ = "rpc/identity/createIdentityRequest",
|
||||
SET_CONNECTED_IDENTITY = "rpc/identity/setConnectedIdentity",
|
||||
CONNECT_IDENTITY = "rpc/identity/connectIdentity",
|
||||
SET_IDENTITY_NAME = "rpc/identity/setIdentityName",
|
||||
SET_IDENTITY_HOST = "rpc/identity/setIdentityHost",
|
||||
DELETE_IDENTITY = "rpc/identity/deleteIdentity",
|
||||
|
||||
@@ -14,8 +14,9 @@ import {
|
||||
InjectedProviderRequest,
|
||||
MerkleProofArtifacts,
|
||||
RLNFullProof,
|
||||
SelectedIdentity,
|
||||
ConnectedIdentity,
|
||||
SemaphoreProof,
|
||||
ICreateIdentityRequestArgs,
|
||||
} from "@src/types";
|
||||
import { HostPermission } from "@src/ui/ducks/permissions";
|
||||
|
||||
@@ -161,10 +162,10 @@ export class CryptKeeperInjectedProvider extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
async getConnectedIdentity(): Promise<SelectedIdentity> {
|
||||
async getConnectedIdentity(): Promise<ConnectedIdentity> {
|
||||
return this.post({
|
||||
method: RPCAction.GET_CONNECTED_IDENTITY_DATA,
|
||||
}) as Promise<SelectedIdentity>;
|
||||
}) as Promise<ConnectedIdentity>;
|
||||
}
|
||||
|
||||
async getHostPermissions(host: string): Promise<unknown> {
|
||||
@@ -184,9 +185,12 @@ export class CryptKeeperInjectedProvider extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
async createIdentity(): Promise<unknown> {
|
||||
async createIdentity({ host }: ICreateIdentityRequestArgs): Promise<unknown> {
|
||||
return this.post({
|
||||
method: RPCAction.CREATE_IDENTITY_REQ,
|
||||
payload: {
|
||||
host,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { CreateIdentityOptions, EWallet, GroupData, IdentityStrategy } from "../identity";
|
||||
|
||||
export interface SelectedIdentity {
|
||||
export interface ConnectedIdentity {
|
||||
commitment: string;
|
||||
web2Provider?: string;
|
||||
host?: string;
|
||||
|
||||
@@ -10,6 +10,10 @@ export type CreateIdentityOptions = {
|
||||
name?: string;
|
||||
};
|
||||
|
||||
export interface ICreateIdentityRequestArgs {
|
||||
host: string;
|
||||
}
|
||||
|
||||
export type NewIdentityRequest = {
|
||||
strategy: IdentityStrategy;
|
||||
options: CreateIdentityOptions;
|
||||
@@ -57,7 +61,7 @@ export interface SetIdentityHostArgs {
|
||||
host: string;
|
||||
}
|
||||
|
||||
export interface SetConnectedIdentityArgs {
|
||||
export interface ConnectIdentityArgs {
|
||||
identityCommitment: string;
|
||||
host: string;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ export const IdentityList = ({
|
||||
);
|
||||
|
||||
const onCreateIdentityRequest = useCallback(() => {
|
||||
dispatch(createIdentityRequest());
|
||||
dispatch(createIdentityRequest({ host: "" }));
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Provider } from "react-redux";
|
||||
|
||||
import { ZERO_ADDRESS } from "@src/config/const";
|
||||
import { RPCAction } from "@src/constants";
|
||||
import { EWallet, HistorySettings, OperationType, SelectedIdentity } from "@src/types";
|
||||
import { EWallet, HistorySettings, OperationType, ConnectedIdentity } from "@src/types";
|
||||
import { store } from "@src/ui/store/configureAppStore";
|
||||
import postMessage from "@src/util/postMessage";
|
||||
|
||||
@@ -22,10 +22,10 @@ import {
|
||||
IdentitiesState,
|
||||
setIdentities,
|
||||
setIdentityRequestPending,
|
||||
setSelectedCommitment,
|
||||
connectIdentity,
|
||||
useIdentities,
|
||||
useIdentityRequestPending,
|
||||
useSelectedIdentity,
|
||||
useConnectedIdentity,
|
||||
fetchHistory,
|
||||
useIdentityOperations,
|
||||
getHistory,
|
||||
@@ -77,9 +77,10 @@ describe("ui/ducks/identities", () => {
|
||||
|
||||
const defaultSettings: HistorySettings = { isEnabled: true };
|
||||
|
||||
const defaultSelectedIdentity: SelectedIdentity = {
|
||||
const defaultConnectedIdentity: ConnectedIdentity = {
|
||||
commitment: defaultIdentities[0].commitment,
|
||||
web2Provider: defaultIdentities[0].metadata.web2Provider,
|
||||
host: defaultIdentities[0].metadata.host,
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
@@ -87,7 +88,7 @@ describe("ui/ducks/identities", () => {
|
||||
});
|
||||
|
||||
test("should fetch identities properly", async () => {
|
||||
(postMessage as jest.Mock).mockResolvedValueOnce(defaultIdentities).mockResolvedValueOnce(defaultSelectedIdentity);
|
||||
(postMessage as jest.Mock).mockResolvedValueOnce(defaultIdentities).mockResolvedValueOnce(defaultConnectedIdentity);
|
||||
|
||||
await Promise.resolve(store.dispatch(fetchIdentities()));
|
||||
const { identities } = store.getState();
|
||||
@@ -100,7 +101,7 @@ describe("ui/ducks/identities", () => {
|
||||
const unlinkedIdentitiesHookData = renderHook(() => useUnlinkedIdentities(), {
|
||||
wrapper: ({ children }) => <Provider store={store}>{children}</Provider>,
|
||||
});
|
||||
const selectedIdentityHookData = renderHook(() => useSelectedIdentity(), {
|
||||
const connectedIdentityHookData = renderHook(() => useConnectedIdentity(), {
|
||||
wrapper: ({ children }) => <Provider store={store}>{children}</Provider>,
|
||||
});
|
||||
|
||||
@@ -108,7 +109,7 @@ describe("ui/ducks/identities", () => {
|
||||
expect(identitiesHookData.result.current).toStrictEqual(defaultIdentities);
|
||||
expect(linkedIdentitiesHookData.result.current).toStrictEqual(defaultIdentities.slice(0, 1));
|
||||
expect(unlinkedIdentitiesHookData.result.current).toStrictEqual(defaultIdentities.slice(1));
|
||||
expect(selectedIdentityHookData.result.current).toStrictEqual(defaultIdentities[0]);
|
||||
expect(connectedIdentityHookData.result.current).toStrictEqual(defaultIdentities[0]);
|
||||
});
|
||||
|
||||
test("should fetch history properly", async () => {
|
||||
@@ -176,12 +177,13 @@ describe("ui/ducks/identities", () => {
|
||||
expect(identities.operations).toStrictEqual(defaultOperations);
|
||||
});
|
||||
|
||||
test("should set selected commitment properly", async () => {
|
||||
await Promise.resolve(store.dispatch(setSelectedCommitment(defaultSelectedIdentity)));
|
||||
test("should set connected identity properly", async () => {
|
||||
await Promise.resolve(store.dispatch(setConnectedIdentity(defaultConnectedIdentity)));
|
||||
const { identities } = store.getState();
|
||||
|
||||
expect(identities.selected.commitment).toBe("1");
|
||||
expect(identities.selected.web2Provider).toBe("twitter");
|
||||
expect(identities.connected.commitment).toBe("1");
|
||||
expect(identities.connected.web2Provider).toBe("twitter");
|
||||
expect(identities.connected.host).toBe("http://localhost:3000");
|
||||
});
|
||||
|
||||
test("should set identities properly", async () => {
|
||||
@@ -203,10 +205,13 @@ describe("ui/ducks/identities", () => {
|
||||
});
|
||||
|
||||
test("should call create identity request action properly", async () => {
|
||||
await Promise.resolve(store.dispatch(createIdentityRequest()));
|
||||
await Promise.resolve(store.dispatch(createIdentityRequest({ host: "http://localhost:3000" })));
|
||||
|
||||
expect(postMessage).toBeCalledTimes(1);
|
||||
expect(postMessage).toBeCalledWith({ method: RPCAction.CREATE_IDENTITY_REQ });
|
||||
expect(postMessage).toBeCalledWith({
|
||||
method: RPCAction.CREATE_IDENTITY_REQ,
|
||||
payload: { host: "http://localhost:3000" },
|
||||
});
|
||||
});
|
||||
|
||||
test("should call create identity action properly", async () => {
|
||||
@@ -238,13 +243,11 @@ describe("ui/ducks/identities", () => {
|
||||
});
|
||||
|
||||
test("should call set connected identity action properly", async () => {
|
||||
await Promise.resolve(
|
||||
store.dispatch(setConnectedIdentity({ identityCommitment: "1", host: "http://localhost:3000" })),
|
||||
);
|
||||
await Promise.resolve(store.dispatch(connectIdentity({ identityCommitment: "1", host: "http://localhost:3000" })));
|
||||
|
||||
expect(postMessage).toBeCalledTimes(1);
|
||||
expect(postMessage).toBeCalledWith({
|
||||
method: RPCAction.SET_CONNECTED_IDENTITY,
|
||||
method: RPCAction.CONNECT_IDENTITY,
|
||||
payload: {
|
||||
identityCommitment: "1",
|
||||
host: "http://localhost:3000",
|
||||
|
||||
@@ -8,8 +8,9 @@ import {
|
||||
ICreateIdentityUiArgs,
|
||||
IdentityData,
|
||||
Operation,
|
||||
SelectedIdentity,
|
||||
SetConnectedIdentityArgs,
|
||||
ConnectedIdentity,
|
||||
ConnectIdentityArgs,
|
||||
ICreateIdentityRequestArgs,
|
||||
} from "@src/types";
|
||||
import postMessage from "@src/util/postMessage";
|
||||
|
||||
@@ -21,7 +22,7 @@ export interface IdentitiesState {
|
||||
identities: IdentityData[];
|
||||
operations: Operation[];
|
||||
requestPending: boolean;
|
||||
selected: SelectedIdentity; // This aim to be a short-term solution to the integration with Zkitter
|
||||
connected: ConnectedIdentity; // This aim to be a short-term solution to the integration with Zkitter
|
||||
settings?: HistorySettings;
|
||||
}
|
||||
|
||||
@@ -30,9 +31,10 @@ const initialState: IdentitiesState = {
|
||||
operations: [],
|
||||
settings: undefined,
|
||||
requestPending: false,
|
||||
selected: {
|
||||
connected: {
|
||||
commitment: "",
|
||||
web2Provider: "",
|
||||
host: "",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -40,10 +42,11 @@ const identitiesSlice = createSlice({
|
||||
name: "identities",
|
||||
initialState,
|
||||
reducers: {
|
||||
setSelectedCommitment: (state: IdentitiesState, action: PayloadAction<SelectedIdentity>) => {
|
||||
state.selected = {
|
||||
setConnectedIdentity: (state: IdentitiesState, action: PayloadAction<ConnectedIdentity>) => {
|
||||
state.connected = {
|
||||
commitment: action.payload.commitment,
|
||||
web2Provider: action.payload.web2Provider,
|
||||
host: action.payload.host,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -65,12 +68,19 @@ const identitiesSlice = createSlice({
|
||||
},
|
||||
});
|
||||
|
||||
export const { setSelectedCommitment, setIdentities, setIdentityRequestPending, setOperations, setSettings } =
|
||||
export const { setConnectedIdentity, setIdentities, setIdentityRequestPending, setOperations, setSettings } =
|
||||
identitiesSlice.actions;
|
||||
|
||||
export const createIdentityRequest = () => async (): Promise<void> => {
|
||||
await postMessage({ method: RPCAction.CREATE_IDENTITY_REQ });
|
||||
};
|
||||
export const createIdentityRequest =
|
||||
({ host }: ICreateIdentityRequestArgs) =>
|
||||
async (): Promise<void> => {
|
||||
await postMessage({
|
||||
method: RPCAction.CREATE_IDENTITY_REQ,
|
||||
payload: {
|
||||
host,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const createIdentity =
|
||||
({ walletType, strategy, messageSignature, groups, host, options }: ICreateIdentityUiArgs) =>
|
||||
@@ -87,11 +97,11 @@ export const createIdentity =
|
||||
},
|
||||
});
|
||||
|
||||
export const setConnectedIdentity =
|
||||
({ identityCommitment, host }: SetConnectedIdentityArgs) =>
|
||||
export const connectIdentity =
|
||||
({ identityCommitment, host }: ConnectIdentityArgs) =>
|
||||
async (): Promise<boolean> =>
|
||||
postMessage({
|
||||
method: RPCAction.SET_CONNECTED_IDENTITY,
|
||||
method: RPCAction.CONNECT_IDENTITY,
|
||||
payload: {
|
||||
identityCommitment,
|
||||
host,
|
||||
@@ -122,14 +132,15 @@ export const deleteAllIdentities = () => async (): Promise<boolean> =>
|
||||
|
||||
export const fetchIdentities = (): TypedThunk => async (dispatch) => {
|
||||
const data = await postMessage<IdentityData[]>({ method: RPCAction.GET_IDENTITIES });
|
||||
const { commitment, web2Provider } = await postMessage<SelectedIdentity>({
|
||||
const { commitment, web2Provider, host } = await postMessage<ConnectedIdentity>({
|
||||
method: RPCAction.GET_CONNECTED_IDENTITY_DATA,
|
||||
});
|
||||
dispatch(setIdentities(data));
|
||||
dispatch(
|
||||
setSelectedCommitment({
|
||||
setConnectedIdentity({
|
||||
commitment,
|
||||
web2Provider,
|
||||
host,
|
||||
}),
|
||||
);
|
||||
};
|
||||
@@ -177,10 +188,10 @@ export const useLinkedIdentities = (host: string): IdentityData[] =>
|
||||
export const useUnlinkedIdentities = (): IdentityData[] =>
|
||||
useAppSelector((state) => state.identities.identities.filter((identity) => !identity.metadata.host), deepEqual);
|
||||
|
||||
export const useSelectedIdentity = (): IdentityData | undefined =>
|
||||
export const useConnectedIdentity = (): IdentityData | undefined =>
|
||||
useAppSelector((state) => {
|
||||
const { identities, selected } = state.identities;
|
||||
return identities.find(({ commitment }) => commitment === selected.commitment);
|
||||
const { identities, connected } = state.identities;
|
||||
return identities.find(({ commitment }) => commitment === connected.commitment);
|
||||
}, deepEqual);
|
||||
|
||||
export const useIdentityRequestPending = (): boolean =>
|
||||
|
||||
@@ -10,12 +10,7 @@ import { useNavigate } from "react-router-dom";
|
||||
import { ZERO_ADDRESS } from "@src/config/const";
|
||||
import { closePopup } from "@src/ui/ducks/app";
|
||||
import { useAppDispatch } from "@src/ui/ducks/hooks";
|
||||
import {
|
||||
fetchIdentities,
|
||||
setConnectedIdentity,
|
||||
useLinkedIdentities,
|
||||
useUnlinkedIdentities,
|
||||
} from "@src/ui/ducks/identities";
|
||||
import { connectIdentity, fetchIdentities, useLinkedIdentities, useUnlinkedIdentities } from "@src/ui/ducks/identities";
|
||||
|
||||
import { EConnectIdentityTabs, IUseConnectIdentityData, useConnectIdentity } from "../useConnectIdentity";
|
||||
|
||||
@@ -39,7 +34,7 @@ jest.mock("@src/ui/ducks/app", (): unknown => ({
|
||||
|
||||
jest.mock("@src/ui/ducks/identities", (): unknown => ({
|
||||
fetchIdentities: jest.fn(),
|
||||
setConnectedIdentity: jest.fn(),
|
||||
connectIdentity: jest.fn(),
|
||||
useLinkedIdentities: jest.fn(),
|
||||
useUnlinkedIdentities: jest.fn(),
|
||||
}));
|
||||
@@ -147,8 +142,8 @@ describe("ui/pages/ConnectIdentity/useConnectIdentity", () => {
|
||||
|
||||
expect(mockDispatch).toBeCalledTimes(3);
|
||||
expect(fetchIdentities).toBeCalledTimes(1);
|
||||
expect(setConnectedIdentity).toBeCalledTimes(1);
|
||||
expect(setConnectedIdentity).toBeCalledWith({ identityCommitment: "1", host: "http://localhost:3000" });
|
||||
expect(connectIdentity).toBeCalledTimes(1);
|
||||
expect(connectIdentity).toBeCalledWith({ identityCommitment: "1", host: "http://localhost:3000" });
|
||||
expect(closePopup).toBeCalledTimes(1);
|
||||
expect(mockNavigate).toBeCalledTimes(1);
|
||||
expect(mockNavigate).toBeCalledWith(-1);
|
||||
|
||||
@@ -4,12 +4,7 @@ import { useNavigate } from "react-router-dom";
|
||||
|
||||
import { closePopup } from "@src/ui/ducks/app";
|
||||
import { useAppDispatch } from "@src/ui/ducks/hooks";
|
||||
import {
|
||||
fetchIdentities,
|
||||
setConnectedIdentity,
|
||||
useLinkedIdentities,
|
||||
useUnlinkedIdentities,
|
||||
} from "@src/ui/ducks/identities";
|
||||
import { connectIdentity, fetchIdentities, useLinkedIdentities, useUnlinkedIdentities } from "@src/ui/ducks/identities";
|
||||
|
||||
import type { IdentityData } from "@src/types";
|
||||
|
||||
@@ -63,7 +58,7 @@ export const useConnectIdentity = (): IUseConnectIdentityData => {
|
||||
}, [dispatch, navigate]);
|
||||
|
||||
const onConnect = useCallback(async () => {
|
||||
await dispatch(setConnectedIdentity({ identityCommitment: selectedIdentityCommitment as string, host }));
|
||||
await dispatch(connectIdentity({ identityCommitment: selectedIdentityCommitment as string, host }));
|
||||
await dispatch(closePopup()).then(() => navigate(-1));
|
||||
}, [selectedIdentityCommitment, host, dispatch]);
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import "./home.scss";
|
||||
import { useHome } from "./useHome";
|
||||
|
||||
const Home = (): JSX.Element => {
|
||||
const { identities, selectedIdentity, refreshConnectionStatus, onSelectIdentity } = useHome();
|
||||
const { identities, connectedIdentity, refreshConnectionStatus, onSelectIdentity } = useHome();
|
||||
|
||||
return (
|
||||
<div className="w-full h-full flex flex-col home" data-testid="home-page">
|
||||
@@ -22,7 +22,7 @@ const Home = (): JSX.Element => {
|
||||
isShowAddNew
|
||||
isShowMenu
|
||||
identities={identities}
|
||||
selectedCommitment={selectedIdentity?.commitment}
|
||||
selectedCommitment={connectedIdentity?.commitment}
|
||||
onSelect={onSelectIdentity}
|
||||
/>
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ import {
|
||||
useIdentities,
|
||||
fetchIdentities,
|
||||
fetchHistory,
|
||||
useSelectedIdentity,
|
||||
setConnectedIdentity,
|
||||
useConnectedIdentity,
|
||||
connectIdentity,
|
||||
} from "@src/ui/ducks/identities";
|
||||
import { checkHostApproval } from "@src/ui/ducks/permissions";
|
||||
import { useEthWallet } from "@src/ui/hooks/wallet";
|
||||
@@ -38,8 +38,8 @@ jest.mock("@src/ui/ducks/identities", (): unknown => ({
|
||||
fetchIdentities: jest.fn(),
|
||||
fetchHistory: jest.fn(),
|
||||
useIdentities: jest.fn(),
|
||||
useSelectedIdentity: jest.fn(),
|
||||
setConnectedIdentity: jest.fn(),
|
||||
useConnectedIdentity: jest.fn(),
|
||||
connectIdentity: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock("@src/ui/ducks/permissions", (): unknown => ({
|
||||
@@ -90,7 +90,7 @@ describe("ui/pages/Home/useHome", () => {
|
||||
|
||||
(useIdentities as jest.Mock).mockReturnValue(defaultIdentities);
|
||||
|
||||
(useSelectedIdentity as jest.Mock).mockReturnValue(defaultIdentities[0]);
|
||||
(useConnectedIdentity as jest.Mock).mockReturnValue(defaultIdentities[0]);
|
||||
|
||||
(checkHostApproval as jest.Mock).mockReturnValue(true);
|
||||
});
|
||||
@@ -133,7 +133,7 @@ describe("ui/pages/Home/useHome", () => {
|
||||
|
||||
await act(async () => Promise.resolve(result.current.onSelectIdentity("1")));
|
||||
|
||||
expect(setConnectedIdentity).toBeCalledTimes(1);
|
||||
expect(setConnectedIdentity).toBeCalledWith({ identityCommitment: "1", host: "" });
|
||||
expect(connectIdentity).toBeCalledTimes(1);
|
||||
expect(connectIdentity).toBeCalledWith({ identityCommitment: "1", host: "http://localhost:3000" });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,11 +2,11 @@ import { useEffect, useCallback } from "react";
|
||||
|
||||
import { useAppDispatch } from "@src/ui/ducks/hooks";
|
||||
import {
|
||||
connectIdentity,
|
||||
fetchHistory,
|
||||
fetchIdentities,
|
||||
setConnectedIdentity,
|
||||
useIdentities,
|
||||
useSelectedIdentity,
|
||||
useConnectedIdentity,
|
||||
} from "@src/ui/ducks/identities";
|
||||
import { checkHostApproval } from "@src/ui/ducks/permissions";
|
||||
import { useEthWallet } from "@src/ui/hooks/wallet";
|
||||
@@ -16,7 +16,7 @@ import type { IdentityData } from "@src/types";
|
||||
|
||||
export interface IUseHomeData {
|
||||
identities: IdentityData[];
|
||||
selectedIdentity?: IdentityData;
|
||||
connectedIdentity?: IdentityData;
|
||||
address?: string;
|
||||
refreshConnectionStatus: () => Promise<boolean>;
|
||||
onSelectIdentity: (identityCommitment: string) => void;
|
||||
@@ -25,7 +25,7 @@ export interface IUseHomeData {
|
||||
export const useHome = (): IUseHomeData => {
|
||||
const dispatch = useAppDispatch();
|
||||
const identities = useIdentities();
|
||||
const selectedIdentity = useSelectedIdentity();
|
||||
const connectedIdentity = useConnectedIdentity();
|
||||
|
||||
const { address } = useEthWallet();
|
||||
|
||||
@@ -41,9 +41,16 @@ export const useHome = (): IUseHomeData => {
|
||||
|
||||
const onSelectIdentity = useCallback(
|
||||
(identityCommitment: string) => {
|
||||
dispatch(setConnectedIdentity({ identityCommitment, host: "" }));
|
||||
const identity = identities.find(({ commitment }) => commitment === identityCommitment);
|
||||
|
||||
dispatch(
|
||||
connectIdentity({
|
||||
identityCommitment,
|
||||
host: identity?.metadata.host as string,
|
||||
}),
|
||||
);
|
||||
},
|
||||
[dispatch],
|
||||
[identities, dispatch],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -53,7 +60,7 @@ export const useHome = (): IUseHomeData => {
|
||||
|
||||
return {
|
||||
address,
|
||||
selectedIdentity,
|
||||
connectedIdentity,
|
||||
identities,
|
||||
refreshConnectionStatus,
|
||||
onSelectIdentity,
|
||||
|
||||
@@ -81,6 +81,8 @@ describe("ui/pages/Popup/usePopup", () => {
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
|
||||
window.location.href = oldHref;
|
||||
});
|
||||
|
||||
test("should return initial data", async () => {
|
||||
@@ -149,16 +151,14 @@ describe("ui/pages/Popup/usePopup", () => {
|
||||
test("should redirect to create identity page", async () => {
|
||||
(useAppStatus as jest.Mock).mockReturnValue({ isInitialized: true, isUnlocked: true, isMnemonicGenerated: true });
|
||||
|
||||
const url = `${window.location.href}?redirect=${Paths.CREATE_IDENTITY}`;
|
||||
const url = `${window.location.href}?redirect=${Paths.CREATE_IDENTITY}&host=http://localhost:3000`;
|
||||
window.location.href = url;
|
||||
|
||||
const { result } = renderHook(() => usePopup());
|
||||
await waitForData(result.current);
|
||||
|
||||
expect(mockNavigate).toBeCalledTimes(1);
|
||||
expect(mockNavigate).toBeCalledWith(Paths.CREATE_IDENTITY);
|
||||
|
||||
window.location.href = oldHref;
|
||||
expect(mockNavigate).toBeCalledWith(`${Paths.CREATE_IDENTITY}?host=${encodeURIComponent("http://localhost:3000")}`);
|
||||
});
|
||||
|
||||
test("should redirect to login page", async () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import log from "loglevel";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
import { Paths } from "@src/constants";
|
||||
@@ -27,9 +27,9 @@ export const usePopup = (): IUsePopupData => {
|
||||
const { isInitialized, isUnlocked, isMnemonicGenerated } = useAppStatus();
|
||||
const isShowRequestModal = pendingRequests.length > 0;
|
||||
|
||||
const url = new URL(window.location.href);
|
||||
const url = new URL(window.location.href.replace("#", ""));
|
||||
const redirectParam = url.searchParams.get("redirect");
|
||||
const redirect = useMemo(() => redirectParam && REDIRECT_PATHS[redirectParam], [redirectParam, window.location.href]);
|
||||
const redirect = redirectParam && REDIRECT_PATHS[redirectParam];
|
||||
|
||||
const fetchData = useCallback(async () => {
|
||||
await Promise.all([dispatch(fetchStatus()), dispatch(fetchPendingRequests())]);
|
||||
@@ -53,9 +53,19 @@ export const usePopup = (): IUsePopupData => {
|
||||
} else if (isShowRequestModal) {
|
||||
navigate(Paths.REQUESTS);
|
||||
} else if (redirect) {
|
||||
navigate(redirect);
|
||||
url.searchParams.delete("redirect");
|
||||
navigate(`${redirect}?${url.searchParams.toString()}`);
|
||||
}
|
||||
}, [isLoading, isInitialized, isUnlocked, isShowRequestModal, isMnemonicGenerated, redirect, navigate]);
|
||||
}, [
|
||||
isLoading,
|
||||
isInitialized,
|
||||
isUnlocked,
|
||||
isShowRequestModal,
|
||||
isMnemonicGenerated,
|
||||
redirect,
|
||||
url.searchParams.toString(),
|
||||
navigate,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
setIsLoading(true);
|
||||
|
||||
@@ -42,9 +42,17 @@ module.exports = {
|
||||
patterns: [
|
||||
{ from: path.resolve(__dirname, "./src/static/icons"), to: path.resolve(__dirname, "./dist/[name][ext]") },
|
||||
{
|
||||
from: path.resolve(__dirname, `./src/manifest.${TARGET}.json`),
|
||||
from: path.resolve(__dirname, `./manifest.${TARGET}.json`),
|
||||
to: path.resolve(__dirname, "./dist/manifest.json"),
|
||||
},
|
||||
{
|
||||
from: path.resolve(__dirname, `./privacy_policy.md`),
|
||||
to: path.resolve(__dirname, "./dist/privacy_policy.md"),
|
||||
},
|
||||
{
|
||||
from: path.resolve(__dirname, `./LICENSE`),
|
||||
to: path.resolve(__dirname, "./dist/LICENSE"),
|
||||
},
|
||||
{ from: path.resolve(__dirname, "./zkeyFiles"), to: path.resolve(__dirname, "./dist/js/zkeyFiles") },
|
||||
],
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user