Django REST Framework package for role-based field masking in serializers
Project description
django-role-based-masking
A Django REST Framework package that masks serializer output fields based on the requesting user's role using configurable masking strategies.
Features
- 🎭 Role-based field masking - Automatically mask sensitive fields based on user roles
- 🔧 Flexible strategies - Built-in masking strategies (full, partial, email, percentage)
- 🪆 Nested support - Mask fields in nested serializers using dotted paths
- 🎨 Custom strategies - Easy to add custom masking logic
- ⚡ DRF integration - Simple mixin for existing serializers
- 🧪 Well tested - Comprehensive test suite
- 📦 Production ready - Supports Python 3.10+, Django 3.2+, DRF 3.14+
Installation
pip install django-role-based-masking
Quick Start
1. Basic Usage
from rest_framework import serializers
from django_role_based_masking.serializers import RoleMaskedModelSerializer
class EmployeeSerializer(RoleMaskedModelSerializer):
class Meta:
model = Employee
fields = ['id', 'name', 'email', 'phone', 'salary', 'ssn']
# Define masking rules per role
mask_fields = {
"ADMIN": {}, # No masking for admins
"MANAGER": {
"ssn": "partial_last:4",
"salary": "percentage:50",
},
"EMPLOYEE": {
"email": "email",
"phone": "partial_last:4",
"salary": "full",
"ssn": "full",
},
"ANONYMOUS": {
"email": "full",
"phone": "full",
"salary": "full",
"ssn": "full",
}
}
2. Example Output
For a user with role MANAGER:
# Original data
{
"id": 1,
"name": "John Doe",
"email": "john.doe@example.com",
"phone": "+1234567890",
"salary": "75000",
"ssn": "123-45-6789"
}
# Masked output
{
"id": 1,
"name": "John Doe",
"email": "john.doe@example.com",
"phone": "+1234567890",
"salary": "*****0", # 50% masked
"ssn": "***-**-6789" # Only last 4 visible
}
Built-in Masking Strategies
full
Masks the entire string.
"salary": "full"
# "75000" -> "*****"
partial_last:N
Keeps the last N characters, masks the rest.
"ssn": "partial_last:4"
# "123-45-6789" -> "***-**-6789"
"phone": "partial_last:4"
# "+1234567890" -> "*******7890"
email
Masks the email local-part except the first character.
"email": "email"
# "john.doe@example.com" -> "j*******@example.com"
percentage:N
Masks N% of the string length from the left.
"salary": "percentage:70"
# "75000" -> "****0" # 70% of 5 chars = 3.5 -> 4 chars masked
noop
No masking (passthrough).
"name": "noop"
# "John Doe" -> "John Doe"
Nested Field Masking
Use dotted paths to mask fields in nested serializers:
class UserProfileSerializer(RoleMaskedModelSerializer):
address = AddressSerializer()
class Meta:
model = UserProfile
fields = ['name', 'email', 'address']
mask_fields = {
"GUEST": {
"email": "email",
"address.street": "full",
"address.postal_code": "partial_last:3",
}
}
Custom Masking Strategies
Using a Callable
def custom_mask(value, mask_char="*"):
"""Mask middle portion of string."""
if len(value) <= 4:
return mask_char * len(value)
keep = len(value) // 4
return value[:keep] + mask_char * (len(value) - 2 * keep) + value[-keep:]
class MySerializer(RoleMaskedModelSerializer):
class Meta:
model = MyModel
fields = ['id', 'secret_code']
mask_fields = {
"USER": {
"secret_code": custom_mask,
}
}
Using a Dictionary
mask_fields = {
"USER": {
"phone": {
"name": "partial_last",
"kwargs": {"keep_last": 2}
}
}
}
Configuration
Add these settings to your Django settings.py:
# Default role attribute path (supports dotted paths like "profile.role")
DRM_ROLE_ATTR = "role" # default
# Default masking character
DRM_MASK_CHAR = "*" # default
# Default strategy when not specified
DRM_DEFAULT_STRATEGY = "full" # default
Role Resolution
The package resolves user roles using the following priority:
- Exact role match - Uses the role-specific rules
- DEFAULT role - Falls back to "DEFAULT" if defined
- ANONYMOUS role - Falls back to "ANONYMOUS" if user is not authenticated
- No masking - If no rules match, returns data unchanged
Role Attribute Path
By default, the package looks for user.role. You can customize this:
# settings.py
DRM_ROLE_ATTR = "profile.user_role" # Supports dotted paths
Anonymous users automatically get the "ANONYMOUS" role.
Advanced Usage
Using the Mixin
from rest_framework import serializers
from django_role_based_masking.serializers import RoleMaskedSerializerMixin
class CustomSerializer(RoleMaskedSerializerMixin, serializers.Serializer):
name = serializers.CharField()
email = serializers.EmailField()
# Define mask_fields as class attribute
mask_fields = {
"GUEST": {
"email": "email"
}
}
Programmatic Masking
from django_role_based_masking.masking import apply_masking
data = {
"name": "John Doe",
"email": "john@example.com",
"salary": "75000"
}
rules = {
"EMPLOYEE": {
"salary": "full"
}
}
context = {"request": request} # DRF request object
masked_data = apply_masking(data, rules, context)
Requirements
- Python 3.10+
- Django 3.2+
- Django REST Framework 3.14+
Development
Setup
# Clone the repository
git clone https://github.com/gaikwadakshay79/django-role-based-masking.git
cd django-role-based-masking
# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install -e ".[dev]"
Running Tests
pytest
Code Quality
ruff check .
ruff format .
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Changelog
See CHANGELOG.md for a list of changes.
Support
- 📫 Issues: GitHub Issues
- 📖 Documentation: README
Acknowledgments
Built with ❤️ for the Django and DRF community.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_role_based_masking-1.0.0.tar.gz.
File metadata
- Download URL: django_role_based_masking-1.0.0.tar.gz
- Upload date:
- Size: 13.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5455d53f7e109d1a6aa9b822753ba159f0724221f0121cd178ecb74f86811c14
|
|
| MD5 |
fd4a65965f9fd441213b58fb4e9199bc
|
|
| BLAKE2b-256 |
857ed01aed4bdee8621a7c769114966a5d3b56cfe225b400c86d0e347c4c54ed
|
File details
Details for the file django_role_based_masking-1.0.0-py3-none-any.whl.
File metadata
- Download URL: django_role_based_masking-1.0.0-py3-none-any.whl
- Upload date:
- Size: 11.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b305d89376e46b5ab2edd40a14b0d39accd6eae60098b791ba962e74ef0387d5
|
|
| MD5 |
f130ac882f9f9a2231c9506cf8380c15
|
|
| BLAKE2b-256 |
951bb170918706f31864e19dc854012bed07578424fc4c3f48fdae75605e3af2
|