diff --git a/apps/authentication/mfa/custom.py b/apps/authentication/mfa/custom.py index 0819dcfaa..70ceaf34c 100644 --- a/apps/authentication/mfa/custom.py +++ b/apps/authentication/mfa/custom.py @@ -10,7 +10,7 @@ logger = get_logger(__file__) mfa_custom_method = None if settings.MFA_CUSTOM: - """ 保证自定义认证方法在服务运行时不能被更改,只在第一次调用时加载一次 """ + """ 保证自定义的方法在服务运行时不能被更改,只在第一次调用时加载一次 """ try: mfa_custom_method_path = 'data.mfa.main.check_code' mfa_custom_method = import_string(mfa_custom_method_path) diff --git a/apps/common/sdk/sms/custom.py b/apps/common/sdk/sms/custom.py index 64f9a0246..2cfaca6ca 100644 --- a/apps/common/sdk/sms/custom.py +++ b/apps/common/sdk/sms/custom.py @@ -30,7 +30,7 @@ class CustomSMS(BaseSMSClient): code=template_param.get('code'), phone_numbers=phone_numbers_str ) - logger.info(f'Custom sms send: phone_numbers={phone_numbers}param={params}') + logger.info(f'Custom sms send: phone_numbers={phone_numbers}, param={params}') if settings.CUSTOM_SMS_REQUEST_METHOD == 'post': action = requests.post kwargs = {'json': params} diff --git a/apps/common/sdk/sms/custom_file.py b/apps/common/sdk/sms/custom_file.py new file mode 100644 index 000000000..ee24a0d31 --- /dev/null +++ b/apps/common/sdk/sms/custom_file.py @@ -0,0 +1,50 @@ +import os + +from collections import OrderedDict + +from django.conf import settings +from django.utils.translation import gettext_lazy as _ +from django.utils.module_loading import import_string + +from common.utils import get_logger +from common.exceptions import JMSException +from jumpserver.settings import get_file_md5 + +from .base import BaseSMSClient + + +logger = get_logger(__file__) + + +custom_sms_method = None +SMS_CUSTOM_FILE_MD5 = settings.SMS_CUSTOM_FILE_MD5 +SMS_CUSTOM_FILE_PATH = os.path.join(settings.PROJECT_DIR, 'data', 'sms', 'main.py') +if SMS_CUSTOM_FILE_MD5 == get_file_md5(SMS_CUSTOM_FILE_PATH): + try: + custom_sms_method_path = 'data.sms.main.send_sms' + custom_sms_method = import_string(custom_sms_method_path) + except Exception as e: + logger.warning('Import custom sms method failed: {}, Maybe not enabled'.format(e)) + + +class CustomFileSMS(BaseSMSClient): + @classmethod + def new_from_settings(cls): + return cls() + + @staticmethod + def need_pre_check(): + return False + + def send_sms(self, phone_numbers: list, template_param: OrderedDict, **kwargs): + if not callable(custom_sms_method): + raise JMSException(_('The custom sms file is invalid')) + + try: + logger.info(f'Custom file sms send: phone_numbers={phone_numbers}, param={template_param}') + custom_sms_method(phone_numbers, template_param, **kwargs) + except Exception as err: + raise JMSException(_('SMS sending failed[%s]: %s') % (f"{_('Custom type')}({_('File')})", err)) + + +client = CustomFileSMS diff --git a/apps/common/sdk/sms/endpoint.py b/apps/common/sdk/sms/endpoint.py index ce016888a..6f5433fa5 100644 --- a/apps/common/sdk/sms/endpoint.py +++ b/apps/common/sdk/sms/endpoint.py @@ -17,7 +17,8 @@ class BACKENDS(TextChoices): TENCENT = 'tencent', _('Tencent cloud') HUAWEI = 'huawei', _('Huawei Cloud') CMPP2 = 'cmpp2', _('CMPP v2.0') - Custom = 'custom', _('Custom type') + CUSTOM = 'custom', _('Custom type') + CUSTOM_FILE = 'custom_file', f"{_('Custom type')}({_('File')})" class SMS: diff --git a/apps/common/utils/verify_code.py b/apps/common/utils/verify_code.py index b21e43b26..f9a721c89 100644 --- a/apps/common/utils/verify_code.py +++ b/apps/common/utils/verify_code.py @@ -67,7 +67,7 @@ class SendAndVerifyCodeUtil(object): return cache.get(self.key) def __generate(self): - code = random_string(4, lower=False, upper=False) + code = random_string(settings.SMS_CODE_LENGTH, lower=False, upper=False) self.code = code return code diff --git a/apps/jumpserver/conf.py b/apps/jumpserver/conf.py index b24ef5746..cb913f4d8 100644 --- a/apps/jumpserver/conf.py +++ b/apps/jumpserver/conf.py @@ -247,10 +247,11 @@ class Config(dict): 'AUTH_CUSTOM': False, 'AUTH_CUSTOM_FILE_MD5': '', - # Custom Config 'MFA_CUSTOM': False, 'MFA_CUSTOM_FILE_MD5': '', + 'SMS_CUSTOM_FILE_MD5': '', + # 临时密码 'AUTH_TEMP_TOKEN': False, @@ -409,6 +410,7 @@ class Config(dict): 'SMS_ENABLED': False, 'SMS_BACKEND': '', + 'SMS_CODE_LENGTH': 4, 'SMS_TEST_PHONE': '', 'ALIBABA_ACCESS_KEY_ID': '', @@ -439,7 +441,7 @@ class Config(dict): 'CMPP2_VERIFY_TEMPLATE_CODE': '{code}', 'CUSTOM_SMS_URL': '', - 'CUSTOM_SMS_API_PARAMS': {'phone_numbers': '{phone_numbers}', 'code': '{code}'}, + 'CUSTOM_SMS_API_PARAMS': {'phone_numbers': '{phone_numbers}', 'content': _('The verification code is: {code}')}, 'CUSTOM_SMS_REQUEST_METHOD': 'get', # Email diff --git a/apps/jumpserver/settings/auth.py b/apps/jumpserver/settings/auth.py index 63a96fe1d..5b6a1cd35 100644 --- a/apps/jumpserver/settings/auth.py +++ b/apps/jumpserver/settings/auth.py @@ -259,6 +259,9 @@ if MFA_CUSTOM and MFA_CUSTOM_FILE_MD5 == get_file_md5(MFA_CUSTOM_FILE_PATH): # 自定义多因子认证模块 MFA_BACKENDS.append(MFA_BACKEND_CUSTOM) +SMS_CUSTOM_FILE_MD5 = CONFIG.SMS_CUSTOM_FILE_MD5 +SMS_CUSTOM_FILE_PATH = os.path.join(PROJECT_DIR, 'data', 'sms', 'main.py') + AUTHENTICATION_BACKENDS_THIRD_PARTY = [ AUTH_BACKEND_OIDC_CODE, AUTH_BACKEND_CAS, AUTH_BACKEND_SAML2, AUTH_BACKEND_OAUTH2 diff --git a/apps/jumpserver/settings/custom.py b/apps/jumpserver/settings/custom.py index e60b98dad..0ec5c54ff 100644 --- a/apps/jumpserver/settings/custom.py +++ b/apps/jumpserver/settings/custom.py @@ -169,6 +169,7 @@ TERMINAL_KOKO_SSH_ENABLED = CONFIG.TERMINAL_KOKO_SSH_ENABLED # SMS enabled SMS_ENABLED = CONFIG.SMS_ENABLED SMS_BACKEND = CONFIG.SMS_BACKEND +SMS_CODE_LENGTH = CONFIG.SMS_CODE_LENGTH SMS_TEST_PHONE = CONFIG.SMS_TEST_PHONE # Alibaba @@ -186,6 +187,11 @@ TENCENT_VERIFY_SIGN_NAME = CONFIG.TENCENT_VERIFY_SIGN_NAME TENCENT_VERIFY_TEMPLATE_CODE = CONFIG.TENCENT_VERIFY_TEMPLATE_CODE TENCENT_SMS_SIGN_AND_TEMPLATES = CONFIG.TENCENT_SMS_SIGN_AND_TEMPLATES +# CUSTOM_SMS +CUSTOM_SMS_URL = CONFIG.CUSTOM_SMS_URL +CUSTOM_SMS_API_PARAMS = CONFIG.CUSTOM_SMS_API_PARAMS +CUSTOM_SMS_REQUEST_METHOD = CONFIG.CUSTOM_SMS_REQUEST_METHOD + # 公告 ANNOUNCEMENT_ENABLED = CONFIG.ANNOUNCEMENT_ENABLED ANNOUNCEMENT = CONFIG.ANNOUNCEMENT diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index bcd757537..98a9685e6 100644 --- a/apps/locale/ja/LC_MESSAGES/django.po +++ b/apps/locale/ja/LC_MESSAGES/django.po @@ -81,7 +81,7 @@ msgid "Collected" msgstr "集めました" #: accounts/const/account.py:27 accounts/serializers/account/account.py:28 -#: settings/serializers/auth/sms.py:75 +#: settings/serializers/auth/sms.py:79 msgid "Template" msgstr "テンプレート" @@ -1325,7 +1325,7 @@ msgid "Script" msgstr "脚本" #: assets/const/category.py:10 assets/models/asset/host.py:8 -#: settings/serializers/auth/radius.py:16 settings/serializers/auth/sms.py:67 +#: settings/serializers/auth/radius.py:16 settings/serializers/auth/sms.py:71 #: settings/serializers/feature.py:47 terminal/models/component/endpoint.py:13 #: terminal/serializers/applet.py:17 #: xpack/plugins/cloud/serializers/account_attrs.py:72 @@ -1616,7 +1616,7 @@ msgid "Cloud" msgstr "クラウド サービス" #: assets/models/asset/common.py:92 assets/models/platform.py:16 -#: settings/serializers/auth/radius.py:17 settings/serializers/auth/sms.py:68 +#: settings/serializers/auth/radius.py:17 settings/serializers/auth/sms.py:72 #: xpack/plugins/cloud/serializers/account_attrs.py:73 msgid "Port" msgstr "ポート" @@ -1692,7 +1692,7 @@ msgid "Proxy" msgstr "プロキシー" #: assets/models/automations/base.py:22 ops/models/job.py:223 -#: settings/serializers/auth/sms.py:99 +#: settings/serializers/auth/sms.py:103 msgid "Parameters" msgstr "パラメータ" @@ -2892,7 +2892,7 @@ msgstr "メッセージ検証コードが無効" #: authentication/mfa/sms.py:12 authentication/serializers/password_mfa.py:16 #: authentication/serializers/password_mfa.py:24 -#: settings/serializers/auth/sms.py:28 users/forms/profile.py:104 +#: settings/serializers/auth/sms.py:32 users/forms/profile.py:104 #: users/forms/profile.py:109 users/templates/users/forgot_password.html:112 #: users/views/profile/reset.py:98 msgid "SMS" @@ -3164,7 +3164,7 @@ msgstr "コードエラー" #: authentication/templates/authentication/_msg_reset_password_code.html:9 #: authentication/templates/authentication/_msg_rest_password_success.html:2 #: authentication/templates/authentication/_msg_rest_public_key_success.html:2 -#: jumpserver/conf.py:447 +#: jumpserver/conf.py:449 #: perms/templates/perms/_msg_item_permissions_expire.html:3 #: perms/templates/perms/_msg_permed_items_expire.html:3 #: tickets/templates/tickets/approve_check_password.html:33 @@ -3674,6 +3674,15 @@ msgstr "SP idは6ビット" msgid "Failed to connect to the CMPP gateway server, err: {}" msgstr "接続ゲートウェイサーバエラー, 非: {}" +#: common/sdk/sms/custom_file.py:41 +msgid "The custom sms file is invalid" +msgstr "カスタムショートメッセージファイルが無効です" + +#: common/sdk/sms/custom_file.py:47 +#, python-format +msgid "SMS sending failed[%s]: %s" +msgstr "ショートメッセージの送信に失敗しました[%s]: %s" + #: common/sdk/sms/endpoint.py:16 msgid "Alibaba cloud" msgstr "アリ雲" @@ -3690,11 +3699,11 @@ msgstr "華為雲" msgid "CMPP v2.0" msgstr "CMPP v2.0" -#: common/sdk/sms/endpoint.py:31 +#: common/sdk/sms/endpoint.py:32 msgid "SMS provider not support: {}" msgstr "SMSプロバイダーはサポートしていません: {}" -#: common/sdk/sms/endpoint.py:53 +#: common/sdk/sms/endpoint.py:54 msgid "SMS verification code signature or template invalid" msgstr "SMS検証コードの署名またはテンプレートが無効" @@ -3765,11 +3774,15 @@ msgstr "特殊文字を含むべきではない" msgid "The mobile phone number format is incorrect" msgstr "携帯電話番号の形式が正しくありません" -#: jumpserver/conf.py:446 +#: jumpserver/conf.py:444 +msgid "The verification code is: {code}" +msgstr "認証コードは: {code}" + +#: jumpserver/conf.py:448 msgid "Create account successfully" msgstr "アカウントを正常に作成" -#: jumpserver/conf.py:448 +#: jumpserver/conf.py:450 msgid "Your account has been created successfully" msgstr "アカウントが正常に作成されました" @@ -4596,7 +4609,7 @@ msgid "View permission tree" msgstr "権限ツリーの表示" #: settings/api/dingtalk.py:31 settings/api/feishu.py:36 -#: settings/api/sms.py:153 settings/api/vault.py:40 settings/api/wecom.py:37 +#: settings/api/sms.py:160 settings/api/vault.py:40 settings/api/wecom.py:37 msgid "Test success" msgstr "テストの成功" @@ -4624,11 +4637,11 @@ msgstr "Ldapユーザーを取得するにはNone" msgid "Imported {} users successfully (Organization: {})" msgstr "{} 人のユーザーを正常にインポートしました (組織: {})" -#: settings/api/sms.py:135 +#: settings/api/sms.py:142 msgid "Invalid SMS platform" msgstr "無効なショートメッセージプラットフォーム" -#: settings/api/sms.py:141 +#: settings/api/sms.py:148 msgid "test_phone is required" msgstr "携帯番号をテストこのフィールドは必須です" @@ -5034,54 +5047,58 @@ msgstr "SP プライベートキー" msgid "SP cert" msgstr "SP 証明書" -#: settings/serializers/auth/sms.py:16 +#: settings/serializers/auth/sms.py:17 msgid "Enable SMS" msgstr "SMSの有効化" -#: settings/serializers/auth/sms.py:18 +#: settings/serializers/auth/sms.py:19 msgid "SMS provider / Protocol" msgstr "SMSプロバイダ / プロトコル" -#: settings/serializers/auth/sms.py:23 settings/serializers/auth/sms.py:45 -#: settings/serializers/auth/sms.py:53 settings/serializers/auth/sms.py:62 -#: settings/serializers/auth/sms.py:73 settings/serializers/msg.py:76 +#: settings/serializers/auth/sms.py:22 +msgid "SMS code length" +msgstr "認証コード長" + +#: settings/serializers/auth/sms.py:27 settings/serializers/auth/sms.py:49 +#: settings/serializers/auth/sms.py:57 settings/serializers/auth/sms.py:66 +#: settings/serializers/auth/sms.py:77 settings/serializers/msg.py:76 msgid "Signature" msgstr "署名" -#: settings/serializers/auth/sms.py:24 settings/serializers/auth/sms.py:46 -#: settings/serializers/auth/sms.py:54 settings/serializers/auth/sms.py:63 +#: settings/serializers/auth/sms.py:28 settings/serializers/auth/sms.py:50 +#: settings/serializers/auth/sms.py:58 settings/serializers/auth/sms.py:67 msgid "Template code" msgstr "テンプレートコード" -#: settings/serializers/auth/sms.py:31 +#: settings/serializers/auth/sms.py:35 msgid "Test phone" msgstr "テスト電話" -#: settings/serializers/auth/sms.py:60 +#: settings/serializers/auth/sms.py:64 msgid "App Access Address" msgstr "アプリケーションアドレス" -#: settings/serializers/auth/sms.py:61 +#: settings/serializers/auth/sms.py:65 msgid "Signature channel number" msgstr "署名チャネル番号" -#: settings/serializers/auth/sms.py:69 +#: settings/serializers/auth/sms.py:73 msgid "Enterprise code(SP id)" msgstr "企業コード(SP id)" -#: settings/serializers/auth/sms.py:70 +#: settings/serializers/auth/sms.py:74 msgid "Shared secret(Shared secret)" msgstr "パスワードを共有する(Shared secret)" -#: settings/serializers/auth/sms.py:71 +#: settings/serializers/auth/sms.py:75 msgid "Original number(Src id)" msgstr "元の番号(Src id)" -#: settings/serializers/auth/sms.py:72 +#: settings/serializers/auth/sms.py:76 msgid "Business type(Service id)" msgstr "ビジネス・タイプ(Service id)" -#: settings/serializers/auth/sms.py:76 +#: settings/serializers/auth/sms.py:80 #, python-brace-format msgid "" "Template need contain {code} and Signature + template length does not exceed " @@ -5092,24 +5109,24 @@ msgstr "" "満です。たとえば、認証コードは{code}で、有効期間は5分です。他の人には言わない" "でください。" -#: settings/serializers/auth/sms.py:85 +#: settings/serializers/auth/sms.py:89 #, python-brace-format msgid "The template needs to contain {code}" msgstr "テンプレートには{code}を含める必要があります" -#: settings/serializers/auth/sms.py:88 +#: settings/serializers/auth/sms.py:92 msgid "Signature + Template must not exceed 65 words" msgstr "署名+テンプレートの長さは65文字以内" -#: settings/serializers/auth/sms.py:97 +#: settings/serializers/auth/sms.py:101 msgid "URL" msgstr "URL" -#: settings/serializers/auth/sms.py:102 +#: settings/serializers/auth/sms.py:106 msgid "Request method" msgstr "請求方法です" -#: settings/serializers/auth/sms.py:111 +#: settings/serializers/auth/sms.py:117 #, python-format msgid "The value in the parameter must contain %s" msgstr "パラメータの値には必ず %s が含まれます" diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index f42e27fd6..be805ccf0 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -80,7 +80,7 @@ msgid "Collected" msgstr "收集" #: accounts/const/account.py:27 accounts/serializers/account/account.py:28 -#: settings/serializers/auth/sms.py:75 +#: settings/serializers/auth/sms.py:79 msgid "Template" msgstr "模板" @@ -1317,7 +1317,7 @@ msgid "Script" msgstr "脚本" #: assets/const/category.py:10 assets/models/asset/host.py:8 -#: settings/serializers/auth/radius.py:16 settings/serializers/auth/sms.py:67 +#: settings/serializers/auth/radius.py:16 settings/serializers/auth/sms.py:71 #: settings/serializers/feature.py:47 terminal/models/component/endpoint.py:13 #: terminal/serializers/applet.py:17 #: xpack/plugins/cloud/serializers/account_attrs.py:72 @@ -1608,7 +1608,7 @@ msgid "Cloud" msgstr "云服务" #: assets/models/asset/common.py:92 assets/models/platform.py:16 -#: settings/serializers/auth/radius.py:17 settings/serializers/auth/sms.py:68 +#: settings/serializers/auth/radius.py:17 settings/serializers/auth/sms.py:72 #: xpack/plugins/cloud/serializers/account_attrs.py:73 msgid "Port" msgstr "端口" @@ -1684,7 +1684,7 @@ msgid "Proxy" msgstr "代理" #: assets/models/automations/base.py:22 ops/models/job.py:223 -#: settings/serializers/auth/sms.py:99 +#: settings/serializers/auth/sms.py:103 msgid "Parameters" msgstr "参数" @@ -2862,7 +2862,7 @@ msgstr "短信验证码校验失败" #: authentication/mfa/sms.py:12 authentication/serializers/password_mfa.py:16 #: authentication/serializers/password_mfa.py:24 -#: settings/serializers/auth/sms.py:28 users/forms/profile.py:104 +#: settings/serializers/auth/sms.py:32 users/forms/profile.py:104 #: users/forms/profile.py:109 users/templates/users/forgot_password.html:112 #: users/views/profile/reset.py:98 msgid "SMS" @@ -3132,7 +3132,7 @@ msgstr "代码错误" #: authentication/templates/authentication/_msg_reset_password_code.html:9 #: authentication/templates/authentication/_msg_rest_password_success.html:2 #: authentication/templates/authentication/_msg_rest_public_key_success.html:2 -#: jumpserver/conf.py:447 +#: jumpserver/conf.py:449 #: perms/templates/perms/_msg_item_permissions_expire.html:3 #: perms/templates/perms/_msg_permed_items_expire.html:3 #: tickets/templates/tickets/approve_check_password.html:33 @@ -3628,6 +3628,15 @@ msgstr "SP_id 为6位" msgid "Failed to connect to the CMPP gateway server, err: {}" msgstr "连接网关服务器错误,错误:{}" +#: common/sdk/sms/custom_file.py:41 +msgid "The custom sms file is invalid" +msgstr "自定义短信文件无效" + +#: common/sdk/sms/custom_file.py:47 +#, python-format +msgid "SMS sending failed[%s]: %s" +msgstr "短信发送失败[%s]: %s" + #: common/sdk/sms/endpoint.py:16 msgid "Alibaba cloud" msgstr "阿里云" @@ -3644,11 +3653,11 @@ msgstr "华为云" msgid "CMPP v2.0" msgstr "CMPP v2.0" -#: common/sdk/sms/endpoint.py:31 +#: common/sdk/sms/endpoint.py:32 msgid "SMS provider not support: {}" msgstr "短信服务商不支持:{}" -#: common/sdk/sms/endpoint.py:53 +#: common/sdk/sms/endpoint.py:54 msgid "SMS verification code signature or template invalid" msgstr "短信验证码签名或模版无效" @@ -3719,11 +3728,15 @@ msgstr "不能包含特殊字符" msgid "The mobile phone number format is incorrect" msgstr "手机号格式不正确" -#: jumpserver/conf.py:446 +#: jumpserver/conf.py:444 +msgid "The verification code is: {code}" +msgstr "验证码为: {code}" + +#: jumpserver/conf.py:448 msgid "Create account successfully" msgstr "创建账号成功" -#: jumpserver/conf.py:448 +#: jumpserver/conf.py:450 msgid "Your account has been created successfully" msgstr "你的账号已创建成功" @@ -4543,7 +4556,7 @@ msgid "View permission tree" msgstr "查看授权树" #: settings/api/dingtalk.py:31 settings/api/feishu.py:36 -#: settings/api/sms.py:153 settings/api/vault.py:40 settings/api/wecom.py:37 +#: settings/api/sms.py:160 settings/api/vault.py:40 settings/api/wecom.py:37 msgid "Test success" msgstr "测试成功" @@ -4571,11 +4584,11 @@ msgstr "获取 LDAP 用户为 None" msgid "Imported {} users successfully (Organization: {})" msgstr "成功导入 {} 个用户 ( 组织: {} )" -#: settings/api/sms.py:135 +#: settings/api/sms.py:142 msgid "Invalid SMS platform" msgstr "无效的短信平台" -#: settings/api/sms.py:141 +#: settings/api/sms.py:148 msgid "test_phone is required" msgstr "测试手机号 该字段是必填项。" @@ -4980,54 +4993,58 @@ msgstr "SP 密钥" msgid "SP cert" msgstr "SP 证书" -#: settings/serializers/auth/sms.py:16 +#: settings/serializers/auth/sms.py:17 msgid "Enable SMS" msgstr "启用 SMS" -#: settings/serializers/auth/sms.py:18 +#: settings/serializers/auth/sms.py:19 msgid "SMS provider / Protocol" msgstr "短信服务商 / 协议" -#: settings/serializers/auth/sms.py:23 settings/serializers/auth/sms.py:45 -#: settings/serializers/auth/sms.py:53 settings/serializers/auth/sms.py:62 -#: settings/serializers/auth/sms.py:73 settings/serializers/msg.py:76 +#: settings/serializers/auth/sms.py:22 +msgid "SMS code length" +msgstr "验证码长度" + +#: settings/serializers/auth/sms.py:27 settings/serializers/auth/sms.py:49 +#: settings/serializers/auth/sms.py:57 settings/serializers/auth/sms.py:66 +#: settings/serializers/auth/sms.py:77 settings/serializers/msg.py:76 msgid "Signature" msgstr "签名" -#: settings/serializers/auth/sms.py:24 settings/serializers/auth/sms.py:46 -#: settings/serializers/auth/sms.py:54 settings/serializers/auth/sms.py:63 +#: settings/serializers/auth/sms.py:28 settings/serializers/auth/sms.py:50 +#: settings/serializers/auth/sms.py:58 settings/serializers/auth/sms.py:67 msgid "Template code" msgstr "模板" -#: settings/serializers/auth/sms.py:31 +#: settings/serializers/auth/sms.py:35 msgid "Test phone" msgstr "测试手机号" -#: settings/serializers/auth/sms.py:60 +#: settings/serializers/auth/sms.py:64 msgid "App Access Address" msgstr "应用地址" -#: settings/serializers/auth/sms.py:61 +#: settings/serializers/auth/sms.py:65 msgid "Signature channel number" msgstr "签名通道号" -#: settings/serializers/auth/sms.py:69 +#: settings/serializers/auth/sms.py:73 msgid "Enterprise code(SP id)" msgstr "企业代码(SP id)" -#: settings/serializers/auth/sms.py:70 +#: settings/serializers/auth/sms.py:74 msgid "Shared secret(Shared secret)" msgstr "共享密码(Shared secret)" -#: settings/serializers/auth/sms.py:71 +#: settings/serializers/auth/sms.py:75 msgid "Original number(Src id)" msgstr "原始号码(Src id)" -#: settings/serializers/auth/sms.py:72 +#: settings/serializers/auth/sms.py:76 msgid "Business type(Service id)" msgstr "业务类型(Service id)" -#: settings/serializers/auth/sms.py:76 +#: settings/serializers/auth/sms.py:80 #, python-brace-format msgid "" "Template need contain {code} and Signature + template length does not exceed " @@ -5037,24 +5054,24 @@ msgstr "" "模板需要包含 {code},并且模板+签名长度不能超过67个字。例如, 您的验证码是 " "{code}, 有效期为5分钟。请不要泄露给其他人。" -#: settings/serializers/auth/sms.py:85 +#: settings/serializers/auth/sms.py:89 #, python-brace-format msgid "The template needs to contain {code}" msgstr "模板需要包含 {code}" -#: settings/serializers/auth/sms.py:88 +#: settings/serializers/auth/sms.py:92 msgid "Signature + Template must not exceed 65 words" msgstr "模板+签名不能超过65个字" -#: settings/serializers/auth/sms.py:97 +#: settings/serializers/auth/sms.py:101 msgid "URL" msgstr "URL" -#: settings/serializers/auth/sms.py:102 +#: settings/serializers/auth/sms.py:106 msgid "Request method" msgstr "请求方式" -#: settings/serializers/auth/sms.py:111 +#: settings/serializers/auth/sms.py:117 #, python-format msgid "The value in the parameter must contain %s" msgstr "参数中的值必须包含 %s" diff --git a/apps/settings/api/sms.py b/apps/settings/api/sms.py index ec767828d..ecf7bd343 100644 --- a/apps/settings/api/sms.py +++ b/apps/settings/api/sms.py @@ -2,6 +2,7 @@ import importlib from collections import OrderedDict from django.utils.translation import gettext_lazy as _ +from django.conf import settings from rest_framework import status from rest_framework.exceptions import APIException from rest_framework.generics import ListAPIView, GenericAPIView @@ -28,7 +29,6 @@ class SMSBackendAPI(ListAPIView): } for b in BACKENDS.choices ] - return Response(data) @@ -39,11 +39,16 @@ class SMSTestingAPI(GenericAPIView): 'huawei': serializers.HuaweiSMSSettingSerializer, 'cmpp2': serializers.CMPP2SMSSettingSerializer, 'custom': serializers.CustomSMSSettingSerializer, + 'custom_file': serializers.BaseSMSSettingSerializer, } rbac_perms = { 'POST': 'settings.change_sms' } + @property + def test_code(self): + return '6' * settings.SMS_CODE_LENGTH + @staticmethod def get_or_from_setting(key, value=''): if not value: @@ -63,7 +68,7 @@ class SMSTestingAPI(GenericAPIView): send_sms_params = { 'sign_name': data['ALIBABA_VERIFY_SIGN_NAME'], 'template_code': data['ALIBABA_VERIFY_TEMPLATE_CODE'], - 'template_param': {'code': '666666'} + 'template_param': {'code': self.test_code} } return init_params, send_sms_params @@ -78,7 +83,7 @@ class SMSTestingAPI(GenericAPIView): send_sms_params = { 'sign_name': data['TENCENT_VERIFY_SIGN_NAME'], 'template_code': data['TENCENT_VERIFY_TEMPLATE_CODE'], - 'template_param': OrderedDict(code='666666') + 'template_param': OrderedDict(code=self.test_code) } return init_params, send_sms_params @@ -94,7 +99,7 @@ class SMSTestingAPI(GenericAPIView): send_sms_params = { 'sign_name': data['HUAWEI_VERIFY_SIGN_NAME'], 'template_code': data['HUAWEI_VERIFY_TEMPLATE_CODE'], - 'template_param': OrderedDict(code='666666') + 'template_param': OrderedDict(code=self.test_code) } return init_params, send_sms_params @@ -110,16 +115,18 @@ class SMSTestingAPI(GenericAPIView): send_sms_params = { 'sign_name': data['CMPP2_VERIFY_SIGN_NAME'], 'template_code': data['CMPP2_VERIFY_TEMPLATE_CODE'], - 'template_param': OrderedDict(code='666666') + 'template_param': OrderedDict(code=self.test_code) } return init_params, send_sms_params - @staticmethod - def get_custom_params(data): + def get_custom_params(self, data): init_params = {} - send_sms_params = {'template_param': OrderedDict(code='666666')} + send_sms_params = {'template_param': OrderedDict(code=self.test_code)} return init_params, send_sms_params + def get_custom_file_params(self, data): + return self.get_custom_params(data) + def get_params_by_backend(self, backend, data): """ 返回两部分参数 diff --git a/apps/settings/serializers/auth/sms.py b/apps/settings/serializers/auth/sms.py index 40881e52a..1011c9aa6 100644 --- a/apps/settings/serializers/auth/sms.py +++ b/apps/settings/serializers/auth/sms.py @@ -7,6 +7,7 @@ from common.serializers.fields import EncryptedField, PhoneField from common.validators import PhoneValidator __all__ = [ + 'BaseSMSSettingSerializer', 'SMSSettingSerializer', 'AlibabaSMSSettingSerializer', 'TencentSMSSettingSerializer', 'HuaweiSMSSettingSerializer', 'CMPP2SMSSettingSerializer', 'CustomSMSSettingSerializer', ] @@ -17,6 +18,9 @@ class SMSSettingSerializer(serializers.Serializer): 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): @@ -102,12 +106,14 @@ class CustomSMSSettingSerializer(BaseSMSSettingSerializer): default=RequestType.get, choices=RequestType.choices, label=_("Request method") ) - @staticmethod - def validate(attrs): + def validate(self, attrs): need_params = {'{phone_numbers}', '{code}'} params = attrs.get('CUSTOM_SMS_API_PARAMS', {}) - if len(set(params.values()) & need_params) != len(need_params): - raise serializers.ValidationError( + # 这里用逗号分隔是保证需要的参数必须是完整的,不能分开在不同的参数中首位相连 + 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