~shulhan/gotp

de4158b930a2afcfa59947ae2cd7127943751805 — Shulhan 9 months ago 6a9e476
all: add command to remove the private key

The remove-private-key decrypt the issuer's value back using previous
private key and store it back to file as plain text.
M README.md => README.md +5 -0
@@ 44,6 44,11 @@ remove <LABEL>

	Remove LABEL from configuration.

remove-private-key

    Decrypt the issuer's value (hash:secret...) using previous private key and
    store it back to file as plain text.

rename <LABEL> <NEW-LABEL>

	Rename a LABEL into NEW-LABEL.

M _sys/etc/bash_completion.d/gotp => _sys/etc/bash_completion.d/gotp +3 -1
@@ 15,7 15,7 @@ suggest_key() {

_gotp_completions()
{
	commands=("add" "gen" "import" "list" "remove" "rename" "set-private-key")
	commands=("add" "gen" "import" "list" "remove" "remove-private-key" "rename" "set-private-key")

	local len=${#COMP_WORDS[@]}
	local cmd=${COMP_WORDS[1]}


@@ 38,6 38,8 @@ _gotp_completions()
				suggest_key "$key"
			fi
			;;
		remove-private-key)
			;;
		rename)
			if [[ $len == 3 ]]; then
				suggest_key "$key"

M cli.go => cli.go +44 -0
@@ 271,6 271,50 @@ func (cli *Cli) Remove(label string) (err error) {
	return nil
}

// RemovePrivateKey Decrypt the issuer's value (hash:secret...) using previous
// private key and store it back to file as plain text.
func (cli *Cli) RemovePrivateKey() (err error) {
	if cli.cfg.privateKey == nil {
		return nil
	}

	var (
		logp          = `RemovePrivateKey`
		oldPrivateKey = cli.cfg.privateKey
		oldIssuers    = cli.cfg.Issuers

		issuer *Issuer
		label  string
		raw    string
	)

	cli.cfg.privateKey = nil
	cli.cfg.Issuers = map[string]string{}

	for label, raw = range oldIssuers {
		// Decrypt the issuer using old private key.
		issuer, err = NewIssuer(label, raw, oldPrivateKey)
		if err != nil {
			return fmt.Errorf(`%s: %w`, logp, err)
		}

		// Add it to the config back as plain text.
		err = cli.cfg.add(issuer)
		if err != nil {
			return fmt.Errorf(`%s: %w`, logp, err)
		}
	}

	cli.cfg.PrivateKey = ``

	err = cli.cfg.save()
	if err != nil {
		return fmt.Errorf(`%s: %w`, logp, err)
	}

	return nil
}

// Rename a label to newLabel.
// It will return an error if the label parameter is not exist or newLabel
// already exist.

M cli_test.go => cli_test.go +18 -1
@@ 156,7 156,7 @@ func TestCli_SetPrivateKey(t *testing.T) {
		cfg       *config
	)

	rawConfig = tdata.Input[`config.ini.before`]
	rawConfig = tdata.Input[`config.ini`]

	cfg, err = loadConfig(rawConfig)
	if err != nil {


@@ 208,4 208,21 @@ func TestCli_SetPrivateKey(t *testing.T) {
	}

	test.Assert(t, `get all labels`, string(tdata.Output[`issuers`]), got.String())

	// Remove the private key, and compare the plain config.

	err = cli.RemovePrivateKey()
	if err != nil {
		t.Fatal(err)
	}

	var gotConfig []byte

	gotConfig, err = cli.cfg.MarshalText()
	if err != nil {
		t.Fatal(err)
	}

	rawConfig = tdata.Input[`config.ini`]
	test.Assert(t, `RemovePrivateKey`, string(rawConfig), string(gotConfig))
}

M cmd/gotp/main.go => cmd/gotp/main.go +21 -9
@@ 17,15 17,16 @@ import (
)

const (
	cmdName          = `gotp`
	cmdAdd           = `add`
	cmdGenerate      = `gen`
	cmdImport        = `import`
	cmdList          = `list`
	cmdRemove        = `remove`
	cmdRename        = `rename`
	cmdSetPrivateKey = `set-private-key`
	cmdVersion       = `version`
	cmdName             = `gotp`
	cmdAdd              = `add`
	cmdGenerate         = `gen`
	cmdImport           = `import`
	cmdList             = `list`
	cmdRemove           = `remove`
	cmdRemovePrivateKey = `remove-private-key`
	cmdRename           = `rename`
	cmdSetPrivateKey    = `set-private-key`
	cmdVersion          = `version`
)

func main() {


@@ 75,6 76,8 @@ func main() {
			log.Printf(`%s %s: missing parameters`, cmdName, cmd)
			os.Exit(1)
		}
	case cmdRemovePrivateKey:
		// NOOP.
	case cmdRename:
		if len(args) <= 2 {
			log.Printf(`%s %s: missing parameters`, cmdName, cmd)


@@ 113,6 116,8 @@ func main() {
		doList(cli)
	case cmdRemove:
		doRemove(cli, args)
	case cmdRemovePrivateKey:
		doRemovePrivateKey(cli)
	case cmdRename:
		doRename(cli, args)
	case cmdSetPrivateKey:


@@ 213,6 218,13 @@ func doRemove(cli *gotp.Cli, args []string) {
	fmt.Println(`OK`)
}

func doRemovePrivateKey(cli *gotp.Cli) {
	var err = cli.RemovePrivateKey()
	if err != nil {
		log.Fatalf(`%s: %s`, cmdName, err)
	}
}

func doRename(cli *gotp.Cli, args []string) {
	var (
		label    = args[1]

M testdata/cli_SetPrivateKey_test.txt => testdata/cli_SetPrivateKey_test.txt +1 -1
@@ 3,7 3,7 @@ private_key_openssh: testdata/keys/rsa-openssh.pem

Test setting private key from unencrypted configuration.

>>> config.ini.before
>>> config.ini
[gotp "issuer"]
test1 = SHA1:a:6:30:
test2 = SHA1:b:6:30: