field_ios

In-the-field app for Radroots on iOS
git clone https://radroots.dev/git/field_ios.git
Log | Files | Refs | README | LICENSE

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")