This commit is contained in:
parent
02a3770803
commit
69e498dc00
|
@ -34,7 +34,9 @@ const
|
||||||
"../vendor/nimbus-security-resources/passwords/10-million-password-list-top-100000.txt",
|
"../vendor/nimbus-security-resources/passwords/10-million-password-list-top-100000.txt",
|
||||||
minWordLen = minPasswordLen)
|
minWordLen = minPasswordLen)
|
||||||
|
|
||||||
template echo80(msg: string) =
|
proc echoP(msg: string) =
|
||||||
|
## Prints a paragraph aligned to 80 columns
|
||||||
|
echo ""
|
||||||
echo wrapWords(msg, 80)
|
echo wrapWords(msg, 80)
|
||||||
|
|
||||||
proc checkAndCreateDataDir*(dataDir: string): bool =
|
proc checkAndCreateDataDir*(dataDir: string): bool =
|
||||||
|
@ -129,15 +131,18 @@ proc keyboardCreatePassword(prompt: string, confirm: string): KsResult[string] =
|
||||||
# We treat `password` as UTF-8 encoded string.
|
# We treat `password` as UTF-8 encoded string.
|
||||||
if validateUtf8(password) == -1:
|
if validateUtf8(password) == -1:
|
||||||
if runeLen(password) < minPasswordLen:
|
if runeLen(password) < minPasswordLen:
|
||||||
echo80 "The entered password should be at least " & $minPasswordLen &
|
echoP "The entered password should be at least " & $minPasswordLen &
|
||||||
" characters."
|
" characters."
|
||||||
|
echo ""
|
||||||
continue
|
continue
|
||||||
elif password in mostCommonPasswords:
|
elif password in mostCommonPasswords:
|
||||||
echo80 "The entered password is too commonly used and it would be " &
|
echoP "The entered password is too commonly used and it would be " &
|
||||||
"easy to brute-force with automated tools."
|
"easy to brute-force with automated tools."
|
||||||
|
echo ""
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
echo80 "Entered password is not valid UTF-8 string"
|
echoP "Entered password is not valid UTF-8 string"
|
||||||
|
echo ""
|
||||||
continue
|
continue
|
||||||
|
|
||||||
let confirmedPassword =
|
let confirmedPassword =
|
||||||
|
@ -148,7 +153,7 @@ proc keyboardCreatePassword(prompt: string, confirm: string): KsResult[string] =
|
||||||
return err("Could not read password from stdin")
|
return err("Could not read password from stdin")
|
||||||
|
|
||||||
if password != confirmedPassword:
|
if password != confirmedPassword:
|
||||||
echo "Passwords don't match, please try again"
|
echo "Passwords don't match, please try again\n"
|
||||||
continue
|
continue
|
||||||
|
|
||||||
return ok(password)
|
return ok(password)
|
||||||
|
@ -539,11 +544,10 @@ template ask(prompt: string): string =
|
||||||
proc pickPasswordAndSaveWallet(rng: var BrHmacDrbgContext,
|
proc pickPasswordAndSaveWallet(rng: var BrHmacDrbgContext,
|
||||||
config: BeaconNodeConf,
|
config: BeaconNodeConf,
|
||||||
mnemonic: Mnemonic): Result[WalletPathPair, string] =
|
mnemonic: Mnemonic): Result[WalletPathPair, string] =
|
||||||
echo ""
|
echoP "When you perform operations with your wallet such as withdrawals " &
|
||||||
echo80 "When you perform operations with your wallet such as withdrawals " &
|
"and additional deposits, you'll be asked to enter a password. " &
|
||||||
"and additional deposits, you'll be asked to enter a password. " &
|
"Please note that this password is local to the current machine " &
|
||||||
"Please note that this password is local to the current Nimbus " &
|
"and you can change it at any time."
|
||||||
"installation and can be changed at any time."
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
var password =
|
var password =
|
||||||
|
@ -561,10 +565,9 @@ proc pickPasswordAndSaveWallet(rng: var BrHmacDrbgContext,
|
||||||
if outWalletName.isSome:
|
if outWalletName.isSome:
|
||||||
name = outWalletName.get
|
name = outWalletName.get
|
||||||
else:
|
else:
|
||||||
echo ""
|
echoP "For your convenience, the wallet can be identified with a name " &
|
||||||
echo80 "For your convenience, the wallet can be identified with a name " &
|
"of your choice. Please enter a wallet name below or press ENTER " &
|
||||||
"of your choice. Please enter a wallet name below or press ENTER " &
|
"to continue with a machine-generated name."
|
||||||
"to continue with a machine-generated name."
|
|
||||||
|
|
||||||
while true:
|
while true:
|
||||||
var enteredName = ask "Wallet name"
|
var enteredName = ask "Wallet name"
|
||||||
|
@ -577,30 +580,38 @@ proc pickPasswordAndSaveWallet(rng: var BrHmacDrbgContext,
|
||||||
continue
|
continue
|
||||||
break
|
break
|
||||||
|
|
||||||
let nextAccount =
|
let nextAccount =
|
||||||
if config.cmd == wallets and config.walletsCmd == WalletsCmd.restore:
|
if config.cmd == wallets and config.walletsCmd == WalletsCmd.restore:
|
||||||
config.restoredDepositsCount
|
config.restoredDepositsCount
|
||||||
else:
|
else:
|
||||||
none Natural
|
none Natural
|
||||||
|
|
||||||
let wallet = createWallet(kdfPbkdf2, rng, mnemonic,
|
let wallet = createWallet(kdfPbkdf2, rng, mnemonic,
|
||||||
name = name,
|
name = name,
|
||||||
nextAccount = nextAccount,
|
nextAccount = nextAccount,
|
||||||
password = KeystorePass.init password)
|
password = KeystorePass.init password)
|
||||||
|
|
||||||
let outWalletFileFlag = config.outWalletFile
|
let outWalletFileFlag = config.outWalletFile
|
||||||
let outWalletFile =
|
let outWalletFile =
|
||||||
if outWalletFileFlag.isSome:
|
if outWalletFileFlag.isSome:
|
||||||
string outWalletFileFlag.get
|
string outWalletFileFlag.get
|
||||||
else:
|
else:
|
||||||
config.walletsDir / addFileExt(string wallet.name, "json")
|
config.walletsDir / addFileExt(string wallet.name, "json")
|
||||||
|
|
||||||
let status = saveWallet(wallet, outWalletFile)
|
let status = saveWallet(wallet, outWalletFile)
|
||||||
if status.isErr:
|
if status.isErr:
|
||||||
return err("failure to create wallet file due to " & status.error)
|
return err("failure to create wallet file due to " & status.error)
|
||||||
|
|
||||||
echo "\nWallet file successfully written to \"", outWalletFile, "\""
|
echo "\nWallet file successfully written to \"", outWalletFile, "\""
|
||||||
return ok WalletPathPair(wallet: wallet, path: outWalletFile)
|
return ok WalletPathPair(wallet: wallet, path: outWalletFile)
|
||||||
|
|
||||||
|
proc safeEraseScreen() =
|
||||||
|
try:
|
||||||
|
stdout.eraseScreen
|
||||||
|
except IOError:
|
||||||
|
discard
|
||||||
|
|
||||||
|
discard execShellCmd(when defined(windows): "cls" else: "clear")
|
||||||
|
|
||||||
proc createWalletInteractively*(
|
proc createWalletInteractively*(
|
||||||
rng: var BrHmacDrbgContext,
|
rng: var BrHmacDrbgContext,
|
||||||
|
@ -609,40 +620,74 @@ proc createWalletInteractively*(
|
||||||
if config.nonInteractive:
|
if config.nonInteractive:
|
||||||
return err "not running in interactive mode"
|
return err "not running in interactive mode"
|
||||||
|
|
||||||
|
echoP "The generated wallet is uniquely identified by a seed phrase " &
|
||||||
|
"consisting of 24 words. In case you lose your wallet and you " &
|
||||||
|
"need to restore it on a different machine, you can use the " &
|
||||||
|
"seed phrase to re-generate your signing and withdrawal keys."
|
||||||
|
echoP "The seed phrase should be kept secretly in a safe location as if " &
|
||||||
|
"you are protecting a sensitive password. It can be used to withdraw " &
|
||||||
|
"funds from your wallet."
|
||||||
|
echoP "We will display the seed phrase on the next screen. Please make sure " &
|
||||||
|
"you are in a safe environment and there are no cameras or potentially " &
|
||||||
|
"unwanted eye witnesses around you. Please prepare everything necessary " &
|
||||||
|
"to copy the seed phrase to a safe location and type 'continue' in " &
|
||||||
|
"the prompt below to proceed to the next screen or 'q' to exit now."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
while true:
|
||||||
|
let answer = ask "Action"
|
||||||
|
if answer.len > 0 and answer[0] == 'q': quit 1
|
||||||
|
if answer == "continue": break
|
||||||
|
echoP "To proceed to your seed phrase, please type 'continue' (without the quotes). " &
|
||||||
|
"Type 'q' to exit now."
|
||||||
|
echo ""
|
||||||
|
|
||||||
var mnemonic = generateMnemonic(rng)
|
var mnemonic = generateMnemonic(rng)
|
||||||
defer: burnMem(mnemonic)
|
defer: burnMem(mnemonic)
|
||||||
|
|
||||||
echo80 "The generated wallet is uniquely identified by a seed phrase " &
|
|
||||||
"consisting of 24 words. In case you lose your wallet and you " &
|
|
||||||
"need to restore it on a different machine, you must use the " &
|
|
||||||
"words displayed below:"
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
echo ""
|
echoP "Your seed phrase is:"
|
||||||
setStyleNoError({styleBright})
|
setStyleNoError({styleBright})
|
||||||
setForegroundColorNoError fgCyan
|
setForegroundColorNoError fgCyan
|
||||||
echo80 $mnemonic
|
echoP $mnemonic
|
||||||
resetAttributesNoError()
|
resetAttributesNoError()
|
||||||
echo ""
|
|
||||||
except IOError, ValueError:
|
except IOError, ValueError:
|
||||||
return err "failure to write to the standard output"
|
return err "failure to write to the standard output"
|
||||||
|
|
||||||
echo80 "Please back up the seed phrase now to a safe location as " &
|
echoP "Press any key to continue."
|
||||||
"if you are protecting a sensitive password. The seed phrase " &
|
try:
|
||||||
"can be used to withdraw funds from your wallet."
|
discard stdin.readChar()
|
||||||
|
except IOError as err:
|
||||||
|
fatal "Failed to read a key from stdin", err = err.msg
|
||||||
|
quit 1
|
||||||
|
|
||||||
|
safeEraseScreen()
|
||||||
|
|
||||||
|
echoP "To confirm that you've saved the seed phrase, please enter the first and the " &
|
||||||
|
"last three words of it. In case you've saved the seek phrase in your clipboard, " &
|
||||||
|
"we strongly advice clearing the clipboard now."
|
||||||
echo ""
|
echo ""
|
||||||
echo "Did you back up your seed recovery phrase?\p" &
|
|
||||||
"(please type 'yes' to continue or press enter to quit)"
|
|
||||||
|
|
||||||
while true:
|
for i in countdown(2, 0):
|
||||||
let answer = ask "Answer"
|
let answer = ask "Answer"
|
||||||
if answer == "":
|
let parts = answer.split(' ', maxsplit = 1)
|
||||||
return err "aborted wallet creation"
|
if parts.len == 2:
|
||||||
elif answer != "yes":
|
if count(parts[1], ' ') == 2 and
|
||||||
echo "To continue, please type 'yes' (without the quotes) or press enter to quit"
|
mnemonic.string.startsWith(parts[0]) and
|
||||||
|
mnemonic.string.endsWith(parts[1]):
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
break
|
doAssert parts.len == 1
|
||||||
|
|
||||||
|
if i > 0:
|
||||||
|
echo "\nYour answer was not correct. You have ", i, " more attempts"
|
||||||
|
echoP "Please enter 4 words separated with a single space " &
|
||||||
|
"(the first word from the seed phrase, followed by the last 3)"
|
||||||
|
echo ""
|
||||||
|
else:
|
||||||
|
quit 1
|
||||||
|
|
||||||
|
safeEraseScreen()
|
||||||
|
|
||||||
let walletPath = ? pickPasswordAndSaveWallet(rng, config, mnemonic)
|
let walletPath = ? pickPasswordAndSaveWallet(rng, config, mnemonic)
|
||||||
return ok CreatedWallet(walletPath: walletPath, mnemonic: mnemonic)
|
return ok CreatedWallet(walletPath: walletPath, mnemonic: mnemonic)
|
||||||
|
|
Loading…
Reference in New Issue