////////////////////////////////////////////////////////////////////////// package libvault ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// import ( "errors" log "github.com/sirupsen/logrus" "os" "strings" "time" ) ////////////////////////////////////////////////////////////////////////// type Token struct { Token string expires time.Time } ////////////////////////////////////////////////////////////////////////// // read and save token to a file func NewTokenFromFile(filename string) (*Token, error) { // default the filename if not passed as arg if filename == "" { filename = VAULT_TOKEN_FILE } // read the contents of the file b, err := os.ReadFile(filename) if err != nil { log.WithFields(log.Fields{ "filename": filename, "error": err, }).Error("libvault: failed to read vault token from file") return nil, err } // get first line and trim any whitespace ts, _, _ := strings.Cut(string(b), "\n") ts = strings.TrimSpace(ts) if ts == "" { log.WithFields(log.Fields{ "filename": filename, "raw": string(b), }).Error("libvault: failed to parse vault token from file") return nil, errors.New("libvault: failed to parse vault token from file") } log.WithFields(log.Fields{ "filename": filename, "token": ts, }).Debug("libvault: successfully read vault token") return &Token{Token: ts}, nil } func (t *Token) SaveToFile(filename string) error { if filename == "" { filename = VAULT_TOKEN_FILE } data := []byte(t.Token + "\n") if err := os.WriteFile(filename, data, 0600); err != nil { log.WithFields(log.Fields{ "filename": filename, "error": err, }).Error("libvault: failed to write token to file") return err } log.WithFields(log.Fields{ "filename": filename, }).Debug("libvault: successfully saved vault token") return nil } ////////////////////////////////////////////////////////////////////////// // find token expiry date func (t *Token) Expires() (time.Time, error) { if t.expires.IsZero() { resp := &struct { Data *struct { ExpireTime time.Time `json:"expire_time"` } `json:"data"` }{} if err := vault.GET(t, "/auth/token/lookup-self", resp); err != nil { log.WithFields(log.Fields{ "token": t.Token, }).Error("libvault: failed to determine token expiry date") return t.expires, err } t.expires = resp.Data.ExpireTime } return t.expires, nil } ////////////////////////////////////////////////////////////////////////// // renew token func (t *Token) Renew(increment time.Duration) error { expiry, err := t.Expires() if err != nil { return err } // check if token should be renewed ttl := expiry.Sub(time.Now()) if ttl.Seconds() > (VAULT_RENEW_PERIOD.Seconds()) { log.WithFields(log.Fields{ "expiry": expiry.String(), "ttl": ttl.String(), }).Debug("Token renewal not required") return nil } // renew token if increment == 0 { increment = VAULT_TTL } req := &struct { Increment string `json:"increment"` }{Increment: increment.String()} if err := vault.POST(t, "/auth/token/renew-self", req, nil); err != nil { log.WithFields(log.Fields{ "token": t.Token, "expiry": expiry.String(), "ttl": ttl.String(), "increment": increment.String(), }).Error("libvault: failed to renew token") return err } // reset expiry t.expires = time.Time{} return nil } ////////////////////////////////////////////////////////////////////////// // end of file