fix(mobile): handle rejected video preview authentication

Signed-off-by: Tom Brow <tomb@block.xyz>
This commit is contained in:
Tom Brow
2026-10-18 12:45:41 -07:00
committed by Tom Brow
parent 3aebb4e50c
commit b6dd9bca45
2 changed files with 70 additions and 2 deletions

View File

@@ -30,8 +30,17 @@ final videoPreviewFrameLoaderProvider = Provider<VideoPreviewFrameLoader>((
ref,
) {
final auth = ref.watch(mediaGetAuthServiceProvider);
return (url) async =>
_loadVideoPreviewFrame(url, headers: await auth.headersForAsync(url));
return (url) async {
final Map<String, String> headers;
try {
headers = await auth.headersForAsync(url);
} catch (_) {
// Queue rejection or a failed signing worker leaves this preview
// unavailable. Do not attempt an unauthenticated video request.
return null;
}
return _loadVideoPreviewFrame(url, headers: headers);
};
});
class _MessageVideoPreview extends HookConsumerWidget {

View File

@@ -0,0 +1,59 @@
import 'dart:isolate';
import 'package:buzz/features/channels/message_content.dart';
import 'package:buzz/shared/relay/media_auth.dart';
import 'package:buzz/shared/theme/theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
class _FailingMediaAuth extends MediaGetAuthService {
_FailingMediaAuth(this.error)
: super(baseUrl: 'https://example.com', nsec: null);
final Object error;
final requests = <String>[];
@override
Future<Map<String, String>> headersForAsync(String url) async {
requests.add(url);
throw error;
}
}
void main() {
for (final failure in <String, Object>{
'queue overflow': StateError('Media authentication queue is full'),
'isolate startup': IsolateSpawnException('worker unavailable'),
}.entries) {
testWidgets('posterless video handles auth ${failure.key}', (tester) async {
const url = 'https://example.com/media/clip.mp4';
final auth = _FailingMediaAuth(failure.value);
await tester.pumpWidget(
ProviderScope(
overrides: [mediaGetAuthServiceProvider.overrideWithValue(auth)],
child: MaterialApp(
theme: AppTheme.light(),
home: const AppMarkdownTheme(
child: Scaffold(
body: MessageContent(
content: '![video]($url)',
tags: [
['imeta', 'url $url', 'm video/mp4'],
],
),
),
),
),
),
);
await tester.pumpAndSettle();
expect(auth.requests, [url]);
expect(find.text('Video attachment'), findsOneWidget);
expect(tester.takeException(), isNull);
await tester.pumpWidget(const SizedBox.shrink());
await tester.pump();
expect(tester.takeException(), isNull);
});
}
}