mirror of
				https://github.com/mealie-recipes/mealie.git
				synced 2025-11-04 03:03:18 -05:00 
			
		
		
		
	
		
			
	
	
		
			75 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			75 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 
								 | 
							
								import json
							 | 
						||
| 
								 | 
							
								import logging
							 | 
						||
| 
								 | 
							
								import random
							 | 
						||
| 
								 | 
							
								import string
							 | 
						||
| 
								 | 
							
								from datetime import datetime
							 | 
						||
| 
								 | 
							
								from uuid import UUID
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								logger = logging.getLogger("anonymize_backups")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def is_uuid4(value: str):
							 | 
						||
| 
								 | 
							
								    try:
							 | 
						||
| 
								 | 
							
								        UUID(value)
							 | 
						||
| 
								 | 
							
								        return True
							 | 
						||
| 
								 | 
							
								    except ValueError:
							 | 
						||
| 
								 | 
							
								        return False
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def is_iso_datetime(value: str):
							 | 
						||
| 
								 | 
							
								    try:
							 | 
						||
| 
								 | 
							
								        datetime.fromisoformat(value)
							 | 
						||
| 
								 | 
							
								        return True
							 | 
						||
| 
								 | 
							
								    except ValueError:
							 | 
						||
| 
								 | 
							
								        return False
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def random_string(length=10):
							 | 
						||
| 
								 | 
							
								    return "".join(random.choice(string.ascii_lowercase) for _ in range(length))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def clean_value(value):
							 | 
						||
| 
								 | 
							
								    try:
							 | 
						||
| 
								 | 
							
								        match value:
							 | 
						||
| 
								 | 
							
								            # preserve non-strings
							 | 
						||
| 
								 | 
							
								            case int(value) | float(value):
							 | 
						||
| 
								 | 
							
								                return value
							 | 
						||
| 
								 | 
							
								            case None:
							 | 
						||
| 
								 | 
							
								                return value
							 | 
						||
| 
								 | 
							
								            # preserve UUIDs and datetimes
							 | 
						||
| 
								 | 
							
								            case str(value) if is_uuid4(value) or is_iso_datetime(value):
							 | 
						||
| 
								 | 
							
								                return value
							 | 
						||
| 
								 | 
							
								            # randomize strings
							 | 
						||
| 
								 | 
							
								            case str(value):
							 | 
						||
| 
								 | 
							
								                return random_string()
							 | 
						||
| 
								 | 
							
								            case _:
							 | 
						||
| 
								 | 
							
								                pass
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    except Exception as e:
							 | 
						||
| 
								 | 
							
								        logger.exception(e)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    logger.error(f"Failed to anonymize value: {value}")
							 | 
						||
| 
								 | 
							
								    return value
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def walk_data_and_anonymize(data):
							 | 
						||
| 
								 | 
							
								    for k, v in data.items():
							 | 
						||
| 
								 | 
							
								        if isinstance(v, list):
							 | 
						||
| 
								 | 
							
								            for item in v:
							 | 
						||
| 
								 | 
							
								                walk_data_and_anonymize(item)
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            # preserve alembic version number and enums
							 | 
						||
| 
								 | 
							
								            if k in ["auth_method", "version_num"]:
							 | 
						||
| 
								 | 
							
								                continue
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            data[k] = clean_value(v)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def anonymize_database_json(input_filepath: str, output_filepath: str):
							 | 
						||
| 
								 | 
							
								    with open(input_filepath) as f:
							 | 
						||
| 
								 | 
							
								        data = json.load(f)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    walk_data_and_anonymize(data)
							 | 
						||
| 
								 | 
							
								    with open(output_filepath, "w") as f:
							 | 
						||
| 
								 | 
							
								        json.dump(data, f)
							 |