feat: totps - show remaining time (#12)
This commit is contained in:
parent
b040127bef
commit
90682c1ea8
|
@ -102,11 +102,10 @@ func Decrypt(password, text []byte) ([]byte, error) {
|
|||
|
||||
type Entry struct {
|
||||
Algorithm string `json:"algorithm"`
|
||||
Digits uint `json:"digits"`
|
||||
Digits uint8 `json:"digits"`
|
||||
Issuer string `json:"issuer"`
|
||||
Label string `json:"label"`
|
||||
LastUsed int64 `json:"last_used"`
|
||||
Period uint `json:"period"`
|
||||
Period uint32 `json:"period"`
|
||||
Secret string `json:"secret"`
|
||||
Tags []string `json:"tags"`
|
||||
Thumbnail string `json:"thumbnail"`
|
||||
|
|
|
@ -3,7 +3,6 @@ package internal_test
|
|||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Kichiyaki/gootp/internal"
|
||||
|
||||
|
@ -19,7 +18,6 @@ func TestEncryptDecrypt(t *testing.T) {
|
|||
Digits: 6,
|
||||
Issuer: "TestIssuer",
|
||||
Label: "TestLabel",
|
||||
LastUsed: time.Now().Unix(),
|
||||
Period: 30,
|
||||
Secret: "secret",
|
||||
Thumbnail: "Default",
|
||||
|
|
|
@ -9,30 +9,31 @@ import (
|
|||
"github.com/pquerna/otp/totp"
|
||||
)
|
||||
|
||||
func GenerateOTP(entry Entry, t time.Time) (string, error) {
|
||||
func GenerateOTP(entry Entry, t time.Time) (string, int64, error) {
|
||||
algorithm, err := parseAlgorithm(entry.Algorithm)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("parseAlgorithm: %w", err)
|
||||
return "", 0, fmt.Errorf("parseAlgorithm: %w", err)
|
||||
}
|
||||
|
||||
digits, err := parseDigits(entry.Digits)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("parseDigits: %w", err)
|
||||
return "", 0, fmt.Errorf("parseDigits: %w", err)
|
||||
}
|
||||
|
||||
switch strings.ToUpper(entry.Type) {
|
||||
case "TOTP":
|
||||
code, err := totp.GenerateCodeCustom(entry.Secret, t, totp.ValidateOpts{
|
||||
Algorithm: algorithm,
|
||||
Period: entry.Period,
|
||||
Period: uint(entry.Period),
|
||||
Digits: digits,
|
||||
})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("something went wrong while generating totp: %w", err)
|
||||
return "", 0, fmt.Errorf("something went wrong while generating totp: %w", err)
|
||||
}
|
||||
return code, nil
|
||||
period := int64(entry.Period)
|
||||
return code, period - (t.Unix() % period), nil
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported entry type: %s", entry.Type)
|
||||
return "", 0, fmt.Errorf("unsupported entry type: %s", entry.Type)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,7 +52,7 @@ func parseAlgorithm(algorithm string) (otp.Algorithm, error) {
|
|||
}
|
||||
}
|
||||
|
||||
func parseDigits(digits uint) (otp.Digits, error) {
|
||||
func parseDigits(digits uint8) (otp.Digits, error) {
|
||||
switch digits {
|
||||
case 6:
|
||||
return otp.DigitsSix, nil
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/charmbracelet/bubbles/list"
|
||||
|
@ -87,21 +88,25 @@ func (ui UI) tick() tea.Cmd {
|
|||
func entriesToItems(entries []Entry, t time.Time) []list.Item {
|
||||
items := make([]list.Item, len(entries))
|
||||
for i, e := range entries {
|
||||
title := e.Label
|
||||
if e.Issuer != "" {
|
||||
title = e.Issuer + " - " + e.Label
|
||||
}
|
||||
|
||||
otp, err := GenerateOTP(e, t)
|
||||
description := otp
|
||||
if err != nil {
|
||||
description = err.Error()
|
||||
}
|
||||
|
||||
items[i] = item{
|
||||
title: title,
|
||||
description: description,
|
||||
title: buildItemTitle(e.Issuer, e.Label),
|
||||
description: buildItemDescription(e, t),
|
||||
}
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
func buildItemTitle(issuer, label string) string {
|
||||
if issuer != "" {
|
||||
return issuer + " - " + label
|
||||
}
|
||||
return label
|
||||
}
|
||||
|
||||
func buildItemDescription(e Entry, t time.Time) string {
|
||||
otp, remaining, err := GenerateOTP(e, t)
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
return fmt.Sprintf("%s - %d", otp, remaining)
|
||||
}
|
||||
|
|
Reference in New Issue