Add password to identity (#94)

This commit is contained in:
Szymon Szlachtowicz 2021-10-22 14:27:26 +02:00 committed by GitHub
parent 1f71792d56
commit 093b6ca7be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 205 additions and 39 deletions

View File

@ -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 ?? "",

View File

@ -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} />;
}
}

View File

@ -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;
`;

View File

@ -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}

View File

@ -28,7 +28,6 @@ export function useMessages(chatId: string) {
),
};
});
console.log(`increase noti ${id}`);
incNotification(id);
}
},

View File

@ -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(() => {

View File

@ -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 }) => {

View File

@ -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 {

View File

@ -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";