data_masker

Pure Dart data masking library for sensitive data anonymization. Works on all Dart platforms with zero dependencies.

Quick Results

See what data_masker can do at a glance:

Data Type Input Output
Phone 13812345678 138****5678
Email user@example.com use***@example.com
ID Card 110101199001011234 110101********1234
Bank Card 6222021234567890123 6222***********0123
IP Address 192.168.1.100 192.168.***.100
URL https://example.com/api/users https://example.com********
Passport G12345678 G******
License Plate CA12345 CA1***
JWT Token eyJhbGciOiJIUzI1Ni...w5c eyJhbGci****************w5c
UUID 550e8400-e29b-41d4-a716-...0000 550e8400-****-****-****-446655440000
API Key sk_test_abcdefghijklmnop... sk_************
Chinese Name Zhang San, Zhang Sanfeng Zhang ***, Zhang ***
English Name John Doe John D***
Date of Birth 1990-01-01 1990-01-**

Features

  • Cross-platform: Pure Dart implementation, works everywhere Dart runs
  • 15+ Preset Rules: Phone, email, ID card, bank card, IP, URL, passport, license plate, JWT, UUID, API key, names, date of birth
  • 4 Mask Strategies: Full mask, keep prefix, keep suffix, keep both ends
  • Custom Rules: Field name matching, regex matching, custom logic
  • Nested Support: Recursively masks nested Map and List structures
  • Type Safe: Full null safety support
  • Dart 2.19+: Compatible with a wide range of Dart versions

Getting Started

Installation

dependencies:
  data_masker: ^1.0.0
dart pub get

Basic Usage

import 'package:data_masker/data_masker.dart';

void main() {
  final config = MaskConfig(
    enabled: true,
    rules: [
      PresetMaskRules.phone(),
      PresetMaskRules.email(),
      FieldMaskRule(fieldNames: ['password', 'token']),
    ],
  );

  final masker = DataMasker(config);

  // Mask string
  final maskedString = masker.process('Phone: 13812345678, Email: user@example.com');
  print(maskedString);
  // Output: Phone: 138****5678, Email: use***@example.com

  // Mask Map
  final maskedMap = masker.process({
    'username': 'test',
    'password': 'secret123',
    'phone': '13812345678',
  });
  print(maskedMap);
  // Output: {username: test, password: *********, phone: 138****5678}

  // Mask nested structure
  final nestedData = {
    'user': {
      'name': 'Zhang San',
      'auth': {'token': 'abc123xyz'}
    },
    'contacts': [{'phone': '13987654321'}],
  };
  final maskedNested = masker.process(nestedData);
  print(maskedNested);
  // Output: {user: {name: Zhang ***, auth: {token: *********}}, contacts: [{phone: 139****4321}]}
}

Run Example

dart run example/data_masker_example.dart

Actual Output:

=== data_masker Complete Example ===

1. MaskStrategy (Masking Strategy)
   full: **********
   keepPrefix: 123*******
   keepSuffix: ******7890
   keepBoth: 123****890

2. PresetMaskRules (Preset Rules)
   Phone: 138****5678
   Email: use***@example.com
   ID Card: 110101********1234
   Bank Card: 6222***********0123
   IP Address: 192.168.***.100
   URL: https://example.com********

3. Supported Data Types
   String: Phone: 138****5678, Email: use***@example.com
   Map: {username: test, password: *********, phone: 138****5678}
   List: [{name: Alice, email: ali***@example.com}, {name: Bob, email: bob***@example.com}]

4. Real-world Scenario
   API Response Masking:
   {code: 200, message: success, data: {user: {id: 123, name: Zhang ***, phone: 138****5678, email: zha***@company.com, idCard: 110101********1234, bankCard: 6222***********0123}, session: {token: ********************, expireTime: 2024-12-31 23:59:59}}}

API Documentation

MaskStrategy

Enumeration defining the masking strategy.

Strategy Description Example
full Mask entire value 1234567890**********
keepPrefix Keep prefix, mask rest 1234567890123*******
keepSuffix Keep suffix, mask rest 1234567890******7890
keepBoth Keep both ends, mask middle 1234567890123****890

MaskConfig

const MaskConfig({
  this.enabled = false,           // Enable/disable masking
  this.defaultStrategy = MaskStrategy.full,
  this.rules = const [],          // List of mask rules
  this.maskChar = '*',            // Mask character: '*' or '#' or any
  this.maxMaskLength = 20,        // Maximum mask characters
  this.caseSensitive = false,     // Case sensitive field matching
});

Example:

final config = MaskConfig(
  enabled: true,
  maskChar: '#',
  maxMaskLength: 10,
  rules: [PresetMaskRules.phone()],
);

final masker = DataMasker(config);
print(masker.process('13812345678'));
// Output: 138####5678

DataMasker

const DataMasker([this.config = const MaskConfig()]);

Object? process(Object? data);

Supported Types:

Type Behavior
String Apply regex rules to find and mask patterns
Map Recursively process keys and values
Iterable Recursively process each item
Other Convert to string and apply rules

Example:

final masker = DataMasker(MaskConfig(
  enabled: true,
  rules: [PresetMaskRules.email()],
));

// Process String
masker.process('Contact: alice@example.com');
// Output: Contact: ali***@example.com

// Process Map
masker.process({'email': 'bob@example.com'});
// Output: {email: bob***@example.com}

// Process List
masker.process([
  {'name': 'Alice', 'email': 'alice@example.com'},
  {'name': 'Bob', 'email': 'bob@example.com'},
]);
// Output: [{name: Alice, email: ali***@example.com}, {name: Bob, email: bob***@example.com}]

// Process nested structure
masker.process({
  'user': {'name': 'John', 'auth': {'token': 'abc123'}}
});
// Output: {user: {name: John, auth: {token: *********}}}

FieldMaskRule

Mask values based on field name matching.

const FieldMaskRule({
  required this.fieldNames,       // List of field names to match
  super.strategy = MaskStrategy.full,
  super.keepCount = 4,
  super.customMask,
});

Example:

final rule = FieldMaskRule(
  fieldNames: ['password', 'token', 'secret'],
  strategy: MaskStrategy.keepPrefix,
  keepCount: 2,
);

const config = MaskConfig(enabled: true);

// Check if field matches
rule.matches('password', 'secret123');  // true
rule.matches('username', 'test');       // false

// Apply mask
rule.apply('secret123', config);        // 'se*********'

// Apply to JSON string
rule.applyToJsonString('{"password":"secret123"}', config);
// Output: {"password":"*********"}

RegexMaskRule

Mask values based on regular expression matching.

const RegexMaskRule({
  required this.pattern,          // RegExp pattern to match
  this.formatter,                 // Custom formatter function
  super.strategy = MaskStrategy.full,
  super.keepCount = 4,
  super.customMask,
});

Example with Strategy:

final rule = RegexMaskRule(
  pattern: RegExp(r'\d{6,8}'),
  strategy: MaskStrategy.keepBoth,
  keepCount: 3,
);

const config = MaskConfig(enabled: true);
rule.apply('ID: 12345678', config);
// Output: ID: 123**678

Example with Custom Formatter:

final rule = RegexMaskRule(
  pattern: RegExp(r'(\d{3})\d{4}(\d{4})'),
  formatter: (match, config) {
    return '${match.group(1)}****${match.group(2)}';
  },
);

rule.apply('13812345678', config);
// Output: 138****5678

CustomMaskRule

Mask values with custom matching logic.

const CustomMaskRule({
  required this.matcher,          // Custom matcher function
  this.formatter,                 // Custom formatter function
  super.strategy = MaskStrategy.full,
  super.keepCount = 4,
  super.customMask,
});

Example:

// Custom matcher
final rule = CustomMaskRule(
  matcher: (key, value) => key?.toString() == 'custom_field',
  strategy: MaskStrategy.keepPrefix,
  keepCount: 2,
);

rule.matches('custom_field', 'value');  // true
rule.matches('other_field', 'value');   // false
rule.apply('abcdef', config);           // 'ab****'

// Custom formatter
final formatterRule = CustomMaskRule(
  matcher: (key, value) => true,
  formatter: (value) => '[MASKED]',
);

formatterRule.apply('sensitive data', config);
// Output: [MASKED]

MaskUtils

static String applyMask(
  String value,
  MaskStrategy strategy,
  int? keepCount,
  String? customMask,
  MaskConfig config,
);

Example:

MaskUtils.applyMask('1234567890', MaskStrategy.keepBoth, 3, null, config);
// Output: 123****890

MaskUtils.applyMask('secret', MaskStrategy.full, 4, '[HIDDEN]', config);
// Output: [HIDDEN]

PresetMaskRules

Individual Rules

// Phone
PresetMaskRules.phone().apply('13812345678', config);
// Output: 138****5678

// Email
PresetMaskRules.email().apply('user@example.com', config);
// Output: use***@example.com

// ID Card
PresetMaskRules.idCard().apply('110101199001011234', config);
// Output: 110101********1234

// Bank Card
PresetMaskRules.bankCard().apply('6222021234567890123', config);
// Output: 6222***********0123

// IP Address
PresetMaskRules.ipAddress().apply('192.168.1.100', config);
// Output: 192.168.***.100

// URL
PresetMaskRules.url().apply('https://example.com/api/users', config);
// Output: https://example.com********

// Passport
PresetMaskRules.passport().apply('G12345678', config);
// Output: G******

// License Plate
PresetMaskRules.plateNumber().apply('CA12345', config);
// Output: CA1***

// JWT Token
PresetMaskRules.jwtToken().apply('eyJhbGciOiJIUzI1Ni...w5c', config);
// Output: eyJhbGci****************w5c

// UUID
PresetMaskRules.uuid().apply('550e8400-e29b-41d4-a716-446655440000', config);
// Output: 550e8400-****-****-****-446655440000

// API Key
PresetMaskRules.apiKey().apply('sk_test_abcdefghijklmnop', config);
// Output: sk_************

// Chinese Name (matches 2-4 Chinese characters)
// Pattern: [\u4e00-\u9fa5]{2,4}
// Keep first char, mask the rest

// English Name
PresetMaskRules.englishName().apply('John Doe', config);
// Output: John D***

// Date of Birth
PresetMaskRules.dateOfBirth().apply('1990-01-01', config);
// Output: 1990-01-**

Preset Combinations

Pre-configured rule combinations for common use cases:

// Financial data: bankCard + idCard + phone + commonFields
final financialConfig = MaskConfig(
  enabled: true,
  rules: PresetMaskRules.financial(),
);

// API logging: jwtToken + apiKey + email + ipAddress + url + commonFields
final apiLogConfig = MaskConfig(
  enabled: true,
  rules: PresetMaskRules.apiLog(),
);

// Personal info: phone + email + idCard + names + dateOfBirth + passport + commonFields
final personalConfig = MaskConfig(
  enabled: true,
  rules: PresetMaskRules.personalInfo(),
);

// Network logging: ipAddress + url + jwtToken + apiKey + email
final networkConfig = MaskConfig(
  enabled: true,
  rules: PresetMaskRules.networkLog(),
);

Advanced Usage

Disable Masking

final config = MaskConfig(
  enabled: false,  // All masking disabled
  rules: [PresetMaskRules.phone()],
);

final masker = DataMasker(config);
masker.process('13812345678');
// Output: 13812345678 (unchanged)

Custom Mask Character

final config = MaskConfig(
  enabled: true,
  maskChar: '#',
  rules: [PresetMaskRules.phone()],
);

final masker = DataMasker(config);
masker.process('13812345678');
// Output: 138####5678

Multiple Rules

final config = MaskConfig(
  enabled: true,
  rules: [
    PresetMaskRules.phone(),
    PresetMaskRules.email(),
    FieldMaskRule(fieldNames: ['password', 'token']),
    RegexMaskRule(pattern: RegExp(r'\d{8,}')),
  ],
);

final masker = DataMasker(config);
masker.process({
  'phone': '13812345678',
  'email': 'user@example.com',
  'password': 'secret123',
});
// Output: {phone: 138****5678, email: use***@example.com, password: *********}

Platform Support

  • ✅ Flutter Android
  • ✅ Flutter iOS
  • ✅ Flutter Web
  • ✅ Flutter Desktop (macOS, Linux, Windows)
  • ✅ Dart CLI
  • ✅ Dart Server

Dart Version

  • Minimum: Dart 2.19.0
  • Recommended: Dart 3.0+

License

MIT

Libraries

data_masker
Pure Dart data masking library for sensitive data anonymization.