-
This commit is contained in:
47
internal/domain/duration.go
Normal file
47
internal/domain/duration.go
Normal file
@ -0,0 +1,47 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Duration is a wrapper around time.Duration that can unmarshal from both
|
||||
// string duration formats (like "168h") and nanosecond integers
|
||||
type Duration struct {
|
||||
time.Duration
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements json.Unmarshaler interface
|
||||
func (d *Duration) UnmarshalJSON(data []byte) error {
|
||||
// Try to unmarshal as string first (e.g., "168h", "24h", "30m")
|
||||
var str string
|
||||
if err := json.Unmarshal(data, &str); err == nil {
|
||||
duration, err := time.ParseDuration(str)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid duration format: %s", str)
|
||||
}
|
||||
d.Duration = duration
|
||||
return nil
|
||||
}
|
||||
|
||||
// Try to unmarshal as integer (nanoseconds)
|
||||
var ns int64
|
||||
if err := json.Unmarshal(data, &ns); err == nil {
|
||||
d.Duration = time.Duration(ns)
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("duration must be either a string (e.g., '168h') or integer nanoseconds")
|
||||
}
|
||||
|
||||
// MarshalJSON implements json.Marshaler interface
|
||||
func (d Duration) MarshalJSON() ([]byte, error) {
|
||||
// Always marshal as nanoseconds for consistency
|
||||
return json.Marshal(int64(d.Duration))
|
||||
}
|
||||
|
||||
// String returns the string representation of the duration
|
||||
func (d Duration) String() string {
|
||||
return d.Duration.String()
|
||||
}
|
||||
@ -44,8 +44,8 @@ type Application struct {
|
||||
Type []ApplicationType `json:"type" validate:"required,min=1,dive,oneof=static user" db:"type"`
|
||||
CallbackURL string `json:"callback_url" validate:"required,url,max=500" db:"callback_url"`
|
||||
HMACKey string `json:"hmac_key" validate:"required,min=1,max=255" db:"hmac_key"`
|
||||
TokenRenewalDuration time.Duration `json:"token_renewal_duration" validate:"required,min=1" db:"token_renewal_duration"`
|
||||
MaxTokenDuration time.Duration `json:"max_token_duration" validate:"required,min=1" db:"max_token_duration"`
|
||||
TokenRenewalDuration Duration `json:"token_renewal_duration" validate:"required,min=1" db:"token_renewal_duration"`
|
||||
MaxTokenDuration Duration `json:"max_token_duration" validate:"required,min=1" db:"max_token_duration"`
|
||||
Owner Owner `json:"owner" validate:"required"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
||||
@ -157,8 +157,8 @@ type CreateApplicationRequest struct {
|
||||
AppLink string `json:"app_link" validate:"required,url,max=500"`
|
||||
Type []ApplicationType `json:"type" validate:"required,min=1,dive,oneof=static user"`
|
||||
CallbackURL string `json:"callback_url" validate:"required,url,max=500"`
|
||||
TokenRenewalDuration time.Duration `json:"token_renewal_duration" validate:"required,min=1"`
|
||||
MaxTokenDuration time.Duration `json:"max_token_duration" validate:"required,min=1"`
|
||||
TokenRenewalDuration Duration `json:"token_renewal_duration" validate:"required,min=1"`
|
||||
MaxTokenDuration Duration `json:"max_token_duration" validate:"required,min=1"`
|
||||
Owner Owner `json:"owner" validate:"required"`
|
||||
}
|
||||
|
||||
@ -168,8 +168,8 @@ type UpdateApplicationRequest struct {
|
||||
Type *[]ApplicationType `json:"type,omitempty" validate:"omitempty,min=1,dive,oneof=static user"`
|
||||
CallbackURL *string `json:"callback_url,omitempty" validate:"omitempty,url,max=500"`
|
||||
HMACKey *string `json:"hmac_key,omitempty" validate:"omitempty,min=1,max=255"`
|
||||
TokenRenewalDuration *time.Duration `json:"token_renewal_duration,omitempty" validate:"omitempty,min=1"`
|
||||
MaxTokenDuration *time.Duration `json:"max_token_duration,omitempty" validate:"omitempty,min=1"`
|
||||
TokenRenewalDuration *Duration `json:"token_renewal_duration,omitempty" validate:"omitempty,min=1"`
|
||||
MaxTokenDuration *Duration `json:"max_token_duration,omitempty" validate:"omitempty,min=1"`
|
||||
Owner *Owner `json:"owner,omitempty" validate:"omitempty"`
|
||||
}
|
||||
|
||||
|
||||
@ -38,7 +38,7 @@ type TenantSettings struct {
|
||||
OAuth2Settings *OAuth2Settings `json:"oauth2_settings,omitempty"`
|
||||
|
||||
// Session settings
|
||||
SessionTimeout time.Duration `json:"session_timeout,omitempty"`
|
||||
SessionTimeout Duration `json:"session_timeout,omitempty"`
|
||||
MaxConcurrentSessions int `json:"max_concurrent_sessions,omitempty"`
|
||||
|
||||
// Security settings
|
||||
@ -47,8 +47,8 @@ type TenantSettings struct {
|
||||
PasswordPolicy *PasswordPolicy `json:"password_policy,omitempty"`
|
||||
|
||||
// Token settings
|
||||
DefaultTokenDuration time.Duration `json:"default_token_duration,omitempty"`
|
||||
MaxTokenDuration time.Duration `json:"max_token_duration,omitempty"`
|
||||
DefaultTokenDuration Duration `json:"default_token_duration,omitempty"`
|
||||
MaxTokenDuration Duration `json:"max_token_duration,omitempty"`
|
||||
|
||||
// Feature flags
|
||||
Features map[string]bool `json:"features,omitempty"`
|
||||
@ -83,7 +83,7 @@ type PasswordPolicy struct {
|
||||
RequireLowercase bool `json:"require_lowercase"`
|
||||
RequireNumbers bool `json:"require_numbers"`
|
||||
RequireSymbols bool `json:"require_symbols"`
|
||||
MaxAge time.Duration `json:"max_age,omitempty"`
|
||||
MaxAge Duration `json:"max_age,omitempty"`
|
||||
PreventReuse int `json:"prevent_reuse"` // Number of previous passwords to prevent reuse
|
||||
}
|
||||
|
||||
@ -225,8 +225,8 @@ func (t *Tenant) GetAuthProvider() string {
|
||||
|
||||
// GetSessionTimeout returns the session timeout for the tenant
|
||||
func (t *Tenant) GetSessionTimeout() time.Duration {
|
||||
if t.Settings.SessionTimeout > 0 {
|
||||
return t.Settings.SessionTimeout
|
||||
if t.Settings.SessionTimeout.Duration > 0 {
|
||||
return t.Settings.SessionTimeout.Duration
|
||||
}
|
||||
return 8 * time.Hour // default
|
||||
}
|
||||
|
||||
@ -48,8 +48,8 @@ func (r *ApplicationRepository) Create(ctx context.Context, app *domain.Applicat
|
||||
pq.Array(typeStrings),
|
||||
app.CallbackURL,
|
||||
app.HMACKey,
|
||||
app.TokenRenewalDuration.Nanoseconds(),
|
||||
app.MaxTokenDuration.Nanoseconds(),
|
||||
app.TokenRenewalDuration.Duration.Nanoseconds(),
|
||||
app.MaxTokenDuration.Duration.Nanoseconds(),
|
||||
string(app.Owner.Type),
|
||||
app.Owner.Name,
|
||||
app.Owner.Owner,
|
||||
@ -118,8 +118,8 @@ func (r *ApplicationRepository) GetByID(ctx context.Context, appID string) (*dom
|
||||
}
|
||||
|
||||
// Convert nanoseconds to duration
|
||||
app.TokenRenewalDuration = time.Duration(tokenRenewalNanos)
|
||||
app.MaxTokenDuration = time.Duration(maxTokenNanos)
|
||||
app.TokenRenewalDuration = domain.Duration{Duration: time.Duration(tokenRenewalNanos)}
|
||||
app.MaxTokenDuration = domain.Duration{Duration: time.Duration(maxTokenNanos)}
|
||||
|
||||
// Convert owner type
|
||||
app.Owner.Type = domain.OwnerType(ownerType)
|
||||
@ -180,8 +180,8 @@ func (r *ApplicationRepository) List(ctx context.Context, limit, offset int) ([]
|
||||
}
|
||||
|
||||
// Convert nanoseconds to duration
|
||||
app.TokenRenewalDuration = time.Duration(tokenRenewalNanos)
|
||||
app.MaxTokenDuration = time.Duration(maxTokenNanos)
|
||||
app.TokenRenewalDuration = domain.Duration{Duration: time.Duration(tokenRenewalNanos)}
|
||||
app.MaxTokenDuration = domain.Duration{Duration: time.Duration(maxTokenNanos)}
|
||||
|
||||
// Convert owner type
|
||||
app.Owner.Type = domain.OwnerType(ownerType)
|
||||
@ -233,13 +233,13 @@ func (r *ApplicationRepository) Update(ctx context.Context, appID string, update
|
||||
|
||||
if updates.TokenRenewalDuration != nil {
|
||||
setParts = append(setParts, fmt.Sprintf("token_renewal_duration = $%d", argIndex))
|
||||
args = append(args, updates.TokenRenewalDuration.Nanoseconds())
|
||||
args = append(args, updates.TokenRenewalDuration.Duration.Nanoseconds())
|
||||
argIndex++
|
||||
}
|
||||
|
||||
if updates.MaxTokenDuration != nil {
|
||||
setParts = append(setParts, fmt.Sprintf("max_token_duration = $%d", argIndex))
|
||||
args = append(args, updates.MaxTokenDuration.Nanoseconds())
|
||||
args = append(args, updates.MaxTokenDuration.Duration.Nanoseconds())
|
||||
argIndex++
|
||||
}
|
||||
|
||||
|
||||
@ -375,7 +375,7 @@ func (s *sessionService) CreateOAuth2Session(ctx context.Context, userID, appID
|
||||
expiresAt := time.Now().Add(time.Duration(tokenResponse.ExpiresIn) * time.Second)
|
||||
|
||||
// Use application's max token duration if shorter
|
||||
maxExpiration := time.Now().Add(app.MaxTokenDuration)
|
||||
maxExpiration := time.Now().Add(app.MaxTokenDuration.Duration)
|
||||
if expiresAt.After(maxExpiration) {
|
||||
expiresAt = maxExpiration
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user