@@ -27,8 +27,8 @@ class SentryPrivacyOptions {
27
27
Iterable <SentryMaskingRule > get userMaskingRules => _userMaskingRules;
28
28
29
29
@internal
30
- SentryMaskingConfig buildMaskingConfig (
31
- SdkLogCallback logger, RuntimeChecker runtimeChecker ) {
30
+ SentryMaskingConfig buildMaskingConfig (SdkLogCallback logger,
31
+ RuntimeChecker runtimeChecker, String ? flutterVersion ) {
32
32
// First, we collect rules defined by the user (so they're applied first).
33
33
final rules = _userMaskingRules.toList ();
34
34
@@ -75,7 +75,7 @@ class SentryPrivacyOptions {
75
75
));
76
76
}
77
77
78
- _maybeAddSensitiveContentRule (rules);
78
+ maybeAddSensitiveContentRule (rules, flutterVersion );
79
79
80
80
// In Debug mode, check if users explicitly mask (or unmask) widgets that
81
81
// look like they should be masked, e.g. Videos, WebViews, etc.
@@ -161,63 +161,63 @@ class SentryPrivacyOptions {
161
161
}
162
162
}
163
163
164
- /// Adds a masking rule for the [SensitiveContent] widget.
165
- ///
166
- /// The rule masks any widget that exposes a `sensitivity` property which is an
167
- /// [Enum] . This is how the [SensitiveContent] widget can be detected
168
- /// without depending on its type directly (which would fail to compile on
169
- /// older Flutter versions).
170
- void _maybeAddSensitiveContentRule (List <SentryMaskingRule > rules) {
171
- final flutterVersion = FlutterVersion .version;
172
-
173
- // Only add the rule if we can statically determine that the running
174
- // Flutter SDK is at least 3.33 – that is the first version that contains
175
- // the SensitiveContent widget. For older SDKs we skip the rule entirely.
176
- if (flutterVersion == null ) {
177
- return ;
178
- }
164
+ /// Returns `true` if a SensitiveContent masking rule _should_ be added for a
165
+ /// given [flutterVersion] string. The SensitiveContent widget was introduced
166
+ /// in Flutter 3.33, therefore we only add the masking rule when the detected
167
+ /// version is >= 3.33.
168
+ bool _shouldAddSensitiveContentRule (String ? flutterVersion) {
169
+ if (flutterVersion == null ) return false ;
179
170
180
171
final parts = flutterVersion.split ('.' );
181
172
if (parts.length < 2 ) {
182
173
// Malformed version string – be safe and skip.
183
- return ;
174
+ return false ;
184
175
}
185
176
186
177
const requiredMajor = 3 ;
187
178
const requiredMinor = 33 ;
188
- final major = int .tryParse (parts[0 ]) ?? 0 ;
189
- final minor = int .tryParse (parts[1 ]) ?? 0 ;
179
+ final major = int .tryParse (parts[0 ]);
180
+ final minor = int .tryParse (parts[1 ]);
181
+ if (major == null || minor == null ) {
182
+ // Not numeric – treat as unknown.
183
+ return false ;
184
+ }
190
185
191
- final isNewEnough = major > requiredMajor ||
186
+ return major > requiredMajor ||
192
187
(major == requiredMajor && minor >= requiredMinor);
188
+ }
193
189
194
- if (! isNewEnough) {
195
- // Older than 3.33 – skip.
196
- return ;
190
+ /// Adds a masking rule for the [SensitiveContent] widget.
191
+ ///
192
+ /// The rule masks any widget that exposes a `sensitivity` property which is an
193
+ /// [Enum] . This is how the [SensitiveContent] widget can be detected
194
+ /// without depending on its type directly (which would fail to compile on
195
+ /// older Flutter versions).
196
+ @visibleForTesting
197
+ void maybeAddSensitiveContentRule (
198
+ List <SentryMaskingRule > rules, String ? flutterVersion) {
199
+ if (! _shouldAddSensitiveContentRule (flutterVersion)) return ;
200
+
201
+ SentryMaskingDecision maskSensitiveContent (Element element, Widget widget) {
202
+ try {
203
+ final dynamic dynWidget = widget;
204
+ final sensitivity = dynWidget.sensitivity;
205
+ // If the property exists, we assume this is the SensitiveContent widget.
206
+ assert (sensitivity is Enum );
207
+ return SentryMaskingDecision .mask;
208
+ } catch (_) {
209
+ // Property not found – continue processing other rules.
210
+ return SentryMaskingDecision .continueProcessing;
211
+ }
197
212
}
198
213
199
214
rules.add (SentryMaskingCustomRule <Widget >(
200
- callback: _maskSensitiveContent ,
215
+ callback: maskSensitiveContent ,
201
216
name: 'SensitiveContent' ,
202
217
description: 'Mask SensitiveContent widget.' ,
203
218
));
204
219
}
205
220
206
- /// Callback that detects the future `SensitiveContent` widget by checking for
207
- /// the presence of a `sensitivity` property at runtime.
208
- SentryMaskingDecision _maskSensitiveContent (Element element, Widget widget) {
209
- try {
210
- final dynamic dynWidget = widget;
211
- final sensitivity = dynWidget.sensitivity;
212
- // If the property exists, we assume this is the SensitiveContent widget.
213
- assert (sensitivity is Enum );
214
- return SentryMaskingDecision .mask;
215
- } catch (_) {
216
- // Property not found – continue processing other rules.
217
- return SentryMaskingDecision .continueProcessing;
218
- }
219
- }
220
-
221
221
SentryMaskingDecision _maskImagesExceptAssets (Element element, Image widget) {
222
222
final image = widget.image;
223
223
if (image is AssetBundleImageProvider ) {
0 commit comments