1
0
mirror of https://github.com/pocket-id/pocket-id.git synced 2026-02-12 18:30:15 +00:00

fix: for one-time access tokens and signup tokens, pass TTLs instead of absolute expiration date (#855)

This commit is contained in:
Alessandro (Ale) Segala
2025-08-21 23:02:56 -07:00
committed by GitHub
parent 49f0fa423c
commit 7ab0fd3028
12 changed files with 205 additions and 70 deletions

View File

@@ -0,0 +1,42 @@
package utils
import (
"encoding/json"
"errors"
"time"
)
// JSONDuration is a type that allows marshalling/unmarshalling a Duration
type JSONDuration struct {
time.Duration
}
func (d JSONDuration) MarshalJSON() ([]byte, error) {
return json.Marshal(d.String())
}
func (d *JSONDuration) UnmarshalJSON(b []byte) error {
var v any
err := json.Unmarshal(b, &v)
if err != nil {
return err
}
switch value := v.(type) {
case float64:
// If the value is a number, interpret it as a number of seconds
d.Duration = time.Duration(value) * time.Second
return nil
case string:
if v == "" {
return nil
}
var err error
d.Duration, err = time.ParseDuration(value)
if err != nil {
return err
}
return nil
default:
return errors.New("invalid duration")
}
}

View File

@@ -0,0 +1,64 @@
package utils
import (
"encoding/json"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestJSONDuration_MarshalJSON(t *testing.T) {
tests := []struct {
duration time.Duration
want string
}{
{time.Minute + 30*time.Second, "1m30s"},
{0, "0s"},
}
for _, tc := range tests {
d := JSONDuration{Duration: tc.duration}
b, err := json.Marshal(d)
require.NoError(t, err)
assert.Equal(t, `"`+tc.want+`"`, string(b))
}
}
func TestJSONDuration_UnmarshalJSON_String(t *testing.T) {
var d JSONDuration
err := json.Unmarshal([]byte(`"2h15m5s"`), &d)
require.NoError(t, err)
want := 2*time.Hour + 15*time.Minute + 5*time.Second
assert.Equal(t, want, d.Duration)
}
func TestJSONDuration_UnmarshalJSON_NumberSeconds(t *testing.T) {
tests := []struct {
json string
want time.Duration
}{
{"0", 0},
{"1", 1 * time.Second},
{"2.25", 2 * time.Second}, // Milliseconds are truncated
}
for _, tc := range tests {
var d JSONDuration
err := json.Unmarshal([]byte(tc.json), &d)
require.NoError(t, err, "input: %s", tc.json)
assert.Equal(t, tc.want, d.Duration, "input: %s", tc.json)
}
}
func TestJSONDuration_UnmarshalJSON_Invalid(t *testing.T) {
cases := [][]byte{
[]byte(`true`),
[]byte(`{}`),
[]byte(`"not-a-duration"`),
}
for _, b := range cases {
var d JSONDuration
err := json.Unmarshal(b, &d)
require.Error(t, err, "input: %s", string(b))
}
}