fix: harden manual cloud upload authentication
This commit is contained in:
parent
825f327549
commit
d8abc78a40
|
|
@ -37,14 +37,24 @@ class FirebaseSyncProvider implements SyncProvider {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<bool> requiresAuthentication() async => _authService.currentUser == null;
|
||||
Future<bool> requiresAuthentication() async {
|
||||
final user = _authService.currentUser;
|
||||
return user == null || user.isAnonymous;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<SyncResult> uploadRide(SyncItem item) async {
|
||||
if (!await isAvailable()) return SyncResult.temporaryFailure('Firebase services are unavailable or unconfigured. Ride remains safely stored locally.');
|
||||
final user = _authService.currentUser;
|
||||
if (user == null || user.isAnonymous) return SyncResult.authRequired(message: 'Sign in to MotorCloud is required for cloud backup.');
|
||||
final idToken = await _authService.getIdToken();
|
||||
|
||||
// Refresh the Firebase ID token before a manual upload. This prevents a
|
||||
// recently completed sign-in from being rejected because the cached token
|
||||
// has not yet propagated through the app's auth abstraction.
|
||||
var idToken = await _authService.getIdToken();
|
||||
if (idToken == null || idToken.isEmpty) {
|
||||
idToken = await _authService.getIdToken(true);
|
||||
}
|
||||
if (idToken == null || idToken.isEmpty) return SyncResult.authRequired(message: 'Valid Firebase authentication token required for cloud sync.');
|
||||
|
||||
try {
|
||||
|
|
@ -59,13 +69,31 @@ class FirebaseSyncProvider implements SyncProvider {
|
|||
if (zipBytes == null || zipBytes.isEmpty) return SyncResult.permanentFailure('Failed generating compressed telemetry bundle for ride #${item.localRideId}.');
|
||||
final sha256Hash = sha256.convert(zipBytes).toString();
|
||||
|
||||
final r2Result = await _r2UploadService.uploadTelemetryBundle(
|
||||
var r2Result = await _r2UploadService.uploadTelemetryBundle(
|
||||
idToken: idToken,
|
||||
remoteRideId: remoteRideId,
|
||||
zipBytes: zipBytes,
|
||||
sha256Hash: sha256Hash,
|
||||
appVersion: appIdentity.semanticVersion,
|
||||
);
|
||||
|
||||
// If the gateway rejects the first token as unauthorized, refresh once
|
||||
// and retry. This specifically handles token rotation/expiry without
|
||||
// turning a valid signed-in session into a false authentication error.
|
||||
if (!r2Result.success && r2Result.requiresAuth) {
|
||||
final refreshedToken = await _authService.getIdToken(true);
|
||||
if (refreshedToken != null && refreshedToken.isNotEmpty && refreshedToken != idToken) {
|
||||
idToken = refreshedToken;
|
||||
r2Result = await _r2UploadService.uploadTelemetryBundle(
|
||||
idToken: idToken,
|
||||
remoteRideId: remoteRideId,
|
||||
zipBytes: zipBytes,
|
||||
sha256Hash: sha256Hash,
|
||||
appVersion: appIdentity.semanticVersion,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!r2Result.success) {
|
||||
if (r2Result.requiresAuth) return SyncResult.authRequired(message: r2Result.errorMessage ?? 'R2 Gateway authentication required');
|
||||
if (r2Result.isRetryable) return SyncResult.temporaryFailure(r2Result.errorMessage ?? 'Temporary R2 upload error');
|
||||
|
|
|
|||
Loading…
Reference in New Issue