get backup client

This commit is contained in:
Yostra 2020-09-02 22:01:16 -07:00 committed by Gene Hoffman
parent 43cdbb90b9
commit cb0897ba36
9 changed files with 312 additions and 164 deletions

View File

@ -1,5 +1,6 @@
const config = {
local_test: false
local_test: false,
backup_host: "https://backup.chia.net",
};
module.exports = config;

View File

@ -3,14 +3,14 @@ import {
registerService,
startService,
isServiceRunning,
startServiceTest
startServiceTest,
} from "../modules/daemon_messages";
import { handle_message } from "./middleware_api";
import {
service_wallet,
service_full_node,
service_simulator,
service_plotter
service_plotter,
} from "../util/service_names";
const config = require("../config");
@ -24,14 +24,14 @@ const outgoing_message = (command, data, destination) => ({
ack: false,
origin: "wallet_ui",
destination: destination,
request_id: crypto.randomBytes(32).toString("hex")
request_id: crypto.randomBytes(32).toString("hex"),
});
const socketMiddleware = () => {
let socket = null;
let connected = false;
const onOpen = store => event => {
const onOpen = (store) => (event) => {
connected = true;
store.dispatch(actions.wsConnected(event.target.url));
var register_action = registerService();
@ -50,12 +50,12 @@ const socketMiddleware = () => {
store.dispatch(start_node);
};
const onClose = store => () => {
const onClose = (store) => () => {
connected = false;
store.dispatch(actions.wsDisconnected());
};
const onMessage = store => event => {
const onMessage = (store) => (event) => {
const payload = JSON.parse(event.data);
const request_id = payload["request_id"];
if (callback_map[request_id] != null) {
@ -67,7 +67,7 @@ const socketMiddleware = () => {
handle_message(store, payload);
};
return store => next => action => {
return (store) => (next) => (action) => {
switch (action.type) {
case "WS_CONNECT":
if (socket !== null) {

View File

@ -1,21 +1,21 @@
export const presentBackupInfo = "BACKUP_INFO";
export const presentMain = "MAIN";
export const changeBackupView = view => ({ type: "BACKUP_VIEW", view: view });
export const setBackupInfo = backup_info => ({
export const changeBackupView = (view) => ({ type: "BACKUP_VIEW", view: view });
export const setBackupInfo = (backup_info) => ({
type: "BACKUP_INFO",
backup_info: backup_info
backup_info: backup_info,
});
export const selectFilePath = file_path => ({
export const selectFilePath = (file_path) => ({
type: "SELECT_FILEPATH",
file_path: file_path
file_path: file_path,
});
const initial_state = {
view: presentMain,
backup_info: {},
selected_file_path: null
selected_file_path: null,
};
export const backupReducer = (state = { ...initial_state }, action) => {

View File

@ -5,7 +5,7 @@ import { setIncorrectWord, resetMnemonic } from "./mnemonic_input";
import {
changeEntranceMenu,
presentRestoreBackup,
presentOldWallet
presentOldWallet,
} from "./entranceMenu";
import { openDialog } from "./dialogReducer";
import { createState } from "./createWalletReducer";
@ -14,25 +14,27 @@ import {
getPlotDirectories,
removePlotDirectory,
getPlots,
refreshPlots
refreshPlots,
} from "./harvesterMessages";
import {
setBackupInfo,
changeBackupView,
presentBackupInfo,
selectFilePath
selectFilePath,
} from "./backup_state";
import { exitDaemon } from "./daemon_messages";
import { wsDisconnect } from "./websocket";
import {
changeCreateWallet,
ALL_OPTIONS
ALL_OPTIONS,
} from "../modules/createWalletReducer";
const config = require("../config");
const backup_host = config.backup_host;
export const clearSend = () => {
var action = {
type: "CLEAR_SEND",
mesasge: ""
mesasge: "",
};
return action;
};
@ -40,27 +42,27 @@ export const clearSend = () => {
export const walletMessage = () => ({
type: "OUTGOING_MESSAGE",
message: {
destination: service_wallet
}
destination: service_wallet,
},
});
export const selectFingerprint = fingerprint => ({
export const selectFingerprint = (fingerprint) => ({
type: "SELECT_FINGERPRINT",
fingerprint: fingerprint
fingerprint: fingerprint,
});
export const unselectFingerprint = () => ({
type: "UNSELECT_FINGERPRINT"
type: "UNSELECT_FINGERPRINT",
});
export const selectMnemonic = mnemonic => ({
export const selectMnemonic = (mnemonic) => ({
type: "SELECT_MNEMONIC",
mnemonic: mnemonic
mnemonic: mnemonic,
});
export const showCreateBackup = show => ({
export const showCreateBackup = (show) => ({
type: "SHOW_CREATE_BACKUP",
show: show
show: show,
});
export const async_api = (dispatch, action, open_spinner) => {
@ -93,7 +95,7 @@ export const pingWallet = () => {
return action;
};
export const get_balance_for_wallet = id => {
export const get_balance_for_wallet = (id) => {
var action = walletMessage();
action.message.command = "get_wallet_balance";
action.message.data = { wallet_id: id };
@ -107,7 +109,7 @@ export const send_transaction = (wallet_id, amount, fee, puzzle_hash) => {
wallet_id: wallet_id,
amount: amount,
fee: fee,
puzzle_hash: puzzle_hash
puzzle_hash: puzzle_hash,
};
return action;
};
@ -125,18 +127,18 @@ export const add_key = (mnemonic, type, file_path) => {
action.message.data = {
mnemonic: mnemonic,
type: type,
file_path: file_path
file_path: file_path,
};
return action;
};
export const add_new_key_action = mnemonic => {
return dispatch => {
export const add_new_key_action = (mnemonic) => {
return (dispatch) => {
return async_api(
dispatch,
add_key(mnemonic, "new_wallet", null),
true
).then(response => {
).then((response) => {
dispatch(closeProgress());
if (response.data.success) {
// Go to wallet
@ -157,10 +159,10 @@ export const add_new_key_action = mnemonic => {
};
};
export const add_and_skip_backup = mnemonic => {
return dispatch => {
export const add_and_skip_backup = (mnemonic) => {
return (dispatch) => {
return async_api(dispatch, add_key(mnemonic, "skip", null), true).then(
response => {
(response) => {
dispatch(closeProgress());
if (response.data.success) {
// Go to wallet
@ -185,17 +187,16 @@ export const add_and_skip_backup = mnemonic => {
};
export const add_and_restore_from_backup = (mnemonic, file_path) => {
return dispatch => {
return (dispatch) => {
return async_api(
dispatch,
add_key(mnemonic, "restore_backup", file_path),
true
).then(response => {
).then((response) => {
dispatch(closeProgress());
if (response.data.success) {
// Go to wallet
dispatch(resetMnemonic());
dispatch(format_message("get_public_keys", {}));
refreshAllState(dispatch);
} else {
if (response.data.word) {
@ -211,7 +212,7 @@ export const add_and_restore_from_backup = (mnemonic, file_path) => {
};
};
export const delete_key = fingerprint => {
export const delete_key = (fingerprint) => {
var action = walletMessage();
action.message.command = "delete_key";
action.message.data = { fingerprint: fingerprint };
@ -225,17 +226,25 @@ export const delete_all_keys = () => {
return action;
};
export const log_in = fingerprint => {
export const log_in = (fingerprint) => {
var action = walletMessage();
action.message.command = "log_in";
action.message.data = { fingerprint: fingerprint, type: "normal" };
action.message.data = {
fingerprint: fingerprint,
host: backup_host,
type: "normal",
};
return action;
};
export const log_in_and_skip_import = fingerprint => {
export const log_in_and_skip_import = (fingerprint) => {
var action = walletMessage();
action.message.command = "log_in";
action.message.data = { fingerprint: fingerprint, type: "skip" };
action.message.data = {
fingerprint: fingerprint,
host: backup_host,
type: "skip",
};
return action;
};
@ -245,16 +254,17 @@ export const log_in_and_import_backup = (fingerprint, file_path) => {
action.message.data = {
fingerprint: fingerprint,
type: "restore_backup",
file_path: file_path
file_path: file_path,
host: backup_host,
};
return action;
};
export const login_and_skip_action = fingerprint => {
return dispatch => {
export const login_and_skip_action = (fingerprint) => {
return (dispatch) => {
dispatch(selectFingerprint(fingerprint));
return async_api(dispatch, log_in_and_skip_import(fingerprint), true).then(
response => {
(response) => {
dispatch(closeProgress());
if (response.data.success) {
// Go to wallet
@ -273,10 +283,10 @@ export const login_and_skip_action = fingerprint => {
};
};
export const login_action = fingerprint => {
return dispatch => {
export const login_action = (fingerprint) => {
return (dispatch) => {
dispatch(selectFingerprint(fingerprint));
return async_api(dispatch, log_in(fingerprint), true).then(response => {
return async_api(dispatch, log_in(fingerprint), true).then((response) => {
dispatch(closeProgress());
if (response.data.success) {
// Go to wallet
@ -284,7 +294,14 @@ export const login_action = fingerprint => {
} else {
const error = response.data.error;
if (error === "not_initialized") {
const backup_info = response.data.backup_info;
const backup_path = response.data.backup_path;
dispatch(changeEntranceMenu(presentRestoreBackup));
if (backup_info && backup_path) {
dispatch(setBackupInfo(backup_info));
dispatch(selectFilePath(backup_path));
dispatch(changeBackupView(presentBackupInfo));
}
// Go to restore from backup screen
} else {
dispatch(openDialog("Error", error));
@ -300,27 +317,28 @@ export const get_backup_info = (file_path, fingerprint, words) => {
if (fingerprint === null) {
action.message.data = {
file_path: file_path,
words: words
words: words,
};
} else if (words === null) {
action.message.data = {
file_path: file_path,
fingerprint: fingerprint
fingerprint: fingerprint,
};
}
return action;
};
export const get_backup_info_action = (file_path, fingerprint, words) => {
return dispatch => {
return (dispatch) => {
dispatch(selectFilePath(file_path));
return async_api(
dispatch,
get_backup_info(file_path, fingerprint, words),
true
).then(response => {
).then((response) => {
dispatch(closeProgress());
if (response.data.success) {
response.data.backup_info.downloaded = false;
dispatch(setBackupInfo(response.data.backup_info));
dispatch(changeBackupView(presentBackupInfo));
} else {
@ -331,28 +349,28 @@ export const get_backup_info_action = (file_path, fingerprint, words) => {
};
};
export const get_private_key = fingerprint => {
export const get_private_key = (fingerprint) => {
var action = walletMessage();
action.message.command = "get_private_key";
action.message.data = { fingerprint: fingerprint };
return action;
};
export const get_transactions = wallet_id => {
export const get_transactions = (wallet_id) => {
var action = walletMessage();
action.message.command = "get_transactions";
action.message.data = { wallet_id: wallet_id };
return action;
};
export const get_puzzle_hash = wallet_id => {
export const get_puzzle_hash = (wallet_id) => {
var action = walletMessage();
action.message.command = "get_next_puzzle_hash";
action.message.data = { wallet_id: wallet_id };
return action;
};
export const farm_block = puzzle_hash => {
export const farm_block = (puzzle_hash) => {
var action = walletMessage();
action.message.command = "farm_block";
action.message.data = { puzzle_hash: puzzle_hash };
@ -387,7 +405,8 @@ export const create_coloured_coin = (amount, fee) => {
wallet_type: "cc_wallet",
mode: "new",
amount: amount,
fee: fee
fee: fee,
host: backup_host,
};
return action;
};
@ -399,24 +418,25 @@ export const create_cc_for_colour = (colour, fee) => {
wallet_type: "cc_wallet",
mode: "existing",
colour: colour,
fee: fee
fee: fee,
host: backup_host,
};
return action;
};
export const create_backup = file_path => {
export const create_backup = (file_path) => {
var action = walletMessage();
action.message.command = "create_backup";
action.message.data = {
file_path: file_path
file_path: file_path,
};
return action;
};
export const create_backup_action = file_path => {
return dispatch => {
export const create_backup_action = (file_path) => {
return (dispatch) => {
return async_api(dispatch, create_backup(file_path), true).then(
response => {
(response) => {
dispatch(closeProgress());
if (response.data.success) {
dispatch(showCreateBackup(false));
@ -430,9 +450,9 @@ export const create_backup_action = file_path => {
};
export const create_cc_action = (amount, fee) => {
return dispatch => {
return (dispatch) => {
return async_api(dispatch, create_coloured_coin(amount, fee), true).then(
response => {
(response) => {
dispatch(closeProgress());
dispatch(createState(true, false));
if (response.data.success) {
@ -440,7 +460,7 @@ export const create_cc_action = (amount, fee) => {
dispatch(format_message("get_wallets", {}));
dispatch(showCreateBackup(true));
dispatch(createState(true, false));
dispatch(changeCreateWallet(ALL_OPTIONS))
dispatch(changeCreateWallet(ALL_OPTIONS));
} else {
const error = response.data.error;
dispatch(openDialog("Error", error));
@ -451,16 +471,16 @@ export const create_cc_action = (amount, fee) => {
};
export const create_cc_for_colour_action = (colour, fee) => {
return dispatch => {
return (dispatch) => {
return async_api(dispatch, create_cc_for_colour(colour, fee), true).then(
response => {
(response) => {
dispatch(closeProgress());
dispatch(createState(true, false));
if (response.data.success) {
// Go to wallet
dispatch(showCreateBackup(true));
dispatch(format_message("get_wallets", {}));
dispatch(changeCreateWallet(ALL_OPTIONS))
dispatch(changeCreateWallet(ALL_OPTIONS));
} else {
const error = response.data.error;
dispatch(openDialog("Error", error));
@ -470,14 +490,14 @@ export const create_cc_for_colour_action = (colour, fee) => {
};
};
export const get_colour_info = wallet_id => {
export const get_colour_info = (wallet_id) => {
var action = walletMessage();
action.message.command = "cc_get_colour";
action.message.data = { wallet_id: wallet_id };
return action;
};
export const get_colour_name = wallet_id => {
export const get_colour_name = (wallet_id) => {
var action = walletMessage();
action.message.command = "cc_get_name";
action.message.data = { wallet_id: wallet_id };
@ -498,16 +518,16 @@ export const cc_spend = (wallet_id, puzzle_hash, amount, fee) => {
wallet_id: wallet_id,
innerpuzhash: puzzle_hash,
amount: amount,
fee: fee
fee: fee,
};
return action;
};
export const logOut = (command, data) => ({ type: "LOG_OUT", command, data });
export const incomingMessage = message => ({
export const incomingMessage = (message) => ({
type: "INCOMING_MESSAGE",
message: message
message: message,
});
export const create_rl_admin = (interval, limit, pubkey, amount) => {
@ -519,18 +539,19 @@ export const create_rl_admin = (interval, limit, pubkey, amount) => {
interval: interval,
limit: limit,
pubkey: pubkey,
amount: amount
amount: amount,
host: backup_host,
};
return action;
};
export const create_rl_admin_action = (interval, limit, pubkey, amount) => {
return dispatch => {
return (dispatch) => {
return async_api(
dispatch,
create_rl_admin(interval, limit, pubkey, amount),
true
).then(response => {
).then((response) => {
dispatch(closeProgress());
dispatch(createState(true, false));
if (response.data.success) {
@ -552,14 +573,15 @@ export const create_rl_user = () => {
action.message.command = "create_new_wallet";
action.message.data = {
wallet_type: "rl_wallet",
rl_type: "user"
rl_type: "user",
host: backup_host,
};
return action;
};
export const create_rl_user_action = () => {
return dispatch => {
return async_api(dispatch, create_rl_user(), true).then(response => {
return (dispatch) => {
return async_api(dispatch, create_rl_user(), true).then((response) => {
dispatch(closeProgress());
dispatch(createState(true, false));
if (response.data.success) {
@ -575,12 +597,12 @@ export const create_rl_user_action = () => {
};
};
export const add_plot_directory_and_refresh = dir => {
return dispatch => {
return async_api(dispatch, addPlotDirectory(dir), true).then(response => {
export const add_plot_directory_and_refresh = (dir) => {
return (dispatch) => {
return async_api(dispatch, addPlotDirectory(dir), true).then((response) => {
if (response.data.success) {
dispatch(getPlotDirectories());
return async_api(dispatch, refreshPlots(), false).then(response => {
return async_api(dispatch, refreshPlots(), false).then((response) => {
dispatch(closeProgress());
dispatch(getPlots());
});
@ -592,13 +614,13 @@ export const add_plot_directory_and_refresh = dir => {
};
};
export const remove_plot_directory_and_refresh = dir => {
return dispatch => {
export const remove_plot_directory_and_refresh = (dir) => {
return (dispatch) => {
return async_api(dispatch, removePlotDirectory(dir), true).then(
response => {
(response) => {
if (response.data.success) {
dispatch(getPlotDirectories());
return async_api(dispatch, refreshPlots(), false).then(response => {
return async_api(dispatch, refreshPlots(), false).then((response) => {
dispatch(closeProgress());
dispatch(getPlots());
});
@ -625,7 +647,7 @@ export const rl_set_user_info = (
interval: interval,
limit: limit,
origin: origin,
admin_pubkey: admin_pubkey
admin_pubkey: admin_pubkey,
};
return action;
};
@ -637,12 +659,12 @@ export const rl_set_user_info_action = (
origin,
admin_pubkey
) => {
return dispatch => {
return (dispatch) => {
return async_api(
dispatch,
rl_set_user_info(wallet_id, interval, limit, origin, admin_pubkey),
true
).then(response => {
).then((response) => {
dispatch(closeProgress());
dispatch(createState(true, false));
if (response.data.success) {
@ -658,13 +680,13 @@ export const rl_set_user_info_action = (
};
};
export const clawback_rl_coin = wallet_id => {
export const clawback_rl_coin = (wallet_id) => {
// THIS IS A PLACEHOLDER FOR RL CLAWBACK FUNCTIONALITY
};
export const exit_and_close = event => {
return dispatch => {
return async_api(dispatch, exitDaemon(), false).then(response => {
export const exit_and_close = (event) => {
return (dispatch) => {
return async_api(dispatch, exitDaemon(), false).then((response) => {
console.log("GOT RESPONSE", response);
dispatch(wsDisconnect());
event.sender.send("daemon-exited");

View File

@ -8,30 +8,32 @@ import { useSelector, useDispatch } from "react-redux";
import myStyle from "../style";
import {
changeEntranceMenu,
presentSelectKeys
presentSelectKeys,
} from "../../modules/entranceMenu";
import {
add_new_key_action,
log_in_and_import_backup,
add_and_restore_from_backup,
login_and_skip_action,
get_backup_info_action
get_backup_info_action,
} from "../../modules/message";
import { Paper, Grid } from "@material-ui/core";
import {
changeBackupView,
presentMain,
presentBackupInfo
presentBackupInfo,
setBackupInfo,
selectFilePath,
} from "../../modules/backup_state";
import { unix_to_short_date } from "../../util/utils";
import { Box } from "@material-ui/core";
const UIPart = props => {
const UIPart = (props) => {
const dispatch = useDispatch();
const classes = myStyle();
var words = useSelector(state => state.mnemonic_state.mnemonic_input);
var words = useSelector((state) => state.mnemonic_state.mnemonic_input);
var fingerprint = useSelector(
state => state.wallet_state.selected_fingerprint
(state) => state.wallet_state.selected_fingerprint
);
for (let word of words) {
@ -52,24 +54,23 @@ const UIPart = props => {
}
}
const handleDragEnter = e => {
const handleDragEnter = (e) => {
e.preventDefault();
e.stopPropagation();
};
const handleDragLeave = e => {
const handleDragLeave = (e) => {
e.preventDefault();
e.stopPropagation();
};
const handleDragOver = e => {
const handleDragOver = (e) => {
e.preventDefault();
e.stopPropagation();
};
const handleDrop = e => {
const handleDrop = (e) => {
e.preventDefault();
e.stopPropagation();
const file_path = e.dataTransfer.files[0].path;
debugger;
if (fingerprint !== null) {
dispatch(get_backup_info_action(file_path, fingerprint, null));
} else if (words !== null) {
@ -90,10 +91,10 @@ const UIPart = props => {
</Container>
</div>
<div
onDrop={e => handleDrop(e)}
onDragOver={e => handleDragOver(e)}
onDragEnter={e => handleDragEnter(e)}
onDragLeave={e => handleDragLeave(e)}
onDrop={(e) => handleDrop(e)}
onDragOver={(e) => handleDragOver(e)}
onDragEnter={(e) => handleDragEnter(e)}
onDragLeave={(e) => handleDragLeave(e)}
className={classes.dragContainer}
>
<Paper
@ -125,16 +126,23 @@ const UIPart = props => {
const BackupDetails = () => {
const classes = myStyle();
const dispatch = useDispatch();
const file_path = useSelector(state => state.backup_state.selected_file_path);
const backup_info = useSelector(state => state.backup_state.backup_info);
const file_path = useSelector(
(state) => state.backup_state.selected_file_path
);
const backup_info = useSelector((state) => state.backup_state.backup_info);
const selected_file_path = useSelector(
(state) => state.backup_state.selected_file_path
);
const date = unix_to_short_date(backup_info["timestamp"]);
const backup_fingerprint = backup_info["fingerprint"];
const version = backup_info["version"];
const wallets = backup_info["wallets"];
const downloaded = backup_info["downloaded"];
const host = backup_info["backup_host"];
var words = useSelector(state => state.mnemonic_state.mnemonic_input);
var words = useSelector((state) => state.mnemonic_state.mnemonic_input);
var fingerprint = useSelector(
state => state.wallet_state.selected_fingerprint
(state) => state.wallet_state.selected_fingerprint
);
for (let word of words) {
@ -148,6 +156,12 @@ const BackupDetails = () => {
dispatch(changeEntranceMenu(presentSelectKeys));
}
function goBackBackup() {
dispatch(changeBackupView(presentMain));
dispatch(setBackupInfo({}));
dispatch(selectFilePath(null));
}
function next() {
if (fingerprint !== null) {
dispatch(log_in_and_import_backup(fingerprint, file_path));
@ -175,10 +189,16 @@ const BackupDetails = () => {
position: "relative",
width: "80%",
margin: "auto",
padding: "20px"
padding: "20px",
}}
>
<Grid container spacing={0} style={{ marginBottom: 10 }}>
<ArrowBackIosIcon
style={{ cursor: "pointer" }}
onClick={goBackBackup}
>
{" "}
</ArrowBackIosIcon>
<Grid container spacing={3} style={{ marginBottom: 10 }}>
<Grid item xs={6}>
<Typography variant="subtitle1">Backup info:</Typography>
<Box display="flex" style={{ minWidth: "100%" }}>
@ -200,10 +220,26 @@ const BackupDetails = () => {
</Box>
</Box>
</Grid>
<Grid item xs={6}>
<Box display="flex" style={{ minWidth: "100%" }}>
<Box flexGrow={1}>Downloaded: </Box>
<Box className={classes.align_right} flexGrow={1}>
{downloaded + ""}
</Box>
</Box>
<Box display="flex" style={{ minWidth: "100%" }}>
<Box flexGrow={1}>
{downloaded ? "Backup Host:" : "File Path"}
</Box>
<Box className={classes.align_right} flexGrow={1}>
{downloaded ? host : selected_file_path}
</Box>
</Box>
</Grid>
</Grid>
<Typography variant="subtitle1">Smart wallets</Typography>
<WalletHeader></WalletHeader>
{wallets.map(wallet => (
{wallets.map((wallet) => (
<WalletRow wallet={wallet}></WalletRow>
))}
</Paper>
@ -227,7 +263,7 @@ const BackupDetails = () => {
);
};
const WalletRow = props => {
const WalletRow = (props) => {
const wallet = props.wallet;
const id = wallet.id;
const name = wallet.name;
@ -274,7 +310,7 @@ const WalletHeader = () => {
};
export const RestoreBackup = () => {
const view = useSelector(state => state.backup_state.view);
const view = useSelector((state) => state.backup_state.view);
if (view === presentBackupInfo) {
return <BackupDetails></BackupDetails>;
} else {

View File

@ -1,40 +1,40 @@
import { makeStyles } from "@material-ui/styles";
const myStyle = makeStyles(theme => ({
const myStyle = makeStyles((theme) => ({
root: {
background: "linear-gradient(45deg, #181818 30%, #333333 90%)",
height: "100%"
height: "100%",
},
paper: {
display: "flex",
flexDirection: "column",
alignItems: "center",
padding: theme.spacing(0)
padding: theme.spacing(0),
},
avatar: {
marginTop: theme.spacing(8),
backgroundColor: theme.palette.secondary.main
backgroundColor: theme.palette.secondary.main,
},
form: {
width: "100%", // Fix IE 11 issue.
marginTop: theme.spacing(5)
marginTop: theme.spacing(5),
},
textField: {
borderColor: "#ffffff"
borderColor: "#ffffff",
},
submit: {
marginTop: theme.spacing(8),
marginBottom: theme.spacing(3)
marginBottom: theme.spacing(3),
},
grid_wrap: {
paddingLeft: theme.spacing(10),
paddingRight: theme.spacing(10),
textAlign: "center"
textAlign: "center",
},
grid: {
display: "flex",
flexDirection: "column",
alignItems: "center"
alignItems: "center",
},
grid_item: {
padding: theme.spacing(1),
@ -44,17 +44,17 @@ const myStyle = makeStyles(theme => ({
alignItems: "center",
backgroundColor: "#444444",
color: "#ffffff",
height: 60
height: 60,
},
title: {
color: "#ffffff",
marginTop: theme.spacing(4),
marginBottom: theme.spacing(8)
marginBottom: theme.spacing(8),
},
titleSmallMargin: {
color: "#ffffff",
marginTop: theme.spacing(4),
marginBottom: theme.spacing(2)
marginBottom: theme.spacing(2),
},
navigator: {
color: "#ffffff",
@ -62,55 +62,56 @@ const myStyle = makeStyles(theme => ({
marginLeft: theme.spacing(4),
fontSize: 35,
flex: 1,
align: "right"
align: "right",
cursor: "pointer",
},
instructions: {
color: "#ffffff",
fontSize: 18
fontSize: 18,
},
dragContainer: {
paddingLeft: 20,
paddingRight: 20,
paddingBottom: 20
paddingBottom: 20,
},
drag: {
backgroundColor: "#aaaaaa",
height: 300,
width: "100%"
width: "100%",
},
dragText: {
margin: 0,
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)"
transform: "translate(-50%, -50%)",
},
circle: {
height: "100%",
display: "flex",
alignItems: "center",
justifyContent: "center"
justifyContent: "center",
},
logo: {
marginTop: theme.spacing(0),
marginBottom: theme.spacing(1)
marginBottom: theme.spacing(1),
},
whiteP: {
color: "white",
fontSize: "18px"
fontSize: "18px",
},
column_three: {
width: "33%"
width: "33%",
},
align_right: {
textAlign: "right"
textAlign: "right",
},
align_left: {
textAlign: "left"
textAlign: "left",
},
align_center: {
textAlign: "center"
}
textAlign: "center",
},
}));
export default myStyle;

View File

@ -21,8 +21,8 @@ from src.server.outbound_message import NodeType, OutboundMessage, Message, Deli
from src.simulator.simulator_protocol import FarmNewBlockProtocol
from src.util.ints import uint64, uint32
from src.wallet.trade_record import TradeRecord
from src.wallet.util.backup_utils import get_backup_info
from src.wallet.util.trade_utils import trade_record_to_dict
from src.wallet.util.backup_utils import get_backup_info, download_backup, upload_backup
from src.wallet.util.cc_utils import trade_record_to_dict
from src.wallet.util.wallet_types import WalletType
from src.wallet.rl_wallet.rl_wallet import RLWallet
from src.wallet.cc_wallet.cc_wallet import CCWallet
@ -335,9 +335,25 @@ class WalletRpcApi:
return response
async def create_backup_and_upload(self, host):
try:
now = time.time()
file_name = f"backup_{now}"
path = path_from_root(self.service.root_path, file_name)
await self.service.wallet_state_manager.create_wallet_backup(path)
backup_text = path.read_text()
response = await upload_backup(host, backup_text)
success = response["success"]
if success is False:
log.error("Failed to upload backup to wallet backup service")
elif success is True:
log.info("Finished upload of the backup file")
except BaseException as e:
log.error(f"Exception in upload backup. Error: {e}")
async def create_new_wallet(self, request):
config, wallet_state_manager, main_wallet = self.get_wallet_config()
host = request["host"]
if request["wallet_type"] == "cc_wallet":
if request["mode"] == "new":
try:
@ -345,6 +361,7 @@ class WalletRpcApi:
wallet_state_manager, main_wallet, request["amount"]
)
colour = cc_wallet.get_colour()
asyncio.ensure_future(self.create_backup_and_upload(host))
return {
"success": True,
"type": cc_wallet.wallet_info.type,
@ -359,6 +376,7 @@ class WalletRpcApi:
cc_wallet = await CCWallet.create_wallet_for_cc(
wallet_state_manager, main_wallet, request["colour"]
)
asyncio.ensure_future(self.create_backup_and_upload(host))
return {"success": True, "type": cc_wallet.wallet_info.type}
except Exception as e:
log.error("FAILED2 {e}")
@ -376,6 +394,7 @@ class WalletRpcApi:
request["pubkey"],
uint64(int(request["amount"])),
)
asyncio.ensure_future(self.create_backup_and_upload(host))
return {
"success": success,
"id": rl_admin.wallet_info.id,
@ -392,7 +411,7 @@ class WalletRpcApi:
rl_user: RLWallet = await RLWallet.create_rl_user(
wallet_state_manager
)
asyncio.ensure_future(self.create_backup_and_upload(host))
return {
"success": True,
"id": rl_user.wallet_info.id,
@ -657,6 +676,7 @@ class WalletRpcApi:
await self.stop_wallet()
fingerprint = request["fingerprint"]
type = request["type"]
recovery_host = request["host"]
if type == "skip":
started = await self.service._start(
@ -672,9 +692,26 @@ class WalletRpcApi:
if started is True:
return {"success": True}
else:
if self.service.backup_initialized is False:
return {"success": False, "error": "not_initialized"}
elif self.service.backup_initialized is False:
backup_info = None
backup_path = None
try:
private_key = self.service.get_key_for_fingerprint(fingerprint)
last_recovery = await download_backup(recovery_host, private_key)
backup_path = path_from_root(self.service.root_path, "last_recovery")
if backup_path.exists():
backup_path.unlink()
backup_path.write_text(last_recovery)
backup_info = get_backup_info(backup_path, private_key)
backup_info["backup_host"] = recovery_host
backup_info["downloaded"] = True
except BaseException as e:
log.error(f"error {e}")
response = {"success": False, "error": "not_initialized"}
if backup_info is not None:
response["backup_info"] = backup_info
response["backup_path"] = f"{backup_path}"
return response
return {"success": False, "error": "Unknown Error"}

View File

@ -1,7 +1,9 @@
import base64
import json
from typing import Any
from blspy import PublicKeyMPL, SignatureMPL, AugSchemeMPL
import aiohttp
from blspy import PublicKeyMPL, SignatureMPL, AugSchemeMPL, PrivateKey
from cryptography.fernet import Fernet
from src.util.byte_types import hexstr_to_bytes
@ -65,3 +67,49 @@ def get_backup_info(file_path, private_key):
info_dict["wallets"] = wallets
return info_dict
async def post(session: aiohttp.ClientSession, url: str, data: Any):
response = await session.post(url, json=data)
return await response.json()
async def get(session: aiohttp.ClientSession, url: str):
response = await session.get(url)
return await response.text()
async def upload_backup(host: str, backup_text: str):
request = {"backup": backup_text}
session = aiohttp.ClientSession()
nonce_url = f"{host}/upload_backup"
upload_response = await post(session, nonce_url, request)
return upload_response
async def download_backup(host: str, private_key: PrivateKey):
session = aiohttp.ClientSession()
backup_privkey = master_sk_to_backup_sk(private_key)
backup_pubkey = bytes(backup_privkey.get_g1()).hex()
# Get nonce
nonce_request = {"pubkey": backup_pubkey}
nonce_url = f"{host}/get_download_nonce"
nonce_response = await post(session, nonce_url, nonce_request)
nonce = nonce_response["nonce"]
# Sign nonce
signature = bytes(
AugSchemeMPL.sign(backup_privkey, std_hash(hexstr_to_bytes(nonce)))
).hex()
# Request backup url
get_backup_url = f"{host}/download_backup"
backup_request = {"pubkey": backup_pubkey, "signature": signature}
backup_response = await post(session, get_backup_url, backup_request)
# Download from s3
assert backup_response["success"] is True
backup_url = backup_response["url"]
backup_text = await get(session, backup_url)
return backup_text

View File

@ -115,19 +115,13 @@ class WalletNode:
self.sync_generator_task = None
self.server = None
async def _start(
self,
fingerprint: Optional[int] = None,
new_wallet: bool = False,
backup_file: Optional[Path] = None,
skip_backup_import: bool = False,
) -> bool:
def get_key_for_fingerprint(self, fingerprint):
private_keys = self.keychain.get_all_private_keys()
if len(private_keys) == 0:
self.log.warning(
"No keys present. Create keys with the UI, or with the 'chia keys' program."
)
return False
return None
private_key: Optional[PrivateKey] = None
if fingerprint is not None:
@ -137,7 +131,16 @@ class WalletNode:
break
else:
private_key = private_keys[0][0]
return private_key
async def _start(
self,
fingerprint: Optional[int] = None,
new_wallet: bool = False,
backup_file: Optional[Path] = None,
skip_backup_import: bool = False,
) -> bool:
private_key = self.get_key_for_fingerprint(fingerprint)
if private_key is None:
raise RuntimeError("Invalid fingerprint {public_key_fingerprint}")