Implemented key importing/generation for the GUI
This commit is contained in:
		
							
								
								
									
										155
									
								
								ethereal/assets/qml/first_run.qml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								ethereal/assets/qml/first_run.qml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,155 @@ | |||||||
|  | import QtQuick 2.0 | ||||||
|  | import Ethereum 1.0 | ||||||
|  |  | ||||||
|  | // Which ones do we actually need? | ||||||
|  | import QtQuick.Controls 1.0; | ||||||
|  | import QtQuick.Layouts 1.0; | ||||||
|  | import QtQuick.Dialogs 1.0; | ||||||
|  | import QtQuick.Window 2.1; | ||||||
|  | import QtQuick.Controls.Styles 1.1 | ||||||
|  | import QtQuick.Dialogs 1.1 | ||||||
|  |  | ||||||
|  | ApplicationWindow { | ||||||
|  |   id: wizardRoot | ||||||
|  |   width: 500 | ||||||
|  |   height: 400 | ||||||
|  |   title: "Ethereal first run setup" | ||||||
|  |  | ||||||
|  |   Column { | ||||||
|  |     spacing: 5 | ||||||
|  |     anchors.leftMargin: 10 | ||||||
|  |     anchors.left: parent.left | ||||||
|  |  | ||||||
|  |     Text { | ||||||
|  |       visible: true | ||||||
|  |       text: "<h2>Ethereal setup</h2>" | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Column { | ||||||
|  |       id: restoreColumn | ||||||
|  |       spacing: 5 | ||||||
|  |       Text { | ||||||
|  |         visible: true | ||||||
|  |         font.pointSize: 14 | ||||||
|  |         text: "Restore your Ethereum account" | ||||||
|  |         id: restoreLabel | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       TextField { | ||||||
|  |         id: txPrivKey | ||||||
|  |         width: 480 | ||||||
|  |         placeholderText: "Private key or mnemonic words" | ||||||
|  |         focus: true | ||||||
|  |         onTextChanged: { | ||||||
|  |           if(this.text.length == 64){ | ||||||
|  |             detailLabel.text = "Private (hex) key detected." | ||||||
|  |             actionButton.enabled = true | ||||||
|  |           } | ||||||
|  |           else if(this.text.split(" ").length == 24){ | ||||||
|  |             detailLabel.text = "Mnemonic key detected." | ||||||
|  |             actionButton.enabled = true | ||||||
|  |           }else{ | ||||||
|  |             detailLabel.text = "" | ||||||
|  |             actionButton.enabled = false | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       Row { | ||||||
|  |         spacing: 10 | ||||||
|  |         Button { | ||||||
|  |           id: actionButton | ||||||
|  |           text: "Restore" | ||||||
|  |           enabled: false | ||||||
|  |           onClicked: { | ||||||
|  |            var success = eth.importAndSetPrivKey(txPrivKey.text) | ||||||
|  |            if(success){ | ||||||
|  |              importedDetails.visible = true | ||||||
|  |              restoreColumn.visible = false | ||||||
|  |              newKey.visible = false | ||||||
|  |              wizardRoot.height = 120 | ||||||
|  |            } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |         Text { | ||||||
|  |           id: detailLabel | ||||||
|  |           font.pointSize: 12 | ||||||
|  |           anchors.topMargin: 10 | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     Column { | ||||||
|  |       id: importedDetails | ||||||
|  |       visible: false | ||||||
|  |       Text { | ||||||
|  |         text: "<b>Your account has been imported. Please close the application and restart it again to let the changes take effect.</b>" | ||||||
|  |         wrapMode: Text.WordWrap | ||||||
|  |         width: 460 | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     Column { | ||||||
|  |       spacing: 5 | ||||||
|  |       id: newDetailsColumn | ||||||
|  |       visible: false | ||||||
|  |       Text { | ||||||
|  |         font.pointSize: 14 | ||||||
|  |         text: "Your account details" | ||||||
|  |       } | ||||||
|  |       Label { | ||||||
|  |         text: "Address" | ||||||
|  |       } | ||||||
|  |       TextField { | ||||||
|  |         id: addressInput | ||||||
|  |         readOnly:true | ||||||
|  |         width: 480 | ||||||
|  |       } | ||||||
|  |       Label { | ||||||
|  |         text: "Private key" | ||||||
|  |       } | ||||||
|  |       TextField { | ||||||
|  |         id: privkeyInput | ||||||
|  |         readOnly:true | ||||||
|  |         width: 480 | ||||||
|  |       } | ||||||
|  |       Label { | ||||||
|  |         text: "Mnemonic words" | ||||||
|  |       } | ||||||
|  |       TextField { | ||||||
|  |         id: mnemonicInput | ||||||
|  |         readOnly:true | ||||||
|  |         width: 480 | ||||||
|  |       } | ||||||
|  |       Label { | ||||||
|  |         text: "<b>A new account has been created. Please take the time to write down the <i>24 words</i>. You can use those to restore your account at a later date.</b>" | ||||||
|  |         wrapMode: Text.WordWrap | ||||||
|  |         width: 480 | ||||||
|  |       } | ||||||
|  |       Label { | ||||||
|  |         text: "Please restart the application once you have completed the steps above." | ||||||
|  |         wrapMode: Text.WordWrap | ||||||
|  |         width: 480 | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   } | ||||||
|  |   Button { | ||||||
|  |     anchors.right: parent.right | ||||||
|  |     anchors.bottom: parent.bottom | ||||||
|  |     anchors.rightMargin: 10 | ||||||
|  |     anchors.bottomMargin: 10 | ||||||
|  |     id: newKey | ||||||
|  |     text: "I don't have an account yet" | ||||||
|  |     onClicked: { | ||||||
|  |       var res = eth.createAndSetPrivKey() | ||||||
|  |       mnemonicInput.text = res[0] | ||||||
|  |       addressInput.text = res[1] | ||||||
|  |       privkeyInput.text = res[2] | ||||||
|  |  | ||||||
|  |       // Hide restore | ||||||
|  |       restoreColumn.visible = false | ||||||
|  |  | ||||||
|  |       // Show new details | ||||||
|  |       newDetailsColumn.visible = true | ||||||
|  |       newKey.visible = false | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -25,6 +25,35 @@ ApplicationWindow { | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		Menu { | ||||||
|  | 			title: "Test" | ||||||
|  | 			MenuItem { | ||||||
|  | 				text: "Test test" | ||||||
|  | 				shortcut: "Ctrl+t" | ||||||
|  |         onTriggered: { | ||||||
|  |           var win | ||||||
|  |           function finishedLoading(){ | ||||||
|  |             console.log("Trigged") | ||||||
|  |             win = wizard.createObject(root) | ||||||
|  |           } | ||||||
|  |           console.log("Loading wizard") | ||||||
|  |  | ||||||
|  |           var wizard = Qt.createComponent("first_run.qml") | ||||||
|  |           if(wizard.status== Component.Ready){ | ||||||
|  |             console.log("Component is ready") | ||||||
|  |             finishedLoading() | ||||||
|  |           }else if( wizard.status == Component.Error){ | ||||||
|  |             console.log("Error loading component:", wizard.errorString()) | ||||||
|  |           } | ||||||
|  |           else{ | ||||||
|  |             wizard.statusChanged.connect(finishedLoading) | ||||||
|  |             console.log("Component is NOT ready") | ||||||
|  |             win = wizard.createObject(root) | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		Menu { | 		Menu { | ||||||
| 			title: "Network" | 			title: "Network" | ||||||
| 			MenuItem { | 			MenuItem { | ||||||
|   | |||||||
| @@ -84,8 +84,6 @@ func main() { | |||||||
| 				utils.ImportPrivateKey(ImportKey) | 				utils.ImportPrivateKey(ImportKey) | ||||||
| 				os.Exit(0) | 				os.Exit(0) | ||||||
| 			} | 			} | ||||||
| 		} else { |  | ||||||
| 			utils.CreateKeyPair(false) |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -53,7 +53,6 @@ type Gui struct { | |||||||
| 	txDb *ethdb.LDBDatabase | 	txDb *ethdb.LDBDatabase | ||||||
|  |  | ||||||
| 	addr []byte | 	addr []byte | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // Create GUI, but doesn't start it | // Create GUI, but doesn't start it | ||||||
| @@ -64,10 +63,16 @@ func New(ethereum *eth.Ethereum) *Gui { | |||||||
| 		panic(err) | 		panic(err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	key := ethutil.Config.Db.GetKeys()[0] | 	data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) | ||||||
| 	addr := key.Address() | 	// On first run we won't have any keys yet, so this would crash. | ||||||
|  | 	// Therefor we check if we are ready to actually start this process | ||||||
|  | 	var addr []byte | ||||||
|  | 	if len(data) > 0 { | ||||||
|  | 		key := ethutil.Config.Db.GetKeys()[0] | ||||||
|  | 		addr = key.Address() | ||||||
|  |  | ||||||
| 	ethereum.StateManager().WatchAddr(addr) | 		ethereum.StateManager().WatchAddr(addr) | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	return &Gui{eth: ethereum, lib: lib, txDb: db, addr: addr} | 	return &Gui{eth: ethereum, lib: lib, txDb: db, addr: addr} | ||||||
| } | } | ||||||
| @@ -94,9 +99,18 @@ func (ui *Gui) Start(assetPath string) { | |||||||
| 	context.SetVar("ui", uiLib) | 	context.SetVar("ui", uiLib) | ||||||
|  |  | ||||||
| 	// Load the main QML interface | 	// Load the main QML interface | ||||||
| 	component, err := ui.engine.LoadFile(uiLib.AssetPath("qml/wallet.qml")) | 	data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) | ||||||
|  | 	var err error | ||||||
|  | 	var component qml.Object | ||||||
|  | 	firstRun := len(data) == 0 | ||||||
|  |  | ||||||
|  | 	if firstRun { | ||||||
|  | 		component, err = ui.engine.LoadFile(uiLib.AssetPath("qml/first_run.qml")) | ||||||
|  | 	} else { | ||||||
|  | 		component, err = ui.engine.LoadFile(uiLib.AssetPath("qml/wallet.qml")) | ||||||
|  | 	} | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|    	ethutil.Config.Log.Infoln("FATAL: asset not found: you can set an alternative asset path on on the command line using option 'asset_path'") | 		ethutil.Config.Log.Infoln("FATAL: asset not found: you can set an alternative asset path on on the command line using option 'asset_path'") | ||||||
| 		panic(err) | 		panic(err) | ||||||
| 	} | 	} | ||||||
| 	ui.engine.LoadFile(uiLib.AssetPath("qml/transactions.qml")) | 	ui.engine.LoadFile(uiLib.AssetPath("qml/transactions.qml")) | ||||||
| @@ -111,9 +125,11 @@ func (ui *Gui) Start(assetPath string) { | |||||||
| 	ethutil.Config.Log.AddLogSystem(ui) | 	ethutil.Config.Log.AddLogSystem(ui) | ||||||
|  |  | ||||||
| 	// Loads previous blocks | 	// Loads previous blocks | ||||||
| 	go ui.setInitialBlockChain() | 	if firstRun == false { | ||||||
| 	go ui.readPreviousTransactions() | 		go ui.setInitialBlockChain() | ||||||
| 	go ui.update() | 		go ui.readPreviousTransactions() | ||||||
|  | 		go ui.update() | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	ui.win.Show() | 	ui.win.Show() | ||||||
| 	ui.win.Wait() | 	ui.win.Wait() | ||||||
|   | |||||||
| @@ -5,7 +5,9 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"github.com/ethereum/eth-go/ethchain" | 	"github.com/ethereum/eth-go/ethchain" | ||||||
| 	"github.com/ethereum/eth-go/ethutil" | 	"github.com/ethereum/eth-go/ethutil" | ||||||
|  | 	"github.com/ethereum/go-ethereum/utils" | ||||||
| 	"github.com/obscuren/mutan" | 	"github.com/obscuren/mutan" | ||||||
|  | 	"github.com/obscuren/secp256k1-go" | ||||||
| 	"strings" | 	"strings" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -15,6 +17,32 @@ type EthLib struct { | |||||||
| 	txPool       *ethchain.TxPool | 	txPool       *ethchain.TxPool | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (lib *EthLib) ImportAndSetPrivKey(privKey string) bool { | ||||||
|  | 	fmt.Println(privKey) | ||||||
|  | 	mnemonic := strings.Split(privKey, " ") | ||||||
|  | 	if len(mnemonic) == 24 { | ||||||
|  | 		fmt.Println("Got mnemonic key, importing.") | ||||||
|  | 		key := ethutil.MnemonicDecode(mnemonic) | ||||||
|  | 		utils.ImportPrivateKey(key) | ||||||
|  | 	} else if len(mnemonic) == 1 { | ||||||
|  | 		fmt.Println("Got hex key, importing.") | ||||||
|  | 		utils.ImportPrivateKey(privKey) | ||||||
|  | 	} else { | ||||||
|  | 		fmt.Println("Did not recognise format, exiting.") | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (lib *EthLib) CreateAndSetPrivKey() (string, string, string, string) { | ||||||
|  | 	pub, prv := secp256k1.GenerateKeyPair() | ||||||
|  | 	pair := ðutil.Key{PrivateKey: prv, PublicKey: pub} | ||||||
|  | 	ethutil.Config.Db.Put([]byte("KeyRing"), pair.RlpEncode()) | ||||||
|  | 	mne := ethutil.MnemonicEncode(ethutil.Hex(prv)) | ||||||
|  | 	mnemonicString := strings.Join(mne, " ") | ||||||
|  | 	return mnemonicString, fmt.Sprintf("%x", pair.Address()), fmt.Sprintf("%x", prv), fmt.Sprintf("%x", pub) | ||||||
|  | } | ||||||
|  |  | ||||||
| func (lib *EthLib) CreateTx(recipient, valueStr, gasStr, gasPriceStr, data string) (string, error) { | func (lib *EthLib) CreateTx(recipient, valueStr, gasStr, gasPriceStr, data string) (string, error) { | ||||||
| 	var hash []byte | 	var hash []byte | ||||||
| 	var contractCreation bool | 	var contractCreation bool | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user