{-# LANGUAGE FlexibleContexts #-} module Command.Key.FromRecoveryPhraseSpec ( spec ) where import Prelude import System.IO.Temp ( withSystemTempDirectory, writeTempFile ) import Test.Hspec ( Spec, SpecWith, it, shouldBe, shouldContain ) import Test.Utils ( cli, describeCmd ) spec :: Spec spec = describeCmd [ "key", "from-recovery-phrase" ] $ do specGolden "byron" defaultPhrase "root_xsk1vzdkjk8txce80dwm5upjddrawv9l8mq2jyv6qqx2ylzu0yua8age295\ \s38lj9gune65g07w95ttlt5qq3qh67nx4euvj2cut7z6pente84au2qmjqqy8w9x\ \58z6f722j5twq860nhhmlq347wf0yp6wdkvq80h42" specGolden "icarus" defaultPhrase "root_xsk1qz497hekfxq0ftrzjh7sl0m9vseep44mrnmk2dkzawczwy7ghfgd3yp\ \maem5k7lcv782p4haa4kcwmdnks4776rkgrx9zn4h8am82dagca203x7fejp4x04\ \ty47he9rztj2lp46fwyzz3ad2yszwadjfnv76n80u" specGolden "shelley" defaultPhrase "root_xsk1qz497hekfxq0ftrzjh7sl0m9vseep44mrnmk2dkzawczwy7ghfgd3yp\ \maem5k7lcv782p4haa4kcwmdnks4776rkgrx9zn4h8am82dagca203x7fejp4x04\ \ty47he9rztj2lp46fwyzz3ad2yszwadjfnv76n80u" specGolden "shared" defaultPhrase "root_shared_xsk1qz497hekfxq0ftrzjh7sl0m9vseep44mrnmk2dkzawczwy7gh\ \fgd3ypmaem5k7lcv782p4haa4kcwmdnks4776rkgrx9zn4h8am82dagca203x7fej\ \p4x04ty47he9rztj2lp46fwyzz3ad2yszwadjfnvuedzh4" specGoldenWithMnemonicPassphrase "shelley" defaultPhrase "from-mnemonic" (unwords sndFactorPhrase) rootXPrvWithPassphrase specGoldenWithMnemonicPassphrase "shelley" defaultPhrase "from-hex" sndFactorPhraseHex rootXPrvWithPassphrase specGoldenWithMnemonicPassphrase "shelley" defaultPhrase "from-base64" sndFactorPhraseBase64 rootXPrvWithPassphrase specGoldenWithMnemonicPassphrase "shelley" defaultPhrase "from-octets" sndFactorPhraseOctets rootXPrvWithPassphrase specGoldenWithMnemonicPassphrase "icarus" defaultPhrase "from-mnemonic" (unwords sndFactorPhrase) rootXPrvWithPassphrase specGoldenWithMnemonicPassphrase "icarus" defaultPhrase "from-hex" sndFactorPhraseHex rootXPrvWithPassphrase specGoldenWithMnemonicPassphrase "icarus" defaultPhrase "from-base64" sndFactorPhraseBase64 rootXPrvWithPassphrase specGoldenWithMnemonicPassphrase "icarus" defaultPhrase "from-octets" sndFactorPhraseOctets rootXPrvWithPassphrase specGoldenWithMnemonicPassphrase "shared" defaultPhrase "from-mnemonic" (unwords sndFactorPhrase) rootXPrvSharedWithPassphrase specGoldenWithMnemonicPassphrase "shared" defaultPhrase "from-hex" sndFactorPhraseHex rootXPrvSharedWithPassphrase specGoldenWithMnemonicPassphrase "shared" defaultPhrase "from-base64" sndFactorPhraseBase64 rootXPrvSharedWithPassphrase specGoldenWithMnemonicPassphrase "shared" defaultPhrase "from-octets" sndFactorPhraseOctets rootXPrvSharedWithPassphrase specInvalidStyle "patate" defaultPhrase specInvalidStyle "💩" defaultPhrase specInvalidPhrase "shelley" invalidPhrase specGolden :: String -> [String] -> String -> SpecWith () specGolden style phrase want = it ("golden " <> style) $ do out <- cli [ "key", "from-recovery-phrase", style ] (unwords phrase) out `shouldBe` want specInvalidStyle :: String -> [String] -> SpecWith () specInvalidStyle style phrase = it ("invalid style " <> style) $ do (out, err) <- cli [ "key", "from-recovery-phrase", style ] (unwords phrase) out `shouldBe` "" err `shouldContain` "Unknown style; expecting one of" err `shouldContain` "Usage:" specInvalidPhrase :: String -> [String] -> SpecWith () specInvalidPhrase style phrase = it ("invalid phrase " <> unwords phrase) $ do (out, err) <- cli [ "key", "from-recovery-phrase", style ] (unwords phrase) out `shouldBe` "" err `shouldContain` "Found an unknown word not present in the pre-defined dictionary." specGoldenWithMnemonicPassphrase :: String -> [String] -> String -> String -> String -> SpecWith () specGoldenWithMnemonicPassphrase style phrase method sndfactor want = it ("golden " <> style <> " from-file "<> method) $ withSystemTempDirectory "tmpdir" $ \dir -> do filepath <- writeTempFile dir "passphrase" sndfactor out <- cli [ "key", "from-recovery-phrase", style, "--passphrase" , method, "--from-file", filepath] (unwords phrase) out `shouldBe` want defaultPhrase :: [String] defaultPhrase = [ "message", "mask", "aunt", "wheel", "ten" , "maze", "between", "tomato", "slow", "analyst" , "ladder", "such", "report", "capital", "produce" ] invalidPhrase :: [String] invalidPhrase = replicate 9 "¯\\_(ツ)_/¯" sndFactorPhrase :: [String] sndFactorPhrase = [ "test", "child", "burst", "immense", "armed" , "parrot", "company", "walk", "dog" ] --λ> let (Right m9) = mkSomeMnemonic @'[ 9, 12, 15 ] [ "test", "child", "burst", "immense", "armed", "parrot", "company", "walk", "dog" ] --Right (SomeMnemonic (Mnemonic {mnemonicToEntropy = Entropy {entropyRaw = "\223\132\252{8\192\189@\203\167\180@", entropyChecksum = Checksum 4}, mnemonicToSentence = MnemonicSentence {mnemonicSentenceToListN = [WordIndex {unWordIndex = Offset 1788},WordIndex {unWordIndex = Offset 319},WordIndex {unWordIndex = Offset 246},WordIndex {unWordIndex = Offset 908},WordIndex {unWordIndex = Offset 94},WordIndex {unWordIndex = Offset 1283},WordIndex {unWordIndex = Offset 372},WordIndex {unWordIndex = Offset 1972},WordIndex {unWordIndex = Offset 516}]}})) --λ> import qualified Data.ByteString as BS --λ> import qualified Data.ByteArray as BA --λ> let bytes = BA.convert $ someMnemonicToBytes m9 :: BS.ByteString --λ> bytes --"\223\132\252{8\192\189@\203\167\180@" --λ> encode EBase16 bytes --"df84fc7b38c0bd40cba7b440" --λ> import qualified Data.Text.Encoding as T --λ> import qualified Data.ByteArray.Encoding as BA --λ> T.decodeUtf8 $ BA.convertToBase BA.Base64 bytes --"34T8ezjAvUDLp7RA" --λ> BS.unpack bytes -- [223,132,252,123,56,192,189,64,203,167,180,64] sndFactorPhraseHex :: String sndFactorPhraseHex = "df84fc7b38c0bd40cba7b440" sndFactorPhraseBase64 :: String sndFactorPhraseBase64 = "34T8ezjAvUDLp7RA" sndFactorPhraseOctets :: String sndFactorPhraseOctets = "[223,132,252,123,56,192,189,64,203,167,180,64]" rootXPrvWithPassphrase :: String rootXPrvWithPassphrase = "root_xsk1xpk2wzz7xsyhfxxvwraxnq2sps45ygfayrmn8kxjep4gl9jxgfg3tffp7z7w7ltd0\ \gw32wqhyk5c296u7m28l688n8n6v24hrp326kgzz6cgvkvvj2k0t34jkv6ze0d8vxxnavar4tz\ \gl96th9qhfayllsl4qsqq" rootXPrvSharedWithPassphrase :: String rootXPrvSharedWithPassphrase = "root_shared_xsk1xpk2wzz7xsyhfxxvwraxnq2sps45ygfayrmn8kxjep4gl9jxgfg3tffp7z\ \7w7ltd0gw32wqhyk5c296u7m28l688n8n6v24hrp326kgzz6cgvkvvj2k0t34jkv6ze0d8vxxn\ \avar4tzgl96th9qhfayllsak74cf"