This repository has been archived by the owner on Aug 18, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 632
export legacy wallets in a friendly way for automatic import in cardano-wallet #4278
Open
KtorZ
wants to merge
11
commits into
develop
Choose a base branch
from
KtorZ/export-wallets
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
f63761e
implement export-wallets for Byron reboot migration
KtorZ 148076e
Return 'null' for 'passphrase_hash' when there's no passphrase set
KtorZ 787e72e
regen nix files
cleverca22 da6645c
fail when given a non-existing database path
KtorZ 9b53dc1
re-generate nix machinery
KtorZ 1702a9e
actually returns corresponding scrypt hash even for empty passphrases
KtorZ 776a638
returns wallets with no metadata if prv key exists
KtorZ 996a17f
add wallet id (new format) to the exported JSON
KtorZ 6054e7e
re-generate nix machinery
KtorZ 13f5729
make acid-state database optional from the command-line
KtorZ c1815b7
show in the JSON export whether a passphrase is empty or not
KtorZ File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
{-# LANGUAGE FlexibleInstances #-} | ||
{-# LANGUAGE LambdaCase #-} | ||
{-# LANGUAGE NamedFieldPuns #-} | ||
{-# LANGUAGE TypeApplications #-} | ||
|
||
module Main where | ||
|
||
import Universum | ||
|
||
import Cardano.Crypto.Wallet (toXPub, unXPrv, unXPub) | ||
import Cardano.Wallet.Kernel (DatabaseMode (..), DatabaseOptions (..), | ||
bracketPassiveWallet) | ||
import Cardano.Wallet.Kernel.DB.HdWallet (HdRoot (..), | ||
WalletName (..), eskToHdRootId) | ||
import Cardano.Wallet.Kernel.Keystore (bracketLegacyKeystore) | ||
import Cardano.Wallet.Kernel.NodeStateAdaptor (mockNodeStateDef) | ||
import Crypto.Hash (Blake2b_160, hash) | ||
import Data.Aeson (ToJSON (..), (.=)) | ||
import Data.ByteArray.Encoding (Base (..), convertToBase) | ||
import Data.ByteString (ByteString) | ||
import Data.Functor.Contravariant (Contravariant (..), Op (..)) | ||
import Options.Applicative | ||
import Pos.Core.NetworkMagic (makeNetworkMagic) | ||
import Pos.Crypto (EncryptedPass (..), EncryptedSecretKey (..)) | ||
import Pos.Crypto.Configuration (ProtocolMagic (..), | ||
ProtocolMagicId (..), RequiresNetworkMagic (..)) | ||
import Pos.Crypto.Signing (checkPassMatches, emptyPassphrase) | ||
import Pos.Infra.InjectFail (mkFInjects) | ||
import Pos.Util.Trace (Trace (..)) | ||
import Pos.Util.UserSecret (readUserSecret) | ||
import System.Directory (doesDirectoryExist) | ||
|
||
import qualified Cardano.Wallet.Kernel as Kernel | ||
import qualified Cardano.Wallet.Kernel.Internal as Kernel | ||
import qualified Cardano.Wallet.Kernel.Keystore as Keystore | ||
import qualified Cardano.Wallet.Kernel.Read as Kernel | ||
import qualified Data.Aeson as Json | ||
import qualified Data.Aeson.Encode.Pretty as Json | ||
import qualified Data.ByteArray as BA | ||
import qualified Data.ByteString.Char8 as B8 | ||
import qualified Data.ByteString.Lazy.Char8 as BL8 | ||
import qualified Data.Text.Encoding as T | ||
import qualified Data.Text.IO as TIO | ||
|
||
data Options = Options | ||
{ pm :: ProtocolMagic | ||
, dbPath :: Maybe FilePath | ||
, usPath :: FilePath | ||
} | ||
|
||
main :: IO () | ||
main = do | ||
let preferences = prefs showHelpOnEmpty | ||
Options{pm,dbPath,usPath} <- customExecParser preferences parserInfo | ||
dbMode <- getDbMode dbPath | ||
userSecret <- readUserSecret (contramap snd stderrTrace) usPath | ||
bracketLegacyKeystore userSecret $ \ks -> do | ||
fInjects <- mkFInjects Nothing | ||
bracketPassiveWallet pm dbMode log ks mockNodeStateDef fInjects $ \pw -> do | ||
wallets <- extractWallet pw | ||
BL8.putStrLn $ Json.encodePretty (Export <$> wallets) | ||
where | ||
log = const (B8.hPutStrLn stderr . T.encodeUtf8) | ||
|
||
stderrTrace = Trace $ Op $ TIO.hPutStrLn stderr | ||
|
||
guardDatabase = doesDirectoryExist . dbPathAcidState >=> \case | ||
True -> pure () | ||
False -> fail "There's no acid-state database matching the given path." | ||
|
||
getDbMode = \case | ||
Nothing -> | ||
pure UseInMemory | ||
Just dbPath -> do | ||
let dbOpts = DatabaseOptions | ||
{ dbPathAcidState = dbPath <> "-acid" | ||
, dbPathMetadata = dbPath <> "-sqlite.sqlite3" | ||
, dbRebuild = False | ||
} | ||
guardDatabase dbOpts | ||
pure (UseFilePath dbOpts) | ||
|
||
extractWallet | ||
:: Kernel.PassiveWallet | ||
-> IO [(Maybe WalletName, EncryptedSecretKey)] | ||
extractWallet pw = do | ||
wKeys <- Keystore.getKeys (pw ^. Kernel.walletKeystore) | ||
let nm = makeNetworkMagic (pw ^. Kernel.walletProtocolMagic) | ||
snapshot <- Kernel.getWalletSnapshot pw | ||
forM wKeys $ \esk -> do | ||
let rootId = eskToHdRootId nm esk | ||
case Kernel.lookupHdRootId snapshot rootId of | ||
Left _ -> | ||
pure (Nothing, esk) | ||
Right HdRoot{_hdRootName} -> | ||
pure (Just _hdRootName, esk) | ||
|
||
newtype Export a = Export a deriving (Show) | ||
|
||
instance ToJSON (Export (Maybe WalletName, EncryptedSecretKey)) where | ||
toJSON (Export (name, esk@EncryptedSecretKey{eskPayload, eskHash})) = Json.object | ||
[ "id" .= base16 (mkWalletId eskPayload) | ||
, "name" .= (getWalletName <$> name) | ||
, "encrypted_root_private_key" .= base16 (unXPrv eskPayload) | ||
, "passphrase_hash" .= base16 (getEncryptedPass eskHash) | ||
, "is_passphrase_empty" .= case checkPassMatches emptyPassphrase esk of | ||
Nothing -> False | ||
Just{} -> True | ||
] | ||
where | ||
base16 = T.decodeUtf8 . convertToBase @ByteString @ByteString Base16 | ||
mkWalletId = BA.convert . hash @_ @Blake2b_160 . unXPub . toXPub | ||
|
||
-- | ||
-- Command-line | ||
-- | ||
-- | ||
|
||
parserInfo :: ParserInfo Options | ||
parserInfo = info (helper <*> parser) $ | ||
progDesc "Export known legacy wallets with their encrypted secret key" | ||
where | ||
parser = Options <$> pmOption <*> dbOption <*> usOption | ||
|
||
-- --mainnet | --testnet MAGIC | ||
pmOption :: Parser ProtocolMagic | ||
pmOption = mainnetFlag <|> (ProtocolMagic <$> magicOption <*> pure RequiresMagic) | ||
where | ||
mainnetFlag = flag' | ||
(ProtocolMagic (ProtocolMagicId 764824073) RequiresNoMagic) | ||
(long "mainnet") | ||
|
||
magicOption = fmap ProtocolMagicId $ option auto $ mempty | ||
<> long "testnet" | ||
<> metavar "MAGIC" | ||
|
||
-- --db-path FILEPATH | ||
dbOption :: Parser (Maybe FilePath) | ||
dbOption = optional $ option str $ mempty | ||
<> long "wallet-db-path" | ||
<> metavar "FILEPATH" | ||
<> help "Path to the wallet's database." | ||
|
||
-- --keyfile FILEPATH | ||
usOption :: Parser FilePath | ||
usOption = option str $ mempty | ||
<> long "keyfile" | ||
<> metavar "FILEPATH" | ||
<> help "Path to the secret key-store." |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nix files will need regenerating.