import React, { Component } from 'react'; import { withTranslation } from "react-i18next"; import {Button, IconButton, Badge, Tooltip, TextField, Grid, Container, Card, CardHeader, Paper, Avatar, Typography} from "@mui/material"; import ReconnectingWebSocket from 'reconnecting-websocket'; import { encryptMessage , decryptMessage} from "../utils/pgp"; import { getCookie } from "../utils/cookies"; import { saveAsJson } from "../utils/saveFile"; import { AuditPGPDialog } from "./Dialogs" // Icons import CheckIcon from '@mui/icons-material/Check'; import CloseIcon from '@mui/icons-material/Close'; import ContentCopy from "@mui/icons-material/ContentCopy"; import VisibilityIcon from '@mui/icons-material/Visibility'; import CircularProgress from '@mui/material/CircularProgress'; import KeyIcon from '@mui/icons-material/Key'; import { ExportIcon } from './Icons'; class Chat extends Component { constructor(props) { super(props); } state = { own_pub_key: getCookie('pub_key').split('\\').join('\n'), own_enc_priv_key: getCookie('enc_priv_key').split('\\').join('\n'), peer_pub_key: null, token: getCookie('robot_token'), messages: [], value:'', connected: false, peer_connected: false, audit: false, showPGP: new Array, waitingEcho: false, lastSent: '---BLANK---', latestIndex: 0, scrollNow:false, }; rws = new ReconnectingWebSocket('ws://' + window.location.host + '/ws/chat/' + this.props.orderId + '/'); componentDidMount() { this.rws.addEventListener('open', () => { console.log('Connected!'); this.setState({connected: true}); this.rws.send(JSON.stringify({ type: "message", message: this.state.own_pub_key, nick: this.props.ur_nick, })); }); this.rws.addEventListener('message', (message) => { const dataFromServer = JSON.parse(message.data); console.log('Got reply!', dataFromServer.type); console.log('PGP message index', dataFromServer.index, ' latestIndex ',this.state.latestIndex); if (dataFromServer){ console.log(dataFromServer) this.setState({peer_connected: dataFromServer.peer_connected}) // If we receive our own key on a message if (dataFromServer.message == this.state.own_pub_key){console.log("OWN PUB KEY RECEIVED!!")} // If we receive a public key other than ours (our peer key!) if (dataFromServer.message.substring(0,36) == `-----BEGIN PGP PUBLIC KEY BLOCK-----` && dataFromServer.message != this.state.own_pub_key) { if (dataFromServer.message == this.state.peer_pub_key){ console.log("PEER HAS RECONNECTED USING HIS PREVIOUSLY KNOWN PUBKEY") } else if (dataFromServer.message != this.state.peer_pub_key & this.state.peer_pub_key != null){ console.log("PEER PUBKEY HAS CHANGED") } console.log("PEER PUBKEY RECEIVED!!") this.setState({peer_pub_key:dataFromServer.message}) // After receiving the peer pubkey we ask the server for the historic messages if any this.rws.send(JSON.stringify({ type: "message", message: `-----SERVE HISTORY-----`, nick: this.props.ur_nick, })) } else // If we receive an encrypted message if (dataFromServer.message.substring(0,27) == `-----BEGIN PGP MESSAGE-----` && dataFromServer.index > this.state.latestIndex){ decryptMessage( dataFromServer.message.split('\\').join('\n'), dataFromServer.user_nick == this.props.ur_nick ? this.state.own_pub_key : this.state.peer_pub_key, this.state.own_enc_priv_key, this.state.token) .then((decryptedData) => this.setState((state) => ({ scrollNow: true, waitingEcho: this.state.waitingEcho == true ? (decryptedData.decryptedMessage == this.state.lastSent ? false: true ) : false, lastSent: decryptedData.decryptedMessage == this.state.lastSent ? '----BLANK----': this.state.lastSent, latestIndex: dataFromServer.index > this.state.latestIndex ? dataFromServer.index : this.state.latestIndex, messages: [...state.messages, { index: dataFromServer.index, encryptedMessage: dataFromServer.message.split('\\').join('\n'), plainTextMessage: decryptedData.decryptedMessage, validSignature: decryptedData.validSignature, userNick: dataFromServer.user_nick, time: dataFromServer.time }].sort(function(a,b) { // order the message array by their index (increasing) return a.index - b.index }), }) )); } else // We allow plaintext communication. The user must write # to start // If we receive an plaintext message if (dataFromServer.message.substring(0,1) == "#"){ console.log("Got plaintext message", dataFromServer.message) this.setState((state) => ({ scrollNow: true, messages: [...state.messages, { index: this.state.latestIndex + 0.001, encryptedMessage: dataFromServer.message, plainTextMessage: dataFromServer.message, validSignature: false, userNick: dataFromServer.user_nick, time: (new Date).toString(), }]})); } } }); this.rws.addEventListener('close', () => { console.log('Socket is closed. Reconnect will be attempted'); this.setState({connected: false}); }); this.rws.addEventListener('error', () => { console.error('Socket encountered error: Closing socket'); }); } componentDidUpdate() { // Only fire the scroll when the reason for Update is a new message if (this.state.scrollNow){ this.scrollToBottom(); this.setState({scrollNow:false}) } } scrollToBottom = () => { this.messagesEnd.scrollIntoView({ behavior: "smooth" }); } onButtonClicked = (e) => { if(this.state.value.substring(0,1)=='#'){ this.rws.send(JSON.stringify({ type: "message", message: this.state.value, nick: this.props.ur_nick, })); this.setState({value: ""}); } else if(this.state.value!=''){ this.setState({value: "", waitingEcho: true, lastSent:this.state.value}) encryptMessage(this.state.value, this.state.own_pub_key, this.state.peer_pub_key, this.state.own_enc_priv_key, this.state.token) .then((encryptedMessage) => console.log("Sending Encrypted MESSAGE", encryptedMessage) & this.rws.send(JSON.stringify({ type: "message", message: encryptedMessage.split('\n').join('\\'), nick: this.props.ur_nick, }) ) ); } e.preventDefault(); } createJsonFile = () => { return ({ "credentials": { "own_public_key": this.state.own_pub_key, "peer_public_key":this.state.peer_pub_key, "encrypted_private_key":this.state.own_enc_priv_key, "passphrase":this.state.token}, "messages": this.state.messages, }) } messageCard = (props) => { const { t } = this.props; return( } style={{backgroundColor: props.cardColor}} title={
{props.message.userNick} {props.message.validSignature ? : }
this.setState(prevState => { const newShowPGP = [...prevState.showPGP]; newShowPGP[props.index] = !newShowPGP[props.index]; return {showPGP: newShowPGP}; })}>
navigator.clipboard.writeText(this.state.showPGP[props.index] ? props.message.encryptedMessage : props.message.plainTextMessage)}>
} subheader={this.state.showPGP[props.index] ? {props.message.time}
{"Valid signature: " + props.message.validSignature}
{props.message.encryptedMessage}
: props.message.plainTextMessage} subheaderTypographyProps={{sx: {wordWrap: "break-word", width: '215px', color: '#444444', fontSize: this.state.showPGP[props.index]? 11 : null }}} />
) } render() { const { t } = this.props; return ( {t("You")+": "}{this.state.connected ? t("connected"): t("disconnected")} {t("Peer")+": "}{this.state.peer_connected ? t("connected"): t("disconnected")}
{this.state.messages.map((message, index) =>
  • {message.userNick == this.props.ur_nick ? : }
  • )}
    { this.messagesEnd = el; }}>
    { this.setState({ value: e.target.value }); this.value = this.state.value; }} sx={{width: 219}} />
    this.setState({audit:false})} orderId={Number(this.props.orderId)} messages={this.state.messages} own_pub_key={this.state.own_pub_key} own_enc_priv_key={this.state.own_enc_priv_key} peer_pub_key={this.state.peer_pub_key ? this.state.peer_pub_key : "Not received yet"} passphrase={this.state.token} onClickBack={() => this.setState({audit:false})} /> ) } } export default withTranslation()(Chat);