Files
sxchnge/backend/product/sessions/tokens/tokens.go

79 lines
2.2 KiB
Go

package tokens
import (
"context"
"crypto/rand"
"encoding/base64"
customermodel "git.sendico.io/tech/sxchnge/product/customers/model"
sessionmodel "git.sendico.io/tech/sxchnge/product/sessions/model"
"io"
"net/http"
"time"
"git.sendico.io/tech/sxchnge/product/auth/ipguard"
"git.sendico.io/tech/sxchnge/product/sessions/store"
"git.sendico.io/tech/sxchnge/shared/errors"
"git.sendico.io/tech/sxchnge/shared/logging"
"git.sendico.io/tech/sxchnge/shared/logging/fields"
"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 *sessionmodel.SessionIdentifier,
account *customermodel.Account,
logger mlogger.Logger,
) (*sessionmodel.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 := &sessionmodel.RefreshToken{
AccountRef: account.GetID(),
ClientRefreshToken: sessionmodel.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
}