merge main into next

This commit is contained in:
adlerhurst
2023-10-19 12:34:00 +02:00
parent b5564572bc
commit bd23a7a56f
107 changed files with 1321 additions and 554 deletions

View File

@@ -54,7 +54,7 @@ func assertPrepare(t *testing.T, prepareFunc, expectedObject interface{}, sqlExp
}
return isErr(err)
}
object, ok, didScan := execScan(&database.DB{DB: client}, builder, scan, errCheck)
object, ok, didScan := execScan(t, &database.DB{DB: client}, builder, scan, errCheck)
if !ok {
t.Error(object)
return false
@@ -168,7 +168,7 @@ var (
selectBuilderType = reflect.TypeOf(sq.SelectBuilder{})
)
func execScan(client *database.DB, builder sq.SelectBuilder, scan interface{}, errCheck checkErr) (object interface{}, ok bool, didScan bool) {
func execScan(t testing.TB, client *database.DB, builder sq.SelectBuilder, scan interface{}, errCheck checkErr) (object interface{}, ok bool, didScan bool) {
scanType := reflect.TypeOf(scan)
err := validateScan(scanType)
if err != nil {
@@ -177,7 +177,7 @@ func execScan(client *database.DB, builder sq.SelectBuilder, scan interface{}, e
stmt, args, err := builder.ToSql()
if err != nil {
return fmt.Errorf("unexpeted error from sql builder: %w", err), false, false
return fmt.Errorf("unexpected error from sql builder: %w", err), false, false
}
//resultSet represents *sql.Row or *sql.Rows,
@@ -199,6 +199,9 @@ func execScan(client *database.DB, builder sq.SelectBuilder, scan interface{}, e
// if scan(*sql.Row)...
} else if scanType.In(0).AssignableTo(rowType) {
err = client.QueryRow(func(r *sql.Row) error {
if r.Err() != nil {
return r.Err()
}
didScan = true
res = reflect.ValueOf(scan).Call([]reflect.Value{reflect.ValueOf(r)})
if err, ok := res[1].Interface().(error); ok {
@@ -213,6 +216,9 @@ func execScan(client *database.DB, builder sq.SelectBuilder, scan interface{}, e
if err != nil {
err, ok := errCheck(err)
if !ok {
t.Fatal(err)
}
if didScan {
return res[0].Interface(), ok, didScan
}

View File

@@ -14,27 +14,31 @@ import (
)
const (
SessionsProjectionTable = "projections.sessions5"
SessionsProjectionTable = "projections.sessions6"
SessionColumnID = "id"
SessionColumnCreationDate = "creation_date"
SessionColumnChangeDate = "change_date"
SessionColumnSequence = "sequence"
SessionColumnState = "state"
SessionColumnResourceOwner = "resource_owner"
SessionColumnInstanceID = "instance_id"
SessionColumnCreator = "creator"
SessionColumnUserID = "user_id"
SessionColumnUserCheckedAt = "user_checked_at"
SessionColumnPasswordCheckedAt = "password_checked_at"
SessionColumnIntentCheckedAt = "intent_checked_at"
SessionColumnWebAuthNCheckedAt = "webauthn_checked_at"
SessionColumnWebAuthNUserVerified = "webauthn_user_verified"
SessionColumnTOTPCheckedAt = "totp_checked_at"
SessionColumnOTPSMSCheckedAt = "otp_sms_checked_at"
SessionColumnOTPEmailCheckedAt = "otp_email_checked_at"
SessionColumnMetadata = "metadata"
SessionColumnTokenID = "token_id"
SessionColumnID = "id"
SessionColumnCreationDate = "creation_date"
SessionColumnChangeDate = "change_date"
SessionColumnSequence = "sequence"
SessionColumnState = "state"
SessionColumnResourceOwner = "resource_owner"
SessionColumnInstanceID = "instance_id"
SessionColumnCreator = "creator"
SessionColumnUserID = "user_id"
SessionColumnUserCheckedAt = "user_checked_at"
SessionColumnPasswordCheckedAt = "password_checked_at"
SessionColumnIntentCheckedAt = "intent_checked_at"
SessionColumnWebAuthNCheckedAt = "webauthn_checked_at"
SessionColumnWebAuthNUserVerified = "webauthn_user_verified"
SessionColumnTOTPCheckedAt = "totp_checked_at"
SessionColumnOTPSMSCheckedAt = "otp_sms_checked_at"
SessionColumnOTPEmailCheckedAt = "otp_email_checked_at"
SessionColumnMetadata = "metadata"
SessionColumnTokenID = "token_id"
SessionColumnUserAgentFingerprintID = "user_agent_fingerprint_id"
SessionColumnUserAgentIP = "user_agent_ip"
SessionColumnUserAgentDescription = "user_agent_description"
SessionColumnUserAgentHeader = "user_agent_header"
)
type sessionProjection struct{}
@@ -69,8 +73,16 @@ func (*sessionProjection) Init() *old_handler.Check {
handler.NewColumn(SessionColumnOTPEmailCheckedAt, handler.ColumnTypeTimestamp, handler.Nullable()),
handler.NewColumn(SessionColumnMetadata, handler.ColumnTypeJSONB, handler.Nullable()),
handler.NewColumn(SessionColumnTokenID, handler.ColumnTypeText, handler.Nullable()),
handler.NewColumn(SessionColumnUserAgentFingerprintID, handler.ColumnTypeText, handler.Nullable()),
handler.NewColumn(SessionColumnUserAgentIP, handler.ColumnTypeText, handler.Nullable()),
handler.NewColumn(SessionColumnUserAgentDescription, handler.ColumnTypeText, handler.Nullable()),
handler.NewColumn(SessionColumnUserAgentHeader, handler.ColumnTypeJSONB, handler.Nullable()),
},
handler.NewPrimaryKey(SessionColumnInstanceID, SessionColumnID),
handler.WithIndex(handler.NewIndex(
SessionColumnUserAgentFingerprintID+"_idx",
[]string{SessionColumnUserAgentFingerprintID},
)),
),
)
}
@@ -153,19 +165,35 @@ func (p *sessionProjection) reduceSessionAdded(event eventstore.Event) (*handler
return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-Sfrgf", "reduce.wrong.event.type %s", session.AddedType)
}
return handler.NewCreateStatement(
e,
[]handler.Column{
handler.NewCol(SessionColumnID, e.Aggregate().ID),
handler.NewCol(SessionColumnInstanceID, e.Aggregate().InstanceID),
handler.NewCol(SessionColumnCreationDate, e.CreationDate()),
handler.NewCol(SessionColumnChangeDate, e.CreationDate()),
handler.NewCol(SessionColumnResourceOwner, e.Aggregate().ResourceOwner),
handler.NewCol(SessionColumnState, domain.SessionStateActive),
handler.NewCol(SessionColumnSequence, e.Sequence()),
handler.NewCol(SessionColumnCreator, e.User),
},
), nil
cols := make([]handler.Column, 0, 12)
cols = append(cols,
handler.NewCol(SessionColumnID, e.Aggregate().ID),
handler.NewCol(SessionColumnInstanceID, e.Aggregate().InstanceID),
handler.NewCol(SessionColumnCreationDate, e.CreationDate()),
handler.NewCol(SessionColumnChangeDate, e.CreationDate()),
handler.NewCol(SessionColumnResourceOwner, e.Aggregate().ResourceOwner),
handler.NewCol(SessionColumnState, domain.SessionStateActive),
handler.NewCol(SessionColumnSequence, e.Sequence()),
handler.NewCol(SessionColumnCreator, e.User),
)
if e.UserAgent != nil {
cols = append(cols,
handler.NewCol(SessionColumnUserAgentFingerprintID, e.UserAgent.FingerprintID),
handler.NewCol(SessionColumnUserAgentDescription, e.UserAgent.Description),
)
if e.UserAgent.IP != nil {
cols = append(cols,
handler.NewCol(SessionColumnUserAgentIP, e.UserAgent.IP.String()),
)
}
if e.UserAgent.Header != nil {
cols = append(cols,
handler.NewJSONCol(SessionColumnUserAgentHeader, e.UserAgent.Header),
)
}
}
return handler.NewCreateStatement(e, cols), nil
}
func (p *sessionProjection) reduceUserChecked(event eventstore.Event) (*handler.Statement, error) {

View File

@@ -4,6 +4,8 @@ import (
"testing"
"time"
"github.com/muhlemmer/gu"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/errors"
"github.com/zitadel/zitadel/internal/eventstore"
@@ -30,7 +32,15 @@ func TestSessionProjection_reduces(t *testing.T) {
session.AddedType,
session.AggregateType,
[]byte(`{
"domain": "domain"
"domain": "domain",
"user_agent": {
"fingerprint_id": "fp1",
"ip": "1.2.3.4",
"description": "firefox",
"header": {
"foo": ["bar"]
}
}
}`),
), session.AddedEventMapper),
},
@@ -41,7 +51,7 @@ func TestSessionProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "INSERT INTO projections.sessions5 (id, instance_id, creation_date, change_date, resource_owner, state, sequence, creator) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)",
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)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -51,6 +61,10 @@ func TestSessionProjection_reduces(t *testing.T) {
domain.SessionStateActive,
uint64(15),
"editor-user",
gu.Ptr("fp1"),
gu.Ptr("firefox"),
"1.2.3.4",
[]byte(`{"foo":["bar"]}`),
},
},
},
@@ -76,7 +90,7 @@ func TestSessionProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.sessions5 SET (change_date, sequence, user_id, user_checked_at) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)",
expectedStmt: "UPDATE projections.sessions6 SET (change_date, sequence, user_id, user_checked_at) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)",
expectedArgs: []interface{}{
anyArg{},
anyArg{},
@@ -108,7 +122,7 @@ func TestSessionProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.sessions5 SET (change_date, sequence, password_checked_at) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedStmt: "UPDATE projections.sessions6 SET (change_date, sequence, password_checked_at) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedArgs: []interface{}{
anyArg{},
anyArg{},
@@ -140,7 +154,7 @@ func TestSessionProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.sessions5 SET (change_date, sequence, webauthn_checked_at, webauthn_user_verified) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)",
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)",
expectedArgs: []interface{}{
anyArg{},
anyArg{},
@@ -172,7 +186,7 @@ func TestSessionProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.sessions5 SET (change_date, sequence, intent_checked_at) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedStmt: "UPDATE projections.sessions6 SET (change_date, sequence, intent_checked_at) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedArgs: []interface{}{
anyArg{},
anyArg{},
@@ -203,7 +217,7 @@ func TestSessionProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.sessions5 SET (change_date, sequence, totp_checked_at) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedStmt: "UPDATE projections.sessions6 SET (change_date, sequence, totp_checked_at) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedArgs: []interface{}{
anyArg{},
anyArg{},
@@ -234,7 +248,7 @@ func TestSessionProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.sessions5 SET (change_date, sequence, token_id) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedStmt: "UPDATE projections.sessions6 SET (change_date, sequence, token_id) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedArgs: []interface{}{
anyArg{},
anyArg{},
@@ -267,7 +281,7 @@ func TestSessionProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.sessions5 SET (change_date, sequence, metadata) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedStmt: "UPDATE projections.sessions6 SET (change_date, sequence, metadata) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
expectedArgs: []interface{}{
anyArg{},
anyArg{},
@@ -298,7 +312,7 @@ func TestSessionProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "DELETE FROM projections.sessions5 WHERE (id = $1) AND (instance_id = $2)",
expectedStmt: "DELETE FROM projections.sessions6 WHERE (id = $1) AND (instance_id = $2)",
expectedArgs: []interface{}{
"agg-id",
"instance-id",
@@ -325,7 +339,7 @@ func TestSessionProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "DELETE FROM projections.sessions5 WHERE (instance_id = $1)",
expectedStmt: "DELETE FROM projections.sessions6 WHERE (instance_id = $1)",
expectedArgs: []interface{}{
"agg-id",
},
@@ -355,7 +369,7 @@ func TestSessionProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPDATE projections.sessions5 SET password_checked_at = $1 WHERE (user_id = $2) AND (password_checked_at < $3)",
expectedStmt: "UPDATE projections.sessions6 SET password_checked_at = $1 WHERE (user_id = $2) AND (password_checked_at < $3)",
expectedArgs: []interface{}{
nil,
"agg-id",

View File

@@ -4,6 +4,8 @@ import (
"context"
"database/sql"
errs "errors"
"net"
"net/http"
"time"
sq "github.com/Masterminds/squirrel"
@@ -41,6 +43,7 @@ type Session struct {
OTPSMSFactor SessionOTPFactor
OTPEmailFactor SessionOTPFactor
Metadata map[string][]byte
UserAgent domain.UserAgent
}
type SessionUserFactor struct {
@@ -166,6 +169,22 @@ var (
name: projection.SessionColumnTokenID,
table: sessionsTable,
}
SessionColumnUserAgentFingerprintID = Column{
name: projection.SessionColumnUserAgentFingerprintID,
table: sessionsTable,
}
SessionColumnUserAgentIP = Column{
name: projection.SessionColumnUserAgentIP,
table: sessionsTable,
}
SessionColumnUserAgentDescription = Column{
name: projection.SessionColumnUserAgentDescription,
table: sessionsTable,
}
SessionColumnUserAgentHeader = Column{
name: projection.SessionColumnUserAgentHeader,
table: sessionsTable,
}
)
func (q *Queries) SessionByID(ctx context.Context, shouldTriggerBulk bool, id, sessionToken string) (session *Session, err error) {
@@ -265,6 +284,10 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil
SessionColumnOTPEmailCheckedAt.identifier(),
SessionColumnMetadata.identifier(),
SessionColumnToken.identifier(),
SessionColumnUserAgentFingerprintID.identifier(),
SessionColumnUserAgentIP.identifier(),
SessionColumnUserAgentDescription.identifier(),
SessionColumnUserAgentHeader.identifier(),
).From(sessionsTable.identifier()).
LeftJoin(join(LoginNameUserIDCol, SessionColumnUserID)).
LeftJoin(join(HumanUserIDCol, SessionColumnUserID)).
@@ -287,6 +310,8 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil
otpEmailCheckedAt sql.NullTime
metadata database.Map[[]byte]
token sql.NullString
userAgentIP sql.NullString
userAgentHeader database.Map[[]string]
)
err := row.Scan(
@@ -311,6 +336,10 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil
&otpEmailCheckedAt,
&metadata,
&token,
&session.UserAgent.FingerprintID,
&userAgentIP,
&session.UserAgent.Description,
&userAgentHeader,
)
if err != nil {
@@ -333,7 +362,11 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil
session.OTPSMSFactor.OTPCheckedAt = otpSMSCheckedAt.Time
session.OTPEmailFactor.OTPCheckedAt = otpEmailCheckedAt.Time
session.Metadata = metadata
session.UserAgent.Header = http.Header(userAgentHeader)
if userAgentIP.Valid {
session.UserAgent.IP = net.ParseIP(userAgentIP.String)
}
return session, token.String, nil
}
}

View File

@@ -6,10 +6,13 @@ import (
"database/sql/driver"
"errors"
"fmt"
"net"
"net/http"
"regexp"
"testing"
sq "github.com/Masterminds/squirrel"
"github.com/muhlemmer/gu"
"github.com/stretchr/testify/require"
"github.com/zitadel/zitadel/internal/domain"
@@ -17,57 +20,61 @@ import (
)
var (
expectedSessionQuery = regexp.QuoteMeta(`SELECT projections.sessions5.id,` +
` projections.sessions5.creation_date,` +
` projections.sessions5.change_date,` +
` projections.sessions5.sequence,` +
` projections.sessions5.state,` +
` projections.sessions5.resource_owner,` +
` projections.sessions5.creator,` +
` projections.sessions5.user_id,` +
` projections.sessions5.user_checked_at,` +
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,` +
` projections.login_names2.login_name,` +
` projections.users8_humans.display_name,` +
` projections.users8.resource_owner,` +
` projections.sessions5.password_checked_at,` +
` projections.sessions5.intent_checked_at,` +
` projections.sessions5.webauthn_checked_at,` +
` projections.sessions5.webauthn_user_verified,` +
` projections.sessions5.totp_checked_at,` +
` projections.sessions5.otp_sms_checked_at,` +
` projections.sessions5.otp_email_checked_at,` +
` projections.sessions5.metadata,` +
` projections.sessions5.token_id` +
` FROM projections.sessions5` +
` LEFT JOIN projections.login_names2 ON projections.sessions5.user_id = projections.login_names2.user_id AND projections.sessions5.instance_id = projections.login_names2.instance_id` +
` LEFT JOIN projections.users8_humans ON projections.sessions5.user_id = projections.users8_humans.user_id AND projections.sessions5.instance_id = projections.users8_humans.instance_id` +
` LEFT JOIN projections.users8 ON projections.sessions5.user_id = projections.users8.id AND projections.sessions5.instance_id = projections.users8.instance_id` +
` 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` +
` AS OF SYSTEM TIME '-1 ms'`)
expectedSessionsQuery = regexp.QuoteMeta(`SELECT projections.sessions5.id,` +
` projections.sessions5.creation_date,` +
` projections.sessions5.change_date,` +
` projections.sessions5.sequence,` +
` projections.sessions5.state,` +
` projections.sessions5.resource_owner,` +
` projections.sessions5.creator,` +
` projections.sessions5.user_id,` +
` projections.sessions5.user_checked_at,` +
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,` +
` projections.login_names2.login_name,` +
` projections.users8_humans.display_name,` +
` projections.users8.resource_owner,` +
` projections.sessions5.password_checked_at,` +
` projections.sessions5.intent_checked_at,` +
` projections.sessions5.webauthn_checked_at,` +
` projections.sessions5.webauthn_user_verified,` +
` projections.sessions5.totp_checked_at,` +
` projections.sessions5.otp_sms_checked_at,` +
` projections.sessions5.otp_email_checked_at,` +
` projections.sessions5.metadata,` +
` 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,` +
` COUNT(*) OVER ()` +
` FROM projections.sessions5` +
` LEFT JOIN projections.login_names2 ON projections.sessions5.user_id = projections.login_names2.user_id AND projections.sessions5.instance_id = projections.login_names2.instance_id` +
` LEFT JOIN projections.users8_humans ON projections.sessions5.user_id = projections.users8_humans.user_id AND projections.sessions5.instance_id = projections.users8_humans.instance_id` +
` LEFT JOIN projections.users8 ON projections.sessions5.user_id = projections.users8.id AND projections.sessions5.instance_id = projections.users8.instance_id` +
` 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` +
` AS OF SYSTEM TIME '-1 ms'`)
sessionCols = []string{
@@ -92,6 +99,10 @@ var (
"otp_email_checked_at",
"metadata",
"token",
"user_agent_fingerprint_id",
"user_agent_ip",
"user_agent_description",
"user_agent_header",
}
sessionsCols = []string{
@@ -443,6 +454,10 @@ func Test_SessionPrepare(t *testing.T) {
testNow,
[]byte(`{"key": "dmFsdWU="}`),
"tokenID",
"fingerPrintID",
"1.2.3.4",
"agentDescription",
[]byte(`{"foo":["foo","bar"]}`),
},
),
},
@@ -483,6 +498,12 @@ func Test_SessionPrepare(t *testing.T) {
Metadata: map[string][]byte{
"key": []byte("value"),
},
UserAgent: domain.UserAgent{
FingerprintID: gu.Ptr("fingerPrintID"),
IP: net.IPv4(1, 2, 3, 4),
Description: gu.Ptr("agentDescription"),
Header: http.Header{"foo": []string{"foo", "bar"}},
},
},
},
{