Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add mnemonic sentence support #975

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cardano-cli/cardano-cli.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ library
exceptions,
filepath,
formatting,
haskeline,
http-client,
http-client-tls,
http-types,
Expand Down
5 changes: 3 additions & 2 deletions cardano-cli/src/Cardano/CLI/Commands/Key.hs
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,9 @@ data KeyExtendedSigningKeyFromMnemonicArgs = KeyExtendedSigningKeyFromMnemonicAr
}
deriving Show

newtype MnemonicSource
= MnemonicFromFile (File () In)
data MnemonicSource
= MnemonicFromFile !(File () In)
| MnemonicFromInteractivePrompt
deriving Show

data ExtendedSigningType
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DerivedExtendedSigningKeyType?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A comment saying something like "This is the key derived from the mnemonic"

Expand Down
5 changes: 5 additions & 0 deletions cardano-cli/src/Cardano/CLI/Options/Key.hs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,11 @@ pMnemonicSource :: Parser MnemonicSource
pMnemonicSource =
asum
[ MnemonicFromFile . File <$> parseFilePath "mnemonic-from-file" "Input text file with the mnemonic."
, Opt.flag' MnemonicFromInteractivePrompt $
mconcat
[ Opt.long "mnemonic-from-interactive-prompt"
, Opt.help "Input the mnemonic through an interactive prompt."
]
]

pPaymentAddressNumber :: Parser Word32
Expand Down
61 changes: 57 additions & 4 deletions cardano-cli/src/Cardano/CLI/Run/Key.hs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those new additions are quite large so I'd suggest adding a new module for them. For example:
cardano-cli/src/Cardano/CLI/Run/Key/Mnemonic.hs

Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import qualified Cardano.Crypto.Signing as Byron
import qualified Cardano.Crypto.Signing as Byron.Crypto
import qualified Cardano.Crypto.Signing as Crypto
import qualified Cardano.Crypto.Wallet as Crypto
import Cardano.Prelude (isSpace)

import qualified Codec.Binary.Bech32 as Bech32
import qualified Control.Exception as Exception
Expand All @@ -60,6 +61,10 @@ import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text as Text
import qualified Data.Text.Encoding as Text
import System.Console.Haskeline (Completion, InputT, Settings (..), completeWord',
defaultBehavior, defaultPrefs, getInputLineWithInitial,
runInputTBehaviorWithPrefs, simpleCompletion)
import System.Console.Haskeline.Completion (CompletionFunc)
import System.Exit (exitFailure)

-- Note on these constants:
Expand Down Expand Up @@ -317,10 +322,58 @@ runExtendedSigningKeyFromMnemonicCmd
writeTextFile sKeyPath $
serialiseToBech32 skey

readMnemonic :: Cmd.MnemonicSource -> ExceptT KeyCmdError IO [Text]
readMnemonic (Cmd.MnemonicFromFile filePath) = do
fileText <- firstExceptT KeyCmdReadMnemonicFileError $ except =<< readTextFile filePath
return $ map T.pack $ words $ T.unpack fileText
readMnemonic :: Cmd.MnemonicSource -> ExceptT KeyCmdError IO [Text]
readMnemonic (Cmd.MnemonicFromFile filePath) = do
fileText <- firstExceptT KeyCmdReadMnemonicFileError $ except =<< readTextFile filePath
return $ map T.pack $ words $ T.unpack fileText
readMnemonic Cmd.MnemonicFromInteractivePrompt =
liftIO $ do
putStrLn ""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unlines would be a good refactor here

putStrLn "Please enter your mnemonic sentence."
putStrLn ""
putStrLn " - It should consist of either: 12, 15, 18, 21, or 24 words."
putStrLn " - To terminate, press enter on an empty line."
putStrLn " - To abort you can press CTRL+C."
putStrLn ""
putStrLn "(If your terminal supports it, you can use the TAB key for word completion.)"
putStrLn ""
runInputTBehaviorWithPrefs defaultBehavior defaultPrefs settings (inputT ("", "") [])
Comment on lines +331 to +340
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks cool. Can we support non-interactive senario with reading of mnemonic from stdin here? I imagine the following example, when someone stores their mnemonic in bitwarden, and tries to generate key using the following snippet:

bw list items --search 'cardano super secret mnemonic' \
  | jq -r '.[0].login.password' \
  | cardano-cli latest key key-from-mnemonic ... --signing-key-file key.json

@CarlosLopezDeLara thoughts? do you think this could be useful?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would actually work with the interactive one as is, I made it with that in mind, and I tested it feeding the output file of the generate-mnemonic command. But it may be a good idea to make one that is explicitly for that, or adding a comment, because the user may not know.

where
settings :: Monad m => Settings m
settings =
Settings
{ complete = completionFunc
, historyFile = Nothing
, autoAddHistory = False
}

completionFunc :: Monad m => CompletionFunc m
completionFunc = completeWord' Nothing isSpace completeMnemonicWord

completeMnemonicWord :: Monad m => String -> m [Completion]
completeMnemonicWord prefix = return $ map (simpleCompletion . T.unpack . fst) $ findMnemonicWordsWithPrefix (T.pack prefix)

inputT :: (String, String) -> [Text] -> InputT IO [Text]
inputT prefill mnemonic = do
minput <- getInputLineWithInitial (show (length mnemonic + 1) <> ". ") prefill
case minput of
Nothing -> return $ reverse mnemonic
Just "" -> return $ reverse mnemonic
Just input ->
let newWords = map (T.toLower . T.pack) $ filter (not . null) $ words input
in case span isValidMnemonicWord newWords of
(allWords, []) -> inputT ("", "") (reverse allWords ++ mnemonic)
(validWords, invalidWord : notValidatedWords) -> do
liftIO $ putStrLn $ "The word \"" <> T.unpack invalidWord <> "\" is not in the memonic dictionary"
let textBeforeCursor = unwords (map T.unpack validWords <> [T.unpack invalidWord])
textAfterCursor =
if null notValidatedWords
then ""
else ' ' : unwords (map T.unpack notValidatedWords)
inputT (textBeforeCursor, textAfterCursor) mnemonic

isValidMnemonicWord :: Text -> Bool
isValidMnemonicWord word = word `elem` map fst (findMnemonicWordsWithPrefix word)

runConvertByronKeyCmd
:: Cmd.KeyConvertByronKeyCmdArgs
Expand Down
32 changes: 24 additions & 8 deletions cardano-cli/test/cardano-cli-golden/files/golden/help.cli
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ Usage: cardano-cli key key-from-mnemonic [--key-output-format STRING]
| --cc-hot-key
)
--account-number WORD32
--mnemonic-from-file FILEPATH
( --mnemonic-from-file FILEPATH
| --mnemonic-from-interactive-prompt
)
--signing-key-file FILEPATH

Derive an extended signing key from a mnemonic sentence. To ensure the safety
Expand Down Expand Up @@ -1065,7 +1067,9 @@ Usage: cardano-cli shelley key key-from-mnemonic [--key-output-format STRING]
| --cc-hot-key
)
--account-number WORD32
--mnemonic-from-file FILEPATH
( --mnemonic-from-file FILEPATH
| --mnemonic-from-interactive-prompt
)
--signing-key-file FILEPATH

Derive an extended signing key from a mnemonic sentence. To ensure the safety
Expand Down Expand Up @@ -2161,7 +2165,9 @@ Usage: cardano-cli allegra key key-from-mnemonic [--key-output-format STRING]
| --cc-hot-key
)
--account-number WORD32
--mnemonic-from-file FILEPATH
( --mnemonic-from-file FILEPATH
| --mnemonic-from-interactive-prompt
)
--signing-key-file FILEPATH

Derive an extended signing key from a mnemonic sentence. To ensure the safety
Expand Down Expand Up @@ -3257,7 +3263,9 @@ Usage: cardano-cli mary key key-from-mnemonic [--key-output-format STRING]
| --cc-hot-key
)
--account-number WORD32
--mnemonic-from-file FILEPATH
( --mnemonic-from-file FILEPATH
| --mnemonic-from-interactive-prompt
)
--signing-key-file FILEPATH

Derive an extended signing key from a mnemonic sentence. To ensure the safety
Expand Down Expand Up @@ -4343,7 +4351,9 @@ Usage: cardano-cli alonzo key key-from-mnemonic [--key-output-format STRING]
| --cc-hot-key
)
--account-number WORD32
--mnemonic-from-file FILEPATH
( --mnemonic-from-file FILEPATH
| --mnemonic-from-interactive-prompt
)
--signing-key-file FILEPATH

Derive an extended signing key from a mnemonic sentence. To ensure the safety
Expand Down Expand Up @@ -5444,7 +5454,9 @@ Usage: cardano-cli babbage key key-from-mnemonic [--key-output-format STRING]
| --cc-hot-key
)
--account-number WORD32
--mnemonic-from-file FILEPATH
( --mnemonic-from-file FILEPATH
| --mnemonic-from-interactive-prompt
)
--signing-key-file FILEPATH

Derive an extended signing key from a mnemonic sentence. To ensure the safety
Expand Down Expand Up @@ -6825,7 +6837,9 @@ Usage: cardano-cli conway key key-from-mnemonic [--key-output-format STRING]
| --cc-hot-key
)
--account-number WORD32
--mnemonic-from-file FILEPATH
( --mnemonic-from-file FILEPATH
| --mnemonic-from-interactive-prompt
)
--signing-key-file FILEPATH

Derive an extended signing key from a mnemonic sentence. To ensure the safety
Expand Down Expand Up @@ -8848,7 +8862,9 @@ Usage: cardano-cli latest key key-from-mnemonic [--key-output-format STRING]
| --cc-hot-key
)
--account-number WORD32
--mnemonic-from-file FILEPATH
( --mnemonic-from-file FILEPATH
| --mnemonic-from-interactive-prompt
)
--signing-key-file FILEPATH

Derive an extended signing key from a mnemonic sentence. To ensure the safety
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ Usage: cardano-cli allegra key key-from-mnemonic [--key-output-format STRING]
| --cc-hot-key
)
--account-number WORD32
--mnemonic-from-file FILEPATH
( --mnemonic-from-file FILEPATH
| --mnemonic-from-interactive-prompt
)
--signing-key-file FILEPATH

Derive an extended signing key from a mnemonic sentence. To ensure the safety
Expand All @@ -32,6 +34,8 @@ Available options:
--account-number WORD32 Account number in the derivation path.
--mnemonic-from-file FILEPATH
Input text file with the mnemonic.
--mnemonic-from-interactive-prompt
Input the mnemonic through an interactive prompt.
--signing-key-file FILEPATH
Output filepath of the signing key.
-h,--help Show this help text
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ Usage: cardano-cli alonzo key key-from-mnemonic [--key-output-format STRING]
| --cc-hot-key
)
--account-number WORD32
--mnemonic-from-file FILEPATH
( --mnemonic-from-file FILEPATH
| --mnemonic-from-interactive-prompt
)
--signing-key-file FILEPATH

Derive an extended signing key from a mnemonic sentence. To ensure the safety
Expand All @@ -32,6 +34,8 @@ Available options:
--account-number WORD32 Account number in the derivation path.
--mnemonic-from-file FILEPATH
Input text file with the mnemonic.
--mnemonic-from-interactive-prompt
Input the mnemonic through an interactive prompt.
--signing-key-file FILEPATH
Output filepath of the signing key.
-h,--help Show this help text
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ Usage: cardano-cli babbage key key-from-mnemonic [--key-output-format STRING]
| --cc-hot-key
)
--account-number WORD32
--mnemonic-from-file FILEPATH
( --mnemonic-from-file FILEPATH
| --mnemonic-from-interactive-prompt
)
--signing-key-file FILEPATH

Derive an extended signing key from a mnemonic sentence. To ensure the safety
Expand All @@ -32,6 +34,8 @@ Available options:
--account-number WORD32 Account number in the derivation path.
--mnemonic-from-file FILEPATH
Input text file with the mnemonic.
--mnemonic-from-interactive-prompt
Input the mnemonic through an interactive prompt.
--signing-key-file FILEPATH
Output filepath of the signing key.
-h,--help Show this help text
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ Usage: cardano-cli conway key key-from-mnemonic [--key-output-format STRING]
| --cc-hot-key
)
--account-number WORD32
--mnemonic-from-file FILEPATH
( --mnemonic-from-file FILEPATH
| --mnemonic-from-interactive-prompt
)
--signing-key-file FILEPATH

Derive an extended signing key from a mnemonic sentence. To ensure the safety
Expand All @@ -32,6 +34,8 @@ Available options:
--account-number WORD32 Account number in the derivation path.
--mnemonic-from-file FILEPATH
Input text file with the mnemonic.
--mnemonic-from-interactive-prompt
Input the mnemonic through an interactive prompt.
--signing-key-file FILEPATH
Output filepath of the signing key.
-h,--help Show this help text
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ Usage: cardano-cli key key-from-mnemonic [--key-output-format STRING]
| --cc-hot-key
)
--account-number WORD32
--mnemonic-from-file FILEPATH
( --mnemonic-from-file FILEPATH
| --mnemonic-from-interactive-prompt
)
--signing-key-file FILEPATH

Derive an extended signing key from a mnemonic sentence. To ensure the safety
Expand All @@ -32,6 +34,8 @@ Available options:
--account-number WORD32 Account number in the derivation path.
--mnemonic-from-file FILEPATH
Input text file with the mnemonic.
--mnemonic-from-interactive-prompt
Input the mnemonic through an interactive prompt.
--signing-key-file FILEPATH
Output filepath of the signing key.
-h,--help Show this help text
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ Usage: cardano-cli latest key key-from-mnemonic [--key-output-format STRING]
| --cc-hot-key
)
--account-number WORD32
--mnemonic-from-file FILEPATH
( --mnemonic-from-file FILEPATH
| --mnemonic-from-interactive-prompt
)
--signing-key-file FILEPATH

Derive an extended signing key from a mnemonic sentence. To ensure the safety
Expand All @@ -32,6 +34,8 @@ Available options:
--account-number WORD32 Account number in the derivation path.
--mnemonic-from-file FILEPATH
Input text file with the mnemonic.
--mnemonic-from-interactive-prompt
Input the mnemonic through an interactive prompt.
--signing-key-file FILEPATH
Output filepath of the signing key.
-h,--help Show this help text
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ Usage: cardano-cli mary key key-from-mnemonic [--key-output-format STRING]
| --cc-hot-key
)
--account-number WORD32
--mnemonic-from-file FILEPATH
( --mnemonic-from-file FILEPATH
| --mnemonic-from-interactive-prompt
)
--signing-key-file FILEPATH

Derive an extended signing key from a mnemonic sentence. To ensure the safety
Expand All @@ -32,6 +34,8 @@ Available options:
--account-number WORD32 Account number in the derivation path.
--mnemonic-from-file FILEPATH
Input text file with the mnemonic.
--mnemonic-from-interactive-prompt
Input the mnemonic through an interactive prompt.
--signing-key-file FILEPATH
Output filepath of the signing key.
-h,--help Show this help text
Loading
Loading