From 4a436856b4508c9be9aad3382020f91038cd1a8c Mon Sep 17 00:00:00 2001 From: feng626 <1304903146@qq.com> Date: Thu, 9 Sep 2021 20:59:26 +0800 Subject: [PATCH 01/36] feat: sms setting --- apps/settings/api/settings.py | 1 + apps/settings/serializers/auth/sms.py | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/settings/api/settings.py b/apps/settings/api/settings.py index 4dda51408..2047faa08 100644 --- a/apps/settings/api/settings.py +++ b/apps/settings/api/settings.py @@ -34,6 +34,7 @@ class SettingsApi(generics.RetrieveUpdateAPIView): 'sso': serializers.SSOSettingSerializer, 'clean': serializers.CleaningSerializer, 'other': serializers.OtherSettingSerializer, + 'sms': serializers.SMSSettingSerializer, 'alibaba': serializers.AlibabaSMSSettingSerializer, 'tencent': serializers.TencentSMSSettingSerializer, } diff --git a/apps/settings/serializers/auth/sms.py b/apps/settings/serializers/auth/sms.py index 275a8436e..c018720b2 100644 --- a/apps/settings/serializers/auth/sms.py +++ b/apps/settings/serializers/auth/sms.py @@ -3,21 +3,24 @@ from rest_framework import serializers from common.message.backends.sms import BACKENDS -__all__ = ['AlibabaSMSSettingSerializer', 'TencentSMSSettingSerializer'] +__all__ = ['SMSSettingSerializer', 'AlibabaSMSSettingSerializer', 'TencentSMSSettingSerializer'] + + +class SMSSettingSerializer(serializers.Serializer): + SMS_ENABLED = serializers.BooleanField(default=False, label=_('Enable SMS')) + SMS_BACKEND = serializers.ChoiceField(choices=BACKENDS.choices, default=BACKENDS.ALIBABA) class BaseSMSSettingSerializer(serializers.Serializer): - SMS_ENABLED = serializers.BooleanField(default=False, label=_('Enable SMS')) SMS_TEST_PHONE = serializers.CharField(max_length=256, required=False, label=_('Test phone')) def to_representation(self, instance): data = super().to_representation(instance) - data['SMS_BACKEND'] = self.fields['SMS_BACKEND'].default + # data['SMS_BACKEND'] = self.fields['SMS_BACKEND'].default return data class AlibabaSMSSettingSerializer(BaseSMSSettingSerializer): - SMS_BACKEND = serializers.ChoiceField(choices=BACKENDS.choices, default=BACKENDS.ALIBABA) ALIBABA_ACCESS_KEY_ID = serializers.CharField(max_length=256, required=True, label='AccessKeyId') ALIBABA_ACCESS_KEY_SECRET = serializers.CharField( max_length=256, required=False, label='AccessKeySecret', write_only=True) @@ -35,7 +38,6 @@ class AlibabaSMSSettingSerializer(BaseSMSSettingSerializer): class TencentSMSSettingSerializer(BaseSMSSettingSerializer): - SMS_BACKEND = serializers.ChoiceField(choices=BACKENDS.choices, default=BACKENDS.TENCENT) TENCENT_SECRET_ID = serializers.CharField(max_length=256, required=True, label='Secret id') TENCENT_SECRET_KEY = serializers.CharField(max_length=256, required=False, label='Secret key', write_only=True) TENCENT_SDKAPPID = serializers.CharField(max_length=256, required=True, label='SDK app id') From 654ec4970ef7b1c61a625f34ca37f1a9d16635c3 Mon Sep 17 00:00:00 2001 From: xinwen Date: Thu, 9 Sep 2021 21:11:57 +0800 Subject: [PATCH 02/36] =?UTF-8?q?=E6=9B=B4=E6=94=B9=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/message/backends/sms/__init__.py | 4 +-- apps/settings/serializers/auth/sms.py | 36 ++++++++------------ 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/apps/common/message/backends/sms/__init__.py b/apps/common/message/backends/sms/__init__.py index be32c6e94..af7a0e170 100644 --- a/apps/common/message/backends/sms/__init__.py +++ b/apps/common/message/backends/sms/__init__.py @@ -40,8 +40,8 @@ class SMS_MESSAGE(TextChoices): class BACKENDS(TextChoices): - ALIBABA = 'alibaba', _('Alibaba') - TENCENT = 'tencent', _('Tencent') + ALIBABA = 'alibaba', _('Alibaba cloud') + TENCENT = 'tencent', _('Tencent cloud') class BaseSMSClient: diff --git a/apps/settings/serializers/auth/sms.py b/apps/settings/serializers/auth/sms.py index c018720b2..2e186c07b 100644 --- a/apps/settings/serializers/auth/sms.py +++ b/apps/settings/serializers/auth/sms.py @@ -8,7 +8,12 @@ __all__ = ['SMSSettingSerializer', 'AlibabaSMSSettingSerializer', 'TencentSMSSet class SMSSettingSerializer(serializers.Serializer): SMS_ENABLED = serializers.BooleanField(default=False, label=_('Enable SMS')) - SMS_BACKEND = serializers.ChoiceField(choices=BACKENDS.choices, default=BACKENDS.ALIBABA) + SMS_BACKEND = serializers.ChoiceField(choices=BACKENDS.choices, default=BACKENDS.ALIBABA, label=_('SMS provider')) + + +class SignAndTmplPairSerializer(serializers.Serializer): + sign_name = serializers.CharField(max_length=256, required=True, label=_('Signature')) + template_code = serializers.CharField(max_length=256, required=True, label=_('Template')) class BaseSMSSettingSerializer(serializers.Serializer): @@ -20,20 +25,16 @@ class BaseSMSSettingSerializer(serializers.Serializer): return data +class SignAndTmplSerializer(serializers.Serializer): + verification_code = SignAndTmplPairSerializer(default={'sign_name': '', 'template_code': ''}) + + class AlibabaSMSSettingSerializer(BaseSMSSettingSerializer): ALIBABA_ACCESS_KEY_ID = serializers.CharField(max_length=256, required=True, label='AccessKeyId') ALIBABA_ACCESS_KEY_SECRET = serializers.CharField( max_length=256, required=False, label='AccessKeySecret', write_only=True) - ALIBABA_SMS_SIGN_AND_TEMPLATES = serializers.DictField( - label=_('Signatures and Templates'), required=True, help_text=_(''' - Filling in JSON Data: - { - "verification_code": { - "sign_name": "", - "template_code": "" - } - } - ''') + ALIBABA_SMS_SIGN_AND_TEMPLATES = SignAndTmplSerializer( + label=_('Signatures and Templates'), required=True ) @@ -41,13 +42,6 @@ class TencentSMSSettingSerializer(BaseSMSSettingSerializer): TENCENT_SECRET_ID = serializers.CharField(max_length=256, required=True, label='Secret id') TENCENT_SECRET_KEY = serializers.CharField(max_length=256, required=False, label='Secret key', write_only=True) TENCENT_SDKAPPID = serializers.CharField(max_length=256, required=True, label='SDK app id') - TENCENT_SMS_SIGN_AND_TEMPLATES = serializers.DictField( - label=_('Signatures and Templates'), required=True, help_text=_(''' - Filling in JSON Data: - { - "verification_code": { - "sign_name": "", - "template_code": "" - } - } - ''')) + TENCENT_SMS_SIGN_AND_TEMPLATES = SignAndTmplSerializer( + label=_('Signatures and Templates'), required=True + ) From bf6b685e8ce0a6e094d03c5d7ff6efad9c0fa78f Mon Sep 17 00:00:00 2001 From: Michael Bai Date: Fri, 10 Sep 2021 15:04:18 +0800 Subject: [PATCH 03/36] =?UTF-8?q?fix:=20api/health/=E5=81=A5=E5=BA=B7?= =?UTF-8?q?=E6=A3=80=E6=B5=8B=E6=B7=BB=E5=8A=A0localhost?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/jumpserver/api.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/apps/jumpserver/api.py b/apps/jumpserver/api.py index 6be2e4407..76192130f 100644 --- a/apps/jumpserver/api.py +++ b/apps/jumpserver/api.py @@ -17,9 +17,10 @@ from terminal.models import Session from terminal.utils import ComponentsPrometheusMetricsUtil from orgs.utils import current_org from common.permissions import IsOrgAdmin, IsOrgAuditor -from common.utils import lazyproperty +from common.utils import lazyproperty, get_request_ip from orgs.caches import OrgResourceStatisticsCache + __all__ = ['IndexApi'] @@ -304,12 +305,21 @@ class HealthApiMixin(APIView): return False return True + def is_localhost(self): + ip = get_request_ip(self.request) + return ip in ['localhost', '127.0.0.1'] + def check_permissions(self, request): - if not self.is_token_right(): - msg = 'Health check token error, ' \ - 'Please set query param in url and same with setting HEALTH_CHECK_TOKEN. ' \ - 'eg: $PATH/?token=$HEALTH_CHECK_TOKEN' - self.permission_denied(request, message={'error': msg}, code=403) + if self.is_token_right(): + return + if self.is_localhost(): + return + msg = ''' + Health check token error, + Please set query param in url and same with setting HEALTH_CHECK_TOKEN. + eg: $PATH/?token=$HEALTH_CHECK_TOKEN + ''' + self.permission_denied(request, message={'error': msg}, code=403) class HealthCheckView(HealthApiMixin): From 345c0fcf4faa778539edb95a4534454fa296620f Mon Sep 17 00:00:00 2001 From: feng626 <1304903146@qq.com> Date: Fri, 10 Sep 2021 16:08:12 +0800 Subject: [PATCH 04/36] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=B7=A5?= =?UTF-8?q?=E5=8D=95=E6=B5=81bug=20=E6=B7=BB=E5=8A=A0=E7=99=BB=E9=99=86?= =?UTF-8?q?=E5=AE=A1=E6=A0=B8=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/authentication/views/login.py | 4 +- apps/locale/zh/LC_MESSAGES/django.mo | Bin 93675 -> 93382 bytes apps/locale/zh/LC_MESSAGES/django.po | 343 +++++++++++++++++--------- apps/settings/serializers/security.py | 5 +- apps/tickets/models/flow.py | 3 +- 5 files changed, 235 insertions(+), 120 deletions(-) diff --git a/apps/authentication/views/login.py b/apps/authentication/views/login.py index 4fc39b4ac..e4955e289 100644 --- a/apps/authentication/views/login.py +++ b/apps/authentication/views/login.py @@ -212,8 +212,10 @@ class UserLoginWaitConfirmView(TemplateView): if ticket: timestamp_created = datetime.datetime.timestamp(ticket.date_created) ticket_detail_url = TICKET_DETAIL_URL.format(id=ticket_id) + assignees = ticket.current_node.first().ticket_assignees.all() + assignees_display = ', '.join([str(i.assignee) for i in assignees]) msg = _("""Wait for {} confirm, You also can copy link to her/him
- Don't close this page""").format(ticket.assignees_display) + Don't close this page""").format(assignees_display) else: timestamp_created = 0 ticket_detail_url = '' diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index c873509acea1cf8126ba9e73776cf6c207919292..ab8fc5a7994ee8fa11e7d7012cfb0df67bd2f892 100644 GIT binary patch delta 26600 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 delta 26650 zcmZA91(;RU`}XlY!%#CY4Barq3>`yvH_{~y14wsBAG!ntNhtwofdN6fyF)2yloUZx z1eAKe_gN3Wi~qZ?Yw=m@S-IDaa}LIlpJPA17Tb3-Nzg2h<9v|krNd>Bo;N6t=jE=Y zsON=s^t>+vJuflF1bE((&YpJx>vi?KT^QNj^P1A`*B+iX1xxqzyuo-9YtgStFVA~P zd1fEaYfO1^U(dU#_WeDteW2&_4h-&d zDx=D^P+Qm#Q(`n~VS_O~jz_hhj$!yUYT`Ahh3qv?pw9FnX2yr8aYM$rolHHB{a1sE z1h`+k#;Adhpc2#=!fq06X#&rmxOIMFR2C8njE z6Ek5IRDCBO8BH(@)o~_j;N_^5Z@2nWs0n_x_*>M%!zQ`*nNgRj2x^?#sP?T<3m$|T zZyctFeB!{I9Ll4VnftG(WrrYV|<*Ax)h5s5Wh$D z`vEoKF4PVkMJ@OyCcp=Z>-m39MrRl@)$_7oCM=AVu^CMB3DmuC0YlOE3mIL4XQ%<=%yf@e3e*{-Lv_f4x@)6Q*Rl+1 zA@%)3*Us=sUsMT=P|XO|3Y)z0&1gfj>f31Z;e{{XQ&kq zKwXMam<*?(CSGpFU^wONsBx~M`u&P*wf6_6z*uwL)0PH(IynU$gPNU|zhT8GFbJ>3l{5t`y@C~XQ_O;uA zaMXm^Fc%iV+!&2|Uwnxga3*Skg{b!5VKLl+sqt^rrARo>Ei?;i0cGZ~|5{-c0+BSdMbQ0{3dIfSRZy>eH_m=D-1{9b1e#feoky?6&wJ)V*>6brU{9Jsoc>?n}7P zRb(~`qt37zYTyQ_$E+RdjQXRtawO_o@Ep_@Z$V9P4pZT;s7vt%wbdbu_>|k z`un_TWOQaR<~G!eV?SyEcTodB$Fvyt8$RJM3ueR`7=>L>_s9a&r8|b|cO7-cf1t+m z7Q2Oo`Smdf88ys{T4{OI%B!Q!{8LoC3#wfo)E19LEqpSneio|zLR5VWrpGN9ju$Wk z{)37qTS9;4_X?0vhmxo*u7J9hwJ{|&N1ah$)Ygu-`o*XPtV8wRf?CLKD<8J{Q>bw- zVkW$U8b8)j_Fr2PMn)5aV+AaPjq!6_foE_h_W#yxVbn5rQ3DJO?4CX#(ITXXrkqA2Qp$H0lPsum4l74t zKFUS04tB)+xD|ED9-?;aJ;uWj2G=D>hB~1v$d3EGC^EW6wNVY*nqADksELQ7?%pw& z16QCf**OfxC#Zp6p|(8EckUiafoUk`$M{$iwX=;dnEAbqWYnP#hTtgFN~dBWT!@Mfo38eWtZ;OLL>X#ur3Q*aY?EwJqxT?|`~wW2Bz{m1IKj1nQ=_gmLgX z>WqFxZRs=APQ+X1-h^SOoy(0Huq-CPXw(VyM4gDw;!{!m=cDHN7JbUBCZjWpK`mq( z>Lxja3GoW*4DVa{8EQfAQLp3_>s`MBs0qtpB-TRp>xWvX549s-q2^n#p8Z!~IRQ-= zgX(Y))!_{4jP9VW*;A|cVqCirRKFCcyE`Xp=PIDuSI1Cnj=FccpxRAFU6N%n?7vpB zihvff5mnxaIq(o_N1mc4`VVzxp&MMhFlwRYF#;P}d@$-n#-SE6-TW4{b3b4rJmn)3 zPUbr5Oy8mw5WLYXC@Ja;(wn(acXLUzG3xp5ZB92gn&(kF^2~gNI-&QdH=!@&d-r)B zhPoFb&D^NFwE*gUP!IKD>S<0uy}_2Cz7K4{BzOvSPuxP)zeb&L*d|xbW|l&Bz~|K? zqpfd?T2WV2hhC@w#$y3ofZCa}7QbTUC#ao!f$AS?vwJM#q23RLP?w?}>alEr+WHX~ zr00Jc8Ex?_t5}BGiOr~icVI$1iW=x5M&WJL)+YJEU6RzO6DefnGN=VN#cUXjns^fG z63oLuJ^w4n=(${tnqVVp!d<8iCol}Jq9%NdYX27o;(zGBcQ6U%;4N+;=`k7QY?v5J z;aseZ8utPEzyH4^qX~kxx@(ynQ&7%@+QJH`Yu_5R#RIV@4nr;I2h@Ugp$0yLI>QT? z9B*S%e1ST_;B9Val5b=G)iHwwB2inI&&tJ7XI24q*VjRvQ5Vz#eOLu&qZV=lHNjm} zyFXBuAZWYW(S)d{B`s<}CAYKxDaq6!AUk3t`cONv!rW^0$1t4uZPYyzu)}R_n3)-M z_ZPy{SQmAIT~OooF-N1?&GeDUN@fGMs7- z;*YHyxW~nlp)O%0YDdbT#%qeYC)%MF+ynJK8IFnd{BI>qb3-Lx^$yZ6HP$fj5Dl$9%?6+VK{C;-4o|AwvWuuWYpo7Roq9N=~Ih) z``nhrHN#MMcWTr^@}edvjaoo;)WRB~#%YCW-wQR*SXBGT=>PlwxnwlZH>kUGJ%;06 z)J=06b%vq)-J35Ns(lsIW7r6DV>i^b{Tg)-EJaQD;;Ob&Z=^yfbP+eXTqc^|?O|)o#)OA73oV z%p;(IQyz2!W<{MrUMrVEU9&0{uZ z>PtjMk4pxO!s4jAzbk6uk*G78jv9Ee#n+>DU=M2Nj-n>GVDamy_V+M0{*96NF9u=w z5&yz{UIZDvsq&fCPy@C_P0#~%Z9hl7phjaH+-C8;s1rDe8s|Q0tKVY|3_Hr-8(|65 zPV`1CXeh?f^FNA=|C*szHW#&Z3;hkad#!$}m5-oy<}}8|8>orzS@|7moH)na!b4E6 z;FPF-QK)|9F(LDN)yZhWCa5#%g1V+-F%Eud&PMITLe%rT8ny5}sI5M2_17%^0R11k zsBwdjyPb(Z#fzX%1Jxj-t!Zs`L7hQ=)TJ1V@o+rG$7xochg$fzsCHXW;~Ye7@foYX zfbl6mK%MzB)Pny#&i-rQxF_7*9fsPH+`rV$~@FH-iC$oIA+H87>t=u zx}C{`T39L6)>p^u*c3D2sFUn}HZscyEa2f|}?qX25rt5Yu0F*EAQZT`|-(uY{VY4(jG@g7L8hw#Uyf0#9Nee1_%q{I|d2 zuKfzs&2a&%;9G2lm40@AnfwjvuD*h-+`EaX@Gne>Ay?f_WI^3@B~T|;6}8YNs0Fn{ zEwDQ#V1BO;8EuUZLva>rz-6ed+GU7Ad?z1qh2_r%!-(Xat+ia=zzM3#-MJ>Wf+cUQ49VPbt&TAbmJsN z?LZpTJULMdDS}!^#hdKEGBpY4j2f6N&5qcXcyH7W{e;@ON2q>J%@?SN-=TIe{w>!& z6{e${7gJzO)IAi9ddhm;^0~+45&^9+@U|Nu6t&XysIAJ0I>SV|p zD1U`o@OdnbSFivkx#!;Pm2o5Gj;MvCzVBXG8O@5APxE&qqlxFBJ`LAk1nxx*d=GU= zGCpws~A zn3?jcM{eS@zqvCggxc~Fs0CC)-6O3r7<-`>J_L2imY{CBji{&MFzP9|fSK?y`ZRIE z$8Lfon2T~M%!!pS2lm9Q_%-Sb_h24;g1Is6@9tBy8fK*23w0AtL-mWnEO^19X^hKV7x!M{zJ&TddA&}{r={f;E3n$V{^(s{#(?$hV2=k`3vp~>i6Mp$|GL! z1`K4-f8EX2`Zb@V)F*z!^`$<+JAM=3ejJ4*-*a-f2Pa@fpBLbbp~ER0N1$F{fY*ug z71YYh2L<@=jfNOPxhclO4yYGX57bRK!kmq|1Z%DS6srAA)Fpj@{--2%fPY7QmC0z! z+o8645{Bb)REHy|t$&6^Fj1TU?-*9WO)AF?@L$V=s4c#ay2)N*LJW=POoyt^iNRPB zc^Z6P6>Cr%6Hw8@?2KwSz{(>r4&|vDr(s7>e0(9O{z9U^6^y_2I#;T~5?Ig)lAidnJ{@ zCa8(}T7wZ-oAP)ph?lHBm^)QxkP`KL=SNLg3AK=BsOP^uYP^2tNOP(=AAOp5l?4u& z=TQUPM4jnVD+lmsXrjbsHq_%++H8SpKg8;%qHfYiE2 z7VlvWvG@ekRxd(bf>o$~yHE=}XkJI{&_7mAmdH(<2i2~+&oa@d0fwLk9)()KWYn21 zwfOg#iSjOs-$d=eQ`F7(+R9nOTs+DwgF54ysChbC+}Fc0Lr^Q7fLg#x)WjPx7Vbw) zblCh6HQ+7OfUhkcnAo*TWTr#CS8`x3tb}^^_rkn-{%4TUi{Sujpr23^T{Rz|7WUlg zlO}QXX)u&{HnRw-e`WI%)XmobHC_kQJ<SHSw^mM))RiMp1C~IYX#*?wKrLuIY5`MG(HbpI{9qQ6{LH|GhA8dh1<~(x^mZRYg)QVrD21uOT zeKw>*O2}|Yr&g!wgm~jT)dT>dc#8B9Lk$p*9|zemIcld$n{`n;(GIncp{Vww&1n{2h+5Dxi*H8% zKmXfrfitLIJlCw8JiQw*vzY@maDKD2SpzE&Z(`+ns0FUX{J6u)kFER;b;9{F@ciox z>t%2gwMJEZhFa+a)P!@bemUx$z7{pX9`n3;7j-YZv~t3X?iC%5dW;LBUhU;jJN9Wt zpBtz*0S!3DD(09QEPfodkn2`{gxcyiSQBG~2l#&x)j=(M7^?jgRJ(bY5tmqeKkBJD z<0GS=NLMg7zC~?W&P?vj*Bm1$e}(#5y&bjkbEq?Ygj)D}Gf8GwjzE1p7eh_d5VfFI zW>?cUkclcL@uO#XcS3r$Z7uCO| z)93Xfqca+94Hlp#UTtnd4Yb=lWS&F~_#_@KcM;_K>dX0bAn=rMR12s``)Yg_m^{a1zoH!QsX}1C6;aSv{UO~P29-I@R(b$4wF)GwYW)VJo!m>R2NIJQH*sK%f! z?R?akuS6|uJ!-z4NI#!R8AuZ}HlwfjXl44>rf3CY*}e z!C9#Oi%{*qL+$7uf1KySPx~U?pTpKlDbJPNQpe7t>^&`!x z=6qE9RaV}qvY!8A7Pw|UL_J>rm~o=q0#ce;Q3FMx?wLxcOV$&0X46rx+$E^@M-1vc zumkmN`X|&*2N$s4|KVixp;HPqKzG!=Fbwq<4_{mPG^*nxE5A3>7IgPSQB?n$sPUSk z+D}F;WGQOgb*OvjctM_jU7H&ObT|KIzBiK@S$wm3v=Gm~8eX-)6Vw@ag`Huj`f$`^SrE0A_06tUKgP;)Pz%{$?nX^~0(Gg* zqsDuK`YM;mSH!KjC~8Z}Te*?h+U$&ZsPBtIURLV zuJOzBw~ve#a0zqa4J*el;o@Pafm51U%_y@Bs(($?&eXSZ3$q<+p!QYOiQ38T zW$g2Rj5YWIHNafdioZh*{Jpu$JYx0dPz%0n<-4d?_hZyJZ&3Xcm38e>qvDaMohqqUWLqh6WAQ5`0tIxIka$ozmBcn@j;$58jcMJqqY+>`^#x$hTwQDa!ao*IRNhUL0@Xj#%!68JAuE?h z`un_UF5}flonZ@9!~W(d^GkC9>K<5)+L^tmh5Tss*U^8oS@}=%EtaHRa0PdBRzd&Y z|3#D0$6{yH#EVe_uS4BL`%nWuw)($N3wUqw-q0z4MtkURMfRvVs1oDxF0p}WsBcMUCZaFfdebKe(~`u%BfMW7$s$W%9`zEM`v`3wJS1S)k%`+BtBGXXqS5)Tt z*EQcnpc9@#l?zvK6W2yf@TrwMp*r@lxDPeqm#C*=w$*=wTHspLr{zA>xc997of%Tq z=LSqw)fr(HFw3GQ_{7Q$%r>YGqwc7I`=Z)SHfNv~KF?f(+SwgeK7`tl3qCUXT)%}H zAYnDvF&S#$tY&G{0F6;^!ZuhIN1=A)0IL64^OD7HSot?AKSMpv@2u<#tnNA{LQRmu z%HgQzI-8ZtV-V$Ps57gDT1ZROwf0&3E7XFPT091IA_pvf4K>e0WWhe~FRS<$HE^67 z&J?JIk*ERlTf8)C!dj>wlWnX#%$#O^i|W6{+=tqs6R7dd`{nt&X@SS)D>HUY*D#5h z5j8+=)Wii*6Vx@Ene9>SdZ60%NA18@R{jq48}S(Wpa0ur^cMn8P>)xWS z1=P+&n|)AcFv|QAvr}Gx`Yn0b$`4VOC~+-kLDWCAZiGWIX>Fc=eSA(MQwO(U6^vKM z{gp`_)blzK)$SWCfk&|z2G(`2(vql&nxH;I2BB{1x!44c;3&*cFTnq=-7LXEl;hUt z`Pa%z)prwhK%MCjD}RBScnOB%anwY=p+46WG;mv48uf*v5o)V@qn`Uos1LUo)En`p z#d|k&^UQ9@^RJs}1p&Dob$eDsB7Qb;zLjipK9erR^Djk{isWJ z!OC|~PuFvwRfINn4bqy~&BA5{)J;_fHF0CCjcrhWsT70b@HAG#hE3chT!^|9m+=#f z{b_*zKR~XJ`ZV-?M@9obK<&U&)K9U1rtS+#3Nt(E3`(HdRkd<6)SIv)YMkyC?}xes zBT@In3e=@MjJi}$kQ3pb|1@)VZ&K8ml|p@LRl#jo9|vPdbN6XC4x=g0M74W~nmASq z_w)p##z~9%ju&C&QmA%SP?xF}rel7ur9ZiNH7KDBsI8#iDmYQPLu z&SmA2sGF{ul?R}9bhMQhpiX3U8=iknwA}&+Q7iii)!{yt!uP1Vyi{8^VKcL%*$=g) zBT+kf81*T43N`*Y)QMiT@>A5pU$ynQ4zZ)13CyI}jRt8@3mK1E*kV-2O{f9)S^NU( zj31cE+qr%f%@(Mqpg(G1Gf@kh>m#E9m!f|2#h}jMHR=r)*gnAj?{pPJz4@Brw>Sj# z*k$bCK06{%k5xI;W7h(;#UoJ*pN@LdF2kI7+Ty-fWC{`p`OFPa7S*9S>e}}}bsU3b za2@Im_&Zj@d>!3_`=L%`h&jRHvoJ*fA5NHs`c0kOo9{BR6F%=58EwTssEOa3NjkfD z1nRNOhnk>1>dabOeNWT^2cdRgDQXAzptkxjM&WVPj=sixn7fO1g6F>l88sM>YOo#E z;5UB*?t!lE5>!TQZCBJ5PQx6y)8h9qf^u*-*DgP*T_aSx5f)#A;grux=J)<2qtE}u z-JQ8n*Sad|rs-_u307W%x-`d8Z@^o~4tsM*8I|D(2x3A`e;9VqHrSDm@`vNB_P+^% zKr$7HCbP<3lyi{JgZCKlBI-Cv{sHNC@}sdQX%6iwQNNx1hhrMC&xz><{VkAtg1W&Z zeVG|!b5zBy`tL8-Q=zxkc~T-87bYDfrh7q0E7AhepSFlD<}KRoB>olY8wRUy1NX-i zw0T1P1;#mvf6?Y^>sOfiEu`y|r^RCbYmg~K+C=(}3SM&F64D{czmaqlC7xAr2Gj8; z`MTu!df+Xm&cFXqgZvY0WbMd$<%oqc&fnyBkXBk`5q z7HNp&vL4?u(rfZ7t^7A-eZuM}O1=>@45Ux?k4COdER6d6j5CsaUfLD;P)}?Pb-O6n zqfWPNM=leUY9?g(p+0WUGjBk zmx-jW_fIe@v9x%Sez%D6@#7^VeKC-J{}nG70Hig3i52vq+y2Pe`gv zhcWo!2%~Ka(lXlf{l=R?ULW}rY1fhzLi{eVF{IYy^)IgF zAN9>m+aF0!h>fQ{mY#nd>*=f?FdGRLAYbC6PP;5Wg!m#l$03y`zmBA1m&4;E|x zQmSK-={80~#{bv)Wv2aKy8eY}6t30c1Jk$#Lu@>5qx|6*VEIzS z|DxYROpB2=VP-r}8+~c|a5Sflj?~oo|J%ZT6spnaG!7-WnS3_VGbYqAj}BSL$F)H_ zn=@#mBM+$>Z64C*xeZKunAUB$4^ABCg~WlZltPKr#_i!JDW0wg`6RMZFQ?L6LrsNQw+0H*OYcUD8JJ4uVb_SPrlkwxr&N3q7~nzRmmZzx{N|Lh8io=HYQ`e3-@u zY;rZ-M7@r|#A=a0Ywg+*8$^B}eRUkC{-xDjCZCd6IV+ci zrlv`KM;NvlU0#qDDpA`SN7Fn2^&_nm`BS9(r01kZ#0QZ=Xj_T?dq_W$uR`0Kc#8Dl z*iYsV@!6yTw0naejxYFT>D6nMlV$VqXyZ#TC7-A5EgrEdS}G zrA4sS6tteI{oAJPN^Cgg+gQ}<R>@-|R`3Lf!Fi@mF>i#>W3DkW~xe)Q=*8XSI&&yDoK+U7* zpO|=Td_dcY_^-83gd0e`h$qpCYm=!+Do4jjxCMtZ*iU$YbcQx3DW9fOVbWg8jcu|C z)NiJbj_%mmWxb8G+2_B&Uy=K8{6;1|t;Shw!AEu5i02`_CRT@8`jX#E(lL&*jx(5+ zSmKXPwI*@BA$43PWhIqY!5uztmUULSw+;9jGm?rBo5Wz-X!9@moD395xjbpRwOxw^ zsjF|}}8#=!wtt5U0b-W@C zAb*#^XOPBIexVB5j3Hi=SXNT7wLff=sY!NHJ=*QIc_L}In%ElM#t{@o(|A7}yA%9^ z@*d*lZJ?%j+wxygcaAn6juVu1?4f=)sRQ|F`o1A8CWTnP5yU5u?@vsJUfLVz>lpKEZ=~IEu%co%3bMLmRM0MhnpK|Q-*kH(o@EYL%V(C%h>ookbg#OD(!0E zAe^cXkFsPM6R3;*7;HTDp;HS|9XgdHr6+xSjHQi^QN)v2-5T>a@#55ff~D1nV+3RU zi5LAP7DoLg@}mOyB`}Ohm($>cRbHjMg8X3`{b6UfRL=@Ow&VG_&{D@A)FvdKh!$@w z){-Ukq;53jTGZ=UN9;X*YRgN9Ip`DH`lw9{V#{o%b2yZ`GsM3lep3zXxT+u9I-1zv z7WcN%sRNxd&>XFBr{5y?s5njf_^4%tFR9nD0$tS+TfHbylj znf?Ebca(A;+ST|do|(LF5FO7_k@$bZ@kNM=&ZGu5gE|IBdjq;J7X%l{ETEWUg8FVt~5#^1vyF!C#^(FS<2&e9Q3JI|~V^*TRBjs;t z^R+c9Y2$6jdf)NKN*eB_;ac)BG66+Pt=JJ_+31sO zM&kBKeM>)DQeRq?vXZ_%6W3YmsfJSOQVMoLe*N~%oyiTWPY zZ6aSEzoMKI15if;Qd1^bN;wWGKZ8#p_Mg>vrmUkh)+TMG?Ex3^Vtx3Mq;fja7CLpX z4t;4DkJukfb`%qlbo@v8Fm0Z?qW{n7v^`3SL*0ktnk}HIxk&x2vO4)?bDvUIv{@(ourg2?qPb1`MRU*H!ud46<=1n@bsQ4>hex>4>ePUms#A8Sf6U zenI|!>czJ{n_#aEJjlw;C?6ngrPF>JveV6pknW$gZLQp}9O0e& zhWF^%FT8L6UcGwu>DQtCjGkLMZn|?Sq*$Vd+PU`p+WH< z&E5NG{N%ekrf>Zsen83cTX)q6_&zZF{|u>l9&FrsZ_yWbw@tY}Gv@x}k#m|B3uv~r KYpsCh8UG)-IWr9a diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index e36335bda..45b34a9d4 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: JumpServer 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-09-09 20:13+0800\n" +"POT-Creation-Date: 2021-09-10 16:13+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -60,8 +60,8 @@ msgstr "激活中" #: orgs/models.py:27 perms/models/base.py:53 settings/models.py:34 #: terminal/models/storage.py:26 terminal/models/terminal.py:114 #: tickets/models/ticket.py:71 users/models/group.py:16 -#: users/models/user.py:637 xpack/plugins/change_auth_plan/models.py:77 -#: xpack/plugins/cloud/models.py:35 xpack/plugins/cloud/models.py:108 +#: users/models/user.py:637 xpack/plugins/change_auth_plan/models.py:88 +#: xpack/plugins/cloud/models.py:35 xpack/plugins/cloud/models.py:113 #: xpack/plugins/gathered_user/models.py:26 msgid "Comment" msgstr "备注" @@ -125,8 +125,8 @@ msgstr "系统用户" #: terminal/backends/command/serializers.py:13 terminal/models/session.py:40 #: users/templates/users/user_asset_permission.html:40 #: users/templates/users/user_asset_permission.html:70 -#: xpack/plugins/change_auth_plan/models.py:282 -#: xpack/plugins/cloud/models.py:212 +#: xpack/plugins/change_auth_plan/models.py:315 +#: xpack/plugins/cloud/models.py:217 msgid "Asset" msgstr "资产" @@ -179,8 +179,8 @@ msgstr "格式为逗号分隔的字符串, * 表示匹配所有. " #: audits/models.py:105 authentication/forms.py:15 authentication/forms.py:17 #: ops/models/adhoc.py:148 users/forms/profile.py:31 users/models/user.py:602 #: users/templates/users/_select_user_modal.html:14 -#: xpack/plugins/change_auth_plan/models.py:47 -#: xpack/plugins/change_auth_plan/models.py:278 +#: xpack/plugins/change_auth_plan/models.py:51 +#: xpack/plugins/change_auth_plan/models.py:311 #: xpack/plugins/cloud/serializers.py:67 msgid "Username" msgstr "用户名" @@ -266,7 +266,7 @@ msgid "Version" msgstr "版本" #: applications/models/account.py:18 xpack/plugins/cloud/models.py:82 -#: xpack/plugins/cloud/serializers.py:204 +#: xpack/plugins/cloud/serializers.py:207 msgid "Account" msgstr "账户" @@ -287,7 +287,7 @@ msgstr "类别" #: assets/models/user.py:206 perms/models/application_permission.py:23 #: perms/serializers/application/user_permission.py:34 #: terminal/models/storage.py:55 terminal/models/storage.py:116 -#: tickets/models/flow.py:50 tickets/models/ticket.py:48 +#: tickets/models/flow.py:51 tickets/models/ticket.py:48 #: tickets/serializers/ticket/meta/ticket_type/apply_application.py:27 msgid "Type" msgstr "类型" @@ -370,9 +370,9 @@ msgstr "目标URL" #: users/templates/users/user_otp_check_password.html:13 #: users/templates/users/user_password_update.html:43 #: users/templates/users/user_password_verify.html:18 -#: xpack/plugins/change_auth_plan/models.py:68 -#: xpack/plugins/change_auth_plan/models.py:190 -#: xpack/plugins/change_auth_plan/models.py:285 +#: xpack/plugins/change_auth_plan/models.py:72 +#: xpack/plugins/change_auth_plan/models.py:207 +#: xpack/plugins/change_auth_plan/models.py:318 #: xpack/plugins/cloud/serializers.py:69 msgid "Password" msgstr "密码" @@ -425,13 +425,13 @@ msgstr "系统平台" #: assets/models/asset.py:186 assets/serializers/asset.py:65 #: perms/serializers/asset/user_permission.py:41 -#: xpack/plugins/cloud/models.py:99 xpack/plugins/cloud/serializers.py:183 +#: xpack/plugins/cloud/models.py:104 xpack/plugins/cloud/serializers.py:184 msgid "Protocols" msgstr "协议组" #: assets/models/asset.py:189 assets/models/user.py:198 #: perms/models/asset_permission.py:100 -#: xpack/plugins/change_auth_plan/models.py:56 +#: xpack/plugins/change_auth_plan/models.py:60 #: xpack/plugins/gathered_user/models.py:24 msgid "Nodes" msgstr "节点" @@ -444,7 +444,6 @@ msgstr "激活" #: assets/models/asset.py:193 assets/models/cluster.py:19 #: assets/models/user.py:195 assets/models/user.py:330 templates/_nav.html:44 -#: xpack/plugins/cloud/models.py:96 xpack/plugins/cloud/serializers.py:205 msgid "Admin user" msgstr "特权用户" @@ -521,8 +520,8 @@ msgstr "标签管理" #: assets/models/cmd_filter.py:67 assets/models/group.py:21 #: common/db/models.py:70 common/mixins/models.py:49 orgs/models.py:25 #: orgs/models.py:437 perms/models/base.py:51 users/models/user.py:645 -#: users/serializers/group.py:33 xpack/plugins/change_auth_plan/models.py:81 -#: xpack/plugins/cloud/models.py:114 xpack/plugins/gathered_user/models.py:30 +#: users/serializers/group.py:33 xpack/plugins/change_auth_plan/models.py:92 +#: xpack/plugins/cloud/models.py:119 xpack/plugins/gathered_user/models.py:30 msgid "Created by" msgstr "创建者" @@ -532,7 +531,7 @@ msgstr "创建者" #: assets/models/label.py:25 common/db/models.py:72 common/mixins/models.py:50 #: ops/models/adhoc.py:38 ops/models/command.py:29 orgs/models.py:26 #: orgs/models.py:435 perms/models/base.py:52 users/models/group.py:18 -#: users/models/user.py:836 xpack/plugins/cloud/models.py:117 +#: users/models/user.py:836 xpack/plugins/cloud/models.py:122 msgid "Date created" msgstr "创建日期" @@ -561,15 +560,15 @@ msgstr "可连接性" msgid "Date verified" msgstr "校验日期" -#: assets/models/base.py:178 xpack/plugins/change_auth_plan/models.py:72 -#: xpack/plugins/change_auth_plan/models.py:197 -#: xpack/plugins/change_auth_plan/models.py:292 +#: assets/models/base.py:178 xpack/plugins/change_auth_plan/models.py:82 +#: xpack/plugins/change_auth_plan/models.py:214 +#: xpack/plugins/change_auth_plan/models.py:325 msgid "SSH private key" msgstr "SSH密钥" -#: assets/models/base.py:179 xpack/plugins/change_auth_plan/models.py:75 -#: xpack/plugins/change_auth_plan/models.py:193 -#: xpack/plugins/change_auth_plan/models.py:288 +#: assets/models/base.py:179 xpack/plugins/change_auth_plan/models.py:85 +#: xpack/plugins/change_auth_plan/models.py:210 +#: xpack/plugins/change_auth_plan/models.py:321 msgid "SSH public key" msgstr "SSH公钥" @@ -727,7 +726,7 @@ msgstr "ssh私钥" #: users/templates/users/user_asset_permission.html:41 #: users/templates/users/user_asset_permission.html:73 #: users/templates/users/user_asset_permission.html:158 -#: xpack/plugins/cloud/models.py:93 xpack/plugins/cloud/serializers.py:206 +#: xpack/plugins/cloud/models.py:93 xpack/plugins/cloud/serializers.py:210 msgid "Node" msgstr "节点" @@ -748,7 +747,7 @@ msgid "Username same with user" msgstr "用户名与用户相同" #: assets/models/user.py:200 assets/serializers/domain.py:28 -#: templates/_nav.html:39 xpack/plugins/change_auth_plan/models.py:52 +#: templates/_nav.html:39 xpack/plugins/change_auth_plan/models.py:56 msgid "Assets" msgstr "资产" @@ -1077,8 +1076,8 @@ msgstr "成功" #: terminal/models/session.py:52 #: tickets/serializers/ticket/meta/ticket_type/apply_application.py:53 #: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:45 -#: xpack/plugins/change_auth_plan/models.py:177 -#: xpack/plugins/change_auth_plan/models.py:307 +#: xpack/plugins/change_auth_plan/models.py:194 +#: xpack/plugins/change_auth_plan/models.py:340 #: xpack/plugins/gathered_user/models.py:76 msgid "Date start" msgstr "开始日期" @@ -1150,13 +1149,13 @@ msgid "MFA" msgstr "多因子认证" #: audits/models.py:111 terminal/models/sharing.py:88 -#: xpack/plugins/change_auth_plan/models.py:303 -#: xpack/plugins/cloud/models.py:171 +#: xpack/plugins/change_auth_plan/models.py:336 +#: xpack/plugins/cloud/models.py:176 msgid "Reason" msgstr "原因" #: audits/models.py:112 tickets/models/ticket.py:57 -#: xpack/plugins/cloud/models.py:167 xpack/plugins/cloud/models.py:216 +#: xpack/plugins/cloud/models.py:172 xpack/plugins/cloud/models.py:221 msgid "Status" msgstr "状态" @@ -1190,7 +1189,7 @@ msgid "Hosts display" msgstr "主机名称" #: audits/serializers.py:89 ops/models/command.py:26 -#: xpack/plugins/cloud/models.py:165 +#: xpack/plugins/cloud/models.py:170 msgid "Result" msgstr "结果" @@ -1545,6 +1544,7 @@ msgid "" msgstr "账号已被锁定(请联系管理员解锁 或 {}分钟后重试)" #: authentication/errors.py:64 +#, python-brace-format msgid "" "One-time password invalid, or ntp sync server time, You can also try " "{times_try} times (The account will be temporarily locked for {block_time} " @@ -1554,20 +1554,25 @@ msgstr "" "临时 锁定 {block_time} 分钟)" #: authentication/errors.py:69 +#, python-brace-format msgid "" "SMS verify code invalid,You can also try {times_try} times (The account will " "be temporarily locked for {block_time} minutes)" msgstr "" -"短信验证码不正确,或者服务器端时间不对。 您还可以尝试 {times_try} 次(账号将被" -"临时 锁定 {block_time} 分钟)" +"短信验证码不正确,或者服务器端时间不对。 您还可以尝试 {times_try} 次(账号将" +"被临时 锁定 {block_time} 分钟)" #: authentication/errors.py:74 +#, fuzzy, python-brace-format +#| msgid "" +#| "The MFA type({mfa_type}) is not supported, You can also try {times_try} " +#| "times (The account will be temporarily locked for {block_time} minutes)" msgid "" -"The MFA type({mfa_type}) is not supported, You can also try {times_try} times " +"The MFA type({mfa_type}) is not supportedYou can also try {times_try} times " "(The account will be temporarily locked for {block_time} minutes)" msgstr "" -"该({mfa_type}) MFA 类型不支持。 您还可以尝试 {times_try} 次(账号将被" -"临时 锁定 {block_time} 分钟)" +"该({mfa_type}) MFA 类型不支持。 您还可以尝试 {times_try} 次(账号将被临时 锁" +"定 {block_time} 分钟)" #: authentication/errors.py:79 msgid "MFA required" @@ -1905,7 +1910,7 @@ msgstr "正在跳转到 {} 认证" msgid "Please enable cookies and try again." msgstr "设置你的浏览器支持cookie" -#: authentication/views/login.py:215 +#: authentication/views/login.py:217 msgid "" "Wait for {} confirm, You also can copy link to her/him
\n" " Don't close this page" @@ -1913,15 +1918,15 @@ msgstr "" "等待 {} 确认, 你也可以复制链接发给他/她
\n" " 不要关闭本页面" -#: authentication/views/login.py:220 +#: authentication/views/login.py:222 msgid "No ticket found" msgstr "没有发现工单" -#: authentication/views/login.py:252 +#: authentication/views/login.py:254 msgid "Logout success" msgstr "退出登录成功" -#: authentication/views/login.py:253 +#: authentication/views/login.py:255 msgid "Logout success, return login page" msgstr "退出登录成功,返回到登录页面" @@ -2062,11 +2067,15 @@ msgid "Invalid SMS sign and template: {}" msgstr "无效的短信签名和模版: {}" #: common/message/backends/sms/__init__.py:43 -msgid "Alibaba" +#, fuzzy +#| msgid "Alibaba Cloud" +msgid "Alibaba cloud" msgstr "阿里云" #: common/message/backends/sms/__init__.py:44 -msgid "Tencent" +#, fuzzy +#| msgid "Tencent Cloud" +msgid "Tencent cloud" msgstr "腾讯云" #: common/message/backends/sms/alibaba.py:56 @@ -2167,7 +2176,7 @@ msgid "Regularly perform" msgstr "定期执行" #: ops/mixin.py:106 ops/mixin.py:147 -#: xpack/plugins/change_auth_plan/serializers.py:55 +#: xpack/plugins/change_auth_plan/serializers.py:60 msgid "Periodic perform" msgstr "定时执行" @@ -2246,8 +2255,8 @@ msgstr "开始时间" msgid "End time" msgstr "完成时间" -#: ops/models/adhoc.py:246 xpack/plugins/change_auth_plan/models.py:180 -#: xpack/plugins/change_auth_plan/models.py:310 +#: ops/models/adhoc.py:246 xpack/plugins/change_auth_plan/models.py:197 +#: xpack/plugins/change_auth_plan/models.py:343 #: xpack/plugins/gathered_user/models.py:79 msgid "Time" msgstr "时间" @@ -2635,7 +2644,7 @@ msgstr "" "用户属性映射代表怎样将LDAP中用户属性映射到jumpserver用户上,username, name," "email 是jumpserver的用户需要属性" -#: settings/serializers/auth/ldap.py:58 xpack/plugins/cloud/serializers.py:207 +#: settings/serializers/auth/ldap.py:58 xpack/plugins/cloud/serializers.py:211 #: xpack/plugins/gathered_user/serializers.py:20 msgid "Periodic display" msgstr "定时执行" @@ -2753,26 +2762,27 @@ msgid "Enable SMS" msgstr "启用 SMS" #: settings/serializers/auth/sms.py:11 +#, fuzzy +#| msgid "Provider" +msgid "SMS provider" +msgstr "云服务商" + +#: settings/serializers/auth/sms.py:15 settings/serializers/email.py:69 +msgid "Signature" +msgstr "署名" + +#: settings/serializers/auth/sms.py:16 +msgid "Template" +msgstr "" + +#: settings/serializers/auth/sms.py:20 msgid "Test phone" msgstr "测试手机号" -#: settings/serializers/auth/sms.py:25 settings/serializers/auth/sms.py:43 +#: settings/serializers/auth/sms.py:37 settings/serializers/auth/sms.py:46 msgid "Signatures and Templates" msgstr "签名和模版" -#: settings/serializers/auth/sms.py:25 settings/serializers/auth/sms.py:43 -msgid "" -"\n" -" Filling in JSON Data: \n" -" {\n" -" \"verification_code\": {\n" -" \"sign_name\": \"\", \n" -" \"template_code\": \"\"\n" -" }\n" -" }\n" -" " -msgstr "" - #: settings/serializers/auth/sso.py:12 msgid "Enable SSO auth" msgstr "启用 SSO Token 认证" @@ -2933,10 +2943,6 @@ msgstr "邮件的内容" msgid "Tips:When creating a user, send the content of the email" msgstr "提示: 创建用户时,发送设置密码邮件的内容" -#: settings/serializers/email.py:69 -msgid "Signature" -msgstr "署名" - #: settings/serializers/email.py:70 msgid "Tips: Email signature (eg:jumpserver)" msgstr "邮件署名 (如:jumpserver)" @@ -3138,6 +3144,16 @@ msgstr "会话分享" msgid "Enabled, Allows user active session to be shared with other users" msgstr "开启后允许用户分享已连接的资产会话给它人,协同工作" +#: settings/serializers/security.py:115 +#, fuzzy +#| msgid "Login confirm" +msgid "Login Confirm" +msgstr "登录复核" + +#: settings/serializers/security.py:116 +msgid "After opening, please go to the personal information setting approver" +msgstr "开启后, 请前往个人信息设置审批人" + #: settings/serializers/sms.py:7 msgid "Label" msgstr "标签" @@ -3922,7 +3938,7 @@ msgstr "加入日期" msgid "Date left" msgstr "结束日期" -#: terminal/models/sharing.py:91 xpack/plugins/change_auth_plan/models.py:274 +#: terminal/models/sharing.py:91 xpack/plugins/change_auth_plan/models.py:307 msgid "Finished" msgstr "结束" @@ -4120,7 +4136,7 @@ msgstr "Secret key" msgid "Endpoint" msgstr "端点" -#: terminal/serializers/storage.py:66 xpack/plugins/cloud/models.py:209 +#: terminal/serializers/storage.py:66 xpack/plugins/cloud/models.py:214 msgid "Region" msgstr "地域" @@ -4363,28 +4379,28 @@ msgstr "用户显示名称" msgid "Body" msgstr "内容" -#: tickets/models/flow.py:19 tickets/models/flow.py:55 +#: tickets/models/flow.py:20 tickets/models/flow.py:56 #: tickets/models/ticket.py:25 msgid "Approve level" msgstr "审批级别" -#: tickets/models/flow.py:24 tickets/serializers/ticket/ticket.py:140 +#: tickets/models/flow.py:25 tickets/serializers/ticket/ticket.py:140 msgid "Approve strategy" msgstr "审批策略" -#: tickets/models/flow.py:29 tickets/serializers/ticket/ticket.py:141 +#: tickets/models/flow.py:30 tickets/serializers/ticket/ticket.py:141 msgid "Assignees" msgstr "受理人" -#: tickets/models/flow.py:33 +#: tickets/models/flow.py:34 msgid "Assignees display" msgstr "受理人名称" -#: tickets/models/flow.py:37 +#: tickets/models/flow.py:38 msgid "Ticket flow approval rule" msgstr "工单批准信息" -#: tickets/models/flow.py:60 +#: tickets/models/flow.py:61 msgid "Ticket flow" msgstr "工单流程" @@ -4706,6 +4722,7 @@ msgid "Reset password" msgstr "重置密码" #: users/notifications.py:44 +#, python-format msgid "" "\n" "Hello %(name)s:\n" @@ -4728,8 +4745,8 @@ msgid "" msgstr "" "\n" "您好 %(name)s:\n" -"请点击下面链接重置密码, 如果不是您申请的,请关注账号安全\n " -"\n" +"请点击下面链接重置密码, 如果不是您申请的,请关注账号安全\n" +" \n" "请点击这里设置密码 👇\n" "%(rest_password_url)s?token=%(rest_password_token)s\n" "\n" @@ -4745,6 +4762,7 @@ msgstr "" "\n" #: users/notifications.py:77 +#, python-format msgid "" "\n" " Hello %(name)s:\n" @@ -4793,6 +4811,7 @@ msgid "Reset password success" msgstr "重置密码成功" #: users/notifications.py:117 +#, python-format msgid "" "\n" " \n" @@ -4824,8 +4843,7 @@ msgstr "" "\n" "你的 JumpServer 密码刚刚已经成功更新。\n" "\n" -"如果这次密码更新不是由你发起的,那么你的账号可能存在安全问题。 " -"\n" +"如果这次密码更新不是由你发起的,那么你的账号可能存在安全问题。 \n" "建议你立刻登录 JumpServer 更改密码。 \n" "\n" "如果你有任何疑问,可以联系管理员。\n" @@ -4842,6 +4860,7 @@ msgstr "" " " #: users/notifications.py:151 +#, python-format msgid "" "\n" " \n" @@ -4908,6 +4927,7 @@ msgid "Security notice" msgstr "安全通知" #: users/notifications.py:195 +#, python-format msgid "" "\n" "Hello %(name)s:\n" @@ -4939,10 +4959,8 @@ msgstr "" "为了您的账号安全,请点击下面的链接及时更新密码 \n" "\n" "请点击这里更新密码 👇\n" -"%(update_password_url)s" -"\n" -"如果您的密码已经过期,请点击 👇 申请一份重置密码邮件。 " -"\n" +"%(update_password_url)s\n" +"如果您的密码已经过期,请点击 👇 申请一份重置密码邮件。 \n" "%(forget_password_url)s?email=%(email)s\n" "\n" "-------------------\n" @@ -4953,6 +4971,7 @@ msgstr "" " " #: users/notifications.py:231 +#, python-format msgid "" "\n" " Hello %(name)s:\n" @@ -5005,6 +5024,7 @@ msgid "Expiration notice" msgstr "过期通知" #: users/notifications.py:269 +#, python-format msgid "" "\n" "Hello %(name)s:\n" @@ -5021,11 +5041,11 @@ msgstr "" "\n" "您的账户会在 %(date_expired)s 过期,\n" "\n" -"为了不影响您正常工作,请联系管理员确认。" -"\n" +"为了不影响您正常工作,请联系管理员确认。\n" " " #: users/notifications.py:288 +#, python-format msgid "" "\n" " Hello %(name)s:\n" @@ -5051,6 +5071,7 @@ msgid "SSH Key Reset" msgstr "重置SSH密钥" #: users/notifications.py:309 +#, python-format msgid "" "\n" "Hello %(name)s:\n" @@ -5075,6 +5096,7 @@ msgstr "" " " #: users/notifications.py:330 +#, python-format msgid "" "\n" " Hello %(name)s:\n" @@ -5103,6 +5125,7 @@ msgid "MFA Reset" msgstr "重置 MFA" #: users/notifications.py:353 +#, python-format msgid "" "\n" "Hello %(name)s:\n" @@ -5127,6 +5150,7 @@ msgstr "" " " #: users/notifications.py:373 +#, python-format msgid "" "\n" " Hello %(name)s:\n" @@ -5170,8 +5194,8 @@ msgstr "两次密码不一致" msgid "Is first login" msgstr "首次登录" -#: users/serializers/user.py:22 xpack/plugins/change_auth_plan/models.py:61 -#: xpack/plugins/change_auth_plan/serializers.py:30 +#: users/serializers/user.py:22 xpack/plugins/change_auth_plan/models.py:65 +#: xpack/plugins/change_auth_plan/serializers.py:33 msgid "Password strategy" msgstr "密码策略" @@ -5561,89 +5585,153 @@ msgid "Reset password success, return to login page" msgstr "重置密码成功,返回到登录页面" #: xpack/plugins/change_auth_plan/meta.py:9 -#: xpack/plugins/change_auth_plan/models.py:89 -#: xpack/plugins/change_auth_plan/models.py:184 +#: xpack/plugins/change_auth_plan/models.py:100 +#: xpack/plugins/change_auth_plan/models.py:201 msgid "Change auth plan" msgstr "改密计划" -#: xpack/plugins/change_auth_plan/models.py:41 +#: xpack/plugins/change_auth_plan/models.py:40 msgid "Custom password" msgstr "自定义密码" -#: xpack/plugins/change_auth_plan/models.py:42 +#: xpack/plugins/change_auth_plan/models.py:41 msgid "All assets use the same random password" msgstr "使用相同的随机密码" -#: xpack/plugins/change_auth_plan/models.py:43 +#: xpack/plugins/change_auth_plan/models.py:42 msgid "All assets use different random password" msgstr "使用不同的随机密码" -#: xpack/plugins/change_auth_plan/models.py:65 +#: xpack/plugins/change_auth_plan/models.py:46 +msgid "Append SSH KEY" +msgstr "" + +#: xpack/plugins/change_auth_plan/models.py:47 +msgid "Empty and append SSH KEY" +msgstr "" + +#: xpack/plugins/change_auth_plan/models.py:48 +msgid "Empty current user and append SSH KEY" +msgstr "" + +#: xpack/plugins/change_auth_plan/models.py:69 msgid "Password rules" msgstr "密码规则" -#: xpack/plugins/change_auth_plan/models.py:187 +#: xpack/plugins/change_auth_plan/models.py:78 +#: xpack/plugins/change_auth_plan/serializers.py:35 +#, fuzzy +#| msgid "SSH Key Reset" +msgid "SSH Key strategy" +msgstr "重置SSH密钥" + +#: xpack/plugins/change_auth_plan/models.py:189 +msgid "Manual trigger" +msgstr "" + +#: xpack/plugins/change_auth_plan/models.py:190 +msgid "Timing trigger" +msgstr "" + +#: xpack/plugins/change_auth_plan/models.py:204 msgid "Change auth plan snapshot" msgstr "改密计划快照" -#: xpack/plugins/change_auth_plan/models.py:202 -#: xpack/plugins/change_auth_plan/models.py:296 +#: xpack/plugins/change_auth_plan/models.py:218 +#: xpack/plugins/change_auth_plan/serializers.py:166 +msgid "Trigger mode" +msgstr "" + +#: xpack/plugins/change_auth_plan/models.py:223 +#: xpack/plugins/change_auth_plan/models.py:329 msgid "Change auth plan execution" msgstr "改密计划执行" -#: xpack/plugins/change_auth_plan/models.py:269 +#: xpack/plugins/change_auth_plan/models.py:302 msgid "Ready" msgstr "准备" -#: xpack/plugins/change_auth_plan/models.py:270 +#: xpack/plugins/change_auth_plan/models.py:303 msgid "Preflight check" msgstr "改密前的校验" -#: xpack/plugins/change_auth_plan/models.py:271 +#: xpack/plugins/change_auth_plan/models.py:304 msgid "Change auth" msgstr "执行改密" -#: xpack/plugins/change_auth_plan/models.py:272 +#: xpack/plugins/change_auth_plan/models.py:305 msgid "Verify auth" msgstr "验证密码/密钥" -#: xpack/plugins/change_auth_plan/models.py:273 +#: xpack/plugins/change_auth_plan/models.py:306 msgid "Keep auth" msgstr "保存密码/密钥" -#: xpack/plugins/change_auth_plan/models.py:300 +#: xpack/plugins/change_auth_plan/models.py:333 msgid "Step" msgstr "步骤" -#: xpack/plugins/change_auth_plan/models.py:317 +#: xpack/plugins/change_auth_plan/models.py:350 msgid "Change auth plan task" msgstr "改密计划任务" -#: xpack/plugins/change_auth_plan/serializers.py:56 +#: xpack/plugins/change_auth_plan/serializers.py:29 +#, fuzzy +#| msgid "Password" +msgid "Change Password" +msgstr "密码" + +#: xpack/plugins/change_auth_plan/serializers.py:30 +#, fuzzy +#| msgid "Change by" +msgid "Change SSH Key" +msgstr "修改者" + +#: xpack/plugins/change_auth_plan/serializers.py:61 msgid "Run times" msgstr "执行次数" -#: xpack/plugins/change_auth_plan/serializers.py:72 -msgid "* Please enter custom password" -msgstr "* 请输入自定义密码" +#: xpack/plugins/change_auth_plan/serializers.py:79 +#, fuzzy +#| msgid "Require periodic or regularly perform setting" +msgid "Require password strategy perform setting" +msgstr "需要周期或定期设置" #: xpack/plugins/change_auth_plan/serializers.py:82 +#, fuzzy +#| msgid "Require periodic or regularly perform setting" +msgid "Require password perform setting" +msgstr "需要周期或定期设置" + +#: xpack/plugins/change_auth_plan/serializers.py:85 +#, fuzzy +#| msgid "Require periodic or regularly perform setting" +msgid "Require password rule perform setting" +msgstr "需要周期或定期设置" + +#: xpack/plugins/change_auth_plan/serializers.py:97 msgid "* Please enter the correct password length" msgstr "* 请输入正确的密码长度" -#: xpack/plugins/change_auth_plan/serializers.py:85 +#: xpack/plugins/change_auth_plan/serializers.py:100 msgid "* Password length range 6-30 bits" msgstr "* 密码长度范围 6-30 位" -#: xpack/plugins/change_auth_plan/utils.py:442 +#: xpack/plugins/change_auth_plan/serializers.py:118 +#, fuzzy +#| msgid "Require periodic or regularly perform setting" +msgid "Require ssh key strategy or ssh key perform setting" +msgstr "需要周期或定期设置" + +#: xpack/plugins/change_auth_plan/utils.py:485 msgid "Invalid/incorrect password" msgstr "无效/错误 密码" -#: xpack/plugins/change_auth_plan/utils.py:444 +#: xpack/plugins/change_auth_plan/utils.py:487 msgid "Failed to connect to the host" msgstr "连接主机失败" -#: xpack/plugins/change_auth_plan/utils.py:446 +#: xpack/plugins/change_auth_plan/utils.py:489 msgid "Data could not be sent to remote" msgstr "无法将数据发送到远程" @@ -5747,35 +5835,47 @@ msgstr "地域" msgid "Hostname strategy" msgstr "主机名策略" -#: xpack/plugins/cloud/models.py:102 xpack/plugins/cloud/serializers.py:186 +#: xpack/plugins/cloud/models.py:97 xpack/plugins/cloud/serializers.py:208 +#, fuzzy +#| msgid "Only admin users" +msgid "Unix admin user" +msgstr "仅管理员" + +#: xpack/plugins/cloud/models.py:101 xpack/plugins/cloud/serializers.py:209 +#, fuzzy +#| msgid "Only admin users" +msgid "Windows admin user" +msgstr "仅管理员" + +#: xpack/plugins/cloud/models.py:107 xpack/plugins/cloud/serializers.py:187 msgid "IP network segment group" msgstr "IP网段组" -#: xpack/plugins/cloud/models.py:105 xpack/plugins/cloud/serializers.py:208 +#: xpack/plugins/cloud/models.py:110 xpack/plugins/cloud/serializers.py:212 msgid "Always update" msgstr "总是更新" -#: xpack/plugins/cloud/models.py:111 +#: xpack/plugins/cloud/models.py:116 msgid "Date last sync" msgstr "最后同步日期" -#: xpack/plugins/cloud/models.py:122 xpack/plugins/cloud/models.py:163 +#: xpack/plugins/cloud/models.py:127 xpack/plugins/cloud/models.py:168 msgid "Sync instance task" msgstr "同步实例任务" -#: xpack/plugins/cloud/models.py:174 xpack/plugins/cloud/models.py:219 +#: xpack/plugins/cloud/models.py:179 xpack/plugins/cloud/models.py:224 msgid "Date sync" msgstr "同步日期" -#: xpack/plugins/cloud/models.py:199 +#: xpack/plugins/cloud/models.py:204 msgid "Sync task" msgstr "同步任务" -#: xpack/plugins/cloud/models.py:203 +#: xpack/plugins/cloud/models.py:208 msgid "Sync instance task history" msgstr "同步实例任务历史" -#: xpack/plugins/cloud/models.py:206 +#: xpack/plugins/cloud/models.py:211 msgid "Instance" msgstr "实例" @@ -6051,3 +6151,12 @@ msgstr "旗舰版" #: xpack/plugins/license/models.py:77 msgid "Community edition" msgstr "社区版" + +#~ msgid "Alibaba" +#~ msgstr "阿里云" + +#~ msgid "Tencent" +#~ msgstr "腾讯云" + +#~ msgid "* Please enter custom password" +#~ msgstr "* 请输入自定义密码" diff --git a/apps/settings/serializers/security.py b/apps/settings/serializers/security.py index 5749a5c8f..e2f8cb48d 100644 --- a/apps/settings/serializers/security.py +++ b/apps/settings/serializers/security.py @@ -111,5 +111,8 @@ class SecuritySettingSerializer(SecurityPasswordRuleSerializer, SecurityAuthSeri required=True, label=_('Session share'), help_text=_("Enabled, Allows user active session to be shared with other users") ) - + LOGIN_CONFIRM_ENABLE = serializers.BooleanField( + required=False, label=_('Login Confirm'), + help_text=_("After opening, please go to the personal information setting approver") + ) diff --git a/apps/tickets/models/flow.py b/apps/tickets/models/flow.py index 9f008f166..9542c4f2c 100644 --- a/apps/tickets/models/flow.py +++ b/apps/tickets/models/flow.py @@ -6,6 +6,7 @@ from django.utils.translation import ugettext_lazy as _ from common.mixins.models import CommonModelMixin from common.db.encoder import ModelJSONFieldEncoder from orgs.mixins.models import OrgModelMixin +from orgs.models import Organization from orgs.utils import tmp_to_root_org from ..const import TicketType, TicketApprovalLevel, TicketApprovalStrategy from ..signals import post_or_update_change_ticket_flow_approval @@ -67,5 +68,5 @@ class TicketFlow(CommonModelMixin, OrgModelMixin): flows = cls.objects.all() cur_flow_types = flows.values_list('type', flat=True) with tmp_to_root_org(): - diff_global_flows = cls.objects.exclude(type__in=cur_flow_types) + diff_global_flows = cls.objects.exclude(type__in=cur_flow_types).filter(org_id=Organization.ROOT_ID) return flows | diff_global_flows From 3e737c8cb8c221f761d45c4c6415a42170fab2ba Mon Sep 17 00:00:00 2001 From: xinwen Date: Fri, 10 Sep 2021 14:39:02 +0800 Subject: [PATCH 05/36] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=9F=AD?= =?UTF-8?q?=E4=BF=A1=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/message/backends/sms/__init__.py | 6 ++++++ apps/settings/serializers/auth/sms.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/common/message/backends/sms/__init__.py b/apps/common/message/backends/sms/__init__.py index af7a0e170..760b55407 100644 --- a/apps/common/message/backends/sms/__init__.py +++ b/apps/common/message/backends/sms/__init__.py @@ -67,6 +67,12 @@ class SMS: client: BaseSMSClient def __init__(self, backend=None): + backend = backend or settings.SMS_BACKEND + if backend not in BACKENDS: + raise JMSException( + code='sms_provider_not_support', + detail=_('SMS provider not support: {}').format(backend) + ) m = importlib.import_module(f'.{backend or settings.SMS_BACKEND}', __package__) self.client = m.client.new_from_settings() diff --git a/apps/settings/serializers/auth/sms.py b/apps/settings/serializers/auth/sms.py index 2e186c07b..ad63a9907 100644 --- a/apps/settings/serializers/auth/sms.py +++ b/apps/settings/serializers/auth/sms.py @@ -17,7 +17,7 @@ class SignAndTmplPairSerializer(serializers.Serializer): class BaseSMSSettingSerializer(serializers.Serializer): - SMS_TEST_PHONE = serializers.CharField(max_length=256, required=False, label=_('Test phone')) + SMS_TEST_PHONE = serializers.CharField(max_length=256, required=False, allow_blank=True, label=_('Test phone')) def to_representation(self, instance): data = super().to_representation(instance) From 7e6fa277193b97d8108c20bef34a0a79a6bb3081 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Fri, 10 Sep 2021 17:54:34 +0800 Subject: [PATCH 06/36] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E9=80=9A?= =?UTF-8?q?=E7=9F=A5=20(#6798)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * perf: 优化通知 * perf: 优化危险命令提示 * fix: i18n * fix: i18n Co-authored-by: ibuler Co-authored-by: Michael Bai --- apps/locale/zh/LC_MESSAGES/django.mo | Bin 93382 -> 94985 bytes apps/locale/zh/LC_MESSAGES/django.po | 462 +++++++++++++------------- apps/notifications/notifications.py | 9 +- apps/settings/serializers/security.py | 2 +- apps/terminal/notifications.py | 101 +++--- 5 files changed, 290 insertions(+), 284 deletions(-) diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index ab8fc5a7994ee8fa11e7d7012cfb0df67bd2f892..5217e3e638f0a8d329478dd58b805f0c1cb7cd86 100644 GIT binary patch delta 28693 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 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 45b34a9d4..7ed887ae4 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: JumpServer 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-09-10 16:13+0800\n" +"POT-Creation-Date: 2021-09-10 17:46+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -60,7 +60,7 @@ msgstr "激活中" #: orgs/models.py:27 perms/models/base.py:53 settings/models.py:34 #: terminal/models/storage.py:26 terminal/models/terminal.py:114 #: tickets/models/ticket.py:71 users/models/group.py:16 -#: users/models/user.py:637 xpack/plugins/change_auth_plan/models.py:88 +#: users/models/user.py:637 xpack/plugins/change_auth_plan/models/base.py:41 #: xpack/plugins/cloud/models.py:35 xpack/plugins/cloud/models.py:113 #: xpack/plugins/gathered_user/models.py:26 msgid "Comment" @@ -125,7 +125,7 @@ msgstr "系统用户" #: terminal/backends/command/serializers.py:13 terminal/models/session.py:40 #: users/templates/users/user_asset_permission.html:40 #: users/templates/users/user_asset_permission.html:70 -#: xpack/plugins/change_auth_plan/models.py:315 +#: xpack/plugins/change_auth_plan/models/asset.py:195 #: xpack/plugins/cloud/models.py:217 msgid "Asset" msgstr "资产" @@ -139,7 +139,7 @@ msgstr "审批人" msgid "Login asset confirm" msgstr "登录资产复核" -#: acls/serializers/login_acl.py:18 xpack/plugins/cloud/serializers.py:165 +#: acls/serializers/login_acl.py:18 xpack/plugins/cloud/serializers/task.py:23 msgid "IP address invalid: `{}`" msgstr "IP 地址无效: `{}`" @@ -179,9 +179,9 @@ msgstr "格式为逗号分隔的字符串, * 表示匹配所有. " #: audits/models.py:105 authentication/forms.py:15 authentication/forms.py:17 #: ops/models/adhoc.py:148 users/forms/profile.py:31 users/models/user.py:602 #: users/templates/users/_select_user_modal.html:14 -#: xpack/plugins/change_auth_plan/models.py:51 -#: xpack/plugins/change_auth_plan/models.py:311 -#: xpack/plugins/cloud/serializers.py:67 +#: xpack/plugins/change_auth_plan/models/asset.py:35 +#: xpack/plugins/change_auth_plan/models/asset.py:191 +#: xpack/plugins/cloud/serializers/account_attrs.py:62 msgid "Username" msgstr "用户名" @@ -234,6 +234,7 @@ msgstr "我的应用" #: applications/const.py:8 applications/models/account.py:10 #: applications/serializers/attrs/application_category/db.py:14 #: applications/serializers/attrs/application_type/mysql_workbench.py:26 +#: xpack/plugins/change_auth_plan/models/app.py:32 msgid "Database" msgstr "数据库" @@ -257,6 +258,8 @@ msgstr "自定义" #: users/templates/users/user_asset_permission.html:159 #: users/templates/users/user_database_app_permission.html:40 #: users/templates/users/user_database_app_permission.html:67 +#: xpack/plugins/change_auth_plan/models/app.py:36 +#: xpack/plugins/change_auth_plan/models/app.py:142 msgid "System user" msgstr "系统用户" @@ -266,7 +269,7 @@ msgid "Version" msgstr "版本" #: applications/models/account.py:18 xpack/plugins/cloud/models.py:82 -#: xpack/plugins/cloud/serializers.py:207 +#: xpack/plugins/cloud/serializers/task.py:65 msgid "Account" msgstr "账户" @@ -279,6 +282,7 @@ msgstr "应用管理" #: perms/models/application_permission.py:20 #: perms/serializers/application/user_permission.py:33 #: tickets/serializers/ticket/meta/ticket_type/apply_application.py:20 +#: xpack/plugins/change_auth_plan/models/app.py:25 msgid "Category" msgstr "类别" @@ -289,6 +293,8 @@ msgstr "类别" #: terminal/models/storage.py:55 terminal/models/storage.py:116 #: tickets/models/flow.py:51 tickets/models/ticket.py:48 #: tickets/serializers/ticket/meta/ticket_type/apply_application.py:27 +#: xpack/plugins/change_auth_plan/models/app.py:28 +#: xpack/plugins/change_auth_plan/models/app.py:148 msgid "Type" msgstr "类型" @@ -329,7 +335,7 @@ msgstr "集群" #: applications/serializers/attrs/application_category/db.py:11 #: ops/models/adhoc.py:146 settings/serializers/auth/radius.py:14 -#: xpack/plugins/cloud/serializers.py:65 +#: xpack/plugins/cloud/serializers/account_attrs.py:60 msgid "Host" msgstr "主机" @@ -339,7 +345,8 @@ msgstr "主机" #: applications/serializers/attrs/application_type/oracle.py:11 #: applications/serializers/attrs/application_type/pgsql.py:11 #: assets/models/asset.py:185 assets/models/domain.py:62 -#: settings/serializers/auth/radius.py:15 xpack/plugins/cloud/serializers.py:66 +#: settings/serializers/auth/radius.py:15 +#: xpack/plugins/cloud/serializers/account_attrs.py:61 msgid "Port" msgstr "端口" @@ -351,6 +358,7 @@ msgid "Application path" msgstr "应用路径" #: applications/serializers/attrs/application_category/remote_app.py:45 +#: xpack/plugins/cloud/serializers/account_attrs.py:44 msgid "This field is required." msgstr "该字段是必填项。" @@ -370,10 +378,10 @@ msgstr "目标URL" #: users/templates/users/user_otp_check_password.html:13 #: users/templates/users/user_password_update.html:43 #: users/templates/users/user_password_verify.html:18 -#: xpack/plugins/change_auth_plan/models.py:72 -#: xpack/plugins/change_auth_plan/models.py:207 -#: xpack/plugins/change_auth_plan/models.py:318 -#: xpack/plugins/cloud/serializers.py:69 +#: xpack/plugins/change_auth_plan/models/base.py:39 +#: xpack/plugins/change_auth_plan/models/base.py:114 +#: xpack/plugins/change_auth_plan/models/base.py:182 +#: xpack/plugins/cloud/serializers/account_attrs.py:64 msgid "Password" msgstr "密码" @@ -425,13 +433,13 @@ msgstr "系统平台" #: assets/models/asset.py:186 assets/serializers/asset.py:65 #: perms/serializers/asset/user_permission.py:41 -#: xpack/plugins/cloud/models.py:104 xpack/plugins/cloud/serializers.py:184 +#: xpack/plugins/cloud/models.py:104 xpack/plugins/cloud/serializers/task.py:42 msgid "Protocols" msgstr "协议组" #: assets/models/asset.py:189 assets/models/user.py:198 #: perms/models/asset_permission.py:100 -#: xpack/plugins/change_auth_plan/models.py:60 +#: xpack/plugins/change_auth_plan/models/asset.py:44 #: xpack/plugins/gathered_user/models.py:24 msgid "Nodes" msgstr "节点" @@ -520,7 +528,8 @@ msgstr "标签管理" #: assets/models/cmd_filter.py:67 assets/models/group.py:21 #: common/db/models.py:70 common/mixins/models.py:49 orgs/models.py:25 #: orgs/models.py:437 perms/models/base.py:51 users/models/user.py:645 -#: users/serializers/group.py:33 xpack/plugins/change_auth_plan/models.py:92 +#: users/serializers/group.py:33 +#: xpack/plugins/change_auth_plan/models/base.py:45 #: xpack/plugins/cloud/models.py:119 xpack/plugins/gathered_user/models.py:30 msgid "Created by" msgstr "创建者" @@ -548,7 +557,7 @@ msgid "Ok" msgstr "成功" #: assets/models/base.py:32 audits/models.py:102 -#: xpack/plugins/cloud/const.py:27 +#: xpack/plugins/cloud/const.py:28 msgid "Failed" msgstr "失败" @@ -560,15 +569,15 @@ msgstr "可连接性" msgid "Date verified" msgstr "校验日期" -#: assets/models/base.py:178 xpack/plugins/change_auth_plan/models.py:82 -#: xpack/plugins/change_auth_plan/models.py:214 -#: xpack/plugins/change_auth_plan/models.py:325 +#: assets/models/base.py:178 xpack/plugins/change_auth_plan/models/asset.py:54 +#: xpack/plugins/change_auth_plan/models/asset.py:126 +#: xpack/plugins/change_auth_plan/models/asset.py:202 msgid "SSH private key" msgstr "SSH密钥" -#: assets/models/base.py:179 xpack/plugins/change_auth_plan/models.py:85 -#: xpack/plugins/change_auth_plan/models.py:210 -#: xpack/plugins/change_auth_plan/models.py:321 +#: assets/models/base.py:179 xpack/plugins/change_auth_plan/models/asset.py:57 +#: xpack/plugins/change_auth_plan/models/asset.py:122 +#: xpack/plugins/change_auth_plan/models/asset.py:198 msgid "SSH public key" msgstr "SSH公钥" @@ -726,7 +735,7 @@ msgstr "ssh私钥" #: users/templates/users/user_asset_permission.html:41 #: users/templates/users/user_asset_permission.html:73 #: users/templates/users/user_asset_permission.html:158 -#: xpack/plugins/cloud/models.py:93 xpack/plugins/cloud/serializers.py:210 +#: xpack/plugins/cloud/models.py:93 xpack/plugins/cloud/serializers/task.py:68 msgid "Node" msgstr "节点" @@ -747,7 +756,7 @@ msgid "Username same with user" msgstr "用户名与用户相同" #: assets/models/user.py:200 assets/serializers/domain.py:28 -#: templates/_nav.html:39 xpack/plugins/change_auth_plan/models.py:56 +#: templates/_nav.html:39 xpack/plugins/change_auth_plan/models/asset.py:40 msgid "Assets" msgstr "资产" @@ -1076,8 +1085,8 @@ msgstr "成功" #: terminal/models/session.py:52 #: tickets/serializers/ticket/meta/ticket_type/apply_application.py:53 #: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:45 -#: xpack/plugins/change_auth_plan/models.py:194 -#: xpack/plugins/change_auth_plan/models.py:340 +#: xpack/plugins/change_auth_plan/models/base.py:105 +#: xpack/plugins/change_auth_plan/models/base.py:189 #: xpack/plugins/gathered_user/models.py:76 msgid "Date start" msgstr "开始日期" @@ -1149,7 +1158,7 @@ msgid "MFA" msgstr "多因子认证" #: audits/models.py:111 terminal/models/sharing.py:88 -#: xpack/plugins/change_auth_plan/models.py:336 +#: xpack/plugins/change_auth_plan/models/base.py:187 #: xpack/plugins/cloud/models.py:176 msgid "Reason" msgstr "原因" @@ -1563,15 +1572,12 @@ msgstr "" "被临时 锁定 {block_time} 分钟)" #: authentication/errors.py:74 -#, fuzzy, python-brace-format -#| msgid "" -#| "The MFA type({mfa_type}) is not supported, You can also try {times_try} " -#| "times (The account will be temporarily locked for {block_time} minutes)" +#, python-brace-format msgid "" "The MFA type({mfa_type}) is not supportedYou can also try {times_try} times " "(The account will be temporarily locked for {block_time} minutes)" msgstr "" -"该({mfa_type}) MFA 类型不支持。 您还可以尝试 {times_try} 次(账号将被临时 锁" +"该 ({mfa_type}) MFA 类型不支持。 您还可以尝试 {times_try} 次(账号将被临时 锁" "定 {block_time} 分钟)" #: authentication/errors.py:79 @@ -2067,17 +2073,17 @@ msgid "Invalid SMS sign and template: {}" msgstr "无效的短信签名和模版: {}" #: common/message/backends/sms/__init__.py:43 -#, fuzzy -#| msgid "Alibaba Cloud" msgid "Alibaba cloud" msgstr "阿里云" #: common/message/backends/sms/__init__.py:44 -#, fuzzy -#| msgid "Tencent Cloud" msgid "Tencent cloud" msgstr "腾讯云" +#: common/message/backends/sms/__init__.py:74 +msgid "SMS provider not support: {}" +msgstr "不支持 SMS 服务商: {}" + #: common/message/backends/sms/alibaba.py:56 msgid "Signature does not match" msgstr "签名不匹配" @@ -2176,7 +2182,7 @@ msgid "Regularly perform" msgstr "定期执行" #: ops/mixin.py:106 ops/mixin.py:147 -#: xpack/plugins/change_auth_plan/serializers.py:60 +#: xpack/plugins/change_auth_plan/serializers/base.py:42 msgid "Periodic perform" msgstr "定时执行" @@ -2255,8 +2261,8 @@ msgstr "开始时间" msgid "End time" msgstr "完成时间" -#: ops/models/adhoc.py:246 xpack/plugins/change_auth_plan/models.py:197 -#: xpack/plugins/change_auth_plan/models.py:343 +#: ops/models/adhoc.py:246 xpack/plugins/change_auth_plan/models/base.py:108 +#: xpack/plugins/change_auth_plan/models/base.py:190 #: xpack/plugins/gathered_user/models.py:79 msgid "Time" msgstr "时间" @@ -2644,7 +2650,8 @@ msgstr "" "用户属性映射代表怎样将LDAP中用户属性映射到jumpserver用户上,username, name," "email 是jumpserver的用户需要属性" -#: settings/serializers/auth/ldap.py:58 xpack/plugins/cloud/serializers.py:211 +#: settings/serializers/auth/ldap.py:58 +#: xpack/plugins/cloud/serializers/task.py:69 #: xpack/plugins/gathered_user/serializers.py:20 msgid "Periodic display" msgstr "定时执行" @@ -2669,7 +2676,8 @@ msgstr "JumpServer 地址" msgid "Client Id" msgstr "客户端 ID" -#: settings/serializers/auth/oidc.py:18 xpack/plugins/cloud/serializers.py:33 +#: settings/serializers/auth/oidc.py:18 +#: xpack/plugins/cloud/serializers/account_attrs.py:26 msgid "Client Secret" msgstr "客户端密钥" @@ -2762,10 +2770,8 @@ msgid "Enable SMS" msgstr "启用 SMS" #: settings/serializers/auth/sms.py:11 -#, fuzzy -#| msgid "Provider" msgid "SMS provider" -msgstr "云服务商" +msgstr "SMS 服务商" #: settings/serializers/auth/sms.py:15 settings/serializers/email.py:69 msgid "Signature" @@ -2773,7 +2779,7 @@ msgstr "署名" #: settings/serializers/auth/sms.py:16 msgid "Template" -msgstr "" +msgstr "模版" #: settings/serializers/auth/sms.py:20 msgid "Test phone" @@ -3145,14 +3151,12 @@ msgid "Enabled, Allows user active session to be shared with other users" msgstr "开启后允许用户分享已连接的资产会话给它人,协同工作" #: settings/serializers/security.py:115 -#, fuzzy -#| msgid "Login confirm" msgid "Login Confirm" msgstr "登录复核" #: settings/serializers/security.py:116 -msgid "After opening, please go to the personal information setting approver" -msgstr "开启后, 请前往个人信息设置审批人" +msgid "Enabled, please go to the user detail add approver" +msgstr "启用后, 请在用户详情中添加审批人" #: settings/serializers/sms.py:7 msgid "Label" @@ -3502,7 +3506,7 @@ msgstr "数据库应用" msgid "Perms" msgstr "权限管理" -#: templates/_nav.html:97 terminal/notifications.py:16 +#: templates/_nav.html:97 terminal/notifications.py:18 msgid "Sessions" msgstr "会话管理" @@ -3938,7 +3942,8 @@ msgstr "加入日期" msgid "Date left" msgstr "结束日期" -#: terminal/models/sharing.py:91 xpack/plugins/change_auth_plan/models.py:307 +#: terminal/models/sharing.py:91 +#: xpack/plugins/change_auth_plan/models/base.py:178 msgid "Finished" msgstr "结束" @@ -4010,52 +4015,45 @@ msgstr "命令存储" msgid "Replay storage" msgstr "录像存储" -#: terminal/notifications.py:50 +#: terminal/notifications.py:68 msgid "Danger command alert" msgstr "危险命令告警" -#: terminal/notifications.py:59 +#: terminal/notifications.py:81 #, python-format msgid "" "\n" -" Command: %(command)s\n" -"
\n" -" Asset: %(host_name)s (%(host_ip)s)\n" -"
\n" -" User: %(user)s\n" -"
\n" -" Level: %(risk_level)s\n" -"
\n" -" Session:
session " +" Command: %(command)s\n" +"
\n" +" Asset: %(hostname)s (%(host_ip)s)\n" +"
\n" +" User: %(user)s\n" +"
\n" +" Level: %(risk_level)s\n" +"
\n" +" Session:
session " "detail\n" -"
\n" -" " +"
\n" +" " msgstr "" "\n" " 命令: %(command)s\n" "
\n" -" 资产: %(host_name)s (%(host_ip)s)\n" +" 资产: %(hostname)s (%(host_ip)s)\n" "
\n" " 用户: %(user)s\n" "
\n" " 等级: %(risk_level)s\n" "
\n" -" 会话: 会话详情\n" +" 会话: 会话详情\n" "
\n" " " -#: terminal/notifications.py:99 -#, python-format -msgid "" -"Insecure Command Alert: [%(name)s->%(login_from)s@%(remote_addr)s] $" -"%(command)s" -msgstr "危险命令告警: [%(name)s->%(login_from)s@%(remote_addr)s] $%(command)s" - -#: terminal/notifications.py:117 +#: terminal/notifications.py:116 msgid "Batch danger command alert" msgstr "批量危险命令告警" -#: terminal/notifications.py:128 +#: terminal/notifications.py:127 #, python-format msgid "" "\n" @@ -4080,17 +4078,13 @@ msgstr "" "
\n" " 等级: %(risk_level)s\n" "
\n" -"\n" +"
\n" " ----------------- 命令 ----------------
\n" " %(command)s
\n" " ----------------- 命令 ----------------
\n" +"
\n" " " -#: terminal/notifications.py:150 -#, python-format -msgid "Insecure Web Command Execution Alert: [%(name)s]" -msgstr "批量危险命令告警: [%(name)s]" - #: terminal/serializers/session.py:31 msgid "User ID" msgstr "用户 ID" @@ -5194,8 +5188,9 @@ msgstr "两次密码不一致" msgid "Is first login" msgstr "首次登录" -#: users/serializers/user.py:22 xpack/plugins/change_auth_plan/models.py:65 -#: xpack/plugins/change_auth_plan/serializers.py:33 +#: users/serializers/user.py:22 +#: xpack/plugins/change_auth_plan/models/base.py:32 +#: xpack/plugins/change_auth_plan/serializers/base.py:24 msgid "Password strategy" msgstr "密码策略" @@ -5584,154 +5579,163 @@ msgstr "* 新密码不能是最近 {} 次的密码" msgid "Reset password success, return to login page" msgstr "重置密码成功,返回到登录页面" +#: xpack/plugins/change_auth_plan/api/app.py:112 +#: xpack/plugins/change_auth_plan/api/asset.py:100 +msgid "The parameter 'action' must be [{}]" +msgstr "参数 'action' 必须是 [{}]" + #: xpack/plugins/change_auth_plan/meta.py:9 -#: xpack/plugins/change_auth_plan/models.py:100 -#: xpack/plugins/change_auth_plan/models.py:201 +#: xpack/plugins/change_auth_plan/models/asset.py:63 +#: xpack/plugins/change_auth_plan/models/asset.py:119 msgid "Change auth plan" msgstr "改密计划" -#: xpack/plugins/change_auth_plan/models.py:40 -msgid "Custom password" -msgstr "自定义密码" +#: xpack/plugins/change_auth_plan/models/app.py:41 +#: xpack/plugins/change_auth_plan/models/app.py:90 +msgid "Application change auth plan" +msgstr "应用改密计划执行" -#: xpack/plugins/change_auth_plan/models.py:41 -msgid "All assets use the same random password" -msgstr "使用相同的随机密码" +#: xpack/plugins/change_auth_plan/models/app.py:94 +#: xpack/plugins/change_auth_plan/models/app.py:146 +msgid "Application change auth plan execution" +msgstr "应用改密计划执行" -#: xpack/plugins/change_auth_plan/models.py:42 -msgid "All assets use different random password" -msgstr "使用不同的随机密码" +#: xpack/plugins/change_auth_plan/models/app.py:139 +msgid "App" +msgstr "应用" -#: xpack/plugins/change_auth_plan/models.py:46 +#: xpack/plugins/change_auth_plan/models/app.py:151 +msgid "Application change auth plan task" +msgstr "用用改密计划任务" + +#: xpack/plugins/change_auth_plan/models/asset.py:30 msgid "Append SSH KEY" -msgstr "" +msgstr "追加" -#: xpack/plugins/change_auth_plan/models.py:47 +#: xpack/plugins/change_auth_plan/models/asset.py:31 msgid "Empty and append SSH KEY" -msgstr "" +msgstr "清空所有并添加" -#: xpack/plugins/change_auth_plan/models.py:48 -msgid "Empty current user and append SSH KEY" -msgstr "" +#: xpack/plugins/change_auth_plan/models/asset.py:32 +msgid "Empty pre add and append SSH KEY" +msgstr "清空上次并添加" -#: xpack/plugins/change_auth_plan/models.py:69 -msgid "Password rules" -msgstr "密码规则" - -#: xpack/plugins/change_auth_plan/models.py:78 -#: xpack/plugins/change_auth_plan/serializers.py:35 -#, fuzzy -#| msgid "SSH Key Reset" +#: xpack/plugins/change_auth_plan/models/asset.py:50 +#: xpack/plugins/change_auth_plan/serializers/asset.py:34 msgid "SSH Key strategy" -msgstr "重置SSH密钥" +msgstr "SSH 密钥策略" -#: xpack/plugins/change_auth_plan/models.py:189 -msgid "Manual trigger" -msgstr "" - -#: xpack/plugins/change_auth_plan/models.py:190 -msgid "Timing trigger" -msgstr "" - -#: xpack/plugins/change_auth_plan/models.py:204 -msgid "Change auth plan snapshot" -msgstr "改密计划快照" - -#: xpack/plugins/change_auth_plan/models.py:218 -#: xpack/plugins/change_auth_plan/serializers.py:166 -msgid "Trigger mode" -msgstr "" - -#: xpack/plugins/change_auth_plan/models.py:223 -#: xpack/plugins/change_auth_plan/models.py:329 +#: xpack/plugins/change_auth_plan/models/asset.py:130 +#: xpack/plugins/change_auth_plan/models/asset.py:206 msgid "Change auth plan execution" msgstr "改密计划执行" -#: xpack/plugins/change_auth_plan/models.py:302 -msgid "Ready" -msgstr "准备" - -#: xpack/plugins/change_auth_plan/models.py:303 -msgid "Preflight check" -msgstr "改密前的校验" - -#: xpack/plugins/change_auth_plan/models.py:304 -msgid "Change auth" -msgstr "执行改密" - -#: xpack/plugins/change_auth_plan/models.py:305 -msgid "Verify auth" -msgstr "验证密码/密钥" - -#: xpack/plugins/change_auth_plan/models.py:306 -msgid "Keep auth" -msgstr "保存密码/密钥" - -#: xpack/plugins/change_auth_plan/models.py:333 -msgid "Step" -msgstr "步骤" - -#: xpack/plugins/change_auth_plan/models.py:350 +#: xpack/plugins/change_auth_plan/models/asset.py:213 msgid "Change auth plan task" msgstr "改密计划任务" -#: xpack/plugins/change_auth_plan/serializers.py:29 -#, fuzzy -#| msgid "Password" +#: xpack/plugins/change_auth_plan/models/base.py:24 +msgid "Custom password" +msgstr "自定义密码" + +#: xpack/plugins/change_auth_plan/models/base.py:25 +msgid "All assets use the same random password" +msgstr "使用相同的随机密码" + +#: xpack/plugins/change_auth_plan/models/base.py:26 +msgid "All assets use different random password" +msgstr "使用不同的随机密码" + +#: xpack/plugins/change_auth_plan/models/base.py:36 +msgid "Password rules" +msgstr "密码规则" + +#: xpack/plugins/change_auth_plan/models/base.py:100 +msgid "Manual trigger" +msgstr "手动触发" + +#: xpack/plugins/change_auth_plan/models/base.py:101 +msgid "Timing trigger" +msgstr "定时触发" + +#: xpack/plugins/change_auth_plan/models/base.py:111 +msgid "Change auth plan snapshot" +msgstr "改密计划快照" + +#: xpack/plugins/change_auth_plan/models/base.py:118 +#: xpack/plugins/change_auth_plan/serializers/base.py:70 +msgid "Trigger mode" +msgstr "触发模式" + +#: xpack/plugins/change_auth_plan/models/base.py:173 +msgid "Ready" +msgstr "准备" + +#: xpack/plugins/change_auth_plan/models/base.py:174 +msgid "Preflight check" +msgstr "改密前的校验" + +#: xpack/plugins/change_auth_plan/models/base.py:175 +msgid "Change auth" +msgstr "执行改密" + +#: xpack/plugins/change_auth_plan/models/base.py:176 +msgid "Verify auth" +msgstr "验证密码/密钥" + +#: xpack/plugins/change_auth_plan/models/base.py:177 +msgid "Keep auth" +msgstr "保存密码/密钥" + +#: xpack/plugins/change_auth_plan/models/base.py:185 +msgid "Step" +msgstr "步骤" + +#: xpack/plugins/change_auth_plan/serializers/asset.py:31 msgid "Change Password" -msgstr "密码" +msgstr "更改密码" -#: xpack/plugins/change_auth_plan/serializers.py:30 -#, fuzzy -#| msgid "Change by" +#: xpack/plugins/change_auth_plan/serializers/asset.py:32 msgid "Change SSH Key" -msgstr "修改者" +msgstr "修改 SSH Key" -#: xpack/plugins/change_auth_plan/serializers.py:61 +#: xpack/plugins/change_auth_plan/serializers/asset.py:65 +msgid "Require password strategy perform setting" +msgstr "需要密码策略设置" + +#: xpack/plugins/change_auth_plan/serializers/asset.py:68 +msgid "Require password perform setting" +msgstr "需要密码设置" + +#: xpack/plugins/change_auth_plan/serializers/asset.py:71 +msgid "Require password rule perform setting" +msgstr "需要密码规则设置" + +#: xpack/plugins/change_auth_plan/serializers/asset.py:87 +msgid "Require ssh key strategy or ssh key perform setting" +msgstr "需要 ssh key 策略 配置" + +#: xpack/plugins/change_auth_plan/serializers/base.py:43 msgid "Run times" msgstr "执行次数" -#: xpack/plugins/change_auth_plan/serializers.py:79 -#, fuzzy -#| msgid "Require periodic or regularly perform setting" -msgid "Require password strategy perform setting" -msgstr "需要周期或定期设置" - -#: xpack/plugins/change_auth_plan/serializers.py:82 -#, fuzzy -#| msgid "Require periodic or regularly perform setting" -msgid "Require password perform setting" -msgstr "需要周期或定期设置" - -#: xpack/plugins/change_auth_plan/serializers.py:85 -#, fuzzy -#| msgid "Require periodic or regularly perform setting" -msgid "Require password rule perform setting" -msgstr "需要周期或定期设置" - -#: xpack/plugins/change_auth_plan/serializers.py:97 +#: xpack/plugins/change_auth_plan/serializers/base.py:54 msgid "* Please enter the correct password length" msgstr "* 请输入正确的密码长度" -#: xpack/plugins/change_auth_plan/serializers.py:100 +#: xpack/plugins/change_auth_plan/serializers/base.py:57 msgid "* Password length range 6-30 bits" msgstr "* 密码长度范围 6-30 位" -#: xpack/plugins/change_auth_plan/serializers.py:118 -#, fuzzy -#| msgid "Require periodic or regularly perform setting" -msgid "Require ssh key strategy or ssh key perform setting" -msgstr "需要周期或定期设置" - -#: xpack/plugins/change_auth_plan/utils.py:485 +#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:248 msgid "Invalid/incorrect password" msgstr "无效/错误 密码" -#: xpack/plugins/change_auth_plan/utils.py:487 +#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:250 msgid "Failed to connect to the host" msgstr "连接主机失败" -#: xpack/plugins/change_auth_plan/utils.py:489 +#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:252 msgid "Data could not be sent to remote" msgstr "无法将数据发送到远程" @@ -5787,31 +5791,35 @@ msgstr "华为私有云" msgid "Qingyun Private Cloud" msgstr "青云私有云" -#: xpack/plugins/cloud/const.py:22 +#: xpack/plugins/cloud/const.py:19 +msgid "Google Cloud Platform" +msgstr "谷歌云" + +#: xpack/plugins/cloud/const.py:23 msgid "Instance name" msgstr "实例名称" -#: xpack/plugins/cloud/const.py:23 +#: xpack/plugins/cloud/const.py:24 msgid "Instance name and Partial IP" msgstr "实例名称和部分IP" -#: xpack/plugins/cloud/const.py:28 +#: xpack/plugins/cloud/const.py:29 msgid "Succeed" msgstr "成功" -#: xpack/plugins/cloud/const.py:32 +#: xpack/plugins/cloud/const.py:33 msgid "Unsync" msgstr "未同步" -#: xpack/plugins/cloud/const.py:33 +#: xpack/plugins/cloud/const.py:34 msgid "New Sync" msgstr "新同步" -#: xpack/plugins/cloud/const.py:34 +#: xpack/plugins/cloud/const.py:35 msgid "Synced" msgstr "已同步" -#: xpack/plugins/cloud/const.py:35 +#: xpack/plugins/cloud/const.py:36 msgid "Released" msgstr "已释放" @@ -5827,7 +5835,7 @@ msgstr "云服务商" msgid "Cloud account" msgstr "云账号" -#: xpack/plugins/cloud/models.py:85 xpack/plugins/cloud/serializers.py:179 +#: xpack/plugins/cloud/models.py:85 xpack/plugins/cloud/serializers/task.py:37 msgid "Regions" msgstr "地域" @@ -5835,23 +5843,19 @@ msgstr "地域" msgid "Hostname strategy" msgstr "主机名策略" -#: xpack/plugins/cloud/models.py:97 xpack/plugins/cloud/serializers.py:208 -#, fuzzy -#| msgid "Only admin users" +#: xpack/plugins/cloud/models.py:97 xpack/plugins/cloud/serializers/task.py:66 msgid "Unix admin user" -msgstr "仅管理员" +msgstr "Unix 管理员" -#: xpack/plugins/cloud/models.py:101 xpack/plugins/cloud/serializers.py:209 -#, fuzzy -#| msgid "Only admin users" +#: xpack/plugins/cloud/models.py:101 xpack/plugins/cloud/serializers/task.py:67 msgid "Windows admin user" -msgstr "仅管理员" +msgstr "Windows 管理员" -#: xpack/plugins/cloud/models.py:107 xpack/plugins/cloud/serializers.py:187 +#: xpack/plugins/cloud/models.py:107 xpack/plugins/cloud/serializers/task.py:45 msgid "IP network segment group" msgstr "IP网段组" -#: xpack/plugins/cloud/models.py:110 xpack/plugins/cloud/serializers.py:212 +#: xpack/plugins/cloud/models.py:110 xpack/plugins/cloud/serializers/task.py:70 msgid "Always update" msgstr "总是更新" @@ -6019,35 +6023,40 @@ msgstr "西南-贵阳1" msgid "EU-Paris" msgstr "欧洲-巴黎" -#: xpack/plugins/cloud/serializers.py:21 +#: xpack/plugins/cloud/serializers/account_attrs.py:13 msgid "AccessKey ID" msgstr "" -#: xpack/plugins/cloud/serializers.py:24 +#: xpack/plugins/cloud/serializers/account_attrs.py:16 msgid "AccessKey Secret" msgstr "" -#: xpack/plugins/cloud/serializers.py:30 +#: xpack/plugins/cloud/serializers/account_attrs.py:23 msgid "Client ID" msgstr "客户端 ID" -#: xpack/plugins/cloud/serializers.py:36 +#: xpack/plugins/cloud/serializers/account_attrs.py:29 msgid "Tenant ID" msgstr "租户 ID" -#: xpack/plugins/cloud/serializers.py:39 +#: xpack/plugins/cloud/serializers/account_attrs.py:32 msgid "Subscription ID" msgstr "订阅 ID" -#: xpack/plugins/cloud/serializers.py:51 -msgid "This field is required" -msgstr "该字段是必填项。" - -#: xpack/plugins/cloud/serializers.py:85 xpack/plugins/cloud/serializers.py:89 +#: xpack/plugins/cloud/serializers/account_attrs.py:81 +#: xpack/plugins/cloud/serializers/account_attrs.py:86 msgid "API Endpoint" msgstr "API 端点" -#: xpack/plugins/cloud/serializers.py:171 +#: xpack/plugins/cloud/serializers/account_attrs.py:92 +msgid "Service account key" +msgstr "账户密钥" + +#: xpack/plugins/cloud/serializers/account_attrs.py:93 +msgid "The file is in JSON format" +msgstr "JSON 格式的文件" + +#: xpack/plugins/cloud/serializers/task.py:29 msgid "" "The IP address that is first matched to will be used as the IP of the " "created asset.
The default * indicates a random match.
Format for " @@ -6056,11 +6065,11 @@ msgstr "" "第一个匹配到的 IP 地址将被用作创建的资产的 IP。
默认值 * 表示随机匹配。" "
格式为以逗号分隔的字符串,例如:192.168.1.0/24,10.1.1.1-10.1.1.20" -#: xpack/plugins/cloud/serializers.py:177 +#: xpack/plugins/cloud/serializers/task.py:35 msgid "History count" msgstr "执行次数" -#: xpack/plugins/cloud/serializers.py:178 +#: xpack/plugins/cloud/serializers/task.py:36 msgid "Instance count" msgstr "实例个数" @@ -6157,6 +6166,3 @@ msgstr "社区版" #~ msgid "Tencent" #~ msgstr "腾讯云" - -#~ msgid "* Please enter custom password" -#~ msgstr "* 请输入自定义密码" diff --git a/apps/notifications/notifications.py b/apps/notifications/notifications.py index 1141c104f..97ff30469 100644 --- a/apps/notifications/notifications.py +++ b/apps/notifications/notifications.py @@ -1,7 +1,6 @@ from typing import Iterable import traceback from itertools import chain -from collections import defaultdict from celery import shared_task @@ -90,6 +89,11 @@ class Message(metaclass=MessageType): except: traceback.print_exc() + def send_test_msg(self): + from users.models import User + users = User.objects.filter(username='admin') + self.send_msg(users, []) + def get_common_msg(self) -> dict: raise NotImplementedError @@ -115,7 +119,7 @@ class Message(metaclass=MessageType): return self.common_msg def get_sms_msg(self) -> dict: - raise NotImplementedError + return self.common_msg # -------------------------------------------------------------- @@ -136,6 +140,7 @@ class SystemMessage(Message): self.send_msg(users, receive_backends) + @classmethod def post_insert_to_db(cls, subscription: SystemMsgSubscription): pass diff --git a/apps/settings/serializers/security.py b/apps/settings/serializers/security.py index e2f8cb48d..1681b08a3 100644 --- a/apps/settings/serializers/security.py +++ b/apps/settings/serializers/security.py @@ -113,6 +113,6 @@ class SecuritySettingSerializer(SecurityPasswordRuleSerializer, SecurityAuthSeri ) LOGIN_CONFIRM_ENABLE = serializers.BooleanField( required=False, label=_('Login Confirm'), - help_text=_("After opening, please go to the personal information setting approver") + help_text=_("Enabled, please go to the user detail add approver") ) diff --git a/apps/terminal/notifications.py b/apps/terminal/notifications.py index 46ac5b18d..22e1acf6d 100644 --- a/apps/terminal/notifications.py +++ b/apps/terminal/notifications.py @@ -1,3 +1,5 @@ +from typing import Callable + from django.utils.translation import gettext_lazy as _ from django.conf import settings @@ -17,19 +19,35 @@ CATEGORY_LABEL = _('Sessions') class CommandAlertMixin: + command: dict + _get_message: Callable + message_type_label: str + def get_dingtalk_msg(self) -> str: msg = self._get_message() msg = msg.replace('
', '') return msg + def get_subject(self): + _input = self.command['input'] + if isinstance(_input, str): + _input = _input.replace('\r\n', ' ').replace('\r', ' ').replace('\n', ' ') + + subject = self.message_type_label + "%(cmd)s" % { + 'cmd': _input + } + return subject + @classmethod def post_insert_to_db(cls, subscription: SystemMsgSubscription): """ - 兼容操作,试图用 `settings.SECURITY_INSECURE_COMMAND_EMAIL_RECEIVER` 的邮件地址assets_systemuser_assets找到 - 用户,把用户设置为默认接收者 + 兼容操作,试图用 `settings.SECURITY_INSECURE_COMMAND_EMAIL_RECEIVER` 的邮件地址 + assets_systemuser_assets找到用户,把用户设置为默认接收者 """ from settings.models import Setting - db_setting = Setting.objects.filter(name='SECURITY_INSECURE_COMMAND_EMAIL_RECEIVER').first() + db_setting = Setting.objects.filter( + name='SECURITY_INSECURE_COMMAND_EMAIL_RECEIVER' + ).first() if db_setting: emails = db_setting.value else: @@ -54,60 +72,41 @@ class CommandAlertMessage(CommandAlertMixin, SystemMessage): def _get_message(self): command = self.command - session_obj = Session.objects.get(id=command['session']) + session = Session.objects.get(id=command['session']) + session_detail_url = reverse( + 'api-terminal:session-detail', kwargs={'pk': command['session']}, + external=True, api_to_ui=True + ) message = _(""" - Command: %(command)s -
- Asset: %(host_name)s (%(host_ip)s) -
- User: %(user)s -
- Level: %(risk_level)s -
- Session: session detail -
- """) % { + Command: %(command)s +
+ Asset: %(hostname)s (%(host_ip)s) +
+ User: %(user)s +
+ Level: %(risk_level)s +
+ Session: session detail +
+ """) % { 'command': command['input'], - 'host_name': command['asset'], - 'host_ip': session_obj.asset_obj.ip, + 'hostname': command['asset'], + 'host_ip': session.asset_obj.ip, 'user': command['user'], 'risk_level': Command.get_risk_level_str(command['risk_level']), - 'session_detail_url': reverse('api-terminal:session-detail', - kwargs={'pk': command['session']}, - external=True, api_to_ui=True), + 'session_detail_url': session_detail_url, + 'oid': session.org_id } - return message def get_common_msg(self): msg = self._get_message() - - return { - 'subject': msg[:80], - 'message': msg - } - - def get_email_msg(self): - command = self.command - session_obj = Session.objects.get(id=command['session']) - - input = command['input'] - if isinstance(input, str): - input = input.replace('\r\n', ' ').replace('\r', ' ').replace('\n', ' ') - - subject = _("Insecure Command Alert: [%(name)s->%(login_from)s@%(remote_addr)s] $%(command)s") % { - 'name': command['user'], - 'login_from': session_obj.get_login_from_display(), - 'remote_addr': session_obj.remote_addr, - 'command': input - } - - message = self._get_message() + subject = self.get_subject() return { 'subject': subject, - 'message': message + 'message': msg } @@ -121,8 +120,8 @@ class CommandExecutionAlert(CommandAlertMixin, SystemMessage): def _get_message(self): command = self.command - input = command['input'] - input = input.replace('\n', '
') + _input = command['input'] + _input = _input.replace('\n', '
') assets = ', '.join([str(asset) for asset in command['assets']]) message = _(""" @@ -137,19 +136,15 @@ class CommandExecutionAlert(CommandAlertMixin, SystemMessage): %(command)s
----------------- Commands ----------------
""") % { - 'command': input, + 'command': _input, 'assets': assets, 'user': command['user'], - 'risk_level': Command.get_risk_level_str(command['risk_level']), + 'risk_level': Command.get_risk_level_str(command['risk_level']) } return message def get_common_msg(self): - command = self.command - - subject = _("Insecure Web Command Execution Alert: [%(name)s]") % { - 'name': command['user'], - } + subject = self.get_subject() message = self._get_message() return { From fa81652de504c064f4e199718c22b9be6d688c7b Mon Sep 17 00:00:00 2001 From: Michael Bai Date: Fri, 10 Sep 2021 12:53:51 +0800 Subject: [PATCH 07/36] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=E6=8E=88?= =?UTF-8?q?=E6=9D=83=E4=B8=AD(=E8=B5=84=E4=BA=A7/=E5=BA=94=E7=94=A8)?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E7=94=A8=E6=88=B7=E5=AD=97=E6=AE=B5=E4=B8=8D?= =?UTF-8?q?=E5=BF=85=E5=A1=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0020_auto_20210910_1103.py | 24 +++++++++++++++++++ apps/perms/models/application_permission.py | 3 ++- apps/perms/models/asset_permission.py | 2 +- 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 apps/perms/migrations/0020_auto_20210910_1103.py diff --git a/apps/perms/migrations/0020_auto_20210910_1103.py b/apps/perms/migrations/0020_auto_20210910_1103.py new file mode 100644 index 000000000..0d01345f5 --- /dev/null +++ b/apps/perms/migrations/0020_auto_20210910_1103.py @@ -0,0 +1,24 @@ +# Generated by Django 3.1.12 on 2021-09-10 03:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('assets', '0076_delete_assetuser'), + ('perms', '0019_auto_20210906_1044'), + ] + + operations = [ + migrations.AlterField( + model_name='assetpermission', + name='system_users', + field=models.ManyToManyField(blank=True, related_name='granted_by_permissions', to='assets.SystemUser', verbose_name='System user'), + ), + migrations.AlterField( + model_name='applicationpermission', + name='system_users', + field=models.ManyToManyField(blank=True, related_name='granted_by_application_permissions', to='assets.SystemUser', verbose_name='System user'), + ), + ] diff --git a/apps/perms/models/application_permission.py b/apps/perms/models/application_permission.py index a405e667c..40ac61ed8 100644 --- a/apps/perms/models/application_permission.py +++ b/apps/perms/models/application_permission.py @@ -27,7 +27,8 @@ class ApplicationPermission(BasePermission): verbose_name=_("Application") ) system_users = models.ManyToManyField( - 'assets.SystemUser', related_name='granted_by_application_permissions', + 'assets.SystemUser', + related_name='granted_by_application_permissions', blank=True, verbose_name=_("System user") ) diff --git a/apps/perms/models/asset_permission.py b/apps/perms/models/asset_permission.py index f763bee10..78e6b9b5b 100644 --- a/apps/perms/models/asset_permission.py +++ b/apps/perms/models/asset_permission.py @@ -98,7 +98,7 @@ class Action: class AssetPermission(BasePermission): assets = models.ManyToManyField('assets.Asset', related_name='granted_by_permissions', blank=True, verbose_name=_("Asset")) nodes = models.ManyToManyField('assets.Node', related_name='granted_by_permissions', blank=True, verbose_name=_("Nodes")) - system_users = models.ManyToManyField('assets.SystemUser', related_name='granted_by_permissions', verbose_name=_("System user")) + system_users = models.ManyToManyField('assets.SystemUser', related_name='granted_by_permissions', blank=True, verbose_name=_("System user")) actions = models.IntegerField(choices=Action.DB_CHOICES, default=Action.ALL, verbose_name=_("Actions")) class Meta: From 58a10778cd94d6e4bdb02163cefc2d33c0439e68 Mon Sep 17 00:00:00 2001 From: xinwen Date: Fri, 10 Sep 2021 14:39:02 +0800 Subject: [PATCH 08/36] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=9F=AD?= =?UTF-8?q?=E4=BF=A1=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/authentication/errors.py | 2 +- apps/authentication/sms_verify_code.py | 11 +++-- .../templates/authentication/login_otp.html | 42 ++++++++++++++----- apps/authentication/views/mfa.py | 2 +- apps/locale/zh/LC_MESSAGES/django.po | 35 +++++++++++----- 5 files changed, 65 insertions(+), 27 deletions(-) diff --git a/apps/authentication/errors.py b/apps/authentication/errors.py index c8005ba95..f2346ab6d 100644 --- a/apps/authentication/errors.py +++ b/apps/authentication/errors.py @@ -71,7 +71,7 @@ sms_failed_msg = _( "(The account will be temporarily locked for {block_time} minutes)" ) mfa_type_failed_msg = _( - "The MFA type({mfa_type}) is not supported" + "The MFA type({mfa_type}) is not supported, " "You can also try {times_try} times " "(The account will be temporarily locked for {block_time} minutes)" ) diff --git a/apps/authentication/sms_verify_code.py b/apps/authentication/sms_verify_code.py index 33d17b207..0c3e986ce 100644 --- a/apps/authentication/sms_verify_code.py +++ b/apps/authentication/sms_verify_code.py @@ -52,10 +52,13 @@ class VerifyCodeUtil: ttl = self.ttl() if ttl > 0: raise CodeSendTooFrequently(ttl) - - self.generate() - self.save() - self.send() + try: + self.generate() + self.save() + self.send() + except JMSException: + self.clear() + raise def generate(self): code = ''.join(random.sample('0123456789', 4)) diff --git a/apps/authentication/templates/authentication/login_otp.html b/apps/authentication/templates/authentication/login_otp.html index 858c2737d..ff4d4e28b 100644 --- a/apps/authentication/templates/authentication/login_otp.html +++ b/apps/authentication/templates/authentication/login_otp.html @@ -19,19 +19,25 @@ {% endfor %} -
- - - {% trans 'Please enter the verification code' %} - -
- - +
+ + + +
+ +
{% trans "Can't provide security? Please contact the administrator!" %}
+