Add password to identity (#94)
This commit is contained in:
parent
1f71792d56
commit
093b6ca7be
|
@ -1,4 +1,5 @@
|
|||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import { Identity } from "status-communities/dist/cjs";
|
||||
import styled from "styled-components";
|
||||
|
||||
import { useNarrow } from "../contexts/narrowProvider";
|
||||
|
@ -19,9 +20,15 @@ interface ChatProps {
|
|||
theme: Theme;
|
||||
communityKey: string;
|
||||
fetchMetadata?: (url: string) => Promise<Metadata | undefined>;
|
||||
identity: Identity;
|
||||
}
|
||||
|
||||
export function Chat({ theme, communityKey, fetchMetadata }: ChatProps) {
|
||||
export function Chat({
|
||||
theme,
|
||||
communityKey,
|
||||
fetchMetadata,
|
||||
identity,
|
||||
}: ChatProps) {
|
||||
const [activeChannel, setActiveChannel] = useState<ChannelData>({
|
||||
id: "",
|
||||
name: "",
|
||||
|
@ -40,14 +47,13 @@ export function Chat({ theme, communityKey, fetchMetadata }: ChatProps) {
|
|||
loadPrevDay,
|
||||
loadingMessages,
|
||||
community,
|
||||
} = useMessenger(activeChannel?.id ?? "", communityKey);
|
||||
} = useMessenger(activeChannel?.id ?? "", communityKey, identity);
|
||||
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
const showModal = () => setIsModalVisible(true);
|
||||
|
||||
const communityData = useMemo(() => {
|
||||
if (community?.description) {
|
||||
console.log(Object.keys(community.description.proto.members));
|
||||
return {
|
||||
id: 1,
|
||||
name: community.description.identity?.displayName ?? "",
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
import React, { useState } from "react";
|
||||
import { Identity } from "status-communities/dist/cjs";
|
||||
|
||||
import { Metadata } from "../models/Metadata";
|
||||
import { Theme } from "../styles/themes";
|
||||
|
||||
import { Chat } from "./Chat";
|
||||
import { IdentityLoader } from "./Form/IdentityLoader";
|
||||
|
||||
interface ChatLoaderProps {
|
||||
theme: Theme;
|
||||
communityKey: string;
|
||||
fetchMetadata?: (url: string) => Promise<Metadata | undefined>;
|
||||
}
|
||||
|
||||
export function ChatLoader({
|
||||
theme,
|
||||
communityKey,
|
||||
fetchMetadata,
|
||||
}: ChatLoaderProps) {
|
||||
const [identity, setIdentity] = useState<Identity | undefined>(undefined);
|
||||
|
||||
if (identity) {
|
||||
return (
|
||||
<Chat
|
||||
communityKey={communityKey}
|
||||
fetchMetadata={fetchMetadata}
|
||||
theme={theme}
|
||||
identity={identity}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return <IdentityLoader setIdentity={setIdentity} />;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { Identity } from "status-communities/dist/cjs";
|
||||
import styled from "styled-components";
|
||||
|
||||
import {
|
||||
decryptIdentity,
|
||||
loadEncryptedIdentity,
|
||||
saveIdentity,
|
||||
} from "../../utils";
|
||||
|
||||
interface IdentityLoaderProps {
|
||||
setIdentity: (e: Identity) => void;
|
||||
}
|
||||
|
||||
export function IdentityLoader({ setIdentity }: IdentityLoaderProps) {
|
||||
const [password, setPassword] = useState("");
|
||||
// Test password for now
|
||||
// Need design for password input
|
||||
const [encryptedIdentity, setEncryptedIdentity] = useState(
|
||||
loadEncryptedIdentity() ?? ""
|
||||
);
|
||||
const [identityInMemory, setIdentityInMemory] = useState(false);
|
||||
const [wrongPassword, setWrongPassword] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (encryptedIdentity) {
|
||||
setIdentityInMemory(true);
|
||||
}
|
||||
setWrongPassword(false);
|
||||
}, [encryptedIdentity]);
|
||||
|
||||
const loadIdentity = useCallback(async () => {
|
||||
const identity = await decryptIdentity(encryptedIdentity, password);
|
||||
if (!identity) {
|
||||
setWrongPassword(true);
|
||||
} else {
|
||||
setIdentity(identity);
|
||||
}
|
||||
}, [encryptedIdentity, password]);
|
||||
|
||||
const createIdentity = useCallback(async () => {
|
||||
const identity = Identity.generate();
|
||||
await saveIdentity(identity, password);
|
||||
setIdentity(identity);
|
||||
}, [encryptedIdentity, password]);
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
{encryptedIdentity ? (
|
||||
<FormWrappers>
|
||||
<InfoDiv>Please provide password for your identity</InfoDiv>
|
||||
{wrongPassword && <div>Wrong password</div>}
|
||||
<Input
|
||||
value={password}
|
||||
type={"password"}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
onKeyPress={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
loadIdentity();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Button onClick={loadIdentity}>LOAD</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setEncryptedIdentity("");
|
||||
}}
|
||||
>
|
||||
Create new identity
|
||||
</Button>
|
||||
</FormWrappers>
|
||||
) : (
|
||||
<FormWrappers>
|
||||
<InfoDiv>Please provide password for your identity</InfoDiv>
|
||||
<Input
|
||||
value={password}
|
||||
type={"password"}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
onKeyPress={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
createIdentity();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Button onClick={createIdentity}>Create</Button>
|
||||
{identityInMemory && (
|
||||
<Button
|
||||
onClick={() =>
|
||||
setEncryptedIdentity(loadEncryptedIdentity() ?? "")
|
||||
}
|
||||
>
|
||||
Go back
|
||||
</Button>
|
||||
)}
|
||||
</FormWrappers>
|
||||
)}
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
|
||||
const Input = styled.input`
|
||||
border-radius: 5px;
|
||||
padding: 5px;
|
||||
margin: 5px;
|
||||
`;
|
||||
|
||||
const Button = styled.button`
|
||||
padding: 5px;
|
||||
margin: 5px;
|
||||
|
||||
box-shadow: 5px 5px 10px -4px rgba(197, 197, 255, 1);
|
||||
border-radius: 5px;
|
||||
background-color: ${({ theme }) => theme.buttonBg};
|
||||
`;
|
||||
|
||||
const Wrapper = styled.div`
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
`;
|
||||
|
||||
const FormWrappers = styled.div`
|
||||
margin: auto;
|
||||
`;
|
||||
|
||||
const InfoDiv = styled.div`
|
||||
margin: 5px;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
`;
|
|
@ -7,7 +7,7 @@ import { Metadata } from "../models/Metadata";
|
|||
import { GlobalStyle } from "../styles/GlobalStyle";
|
||||
import { Theme } from "../styles/themes";
|
||||
|
||||
import { Chat } from "./Chat";
|
||||
import { ChatLoader } from "./ChatLoader";
|
||||
|
||||
interface ReactChatProps {
|
||||
theme: Theme;
|
||||
|
@ -26,7 +26,7 @@ export function ReactChat({
|
|||
<NarrowProvider myRef={ref}>
|
||||
<Wrapper ref={ref}>
|
||||
<GlobalStyle />
|
||||
<Chat
|
||||
<ChatLoader
|
||||
communityKey={communityKey}
|
||||
fetchMetadata={fetchMetadata}
|
||||
theme={theme}
|
||||
|
|
|
@ -28,7 +28,6 @@ export function useMessages(chatId: string) {
|
|||
),
|
||||
};
|
||||
});
|
||||
console.log(`increase noti ${id}`);
|
||||
incNotification(id);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
// import { StoreCodec } from "js-waku";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { Community, Messenger } from "status-communities/dist/cjs";
|
||||
import { Community, Identity, Messenger } from "status-communities/dist/cjs";
|
||||
|
||||
import { createCommunityMessenger } from "../../utils/createCommunityMessenger";
|
||||
|
||||
import { useLoadPrevDay } from "./useLoadPrevDay";
|
||||
import { useMessages } from "./useMessages";
|
||||
|
||||
export function useMessenger(chatId: string, communityKey: string) {
|
||||
export function useMessenger(
|
||||
chatId: string,
|
||||
communityKey: string,
|
||||
identity: Identity
|
||||
) {
|
||||
const [messenger, setMessenger] = useState<Messenger | undefined>(undefined);
|
||||
const { addMessage, clearNotifications, notifications, messages } =
|
||||
useMessages(chatId);
|
||||
|
@ -15,10 +19,12 @@ export function useMessenger(chatId: string, communityKey: string) {
|
|||
const { loadPrevDay, loadingMessages } = useLoadPrevDay(chatId, messenger);
|
||||
|
||||
useEffect(() => {
|
||||
createCommunityMessenger(communityKey, addMessage).then((result) => {
|
||||
setCommunity(result.community);
|
||||
setMessenger(result.messenger);
|
||||
});
|
||||
createCommunityMessenger(communityKey, addMessage, identity).then(
|
||||
(result) => {
|
||||
setCommunity(result.community);
|
||||
setMessenger(result.messenger);
|
||||
}
|
||||
);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
@ -2,8 +2,6 @@ import { StoreCodec } from "js-waku";
|
|||
import { Community, Identity, Messenger } from "status-communities/dist/cjs";
|
||||
import { ApplicationMetadataMessage } from "status-communities/dist/cjs";
|
||||
|
||||
import { loadIdentity, saveIdentity } from "./";
|
||||
|
||||
const WAKU_OPTIONS = {
|
||||
libp2p: {
|
||||
config: {
|
||||
|
@ -17,15 +15,9 @@ const WAKU_OPTIONS = {
|
|||
|
||||
export async function createCommunityMessenger(
|
||||
communityKey: string,
|
||||
addMessage: (msg: ApplicationMetadataMessage, id: string, date: Date) => void
|
||||
addMessage: (msg: ApplicationMetadataMessage, id: string, date: Date) => void,
|
||||
identity: Identity
|
||||
) {
|
||||
// Test password for now
|
||||
// Need design for password input
|
||||
let identity = await loadIdentity("test");
|
||||
if (!identity) {
|
||||
identity = Identity.generate();
|
||||
await saveIdentity(identity, "test");
|
||||
}
|
||||
const messenger = await Messenger.create(identity, WAKU_OPTIONS);
|
||||
await new Promise((resolve) => {
|
||||
messenger.waku.libp2p.peerStore.on("change:protocols", ({ protocols }) => {
|
||||
|
|
|
@ -24,18 +24,8 @@ export async function saveIdentity(identity: Identity, password: string) {
|
|||
localStorage.setItem("cipherIdentity", JSON.stringify(data));
|
||||
}
|
||||
|
||||
export async function loadIdentity(
|
||||
password: string
|
||||
): Promise<Identity | undefined> {
|
||||
const str = localStorage.getItem("cipherIdentity");
|
||||
if (!str) return;
|
||||
const data = JSON.parse(str);
|
||||
|
||||
const salt = hexToBuf(data.salt);
|
||||
const iv = hexToBuf(data.iv);
|
||||
const cipher = hexToBuf(data.cipher);
|
||||
|
||||
return await decryptIdentity(salt, iv, cipher, password);
|
||||
export function loadEncryptedIdentity(): string | null {
|
||||
return localStorage.getItem("cipherIdentity");
|
||||
}
|
||||
|
||||
async function getWrapKey(password: string, salt: Uint8Array) {
|
||||
|
@ -61,12 +51,16 @@ async function getWrapKey(password: string, salt: Uint8Array) {
|
|||
);
|
||||
}
|
||||
|
||||
async function decryptIdentity(
|
||||
salt: Buffer,
|
||||
iv: Buffer,
|
||||
cipherKeyPair: Buffer,
|
||||
export async function decryptIdentity(
|
||||
encryptedIdentity: string,
|
||||
password: string
|
||||
): Promise<Identity | undefined> {
|
||||
const data = JSON.parse(encryptedIdentity);
|
||||
|
||||
const salt = hexToBuf(data.salt);
|
||||
const iv = hexToBuf(data.iv);
|
||||
const cipherKeyPair = hexToBuf(data.cipher);
|
||||
|
||||
const key = await getWrapKey(password, salt);
|
||||
|
||||
try {
|
||||
|
|
|
@ -2,6 +2,10 @@ export { binarySetInsert } from "./binarySetInsert";
|
|||
export { copy } from "./copy";
|
||||
export { copyImg } from "./copyImg";
|
||||
export { downloadImg } from "./downloadImg";
|
||||
export { saveIdentity, loadIdentity } from "./identityStorage";
|
||||
export {
|
||||
saveIdentity,
|
||||
loadEncryptedIdentity,
|
||||
decryptIdentity,
|
||||
} from "./identityStorage";
|
||||
export { reduceString } from "./reduceString";
|
||||
export { uintToImgUrl } from "./uintToImgUrl";
|
||||
|
|
Loading…
Reference in New Issue