Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v9]: Enable privacy masking for screenshots by default #2728

Merged
merged 3 commits into from
Feb 18, 2025
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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
- Responses are now only attached if size is below ~0.15mb
- Responses are attached to the `Hint` object, which can be read in `beforeSend`/`beforeSendTransaction` callbacks via `hint.response`.
- For now, only the `dio` integration is supported.

- Enable privacy masking for screenshots by default ([#2728](https://github.com/getsentry/sentry-dart/pull/2728))

### Enhancements

- Replay: improve Android native interop performance by using JNI ([#2670](https://github.com/getsentry/sentry-dart/pull/2670))
Expand Down
12 changes: 5 additions & 7 deletions flutter/lib/src/native/sentry_native_channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,11 @@ class SentryNativeChannel
'sessionSampleRate': options.experimental.replay.sessionSampleRate,
'onErrorSampleRate': options.experimental.replay.onErrorSampleRate,
'tags': <String, dynamic>{
'maskAllText': options.experimental.privacyForReplay.maskAllText,
'maskAllImages': options.experimental.privacyForReplay.maskAllImages,
'maskAssetImages':
options.experimental.privacyForReplay.maskAssetImages,
if (options.experimental.privacyForReplay.userMaskingRules.isNotEmpty)
'maskingRules': options
.experimental.privacyForReplay.userMaskingRules
'maskAllText': options.experimental.privacy.maskAllText,
'maskAllImages': options.experimental.privacy.maskAllImages,
'maskAssetImages': options.experimental.privacy.maskAssetImages,
if (options.experimental.privacy.userMaskingRules.isNotEmpty)
'maskingRules': options.experimental.privacy.userMaskingRules
.map((rule) => '${rule.name}: ${rule.description}')
.toList(growable: false),
},
Expand Down
2 changes: 1 addition & 1 deletion flutter/lib/src/replay/replay_recorder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ var _instanceCounter = 0;
class ReplayScreenshotRecorder extends ScreenshotRecorder {
ReplayScreenshotRecorder(super.config, super.options)
: super(
privacyOptions: options.experimental.privacyForReplay,
privacyOptions: options.experimental.privacy,
logName: 'ReplayRecorder #${++_instanceCounter}');

@override
Expand Down
10 changes: 3 additions & 7 deletions flutter/lib/src/screenshot/recorder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,17 @@ class ScreenshotRecorder {
bool _warningLogged = false;
late final SentryMaskingConfig? _maskingConfig;

// TODO: remove in the next major release, see recorder_test.dart.
@visibleForTesting
bool get hasWidgetFilter => _maskingConfig != null;

ScreenshotRecorder(
this.config,
this.options, {
SentryPrivacyOptions? privacyOptions,
this.logName = 'ScreenshotRecorder',
}) {
privacyOptions ??= options.experimental.privacyForScreenshots;
privacyOptions ??= options.experimental.privacy;

final maskingConfig =
privacyOptions?.buildMaskingConfig(_log, options.platformChecker);
_maskingConfig = (maskingConfig?.length ?? 0) > 0 ? maskingConfig : null;
privacyOptions.buildMaskingConfig(_log, options.platformChecker);
_maskingConfig = maskingConfig.length > 0 ? maskingConfig : null;
}

void _log(SentryLevel level, String message,
Expand Down
29 changes: 2 additions & 27 deletions flutter/lib/src/sentry_flutter_options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -381,33 +381,8 @@ class _SentryFlutterExperimentalOptions {
final replay = SentryReplayOptions();

/// Privacy configuration for masking sensitive data in screenshots and Session Replay.
/// Screen content masking is:
/// - enabled by default for SessionReplay
/// - disabled by default for screenshots captured with events.
/// In order to mask screenshots captured with events, access or change
/// this property in your application: `options.experimental.privacy`.
/// Doing so will indicate that you want to configure privacy settings and
/// will enable screenshot masking alongside the default replay masking.
/// Note: this will change in a future SDK major release to enable screenshot
/// masking by default for all captures.
SentryPrivacyOptions get privacy {
// If the user explicitly sets the privacy setting, we use that.
// Otherwise, we use the default settings, which is no masking for screenshots
// and full masking for session replay.
// This property must only by accessed by user code otherwise it defeats the purpose.
_privacy ??= SentryPrivacyOptions();
return _privacy!;
}

/// TODO: remove when default masking value are synced with SS & SR in the next major release
SentryPrivacyOptions? _privacy;

@meta.internal
SentryPrivacyOptions? get privacyForScreenshots => _privacy;

@meta.internal
SentryPrivacyOptions get privacyForReplay =>
_privacy ?? SentryPrivacyOptions();
/// Screen content masking is enabled by default.
final privacy = SentryPrivacyOptions();
}

/// A callback which can be used to suppress capturing of screenshots.
Expand Down
26 changes: 0 additions & 26 deletions flutter/test/screenshot/recorder_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import 'dart:ui';
import 'package:flutter/widgets.dart' as widgets;
import 'package:flutter_test/flutter_test.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:sentry_flutter/src/replay/replay_recorder.dart';
import 'package:sentry_flutter/src/screenshot/recorder.dart';
import 'package:sentry_flutter/src/screenshot/recorder_config.dart';
import 'package:sentry_flutter/src/screenshot/screenshot.dart';
Expand Down Expand Up @@ -114,31 +113,6 @@ void main() async {
expect(await fixture.capture(), isNull);
});

// TODO: remove in the next major release, see _SentryFlutterExperimentalOptions.
group('Widget filter is used based on config or application', () {
test('Uses widget filter by default for Replay', () {
final sut = ReplayScreenshotRecorder(
ScreenshotRecorderConfig(),
defaultTestOptions(),
);
expect(sut.hasWidgetFilter, isTrue);
});

test('Does not use widget filter by default for Screenshots', () {
final sut =
ScreenshotRecorder(ScreenshotRecorderConfig(), defaultTestOptions());
expect(sut.hasWidgetFilter, isFalse);
});

test(
'Uses widget filter for Screenshots when privacy configured explicitly',
() {
final sut = ScreenshotRecorder(ScreenshotRecorderConfig(),
defaultTestOptions()..experimental.privacy.maskAllText = false);
expect(sut.hasWidgetFilter, isTrue);
});
});

group('$Screenshot', () {
test('listEquals()', () {
expect(
Expand Down
Loading