formats - JSCalendar and jCal Support#
JSCalendar (RFC 8984) anonymization support.
JSCalendar’s JSON shape is structurally different from iCalendar’s flat property model (participants are a map keyed by role flags rather than separate ATTENDEE/ORGANIZER properties, locations are a map rather than a single value, and so on), so this module walks the JSCalendar document directly rather than converting to iCalendar and reusing anonymize().
Converting to iCalendar and back was considered and rejected: verified directly against calendaring-jmap 1.0.0 that its converter silently drops ATTACH/URL/CONFERENCE-equivalent data (links, virtualLocations) in both directions, and loses participant/location changes on individual recurrence-override instances, keeping only title/start/duration/ description (tracked upstream as calendaring-jmap issues #19 and #20). A lossy round trip would delete real user data from anonymized output, not just fail to anonymize it, which is unacceptable for a privacy tool.
- icalendar_anonymizer.formats.jscal.JSCAL_CONFIGURABLE_FIELDS = frozenset({'DESCRIPTION', 'KEYWORDS', 'LINKS', 'LOCATIONS', 'PARTICIPANTS', 'TITLE', 'UID', 'VIRTUALLOCATIONS'})#
Set of JSCalendar field names that can be configured with field_modes.
Contains 8 fields: TITLE, DESCRIPTION, LOCATIONS, PARTICIPANTS, KEYWORDS, LINKS, VIRTUALLOCATIONS, and UID. This is JSCalendar’s own field vocabulary, structurally different from iCalendar’s CONFIGURABLE_FIELDS in _config.py, since JSCalendar’s property shapes differ (participants is one map for both organizer and attendees, locations is a map rather than a single value, and so on).
- icalendar_anonymizer.formats.jscal.validate_jscal_field_modes(field_modes: dict[str, str] | None)[source]#
Validate and normalize a JSCalendar field_modes dict.
Same validation algorithm as _config.validate_field_modes, applied to JSCalendar’s own field vocabulary instead of iCalendar’s.
- Parameters:
field_modes – Dict mapping JSCalendar field name to mode string
- Returns:
Normalized dict with uppercase keys and AnonymizeMode values
- Raises:
ValueError – If invalid field name, invalid mode, or UID set to remove
TypeError – If field_modes is not a dict or None
- icalendar_anonymizer.formats.jscal.anonymize_jscal(data: dict, salt: bytes | None = None, field_modes: dict[str, str] | None = None) dict[source]#
Anonymize a JSCalendar (RFC 8984) document.
Walks the JSCalendar JSON structure directly. Never converts to or from iCalendar, since round-tripping through iCalendar silently drops ATTACH/URL/CONFERENCE-equivalent data and per-instance recurrence override fields (verified against calendaring-jmap 1.0.0, tracked as calendaring-jmap issues #19 and #20).
- Parameters:
data – Parsed JSCalendar document (a dict, e.g. an Event object per RFC 8984, as produced by json.loads()).
salt – Optional salt for hashing. If None, generates random salt.
field_modes – Optional dict mapping JSCalendar field names to anonymization modes. Fields: TITLE, DESCRIPTION, LOCATIONS, PARTICIPANTS, KEYWORDS, LINKS, VIRTUALLOCATIONS, UID. Modes: keep, remove, randomize, replace.
- Returns:
New anonymized JSCalendar document (same dict shape).
- Raises:
TypeError – If data is not a dict, or salt is not bytes.
ValueError – If field_modes contains invalid fields/modes.
jCal (RFC 7265) anonymization support.
jCal is a lossless JSON encoding of iCalendar’s own property model, so anonymization is delegated entirely to the existing anonymize() engine: parse jCal into a Calendar, anonymize unchanged, serialize back to jCal. No jCal-specific anonymization logic exists or is needed.
- icalendar_anonymizer.formats.jcal.anonymize_jcal(data: list, salt: bytes | None = None, field_modes: dict[str, str] | None = None) list[source]#
Anonymize a jCal (RFC 7265) document.
jCal is a direct JSON encoding of iCalendar’s property model, so this reuses the same field names and modes as anonymize() for .ics input (SUMMARY, DESCRIPTION, ATTENDEE, etc.). jCal property names are lowercase per RFC 7265, but anonymize() already treats field names case-insensitively.
- Parameters:
data – Parsed jCal document, e.g. [“vcalendar”, […], […]] as produced by json.loads() of jCal JSON text, or an equivalent Python list structure.
salt – Optional salt for hashing. If None, generates random salt.
field_modes – Optional dict mapping field names to anonymization modes. Same shape and vocabulary as anonymize()’s field_modes.
- Returns:
New anonymized jCal document (same list-of-lists shape).
- Raises:
TypeError – If data is not a list, or salt is not bytes.
ValueError – If data is not a valid jCal document, or field_modes contains invalid fields/modes.