-
-
Notifications
You must be signed in to change notification settings - Fork 237
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: custom replay masking rules (#2324)
* refactor: change redaction logic to custom filters * refactor widget filter to handle errors gracefully * cleanup * add an option to disable masking asset images * add new masking config class * update widget filter to use the masking config * cleanup * masking tests * cleanup * test masking editable text * fix tests on web * fix tests on web * fix tests for wasm * add SentryMask and SentryUnmask widgets * linter issue * chore: changelog * rename to SentryMaskingDecision * mark new replay APIs as experimental * Update flutter/lib/src/replay/masking_config.dart Co-authored-by: Giancarlo Buenaflor <[email protected]> * chore: update changelog * test: mask parent if masking the child fails --------- Co-authored-by: Giancarlo Buenaflor <[email protected]>
- Loading branch information
Showing
11 changed files
with
712 additions
and
92 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import 'package:flutter/widgets.dart'; | ||
import 'package:meta/meta.dart'; | ||
|
||
@internal | ||
class SentryMaskingConfig { | ||
@visibleForTesting | ||
final List<SentryMaskingRule> rules; | ||
|
||
final int length; | ||
|
||
SentryMaskingConfig(List<SentryMaskingRule> rules) | ||
// Note: fixed-size list has performance benefits over growable list. | ||
: rules = List.of(rules, growable: false), | ||
length = rules.length; | ||
|
||
SentryMaskingDecision shouldMask<T extends Widget>( | ||
Element element, T widget) { | ||
for (int i = 0; i < length; i++) { | ||
if (rules[i].appliesTo(widget)) { | ||
// We use a switch here to get lints if more values are added. | ||
switch (rules[i].shouldMask(element, widget)) { | ||
case SentryMaskingDecision.mask: | ||
return SentryMaskingDecision.mask; | ||
case SentryMaskingDecision.unmask: | ||
return SentryMaskingDecision.unmask; | ||
case SentryMaskingDecision.continueProcessing: | ||
// Continue to the next matching rule. | ||
} | ||
} | ||
} | ||
return SentryMaskingDecision.continueProcessing; | ||
} | ||
} | ||
|
||
@experimental | ||
enum SentryMaskingDecision { | ||
/// Mask the widget and its children | ||
mask, | ||
|
||
/// Leave the widget visible, including its children (no more rules will | ||
/// be checked for children). | ||
unmask, | ||
|
||
/// Don't make a decision - continue checking other rules and children. | ||
continueProcessing | ||
} | ||
|
||
@internal | ||
abstract class SentryMaskingRule<T extends Widget> { | ||
@pragma('vm:prefer-inline') | ||
bool appliesTo(Widget widget) => widget is T; | ||
SentryMaskingDecision shouldMask(Element element, T widget); | ||
|
||
const SentryMaskingRule(); | ||
} | ||
|
||
@internal | ||
class SentryMaskingCustomRule<T extends Widget> extends SentryMaskingRule<T> { | ||
final SentryMaskingDecision Function(Element element, T widget) callback; | ||
|
||
const SentryMaskingCustomRule(this.callback); | ||
|
||
@override | ||
SentryMaskingDecision shouldMask(Element element, T widget) => | ||
callback(element, widget); | ||
|
||
@override | ||
String toString() => '$SentryMaskingCustomRule<$T>($callback)'; | ||
} | ||
|
||
@internal | ||
class SentryMaskingConstantRule<T extends Widget> extends SentryMaskingRule<T> { | ||
final SentryMaskingDecision _value; | ||
const SentryMaskingConstantRule(this._value); | ||
|
||
@override | ||
SentryMaskingDecision shouldMask(Element element, T widget) { | ||
// This rule only makes sense with true/false. Continue won't do anything. | ||
assert(_value == SentryMaskingDecision.mask || | ||
_value == SentryMaskingDecision.unmask); | ||
return _value; | ||
} | ||
|
||
@override | ||
String toString() => | ||
'$SentryMaskingConstantRule<$T>(${_value == SentryMaskingDecision.mask ? 'mask' : 'unmask'})'; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.