class DeviceFileSchema(LegacyDeviceFileSchema): """Schema for device files that does not rely on the filename for complementary information.""" # Override those fields to make them required (although `None` is still valid) human_handle = HumanHandleField(required=True, allow_none=True) device_label = fields.String(required=True, allow_none=True) # Store device ID, organization ID and slug in the device file # For legacy versions, this information is available in the file name device_id = DeviceIDField(required=True) organization_id = OrganizationIDField(required=True) slug = fields.String(required=True)
class SCHEMA_CLS(BaseSchema): organization_addr = BackendOrganizationAddrField(required=True) device_id = DeviceIDField(required=True) device_label = fields.String(allow_none=True, missing=None) human_handle = HumanHandleField(allow_none=True, missing=None) signing_key = fields.SigningKey(required=True) private_key = fields.PrivateKey(required=True) # `profile` replaces `is_admin` field (which is still required for backward # compatibility), hence `None` is not allowed is_admin = fields.Boolean(required=True) profile = UserProfileField(allow_none=False) user_manifest_id = EntryIDField(required=True) user_manifest_key = fields.SecretKey(required=True) local_symkey = fields.SecretKey(required=True) @post_load def make_obj(self, data): # Handle legacy `is_admin` field default_profile = UserProfile.ADMIN if data.pop( "is_admin") else UserProfile.STANDARD try: profile = data["profile"] except KeyError: data["profile"] = default_profile else: if default_profile == UserProfile.ADMIN and profile != UserProfile.ADMIN: raise ValidationError( "Fields `profile` and `is_admin` have incompatible values" ) return LocalDevice(**data)
class HumanFindReqSchema(BaseReqSchema): query = fields.String(required=True, allow_none=True) omit_revoked = fields.Boolean(required=True) omit_non_human = fields.Boolean(required=True) # First page is 1 page = fields.Int(required=True, validate=lambda n: n > 0) per_page = fields.Integer(required=True, validate=lambda n: 0 < n <= 100)
class OrganizationBootstrapReqSchema(BaseReqSchema): bootstrap_token = fields.String(required=True) root_verify_key = fields.VerifyKey(required=True) user_certificate = fields.Bytes(required=True) device_certificate = fields.Bytes(required=True) redacted_user_certificate = fields.Bytes(required=True) redacted_device_certificate = fields.Bytes(required=True)
class UserClaimSchema(UnknownCheckedSchema): type = fields.CheckedConstant("user_claim", required=True) token = fields.String(required=True) # Note claiming user also imply creating a first device device_id = fields.DeviceID(required=True) public_key = fields.PublicKey(required=True) verify_key = fields.VerifyKey(required=True)
class SCHEMA_CLS(BaseSignedDataSchema): type = fields.CheckedConstant("ping", required=True) ping = fields.String(required=True) @post_load def make_obj(self, data): data.pop("type") return PingMessageContent(**data)
class MessageReceivedSchema(BaseSchema): __id__ = fields.String(required=True) __signal__ = fields.EnumCheckedConstant(BackendEvent.MESSAGE_RECEIVED, required=True) organization_id = OrganizationIDField(required=True) author = DeviceIDField(required=True) recipient = UserIDField(required=True) index = fields.Integer(required=True)
class RealmMaintenanceStartedSchema(BaseSchema): __id__ = fields.String(required=True) __signal__ = fields.EnumCheckedConstant( BackendEvent.REALM_MAINTENANCE_STARTED, required=True) organization_id = OrganizationIDField(required=True) author = DeviceIDField(required=True) realm_id = RealmIDField(required=True) encryption_revision = fields.Integer(required=True)
class DeviceCreatedSchema(BaseSchema): __id__ = fields.String(required=True) __signal__ = fields.EnumCheckedConstant(BackendEvent.DEVICE_CREATED, required=True) organization_id = OrganizationIDField(required=True) device_id = DeviceIDField(required=True) device_certificate = fields.Bytes(required=True) encrypted_answer = fields.Bytes(required=True)
class InviteStatusChangedSchema(BaseSchema): __id__ = fields.String(required=True) __signal__ = fields.EnumCheckedConstant(BackendEvent.INVITE_STATUS_CHANGED, required=True) organization_id = OrganizationIDField(required=True) greeter = UserIDField(required=True) token = InvitationTokenField(required=True) status = InvitationStatusField(required=True)
class UserCreatedSchema(BaseSchema): __id__ = fields.String(required=True) __signal__ = fields.EnumCheckedConstant(BackendEvent.USER_CREATED, required=True) organization_id = OrganizationIDField(required=True) user_id = UserIDField(required=True) user_certificate = fields.Bytes(required=True) first_device_id = DeviceIDField(required=True) first_device_certificate = fields.Bytes(required=True)
class RealmRolesUpdatedSchema(BaseSchema): __id__ = fields.String(required=True) __signal__ = fields.EnumCheckedConstant(BackendEvent.REALM_ROLES_UPDATED, required=True) organization_id = OrganizationIDField(required=True) author = DeviceIDField(required=True) realm_id = RealmIDField(required=True) user = UserIDField(required=True) role = RealmRoleField(required=True, allow_none=True)
class RealmVlobsUpdatedSchema(BaseSchema): __id__ = fields.String(required=True) __signal__ = fields.EnumCheckedConstant(BackendEvent.REALM_VLOBS_UPDATED, required=True) organization_id = OrganizationIDField(required=True) author = DeviceIDField(required=True) realm_id = RealmIDField(required=True) checkpoint = fields.Integer(required=True) src_id = VlobIDField(required=True) src_version = fields.Integer(required=True)
class SCHEMA_CLS(BaseSchema): type = fields.CheckedConstant("invite_device_data", required=True) # Claimer ask for device_label, but greeter has final word on this requested_device_label = fields.String(allow_none=True, missing=None) verify_key = fields.VerifyKey(required=True) @post_load def make_obj(self, data): data.pop("type") return InviteDeviceData(**data)
class SCHEMA_CLS(BaseSchema): type = fields.CheckedConstant("device_claim", required=True) token = fields.String(required=True) device_id = DeviceIDField(required=True) verify_key = fields.VerifyKey(required=True) answer_public_key = fields.PublicKey(required=True) @post_load def make_obj(self, data): data.pop("type") return DeviceClaimContent(**data)
class UserSchema(UnknownCheckedSchema): user_id = fields.String(required=True) is_admin = fields.Boolean(required=True) created_on = fields.DateTime(required=True) certified_user = fields.Bytes(required=True) user_certifier = fields.DeviceID(allow_none=True) devices = fields.Map(fields.DeviceName(), fields.Nested(DeviceSchema), required=True)
class SCHEMA_CLS(BaseSignedDataSchema): type = fields.CheckedConstant("device_certificate", required=True) device_id = DeviceIDField(required=True) verify_key = fields.VerifyKey(required=True) # Device label can be none in case of redacted certificate device_label = fields.String(allow_none=True, missing=None) @post_load def make_obj(self, data): data.pop("type") return DeviceCertificateContent(**data)
class DeviceFileSchema(BaseSchema): type = fields.CheckedConstant("password", required=True) salt = fields.Bytes(required=True) ciphertext = fields.Bytes(required=True) # Since human_handle/device_label has been introduced, device_id is # redacted (i.e. user_id and device_name are 2 random uuids), hence # those fields have been added to the device file so the login page in # the GUI can use them to provide useful information. human_handle = HumanHandleField(allow_none=True, missing=None) device_label = fields.String(allow_none=True, missing=None)
class BaseReqSchema(UnknownCheckedSchema): cmd = fields.String(required=True) @post_load def _drop_cmd_field(self, item): if self.drop_cmd_field: item.pop("cmd") return item def __init__(self, drop_cmd_field=True, **kwargs): super().__init__(**kwargs) self.drop_cmd_field = drop_cmd_field
class SCHEMA_CLS(BaseSchema): type = fields.CheckedConstant("user_claim", required=True) token = fields.String(required=True) # Note claiming user also imply creating a first device device_id = DeviceIDField(required=True) public_key = fields.PublicKey(required=True) verify_key = fields.VerifyKey(required=True) @post_load def make_obj(self, data: Dict[str, Any]) -> "APIV1_UserClaimContent": # type: ignore[misc] data.pop("type") return APIV1_UserClaimContent(**data)
class BaseReqSchema(BaseSchema): cmd = fields.String(required=True) @post_load def _drop_cmd_field(self, item: Dict[str, T]) -> Dict[str, T]: # type: ignore[misc] if self.drop_cmd_field: item.pop("cmd") return item def __init__(self, drop_cmd_field: bool = True, **kwargs: object): super().__init__(**kwargs) self.drop_cmd_field = drop_cmd_field
class SCHEMA_CLS(BaseSignedDataSchema): type = fields.EnumCheckedConstant(MessageContentType.PING, required=True) ping = fields.String(required=True) @post_load def make_obj( self, data: Dict[str, Any]) -> "PingMessageContent": # type: ignore[misc] data.pop("type") return PingMessageContent(**data)
class SCHEMA_CLS(BaseSchema): type = fields.CheckedConstant("invite_user_confirmation", required=True) device_id = DeviceIDField(required=True) device_label = fields.String(allow_none=True, missing=None) human_handle = HumanHandleField(allow_none=True, missing=None) profile = UserProfileField(required=True) root_verify_key = fields.VerifyKey(required=True) @post_load def make_obj(self, data): data.pop("type") return InviteUserConfirmation(**data)
class SCHEMA_CLS(BaseSchema): type = fields.CheckedConstant("x509_certificate", required=True) issuer = fields.Dict(required=True) subject = fields.Dict(required=True) der_x509_certificate = fields.Bytes(required=True) certificate_sha1 = fields.Bytes(required=True) certificate_id = fields.String(required=True, allow_none=True) @post_load def make_obj(self, data): data.pop("type", None) return X509Certificate(**data)
class SCHEMA_CLS(BaseSchema): type = fields.CheckedConstant("device_claim", required=True) token = fields.String(required=True) device_id = DeviceIDField(required=True) verify_key = fields.VerifyKey(required=True) answer_public_key = fields.PublicKey(required=True) @post_load def make_obj( # type: ignore[misc] self, data: Dict[str, Any] ) -> "APIV1_DeviceClaimContent": data.pop("type") return APIV1_DeviceClaimContent(**data)
class SCHEMA_CLS(BaseSchema): type = fields.CheckedConstant("invite_user_data", required=True) # Claimer ask for device_label/human_handle, but greeter has final word on this requested_device_label = fields.String(allow_none=True, missing=None) requested_human_handle = HumanHandleField(allow_none=True, missing=None) # Note claiming user also imply creating a first device public_key = fields.PublicKey(required=True) verify_key = fields.VerifyKey(required=True) @post_load def make_obj(self, data): data.pop("type") return InviteUserData(**data)
class ApiReleaseSchema(BaseSchema): draft = fields.Boolean(missing=False) prerelease = fields.Boolean(missing=False) tag_name = fields.String(required=True) assets = fields.List(fields.Nested(ApiReleaseAssetSchema), missing=[]) @post_load def add_version_field(self, data): try: data["version"] = Version(data["tag_name"]) except ValueError: data["version"] = None return data
class SCHEMA_CLS(BaseSignedDataSchema): # Override author field to allow for None value if signed by the root key author = DeviceIDField(required=True, allow_none=True) type = fields.CheckedConstant("device_certificate", required=True) device_id = DeviceIDField(required=True) # Device label can be none in case of redacted certificate device_label = fields.String(allow_none=True, missing=None) verify_key = fields.VerifyKey(required=True) @post_load def make_obj(self, data: Dict[str, Any]) -> "DeviceCertificateContent": data.pop("type") return DeviceCertificateContent(**data)
class PkiEnrollmentSubmitReqSchema(BaseReqSchema): enrollment_id = fields.UUID(required=True) # Existing enrollment with SUMBITTED status prevent submitting new # enrollment with similir x509 certificate unless force flag is set. force = fields.Boolean(required=True) submitter_der_x509_certificate = fields.Bytes(required=True) # Duplicated certificate email field. (The backend need to check if the email is used without loading the certificate) submitter_der_x509_certificate_email = fields.String(required=False, missing=None, allow_none=True) submit_payload_signature = fields.Bytes(required=True) submit_payload = fields.Bytes( required=True) # Signature should be checked before loading
class APIV1_OrganizationBootstrapReqSchema(BaseReqSchema): bootstrap_token = fields.String(required=True) root_verify_key = fields.VerifyKey(required=True) user_certificate = fields.Bytes(required=True) device_certificate = fields.Bytes(required=True) # Same certificates than above, but expurged of human_handle/device_label # Backward compatibility prevent those field to be required, however # they should be considered so by recent version of Parsec (hence the # `allow_none=False`). # Hence only old version of Parsec will provide a payload with missing # redacted fields. In such case we consider the non-redacted can also # be used as redacted given the to-be-redacted fields have been introduce # in later version of Parsec. redacted_user_certificate = fields.Bytes(allow_none=False) redacted_device_certificate = fields.Bytes(allow_none=False)