Skip to content

Commit

Permalink
feat: support other languages (#4)
Browse files Browse the repository at this point in the history
* feat: add support for all language supported by tyler-smith/go-bip39

* fix: use full language flag in cmd

* fix: use t.Cleanup to reset language

* fix: add more language identifier for Chinese
  • Loading branch information
jon4hz authored Mar 15, 2022
1 parent 2e724bd commit 7937d4d
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 2 deletions.
48 changes: 46 additions & 2 deletions cmd/melt/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import (
"github.com/muesli/reflow/wordwrap"
"github.com/muesli/roff"
"github.com/muesli/termenv"
"github.com/tyler-smith/go-bip39"
"github.com/tyler-smith/go-bip39/wordlists"
"golang.org/x/crypto/ssh"
"golang.org/x/term"
)
Expand All @@ -39,6 +41,9 @@ var (
Padding(1, 2)
keyPathStyle = lipgloss.NewStyle().Foreground(violet)

mnemonic string
language string

rootCmd = &coral.Command{
Use: "melt",
Example: ` melt ~/.ssh/id_ed25519
Expand All @@ -51,6 +56,10 @@ be used to rebuild your public and private keys.`,
Args: coral.ExactArgs(1),
SilenceUsage: true,
RunE: func(cmd *coral.Command, args []string) error {
if err := setLanguage(language); err != nil {
return err
}

mnemonic, err := backup(args[0], nil)
if err != nil {
return err
Expand All @@ -67,8 +76,12 @@ be used to rebuild your public and private keys.`,

// Build formatted restore command
const cmdEOL = " \\"
var lang string
if language != "en" {
lang = fmt.Sprintf(" --language %s", language)
}
cmd := wordwrap.String(
os.Args[0]+` restore ./my-key --seed "`+mnemonic+`"`,
os.Args[0]+` restore`+lang+` ./my-key --seed "`+mnemonic+`"`,
w-lipgloss.Width(cmdEOL)-baseStyle.GetHorizontalFrameSize()*2,
)
leftPad := strings.Repeat(" ", baseStyle.GetMarginLeft())
Expand All @@ -91,7 +104,6 @@ be used to rebuild your public and private keys.`,
},
}

mnemonic string
restoreCmd = &coral.Command{
Use: "restore",
Short: "Recreate a key using the given seed phrase",
Expand All @@ -100,6 +112,10 @@ be used to rebuild your public and private keys.`,
Aliases: []string{"res", "r"},
Args: coral.ExactArgs(1),
RunE: func(cmd *coral.Command, args []string) error {
if err := setLanguage(language); err != nil {
return err
}

if err := restore(maybeFile(mnemonic), args[0]); err != nil {
return err
}
Expand Down Expand Up @@ -131,6 +147,7 @@ be used to rebuild your public and private keys.`,
)

func init() {
rootCmd.PersistentFlags().StringVarP(&language, "language", "l", "en", "Language")
rootCmd.AddCommand(restoreCmd, manCmd)

restoreCmd.PersistentFlags().StringVarP(&mnemonic, "seed", "s", "-", "Seed phrase")
Expand Down Expand Up @@ -238,3 +255,30 @@ func completeColor(truecolor, ansi256, ansi string) string {
}
return ansi
}

// setLanguage sets the language of the big39 mnemonic seed.
func setLanguage(language string) error {
switch strings.ToLower(language) {
case "chinese-simplified", "zh", "zh_HANS":
bip39.SetWordList(wordlists.ChineseSimplified)
case "chinese-traditional", "zh_HANT":
bip39.SetWordList(wordlists.ChineseTraditional)
case "czech", "cs":
bip39.SetWordList(wordlists.Czech)
case "english", "en":
bip39.SetWordList(wordlists.English)
case "french", "fr":
bip39.SetWordList(wordlists.French)
case "italian", "it":
bip39.SetWordList(wordlists.Italian)
case "japanese", "ja":
bip39.SetWordList(wordlists.Japanese)
case "korean", "ko":
bip39.SetWordList(wordlists.Korean)
case "spanish", "es":
bip39.SetWordList(wordlists.Spanish)
default:
return fmt.Errorf("this language is not supported")
}
return nil
}
41 changes: 41 additions & 0 deletions cmd/melt/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,47 @@ func TestBackupRestoreKnownKey(t *testing.T) {
})
}

func TestBackupRestoreKnownKeyInJapanse(t *testing.T) {
const expectedMnemonic = `
いきおい ざるそば えもの せんめんじょ てあみ ていねい はったつ
ろこつ すあし のぞく かまう ほくろ らくご けぶかい たおす よゆう
ひめじし くたびれる ぐんたい なわばり にかい えほん せなか
そいとげる
`
const expectedSum = "ba34175ef608633b29f046b40cce596dd221347b77abba40763eef2e7ae51fe9"
const expectedFingerprint = "SHA256:tX0ZrsNLIB/ZlRK3vy/HsWIIkyBNhYhCSGmtqtxJcWo"

// set language to Japanse
setLanguage("japanese")

// set language back to English
t.Cleanup(func() {
setLanguage("english")
})

t.Run("backup", func(t *testing.T) {
mnemonic, err := backup("testdata/id_ed25519", nil)
is := is.New(t)
is.NoErr(err)
is.Equal(mnemonic, strings.Join(strings.Fields(expectedMnemonic), " "))
})

t.Run("restore", func(t *testing.T) {
is := is.New(t)
path := filepath.Join(t.TempDir(), "key")
is.NoErr(restore(expectedMnemonic, path))
is.Equal(expectedSum, sha256sum(t, path+".pub"))

bts, err := os.ReadFile(path)
is.NoErr(err)

k, err := ssh.ParsePrivateKey(bts)
is.NoErr(err)

is.Equal(expectedFingerprint, ssh.FingerprintSHA256(k.PublicKey()))
})
}

func TestMaybeFile(t *testing.T) {
t.Run("is a file", func(t *testing.T) {
is := is.New(t)
Expand Down

0 comments on commit 7937d4d

Please sign in to comment.