Files
jumpserver/apps/settings/serializers/auth/sms.py
jiangweidong 70f0f55ddb feat: 支持自定义短信认证(文件) (#11784)
* feat: 支持自定义短信认证(文件)

* perf: 翻译

* perf: 还原注释
2023-10-10 05:23:54 -05:00

120 lines
6.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from django.db import models
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
from common.sdk.sms import BACKENDS
from common.serializers.fields import EncryptedField, PhoneField
from common.validators import PhoneValidator
__all__ = [
'BaseSMSSettingSerializer',
'SMSSettingSerializer', 'AlibabaSMSSettingSerializer', 'TencentSMSSettingSerializer',
'HuaweiSMSSettingSerializer', 'CMPP2SMSSettingSerializer', 'CustomSMSSettingSerializer',
]
class SMSSettingSerializer(serializers.Serializer):
SMS_ENABLED = serializers.BooleanField(default=False, label=_('Enable SMS'))
SMS_BACKEND = serializers.ChoiceField(
choices=BACKENDS.choices, default=BACKENDS.ALIBABA, label=_('SMS provider / Protocol')
)
SMS_CODE_LENGTH = serializers.IntegerField(
default=4, min_value=4, max_value=16, label=_('SMS code length')
)
class SignTmplPairSerializer(serializers.Serializer):
SIGN_NAME = serializers.CharField(max_length=256, required=True, label=_('Signature'))
TEMPLATE_CODE = serializers.CharField(max_length=256, required=True, label=_('Template code'))
class BaseSMSSettingSerializer(serializers.Serializer):
PREFIX_TITLE = _('SMS')
SMS_TEST_PHONE = PhoneField(
validators=[PhoneValidator()], required=False, allow_blank=True, allow_null=True, label=_('Test phone')
)
def to_representation(self, instance):
data = super().to_representation(instance)
# data['SMS_BACKEND'] = self.fields['SMS_BACKEND'].default
return data
class AlibabaSMSSettingSerializer(BaseSMSSettingSerializer):
ALIBABA_ACCESS_KEY_ID = serializers.CharField(max_length=256, required=True, label='Access Key ID')
ALIBABA_ACCESS_KEY_SECRET = EncryptedField(
max_length=256, required=False, label='Access Key Secret',
)
ALIBABA_VERIFY_SIGN_NAME = serializers.CharField(max_length=256, required=True, label=_('Signature'))
ALIBABA_VERIFY_TEMPLATE_CODE = serializers.CharField(max_length=256, required=True, label=_('Template code'))
class TencentSMSSettingSerializer(BaseSMSSettingSerializer):
TENCENT_SECRET_ID = serializers.CharField(max_length=256, required=True, label='Secret ID')
TENCENT_SECRET_KEY = EncryptedField(max_length=256, required=False, label='Secret Key')
TENCENT_SDKAPPID = serializers.CharField(max_length=256, required=True, label='SDK APP ID')
TENCENT_VERIFY_SIGN_NAME = serializers.CharField(max_length=256, required=True, label=_('Signature'))
TENCENT_VERIFY_TEMPLATE_CODE = serializers.CharField(max_length=256, required=True, label=_('Template code'))
class HuaweiSMSSettingSerializer(BaseSMSSettingSerializer):
HUAWEI_APP_KEY = serializers.CharField(max_length=256, required=True, label='App Key')
HUAWEI_APP_SECRET = EncryptedField(max_length=256, required=False, label='App Secret')
HUAWEI_SMS_ENDPOINT = serializers.CharField(max_length=1024, required=True, label=_('App Access Address'))
HUAWEI_SIGN_CHANNEL_NUM = serializers.CharField(max_length=1024, required=True, label=_('Signature channel number'))
HUAWEI_VERIFY_SIGN_NAME = serializers.CharField(max_length=256, required=True, label=_('Signature'))
HUAWEI_VERIFY_TEMPLATE_CODE = serializers.CharField(max_length=256, required=True, label=_('Template code'))
class CMPP2SMSSettingSerializer(BaseSMSSettingSerializer):
CMPP2_HOST = serializers.CharField(max_length=256, required=True, label=_('Host'))
CMPP2_PORT = serializers.IntegerField(default=7890, label=_('Port'))
CMPP2_SP_ID = serializers.CharField(max_length=128, required=True, label=_('Enterprise code(SP id)'))
CMPP2_SP_SECRET = EncryptedField(max_length=256, required=False, label=_('Shared secret(Shared secret)'))
CMPP2_SRC_ID = serializers.CharField(max_length=256, required=False, label=_('Original number(Src id)'))
CMPP2_SERVICE_ID = serializers.CharField(max_length=256, required=True, label=_('Business type(Service id)'))
CMPP2_VERIFY_SIGN_NAME = serializers.CharField(max_length=256, required=True, label=_('Signature'))
CMPP2_VERIFY_TEMPLATE_CODE = serializers.CharField(
max_length=69, required=True, label=_('Template'),
help_text=_('Template need contain {code} and Signature + template length does not exceed 67 words. '
'For example, your verification code is {code}, which is valid for 5 minutes. '
'Please do not disclose it to others.')
)
def validate(self, attrs):
sign_name = attrs.get('CMPP2_VERIFY_SIGN_NAME', '')
template_code = attrs.get('CMPP2_VERIFY_TEMPLATE_CODE', '')
if template_code.find('{code}') == -1:
raise serializers.ValidationError(_('The template needs to contain {code}'))
if len(sign_name + template_code) > 65:
# 保证验证码内容在一条短信中(长度小于70字), 签名两边的括号和空格占3个字再减去2个即可(验证码占用4个但占位符6个
raise serializers.ValidationError(_('Signature + Template must not exceed 65 words'))
return attrs
class CustomSMSSettingSerializer(BaseSMSSettingSerializer):
class RequestType(models.TextChoices):
get = 'get', 'Get'
post = 'post', 'Post'
CUSTOM_SMS_URL = serializers.URLField(required=True, label=_("URL"))
CUSTOM_SMS_API_PARAMS = serializers.JSONField(
label=_('Parameters'), default={'phone_number': '{phone_number}', 'code': '{code}'}
)
CUSTOM_SMS_REQUEST_METHOD = serializers.ChoiceField(
default=RequestType.get, choices=RequestType.choices, label=_("Request method")
)
def validate(self, attrs):
need_params = {'{phone_numbers}', '{code}'}
params = attrs.get('CUSTOM_SMS_API_PARAMS', {})
# 这里用逗号分隔是保证需要的参数必须是完整的,不能分开在不同的参数中首位相连
params_string = ','.join(params.values())
for param in need_params:
if param not in params_string:
raise serializers.ValidationError(
_('The value in the parameter must contain %s') % ','.join(need_params)
)
return attrs