pypush-plus-plus/icloud/cloudkit.py

65 lines
2.8 KiB
Python
Raw Normal View History

2023-10-22 00:39:40 +00:00
from typing import Literal
from . import cloudkit_pb2
2023-10-21 19:53:13 +00:00
import uuid
2023-10-22 00:39:40 +00:00
import dataclasses
import typing
2023-10-21 19:53:13 +00:00
2023-10-22 00:39:40 +00:00
@dataclasses.dataclass
class Record:
name: uuid.UUID
type: str
fields: dict[str, typing.Any]
2023-10-21 19:53:13 +00:00
2023-10-22 00:39:40 +00:00
def build_record_save_request(
record: Record,
container: str,
sandbox: bool = False,
database: Literal["PUBLIC"] | Literal["PRIVATE"] | Literal["SHARED"] = "PUBLIC",
zone: str = "_defaultZone",
owner: str = "_defaultOwner",
):
MAGIC_BYTES = b"\xfe\x03"
2023-10-21 19:53:13 +00:00
2023-10-22 00:39:40 +00:00
hardware_id = uuid.uuid4() # Generate a new hardware ID for each request?
operation_uuid = uuid.uuid4() # Generate a new operation UUID for each request?
record_id = uuid.uuid4() # Generate a new record ID for each request?
2023-10-21 19:53:13 +00:00
2023-10-22 00:39:40 +00:00
request = cloudkit_pb2.RequestOperation()
request.header.applicationContainer = container
request.header.applicationContainerEnvironment = cloudkit_pb2.RequestOperation.Header.ContainerEnvironment.SANDBOX if sandbox else cloudkit_pb2.RequestOperation.Header.ContainerEnvironment.PRODUCTION
2023-10-21 19:53:13 +00:00
2023-10-22 00:39:40 +00:00
request.header.deviceHardwareID = str(hardware_id).upper()
2023-10-21 19:53:13 +00:00
2023-10-22 00:39:40 +00:00
if database == "PUBLIC":
request.header.targetDatabase = cloudkit_pb2.RequestOperation.Header.Database.PUBLIC_DB
elif database == "PRIVATE":
request.header.targetDatabase = cloudkit_pb2.RequestOperation.Header.Database.PRIVATE_DB
elif database == "SHARED":
request.header.targetDatabase = cloudkit_pb2.RequestOperation.Header.Database.SHARED_DB
2023-10-21 19:53:13 +00:00
2023-10-22 00:39:40 +00:00
request.header.isolationLevel = cloudkit_pb2.RequestOperation.Header.IsolationLevel.ZONE
2023-10-21 19:53:13 +00:00
2023-10-22 00:39:40 +00:00
request.request.operationUUID = str(operation_uuid).upper()
request.request.type = cloudkit_pb2.Operation.Type.RECORD_SAVE_TYPE
request.request.last = True
2023-10-21 19:53:13 +00:00
2023-10-22 00:39:40 +00:00
request.recordSaveRequest.record.recordIdentifier.value.name = str(record_id).upper()
request.recordSaveRequest.record.recordIdentifier.value.type = cloudkit_pb2.Identifier.Type.RECORD
2023-10-21 19:53:13 +00:00
2023-10-22 00:39:40 +00:00
request.recordSaveRequest.record.recordIdentifier.zoneIdentifier.value.name = zone
request.recordSaveRequest.record.recordIdentifier.zoneIdentifier.value.type = cloudkit_pb2.Identifier.Type.RECORD_ZONE
2023-10-21 19:53:13 +00:00
2023-10-22 00:39:40 +00:00
request.recordSaveRequest.record.recordIdentifier.zoneIdentifier.ownerIdentifier.name = owner
request.recordSaveRequest.record.recordIdentifier.zoneIdentifier.ownerIdentifier.type = cloudkit_pb2.Identifier.Type.USER
2023-10-21 19:53:13 +00:00
2023-10-22 00:39:40 +00:00
request.recordSaveRequest.record.type.name = record.type
2023-10-21 19:53:13 +00:00
2023-10-22 00:39:40 +00:00
for key, value in record.fields.items():
request.recordSaveRequest.record.recordField.append(cloudkit_pb2.Record.Field())
request.recordSaveRequest.record.recordField[-1].identifier.name = key
request.recordSaveRequest.record.recordField[-1].value.type = cloudkit_pb2.Record.Field.Value.Type.STRING_TYPE
request.recordSaveRequest.record.recordField[-1].value.stringValue = value
2023-10-21 19:53:13 +00:00
2023-10-22 00:39:40 +00:00
return MAGIC_BYTES + request.SerializeToString()