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 = { const config = {
local_test: false local_test: false,
backup_host: "https://backup.chia.net",
}; };
module.exports = config; module.exports = config;

View File

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

View File

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

View File

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

View File

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

View File

@ -1,40 +1,40 @@
import { makeStyles } from "@material-ui/styles"; import { makeStyles } from "@material-ui/styles";
const myStyle = makeStyles(theme => ({ const myStyle = makeStyles((theme) => ({
root: { root: {
background: "linear-gradient(45deg, #181818 30%, #333333 90%)", background: "linear-gradient(45deg, #181818 30%, #333333 90%)",
height: "100%" height: "100%",
}, },
paper: { paper: {
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
alignItems: "center", alignItems: "center",
padding: theme.spacing(0) padding: theme.spacing(0),
}, },
avatar: { avatar: {
marginTop: theme.spacing(8), marginTop: theme.spacing(8),
backgroundColor: theme.palette.secondary.main backgroundColor: theme.palette.secondary.main,
}, },
form: { form: {
width: "100%", // Fix IE 11 issue. width: "100%", // Fix IE 11 issue.
marginTop: theme.spacing(5) marginTop: theme.spacing(5),
}, },
textField: { textField: {
borderColor: "#ffffff" borderColor: "#ffffff",
}, },
submit: { submit: {
marginTop: theme.spacing(8), marginTop: theme.spacing(8),
marginBottom: theme.spacing(3) marginBottom: theme.spacing(3),
}, },
grid_wrap: { grid_wrap: {
paddingLeft: theme.spacing(10), paddingLeft: theme.spacing(10),
paddingRight: theme.spacing(10), paddingRight: theme.spacing(10),
textAlign: "center" textAlign: "center",
}, },
grid: { grid: {
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
alignItems: "center" alignItems: "center",
}, },
grid_item: { grid_item: {
padding: theme.spacing(1), padding: theme.spacing(1),
@ -44,17 +44,17 @@ const myStyle = makeStyles(theme => ({
alignItems: "center", alignItems: "center",
backgroundColor: "#444444", backgroundColor: "#444444",
color: "#ffffff", color: "#ffffff",
height: 60 height: 60,
}, },
title: { title: {
color: "#ffffff", color: "#ffffff",
marginTop: theme.spacing(4), marginTop: theme.spacing(4),
marginBottom: theme.spacing(8) marginBottom: theme.spacing(8),
}, },
titleSmallMargin: { titleSmallMargin: {
color: "#ffffff", color: "#ffffff",
marginTop: theme.spacing(4), marginTop: theme.spacing(4),
marginBottom: theme.spacing(2) marginBottom: theme.spacing(2),
}, },
navigator: { navigator: {
color: "#ffffff", color: "#ffffff",
@ -62,55 +62,56 @@ const myStyle = makeStyles(theme => ({
marginLeft: theme.spacing(4), marginLeft: theme.spacing(4),
fontSize: 35, fontSize: 35,
flex: 1, flex: 1,
align: "right" align: "right",
cursor: "pointer",
}, },
instructions: { instructions: {
color: "#ffffff", color: "#ffffff",
fontSize: 18 fontSize: 18,
}, },
dragContainer: { dragContainer: {
paddingLeft: 20, paddingLeft: 20,
paddingRight: 20, paddingRight: 20,
paddingBottom: 20 paddingBottom: 20,
}, },
drag: { drag: {
backgroundColor: "#aaaaaa", backgroundColor: "#aaaaaa",
height: 300, height: 300,
width: "100%" width: "100%",
}, },
dragText: { dragText: {
margin: 0, margin: 0,
position: "absolute", position: "absolute",
top: "50%", top: "50%",
left: "50%", left: "50%",
transform: "translate(-50%, -50%)" transform: "translate(-50%, -50%)",
}, },
circle: { circle: {
height: "100%", height: "100%",
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
justifyContent: "center" justifyContent: "center",
}, },
logo: { logo: {
marginTop: theme.spacing(0), marginTop: theme.spacing(0),
marginBottom: theme.spacing(1) marginBottom: theme.spacing(1),
}, },
whiteP: { whiteP: {
color: "white", color: "white",
fontSize: "18px" fontSize: "18px",
}, },
column_three: { column_three: {
width: "33%" width: "33%",
}, },
align_right: { align_right: {
textAlign: "right" textAlign: "right",
}, },
align_left: { align_left: {
textAlign: "left" textAlign: "left",
}, },
align_center: { align_center: {
textAlign: "center" textAlign: "center",
} },
})); }));
export default myStyle; 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.simulator.simulator_protocol import FarmNewBlockProtocol
from src.util.ints import uint64, uint32 from src.util.ints import uint64, uint32
from src.wallet.trade_record import TradeRecord from src.wallet.trade_record import TradeRecord
from src.wallet.util.backup_utils import get_backup_info from src.wallet.util.backup_utils import get_backup_info, download_backup, upload_backup
from src.wallet.util.trade_utils import trade_record_to_dict from src.wallet.util.cc_utils import trade_record_to_dict
from src.wallet.util.wallet_types import WalletType from src.wallet.util.wallet_types import WalletType
from src.wallet.rl_wallet.rl_wallet import RLWallet from src.wallet.rl_wallet.rl_wallet import RLWallet
from src.wallet.cc_wallet.cc_wallet import CCWallet from src.wallet.cc_wallet.cc_wallet import CCWallet
@ -335,9 +335,25 @@ class WalletRpcApi:
return response 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): async def create_new_wallet(self, request):
config, wallet_state_manager, main_wallet = self.get_wallet_config() config, wallet_state_manager, main_wallet = self.get_wallet_config()
host = request["host"]
if request["wallet_type"] == "cc_wallet": if request["wallet_type"] == "cc_wallet":
if request["mode"] == "new": if request["mode"] == "new":
try: try:
@ -345,6 +361,7 @@ class WalletRpcApi:
wallet_state_manager, main_wallet, request["amount"] wallet_state_manager, main_wallet, request["amount"]
) )
colour = cc_wallet.get_colour() colour = cc_wallet.get_colour()
asyncio.ensure_future(self.create_backup_and_upload(host))
return { return {
"success": True, "success": True,
"type": cc_wallet.wallet_info.type, "type": cc_wallet.wallet_info.type,
@ -359,6 +376,7 @@ class WalletRpcApi:
cc_wallet = await CCWallet.create_wallet_for_cc( cc_wallet = await CCWallet.create_wallet_for_cc(
wallet_state_manager, main_wallet, request["colour"] 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} return {"success": True, "type": cc_wallet.wallet_info.type}
except Exception as e: except Exception as e:
log.error("FAILED2 {e}") log.error("FAILED2 {e}")
@ -376,6 +394,7 @@ class WalletRpcApi:
request["pubkey"], request["pubkey"],
uint64(int(request["amount"])), uint64(int(request["amount"])),
) )
asyncio.ensure_future(self.create_backup_and_upload(host))
return { return {
"success": success, "success": success,
"id": rl_admin.wallet_info.id, "id": rl_admin.wallet_info.id,
@ -392,7 +411,7 @@ class WalletRpcApi:
rl_user: RLWallet = await RLWallet.create_rl_user( rl_user: RLWallet = await RLWallet.create_rl_user(
wallet_state_manager wallet_state_manager
) )
asyncio.ensure_future(self.create_backup_and_upload(host))
return { return {
"success": True, "success": True,
"id": rl_user.wallet_info.id, "id": rl_user.wallet_info.id,
@ -657,6 +676,7 @@ class WalletRpcApi:
await self.stop_wallet() await self.stop_wallet()
fingerprint = request["fingerprint"] fingerprint = request["fingerprint"]
type = request["type"] type = request["type"]
recovery_host = request["host"]
if type == "skip": if type == "skip":
started = await self.service._start( started = await self.service._start(
@ -672,9 +692,26 @@ class WalletRpcApi:
if started is True: if started is True:
return {"success": True} return {"success": True}
else: elif self.service.backup_initialized is False:
if self.service.backup_initialized is False: backup_info = None
return {"success": False, "error": "not_initialized"} 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"} return {"success": False, "error": "Unknown Error"}

View File

@ -1,7 +1,9 @@
import base64 import base64
import json 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 cryptography.fernet import Fernet
from src.util.byte_types import hexstr_to_bytes 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 info_dict["wallets"] = wallets
return info_dict 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.sync_generator_task = None
self.server = None self.server = None
async def _start( def get_key_for_fingerprint(self, fingerprint):
self,
fingerprint: Optional[int] = None,
new_wallet: bool = False,
backup_file: Optional[Path] = None,
skip_backup_import: bool = False,
) -> bool:
private_keys = self.keychain.get_all_private_keys() private_keys = self.keychain.get_all_private_keys()
if len(private_keys) == 0: if len(private_keys) == 0:
self.log.warning( self.log.warning(
"No keys present. Create keys with the UI, or with the 'chia keys' program." "No keys present. Create keys with the UI, or with the 'chia keys' program."
) )
return False return None
private_key: Optional[PrivateKey] = None private_key: Optional[PrivateKey] = None
if fingerprint is not None: if fingerprint is not None:
@ -137,7 +131,16 @@ class WalletNode:
break break
else: else:
private_key = private_keys[0][0] 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: if private_key is None:
raise RuntimeError("Invalid fingerprint {public_key_fingerprint}") raise RuntimeError("Invalid fingerprint {public_key_fingerprint}")