Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions config/confpar/confpar.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// Package confpar provide the core parameters of the config
package confpar

import "time"
import (
"encoding/json"
"time"
)

// Access provides rules around any access
type Access struct {
Expand All @@ -19,7 +22,7 @@ type Access struct {
type AccessesWebhook struct {
URL string `json:"url"` // URL to call
Headers map[string]string `json:"headers"` // Token to use in the
Timeout time.Duration `json:"timeout"` // Max time request can take
Timeout Duration `json:"timeout"` // Max time request can take
}

// SyncAndDelete provides
Expand Down Expand Up @@ -65,7 +68,7 @@ type Content struct {
PublicHost string `json:"public_host"` // Public host to listen on
MaxClients int `json:"max_clients"` // Maximum clients who can connect
HashPlaintextPasswords bool `json:"hash_plaintext_passwords"` // Overwrite plain-text passwords with hashed equivalents
IdleTimeout time.Duration `json:"idle_timeout"` // Maximum idle time for client connections
IdleTimeout Duration `json:"idle_timeout"` // Maximum idle time for client connections
Accesses []*Access `json:"accesses"` // Accesses offered to users
PassiveTransferPortRange *PortRange `json:"passive_transfer_port_range"` // Listen port range
Extensions Extensions `json:"extensions"` // Extended features
Expand All @@ -74,3 +77,21 @@ type Content struct {
TLSRequired string `json:"tls_required"`
AccessesWebhook *AccessesWebhook `json:"accesses_webhook"` // Webhook to call when accesses are updated
}

// Duration wraps time.Duration to allow unmarshaling from JSON strings
// in Go duration format (e.g., "5m", "30s", "1h")
type Duration struct {
time.Duration
}

func (d *Duration) MarshalJSON() ([]byte, error) {
return json.Marshal(d.String())
}

func (d *Duration) UnmarshalJSON(b []byte) (err error) {
var s string
if err = json.Unmarshal(b, &s); err == nil {
d.Duration, err = time.ParseDuration(s)
}
return
}
54 changes: 54 additions & 0 deletions config/confpar/confpar_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package confpar

import (
"bytes"
"encoding/json"
"testing"
"time"
)

func TestDurationMarshalJSON(t *testing.T) {
for _, item := range []struct {
duration time.Duration
want string
}{
{0, `0s`},
{31 * time.Second, `31s`},
{5 * time.Minute, `5m0s`},
{1 * time.Hour, `1h0m0s`},
} {
have, err := json.Marshal(&Duration{item.duration})
if err != nil {
t.Fatalf("json.Marshal(): %v", err)
}
if !bytes.Equal(have, []byte(`"`+item.want+`"`)) {
t.Fatalf("have:%s want:%q", string(have), item.want)
}
}
}

func TestDurationUnmarshalJSON(t *testing.T) {
for _, item := range []struct {
input string
want time.Duration
wantErr bool
}{
{`5m`, 5 * time.Minute, false},
{`30s`, 30 * time.Second, false},
{`1h`, time.Hour, false},
{`0s`, 0, false},
{`invalid`, 0, true},
} {
var have Duration
err := json.Unmarshal([]byte(`"`+item.input+`"`), &have)
if err == nil && item.wantErr {
t.Fatalf("expecting error for invalid input")
}
if err != nil && !item.wantErr {
t.Fatalf("json.Unmarshal(): %v", err)
}
if have.Duration != item.want {
t.Fatalf("have:%v want:%v", have.Duration, item.want)
}
}
}
2 changes: 1 addition & 1 deletion server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ func (s *Server) getAccessFromWebhook(user, pass string) (*confpar.Access, error
}

// Timeout is implemented with context termination
ctx, cancel := context.WithTimeout(context.Background(), s.config.Content.AccessesWebhook.Timeout)
ctx, cancel := context.WithTimeout(context.Background(), s.config.Content.AccessesWebhook.Timeout.Duration)
defer cancel()

// Create a new HTTP request
Expand Down