Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions lib/cart.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@ import 'package:provider/provider.dart';
import 'models/cart_state_model.dart';
import 'checkout.dart';

/// Masks a dollar amount for session replay privacy.
/// Keeps only the first digit and replaces the rest with X.
/// e.g. "12.99" → "$1XX.XX", "149.00" → "$1XX.XX"
String _maskPrice(String price) {
// Strip leading '$' if present
final raw = price.startsWith('\$') ? price.substring(1) : price;
if (raw.isEmpty) return '\$$price';
final firstDigit = raw[0];
// Replace every digit after the first with 'X', preserve '.' separators
final masked = raw.substring(1).replaceAll(RegExp(r'\d'), 'X');
return '\$$firstDigit$masked';
}

class CartView extends StatefulWidget {
const CartView({super.key});

Expand Down Expand Up @@ -34,7 +47,7 @@ class _CartViewState extends State<CartView> {
),
SizedBox(width: 8),
Text(
'\$${cart.computeSubtotal().toStringAsFixed(2)}',
_maskPrice(cart.computeSubtotal().toStringAsFixed(2)),
style: TextStyle(
fontSize: 17,
fontWeight: FontWeight.bold,
Expand Down Expand Up @@ -122,7 +135,7 @@ class _CartViewState extends State<CartView> {
Text(cartItem.id.toString()),
Padding(padding: EdgeInsets.fromLTRB(0, 5, 0, 5)),
Text(
'\$${cartItem.price}',
_maskPrice(cartItem.price.toString()),
style: TextStyle(color: Colors.red[900], fontSize: 17),
),
],
Expand Down
2 changes: 1 addition & 1 deletion lib/se_config.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// Each engineer should set their name or identifier here.
// This tags all Sentry events with your identifier for separation.
const String se = 'tda'; // <-- Change this to your name or ID
const String se = 'kunal'; // <-- Change this to your name or ID
32 changes: 18 additions & 14 deletions lib/sentry_setup.dart
Original file line number Diff line number Diff line change
Expand Up @@ -188,21 +188,25 @@ Future<void> initSentry({required VoidCallback appRunner}) async {
// ========================================
// Session Replay Privacy Configuration
// ========================================
// Disable default masking - everything is visible in session replays
// WARNING: Only use this for demo environments without sensitive data
// Mask all images (product photos) in session replays
options.privacy.maskAllImages = true;
// Also mask asset images (AssetImage widgets loaded from the bundle)
options.privacy.maskAssetImages = true;
// Leave text unmasked by default — we use a callback to selectively mask prices
options.privacy.maskAllText = false;
options.privacy.maskAllImages = false;

// To enable masking again, set the above to true and add custom rules:
// options.privacy.mask<YourWidget>();
// options.privacy.unmask<YourWidget>();
// options.privacy.maskCallback<Text>(
// (element, widget) {
// final text = widget.data?.toLowerCase() ?? '';
// // Add your masking logic here
// return SentryMaskingDecision.continueProcessing;
// },
// );

// Mask any Text widget that displays a price (starts with '$') unless it has
// already been partially obscured in the cart (e.g. '$1XX.XX' format).
options.privacy.maskCallback<Text>(
(element, widget) {
final text = widget.data ?? '';
// Already-masked cart prices contain 'X' — let them render as-is
if (text.startsWith('\$') && !text.contains('X')) {
return SentryMaskingDecision.mask;
}
return SentryMaskingDecision.continueProcessing;
},
);

// ========================================
// Additional Configuration
Expand Down
Loading