mirror of
https://github.com/gravitational/teleport
synced 2024-10-21 01:34:01 +00:00
Fix remaining gosimple findings
List of fixed items: ``` integration/helpers.go:1279:2 gosimple S1000: should use for range instead of for { select {} } integration/integration_test.go:144:5 gosimple S1009: should omit nil check; len() for nil slices is defined as zero integration/integration_test.go:173:5 gosimple S1009: should omit nil check; len() for nil slices is defined as zero integration/integration_test.go:296:28 gosimple S1019: should use make(chan error) instead integration/integration_test.go:570:41 gosimple S1019: should use make(chan interface{}) instead integration/integration_test.go:685:40 gosimple S1019: should use make(chan interface{}) instead integration/integration_test.go:759:33 gosimple S1019: should use make(chan string) instead lib/auth/init_test.go:62:2 gosimple S1021: should merge variable declaration with assignment on next line lib/auth/tls_test.go:1658:22 gosimple S1024: should use time.Until instead of t.Sub(time.Now()) lib/backend/dynamo/dynamodbbk.go:420:5 gosimple S1004: should use !bytes.Equal(expected.Key, replaceWith.Key) instead lib/backend/dynamo/dynamodbbk.go:656:12 gosimple S1039: unnecessary use of fmt.Sprintf lib/backend/etcdbk/etcd.go:458:5 gosimple S1004: should use !bytes.Equal(expected.Key, replaceWith.Key) instead lib/backend/firestore/firestorebk.go:407:5 gosimple S1004: should use !bytes.Equal(expected.Key, replaceWith.Key) instead lib/backend/lite/lite.go:317:5 gosimple S1004: should use !bytes.Equal(expected.Key, replaceWith.Key) instead lib/backend/lite/lite.go:336:6 gosimple S1004: should use !bytes.Equal(value, expected.Value) instead lib/backend/memory/memory.go:365:5 gosimple S1004: should use !bytes.Equal(expected.Key, replaceWith.Key) instead lib/backend/memory/memory.go:376:5 gosimple S1004: should use !bytes.Equal(existingItem.Value, expected.Value) instead lib/backend/test/suite.go:327:10 gosimple S1024: should use time.Until instead of t.Sub(time.Now()) lib/client/api.go:1410:9 gosimple S1003: should use strings.ContainsRune(name, ':') instead lib/client/api.go:2355:32 gosimple S1019: should use make([]ForwardedPort, len(spec)) instead lib/client/keyagent_test.go:85:2 gosimple S1021: should merge variable declaration with assignment on next line lib/client/player.go:54:33 gosimple S1019: should use make(chan int) instead lib/config/configuration.go:1024:52 gosimple S1019: should use make(services.CommandLabels) instead lib/config/configuration.go:1025:44 gosimple S1019: should use make(map[string]string) instead lib/config/configuration.go:930:21 gosimple S1003: should use strings.Contains(clf.Roles, defaults.RoleNode) instead lib/config/configuration.go:931:22 gosimple S1003: should use strings.Contains(clf.Roles, defaults.RoleAuthService) instead lib/config/configuration.go:932:23 gosimple S1003: should use strings.Contains(clf.Roles, defaults.RoleProxy) instead lib/service/supervisor.go:387:2 gosimple S1001: should use copy() instead of a loop lib/tlsca/parsegen.go:140:9 gosimple S1034: assigning the result of this type assertion to a variable (switch generalKey := generalKey.(type)) could eliminate type assertions in switch cases lib/utils/certs.go:140:9 gosimple S1034: assigning the result of this type assertion to a variable (switch generalKey := generalKey.(type)) could eliminate type assertions in switch cases lib/utils/certs.go:167:40 gosimple S1010: should omit second index in slice, s[a:len(s)] is identical to s[a:] lib/utils/certs.go:204:5 gosimple S1004: should use !bytes.Equal(certificateChain[0].SubjectKeyId, certificateChain[0].AuthorityKeyId) instead lib/utils/parse/parse.go:116:45 gosimple S1003: should use strings.Contains(variable, "}}") instead lib/utils/parse/parse.go:116:6 gosimple S1003: should use strings.Contains(variable, "{{") instead lib/utils/socks/socks.go:192:10 gosimple S1025: should use String() instead of fmt.Sprintf lib/utils/socks/socks.go:199:10 gosimple S1025: should use String() instead of fmt.Sprintf lib/web/apiserver.go:1054:18 gosimple S1024: should use time.Until instead of t.Sub(time.Now()) lib/web/apiserver.go:1954:9 gosimple S1039: unnecessary use of fmt.Sprintf tool/tsh/tsh.go:1193:14 gosimple S1024: should use time.Until instead of t.Sub(time.Now()) ```
This commit is contained in:
parent
983b735e67
commit
617afc7e6f
|
@ -1276,23 +1276,17 @@ func (s *discardServer) HandleNewChan(ccx *sshutils.ConnectionContext, newChanne
|
|||
func (s *discardServer) handleChannel(channel ssh.Channel, reqs <-chan *ssh.Request) {
|
||||
defer channel.Close()
|
||||
|
||||
for {
|
||||
select {
|
||||
case req := <-reqs:
|
||||
if req == nil {
|
||||
return
|
||||
}
|
||||
if req.Type == "exec" {
|
||||
successPayload := ssh.Marshal(struct{ C uint32 }{C: uint32(0)})
|
||||
channel.SendRequest("exit-status", false, successPayload)
|
||||
if req.WantReply {
|
||||
req.Reply(true, nil)
|
||||
}
|
||||
return
|
||||
}
|
||||
for req := range reqs {
|
||||
if req.Type == "exec" {
|
||||
successPayload := ssh.Marshal(struct{ C uint32 }{C: uint32(0)})
|
||||
channel.SendRequest("exit-status", false, successPayload)
|
||||
if req.WantReply {
|
||||
req.Reply(true, nil)
|
||||
}
|
||||
return
|
||||
}
|
||||
if req.WantReply {
|
||||
req.Reply(true, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,7 +141,7 @@ func (s *IntSuite) SetUpTest(c *check.C) {
|
|||
func (s *IntSuite) newUnstartedTeleport(c *check.C, logins []string, enableSSH bool) *TeleInstance {
|
||||
t := NewInstance(InstanceConfig{ClusterName: Site, HostID: HostID, NodeName: Host, Ports: s.getPorts(5), Priv: s.priv, Pub: s.pub})
|
||||
// use passed logins, but use suite's default login if nothing was passed
|
||||
if logins == nil || len(logins) == 0 {
|
||||
if len(logins) == 0 {
|
||||
logins = []string{s.me.Username}
|
||||
}
|
||||
for _, login := range logins {
|
||||
|
@ -170,7 +170,7 @@ func (s *IntSuite) newTeleportWithConfig(c *check.C, logins []string, instanceSe
|
|||
t := NewInstance(InstanceConfig{ClusterName: Site, HostID: HostID, NodeName: Host, Ports: s.getPorts(5), Priv: s.priv, Pub: s.pub})
|
||||
|
||||
// use passed logins, but use suite's default login if nothing was passed
|
||||
if logins == nil || len(logins) == 0 {
|
||||
if len(logins) == 0 {
|
||||
logins = []string{s.me.Username}
|
||||
}
|
||||
for _, login := range logins {
|
||||
|
@ -293,7 +293,7 @@ func (s *IntSuite) TestAuditOn(c *check.C) {
|
|||
c.Assert(len(sessions), check.Equals, 0)
|
||||
|
||||
// create interactive session (this goroutine is this user's terminal time)
|
||||
endC := make(chan error, 0)
|
||||
endC := make(chan error)
|
||||
myTerm := NewTerminal(250)
|
||||
go func() {
|
||||
cl, err := t.NewClient(ClientConfig{
|
||||
|
@ -567,7 +567,7 @@ func (s *IntSuite) TestInteroperability(c *check.C) {
|
|||
cl.Stderr = outbuf
|
||||
|
||||
// run command and wait a maximum of 10 seconds for it to complete
|
||||
sessionEndC := make(chan interface{}, 0)
|
||||
sessionEndC := make(chan interface{})
|
||||
go func() {
|
||||
// don't check for err, because sometimes this process should fail
|
||||
// with an error and that's what the test is checking for.
|
||||
|
@ -682,7 +682,7 @@ func (s *IntSuite) TestInteractive(c *check.C) {
|
|||
t := s.newTeleport(c, nil, true)
|
||||
defer t.StopAll()
|
||||
|
||||
sessionEndC := make(chan interface{}, 0)
|
||||
sessionEndC := make(chan interface{})
|
||||
|
||||
// get a reference to site obj:
|
||||
site := t.GetSiteAPI(Site)
|
||||
|
@ -756,7 +756,7 @@ func (s *IntSuite) TestShutdown(c *check.C) {
|
|||
person := NewTerminal(250)
|
||||
|
||||
// commandsC receive commands
|
||||
commandsC := make(chan string, 0)
|
||||
commandsC := make(chan string)
|
||||
|
||||
// PersonA: SSH into the server, wait one second, then type some commands on stdin:
|
||||
openSession := func() {
|
||||
|
|
|
@ -59,8 +59,7 @@ func (s *AuthInitSuite) SetUpTest(c *C) {
|
|||
}
|
||||
|
||||
func (s *AuthInitSuite) TearDownTest(c *C) {
|
||||
var err error
|
||||
err = os.RemoveAll(s.tempDir)
|
||||
err := os.RemoveAll(s.tempDir)
|
||||
c.Assert(err, IsNil)
|
||||
}
|
||||
|
||||
|
|
|
@ -1655,7 +1655,7 @@ func (s *TLSSuite) TestGenerateCerts(c *check.C) {
|
|||
c.Assert(err, check.IsNil)
|
||||
parsedCert, _ := parsedKey.(*ssh.Certificate)
|
||||
validBefore := time.Unix(int64(parsedCert.ValidBefore), 0)
|
||||
return parsedCert, validBefore.Sub(time.Now())
|
||||
return parsedCert, time.Until(validBefore)
|
||||
}
|
||||
_, diff := parseCert(userCerts.SSH)
|
||||
c.Assert(diff < testUser2.TTL, check.Equals, true, check.Commentf("expected %v < %v", diff, testUser2.TTL))
|
||||
|
|
|
@ -20,7 +20,6 @@ package dynamo
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
@ -417,7 +416,7 @@ func (b *DynamoDBBackend) CompareAndSwap(ctx context.Context, expected backend.I
|
|||
if len(replaceWith.Key) == 0 {
|
||||
return nil, trace.BadParameter("missing parameter Key")
|
||||
}
|
||||
if bytes.Compare(expected.Key, replaceWith.Key) != 0 {
|
||||
if !bytes.Equal(expected.Key, replaceWith.Key) {
|
||||
return nil, trace.BadParameter("expected and replaceWith keys should match")
|
||||
}
|
||||
r := record{
|
||||
|
@ -653,7 +652,7 @@ func (b *DynamoDBBackend) getRecords(ctx context.Context, startKey, endKey strin
|
|||
|
||||
// filter out expired items, otherwise they might show up in the query
|
||||
// http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/howitworks-ttl.html
|
||||
filter := fmt.Sprintf("attribute_not_exists(Expires) OR Expires >= :timestamp")
|
||||
filter := "attribute_not_exists(Expires) OR Expires >= :timestamp"
|
||||
av, err := dynamodbattribute.MarshalMap(attrV)
|
||||
if err != nil {
|
||||
return nil, convertError(err)
|
||||
|
|
|
@ -455,7 +455,7 @@ func (b *EtcdBackend) CompareAndSwap(ctx context.Context, expected backend.Item,
|
|||
if len(replaceWith.Key) == 0 {
|
||||
return nil, trace.BadParameter("missing parameter Key")
|
||||
}
|
||||
if bytes.Compare(expected.Key, replaceWith.Key) != 0 {
|
||||
if !bytes.Equal(expected.Key, replaceWith.Key) {
|
||||
return nil, trace.BadParameter("expected and replaceWith keys should match")
|
||||
}
|
||||
var opts []clientv3.OpOption
|
||||
|
|
|
@ -406,7 +406,7 @@ func (b *FirestoreBackend) CompareAndSwap(ctx context.Context, expected backend.
|
|||
if len(replaceWith.Key) == 0 {
|
||||
return nil, trace.BadParameter("missing parameter Key")
|
||||
}
|
||||
if bytes.Compare(expected.Key, replaceWith.Key) != 0 {
|
||||
if !bytes.Equal(expected.Key, replaceWith.Key) {
|
||||
return nil, trace.BadParameter("expected and replaceWith keys should match")
|
||||
}
|
||||
|
||||
|
|
|
@ -314,7 +314,7 @@ func (l *LiteBackend) CompareAndSwap(ctx context.Context, expected backend.Item,
|
|||
if len(replaceWith.Key) == 0 {
|
||||
return nil, trace.BadParameter("missing parameter Key")
|
||||
}
|
||||
if bytes.Compare(expected.Key, replaceWith.Key) != 0 {
|
||||
if !bytes.Equal(expected.Key, replaceWith.Key) {
|
||||
return nil, trace.BadParameter("expected and replaceWith keys should match")
|
||||
}
|
||||
now := l.clock.Now().UTC()
|
||||
|
@ -333,7 +333,7 @@ func (l *LiteBackend) CompareAndSwap(ctx context.Context, expected backend.Item,
|
|||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
if bytes.Compare(value, expected.Value) != 0 {
|
||||
if !bytes.Equal(value, expected.Value) {
|
||||
return trace.CompareFailed("current value does not match expected for %v", string(expected.Key))
|
||||
}
|
||||
|
||||
|
|
|
@ -362,7 +362,7 @@ func (m *Memory) CompareAndSwap(ctx context.Context, expected backend.Item, repl
|
|||
if len(replaceWith.Key) == 0 {
|
||||
return nil, trace.BadParameter("missing parameter Key")
|
||||
}
|
||||
if bytes.Compare(expected.Key, replaceWith.Key) != 0 {
|
||||
if !bytes.Equal(expected.Key, replaceWith.Key) {
|
||||
return nil, trace.BadParameter("expected and replaceWith keys should match")
|
||||
}
|
||||
m.Lock()
|
||||
|
@ -373,7 +373,7 @@ func (m *Memory) CompareAndSwap(ctx context.Context, expected backend.Item, repl
|
|||
return nil, trace.CompareFailed("key %q is not found", string(expected.Key))
|
||||
}
|
||||
existingItem := i.(*btreeItem).Item
|
||||
if bytes.Compare(existingItem.Value, expected.Value) != 0 {
|
||||
if !bytes.Equal(existingItem.Value, expected.Value) {
|
||||
return nil, trace.CompareFailed("current value does not match expected for %v", string(expected.Key))
|
||||
}
|
||||
event := backend.Event{
|
||||
|
|
|
@ -324,7 +324,7 @@ func (s *BackendSuite) KeepAlive(c *check.C) {
|
|||
c.Assert(err, check.IsNil)
|
||||
|
||||
// should have expired if not keep alive
|
||||
diff := addSeconds(time.Now(), 1).Sub(time.Now())
|
||||
diff := time.Until(addSeconds(time.Now(), 1))
|
||||
time.Sleep(diff + 100*time.Millisecond)
|
||||
|
||||
out, err = s.B.Get(ctx, item.Key)
|
||||
|
|
|
@ -1407,7 +1407,7 @@ func (tc *TeleportClient) SCP(ctx context.Context, args []string, port int, recu
|
|||
}
|
||||
|
||||
func isRemoteDest(name string) bool {
|
||||
return strings.IndexRune(name, ':') >= 0
|
||||
return strings.ContainsRune(name, ':')
|
||||
}
|
||||
|
||||
// ListNodes returns a list of nodes connected to a proxy
|
||||
|
@ -2373,7 +2373,7 @@ func ParsePortForwardSpec(spec []string) (ports ForwardedPorts, err error) {
|
|||
return ports, nil
|
||||
}
|
||||
const errTemplate = "Invalid port forwarding spec: '%s'. Could be like `80:remote.host:80`"
|
||||
ports = make([]ForwardedPort, len(spec), len(spec))
|
||||
ports = make([]ForwardedPort, len(spec))
|
||||
|
||||
for i, str := range spec {
|
||||
parts := strings.Split(str, ":")
|
||||
|
|
|
@ -82,8 +82,7 @@ func (s *KeyAgentTestSuite) SetUpSuite(c *check.C) {
|
|||
}
|
||||
|
||||
func (s *KeyAgentTestSuite) TearDownSuite(c *check.C) {
|
||||
var err error
|
||||
err = os.RemoveAll(s.keyDir)
|
||||
err := os.RemoveAll(s.keyDir)
|
||||
c.Assert(err, check.IsNil)
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ func newSessionPlayer(sessionEvents []events.EventFields, stream []byte) *sessio
|
|||
return &sessionPlayer{
|
||||
stream: stream,
|
||||
sessionEvents: sessionEvents,
|
||||
stopC: make(chan int, 0),
|
||||
stopC: make(chan int),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -927,9 +927,9 @@ func Configure(clf *CommandLineFlags, cfg *service.Config) error {
|
|||
if err := validateRoles(clf.Roles); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
cfg.SSH.Enabled = strings.Index(clf.Roles, defaults.RoleNode) != -1
|
||||
cfg.Auth.Enabled = strings.Index(clf.Roles, defaults.RoleAuthService) != -1
|
||||
cfg.Proxy.Enabled = strings.Index(clf.Roles, defaults.RoleProxy) != -1
|
||||
cfg.SSH.Enabled = strings.Contains(clf.Roles, defaults.RoleNode)
|
||||
cfg.Auth.Enabled = strings.Contains(clf.Roles, defaults.RoleAuthService)
|
||||
cfg.Proxy.Enabled = strings.Contains(clf.Roles, defaults.RoleProxy)
|
||||
}
|
||||
|
||||
// apply --auth-server flag:
|
||||
|
@ -1021,8 +1021,8 @@ func parseLabels(spec string, sshConf *service.SSHConfig) error {
|
|||
return trace.Wrap(err)
|
||||
}
|
||||
if len(lmap) > 0 {
|
||||
sshConf.CmdLabels = make(services.CommandLabels, 0)
|
||||
sshConf.Labels = make(map[string]string, 0)
|
||||
sshConf.CmdLabels = make(services.CommandLabels)
|
||||
sshConf.Labels = make(map[string]string)
|
||||
}
|
||||
// see which labels are actually command labels:
|
||||
for key, value := range lmap {
|
||||
|
|
|
@ -384,9 +384,7 @@ func (s *LocalSupervisor) getWaiters(name string) []*waiter {
|
|||
|
||||
waiters := s.eventWaiters[name]
|
||||
out := make([]*waiter, len(waiters))
|
||||
for i := range waiters {
|
||||
out[i] = waiters[i]
|
||||
}
|
||||
copy(out, waiters)
|
||||
return out
|
||||
}
|
||||
|
||||
|
|
|
@ -137,11 +137,11 @@ func ParsePrivateKeyDER(der []byte) (crypto.Signer, error) {
|
|||
}
|
||||
}
|
||||
|
||||
switch generalKey.(type) {
|
||||
switch k := generalKey.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
return generalKey.(*rsa.PrivateKey), nil
|
||||
return k, nil
|
||||
case *ecdsa.PrivateKey:
|
||||
return generalKey.(*ecdsa.PrivateKey), nil
|
||||
return k, nil
|
||||
}
|
||||
|
||||
return nil, trace.BadParameter("unsupported private key type")
|
||||
|
|
|
@ -137,11 +137,11 @@ func ParsePrivateKeyDER(der []byte) (crypto.Signer, error) {
|
|||
}
|
||||
}
|
||||
|
||||
switch generalKey.(type) {
|
||||
switch k := generalKey.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
return generalKey.(*rsa.PrivateKey), nil
|
||||
return k, nil
|
||||
case *ecdsa.PrivateKey:
|
||||
return generalKey.(*ecdsa.PrivateKey), nil
|
||||
return k, nil
|
||||
}
|
||||
|
||||
return nil, trace.BadParameter("unsupported private key type")
|
||||
|
@ -164,7 +164,7 @@ func VerifyCertificateChain(certificateChain []*x509.Certificate) error {
|
|||
// extract intermediate certificate chain.
|
||||
intermediates := x509.NewCertPool()
|
||||
if len(certificateChain) > 1 {
|
||||
for _, v := range certificateChain[1:len(certificateChain)] {
|
||||
for _, v := range certificateChain[1:] {
|
||||
intermediates.AddCert(v)
|
||||
}
|
||||
}
|
||||
|
@ -201,11 +201,7 @@ func IsSelfSigned(certificateChain []*x509.Certificate) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
if bytes.Compare(certificateChain[0].SubjectKeyId, certificateChain[0].AuthorityKeyId) != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
return bytes.Equal(certificateChain[0].SubjectKeyId, certificateChain[0].AuthorityKeyId)
|
||||
}
|
||||
|
||||
// ReadCertificateChain parses PEM encoded bytes that can contain one or
|
||||
|
|
|
@ -113,7 +113,7 @@ var reVariable = regexp.MustCompile(
|
|||
func RoleVariable(variable string) (*Expression, error) {
|
||||
match := reVariable.FindStringSubmatch(variable)
|
||||
if len(match) == 0 {
|
||||
if strings.Index(variable, "{{") != -1 || strings.Index(variable, "}}") != -1 {
|
||||
if strings.Contains(variable, "{{") || strings.Contains(variable, "}}") {
|
||||
return nil, trace.BadParameter(
|
||||
"%q is using template brackets '{{' or '}}', however expression does not parse, make sure the format is {{variable}}",
|
||||
variable)
|
||||
|
|
|
@ -19,7 +19,6 @@ package socks
|
|||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
|
@ -189,14 +188,14 @@ func readDestAddr(conn net.Conn) (string, error) {
|
|||
if err != nil {
|
||||
return "", trace.Wrap(err)
|
||||
}
|
||||
return fmt.Sprintf("%s", net.IP(destAddr)), nil
|
||||
return net.IP(destAddr).String(), nil
|
||||
case socks5AddressTypeIPv6:
|
||||
destAddr := make([]byte, net.IPv6len)
|
||||
_, err = io.ReadFull(conn, destAddr)
|
||||
if err != nil {
|
||||
return "", trace.Wrap(err)
|
||||
}
|
||||
return fmt.Sprintf("%s", net.IP(destAddr)), nil
|
||||
return net.IP(destAddr).String(), nil
|
||||
case socks5AddressTypeDomainName:
|
||||
len, err := readByte(conn)
|
||||
if err != nil {
|
||||
|
|
|
@ -1051,7 +1051,7 @@ func NewSessionResponse(ctx *SessionContext) (*CreateSessionResponse, error) {
|
|||
return &CreateSessionResponse{
|
||||
Type: roundtrip.AuthBearer,
|
||||
Token: webSession.GetBearerToken(),
|
||||
ExpiresIn: int(webSession.GetBearerTokenExpiryTime().Sub(time.Now()) / time.Second),
|
||||
ExpiresIn: int(time.Until(webSession.GetBearerTokenExpiryTime()) / time.Second),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -1953,7 +1953,7 @@ func (h *Handler) validateTrustedCluster(w http.ResponseWriter, r *http.Request,
|
|||
}
|
||||
|
||||
func (h *Handler) String() string {
|
||||
return fmt.Sprintf("multi site")
|
||||
return "multi site"
|
||||
}
|
||||
|
||||
// currentSiteShortcut is a special shortcut that will return the first
|
||||
|
|
|
@ -1190,7 +1190,7 @@ func printStatus(debug bool, p *client.ProfileStatus, isActive bool) {
|
|||
} else {
|
||||
prefix = " "
|
||||
}
|
||||
duration := p.ValidUntil.Sub(time.Now())
|
||||
duration := time.Until(p.ValidUntil)
|
||||
humanDuration := "EXPIRED"
|
||||
if duration.Nanoseconds() > 0 {
|
||||
humanDuration = fmt.Sprintf("valid for %v", duration.Round(time.Minute))
|
||||
|
|
Loading…
Reference in a new issue