package migration import ( "context" "fmt" "time" "golang.org/x/oauth2" "github.com/ultisuite/ulti-backend/internal/mail/credentials" ) // RefreshCredential refreshes an expired migration OAuth token and persists it. func (s *Service) RefreshCredential( ctx context.Context, oauth *OAuthService, userID, projectID, provider string, cred credentials.Credential, ) (credentials.Credential, error) { if oauth == nil { return cred, fmt.Errorf("migration oauth not configured") } if !cred.NeedsRefresh() { return cred, nil } if cred.RefreshToken == "" { return cred, fmt.Errorf("migration refresh token missing; re-run OAuth consent") } token, err := oauth.Refresh(ctx, Provider(provider), cred.RefreshToken) if err != nil { return cred, fmt.Errorf("refresh migration token: %w", err) } updated := applyOAuthTokenFromOAuth2(cred, token) if err := s.SaveCredential(ctx, userID, projectID, provider, updated); err != nil { return cred, err } return updated, nil } // SaveCredential encrypts and stores migration OAuth credentials. func (s *Service) SaveCredential(ctx context.Context, userID, projectID, provider string, cred credentials.Credential) error { if s.creds == nil { return fmt.Errorf("credential manager not configured") } cred.AuthType = credentials.AuthOAuth2 cred.OAuthProvider = provider enc, err := s.creds.EncryptCredential(cred) if err != nil { return err } var expiresAt *time.Time if !cred.Expiry.IsZero() { expiresAt = &cred.Expiry } _, err = s.db.Exec(ctx, ` UPDATE migration_credentials SET encrypted_token = $4, expires_at = $5, revoked_at = NULL WHERE user_id = $1::uuid AND project_id = $2::uuid AND provider = $3 `, userID, projectID, provider, enc, expiresAt) return err } func (s *Service) MicrosoftAdminConsentURL(tenant, projectID string) (string, error) { if s.oauth == nil { return "", fmt.Errorf("migration oauth not configured") } return s.oauth.AdminConsentURL(tenant, EncodeAdminConsentState(projectID)) } func applyOAuthTokenFromOAuth2(cred credentials.Credential, token *oauth2.Token) credentials.Credential { return applyOAuthToken(cred, &oauthToken{ AccessToken: token.AccessToken, RefreshToken: token.RefreshToken, Expiry: token.Expiry, }) }