JournalMembers: change to be a function component.

master
Tom Hacohen 4 years ago
parent 6e4689f697
commit 6d18d494a7

@ -12,9 +12,8 @@ import ConfirmationDialog from "../widgets/ConfirmationDialog";
import PrettyFingerprint from "../widgets/PrettyFingerprint";
import * as EteSync from "etesync";
import { CredentialsData } from "../store";
import { handleInputChange } from "../helpers";
import { CredentialsData } from "../store";
interface PropsType {
etesync: CredentialsData;
@ -23,28 +22,33 @@ interface PropsType {
onClose: () => void;
}
class JournalMemberAddDialog extends React.PureComponent<PropsType> {
public state = {
addUser: "",
publicKey: "",
readOnly: false,
userChosen: false,
error: undefined as Error | undefined,
};
export default function JournalMemberAddDialog(props: PropsType) {
const [addUser, setAddUser] = React.useState("");
const [publicKey, setPublicKey] = React.useState("");
const [readOnly, setReadOnly] = React.useState(false);
const [userChosen, setUserChosen] = React.useState(false);
const [error, setError] = React.useState<Error>();
private handleInputChange: any;
function onAddRequest(_user: string) {
setUserChosen(true);
constructor(props: PropsType) {
super(props);
const { etesync } = props;
this.handleInputChange = handleInputChange(this);
this.onAddRequest = this.onAddRequest.bind(this);
this.onOk = this.onOk.bind(this);
const creds = etesync.credentials;
const apiBase = etesync.serviceApiUrl;
const userInfoManager = new EteSync.UserInfoManager(creds, apiBase);
userInfoManager.fetch(addUser).then((userInfo) => {
setPublicKey(userInfo.publicKey);
}).catch((error) => {
setError(error);
});
}
function onOk() {
props.onOk(addUser, publicKey, readOnly);
}
public render() {
const { onClose } = this.props;
const { addUser, userChosen, publicKey, error } = this.state;
const { onClose } = props;
if (error) {
return (
@ -69,7 +73,7 @@ class JournalMemberAddDialog extends React.PureComponent<PropsType> {
title="Verify security fingerprint"
labelOk="OK"
open
onOk={this.onOk}
onOk={onOk}
onCancel={onClose}
>
<p>
@ -88,7 +92,7 @@ class JournalMemberAddDialog extends React.PureComponent<PropsType> {
title="Add member"
labelOk="OK"
open={!userChosen}
onOk={this.onAddRequest}
onOk={onAddRequest}
onCancel={onClose}
>
{userChosen ?
@ -101,13 +105,13 @@ class JournalMemberAddDialog extends React.PureComponent<PropsType> {
placeholder="User email"
style={{ width: "100%" }}
value={addUser}
onChange={this.handleInputChange}
onChange={(ev) => setAddUser(ev.target.value)}
/>
<FormControlLabel
control={
<Checkbox
checked={this.state.readOnly}
onChange={(event) => this.setState({ readOnly: event.target.checked })}
checked={readOnly}
onChange={(event) => setReadOnly(event.target.checked)}
/>
}
label="Read only?"
@ -119,31 +123,3 @@ class JournalMemberAddDialog extends React.PureComponent<PropsType> {
);
}
}
private onAddRequest(_user: string) {
this.setState({
userChosen: true,
});
const { etesync } = this.props;
const { addUser } = this.state;
const creds = etesync.credentials;
const apiBase = etesync.serviceApiUrl;
const userInfoManager = new EteSync.UserInfoManager(creds, apiBase);
userInfoManager.fetch(addUser).then((userInfo) => {
this.setState({
publicKey: userInfo.publicKey,
});
}).catch((error) => {
this.setState({ error });
});
}
private onOk() {
const { addUser, publicKey, readOnly } = this.state;
this.props.onOk(addUser, publicKey, readOnly);
}
}
export default JournalMemberAddDialog;

@ -6,7 +6,6 @@ import sjcl from "sjcl";
import { List, ListItem } from "../widgets/List";
import { Theme, withTheme } from "@material-ui/core/styles";
import IconMemberAdd from "@material-ui/icons/PersonAdd";
import VisibilityIcon from "@material-ui/icons/Visibility";
@ -28,28 +27,65 @@ interface PropsType {
userInfo: UserInfoData;
}
interface PropsTypeInner extends PropsType {
theme: Theme;
export default function JournalMembers(props: PropsType) {
const [members, setMembers] = React.useState<EteSync.JournalMemberJson[] | null>(null);
const [revokeUser, setRevokeUser] = React.useState<string | null>(null);
const [addMemberOpen, setAddMemberOpen] = React.useState(false);
function fetchMembers() {
const { etesync, syncJournal } = props;
const info = syncJournal.collection;
const creds = etesync.credentials;
const apiBase = etesync.serviceApiUrl;
const journalMembersManager = new EteSync.JournalMembersManager(creds, apiBase, info.uid);
journalMembersManager.list().then((members) => {
setMembers(members);
});
}
class JournalMembers extends React.PureComponent<PropsTypeInner> {
public state = {
members: null as EteSync.JournalMemberJson[] | null,
revokeUser: null as string | null,
addMemberOpen: false,
};
React.useEffect(() => {
fetchMembers();
}, []);
constructor(props: PropsTypeInner) {
super(props);
function onRevokeRequest(user: string) {
setRevokeUser(user);
}
this.onRevokeRequest = this.onRevokeRequest.bind(this);
this.onRevokeDo = this.onRevokeDo.bind(this);
this.onMemberAdd = this.onMemberAdd.bind(this);
function onRevokeDo() {
const { etesync, syncJournal } = props;
const info = syncJournal.collection;
const creds = etesync.credentials;
const apiBase = etesync.serviceApiUrl;
const journalMembersManager = new EteSync.JournalMembersManager(creds, apiBase, info.uid);
journalMembersManager.delete({ user: revokeUser!, key: "" }).then(() => {
fetchMembers();
});
setRevokeUser(null);
}
public render() {
const { syncJournal } = this.props;
const { members, revokeUser, addMemberOpen } = this.state;
function onMemberAdd(user: string, publicKey: string, readOnly: boolean) {
const { etesync, syncJournal, userInfo } = props;
const journal = syncJournal.journal;
const derived = props.etesync.encryptionKey;
const keyPair = userInfo.getKeyPair(userInfo.getCryptoManager(derived));
const cryptoManager = journal.getCryptoManager(derived, keyPair);
const pubkeyBytes = sjcl.codec.bytes.fromBits(sjcl.codec.base64.toBits(publicKey));
const encryptedKey = sjcl.codec.base64.fromBits(sjcl.codec.bytes.toBits(cryptoManager.getEncryptedKey(keyPair, pubkeyBytes)));
const creds = etesync.credentials;
const apiBase = etesync.serviceApiUrl;
const journalMembersManager = new EteSync.JournalMembersManager(creds, apiBase, journal.uid);
journalMembersManager.create({ user, key: encryptedKey, readOnly }).then(() => {
fetchMembers();
});
setAddMemberOpen(false);
}
const { syncJournal } = props;
const info = syncJournal.collection;
const sharingAllowed = syncJournal.journal.version > 1;
@ -60,14 +96,14 @@ class JournalMembers extends React.PureComponent<PropsTypeInner> {
<Container style={{ maxWidth: "30rem" }}>
{members ?
<List>
<ListItem rightIcon={<IconMemberAdd />} onClick={() => this.setState({ addMemberOpen: true })}>
<ListItem rightIcon={<IconMemberAdd />} onClick={() => setAddMemberOpen(true)}>
Add member
</ListItem>
{(members.length > 0 ?
members.map((member) => (
<ListItem
key={member.user}
onClick={() => this.onRevokeRequest(member.user)}
onClick={() => onRevokeRequest(member.user)}
rightIcon={(member.readOnly) ? (<VisibilityIcon />) : undefined}
>
{member.user}
@ -87,8 +123,8 @@ class JournalMembers extends React.PureComponent<PropsTypeInner> {
title="Remove member"
labelOk="OK"
open={revokeUser !== null}
onOk={this.onRevokeDo}
onCancel={() => this.setState({ revokeUser: null })}
onOk={onRevokeDo}
onCancel={() => setRevokeUser(null)}
>
Would you like to revoke {revokeUser}'s access?<br />
Please be advised that a malicious user would potentially be able to retain access to encryption keys. Please refer to the FAQ for more information.
@ -97,18 +133,18 @@ class JournalMembers extends React.PureComponent<PropsTypeInner> {
{addMemberOpen &&
(sharingAllowed ?
<JournalMemberAddDialog
etesync={this.props.etesync}
etesync={props.etesync}
info={info}
onOk={this.onMemberAdd}
onClose={() => this.setState({ addMemberOpen: false })}
onOk={onMemberAdd}
onClose={() => setAddMemberOpen(false)}
/>
:
<ConfirmationDialog
title="Now Allowed"
labelOk="OK"
open
onOk={() => this.setState({ addMemberOpen: false })}
onClose={() => this.setState({ addMemberOpen: false })}
onOk={() => setAddMemberOpen(false)}
onClose={() => setAddMemberOpen(false)}
>
Sharing of old-style journals is not allowed. In order to share this journal, create a new one, and copy its contents over using the "import" dialog. If you are experiencing any issues, please contact support.
</ConfirmationDialog>
@ -117,68 +153,3 @@ class JournalMembers extends React.PureComponent<PropsTypeInner> {
</>
);
}
public componentDidMount() {
this.fetchMembers();
}
private fetchMembers() {
const { etesync, syncJournal } = this.props;
const info = syncJournal.collection;
const creds = etesync.credentials;
const apiBase = etesync.serviceApiUrl;
const journalMembersManager = new EteSync.JournalMembersManager(creds, apiBase, info.uid);
journalMembersManager.list().then((members) => {
this.setState({
members,
});
});
}
private onRevokeRequest(user: string) {
this.setState({
revokeUser: user,
});
}
private onRevokeDo() {
const { etesync, syncJournal } = this.props;
const { revokeUser } = this.state;
const info = syncJournal.collection;
const creds = etesync.credentials;
const apiBase = etesync.serviceApiUrl;
const journalMembersManager = new EteSync.JournalMembersManager(creds, apiBase, info.uid);
journalMembersManager.delete({ user: revokeUser!, key: "" }).then(() => {
this.fetchMembers();
});
this.setState({
revokeUser: null,
});
}
private onMemberAdd(user: string, publicKey: string, readOnly: boolean) {
const { etesync, syncJournal, userInfo } = this.props;
const journal = syncJournal.journal;
const derived = this.props.etesync.encryptionKey;
const keyPair = userInfo.getKeyPair(userInfo.getCryptoManager(derived));
const cryptoManager = journal.getCryptoManager(derived, keyPair);
const pubkeyBytes = sjcl.codec.bytes.fromBits(sjcl.codec.base64.toBits(publicKey));
const encryptedKey = sjcl.codec.base64.fromBits(sjcl.codec.bytes.toBits(cryptoManager.getEncryptedKey(keyPair, pubkeyBytes)));
const creds = etesync.credentials;
const apiBase = etesync.serviceApiUrl;
const journalMembersManager = new EteSync.JournalMembersManager(creds, apiBase, journal.uid);
journalMembersManager.create({ user, key: encryptedKey, readOnly }).then(() => {
this.fetchMembers();
});
this.setState({
addMemberOpen: false,
});
}
}
export default withTheme(JournalMembers);

Loading…
Cancel
Save