示例#1
0
class MailboxSerializer(serializers.ModelSerializer):
    """Base mailbox serializer."""

    full_address = lib_fields.DRFEmailFieldUTF8()
    quota = serializers.CharField(required=False)

    class Meta:
        model = models.Mailbox
        fields = (
            "pk", "full_address", "use_domain_quota", "quota", "message_limit"
        )

    def validate_full_address(self, value):
        """Lower case address."""
        return value.lower()

    def validate_quota(self, value):
        """Convert quota to MB."""
        return web_utils.size2integer(value, output_unit="MB")

    def validate(self, data):
        """Check if quota is required."""
        method = self.context["request"].method
        if not data.get("use_domain_quota", False):
            if "quota" not in data and method != "PATCH":
                raise serializers.ValidationError({
                    "quota": _("This field is required")
                })
        return data
示例#2
0
class AccountSerializer(v1_serializers.AccountSerializer):
    """Add support for user resources."""

    aliases = serializers.ListField(child=lib_fields.DRFEmailFieldUTF8(),
                                    source="mailbox.alias_addresses")

    class Meta(v1_serializers.AccountSerializer.Meta):
        fields = (v1_serializers.AccountSerializer.Meta.fields + ("aliases", ))

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if not param_tools.get_global_parameter("enable_admin_limits",
                                                app="limits"):
            return
        self.fields["resources"] = serializers.SerializerMethodField()

    def get_resources(self, account) -> List[AccountResourceSerializer]:
        if account.role == 'SimpleUsers':
            return []
        resources = []
        for limit in account.userobjectlimit_set.all():
            tpl = limits_constants.DEFAULT_USER_LIMITS[limit.name]
            if "required_role" in tpl:
                if account.role != tpl["required_role"]:
                    continue
            resources.append(limit)
        return AccountResourceSerializer(resources, many=True).data
示例#3
0
class MailboxSerializer(serializers.ModelSerializer):
    """Base mailbox serializer."""

    full_address = lib_fields.DRFEmailFieldUTF8()

    class Meta:
        model = models.Mailbox
        fields = ("full_address", "use_domain_quota", "quota", )
示例#4
0
class MailboxSerializer(serializers.ModelSerializer):
    """Mailbox serializer."""

    pk = serializers.IntegerField()
    full_address = lib_fields.DRFEmailFieldUTF8()

    class Meta:
        model = admin_models.Mailbox
        fields = ("pk", "full_address")
        read_only_fields = (
            "pk",
            "full_address",
        )
示例#5
0
class MailboxSerializer(serializers.ModelSerializer):
    """Base mailbox serializer."""

    full_address = lib_fields.DRFEmailFieldUTF8()

    class Meta:
        model = models.Mailbox
        fields = (
            "pk",
            "full_address",
            "use_domain_quota",
            "quota",
        )

    def validate_full_address(self, value):
        """Lower case address."""
        return value.lower()
示例#6
0
class MailboxSerializer(serializers.ModelSerializer):
    """Base mailbox serializer."""

    full_address = lib_fields.DRFEmailFieldUTF8()
    quota = serializers.CharField()

    class Meta:
        model = models.Mailbox
        fields = ("pk", "full_address", "use_domain_quota", "quota", )

    def validate_full_address(self, value):
        """Lower case address."""
        return value.lower()

    def validate_quota(self, value):
        """Convert quota to MB."""
        return web_utils.size2integer(value, output_unit="MB")
示例#7
0
class ResetPasswordSerializer(serializers.Serializer):
    """Serializer by the reset password endpoint."""

    email = lib_fields.DRFEmailFieldUTF8()
示例#8
0
class WritableAccountSerializer(v1_serializers.WritableAccountSerializer):
    """Add support for aliases and sender addresses."""

    aliases = serializers.ListField(child=lib_fields.DRFEmailFieldUTF8(),
                                    required=False)
    mailbox = MailboxSerializer(required=False)

    class Meta(v1_serializers.WritableAccountSerializer.Meta):
        fields = tuple(
            field
            for field in v1_serializers.WritableAccountSerializer.Meta.fields
            if field != "random_password") + ("aliases", )

    def validate_aliases(self, value):
        """Check if required domains are locals and user can access them."""
        aliases = []
        for alias in value:
            localpart, domain = models.validate_alias_address(
                alias, self.context["request"].user)
            aliases.append({"localpart": localpart, "domain": domain})
        return aliases

    def validate(self, data):
        """Check constraints."""
        master_user = data.get("master_user", False)
        role = data.get("role")
        if master_user and role != "SuperAdmins":
            raise serializers.ValidationError(
                {"master_user": _("Not allowed for this role.")})
        if role == "SimpleUsers":
            username = data.get("username")
            if username:
                try:
                    validators.UTF8EmailValidator()(username)
                except ValidationError as err:
                    raise ValidationError({"username": err.message})
            mailbox = data.get("mailbox")
            if mailbox is None:
                if not self.instance:
                    data["mailbox"] = {"use_domain_quota": True}
        if data.get("password") or not self.partial:
            password = data.get("password")
            if password:
                try:
                    password_validation.validate_password(
                        data["password"], self.instance)
                except ValidationError as exc:
                    raise serializers.ValidationError(
                        {"password": exc.messages[0]})
            elif not self.instance:
                raise serializers.ValidationError(
                    {"password": _("This field is required.")})
        aliases = data.get("aliases")
        if aliases and "mailbox" not in data:
            raise serializers.ValidationError(
                {"aliases": _("A mailbox is required to create aliases.")})
        domain_names = data.get("domains")
        if not domain_names:
            return data
        domains = []
        for name in domain_names:
            domain = models.Domain.objects.filter(name=name).first()
            if domain:
                domains.append(domain)
                continue
            raise serializers.ValidationError(
                {"domains": _("Local domain {} does not exist").format(name)})
        data["domains"] = domains
        return data

    def create(self, validated_data):
        """Create account, mailbox and aliases."""
        creator = self.context["request"].user
        mailbox_data = validated_data.pop("mailbox", None)
        role = validated_data.pop("role")
        domains = validated_data.pop("domains", [])
        aliases = validated_data.pop("aliases", None)
        user = core_models.User(**validated_data)
        password = validated_data.pop("password")
        user.set_password(password)
        if "language" not in validated_data:
            user.language = settings.LANGUAGE_CODE
        user.save(creator=creator)
        if mailbox_data:
            mailbox_data["full_address"] = user.username
            self._create_mailbox(creator, user, mailbox_data)
        user.role = role
        self.set_permissions(user, domains)
        if aliases:
            for alias in aliases:
                models.Alias.objects.create(creator=creator,
                                            domain=alias["domain"],
                                            address="{}@{}".format(
                                                alias["localpart"],
                                                alias["domain"]),
                                            recipients=[user.username])
        return user
示例#9
0
class CoreGlobalParametersSerializer(serializers.Serializer):
    """A serializer for global parameters."""

    # General settings
    authentication_type = serializers.ChoiceField(
        choices=[("local", ugettext_lazy("Local")),
                 ("ldap", "LDAP")],
        default="local"
    )
    password_scheme = serializers.ChoiceField(
        choices=[("sha512crypt", "sha512crypt"),
                 ("sha256crypt", "sha256crypt"),
                 ("blfcrypt", "bcrypt"),
                 ("md5crypt", ugettext_lazy("md5crypt (weak)")),
                 ("sha256", ugettext_lazy("sha256 (weak)")),
                 ("md5", ugettext_lazy("md5 (weak)")),
                 ("crypt", ugettext_lazy("crypt (weak)")),
                 ("plain", ugettext_lazy("plain (weak)"))],
        default="sha512crypt"
    )
    rounds_number = serializers.IntegerField(default=70000)
    update_scheme = serializers.BooleanField(default=True)
    default_password = serializers.CharField(default="password")
    random_password_length = serializers.IntegerField(min_value=8, default=8)
    update_password_url = serializers.URLField(required=False, allow_blank=True)
    password_recovery_msg = serializers.CharField(
        required=False, allow_blank=True)
    sms_password_recovery = serializers.BooleanField(default=False)
    sms_provider = serializers.ChoiceField(
        choices=constants.SMS_BACKENDS, required=False)

    # LDAP settings
    ldap_server_address = serializers.CharField(default="localhost")
    ldap_server_port = serializers.IntegerField(default=389)
    ldap_enable_secondary_server = serializers.BooleanField(default=False)
    ldap_secondary_server_address = serializers.CharField(required=False)
    ldap_secondary_server_port = serializers.IntegerField(
        default=389, required=False)
    ldap_secured = serializers.ChoiceField(
        choices=constants.LDAP_SECURE_MODES,
        default="none"
    )
    ldap_is_active_directory = serializers.BooleanField(default=False)
    ldap_admin_groups = serializers.CharField(
        default="", required=False, allow_blank=True)
    ldap_group_type = serializers.ChoiceField(
        default="posixgroup",
        choices=constants.LDAP_GROUP_TYPES
    )
    ldap_groups_search_base = serializers.CharField(
        default="", required=False, allow_blank=True)
    ldap_password_attribute = serializers.CharField(default="userPassword")

    # LDAP auth settings
    ldap_auth_method = serializers.ChoiceField(
        choices=constants.LDAP_AUTH_METHODS,
        default="searchbind",
    )
    ldap_bind_dn = serializers.CharField(
        default="", required=False, allow_blank=True)
    ldap_bind_password = serializers.CharField(
        default="", required=False, allow_blank=True)
    ldap_search_base = serializers.CharField(
        default="", required=False, allow_blank=True)
    ldap_search_filter = serializers.CharField(
        default="(mail=%(user)s)", required=False,
        allow_blank=True)
    ldap_user_dn_template = serializers.CharField(
        default="", required=False, allow_blank=True)

    # LDAP sync settings
    ldap_sync_bind_dn = serializers.CharField(required=False, allow_blank=True)
    ldap_sync_bind_password = serializers.CharField(
        required=False, allow_blank=True)
    ldap_enable_sync = serializers.BooleanField(default=False)
    ldap_sync_delete_remote_account = serializers.BooleanField(default=False)
    ldap_sync_account_dn_template = serializers.CharField(
        required=False, allow_blank=True)
    ldap_enable_import = serializers.BooleanField(default=False)
    ldap_import_search_base = serializers.CharField(
        required=False, allow_blank=True)
    ldap_import_search_filter = serializers.CharField(
        default="(cn=*)", required=False
    )
    ldap_import_username_attr = serializers.CharField(default="cn")
    ldap_dovecot_sync = serializers.BooleanField(default=False)
    ldap_dovecot_conf_file = serializers.CharField(
        default="/etc/dovecot/dovecot-modoboa.conf", required=False
    )

    # Dashboard settings
    rss_feed_url = serializers.URLField(allow_blank=True)
    hide_features_widget = serializers.BooleanField(default=False)

    # Notification settings
    sender_address = lib_fields.DRFEmailFieldUTF8(
        default="*****@*****.**")

    # API settings
    enable_api_communication = serializers.BooleanField(default=True)
    check_new_versions = serializers.BooleanField(default=True)
    send_new_versions_email = serializers.BooleanField(default=False)
    new_versions_email_rcpt = lib_fields.DRFEmailFieldUTF8(required=False)
    send_statistics = serializers.BooleanField(default=True)

    # Misc settings
    inactive_account_threshold = serializers.IntegerField(default=30)
    top_notifications_check_interval = serializers.IntegerField(default=30)
    log_maximum_age = serializers.IntegerField(default=365)
    items_per_page = serializers.IntegerField(default=30)
    default_top_redirection = serializers.ChoiceField(
        default="user", choices=[""])

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        sms_backend_fields = sms_backends.get_all_backend_serializer_settings()
        for field, definition in sms_backend_fields.items():
            self.fields[field] = definition["type"](
                **definition["attrs"])

    def validate_ldap_user_dn_template(self, value):
        try:
            value % {"user": "******"}
        except (KeyError, ValueError):
            raise serializers.ValidationError(_("Invalid syntax"))
        return value

    def validate_ldap_sync_account_dn_template(self, value):
        try:
            value % {"user": "******"}
        except (KeyError, ValueError):
            raise serializers.ValidationError(_("Invalid syntax"))
        return value

    def validate_ldap_search_filter(self, value):
        try:
            value % {"user": "******"}
        except (KeyError, ValueError, TypeError):
            raise serializers.ValidationError(_("Invalid syntax"))
        return value

    def validate_rounds_number(self, value):
        if value < 1000 or value > 999999999:
            raise serializers.ValidationError(_("Invalid rounds number"))
        return value

    def validate_default_password(self, value):
        """Check password complexity."""
        password_validation.validate_password(value)
        return value

    def validate(self, data):
        """Custom validation method

        Depending on 'ldap_auth_method' value, we check for different
        required parameters.
        """
        errors = {}
        if data["sms_password_recovery"]:
            provider = data.get("sms_provider")
            if provider:
                sms_settings = sms_backends.get_backend_settings(provider)
                if sms_settings:
                    for name in sms_settings.keys():
                        if not data.get(name):
                            errors[name] = _("This field is required")
            else:
                errors["sms_provider"] = _("This field is required")

        if data["authentication_type"] == "ldap":
            if data["ldap_auth_method"] == "searchbind":
                required_fields = ["ldap_search_base", "ldap_search_filter"]
            else:
                required_fields = ["ldap_user_dn_template"]
            for f in required_fields:
                if data.get(f, "") == "":
                    errors[f] = _("This field is required")
        if len(errors):
            raise serializers.ValidationError(errors)
        return data
示例#10
0
class WritableAccountSerializer(v1_serializers.WritableAccountSerializer):
    """Add support for aliases and sender addresses."""

    aliases = serializers.ListField(child=lib_fields.DRFEmailFieldUTF8(),
                                    required=False)
    mailbox = MailboxSerializer(required=False)

    class Meta(v1_serializers.WritableAccountSerializer.Meta):
        fields = tuple(
            field
            for field in v1_serializers.WritableAccountSerializer.Meta.fields
            if field != "random_password") + ("aliases", )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if not param_tools.get_global_parameter("enable_admin_limits",
                                                app="limits"):
            return
        self.fields["resources"] = WritableResourceSerializer(many=True,
                                                              required=False)

    def validate_aliases(self, value):
        """Check if required domains are locals and user can access them."""
        aliases = []
        for alias in value:
            localpart, domain = models.validate_alias_address(
                alias, self.context["request"].user)
            aliases.append({"localpart": localpart, "domain": domain})
        return aliases

    def validate(self, data):
        """Check constraints."""
        master_user = data.get("master_user", False)
        role = data.get("role")
        if master_user and role != "SuperAdmins":
            raise serializers.ValidationError(
                {"master_user": _("Not allowed for this role.")})
        if role == "SimpleUsers":
            username = data.get("username")
            if username:
                try:
                    validators.UTF8EmailValidator()(username)
                except ValidationError as err:
                    raise ValidationError({"username": err.message})
            mailbox = data.get("mailbox")
            if mailbox is None:
                if not self.instance:
                    data["mailbox"] = {"use_domain_quota": True}
        if "mailbox" in data and "username" in data:
            self.address, domain_name = email_utils.split_mailbox(
                data["username"])
            self.domain = get_object_or_404(models.Domain, name=domain_name)
            creator = self.context["request"].user
            if not creator.can_access(self.domain):
                raise serializers.ValidationError(
                    {"mailbox": _("Permission denied.")})
            if not self.instance:
                try:
                    core_signals.can_create_object.send(sender=self.__class__,
                                                        context=creator,
                                                        klass=models.Mailbox)
                    core_signals.can_create_object.send(
                        sender=self.__class__,
                        context=self.domain,
                        object_type="mailboxes")
                except lib_exceptions.ModoboaException as inst:
                    raise serializers.ValidationError({"mailbox": str(inst)})
        if data.get("password") or not self.partial:
            password = data.get("password")
            if password:
                try:
                    password_validation.validate_password(
                        data["password"], self.instance)
                except ValidationError as exc:
                    raise serializers.ValidationError(
                        {"password": exc.messages[0]})
            elif not self.instance:
                raise serializers.ValidationError(
                    {"password": _("This field is required.")})
        aliases = data.get("aliases")
        if aliases and "mailbox" not in data:
            raise serializers.ValidationError(
                {"aliases": _("A mailbox is required to create aliases.")})
        domain_names = data.get("domains")
        if not domain_names:
            return data
        domains = []
        for name in domain_names:
            domain = models.Domain.objects.filter(name=name).first()
            if domain:
                domains.append(domain)
                continue
            raise serializers.ValidationError(
                {"domains": _("Local domain {} does not exist").format(name)})
        data["domains"] = domains
        return data

    def create(self, validated_data):
        """Create account, mailbox and aliases."""
        creator = self.context["request"].user
        mailbox_data = validated_data.pop("mailbox", None)
        role = validated_data.pop("role")
        domains = validated_data.pop("domains", [])
        aliases = validated_data.pop("aliases", None)
        user = core_models.User(**validated_data)
        password = validated_data.pop("password")
        user.set_password(password)
        if "language" not in validated_data:
            user.language = settings.LANGUAGE_CODE
        user.save(creator=creator)
        if mailbox_data:
            mailbox_data["full_address"] = user.username
            self._create_mailbox(creator, user, mailbox_data)
        user.role = role
        self.set_permissions(user, domains)
        if aliases:
            for alias in aliases:
                models.Alias.objects.create(creator=creator,
                                            domain=alias["domain"],
                                            address="{}@{}".format(
                                                alias["localpart"],
                                                alias["domain"]),
                                            recipients=[user.username])
        return user

    def update(self, instance, validated_data):
        """Update account and associated objects."""
        mailbox_data = validated_data.pop("mailbox", None)
        password = validated_data.pop("password", None)
        domains = validated_data.pop("domains", [])
        for key, value in validated_data.items():
            setattr(instance, key, value)
        if password:
            instance.set_password(password)
        if mailbox_data:
            creator = self.context["request"].user
            if hasattr(instance, "mailbox"):
                if "username" in validated_data:
                    mailbox_data["email"] = validated_data["username"]
                    instance.email = validated_data["username"]
                instance.mailbox.update_from_dict(creator, mailbox_data)
            elif "username" in validated_data:
                mailbox_data["full_address"] = validated_data["username"]
                instance.email = validated_data["username"]
                self._create_mailbox(creator, instance, mailbox_data)
        instance.save()
        resources = validated_data.get("resources")
        if resources:
            for resource in resources:
                instance.userobjectlimit_set.filter(
                    name=resource["name"]).update(
                        max_value=resource["max_value"])
        self.set_permissions(instance, domains)
        return instance