115 lines
3.0 KiB
Go
115 lines
3.0 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/Wei-Shaw/sub2api/internal/config"
|
|
"github.com/Wei-Shaw/sub2api/internal/domain"
|
|
"github.com/Wei-Shaw/sub2api/internal/pkg/windsurf"
|
|
)
|
|
|
|
type WindsurfTokenProvider struct {
|
|
cfg config.WindsurfConfig
|
|
accountRepo AccountRepository
|
|
proxyRepo ProxyRepository
|
|
authClient *windsurf.AuthClient
|
|
}
|
|
|
|
func NewWindsurfTokenProvider(
|
|
cfg config.WindsurfConfig,
|
|
accountRepo AccountRepository,
|
|
proxyRepo ProxyRepository,
|
|
authClient *windsurf.AuthClient,
|
|
) *WindsurfTokenProvider {
|
|
return &WindsurfTokenProvider{
|
|
cfg: cfg,
|
|
accountRepo: accountRepo,
|
|
proxyRepo: proxyRepo,
|
|
authClient: authClient,
|
|
}
|
|
}
|
|
|
|
type WindsurfToken struct {
|
|
APIKey string
|
|
ProxyURL string
|
|
AccountID int64
|
|
Tier string
|
|
LSBinding WindsurfLSBinding
|
|
}
|
|
|
|
func (p *WindsurfTokenProvider) GetToken(ctx context.Context, accountID int64) (*WindsurfToken, error) {
|
|
account, err := p.accountRepo.GetByID(ctx, accountID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("get account: %w", err)
|
|
}
|
|
if account.Platform != domain.PlatformWindsurf {
|
|
return nil, fmt.Errorf("account %d is not a windsurf account", accountID)
|
|
}
|
|
|
|
creds := LoadWindsurfCredentials(account.Credentials)
|
|
if creds.APIKey == "" {
|
|
return nil, fmt.Errorf("account %d has no api_key", accountID)
|
|
}
|
|
|
|
proxyURL := ""
|
|
if account.ProxyID != nil {
|
|
proxy, err := p.proxyRepo.GetByID(ctx, *account.ProxyID)
|
|
if err == nil {
|
|
proxyURL = proxy.URL()
|
|
}
|
|
}
|
|
|
|
if creds.NeedsRefresh(p.cfg.Refresh.RefreshBeforeExpiry) {
|
|
if refreshErr := p.refreshInline(ctx, account, &creds, proxyURL); refreshErr != nil {
|
|
if !creds.IsExpired() {
|
|
extra := LoadWindsurfExtra(account.Extra)
|
|
return &WindsurfToken{
|
|
APIKey: creds.APIKey,
|
|
ProxyURL: proxyURL,
|
|
AccountID: accountID,
|
|
Tier: creds.Tier,
|
|
LSBinding: extra.LSBinding,
|
|
}, nil
|
|
}
|
|
return nil, fmt.Errorf("token expired and refresh failed: %w", refreshErr)
|
|
}
|
|
}
|
|
|
|
extra := LoadWindsurfExtra(account.Extra)
|
|
|
|
return &WindsurfToken{
|
|
APIKey: creds.APIKey,
|
|
ProxyURL: proxyURL,
|
|
AccountID: accountID,
|
|
Tier: creds.Tier,
|
|
LSBinding: extra.LSBinding,
|
|
}, nil
|
|
}
|
|
|
|
func (p *WindsurfTokenProvider) refreshInline(ctx context.Context, account *Account, creds *WindsurfCredentials, proxyURL string) error {
|
|
if creds.AuthMethod != "firebase" || creds.RefreshToken == "" {
|
|
return fmt.Errorf("cannot refresh: auth_method=%s", creds.AuthMethod)
|
|
}
|
|
|
|
result, err := p.authClient.RefreshFirebaseToken(ctx, creds.RefreshToken, proxyURL)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
creds.IDToken = result.IDToken
|
|
creds.RefreshToken = result.RefreshToken
|
|
creds.ExpiresAt = time.Now().Add(time.Duration(result.ExpiresIn) * time.Second).Format(time.RFC3339)
|
|
creds.LastRefreshAt = time.Now().Format(time.RFC3339)
|
|
|
|
regResult, err := p.authClient.ReRegisterWithCodeium(ctx, result.IDToken, proxyURL)
|
|
if err == nil {
|
|
creds.APIKey = regResult.APIKey
|
|
creds.LastReregisterAt = time.Now().Format(time.RFC3339)
|
|
}
|
|
|
|
account.Credentials = StoreWindsurfCredentials(*creds)
|
|
return p.accountRepo.Update(ctx, account)
|
|
}
|