mirror of
https://github.com/RoboSats/robosats.git
synced 2025-02-07 13:59:06 +00:00
Add download robot credential button. Add timedate to messages in chat.
This commit is contained in:
parent
3cb544ef10
commit
40d44d8d59
@ -208,7 +208,7 @@ class Chat extends Component {
|
|||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
}
|
}
|
||||||
subheader={this.state.showPGP[props.index] ? props.message.encryptedMessage : props.message.plainTextMessage}
|
subheader={this.state.showPGP[props.index] ? <a> {props.message.time} <br/> {"Valid signature: " + props.message.validSignature} <br/> {props.message.encryptedMessage} </a> : props.message.plainTextMessage}
|
||||||
subheaderTypographyProps={{sx: {wordWrap: "break-word", width: '200px', color: '#444444', fontSize: this.state.showPGP[props.index]? 11 : null }}}
|
subheaderTypographyProps={{sx: {wordWrap: "break-word", width: '200px', color: '#444444', fontSize: this.state.showPGP[props.index]? 11 : null }}}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
@ -256,7 +256,7 @@ class Chat extends Component {
|
|||||||
label={t("Type a message")}
|
label={t("Type a message")}
|
||||||
variant="standard"
|
variant="standard"
|
||||||
size="small"
|
size="small"
|
||||||
helperText={this.state.connected ? null : t("Connecting...")}
|
helperText={this.state.connected ? (this.state.peer_pub_key ? null : t("Waiting for peer public key...")) : t("Connecting...")}
|
||||||
value={this.state.value}
|
value={this.state.value}
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
this.setState({ value: e.target.value });
|
this.setState({ value: e.target.value });
|
||||||
@ -266,7 +266,7 @@ class Chat extends Component {
|
|||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item alignItems="stretch" style={{ display: "flex" }}>
|
<Grid item alignItems="stretch" style={{ display: "flex" }}>
|
||||||
<Button sx={{'width':68}} disabled={!this.state.connected || this.state.waitingEcho} type="submit" variant="contained" color="primary">
|
<Button sx={{'width':68}} disabled={!this.state.connected || this.state.waitingEcho || this.state.peer_pub_key == null} type="submit" variant="contained" color="primary">
|
||||||
{this.state.waitingEcho ?
|
{this.state.waitingEcho ?
|
||||||
<div style={{display:'flex',alignItems:'center', flexWrap:'wrap', minWidth:68, width:68, position:"relative",left:15}}>
|
<div style={{display:'flex',alignItems:'center', flexWrap:'wrap', minWidth:68, width:68, position:"relative",left:15}}>
|
||||||
<div style={{width:20}}><KeyIcon sx={{width:18}}/></div>
|
<div style={{width:20}}><KeyIcon sx={{width:18}}/></div>
|
||||||
@ -301,7 +301,7 @@ class Chat extends Component {
|
|||||||
|
|
||||||
<Grid item xs={6}>
|
<Grid item xs={6}>
|
||||||
<Tooltip placement="bottom" enterTouchDelay={0} enterDelay={500} enterNextDelay={2000} title={t("Save full log as a JSON file (messages and credentials)")}>
|
<Tooltip placement="bottom" enterTouchDelay={0} enterDelay={500} enterNextDelay={2000} title={t("Save full log as a JSON file (messages and credentials)")}>
|
||||||
<Button size="small" color="primary" variant="outlined" onClick={()=>saveAsJson('chat_'+this.props.orderId+'.json', this.createJsonFile())}><div style={{width:28,height:20}}><ExportIcon sx={{width:20,height:20}}/></div> {t("Export")} </Button>
|
<Button size="small" color="primary" variant="outlined" onClick={()=>saveAsJson('complete_log_chat_'+this.props.orderId+'.json', this.createJsonFile())}><div style={{width:28,height:20}}><ExportIcon sx={{width:20,height:20}}/></div> {t("Export")} </Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -9,12 +9,14 @@ import SmartToyIcon from '@mui/icons-material/SmartToy';
|
|||||||
import CasinoIcon from '@mui/icons-material/Casino';
|
import CasinoIcon from '@mui/icons-material/Casino';
|
||||||
import ContentCopy from "@mui/icons-material/ContentCopy";
|
import ContentCopy from "@mui/icons-material/ContentCopy";
|
||||||
import BoltIcon from '@mui/icons-material/Bolt';
|
import BoltIcon from '@mui/icons-material/Bolt';
|
||||||
|
import DownloadIcon from '@mui/icons-material/Download';
|
||||||
import { RoboSatsNoTextIcon } from "./Icons";
|
import { RoboSatsNoTextIcon } from "./Icons";
|
||||||
|
|
||||||
import { sha256 } from 'js-sha256';
|
import { sha256 } from 'js-sha256';
|
||||||
import { genBase62Token, tokenStrength } from "../utils/token";
|
import { genBase62Token, tokenStrength } from "../utils/token";
|
||||||
import { genKey } from "../utils/pgp";
|
import { genKey } from "../utils/pgp";
|
||||||
import { getCookie, writeCookie } from "../utils/cookies";
|
import { getCookie, writeCookie } from "../utils/cookies";
|
||||||
|
import { saveAsJson } from "../utils/saveFile";
|
||||||
|
|
||||||
|
|
||||||
class UserGenPage extends Component {
|
class UserGenPage extends Component {
|
||||||
@ -146,6 +148,16 @@ class UserGenPage extends Component {
|
|||||||
this.setState({openInfo: false});
|
this.setState({openInfo: false});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
createJsonFile = () => {
|
||||||
|
return ({
|
||||||
|
"token":getCookie('robot_token'),
|
||||||
|
"token_shannon_entropy": this.state.shannon_entropy,
|
||||||
|
"token_bit_entropy": this.state.bit_entropy,
|
||||||
|
"public_key": getCookie('pub_key').split('\\').join('\n'),
|
||||||
|
"encrypted_private_key": getCookie('enc_priv_key').split('\\').join('\n'),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { t, i18n} = this.props;
|
const { t, i18n} = this.props;
|
||||||
return (
|
return (
|
||||||
@ -208,11 +220,24 @@ class UserGenPage extends Component {
|
|||||||
}}
|
}}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
startAdornment:
|
startAdornment:
|
||||||
<Tooltip disableHoverListener enterTouchDelay={0} title={t("Copied!")}>
|
<div style={{width:50, minWidth:50, position:'relative',left:-6}}>
|
||||||
<IconButton onClick= {()=> (navigator.clipboard.writeText(this.state.token) & this.props.setAppState({copiedToken:true}))}>
|
<Grid container xs={12}>
|
||||||
<ContentCopy color={this.props.avatarLoaded & !this.props.copiedToken & !this.state.bad_request ? 'primary' : 'inherit' } sx={{width:18, height:18}}/>
|
<Grid item xs={6}>
|
||||||
</IconButton>
|
<Tooltip enterTouchDelay={250} title={t("Save token and PGP credentials to file")}>
|
||||||
</Tooltip>,
|
<IconButton color="primary" disabled={getCookie('robot_token')==null || !this.props.avatarLoaded} onClick= {()=> saveAsJson(this.state.nickname+'.json', this.createJsonFile())}>
|
||||||
|
<DownloadIcon sx={{width:22, height:22}}/>
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<Tooltip disableHoverListener enterTouchDelay={0} title={t("Copied!")}>
|
||||||
|
<IconButton onClick= {()=> (navigator.clipboard.writeText(this.state.token) & this.props.setAppState({copiedToken:true}))}>
|
||||||
|
<ContentCopy color={this.props.avatarLoaded & !this.props.copiedToken & !this.state.bad_request ? 'primary' : 'inherit' } sx={{width:18, height:18}}/>
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</div>,
|
||||||
endAdornment:
|
endAdornment:
|
||||||
<Tooltip enterTouchDelay={250} title={t("Generate a new token")}>
|
<Tooltip enterTouchDelay={250} title={t("Generate a new token")}>
|
||||||
<IconButton onClick={this.handleClickNewRandomToken}><CasinoIcon/></IconButton>
|
<IconButton onClick={this.handleClickNewRandomToken}><CasinoIcon/></IconButton>
|
||||||
|
@ -1,9 +1,18 @@
|
|||||||
import * as openpgp from 'openpgp/lightweight';
|
import {
|
||||||
|
generateKey,
|
||||||
|
readKey,
|
||||||
|
readPrivateKey,
|
||||||
|
decryptKey,
|
||||||
|
encrypt,
|
||||||
|
decrypt,
|
||||||
|
createMessage,
|
||||||
|
readMessage
|
||||||
|
} from 'openpgp/lightweight';
|
||||||
|
|
||||||
// Generate KeyPair. Private Key is encrypted with the highEntropyToken
|
// Generate KeyPair. Private Key is encrypted with the highEntropyToken
|
||||||
export async function genKey(highEntropyToken) {
|
export async function genKey(highEntropyToken) {
|
||||||
|
|
||||||
const keyPair = await openpgp.generateKey({
|
const keyPair = await generateKey({
|
||||||
type: 'ecc', // Type of the key, defaults to ECC
|
type: 'ecc', // Type of the key, defaults to ECC
|
||||||
curve: 'curve25519', // ECC curve name, defaults to curve25519
|
curve: 'curve25519', // ECC curve name, defaults to curve25519
|
||||||
userIDs: [{name: 'RoboSats Avatar ID'+ parseInt(Math.random() * 1000000)}], //Just for identification. Ideally it would be the avatar nickname, but the nickname is generated only after submission
|
userIDs: [{name: 'RoboSats Avatar ID'+ parseInt(Math.random() * 1000000)}], //Just for identification. Ideally it would be the avatar nickname, but the nickname is generated only after submission
|
||||||
@ -17,15 +26,15 @@ export async function genKey(highEntropyToken) {
|
|||||||
// Encrypt and sign a message
|
// Encrypt and sign a message
|
||||||
export async function encryptMessage(plaintextMessage, ownPublicKeyArmored, peerPublicKeyArmored, privateKeyArmored, passphrase) {
|
export async function encryptMessage(plaintextMessage, ownPublicKeyArmored, peerPublicKeyArmored, privateKeyArmored, passphrase) {
|
||||||
|
|
||||||
const ownPublicKey = await openpgp.readKey({ armoredKey: ownPublicKeyArmored });
|
const ownPublicKey = await readKey({ armoredKey: ownPublicKeyArmored });
|
||||||
const peerPublicKey = await openpgp.readKey({ armoredKey: peerPublicKeyArmored });
|
const peerPublicKey = await readKey({ armoredKey: peerPublicKeyArmored });
|
||||||
const privateKey = await openpgp.decryptKey({
|
const privateKey = await decryptKey({
|
||||||
privateKey: await openpgp.readPrivateKey({ armoredKey: privateKeyArmored }),
|
privateKey: await readPrivateKey({ armoredKey: privateKeyArmored }),
|
||||||
passphrase
|
passphrase
|
||||||
});
|
});
|
||||||
|
|
||||||
const encryptedMessage = await openpgp.encrypt({
|
const encryptedMessage = await encrypt({
|
||||||
message: await openpgp.createMessage({ text: plaintextMessage }), // input as Message object, message must be string
|
message: await createMessage({ text: plaintextMessage }), // input as Message object, message must be string
|
||||||
encryptionKeys: [ ownPublicKey, peerPublicKey ],
|
encryptionKeys: [ ownPublicKey, peerPublicKey ],
|
||||||
signingKeys: privateKey // optional
|
signingKeys: privateKey // optional
|
||||||
});
|
});
|
||||||
@ -36,16 +45,16 @@ export async function encryptMessage(plaintextMessage, ownPublicKeyArmored, peer
|
|||||||
// Decrypt and check signature of a message
|
// Decrypt and check signature of a message
|
||||||
export async function decryptMessage(encryptedMessage, publicKeyArmored, privateKeyArmored, passphrase) {
|
export async function decryptMessage(encryptedMessage, publicKeyArmored, privateKeyArmored, passphrase) {
|
||||||
|
|
||||||
const publicKey = await openpgp.readKey({ armoredKey: publicKeyArmored });
|
const publicKey = await readKey({ armoredKey: publicKeyArmored });
|
||||||
const privateKey = await openpgp.decryptKey({
|
const privateKey = await decryptKey({
|
||||||
privateKey: await openpgp.readPrivateKey({ armoredKey: privateKeyArmored }),
|
privateKey: await readPrivateKey({ armoredKey: privateKeyArmored }),
|
||||||
passphrase
|
passphrase
|
||||||
});
|
});
|
||||||
|
|
||||||
const message = await openpgp.readMessage({
|
const message = await readMessage({
|
||||||
armoredMessage: encryptedMessage // parse armored message
|
armoredMessage: encryptedMessage // parse armored message
|
||||||
});
|
});
|
||||||
const { data: decrypted, signatures } = await openpgp.decrypt({
|
const { data: decrypted, signatures } = await decrypt({
|
||||||
message,
|
message,
|
||||||
verificationKeys: publicKey, // optional
|
verificationKeys: publicKey, // optional
|
||||||
decryptionKeys: privateKey
|
decryptionKeys: privateKey
|
||||||
|
Loading…
Reference in New Issue
Block a user