diff options
| author | Shulhan <ms@kilabit.info> | 2024-01-28 16:37:00 +0700 |
|---|---|---|
| committer | Shulhan <ms@kilabit.info> | 2024-01-28 17:45:39 +0700 |
| commit | 3aa08b00a1151249c6172f0739daac6be5ef857f (patch) | |
| tree | 5f337e8d19a484ec2e50feea199ab36ae3402fab /config.go | |
| parent | 6aeb5a7c882c30c9a9042f30f2ae16d35d2f47d3 (diff) | |
| download | gotp-3aa08b00a1151249c6172f0739daac6be5ef857f.tar.xz | |
all: make the path to private key static
Instead of prompting user, make the private key static, located at
"$XDG_CONFIG_DIR/gotp/gotp.key".
Implements: https://todo.sr.ht/~shulhan/gotp/1
Diffstat (limited to 'config.go')
| -rw-r--r-- | config.go | 106 |
1 files changed, 73 insertions, 33 deletions
@@ -13,7 +13,8 @@ import ( "strings" "github.com/shuLhan/share/lib/ini" - libos "github.com/shuLhan/share/lib/os" + "golang.org/x/crypto/ssh" + "golang.org/x/term" ) const ( @@ -23,20 +24,24 @@ const ( type config struct { privateKey *rsa.PrivateKey // Only RSA private key can do encryption. - Issuers map[string]string `ini:"gotp:issuer"` - PrivateKey string `ini:"gotp::private_key"` + Issuers map[string]string `ini:"gotp:issuer"` - file string - isNotExist bool + dir string + file string + privateKeyFile string } func newConfig(file string) (cfg *config, err error) { - var ( - logp = `newConfig` + var logp = `newConfig` - content []byte - isNotExist bool - ) + cfg = &config{ + dir: filepath.Dir(file), + file: file, + } + + cfg.privateKeyFile = filepath.Join(cfg.dir, privateKeyFile) + + var content []byte content, err = os.ReadFile(file) if err != nil { @@ -44,24 +49,17 @@ func newConfig(file string) (cfg *config, err error) { return nil, fmt.Errorf(`%s: Open %q: %w`, logp, file, err) } - var dir = filepath.Dir(file) - err = os.MkdirAll(dir, 0700) + err = os.MkdirAll(cfg.dir, 0700) if err != nil { - return nil, fmt.Errorf(`%s: MkdirAll %q: %w`, logp, dir, err) + return nil, fmt.Errorf(`%s: MkdirAll %q: %w`, logp, cfg.dir, err) } - isNotExist = true } - cfg = &config{} - err = cfg.UnmarshalText(content) if err != nil { return nil, fmt.Errorf(`%s: %w`, logp, err) } - cfg.isNotExist = isNotExist - cfg.file = file - return cfg, nil } @@ -78,13 +76,6 @@ func (cfg *config) UnmarshalText(content []byte) (err error) { } } - if len(cfg.PrivateKey) != 0 { - cfg.PrivateKey, err = libos.PathUnfold(cfg.PrivateKey) - if err != nil { - return fmt.Errorf(`%s: %w`, logp, err) - } - } - return nil } @@ -92,13 +83,6 @@ func (cfg *config) UnmarshalText(content []byte) (err error) { func (cfg *config) MarshalText() (text []byte, err error) { var logp = `MarshalText` - if len(cfg.PrivateKey) != 0 { - cfg.PrivateKey, err = libos.PathFold(cfg.PrivateKey) - if err != nil { - return nil, fmt.Errorf(`%s: %w`, logp, err) - } - } - text, err = ini.Marshal(cfg) if err != nil { return nil, fmt.Errorf(`%s: %w`, logp, err) @@ -155,6 +139,62 @@ func (cfg *config) get(name string) (issuer *Issuer, err error) { return issuer, nil } +// loadPrivateKey parse the RSA private key with optional passphrase. +// It will return nil if private key file does not exist. +func (cfg *config) loadPrivateKey() (err error) { + var ( + logp = `loadPrivateKey` + + rawPem []byte + ) + + rawPem, err = os.ReadFile(cfg.privateKeyFile) + if err != nil { + if errors.Is(err, fs.ErrNotExist) { + return nil + } + return fmt.Errorf(`%s: %w`, logp, err) + } + + var privateKey interface{} + + privateKey, err = ssh.ParseRawPrivateKey(rawPem) + if err != nil { + var errPassMissing = &ssh.PassphraseMissingError{} + + if !errors.As(err, &errPassMissing) { + return fmt.Errorf(`%s %q: %w`, logp, cfg.privateKeyFile, err) + } + + fmt.Printf(`Enter passphrase for %s: `, cfg.privateKeyFile) + + var ( + stdin = int(os.Stdin.Fd()) + pass []byte + ) + + pass, err = term.ReadPassword(stdin) + fmt.Println() + if err != nil { + return fmt.Errorf(`%s %q: %w`, logp, cfg.privateKeyFile, err) + } + + privateKey, err = ssh.ParseRawPrivateKeyWithPassphrase(rawPem, pass) + if err != nil { + return fmt.Errorf(`%s %q: %w`, logp, cfg.privateKeyFile, err) + } + } + + var ok bool + + cfg.privateKey, ok = privateKey.(*rsa.PrivateKey) + if !ok { + return fmt.Errorf(`%s: invalid or unsupported private key`, logp) + } + + return nil +} + // save the config to file. func (cfg *config) save() (err error) { if len(cfg.file) == 0 { |
