package refreshtokens import ( "strings" "git.sendico.io/tech/sxchnge/bff/pkg/db/repository" ri "git.sendico.io/tech/sxchnge/bff/pkg/db/repository/index" "git.sendico.io/tech/sxchnge/bff/pkg/db/template" "git.sendico.io/tech/sxchnge/bff/pkg/mlogger" "git.sendico.io/tech/sxchnge/bff/pkg/model" "git.sendico.io/tech/sxchnge/bff/pkg/mservice" "go.mongodb.org/mongo-driver/v2/mongo" "go.uber.org/zap" ) type Collections struct { RefreshTokens string Clients string } type RefreshTokenDB struct { template.DBImp[*model.RefreshToken] clients repository.Repository collection Collections } func Create(logger mlogger.Logger, db *mongo.Database) (*RefreshTokenDB, error) { return CreateWithCollections(logger, db, Collections{}) } func (c Collections) WithDefaults() Collections { if strings.TrimSpace(c.RefreshTokens) == "" { c.RefreshTokens = mservice.RefreshTokens } if strings.TrimSpace(c.Clients) == "" { c.Clients = mservice.Clients } return c } func CreateWithCollections(logger mlogger.Logger, db *mongo.Database, collections Collections) (*RefreshTokenDB, error) { collections = collections.WithDefaults() p := &RefreshTokenDB{ DBImp: *template.Create[*model.RefreshToken](logger, mservice.Type(collections.RefreshTokens), db), clients: repository.CreateMongoRepository(db, collections.Clients), collection: collections, } if err := p.Repository.CreateIndex(&ri.Definition{ Keys: []ri.Key{{Field: "token", Sort: ri.Asc}}, Unique: true, }); err != nil { p.Logger.Error("Failed to create unique token index", zap.Error(err)) return nil, err } ttl := int32(0) if err := p.Repository.CreateIndex(&ri.Definition{ Keys: []ri.Key{{Field: ExpiresAtField, Sort: ri.Asc}}, Name: "expire_sessions", TTL: &ttl, }); err != nil { p.Logger.Error("Failed to create refresh session expiration index", zap.Error(err)) return nil, err } // Add unique constraint on account/client/device combination if err := p.Repository.CreateIndex(&ri.Definition{ Keys: []ri.Key{ {Field: "accountRef", Sort: ri.Asc}, {Field: "clientId", Sort: ri.Asc}, {Field: "deviceId", Sort: ri.Asc}, }, Unique: true, Name: "unique_active_session", PartialFilter: repository.Filter(IsRevokedField, false), }); err != nil { p.Logger.Error("Failed to create unique account/client/device index", zap.Error(err)) return nil, err } if err := p.Repository.CreateIndex(&ri.Definition{ Keys: []ri.Key{{Field: IsRevokedField, Sort: ri.Asc}}, }); err != nil { p.Logger.Error("Failed to create unique token revokation status index", zap.Error(err)) return nil, err } if err := p.clients.CreateIndex(&ri.Definition{ Keys: []ri.Key{{Field: "clientId", Sort: ri.Asc}}, Unique: true, }); err != nil { p.Logger.Error("Failed to create unique client identifier index", zap.Error(err)) return nil, err } return p, nil } func (db *RefreshTokenDB) Collections() Collections { return db.collection }