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 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("user_certificate", required=True) user_id = UserIDField(required=True) # Human handle can be none in case of redacted certificate human_handle = HumanHandleField(allow_none=True, missing=None) public_key = fields.PublicKey(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) @post_load def make_obj(self, data: Dict[str, Any]) -> "UserCertificateContent": data.pop("type") # 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 UserCertificateContent(**data)
class SCHEMA_CLS(BaseSignedDataSchema): type = fields.CheckedConstant("user_certificate", required=True) user_id = UserIDField(required=True) public_key = fields.PublicKey(required=True) is_admin = fields.Boolean(required=True) human_handle = HumanHandleField(allow_none=True, missing=None) @post_load def make_obj(self, data): data.pop("type") return UserCertificateContent(**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 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): 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("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 SCHEMA_CLS(BaseSchema): type = fields.CheckedConstant("pki_enrollment_answer_payload", required=True) device_id = DeviceIDField(required=True) device_label = DeviceLabelField(allow_none=True, required=True) human_handle = HumanHandleField(allow_none=True, required=True) profile = UserProfileField(required=True) root_verify_key = fields.VerifyKey(required=True) @post_load def make_obj(self, data: Dict[str, Any]) -> "PkiEnrollmentAcceptPayload": data.pop("type") return PkiEnrollmentAcceptPayload(**data)
class SCHEMA_CLS(BaseSchema): organization_addr = BackendOrganizationAddrField(required=True) device_id = DeviceIDField(required=True) signing_key = fields.SigningKey(required=True) private_key = fields.PrivateKey(required=True) is_admin = fields.Boolean(required=True) user_manifest_id = EntryIDField(required=True) user_manifest_key = fields.SecretKey(required=True) local_symkey = fields.SecretKey(required=True) human_handle = HumanHandleField(allow_none=True, missing=None) @post_load def make_obj(self, data): return LocalDevice(**data)
class SCHEMA_CLS(BaseSchema): type = fields.CheckedConstant("invite_user_confirmation", required=True) device_id = DeviceIDField(required=True) device_label = DeviceLabelField(required=True, allow_none=True) human_handle = HumanHandleField(required=True, allow_none=True) profile = UserProfileField(required=True) root_verify_key = fields.VerifyKey(required=True) @post_load def make_obj( self, data: Dict[str, Any] ) -> "InviteUserConfirmation": # type: ignore[misc] data.pop("type") return InviteUserConfirmation(**data)
class SCHEMA_CLS(BaseSchema): type = fields.CheckedConstant("invite_device_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) private_key = fields.PrivateKey(required=True) user_manifest_id = EntryIDField(required=True) user_manifest_key = fields.SecretKey(required=True) root_verify_key = fields.VerifyKey(required=True) @post_load def make_obj( # type: ignore[misc] self, data: Dict[str, Any]) -> "InviteDeviceConfirmation": data.pop("type") return InviteDeviceConfirmation(**data)
class LegacyDeviceFileSchema(BaseSchema): """Schema for legacy device files where the filename contains complementary information.""" type = fields.EnumCheckedConstant(DeviceFileType.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. # Added in Parsec v1.14 human_handle = HumanHandleField(required=False, allow_none=True, missing=None) # Added in Parsec v1.14 device_label = DeviceLabelField(required=False, allow_none=True, missing=None)