package tokens import ( "context" "crypto/rand" "encoding/base64" "io" "net/http" "time" "git.sendico.io/tech/sxchnge/bff/edge/shared/http/ipguard" "git.sendico.io/tech/sxchnge/bff/edge/shared/storage/refreshtokens" "git.sendico.io/tech/sxchnge/bff/pkg/merrors" "git.sendico.io/tech/sxchnge/bff/pkg/mlogger" "git.sendico.io/tech/sxchnge/bff/pkg/model" "git.sendico.io/tech/sxchnge/bff/pkg/mutil/mzap" "go.uber.org/zap" ) func generateRefreshTokenData(length int) (string, error) { randomBytes := make([]byte, length) if _, err := io.ReadFull(rand.Reader, randomBytes); err != nil { return "", merrors.InternalWrap(err, "failed to generate secure random bytes") } return base64.URLEncoding.EncodeToString(randomBytes), nil } func PrepareRefreshToken( ctx context.Context, r *http.Request, rtdb refreshtokens.DB, length int, refreshExpiration int, session *model.SessionIdentifier, account *model.Account, logger mlogger.Logger, ) (*model.RefreshToken, error) { refreshToken, err := generateRefreshTokenData(length) if err != nil { logger.Warn("Failed to generate refresh token", zap.Error(err), mzap.StorableRef(account)) return nil, err } sessionVersion, err := generateRefreshTokenData(16) if err != nil { logger.Warn("Failed to generate session version", zap.Error(err), mzap.StorableRef(account)) return nil, err } versionedSession := *session versionedSession.SessionVersion = sessionVersion clientIP := ipguard.ClientIP(r) ipAddress := "" if clientIP != nil { ipAddress = clientIP.String() } token := &model.RefreshToken{ AccountRef: account.GetID(), ClientRefreshToken: model.ClientRefreshToken{ SessionIdentifier: versionedSession, RefreshToken: refreshToken, }, ExpiresAt: time.Now().Add(time.Duration(refreshExpiration) * time.Hour), IsRevoked: false, UserAgent: r.UserAgent(), IPAddress: ipAddress, } if err = rtdb.Create(ctx, token); err != nil { logger.Warn("Failed to store a refresh token", zap.Error(err), mzap.StorableRef(account), zap.String("client_id", token.ClientID), zap.String("device_id", token.DeviceID)) return nil, err } return token, nil }