package_privacy.py (2718B)
1 """Owned privacy and contact declarations for the implemented public product.""" 2 3 from __future__ import annotations 4 5 from typing import Any 6 7 SUPPORT_EMAIL = "support@radroots.org" 8 CAMERA_PURPOSE = ( 9 "Tera uses the camera only when you choose to add a photo to a public post." 10 ) 11 12 13 def manifest() -> dict[str, Any]: 14 """Publicly posted identity/profile/content/media remain linked off device.""" 15 data_types = [ 16 "NSPrivacyCollectedDataTypeName", 17 "NSPrivacyCollectedDataTypeUserID", 18 "NSPrivacyCollectedDataTypePhysicalAddress", 19 "NSPrivacyCollectedDataTypePhotosorVideos", 20 "NSPrivacyCollectedDataTypeOtherUserContent", 21 ] 22 return { 23 "NSPrivacyTracking": False, 24 "NSPrivacyTrackingDomains": [], 25 "NSPrivacyCollectedDataTypes": [ 26 { 27 "NSPrivacyCollectedDataType": value, 28 "NSPrivacyCollectedDataTypeLinked": True, 29 "NSPrivacyCollectedDataTypeTracking": False, 30 "NSPrivacyCollectedDataTypePurposes": [ 31 "NSPrivacyCollectedDataTypePurposeAppFunctionality" 32 ], 33 } 34 for value in data_types 35 ], 36 "NSPrivacyAccessedAPITypes": [ 37 { 38 "NSPrivacyAccessedAPIType": "NSPrivacyAccessedAPICategoryFileTimestamp", 39 "NSPrivacyAccessedAPITypeReasons": ["C617.1"], 40 }, 41 { 42 "NSPrivacyAccessedAPIType": "NSPrivacyAccessedAPICategoryDiskSpace", 43 "NSPrivacyAccessedAPITypeReasons": ["E174.1"], 44 }, 45 { 46 "NSPrivacyAccessedAPIType": "NSPrivacyAccessedAPICategoryUserDefaults", 47 "NSPrivacyAccessedAPITypeReasons": ["CA92.1"], 48 }, 49 ], 50 } 51 52 53 def validate_manifest(document: dict[str, Any]) -> None: 54 # JSON preserves boolean versus numeric types; Python equality aliases 0 55 # and False and cannot independently validate a privacy declaration. 56 import json 57 58 try: 59 actual = json.dumps(document, sort_keys=True, allow_nan=False) 60 except (TypeError, ValueError) as error: 61 raise ValueError("privacy manifest contains unsupported values") from error 62 if actual != json.dumps(manifest(), sort_keys=True): 63 raise ValueError("privacy manifest differs from implemented public product") 64 65 66 def validate_purposes(document: dict[str, Any]) -> None: 67 if document.get("NSCameraUsageDescription") != CAMERA_PURPOSE: 68 raise ValueError("camera purpose differs from implemented public posting") 69 if document.get("TeraSupportEmail") != SUPPORT_EMAIL: 70 raise ValueError("support contact differs from approved canonical contact")