mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 03:47:33 +00:00
feat: add possibility to set an expiration to a session (#6851)
* add lifetime to session api * extend session with lifetime * check session token expiration * fix typo * integration test to check session token expiration * integration test to check session token expiration * i18n * cleanup * improve tests * prevent negative lifetime * fix error message * fix lifetime check
This commit is contained in:
@@ -14,7 +14,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
SessionsProjectionTable = "projections.sessions6"
|
||||
SessionsProjectionTable = "projections.sessions7"
|
||||
|
||||
SessionColumnID = "id"
|
||||
SessionColumnCreationDate = "creation_date"
|
||||
@@ -39,6 +39,7 @@ const (
|
||||
SessionColumnUserAgentIP = "user_agent_ip"
|
||||
SessionColumnUserAgentDescription = "user_agent_description"
|
||||
SessionColumnUserAgentHeader = "user_agent_header"
|
||||
SessionColumnExpiration = "expiration"
|
||||
)
|
||||
|
||||
type sessionProjection struct{}
|
||||
@@ -77,6 +78,7 @@ func (*sessionProjection) Init() *old_handler.Check {
|
||||
handler.NewColumn(SessionColumnUserAgentIP, handler.ColumnTypeText, handler.Nullable()),
|
||||
handler.NewColumn(SessionColumnUserAgentDescription, handler.ColumnTypeText, handler.Nullable()),
|
||||
handler.NewColumn(SessionColumnUserAgentHeader, handler.ColumnTypeJSONB, handler.Nullable()),
|
||||
handler.NewColumn(SessionColumnExpiration, handler.ColumnTypeTimestamp, handler.Nullable()),
|
||||
},
|
||||
handler.NewPrimaryKey(SessionColumnInstanceID, SessionColumnID),
|
||||
handler.WithIndex(handler.NewIndex(
|
||||
@@ -132,6 +134,10 @@ func (p *sessionProjection) Reducers() []handler.AggregateReducer {
|
||||
Event: session.MetadataSetType,
|
||||
Reduce: p.reduceMetadataSet,
|
||||
},
|
||||
{
|
||||
Event: session.LifetimeSetType,
|
||||
Reduce: p.reduceLifetimeSet,
|
||||
},
|
||||
{
|
||||
Event: session.TerminateType,
|
||||
Reduce: p.reduceSessionTerminated,
|
||||
@@ -376,6 +382,26 @@ func (p *sessionProjection) reduceMetadataSet(event eventstore.Event) (*handler.
|
||||
), nil
|
||||
}
|
||||
|
||||
func (p *sessionProjection) reduceLifetimeSet(event eventstore.Event) (*handler.Statement, error) {
|
||||
e, err := assertEvent[*session.LifetimeSetEvent](event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return handler.NewUpdateStatement(
|
||||
e,
|
||||
[]handler.Column{
|
||||
handler.NewCol(SessionColumnChangeDate, e.CreationDate()),
|
||||
handler.NewCol(SessionColumnSequence, e.Sequence()),
|
||||
handler.NewCol(SessionColumnExpiration, e.CreationDate().Add(e.Lifetime)),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(SessionColumnID, e.Aggregate().ID),
|
||||
handler.NewCond(SessionColumnInstanceID, e.Aggregate().InstanceID),
|
||||
},
|
||||
), nil
|
||||
}
|
||||
|
||||
func (p *sessionProjection) reduceSessionTerminated(event eventstore.Event) (*handler.Statement, error) {
|
||||
e, ok := event.(*session.TerminateEvent)
|
||||
if !ok {
|
||||
|
@@ -51,7 +51,7 @@ func TestSessionProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "INSERT INTO projections.sessions6 (id, instance_id, creation_date, change_date, resource_owner, state, sequence, creator, user_agent_fingerprint_id, user_agent_description, user_agent_ip, user_agent_header) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)",
|
||||
expectedStmt: "INSERT INTO projections.sessions7 (id, instance_id, creation_date, change_date, resource_owner, state, sequence, creator, user_agent_fingerprint_id, user_agent_description, user_agent_ip, user_agent_header) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)",
|
||||
expectedArgs: []interface{}{
|
||||
"agg-id",
|
||||
"instance-id",
|
||||
@@ -90,7 +90,7 @@ func TestSessionProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE projections.sessions6 SET (change_date, sequence, user_id, user_checked_at) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)",
|
||||
expectedStmt: "UPDATE projections.sessions7 SET (change_date, sequence, user_id, user_checked_at) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)",
|
||||
expectedArgs: []interface{}{
|
||||
anyArg{},
|
||||
anyArg{},
|
||||
@@ -122,7 +122,7 @@ func TestSessionProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE projections.sessions6 SET (change_date, sequence, password_checked_at) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||
expectedStmt: "UPDATE projections.sessions7 SET (change_date, sequence, password_checked_at) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||
expectedArgs: []interface{}{
|
||||
anyArg{},
|
||||
anyArg{},
|
||||
@@ -154,7 +154,7 @@ func TestSessionProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE projections.sessions6 SET (change_date, sequence, webauthn_checked_at, webauthn_user_verified) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)",
|
||||
expectedStmt: "UPDATE projections.sessions7 SET (change_date, sequence, webauthn_checked_at, webauthn_user_verified) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)",
|
||||
expectedArgs: []interface{}{
|
||||
anyArg{},
|
||||
anyArg{},
|
||||
@@ -186,7 +186,7 @@ func TestSessionProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE projections.sessions6 SET (change_date, sequence, intent_checked_at) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||
expectedStmt: "UPDATE projections.sessions7 SET (change_date, sequence, intent_checked_at) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||
expectedArgs: []interface{}{
|
||||
anyArg{},
|
||||
anyArg{},
|
||||
@@ -217,7 +217,7 @@ func TestSessionProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE projections.sessions6 SET (change_date, sequence, totp_checked_at) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||
expectedStmt: "UPDATE projections.sessions7 SET (change_date, sequence, totp_checked_at) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||
expectedArgs: []interface{}{
|
||||
anyArg{},
|
||||
anyArg{},
|
||||
@@ -248,7 +248,7 @@ func TestSessionProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE projections.sessions6 SET (change_date, sequence, token_id) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||
expectedStmt: "UPDATE projections.sessions7 SET (change_date, sequence, token_id) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||
expectedArgs: []interface{}{
|
||||
anyArg{},
|
||||
anyArg{},
|
||||
@@ -281,7 +281,7 @@ func TestSessionProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE projections.sessions6 SET (change_date, sequence, metadata) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||
expectedStmt: "UPDATE projections.sessions7 SET (change_date, sequence, metadata) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||
expectedArgs: []interface{}{
|
||||
anyArg{},
|
||||
anyArg{},
|
||||
@@ -296,6 +296,37 @@ func TestSessionProjection_reduces(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "instance reduceLifetimeSet",
|
||||
args: args{
|
||||
event: getEvent(testEvent(
|
||||
session.MetadataSetType,
|
||||
session.AggregateType,
|
||||
[]byte(`{
|
||||
"lifetime": 600000000000
|
||||
}`),
|
||||
), eventstore.GenericEventMapper[session.LifetimeSetEvent]),
|
||||
},
|
||||
reduce: (&sessionProjection{}).reduceLifetimeSet,
|
||||
want: wantReduce{
|
||||
aggregateType: eventstore.AggregateType("session"),
|
||||
sequence: 15,
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE projections.sessions7 SET (change_date, sequence, expiration) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||
expectedArgs: []interface{}{
|
||||
anyArg{},
|
||||
anyArg{},
|
||||
anyArg{},
|
||||
"agg-id",
|
||||
"instance-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "instance reduceSessionTerminated",
|
||||
args: args{
|
||||
@@ -312,7 +343,7 @@ func TestSessionProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "DELETE FROM projections.sessions6 WHERE (id = $1) AND (instance_id = $2)",
|
||||
expectedStmt: "DELETE FROM projections.sessions7 WHERE (id = $1) AND (instance_id = $2)",
|
||||
expectedArgs: []interface{}{
|
||||
"agg-id",
|
||||
"instance-id",
|
||||
@@ -339,7 +370,7 @@ func TestSessionProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "DELETE FROM projections.sessions6 WHERE (instance_id = $1)",
|
||||
expectedStmt: "DELETE FROM projections.sessions7 WHERE (instance_id = $1)",
|
||||
expectedArgs: []interface{}{
|
||||
"agg-id",
|
||||
},
|
||||
@@ -369,7 +400,7 @@ func TestSessionProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE projections.sessions6 SET password_checked_at = $1 WHERE (user_id = $2) AND (password_checked_at < $3)",
|
||||
expectedStmt: "UPDATE projections.sessions7 SET password_checked_at = $1 WHERE (user_id = $2) AND (password_checked_at < $3)",
|
||||
expectedArgs: []interface{}{
|
||||
nil,
|
||||
"agg-id",
|
||||
|
@@ -44,6 +44,7 @@ type Session struct {
|
||||
OTPEmailFactor SessionOTPFactor
|
||||
Metadata map[string][]byte
|
||||
UserAgent domain.UserAgent
|
||||
Expiration time.Time
|
||||
}
|
||||
|
||||
type SessionUserFactor struct {
|
||||
@@ -185,6 +186,10 @@ var (
|
||||
name: projection.SessionColumnUserAgentHeader,
|
||||
table: sessionsTable,
|
||||
}
|
||||
SessionColumnExpiration = Column{
|
||||
name: projection.SessionColumnExpiration,
|
||||
table: sessionsTable,
|
||||
}
|
||||
)
|
||||
|
||||
func (q *Queries) SessionByID(ctx context.Context, shouldTriggerBulk bool, id, sessionToken string) (session *Session, err error) {
|
||||
@@ -290,6 +295,7 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil
|
||||
SessionColumnUserAgentIP.identifier(),
|
||||
SessionColumnUserAgentDescription.identifier(),
|
||||
SessionColumnUserAgentHeader.identifier(),
|
||||
SessionColumnExpiration.identifier(),
|
||||
).From(sessionsTable.identifier()).
|
||||
LeftJoin(join(LoginNameUserIDCol, SessionColumnUserID)).
|
||||
LeftJoin(join(HumanUserIDCol, SessionColumnUserID)).
|
||||
@@ -314,6 +320,7 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil
|
||||
token sql.NullString
|
||||
userAgentIP sql.NullString
|
||||
userAgentHeader database.Map[[]string]
|
||||
expiration sql.NullTime
|
||||
)
|
||||
|
||||
err := row.Scan(
|
||||
@@ -342,6 +349,7 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil
|
||||
&userAgentIP,
|
||||
&session.UserAgent.Description,
|
||||
&userAgentHeader,
|
||||
&expiration,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
@@ -365,10 +373,10 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil
|
||||
session.OTPEmailFactor.OTPCheckedAt = otpEmailCheckedAt.Time
|
||||
session.Metadata = metadata
|
||||
session.UserAgent.Header = http.Header(userAgentHeader)
|
||||
|
||||
if userAgentIP.Valid {
|
||||
session.UserAgent.IP = net.ParseIP(userAgentIP.String)
|
||||
}
|
||||
session.Expiration = expiration.Time
|
||||
return session, token.String, nil
|
||||
}
|
||||
}
|
||||
@@ -395,6 +403,7 @@ func prepareSessionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBui
|
||||
SessionColumnOTPSMSCheckedAt.identifier(),
|
||||
SessionColumnOTPEmailCheckedAt.identifier(),
|
||||
SessionColumnMetadata.identifier(),
|
||||
SessionColumnExpiration.identifier(),
|
||||
countColumn.identifier(),
|
||||
).From(sessionsTable.identifier()).
|
||||
LeftJoin(join(LoginNameUserIDCol, SessionColumnUserID)).
|
||||
@@ -420,6 +429,7 @@ func prepareSessionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBui
|
||||
otpSMSCheckedAt sql.NullTime
|
||||
otpEmailCheckedAt sql.NullTime
|
||||
metadata database.Map[[]byte]
|
||||
expiration sql.NullTime
|
||||
)
|
||||
|
||||
err := rows.Scan(
|
||||
@@ -443,6 +453,7 @@ func prepareSessionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBui
|
||||
&otpSMSCheckedAt,
|
||||
&otpEmailCheckedAt,
|
||||
&metadata,
|
||||
&expiration,
|
||||
&sessions.Count,
|
||||
)
|
||||
|
||||
@@ -462,6 +473,7 @@ func prepareSessionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBui
|
||||
session.OTPSMSFactor.OTPCheckedAt = otpSMSCheckedAt.Time
|
||||
session.OTPEmailFactor.OTPCheckedAt = otpEmailCheckedAt.Time
|
||||
session.Metadata = metadata
|
||||
session.Expiration = expiration.Time
|
||||
|
||||
sessions.Sessions = append(sessions.Sessions, session)
|
||||
}
|
||||
|
@@ -20,61 +20,63 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
expectedSessionQuery = regexp.QuoteMeta(`SELECT projections.sessions6.id,` +
|
||||
` projections.sessions6.creation_date,` +
|
||||
` projections.sessions6.change_date,` +
|
||||
` projections.sessions6.sequence,` +
|
||||
` projections.sessions6.state,` +
|
||||
` projections.sessions6.resource_owner,` +
|
||||
` projections.sessions6.creator,` +
|
||||
` projections.sessions6.user_id,` +
|
||||
` projections.sessions6.user_checked_at,` +
|
||||
expectedSessionQuery = regexp.QuoteMeta(`SELECT projections.sessions7.id,` +
|
||||
` projections.sessions7.creation_date,` +
|
||||
` projections.sessions7.change_date,` +
|
||||
` projections.sessions7.sequence,` +
|
||||
` projections.sessions7.state,` +
|
||||
` projections.sessions7.resource_owner,` +
|
||||
` projections.sessions7.creator,` +
|
||||
` projections.sessions7.user_id,` +
|
||||
` projections.sessions7.user_checked_at,` +
|
||||
` projections.login_names2.login_name,` +
|
||||
` projections.users8_humans.display_name,` +
|
||||
` projections.users8.resource_owner,` +
|
||||
` projections.sessions6.password_checked_at,` +
|
||||
` projections.sessions6.intent_checked_at,` +
|
||||
` projections.sessions6.webauthn_checked_at,` +
|
||||
` projections.sessions6.webauthn_user_verified,` +
|
||||
` projections.sessions6.totp_checked_at,` +
|
||||
` projections.sessions6.otp_sms_checked_at,` +
|
||||
` projections.sessions6.otp_email_checked_at,` +
|
||||
` projections.sessions6.metadata,` +
|
||||
` projections.sessions6.token_id,` +
|
||||
` projections.sessions6.user_agent_fingerprint_id,` +
|
||||
` projections.sessions6.user_agent_ip,` +
|
||||
` projections.sessions6.user_agent_description,` +
|
||||
` projections.sessions6.user_agent_header` +
|
||||
` FROM projections.sessions6` +
|
||||
` LEFT JOIN projections.login_names2 ON projections.sessions6.user_id = projections.login_names2.user_id AND projections.sessions6.instance_id = projections.login_names2.instance_id` +
|
||||
` LEFT JOIN projections.users8_humans ON projections.sessions6.user_id = projections.users8_humans.user_id AND projections.sessions6.instance_id = projections.users8_humans.instance_id` +
|
||||
` LEFT JOIN projections.users8 ON projections.sessions6.user_id = projections.users8.id AND projections.sessions6.instance_id = projections.users8.instance_id` +
|
||||
` projections.sessions7.password_checked_at,` +
|
||||
` projections.sessions7.intent_checked_at,` +
|
||||
` projections.sessions7.webauthn_checked_at,` +
|
||||
` projections.sessions7.webauthn_user_verified,` +
|
||||
` projections.sessions7.totp_checked_at,` +
|
||||
` projections.sessions7.otp_sms_checked_at,` +
|
||||
` projections.sessions7.otp_email_checked_at,` +
|
||||
` projections.sessions7.metadata,` +
|
||||
` projections.sessions7.token_id,` +
|
||||
` projections.sessions7.user_agent_fingerprint_id,` +
|
||||
` projections.sessions7.user_agent_ip,` +
|
||||
` projections.sessions7.user_agent_description,` +
|
||||
` projections.sessions7.user_agent_header,` +
|
||||
` projections.sessions7.expiration` +
|
||||
` FROM projections.sessions7` +
|
||||
` LEFT JOIN projections.login_names2 ON projections.sessions7.user_id = projections.login_names2.user_id AND projections.sessions7.instance_id = projections.login_names2.instance_id` +
|
||||
` LEFT JOIN projections.users8_humans ON projections.sessions7.user_id = projections.users8_humans.user_id AND projections.sessions7.instance_id = projections.users8_humans.instance_id` +
|
||||
` LEFT JOIN projections.users8 ON projections.sessions7.user_id = projections.users8.id AND projections.sessions7.instance_id = projections.users8.instance_id` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`)
|
||||
expectedSessionsQuery = regexp.QuoteMeta(`SELECT projections.sessions6.id,` +
|
||||
` projections.sessions6.creation_date,` +
|
||||
` projections.sessions6.change_date,` +
|
||||
` projections.sessions6.sequence,` +
|
||||
` projections.sessions6.state,` +
|
||||
` projections.sessions6.resource_owner,` +
|
||||
` projections.sessions6.creator,` +
|
||||
` projections.sessions6.user_id,` +
|
||||
` projections.sessions6.user_checked_at,` +
|
||||
expectedSessionsQuery = regexp.QuoteMeta(`SELECT projections.sessions7.id,` +
|
||||
` projections.sessions7.creation_date,` +
|
||||
` projections.sessions7.change_date,` +
|
||||
` projections.sessions7.sequence,` +
|
||||
` projections.sessions7.state,` +
|
||||
` projections.sessions7.resource_owner,` +
|
||||
` projections.sessions7.creator,` +
|
||||
` projections.sessions7.user_id,` +
|
||||
` projections.sessions7.user_checked_at,` +
|
||||
` projections.login_names2.login_name,` +
|
||||
` projections.users8_humans.display_name,` +
|
||||
` projections.users8.resource_owner,` +
|
||||
` projections.sessions6.password_checked_at,` +
|
||||
` projections.sessions6.intent_checked_at,` +
|
||||
` projections.sessions6.webauthn_checked_at,` +
|
||||
` projections.sessions6.webauthn_user_verified,` +
|
||||
` projections.sessions6.totp_checked_at,` +
|
||||
` projections.sessions6.otp_sms_checked_at,` +
|
||||
` projections.sessions6.otp_email_checked_at,` +
|
||||
` projections.sessions6.metadata,` +
|
||||
` projections.sessions7.password_checked_at,` +
|
||||
` projections.sessions7.intent_checked_at,` +
|
||||
` projections.sessions7.webauthn_checked_at,` +
|
||||
` projections.sessions7.webauthn_user_verified,` +
|
||||
` projections.sessions7.totp_checked_at,` +
|
||||
` projections.sessions7.otp_sms_checked_at,` +
|
||||
` projections.sessions7.otp_email_checked_at,` +
|
||||
` projections.sessions7.metadata,` +
|
||||
` projections.sessions7.expiration,` +
|
||||
` COUNT(*) OVER ()` +
|
||||
` FROM projections.sessions6` +
|
||||
` LEFT JOIN projections.login_names2 ON projections.sessions6.user_id = projections.login_names2.user_id AND projections.sessions6.instance_id = projections.login_names2.instance_id` +
|
||||
` LEFT JOIN projections.users8_humans ON projections.sessions6.user_id = projections.users8_humans.user_id AND projections.sessions6.instance_id = projections.users8_humans.instance_id` +
|
||||
` LEFT JOIN projections.users8 ON projections.sessions6.user_id = projections.users8.id AND projections.sessions6.instance_id = projections.users8.instance_id` +
|
||||
` FROM projections.sessions7` +
|
||||
` LEFT JOIN projections.login_names2 ON projections.sessions7.user_id = projections.login_names2.user_id AND projections.sessions7.instance_id = projections.login_names2.instance_id` +
|
||||
` LEFT JOIN projections.users8_humans ON projections.sessions7.user_id = projections.users8_humans.user_id AND projections.sessions7.instance_id = projections.users8_humans.instance_id` +
|
||||
` LEFT JOIN projections.users8 ON projections.sessions7.user_id = projections.users8.id AND projections.sessions7.instance_id = projections.users8.instance_id` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`)
|
||||
|
||||
sessionCols = []string{
|
||||
@@ -103,6 +105,7 @@ var (
|
||||
"user_agent_ip",
|
||||
"user_agent_description",
|
||||
"user_agent_header",
|
||||
"expiration",
|
||||
}
|
||||
|
||||
sessionsCols = []string{
|
||||
@@ -126,6 +129,7 @@ var (
|
||||
"otp_sms_checked_at",
|
||||
"otp_email_checked_at",
|
||||
"metadata",
|
||||
"expiration",
|
||||
"count",
|
||||
}
|
||||
)
|
||||
@@ -182,6 +186,7 @@ func Test_SessionsPrepare(t *testing.T) {
|
||||
testNow,
|
||||
testNow,
|
||||
[]byte(`{"key": "dmFsdWU="}`),
|
||||
testNow,
|
||||
},
|
||||
},
|
||||
),
|
||||
@@ -228,6 +233,7 @@ func Test_SessionsPrepare(t *testing.T) {
|
||||
Metadata: map[string][]byte{
|
||||
"key": []byte("value"),
|
||||
},
|
||||
Expiration: testNow,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -261,6 +267,7 @@ func Test_SessionsPrepare(t *testing.T) {
|
||||
testNow,
|
||||
testNow,
|
||||
[]byte(`{"key": "dmFsdWU="}`),
|
||||
testNow,
|
||||
},
|
||||
{
|
||||
"session-id2",
|
||||
@@ -283,6 +290,7 @@ func Test_SessionsPrepare(t *testing.T) {
|
||||
testNow,
|
||||
testNow,
|
||||
[]byte(`{"key": "dmFsdWU="}`),
|
||||
testNow,
|
||||
},
|
||||
},
|
||||
),
|
||||
@@ -329,6 +337,7 @@ func Test_SessionsPrepare(t *testing.T) {
|
||||
Metadata: map[string][]byte{
|
||||
"key": []byte("value"),
|
||||
},
|
||||
Expiration: testNow,
|
||||
},
|
||||
{
|
||||
ID: "session-id2",
|
||||
@@ -367,6 +376,7 @@ func Test_SessionsPrepare(t *testing.T) {
|
||||
Metadata: map[string][]byte{
|
||||
"key": []byte("value"),
|
||||
},
|
||||
Expiration: testNow,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -458,6 +468,7 @@ func Test_SessionPrepare(t *testing.T) {
|
||||
"1.2.3.4",
|
||||
"agentDescription",
|
||||
[]byte(`{"foo":["foo","bar"]}`),
|
||||
testNow,
|
||||
},
|
||||
),
|
||||
},
|
||||
@@ -504,6 +515,7 @@ func Test_SessionPrepare(t *testing.T) {
|
||||
Description: gu.Ptr("agentDescription"),
|
||||
Header: http.Header{"foo": []string{"foo", "bar"}},
|
||||
},
|
||||
Expiration: testNow,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
Reference in New Issue
Block a user