- Added configuration options for Stalwart hosted mail in .env.example. - Updated Docker Compose to include Stalwart service with health checks. - Introduced new API endpoints for managing mail domains and migration projects. - Enhanced Authentik blueprints for user enrollment and post-migration security. - Updated OAuth handling for Google and Microsoft migration processes. - Improved error handling and response structures in the mail API. - Added integration tests for email claiming and migration workflows.
79 lines
2.2 KiB
Go
79 lines
2.2 KiB
Go
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,
|
|
})
|
|
}
|