diff options
| -rw-r--r-- | README.md | 162 | ||||
| -rw-r--r-- | cli.go | 141 | ||||
| -rw-r--r-- | cli_test.go | 68 | ||||
| -rw-r--r-- | config.go | 106 | ||||
| -rw-r--r-- | config_test.go | 28 | ||||
| -rw-r--r-- | gotp.go | 15 | ||||
| -rw-r--r-- | testdata/cli_SetPrivateKey_test.txt | 3 | ||||
| -rw-r--r-- | testdata/config_marshaler_test.txt | 6 | ||||
| -rw-r--r-- | testdata/with_private_key.conf | 3 |
9 files changed, 229 insertions, 303 deletions
@@ -5,126 +5,138 @@ A command line interface to manage and generate Time-based One Time Password ## SYNOPSIS -``` -gotp <command> <parameters...> -``` + gotp <command> <parameters...> -## DESCRIPTION -``` -add <LABEL> <HASH>:<BASE32-SECRET>[:DIGITS][:TIME-STEP][:ISSUER] +## COMMANDS - Add a TOTP secret identified by unique LABEL. - HASH is one of the valid hash function: SHA1, SHA256, or - SHA512. - BASE32-SECRET is the secret to generate one-time password - encoded in base32. - The DIGITS field is optional, define the number digits - generated for password, default to 6. - The TIME-STEP field is optional, its define the interval in - seconds, default to 30 seconds. - The ISSUER field is also optional, its define the name of - provider that generate the secret. +This section describe available command and its usage. -gen <LABEL> [N] + add <LABEL> <HASH>:<BASE32-SECRET>[:DIGITS][:TIME-STEP][:ISSUER] - Generate N number passwords using the secret identified by LABEL. +Add a TOTP secret identified by unique LABEL. +HASH is one of the valid hash function: SHA1, SHA256, or +SHA512. +BASE32-SECRET is the secret to generate one-time password +encoded in base32. +The DIGITS field is optional, define the number digits +generated for password, default to 6. +The TIME-STEP field is optional, its define the interval in +seconds, default to 30 seconds. +The ISSUER field is also optional, its define the name of +provider that generate the secret. -get <LABEL> + gen <LABEL> [N] - Get and print the issuer by its LABEL. - This will print the issuer secret, unencrypted. +Generate N number passwords using the secret identified by LABEL. -import <PROVIDER> <FILE> + get <LABEL> - Import the TOTP configuration from other provider. - Currently, the only supported PROVIDER is Aegis and the supported file - is .txt. +Get and print the issuer by its LABEL. +This will print the issuer secret, unencrypted. -list + import <PROVIDER> <FILE> - List all labels stored in the configuration. +Import the TOTP configuration from other provider. +Currently, the only supported PROVIDER is Aegis and the supported file +is .txt. -remove <LABEL> + list - Remove LABEL from configuration. +List all labels stored in the configuration. -remove-private-key + remove <LABEL> - Decrypt the issuer's value (hash:secret...) using previous private key and - store it back to file as plain text. +Remove LABEL from configuration. -rename <LABEL> <NEW-LABEL> + remove-private-key - Rename a LABEL into NEW-LABEL. +Decrypt the issuer's value (hash:secret...) using current private key and +store it back to file as plain text. +The current private key will be removed from gotp directory. -set-private-key <PRIVATE-KEY-FILE> + rename <LABEL> <NEW-LABEL> + +Rename a LABEL into NEW-LABEL. + + set-private-key <PRIVATE-KEY-FILE> + +Encrypt the issuer's value (hash:secret...) in the file using private key. +The supported private key is RSA. +Once completed, the PRIVATE-KEY-FILE will be copied to default user's gotp +directory, "$XDG_CONFIG_DIR/gotp/gotp.key". - Encrypt the issuer's value (hash:secret...) in the file using private key. - The supported private key is RSA. -``` ## ENCRYPTION -On the first run, the gotp command will ask for path of private key. -If the key exist, all the OTP values (excluding the label) will be encrypted. +On the first run, the gotp command check for private key in the user's +configuration direction (see the private key location in FILES section). + The private key must be RSA based. -One can skip inputting the private key by pressing enter, and the OTP -configuration will be stored as plain text. +If the private key exist, all the OTP values (excluding the label) will be +stored as encrypted. + +If the private key is not exist, the OTP configuration will be stored as +plain text. + ## FILES -$USER_CONFIG_DIR/gotp/gotp.conf:: Path to file where the configuration and +$XDG_CONFIG_DIR/gotp:: Path to user's gotp directory. + +$XDG_CONFIG_DIR/gotp/gotp.conf:: File where the configuration and secret are stored. +$XDG_CONFIG_DIR/gotp/gotp.key:: Private key file to encrypt and decrypt the +issuer. + +For Darwin/macOS the "$XDG_CONFIG_DIR" is equal to "$HOME/Library", +for Windows its equal to "%AppData%". + + ## EXAMPLES +This section show examples on how to use gotp cli. + Add "my-totp" to configuration using SHA1 as hash function, "GEZDGNBVGY3TQOJQ" as the secret, with 6 digits passwords, and 30 seconds as time step. -``` -$ gotp add my-totp SHA1:GEZDGNBVGY3TQOJQ:6:30 -``` + $ gotp add my-totp SHA1:GEZDGNBVGY3TQOJQ:6:30 + -Generate 3 recents passwords from "my-totp", +Generate 3 recent passwords from "my-totp", + + $ gotp gen my-totp 3 + gotp: reading configuration from /home/$USER/.config/gotp/gotp.conf + 847945 + 326823 + 767317 -``` -$ gotp gen my-totp 3 -gotp: reading configuration from /home/$USER/.config/gotp/gotp.conf -847945 -326823 -767317 -``` Import the exported Aegis TOTP from file, -``` -$ gotp import aegis aegis-export-uri.txt -gotp: reading configuration from /home/$USER/.config/gotp/gotp.conf -OK -``` + $ gotp import aegis aegis-export-uri.txt + gotp: reading configuration from /home/$USER/.config/gotp/gotp.conf + OK + List all labels stored in the configuration, -``` -$ gotp list -gotp: reading configuration from /home/$USER/.config/gotp/gotp.conf -my-totp -``` + $ gotp list + gotp: reading configuration from /home/$USER/.config/gotp/gotp.conf + my-totp + Remove a label "my-totp", -``` -$ gotp remove my-totp -gotp: reading configuration from /home/$USER/.config/gotp/gotp.conf -OK -``` + $ gotp remove my-totp + gotp: reading configuration from /home/$USER/.config/gotp/gotp.conf + OK + Rename a label "my-totp" to "my-otp", -``` -$ gotp rename my-totp my-otp -gotp: reading configuration from /home/$USER/.config/gotp/gotp.conf -OK -``` + $ gotp rename my-totp my-otp + gotp: reading configuration from /home/$USER/.config/gotp/gotp.conf + OK @@ -4,19 +4,16 @@ package gotp import ( - "crypto/rsa" _ "embed" "encoding/base32" - "errors" "fmt" "os" "path/filepath" "sort" "strings" + libos "github.com/shuLhan/share/lib/os" "github.com/shuLhan/share/lib/totp" - "golang.org/x/crypto/ssh" - "golang.org/x/term" ) // Readme embed the README.md, rendered in "gotp help". @@ -46,86 +43,9 @@ func NewCli(configDir string) (cli *Cli, err error) { return nil, fmt.Errorf(`%s: UserConfigDir: %w`, logp, err) } - if cli.cfg.isNotExist { - cli.cfg.PrivateKey, err = cli.inputPrivateKey(os.Stdin) - if err != nil { - return nil, fmt.Errorf(`%s: %w`, logp, err) - } - if len(cli.cfg.PrivateKey) > 0 { - cli.cfg.privateKey, err = loadPrivateKey(cli.cfg.PrivateKey, nil) - if err != nil { - return nil, fmt.Errorf(`%s: %w`, logp, err) - } - } - err = cli.cfg.save() - if err != nil { - return nil, fmt.Errorf(`%s: %w`, logp, err) - } - } - return cli, nil } -func (cli *Cli) inputPrivateKey(stdin *os.File) (privateKeyFile string, err error) { - fmt.Println(`Seems like this is your first time using this gotp.`) - fmt.Println(`If you would like to encrypt the secret, please`) - fmt.Printf(`enter the path to private key or enter to skip it: `) - fmt.Fscanln(stdin, &privateKeyFile) - - return privateKeyFile, nil -} - -// loadPrivateKey parse the RSA private key with optional passphrase. -func loadPrivateKey(privateKeyFile string, pass []byte) (rsaPrivateKey *rsa.PrivateKey, err error) { - if len(privateKeyFile) == 0 { - return nil, nil - } - - var ( - logp = `loadPrivateKey` - errPassMissing = &ssh.PassphraseMissingError{} - - privateKey interface{} - stdin int - rawPem []byte - ok bool - ) - - rawPem, err = os.ReadFile(privateKeyFile) - if err != nil { - return nil, fmt.Errorf(`%s: %w`, logp, err) - } - - if len(pass) == 0 { - privateKey, err = ssh.ParseRawPrivateKey(rawPem) - } else { - privateKey, err = ssh.ParseRawPrivateKeyWithPassphrase(rawPem, pass) - } - if err != nil { - if !errors.As(err, &errPassMissing) { - return nil, fmt.Errorf(`%s %q: %w`, logp, privateKeyFile, err) - } - - fmt.Printf(`Enter passphrase for %s: `, privateKeyFile) - - stdin = int(os.Stdin.Fd()) - - pass, err = term.ReadPassword(stdin) - fmt.Println() - if err != nil { - return nil, fmt.Errorf(`%s %q: %w`, logp, privateKeyFile, err) - } - - return loadPrivateKey(privateKeyFile, pass) - } - rsaPrivateKey, ok = privateKey.(*rsa.PrivateKey) - if !ok { - return nil, fmt.Errorf(`%s: invalid or unsupported private key`, logp) - } - - return rsaPrivateKey, nil -} - // Add new issuer to the config. func (cli *Cli) Add(issuer *Issuer) (err error) { if issuer == nil { @@ -134,7 +54,7 @@ func (cli *Cli) Add(issuer *Issuer) (err error) { var logp = `Add` - cli.cfg.privateKey, err = loadPrivateKey(cli.cfg.PrivateKey, nil) + err = cli.cfg.loadPrivateKey() if err != nil { return fmt.Errorf(`%s: %w`, logp, err) } @@ -164,7 +84,7 @@ func (cli *Cli) Generate(label string, n int) (listOtp []string, err error) { proto totp.Protocol ) - cli.cfg.privateKey, err = loadPrivateKey(cli.cfg.PrivateKey, nil) + err = cli.cfg.loadPrivateKey() if err != nil { return nil, fmt.Errorf(`%s: %w`, logp, err) } @@ -203,7 +123,7 @@ func (cli *Cli) Get(label string) (issuer *Issuer, err error) { var logp = `Get` if cli.cfg.privateKey == nil { - cli.cfg.privateKey, err = loadPrivateKey(cli.cfg.PrivateKey, nil) + err = cli.cfg.loadPrivateKey() if err != nil { return nil, fmt.Errorf(`%s: %w`, logp, err) } @@ -226,7 +146,7 @@ func (cli *Cli) Import(providerName, file string) (n int, err error) { issuer *Issuer ) - cli.cfg.privateKey, err = loadPrivateKey(cli.cfg.PrivateKey, nil) + err = cli.cfg.loadPrivateKey() if err != nil { return 0, fmt.Errorf(`%s: %w`, logp, err) } @@ -301,20 +221,24 @@ 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. +// RemovePrivateKey decrypt the issuer's value (hash:secret...) using +// current private key and store it back to file as plain text. +// The current private key file will be removed from gotp directory. +// +// If no private key file, this method does nothing. func (cli *Cli) RemovePrivateKey() (err error) { - if cli.cfg.privateKey == nil { - return nil - } - var logp = `RemovePrivateKey` - cli.cfg.privateKey, err = loadPrivateKey(cli.cfg.PrivateKey, nil) + err = cli.cfg.loadPrivateKey() if err != nil { return fmt.Errorf(`%s: %w`, logp, err) } + if cli.cfg.privateKey == nil { + // The private key file is not exist. + return nil + } + var ( oldPrivateKey = cli.cfg.privateKey oldIssuers = cli.cfg.Issuers @@ -341,13 +265,18 @@ func (cli *Cli) RemovePrivateKey() (err error) { } } - cli.cfg.PrivateKey = `` - err = cli.cfg.save() if err != nil { return fmt.Errorf(`%s: %w`, logp, err) } + err = os.Remove(cli.cfg.privateKeyFile) + if err != nil { + return fmt.Errorf(`%s: %w`, logp, err) + } + + cli.cfg.privateKeyFile = `` + return nil } @@ -386,16 +315,20 @@ func (cli *Cli) Rename(label, newLabel string) (err error) { return nil } -// SetPrivateKey encrypt all the OTP secret using the private key. +// SetPrivateKey encrypt all the OTP secret using the new private key. // The only accepted private key is RSA. -func (cli *Cli) SetPrivateKey(privateKeyFile string) (err error) { +// If the pkeyFile is valid, it will be copied to +// "$XDG_CONFIG_DIR/gotp/gotp.key". +func (cli *Cli) SetPrivateKey(pkeyFile string) (err error) { var ( logp = `SetPrivateKey` oldIssuers = cli.cfg.Issuers oldPrivateKey = cli.cfg.privateKey ) - cli.cfg.privateKey, err = loadPrivateKey(privateKeyFile, nil) + cli.cfg.privateKeyFile = pkeyFile + + err = cli.cfg.loadPrivateKey() if err != nil { return fmt.Errorf(`%s: %w`, logp, err) } @@ -422,13 +355,23 @@ func (cli *Cli) SetPrivateKey(privateKeyFile string) (err error) { } } - cli.cfg.PrivateKey = privateKeyFile - err = cli.cfg.save() if err != nil { return fmt.Errorf(`%s: %w`, logp, err) } + var expPrivateKeyPath = filepath.Join(cli.cfg.dir, privateKeyFile) + + if expPrivateKeyPath != pkeyFile { + // Copy the private key file if the path is not + // "$configDir/gotp.key". + err = libos.Copy(expPrivateKeyPath, pkeyFile) + if err != nil { + return fmt.Errorf(`%s: %w`, logp, err) + } + cli.cfg.privateKeyFile = expPrivateKeyPath + } + return nil } diff --git a/cli_test.go b/cli_test.go index bf15eec..2ae9f8e 100644 --- a/cli_test.go +++ b/cli_test.go @@ -13,53 +13,6 @@ import ( "github.com/shuLhan/share/lib/test" ) -func TestCli_inputPrivateKey(t *testing.T) { - type testCase struct { - desc string - privateKey string - exp string - } - - var ( - cli = &Cli{ - cfg: &config{ - file: `testdata/save.conf`, - isNotExist: true, - }, - } - - c testCase - r *os.File - w *os.File - gotPrivateKeyFile string - err error - ) - - var cases = []testCase{{ - desc: `Without private key`, - exp: "[gotp]\nprivate_key =\n", - }, { - desc: `With private key`, - privateKey: `testdata/rsa`, - }} - - for _, c = range cases { - r, w, err = os.Pipe() - if err != nil { - t.Fatal(err) - } - - fmt.Fprintf(w, "%s\n", c.privateKey) - - gotPrivateKeyFile, err = cli.inputPrivateKey(r) - if err != nil { - t.Fatal(err) - } - - test.Assert(t, cli.cfg.file, c.privateKey, gotPrivateKeyFile) - } -} - func TestCli_Add(t *testing.T) { type testCase struct { issuer *Issuer @@ -85,10 +38,8 @@ func TestCli_Add(t *testing.T) { } var cases = []testCase{{ - desc: `With nil issuer`, - expConfig: `[gotp] -private_key = -`, + desc: `With nil issuer`, + expConfig: ``, }, { desc: `With invalid label`, issuer: &Issuer{ @@ -111,9 +62,6 @@ private_key = }, expConfig: `[gotp "issuer"] test = SHA1:x:6:30: - -[gotp] -private_key = `, }} @@ -153,7 +101,9 @@ func TestCli_SetPrivateKey(t *testing.T) { var ( cli = &Cli{} - cfg = &config{} + cfg = &config{ + dir: t.TempDir(), + } rawConfig []byte ) @@ -166,16 +116,16 @@ func TestCli_SetPrivateKey(t *testing.T) { } cli.cfg = cfg - // Set the private key. + // Set the private key generated from openssl command. err = cli.SetPrivateKey(tdata.Flag[`private_key_openssl`]) if err != nil { t.Fatal(err) } - // Change the private key. + // Change the private key generated from ssh-keygen command. - err = cli.SetPrivateKey(tdata.Flag[`private_key_openssl`]) + err = cli.SetPrivateKey(tdata.Flag[`private_key_openssh`]) if err != nil { t.Fatal(err) } @@ -193,7 +143,7 @@ func TestCli_SetPrivateKey(t *testing.T) { } cli.cfg = cfg - cli.cfg.privateKey, err = loadPrivateKey(cli.cfg.PrivateKey, nil) + err = cli.cfg.loadPrivateKey() if err != nil { t.Fatal(err) } @@ -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 { diff --git a/config_test.go b/config_test.go index 477b438..be61e5c 100644 --- a/config_test.go +++ b/config_test.go @@ -4,8 +4,6 @@ package gotp import ( - "os" - "path/filepath" "testing" "github.com/shuLhan/share/lib/test" @@ -23,19 +21,21 @@ func TestNewConfig(t *testing.T) { desc: `With file not exist`, configFile: `testdata/config-not-exist`, expConfig: &config{ - file: `testdata/config-not-exist`, - isNotExist: true, + dir: `testdata`, + file: `testdata/config-not-exist`, + privateKeyFile: `testdata/gotp.key`, }, }, { desc: `With openssh rsa`, configFile: `testdata/with_private_key.conf`, expConfig: &config{ - PrivateKey: `testdata/keys/rsa-openssl.pem`, Issuers: map[string]string{ `email-domain`: `XYZ`, `test`: `ABCD`, }, - file: `testdata/with_private_key.conf`, + dir: `testdata`, + privateKeyFile: `testdata/gotp.key`, + file: `testdata/with_private_key.conf`, }, }} @@ -60,13 +60,12 @@ func TestNewConfig(t *testing.T) { } } -func TestMarshaler(t *testing.T) { +func TestConfigMarshalText(t *testing.T) { var ( cfg = config{} - tdata *test.Data - userHomeDir string - err error + tdata *test.Data + err error ) tdata, err = test.LoadData(`testdata/config_marshaler_test.txt`) @@ -79,15 +78,6 @@ func TestMarshaler(t *testing.T) { t.Fatal(err) } - userHomeDir, err = os.UserHomeDir() - if err != nil { - t.Fatal(err) - } - - var expPrivateKey = filepath.Join(userHomeDir, `myprivatekey.pem`) - - test.Assert(t, `UnmarshalText: PrivateKey`, expPrivateKey, cfg.PrivateKey) - var gotText []byte gotText, err = cfg.MarshalText() @@ -11,16 +11,19 @@ import ( // List of available algorithm for Provider. const ( - HashSHA1 = `SHA1` // Default algorithm. - HashSHA256 = `SHA256` - HashSHA512 = `SHA512` + HashSHA1 = `SHA1` // Default algorithm. + HashSHA256 = `SHA256` + HashSHA512 = `SHA512` + defaultHash = HashSHA1 ) const ( - configFile = `gotp.conf` - defaultHash = HashSHA1 + configFile = `gotp.conf` + privateKeyFile = `gotp.key` +) - // List of known providers +// List of known providers. +const ( providerNameAegis = `aegis` ) diff --git a/testdata/cli_SetPrivateKey_test.txt b/testdata/cli_SetPrivateKey_test.txt index b767b01..8da9654 100644 --- a/testdata/cli_SetPrivateKey_test.txt +++ b/testdata/cli_SetPrivateKey_test.txt @@ -11,9 +11,6 @@ test3 = SHA1:c:6:30: test4 = SHA1:d:6:30: test5 = SHA1:e:6:30: -[gotp] -private_key = - <<< issuers test1 = SHA1:a:6:30: test2 = SHA1:b:6:30: diff --git a/testdata/config_marshaler_test.txt b/testdata/config_marshaler_test.txt index b354b28..fb8ada9 100644 --- a/testdata/config_marshaler_test.txt +++ b/testdata/config_marshaler_test.txt @@ -5,13 +5,7 @@ Test UnmarshalText and MarshalText on config. test1 = SHA1:a:6:30: test2 = SHA1:b:6:30: -[gotp] -private_key = ~/myprivatekey.pem - <<< output.ini [gotp "issuer"] test1 = SHA1:a:6:30: test2 = SHA1:b:6:30: - -[gotp] -private_key = ~/myprivatekey.pem diff --git a/testdata/with_private_key.conf b/testdata/with_private_key.conf index 51988c3..706112c 100644 --- a/testdata/with_private_key.conf +++ b/testdata/with_private_key.conf @@ -1,6 +1,3 @@ -[gotp] -private_key = testdata/keys/rsa-openssl.pem - [gotp "issuer"] test = ABCD email-domain = XYZ |
