mirror of
https://github.com/photoprism/photoprism.git
synced 2026-07-17 16:49:04 +00:00
Auth: Store session login_at as NULL when no client IP is set #5707
This commit is contained in:
parent
b2116154d3
commit
1b572c0da7
5 changed files with 70 additions and 4 deletions
|
|
@ -66,7 +66,7 @@ type Session struct {
|
|||
data *SessionData `gorm:"-" yaml:"-"`
|
||||
RefID string `gorm:"type:VARBINARY(16);default:'';" json:"ID" yaml:"-"`
|
||||
LoginIP string `gorm:"size:64;column:login_ip" json:"LoginIP" yaml:"-"`
|
||||
LoginAt time.Time `json:"LoginAt" yaml:"-"`
|
||||
LoginAt *time.Time `json:"LoginAt" yaml:"-"`
|
||||
CreatedAt time.Time `json:"CreatedAt" yaml:"CreatedAt"`
|
||||
UpdatedAt time.Time `json:"UpdatedAt" yaml:"UpdatedAt"`
|
||||
Status int `gorm:"-" json:"Status" yaml:"-"`
|
||||
|
|
@ -1053,7 +1053,7 @@ func (m *Session) SetClientIP(ip string) {
|
|||
|
||||
if m.LoginIP == "" {
|
||||
m.LoginIP = ip
|
||||
m.LoginAt = Now()
|
||||
m.LoginAt = TimeStamp()
|
||||
}
|
||||
|
||||
return
|
||||
|
|
|
|||
|
|
@ -95,4 +95,47 @@ func TestAddClientSession(t *testing.T) {
|
|||
|
||||
t.Logf("sess: %#v", sess)
|
||||
})
|
||||
t.Run("NoClientIPPersistsNullLoginAt", func(t *testing.T) {
|
||||
// Sessions created without a client IP (e.g. via "photoprism auth add")
|
||||
// must persist login_at as SQL NULL, not a zero "0000-00-00" datetime
|
||||
// that strict MySQL/MariaDB sql_modes reject with Error 1292.
|
||||
// A value-typed LoginAt leaves Go's zero time.Time, which go-sql-driver/mysql serializes as the literal 0000-00-00.
|
||||
sess, err := AddClientSession("", unix.Day, "metrics", authn.GrantCLI, nil)
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
if sess == nil {
|
||||
t.Fatal("session must not be nil")
|
||||
}
|
||||
|
||||
assert.Nil(t, sess.LoginAt)
|
||||
|
||||
var nullCount int
|
||||
if err = UnscopedDb().Table("auth_sessions").
|
||||
Where("id = ? AND login_at IS NULL", sess.ID).
|
||||
Count(&nullCount).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Equal(t, 1, nullCount, "login_at must be NULL when no client IP was set")
|
||||
})
|
||||
t.Run("ClientIPSetsLoginAt", func(t *testing.T) {
|
||||
sess := NewClientSession("", unix.Day, "metrics", authn.GrantClientCredentials, nil)
|
||||
sess.SetClientIP("203.0.113.7")
|
||||
|
||||
assert.NoError(t, sess.Create())
|
||||
|
||||
if sess.LoginAt == nil {
|
||||
t.Fatal("login_at must be set when a client IP is present")
|
||||
}
|
||||
|
||||
var nullCount int
|
||||
if err := UnscopedDb().Table("auth_sessions").
|
||||
Where("id = ? AND login_at IS NULL", sess.ID).
|
||||
Count(&nullCount).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Equal(t, 0, nullCount, "login_at must not be NULL when a client IP was set")
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ var SessionFixtures = SessionMap{
|
|||
user: UserFixtures.Pointer("bob"),
|
||||
UserUID: UserFixtures.Pointer("bob").UserUID,
|
||||
UserName: UserFixtures.Pointer("bob").UserName,
|
||||
LoginAt: Now().Add(-24),
|
||||
LoginAt: TimePointer(Now().Add(-24)),
|
||||
CreatedAt: Now().Add(-24),
|
||||
UpdatedAt: Now().Add(-24),
|
||||
},
|
||||
|
|
@ -184,7 +184,7 @@ var SessionFixtures = SessionMap{
|
|||
user: UserFixtures.Pointer("friend"),
|
||||
UserUID: UserFixtures.Pointer("friend").UserUID,
|
||||
UserName: UserFixtures.Pointer("friend").UserName,
|
||||
LoginAt: Now().Add(-12),
|
||||
LoginAt: TimePointer(Now().Add(-12)),
|
||||
CreatedAt: Now().Add(-20),
|
||||
UpdatedAt: Now().Add(-12),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -23,6 +23,15 @@ func TimeStamp() *time.Time {
|
|||
return &t
|
||||
}
|
||||
|
||||
// TimePointer returns a reference to the specified time, or nil if it is the zero value.
|
||||
func TimePointer(t time.Time) *time.Time {
|
||||
if t.IsZero() {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &t
|
||||
}
|
||||
|
||||
// Time returns a reference to the specified time in UTC, truncated to seconds, or nil if it is invalid.
|
||||
func Time(s string) *time.Time {
|
||||
if t, err := time.Parse(time.RFC3339, s); err == nil {
|
||||
|
|
|
|||
|
|
@ -137,6 +137,20 @@ func TestTimeStamp(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestTimePointer(t *testing.T) {
|
||||
t.Run("NonZero", func(t *testing.T) {
|
||||
now := Now()
|
||||
result := TimePointer(now)
|
||||
if result == nil {
|
||||
t.Fatal("result must not be nil")
|
||||
}
|
||||
assert.Equal(t, now, *result)
|
||||
})
|
||||
t.Run("Zero", func(t *testing.T) {
|
||||
assert.Nil(t, TimePointer(time.Time{}))
|
||||
})
|
||||
}
|
||||
|
||||
func TestTime(t *testing.T) {
|
||||
result := Time("2022-01-02T13:04:05+01:00")
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue