79 lines
2.2 KiB
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
|
|
}
|