From ca965581e29d38085df4520609b40b97fe9e8a21 Mon Sep 17 00:00:00 2001 From: alltheseas Date: Thu, 5 Feb 2026 14:46:28 -0600 Subject: [PATCH] Address code review feedback - Remove unused originalMessage parameter from _getUserFriendlyMessage - Add rate limiting to user-initiated error reports - Fix empty description showing "Technical details" toggle Co-Authored-By: Claude Opus 4.5 --- lib/services/error_reporting_service.dart | 18 ++++++++++++++++++ lib/services/notification_service.dart | 3 ++- .../android_package_manager.dart | 4 ++-- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/lib/services/error_reporting_service.dart b/lib/services/error_reporting_service.dart index 6b16919..40ca23f 100644 --- a/lib/services/error_reporting_service.dart +++ b/lib/services/error_reporting_service.dart @@ -78,10 +78,24 @@ class ErrorReportingService { /// User-initiated error report (e.g., from "Report issue" button). /// /// Returns true if the report was sent successfully. + /// Rate-limited to prevent accidental spam from repeated taps. Future reportUserError({ required String title, String? technicalDetails, }) async { + // Check session limit + if (_sessionReportCount >= _maxReportsPerSession) { + return false; + } + + // Rate limit by error content + final errorHash = '$title\n${technicalDetails ?? ''}'.hashCode; + final lastReport = _reportedErrors[errorHash]; + if (lastReport != null && + DateTime.now().difference(lastReport) < _rateLimitDuration) { + return false; + } + try { // Create ephemeral signer for error reporting final signer = Bip340PrivateKeySigner(Utils.generateRandomHex64(), ref); @@ -102,6 +116,10 @@ class ErrorReportingService { signedDm, }, source: const RemoteSource(relays: 'social')); + // Update rate limiting + _reportedErrors[errorHash] = DateTime.now(); + _sessionReportCount++; + return true; } catch (e) { debugPrint('[ErrorReporting] Failed to send user report: $e'); diff --git a/lib/services/notification_service.dart b/lib/services/notification_service.dart index 51a5218..b8fe166 100644 --- a/lib/services/notification_service.dart +++ b/lib/services/notification_service.dart @@ -298,7 +298,8 @@ class _ToastContentState extends State<_ToastContent> { @override Widget build(BuildContext context) { - final hasDescription = widget.description != null; + final hasDescription = + widget.description != null && widget.description!.isNotEmpty; final hasActions = widget.actions.isNotEmpty; final hasExtraContent = hasDescription || hasActions; diff --git a/lib/services/package_manager/android_package_manager.dart b/lib/services/package_manager/android_package_manager.dart index c98f87f..2f21306 100644 --- a/lib/services/package_manager/android_package_manager.dart +++ b/lib/services/package_manager/android_package_manager.dart @@ -272,7 +272,7 @@ final class AndroidPackageManager extends PackageManager { case InstallStatus.failed: final failureType = _errorCodeToFailureType(errorCode, message); - final userMessage = _getUserFriendlyMessage(failureType, message); + final userMessage = _getUserFriendlyMessage(failureType); // Preserve technical details: combine original message and description final technicalDetails = [ if (message != null) message, @@ -373,7 +373,7 @@ final class AndroidPackageManager extends PackageManager { /// Convert failure type to user-friendly message. /// Technical details are preserved in the description field. - String _getUserFriendlyMessage(FailureType type, String? originalMessage) { + String _getUserFriendlyMessage(FailureType type) { return switch (type) { FailureType.downloadFailed => 'Download failed. Please try again.', FailureType.hashMismatch =>