From 79b5aa68c8cc5d33629bd10c1414fb6be844c0a5 Mon Sep 17 00:00:00 2001 From: peijianbo Date: Tue, 27 Oct 2020 11:35:31 +0800 Subject: [PATCH] =?UTF-8?q?feat(terminal):=E5=8D=B1=E9=99=A9=E5=91=BD?= =?UTF-8?q?=E4=BB=A4=E5=91=8A=E8=AD=A6=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/utils/django.py | 4 +- apps/jumpserver/conf.py | 3 + apps/jumpserver/settings/custom.py | 3 + apps/locale/zh/LC_MESSAGES/django.mo | Bin 59302 -> 60310 bytes apps/locale/zh/LC_MESSAGES/django.po | 445 +++++++++++------- apps/settings/serializers/settings.py | 2 + apps/terminal/api/command.py | 25 +- apps/terminal/backends/command/models.py | 5 + apps/terminal/backends/command/serializers.py | 8 + apps/terminal/models.py | 5 + apps/terminal/serializers/__init__.py | 1 + apps/terminal/serializers/command.py | 10 + apps/terminal/urls/api_urls.py | 1 + apps/terminal/utils.py | 44 +- 14 files changed, 373 insertions(+), 183 deletions(-) create mode 100644 apps/terminal/serializers/command.py diff --git a/apps/common/utils/django.py b/apps/common/utils/django.py index 8f6809d3e..28a63a954 100644 --- a/apps/common/utils/django.py +++ b/apps/common/utils/django.py @@ -10,13 +10,15 @@ UUID_PATTERN = re.compile(r'[0-9a-zA-Z\-]{36}') def reverse(view_name, urlconf=None, args=None, kwargs=None, - current_app=None, external=False): + current_app=None, external=False, api_to_ui=False): url = dj_reverse(view_name, urlconf=urlconf, args=args, kwargs=kwargs, current_app=current_app) if external: site_url = settings.SITE_URL url = site_url.strip('/') + url + if api_to_ui: + url = url.replace('api/v1', 'ui/#').rstrip('/') return url diff --git a/apps/jumpserver/conf.py b/apps/jumpserver/conf.py index 883760e4a..e23ddc23c 100644 --- a/apps/jumpserver/conf.py +++ b/apps/jumpserver/conf.py @@ -245,6 +245,9 @@ class Config(dict): 'SECURITY_LOGIN_CHALLENGE_ENABLED': False, 'SECURITY_LOGIN_CAPTCHA_ENABLED': True, 'SECURITY_DATA_CRYPTO_ALGO': 'aes', + 'SECURITY_INSECURE_COMMAND': False, + 'SECURITY_INSECURE_COMMAND_LEVEL': 5, + 'SECURITY_INSECURE_COMMAND_EMAIL_RECEIVER': '', 'HTTP_BIND_HOST': '0.0.0.0', 'HTTP_LISTEN_PORT': 8080, diff --git a/apps/jumpserver/settings/custom.py b/apps/jumpserver/settings/custom.py index 379c6ebef..b1f2e1d41 100644 --- a/apps/jumpserver/settings/custom.py +++ b/apps/jumpserver/settings/custom.py @@ -55,6 +55,9 @@ SECURITY_SERVICE_ACCOUNT_REGISTRATION = DYNAMIC.SECURITY_SERVICE_ACCOUNT_REGISTR SECURITY_LOGIN_CAPTCHA_ENABLED = CONFIG.SECURITY_LOGIN_CAPTCHA_ENABLED SECURITY_LOGIN_CHALLENGE_ENABLED = CONFIG.SECURITY_LOGIN_CHALLENGE_ENABLED SECURITY_DATA_CRYPTO_ALGO = CONFIG.SECURITY_DATA_CRYPTO_ALGO +SECURITY_INSECURE_COMMAND = DYNAMIC.SECURITY_INSECURE_COMMAND +SECURITY_INSECURE_COMMAND_LEVEL = CONFIG.SECURITY_INSECURE_COMMAND_LEVEL +SECURITY_INSECURE_COMMAND_EMAIL_RECEIVER = DYNAMIC.SECURITY_INSECURE_COMMAND_EMAIL_RECEIVER # Terminal other setting TERMINAL_PASSWORD_AUTH = DYNAMIC.TERMINAL_PASSWORD_AUTH diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index 23caa533c081688531a12c8f781a20dbc5b10d73..4027d2247ebc4efbfddffe70ebd11a489c8ed3e7 100644 GIT binary patch delta 18294 zcmbW;cYKa#-^cNj5G!ItLX70H6ERzRkD~UdJ*q*FT9E{$^s-mY#@4F6M~RwU6jfA= z)~3|1O^eoz=kvYJpZn?Sex5&`*K@w^!~6LCj(HyEd0mON_lgw1*{A%x7qh3C<#3hu zbDX^RX{h7WNkjcjWgREtEypRE+HoSWJ#mYAjxz<<;!vzq-*MW|z6F0F&eYIx+NE-w z%NT%_8#~TJ^7WfI&Ls73>Nq2CFP?K8uT!^~kfxR61miF0 zkGC;1KEh1sw04{j2*CVU(5#E$#66LFamFL}<1EH9xB^SyY0S_1j(;2Ojzk28VM{EA z1F$51iiPnIp2mlG5f8R?oGiGyo#SN09T;GT}0 zzbc1F=!kyC5WIxCqo=4lNYlxErU9rEDvp}CChFNXMJ@P_<=dm?>xqRh0d=Euu>>x~ z40x;)=dXp%S;w2GqsrXbeFR~s2@0b&+7N^B9n=J|s0}9|@2)cm_2{OcHZ~JA|2!;+ zE3h0MMBfL@`z{|55@j(r_D2nzgj!%4>e0-@(zx34XHg4XMcvtL)JZ+D_Lr!6(syxB zDl@8o9Co>JE>fPUIx2|8>*`@1su8iFQBtc~Fn49BKoN zP%mL?)I4J_jXwXAspw8;U?{G}K>Qx{aXF4!@CNE7dy3lF3)D-PrmOpmv!f;sM?I3F zsBv#tzBU#hZiqU`z8J{*j+cs#ZYpZP5_2=^4)>rYK7=~j6Q~KUTmBhpqfR$>A`kD8}ZM|sKGf5-g9Pf>4kXm|Hy znqVH{R;d1QsCkE?Ha-r0AII*Tzm9S#3ElY`)RFE)4Lo2TM-TCN)QP-6P3Rxvo?Ld+ z$FK;d!D^@*sEz91%;I*a`D0My6Jj`jE$k(sXFd(JvxTUmTW#@P)P_<}6Q4of%ZIw7 z`=}F4)x(`H1L~26qHeH+<;$Yhc?%=(9WRwAD#NfMu0q|xW&8@Sqb6S3(_MJ2xgE8E zeW-m$>IUwh@6ljG;?Q1>^8mY}=5HPAZp_<(ijE@M?2DRs2=ar<8HGBsbC?%z zVQut(-;En!P2wJ?aVs$`eu0s=)#6L&PkbHI;a#M^*ZGr*-s+dAmnK_p_lHjj3@2`d zWiSz=a0Tj)kE15KjylqNs7LX_@>%-03+6;^EDY7ZsO3vxK7IbnTZdMtFP_dAfO9Or z47Kz1s0p@UCj83s2T%*7SpGDYCBBM!1fhN1`Kq8!@@>>c+h7)b{(Di;%k}|g#3a;0 z3sHBv0`+;`Y3+wFGx14OzpJP(t~;ntfqy^u(d0vIv@&MEdZ=;DF%aKHuU>|}))0?+ z#v@Sq&rk!GSiBB3;U@Ip*Qh(chyi#5b!UH|-U0vq?x!ID)t(nqW29NUKj*IrN|Dgc zDx&VV9_q+DpuV7@aSe_@{nUzzbML%?*#fm-dn|=ruo+H6ZTMHzI=3+p|3IzhH-Pik z9cLTh-f2nH%UBULppn_i?2LM=dtg?aj(TK^QIBvP>coDq{4vx9&Z8E-Y5Aw9`BQu2 z-M2auYN86Lqpyuxpg#IxJJgOlp}xc4M@>8$bwbmy0B$gkp-%7*)VSxUcOyfByN(C- zGr$`~MLVm7nxHxArAk1396!YDILGp9P)EJl+>YA#H>ibvL@jg*HU1uIqZt$3k97#D ze>LQ!yw2NHbQCS!gwxSF#Gn?AL%lqsEk7NDh!>!KY;Q!}=?|zIIfDAwT|k}OE7bgc z1Kmd#fZ9-b4ASSnHkBeI+MpI3j)ieLYNuP#gS$~1`3?1q@1qv{3$=mtgIu$q76?H- z$^xhpD{7WNJ+e13pFaOBspy%;nG-Pw@e&NiZK#d?gjw(sY6A~Y3;c~C_zHEWA%k7R zQ5%jx-AFl9|C*?mzAkzTQt3)X6OXeFvr#)Kc4=sL< z4T(cOaOaIieeMUK-mOH`yu&`={I$dJBy@)}QAfHGbpl&a3m!sk@B*s;UG(7Js5{Ct z#Qlqj2er|5sD-+q9z{>oJClGqq4Cx}eF*2Th38tsT5}6(p|4SQco4OrYZ!@tqmI1L zPU7T!^8>J5eX_Giv_x=3UgIeQA2r40Csy5%u{E!rYi2buv{gZiab?-^W5Y4s+pJ z)Pj4l1YSgq3mESHg(V#Ih?=7|)Ead%ossptP7f-2Mv2y8gmsvJI^r3a7gwQPvVGQ` zV)1Fz(f@{T;9b;7c|PKkg>PU4j>T}?fO@n?Fi@ZWb5u0(@2HpO57bVdqmIgtKFVi6 z<+Gv|$YuFrs5>fydSsPRkEQ|Y#@eGcsNXfUP8@3dP|QJbCi90DSd1FD3U!3rEq};7 zj#}Uh>gaExjy%-}ccZ0H3zS2>tTnIRj9i^>iXdb?ku zKBu`yyC?7l>Y3L>ZRl;(r=uKNT z6PC6_1B@VUff_gzb%$PSpN4v5b5Jkoa@2`zM?KpUs108*ucBVY+o%(C#<}COAfFDe zlaGofh(sOLTc|r|VRk}oq^Gs_K^^fB)Pkcdo^0*2P~(?iT3nCXa58G#ZY+ui(WB4* zBVUDYzVYr!ltq2vG(o*Q@1u@-0+z#hSO8N{C-Vq(VyP#%zj#DpQQ{`p83$r4p1=xN zZKC@(sDW6X^_}fh^tRr|4>0#6_nRsSI}s;i5zP9ryP*nLnz%J4;y8@L=ct#r=w!a- zum-Ndd#JDIc~jhzPDX9;2zoW~6DrzSzNzltfLdcZ;%TTyGY2!{X7fALFD6G&{jQ=O z(H+!JyN9Tar=8|Lg0851FVwp>47Jf&(>Q;9@vJAIXTKM-;4#dEmr)bnMLmK?miL?P zE}R85E+=NdLY6Oy`hF;nn&)lw$5v)X%t+jII_IxD=}SU)IvT@pAr`~0F$>;AP58{> zj5FLH)45S^cNNqfHAgMj3$;KZYGE&Go^jSb8@1sjYKW$?4t1x2pSTkQp*9w7aXE`? zp*GqUwLm;Z;czU2t5F*`hkyrC7V@9z8ixARlt-OxAJoV4W30jY&I~FVc+48kqK@nmY9lvL zFWFPn24A5zlxddZ^u}N;gd;IKu0WmS4%EBxjd=*G6Q4%SpL4cecAkG2m69adVSXHs zn{YKY#g22_J6?l1h>u`pyn=cZVRPL_RSDJJ47Gvom^T%lebgO~o9AwPGHTpx)bA3` zCMvqqJs5W=?JO^|B7`>4{P+Cxzrj<9?~EX0DH@IH=Qz?Ts113uF^JI=S* z9cwJ)d?N4xeoMa%EBH+q z`>o=iija?8<3570weAU&LES)k)FZBqde<6ZFm_(czEnvd5snkB!)nxkU04kF;v0A$ z^I?H??l)ph%uU=AJva*0z7*@?ZajeL*7GfjM==D)Y;eEO7Hr^L^v$-Kgx=z9)^Gp= zh)-HoErij|4%9-2Q73g0BQVt${L>RGhLvzEs^7P$^?pSC4DcSc$}?;5@apT%i=sZSWl=BX zJC^ThCYmG7spbOI0;^EtHk#j~PWqI!Uvu?3cc^5c;W285ew*F5Ix}h`rBHWN)#4a4 z9<@QQ#S6`~mfwz=?-XkO%hvu7vlG8WKYcE;@n&eDVAReFSR9FZxyoY{wm|*dAC4t) z5oW~{)VNEid2X10pf;F_kA~VkW>HkXl8W`YtYQtd%?8$?xy7B)kAB@TC-y>3Ji^*P zM@_f_^=V2*-QkZIi094Q=HF(9FF8FulU!6}5!8UPsH3Z6HZj|p(PnSdoejjAILzX& z(f6@M&2u012>!D63|rj|XWh#AYp3~0$kJvV)W9}a2;W03G}fGq`WPjd>re~q!(jZy z;@hZk&r$QG-sT#BI78;J)@D$50GS{0sQR9EG z_y}qP=PZ8>HU5s*I=nIiw!3#0idyImi)*9qtRw2#4?rz29X0VBix*qG%HqwaJKbUK zM}6*3V14vHr=p4K>~MF~5H(?E)WDvojU-xrj5*cvb5Z?Pq2~G0+P^|=bic*dQ1jf! zT=)vPA+M8br#rADYNB#xZL^u#$&5uE-5_(Kw5jzJb{rOAt>%O}q=|;U0@SedW&6&5T3!8;&}OG0N-nKhrua zM*V8F0W0BgoR0zg%+Eq~v9f?D_m>K)1Wt^4uJfyId{p%&_a<#7%c!6O)gf1<_(eCN&+@*U4# z6Be{YY1BrlnQx&6G_trg>e+Wf<@;lG9DJ1W1=OhL_e#=K2t8b23xGN0oT+=2Sy>a^Ewk2i<7dYuteYSCdl zHo_lKI}YCG4k&<%BhB)dlemtxceH$0)Q0<8euy~&^}}d9YNMM`zgzCZ9K3(d5h~jG z71Z~@@2CZznQ8aCady-M;g}!auzV}@Cyqw7_d-AX5OtDX)Z0HDgK#D4gm$5a^_^d= z!xPlPnSXF6%8lw+0+p|C`BoP9#4z%Ss5?(W9rb6ZjU-!szj+k>$)82dcNx8^+@qoa z&rvT~Aipy!ABOtXE6UWVs82-;)SXR0eGC_3Y20b?ZG4kB-9fis6;yi*i$|fx%|+eV7Su`XKFIm2 za=;o=Faz;P|v` zayvwt<;^-~bJWD0QT^jA9$|43YJsKZ7pPCo*Qgu*6{A?+xkW{H5PZZnFKS>xvovZz zHEXYrdX`Nsejn9;fW;r7HZ<0pg*vh2s15H$t#`^N&;KG7EpW{m?xQArf*RnL;!YTX zTDXYCwNYQaEm3#Y8#QhUYQgyy@4zg?`z=0+n&*nt=l>NIO_b-TyR)*WiK>`yo2{+A ztHrVAAk?R0w8ir<3-JnbD{6!LQT=YBzKC9;wG7)N?;hj%>!_Yuhmhm^V;JIsSR9980bGrm;4rHH z8PvqjPz$F%;hF(;=UFZGm_ZaLmX%=S}rU> zz94Gh7O0bY7jt1h)CR|+9^DMAq0fIZ6%BZdTF^P;nhy1gM4-jl%}@*_@3FWtYU8yq z4Yox+%1)>a^heF_wftnvMf^GXe*SN#qMhwSZ6F0T@T7U&+Ml2%a?ZN{h9om8E`}Ok z!K{Uvr;)X{G`pC6%pqra{+eK%C6Z7B7ojFxY57eULHrHs`{0I|@tk`nB``1fdYBu# zp}vSdLXDe-;kX^O-f7EUJIDEJ!oc%x$1+%txC2(g#i(z{b664mF1VlHs%ATEOFj|v z;bAO~zoQ;W{)_HORzMGNebhVB3-u1n_EOQa*p8pzF-*Yjzq-%xw0Rpt$iFm$FY&87 zadE7R15qco3$^e*)FV8HneaC1op_2mfsB{kllJDMl9xmnR>LaRFa$MV1m?gb%!aGX zov4Wpqxzk(_zvn3{)O6*^P3xIG_#@l=R(@OPLws2Lp`&qZiCarY-{b&s5|S0y0eeW zsi+%Rhy`#LYGW78+vYRWNvFNywufN|>pM}FsEyijGmG1sJ4tKw1ATb=p3J7E;oA+CrziDBr6qfzsW zM=d-9{c)kW++2r!$S0%L@!a72wQ!{y?nI4I6E#Oo)Bzh|PxQxRER8#{Fy2PpS+<+} zqKR*!K7OY#4+h?HZ>$);Nn8z;A7J?@w>W>jREtPxfvp&lir-REclPt|?uJgIHu{_S zCu)P~Z@Whxj2Vavqw=Ltd`@Xj zE{)~W`FimeP+}cpQygl!uI2}fxl3tEoJ5JXv4zR$s!Uvp;$6WXaU>^MheDX24xyA- zN*fzM)#+sQB>Lz$yHHC1qkRqaEVMl#--~)2R>w({^^~Qw&A|;6yON@+WYB*D?R2zU zDUK~Y{l260`R{(d?puk!q0A?$N4u^eSbnN1*>B(;BzU*>9cnr8tH9bJ`;56Hd8Fe4KbKPQ_H@X3+0r;>8qQXUIQv ztIn60%JN;wm!{|{kJrI$pN=>oE;zKSHh|>Nc@cZiQ7`zQC1R< zp`}0S8cRt>KFn@ttzzoO)o52?+V$0;YXOD7#Ga(-8T6&lEsPj z{qxLnU!#6F>iV8?j(9q@w07lxw)rNKOHEl#e29EE>dUDgNyYR3!3N|Zk((Va(@3r! zd91oN8x%CxXd) z5^SUs-)&B2>P@NlMtw2r+Uw%9z*1I!fYUXJT{oz|uzD|?MY&+{YZ_4LPie^fZ&AEk ztYr&>x7%cM$UUVzBmRgIMaQqKP2G#KVSQ8kF6!AR2MOMwJfz-w9zZd8|k zL`Pnxy+mJ&$GXk+rwryb=9Ie*K&hqEZT$wgAWpm6cepsm9Ub2ZsI z)MsOmx^PW#J3EK0PYdEzl)orJM4$gE zEU=F9CW#1&u0QEeA2Zp&1oCsJ_ayff^VFfTzPN_P?=Bo^UZ;@YSy7Yk&hY_WK**%zD9Zy}{B^#r%OQ-S#P^$Ydp zv~|bpBv(*=CjJGl;bHXti$5|_bk+UG;P%A75|5{>p(GQ(jj1Su)tRd}C5pmdO?}q@ z+H`GV@>q?bq@}LwQ|cKg-%@nb&B^W2^RHnY0_-T&xgZ^M4WuoUdRf%3Zr}K_yh!AJ zCASV^EO*t$DEyrIK+ET(-$-k#gC{M&(I?M;1j#f6iIfhMDB?PpiGh_U=PB#S<;Mq@ z4|Oe~_*s1e^>=C0RnvUm4SoN)&+pbxDUa0~sGmN6p?2ppX_!ge2!m~sEY_9>Ta(Lb zgG*SR?!N0Kf2JjOo%T-Di_&)((dPtlLFyjc#3f%VFP4p0n2$b>h@Vo5(Jzj;FgCNk_lTeA{(mOXj84-?gwWxg ze@vpjfs{Su#?YPzqlsryuR_r^h4L}=Z}BDV@8K=tUX*Oay0TLLka}6XNZb$85LeOX zU)Mnrudf&y-lu$GiCWbEd6lyGDh9LRNE!pI!xiTFg8DtmPnJ9VkMY^5kEHCQ-wM2_ zk3zgHUXnyx1{K8l6cT+7#eW`L>nXw5zrR{x6BkK3D zH~AX)2@Xczr>C<oG(@uZlSmKHni}vJn{YAbi^q~1Z>xRzf zwEae@KpaBbzo_rTZ&UH64JY{)!3&bQ-o;mL)v1Yr#1pVKeYWCwikDmwVqJYGMTke? zXv$_v7UI{}DC*$^**QjC-x1fN{EP8_>rGos@}x~x2FDSP!?)?whWab&1E{~g9#cO> zZ~@0tM$H#aX>C>A(D!f2extsN_7Yf*_C)IQs7K;S8>jA#DQQ*VN~^zVzDMU9bhvDt z>bh;dKPS_+gIc`h))MnS-&KpsS!(lMC#dhGeh!N<*FDM$;!NE6yS@>8Tai0TeLH2U z)=SO(AEi>A`Vz`U26R>f*M90dD7pg3?W1h4xSI8uZ@Rs>d*ZhU{-U&^?-}9_lnlfz zDZ9zdpme9+5sPYot}gf~>Lq=ogkAH3K>H&P|fu9Gi)NS*$D`$qTcUfEMPqMKWd zOvva-O4T%|u%}i+LQJAsdi768?9wl~Z%kx@C&I$mxX6S^w`Vp_>x7tibsUJV$LI1i zju{lwN9p+3gx+2HD0lNcS_r^~>2 z`WL8fS&y5oS}MA_yKK^e#hH?m8!ZS-?}>|v?;D$tkX)m~=Q$e3bQ>5SnKxafEeATcIBx!>S}X~S#9#gR(v<+St-_Gs|G>v3_(Rfk{o4~p*@ljv#Pva!=D z+E?XOr0xGgn=ou7P`|nzEhm(!7{TG_znaKbE delta 17525 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 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 041706686..b08921d82 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: JumpServer 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-10-27 10:29+0800\n" +"POT-Creation-Date: 2020-11-10 15:38+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -17,18 +17,30 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: applications/const.py:53 +#: applications/const.py:53 applications/models/application.py:34 msgid "Custom" msgstr "自定义" +#: applications/models/application.py:61 applications/models/database_app.py:29 +#: applications/serializers/database_app.py:16 +#: applications/serializers/remote_app.py:69 +#: users/templates/users/user_granted_database_app.html:37 +msgid "Database" +msgstr "数据库" + +#: applications/models/application.py:62 +msgid "Remote app" +msgstr "远程应用" + +#: applications/models/application.py:122 #: applications/models/database_app.py:18 applications/models/k8s_app.py:11 #: applications/models/remote_app.py:21 assets/models/asset.py:149 #: assets/models/base.py:232 assets/models/cluster.py:18 #: assets/models/cmd_filter.py:21 assets/models/domain.py:21 #: assets/models/group.py:20 assets/models/label.py:18 ops/mixin.py:24 #: orgs/models.py:23 perms/models/base.py:48 settings/models.py:27 -#: terminal/models.py:27 terminal/models.py:348 terminal/models.py:380 -#: terminal/models.py:417 users/forms/profile.py:20 users/models/group.py:15 +#: terminal/models.py:28 terminal/models.py:356 terminal/models.py:388 +#: terminal/models.py:425 users/forms/profile.py:20 users/models/group.py:15 #: users/models/user.py:505 users/templates/users/_select_user_modal.html:13 #: users/templates/users/user_asset_permission.html:37 #: users/templates/users/user_asset_permission.html:154 @@ -46,30 +58,33 @@ msgstr "自定义" msgid "Name" msgstr "名称" +#: applications/models/application.py:123 assets/models/asset.py:198 +#: assets/models/domain.py:27 assets/models/domain.py:54 +msgid "Domain" +msgstr "网域" + +#: applications/models/application.py:124 +#: applications/serializers/application.py:16 assets/models/label.py:21 +#: perms/models/application_permission.py:19 +#: perms/serializers/application/permission.py:16 +#: perms/serializers/application/user_permission.py:33 +msgid "Category" +msgstr "分类" + +#: applications/models/application.py:125 #: applications/models/database_app.py:22 applications/models/k8s_app.py:14 -#: assets/models/cmd_filter.py:52 terminal/models.py:382 terminal/models.py:419 -#: tickets/models/ticket.py:40 +#: applications/serializers/application.py:17 assets/models/cmd_filter.py:52 +#: perms/models/application_permission.py:20 +#: perms/serializers/application/permission.py:17 +#: perms/serializers/application/user_permission.py:34 terminal/models.py:390 +#: terminal/models.py:427 tickets/models/ticket.py:40 #: users/templates/users/user_granted_database_app.html:35 msgid "Type" msgstr "类型" -#: applications/models/database_app.py:25 ops/models/adhoc.py:146 -#: users/templates/users/user_granted_database_app.html:36 -msgid "Host" -msgstr "主机" - -#: applications/models/database_app.py:27 assets/models/asset.py:195 -#: assets/models/domain.py:52 -msgid "Port" -msgstr "端口" - -#: applications/models/database_app.py:29 -#: users/templates/users/user_granted_database_app.html:37 -msgid "Database" -msgstr "数据库" - # msgid "Date created" # msgstr "创建日期" +#: applications/models/application.py:128 #: applications/models/database_app.py:33 applications/models/k8s_app.py:18 #: applications/models/remote_app.py:45 assets/models/asset.py:154 #: assets/models/asset.py:230 assets/models/base.py:237 @@ -77,8 +92,8 @@ msgstr "数据库" #: assets/models/cmd_filter.py:57 assets/models/domain.py:22 #: assets/models/domain.py:55 assets/models/group.py:23 #: assets/models/label.py:23 ops/models/adhoc.py:37 orgs/models.py:26 -#: perms/models/base.py:56 settings/models.py:32 terminal/models.py:37 -#: terminal/models.py:387 terminal/models.py:424 tickets/models/ticket.py:43 +#: perms/models/base.py:56 settings/models.py:32 terminal/models.py:38 +#: terminal/models.py:395 terminal/models.py:432 tickets/models/ticket.py:43 #: users/models/group.py:16 users/models/user.py:538 #: users/templates/users/user_detail.html:115 #: users/templates/users/user_granted_database_app.html:38 @@ -91,6 +106,22 @@ msgstr "数据库" msgid "Comment" msgstr "备注" +#: applications/models/database_app.py:25 +#: applications/serializers/database_app.py:13 ops/models/adhoc.py:146 +#: users/templates/users/user_granted_database_app.html:36 +msgid "Host" +msgstr "主机" + +#: applications/models/database_app.py:27 +#: applications/serializers/database_app.py:14 +#: applications/serializers/database_app.py:21 +#: applications/serializers/database_app.py:25 +#: applications/serializers/database_app.py:29 +#: applications/serializers/remote_app.py:68 assets/models/asset.py:195 +#: assets/models/domain.py:52 +msgid "Port" +msgstr "端口" + #: applications/models/database_app.py:41 #: perms/forms/database_app_permission.py:44 #: perms/models/database_app_permission.py:18 @@ -105,7 +136,8 @@ msgstr "数据库应用" msgid "Kubernetes" msgstr "" -#: applications/models/k8s_app.py:16 assets/models/cluster.py:40 +#: applications/models/k8s_app.py:16 applications/serializers/k8s_app.py:9 +#: assets/models/cluster.py:40 msgid "Cluster" msgstr "集群" @@ -114,14 +146,14 @@ msgstr "集群" msgid "KubernetesApp" msgstr "Kubernetes应用" -#: applications/models/remote_app.py:23 assets/models/asset.py:364 +#: applications/models/remote_app.py:23 assets/models/asset.py:363 #: assets/models/authbook.py:26 assets/models/gathered_user.py:14 #: assets/serializers/admin_user.py:32 assets/serializers/asset_user.py:47 -#: assets/serializers/asset_user.py:84 assets/serializers/system_user.py:46 +#: assets/serializers/asset_user.py:84 assets/serializers/system_user.py:45 #: assets/serializers/system_user.py:186 audits/models.py:38 #: perms/forms/asset_permission.py:89 perms/models/asset_permission.py:92 #: templates/index.html:82 terminal/backends/command/models.py:19 -#: terminal/backends/command/serializers.py:13 terminal/models.py:188 +#: terminal/backends/command/serializers.py:13 terminal/models.py:192 #: users/templates/users/user_asset_permission.html:40 #: users/templates/users/user_asset_permission.html:70 #: users/templates/users/user_granted_remote_app.html:36 @@ -177,6 +209,77 @@ msgstr "创建日期" msgid "RemoteApp" msgstr "远程应用" +#: applications/serializers/remote_app.py:36 assets/models/user.py:99 +#: templates/_nav.html:39 xpack/plugins/change_auth_plan/models.py:52 +msgid "Assets" +msgstr "资产管理" + +#: applications/serializers/remote_app.py:37 +#: applications/serializers/remote_app.py:58 +#: applications/serializers/remote_app.py:66 +#: applications/serializers/remote_app.py:76 +msgid "Remote App path" +msgstr "远程应用列表" + +#: applications/serializers/remote_app.py:59 +#: applications/serializers/remote_app.py:77 +msgid "Target URL" +msgstr "目标URL" + +#: applications/serializers/remote_app.py:60 +#: applications/serializers/remote_app.py:70 +#: applications/serializers/remote_app.py:78 +#: applications/serializers/remote_app.py:85 assets/models/base.py:233 +#: assets/models/gathered_user.py:15 audits/models.py:99 +#: authentication/forms.py:11 +#: authentication/templates/authentication/login.html:21 +#: authentication/templates/authentication/xpack_login.html:101 +#: ops/models/adhoc.py:148 users/forms/profile.py:19 users/models/user.py:503 +#: users/templates/users/_select_user_modal.html:14 +#: users/templates/users/user_detail.html:53 +#: users/templates/users/user_list.html:15 +#: users/templates/users/user_profile.html:47 +#: xpack/plugins/change_auth_plan/models.py:47 +#: xpack/plugins/change_auth_plan/models.py:279 +msgid "Username" +msgstr "用户名" + +#: applications/serializers/remote_app.py:61 +#: applications/serializers/remote_app.py:71 +#: applications/serializers/remote_app.py:79 +#: applications/serializers/remote_app.py:86 assets/models/base.py:234 +#: assets/serializers/asset_user.py:71 authentication/forms.py:13 +#: authentication/templates/authentication/login.html:29 +#: authentication/templates/authentication/xpack_login.html:109 +#: users/forms/user.py:22 users/forms/user.py:193 +#: 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 +#: users/templates/users/user_profile_update.html:41 +#: users/templates/users/user_pubkey_update.html:41 +#: users/templates/users/user_update.html:20 +#: xpack/plugins/change_auth_plan/models.py:68 +#: xpack/plugins/change_auth_plan/models.py:191 +#: xpack/plugins/change_auth_plan/models.py:286 +msgid "Password" +msgstr "密码" + +#: applications/serializers/remote_app.py:67 assets/models/asset.py:190 +#: assets/models/domain.py:51 assets/serializers/asset_user.py:46 +#: settings/serializers/settings.py:52 +#: users/templates/users/_granted_assets.html:26 +#: users/templates/users/user_asset_permission.html:156 +msgid "IP" +msgstr "IP" + +#: applications/serializers/remote_app.py:83 +msgid "Operating parameter" +msgstr "运行参数" + +#: applications/serializers/remote_app.py:84 +msgid "Target url" +msgstr "目标URL" + #: assets/api/admin_user.py:46 msgid "Deleted failed, There are related assets" msgstr "删除失败,存在关联资产" @@ -222,13 +325,6 @@ msgstr "内部的" msgid "Platform" msgstr "系统平台" -#: assets/models/asset.py:190 assets/models/domain.py:51 -#: assets/serializers/asset_user.py:46 settings/serializers/settings.py:52 -#: users/templates/users/_granted_assets.html:26 -#: users/templates/users/user_asset_permission.html:156 -msgid "IP" -msgstr "IP" - #: assets/models/asset.py:191 assets/serializers/asset_user.py:45 #: assets/serializers/gathered_user.py:20 settings/serializers/settings.py:51 #: tickets/serializers/request_asset_perm.py:25 @@ -238,21 +334,16 @@ msgid "Hostname" msgstr "主机名" #: assets/models/asset.py:194 assets/models/domain.py:53 -#: assets/models/user.py:97 terminal/serializers/session.py:29 +#: assets/models/user.py:103 terminal/serializers/session.py:29 msgid "Protocol" msgstr "协议" #: assets/models/asset.py:196 assets/serializers/asset.py:69 -#: perms/serializers/user_permission.py:71 +#: perms/serializers/asset/user_permission.py:41 msgid "Protocols" msgstr "协议组" -#: assets/models/asset.py:198 assets/models/domain.py:27 -#: assets/models/domain.py:54 -msgid "Domain" -msgstr "网域" - -#: assets/models/asset.py:199 assets/models/user.py:92 +#: assets/models/asset.py:199 assets/models/user.py:98 #: perms/models/asset_permission.py:93 #: xpack/plugins/change_auth_plan/models.py:56 #: xpack/plugins/gathered_user/models.py:24 @@ -355,37 +446,6 @@ msgstr "版本" msgid "AuthBook" msgstr "" -#: assets/models/base.py:233 assets/models/gathered_user.py:15 -#: audits/models.py:99 authentication/forms.py:11 -#: authentication/templates/authentication/login.html:21 -#: authentication/templates/authentication/xpack_login.html:101 -#: ops/models/adhoc.py:148 users/forms/profile.py:19 users/models/user.py:503 -#: users/templates/users/_select_user_modal.html:14 -#: users/templates/users/user_detail.html:53 -#: users/templates/users/user_list.html:15 -#: users/templates/users/user_profile.html:47 -#: xpack/plugins/change_auth_plan/models.py:47 -#: xpack/plugins/change_auth_plan/models.py:279 -msgid "Username" -msgstr "用户名" - -#: assets/models/base.py:234 assets/serializers/asset_user.py:71 -#: authentication/forms.py:13 -#: authentication/templates/authentication/login.html:29 -#: authentication/templates/authentication/xpack_login.html:109 -#: users/forms/user.py:22 users/forms/user.py:193 -#: 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 -#: users/templates/users/user_profile_update.html:41 -#: users/templates/users/user_pubkey_update.html:41 -#: users/templates/users/user_update.html:20 -#: xpack/plugins/change_auth_plan/models.py:68 -#: xpack/plugins/change_auth_plan/models.py:191 -#: xpack/plugins/change_auth_plan/models.py:286 -msgid "Password" -msgstr "密码" - #: assets/models/base.py:235 xpack/plugins/change_auth_plan/models.py:72 #: xpack/plugins/change_auth_plan/models.py:198 #: xpack/plugins/change_auth_plan/models.py:293 @@ -446,7 +506,7 @@ msgstr "系统" msgid "Default Cluster" msgstr "默认Cluster" -#: assets/models/cmd_filter.py:33 assets/models/user.py:102 +#: assets/models/cmd_filter.py:33 assets/models/user.py:108 msgid "Command filter" msgstr "命令过滤器" @@ -455,7 +515,7 @@ msgid "Regex" msgstr "正则表达式" #: assets/models/cmd_filter.py:41 ops/models/command.py:23 -#: terminal/backends/command/serializers.py:15 terminal/models.py:197 +#: terminal/backends/command/serializers.py:15 terminal/models.py:201 msgid "Command" msgstr "命令" @@ -471,7 +531,7 @@ msgstr "允许" msgid "Filter" msgstr "过滤器" -#: assets/models/cmd_filter.py:53 assets/models/user.py:96 +#: assets/models/cmd_filter.py:53 assets/models/user.py:102 msgid "Priority" msgstr "优先级" @@ -545,7 +605,7 @@ msgstr "默认资产组" #: perms/forms/remote_app_permission.py:40 perms/models/asset_permission.py:169 #: perms/models/base.py:49 templates/index.html:78 #: terminal/backends/command/models.py:18 -#: terminal/backends/command/serializers.py:12 terminal/models.py:186 +#: terminal/backends/command/serializers.py:12 terminal/models.py:190 #: tickets/models/ticket.py:30 tickets/models/ticket.py:136 #: tickets/serializers/request_asset_perm.py:66 #: tickets/serializers/ticket.py:31 users/forms/group.py:15 @@ -563,35 +623,31 @@ msgstr "默认资产组" msgid "User" msgstr "用户" -#: assets/models/label.py:19 assets/models/node.py:397 settings/models.py:28 +#: assets/models/label.py:19 assets/models/node.py:396 settings/models.py:28 msgid "Value" msgstr "值" -#: assets/models/label.py:21 -msgid "Category" -msgstr "分类" - #: assets/models/node.py:131 msgid "New node" msgstr "新节点" -#: assets/models/node.py:303 users/templates/users/_granted_assets.html:130 +#: assets/models/node.py:302 users/templates/users/_granted_assets.html:130 msgid "empty" msgstr "空" -#: assets/models/node.py:396 perms/models/asset_permission.py:144 +#: assets/models/node.py:395 perms/models/asset_permission.py:144 msgid "Key" msgstr "键" -#: assets/models/node.py:398 +#: assets/models/node.py:397 msgid "Full value" msgstr "全称" -#: assets/models/node.py:401 perms/models/asset_permission.py:148 +#: assets/models/node.py:400 perms/models/asset_permission.py:148 msgid "Parent key" msgstr "ssh私钥" -#: assets/models/node.py:410 assets/serializers/system_user.py:45 +#: assets/models/node.py:409 assets/serializers/system_user.py:44 #: assets/serializers/system_user.py:185 perms/forms/asset_permission.py:92 #: perms/forms/asset_permission.py:99 #: users/templates/users/user_asset_permission.html:41 @@ -601,73 +657,69 @@ msgstr "ssh私钥" msgid "Node" msgstr "节点" -#: assets/models/user.py:88 +#: assets/models/user.py:94 msgid "Automatic login" msgstr "自动登录" -#: assets/models/user.py:89 +#: assets/models/user.py:95 msgid "Manually login" msgstr "手动登录" -#: assets/models/user.py:91 +#: assets/models/user.py:97 msgid "Username same with user" msgstr "用户名与用户相同" -#: assets/models/user.py:93 templates/_nav.html:39 -#: xpack/plugins/change_auth_plan/models.py:52 -msgid "Assets" -msgstr "资产管理" - -#: assets/models/user.py:94 templates/_nav.html:17 +#: assets/models/user.py:100 templates/_nav.html:17 #: users/views/profile/password.py:42 users/views/profile/pubkey.py:36 msgid "Users" msgstr "用户管理" -#: assets/models/user.py:95 users/templates/users/user_group_list.html:90 +#: assets/models/user.py:101 users/templates/users/user_group_list.html:90 #: users/templates/users/user_profile.html:124 msgid "User groups" msgstr "用户组" -#: assets/models/user.py:98 +#: assets/models/user.py:104 msgid "Auto push" msgstr "自动推送" -#: assets/models/user.py:99 +#: assets/models/user.py:105 msgid "Sudo" msgstr "Sudo" -#: assets/models/user.py:100 +#: assets/models/user.py:106 msgid "Shell" msgstr "Shell" -#: assets/models/user.py:101 +#: assets/models/user.py:107 msgid "Login mode" msgstr "登录模式" -#: assets/models/user.py:103 +#: assets/models/user.py:109 msgid "SFTP Root" msgstr "SFTP根路径" -#: assets/models/user.py:104 authentication/models.py:88 +#: assets/models/user.py:110 authentication/models.py:88 msgid "Token" msgstr "" -#: assets/models/user.py:105 +#: assets/models/user.py:111 msgid "Home" msgstr "家目录" -#: assets/models/user.py:106 +#: assets/models/user.py:112 msgid "System groups" msgstr "用户组" -#: assets/models/user.py:181 audits/models.py:39 +#: assets/models/user.py:206 audits/models.py:39 #: perms/forms/asset_permission.py:95 perms/forms/remote_app_permission.py:49 +#: perms/models/application_permission.py:22 #: perms/models/asset_permission.py:94 #: perms/models/database_app_permission.py:22 #: perms/models/k8s_app_permission.py:22 #: perms/models/remote_app_permission.py:16 templates/_nav.html:45 #: terminal/backends/command/models.py:20 -#: terminal/backends/command/serializers.py:14 terminal/models.py:190 +#: terminal/backends/command/serializers.py:14 terminal/models.py:194 #: tickets/serializers/request_asset_perm.py:27 #: users/templates/users/_granted_assets.html:27 #: users/templates/users/user_asset_permission.html:42 @@ -725,7 +777,7 @@ msgstr "硬件信息" msgid "Org name" msgstr "组织名称" -#: assets/serializers/asset.py:168 assets/serializers/asset.py:199 +#: assets/serializers/asset.py:166 assets/serializers/asset.py:197 msgid "Connectivity" msgstr "连接" @@ -763,27 +815,31 @@ msgstr "密钥不合法" msgid "value" msgstr "值" -#: assets/serializers/node.py:36 +#: assets/serializers/node.py:29 +msgid "Can't contains: /" +msgstr "" + +#: assets/serializers/node.py:39 msgid "The same level node name cannot be the same" msgstr "同级别节点名字不能重复" -#: assets/serializers/system_user.py:47 assets/serializers/system_user.py:187 +#: assets/serializers/system_user.py:46 assets/serializers/system_user.py:187 msgid "Login mode display" msgstr "登录模式显示" -#: assets/serializers/system_user.py:87 +#: assets/serializers/system_user.py:86 msgid "Username same with user with protocol {} only allow 1" msgstr "用户名和用户相同的一种协议只允许存在一个" -#: assets/serializers/system_user.py:100 +#: assets/serializers/system_user.py:99 msgid "* Automatic login mode must fill in the username." msgstr "自动登录模式,必须填写用户名" -#: assets/serializers/system_user.py:108 +#: assets/serializers/system_user.py:107 msgid "Path should starts with /" msgstr "路径应该以 / 开头" -#: assets/serializers/system_user.py:119 +#: assets/serializers/system_user.py:118 msgid "Password or private key required" msgstr "密码或密钥密码需要一个" @@ -835,25 +891,25 @@ msgstr "更新节点资产硬件信息: {}" msgid "Gather assets users" msgstr "收集资产上的用户" -#: assets/tasks/push_system_user.py:178 +#: assets/tasks/push_system_user.py:183 #: assets/tasks/system_user_connectivity.py:89 msgid "System user is dynamic: {}" msgstr "系统用户是动态的: {}" -#: assets/tasks/push_system_user.py:209 +#: assets/tasks/push_system_user.py:214 msgid "Start push system user for platform: [{}]" msgstr "推送系统用户到平台: [{}]" -#: assets/tasks/push_system_user.py:210 +#: assets/tasks/push_system_user.py:215 #: assets/tasks/system_user_connectivity.py:81 msgid "Hosts count: {}" msgstr "主机数量: {}" -#: assets/tasks/push_system_user.py:228 assets/tasks/push_system_user.py:244 +#: assets/tasks/push_system_user.py:233 assets/tasks/push_system_user.py:251 msgid "Push system users to assets: {}" msgstr "推送系统用户到入资产: {}" -#: assets/tasks/push_system_user.py:236 +#: assets/tasks/push_system_user.py:241 msgid "Push system users to asset: {}({}) => {}" msgstr "推送系统用户到入资产: {}({}) => {}" @@ -933,7 +989,7 @@ msgid "Symlink" msgstr "建立软链接" #: audits/models.py:37 audits/models.py:60 audits/models.py:71 -#: terminal/models.py:193 +#: terminal/models.py:197 msgid "Remote addr" msgstr "远端地址" @@ -951,7 +1007,7 @@ msgid "Success" msgstr "成功" #: audits/models.py:43 ops/models/command.py:28 perms/models/base.py:52 -#: terminal/models.py:200 tickets/serializers/request_asset_perm.py:29 +#: terminal/models.py:204 tickets/serializers/request_asset_perm.py:29 #: xpack/plugins/change_auth_plan/models.py:177 #: xpack/plugins/change_auth_plan/models.py:308 #: xpack/plugins/gathered_user/models.py:76 @@ -1205,7 +1261,7 @@ msgstr "登录复核 {}" msgid "SSO auth closed" msgstr "SSO 认证关闭了" -#: authentication/errors.py:218 authentication/views/login.py:246 +#: authentication/errors.py:218 authentication/views/login.py:247 msgid "Your password is too simple, please change it for security" msgstr "你的密码过于简单,为了安全,请修改" @@ -1358,6 +1414,10 @@ msgstr "正在使用其他认证服务器,请联系管理员" msgid "One-time password" msgstr "一次性密码" +#: authentication/templates/authentication/login_otp.html:23 +#: users/templates/users/user_verify_mfa.html:13 +msgid "Open MFA Authenticator and enter the 6-bit dynamic code" +msgstr "请打开MFA验证器,输入6位动态码" #: authentication/templates/authentication/login_otp.html:26 #: users/templates/users/user_otp_check_password.html:15 @@ -1396,7 +1456,7 @@ msgstr "欢迎回来,请输入用户名和密码登录" msgid "Please enable cookies and try again." msgstr "设置你的浏览器支持cookie" -#: authentication/views/login.py:192 +#: authentication/views/login.py:193 msgid "" "Wait for {} confirm, You also can copy link to her/him
\n" " Don't close this page" @@ -1404,19 +1464,19 @@ msgstr "" "等待 {} 确认, 你也可以复制链接发给他/她
\n" " 不要关闭本页面" -#: authentication/views/login.py:197 +#: authentication/views/login.py:198 msgid "No ticket found" msgstr "没有发现工单" -#: authentication/views/login.py:229 +#: authentication/views/login.py:230 msgid "Logout success" msgstr "退出登录成功" -#: authentication/views/login.py:230 +#: authentication/views/login.py:231 msgid "Logout success, return login page" msgstr "退出登录成功,返回到登录页面" -#: authentication/views/login.py:245 +#: authentication/views/login.py:246 msgid "Please change your password" msgstr "请修改密码" @@ -1488,7 +1548,7 @@ msgstr "" msgid "Marshal data to text field" msgstr "" -#: common/fields/model.py:165 +#: common/fields/model.py:150 msgid "Encrypt field using Secret Key" msgstr "" @@ -1516,7 +1576,7 @@ msgstr "字段必须唯一" msgid "Should not contains special characters" msgstr "不能包含特殊字符" -#: jumpserver/conf.py:471 templates/_base_only_msg_content.html:27 +#: jumpserver/conf.py:477 templates/_base_only_msg_content.html:27 #: xpack/plugins/interface/api.py:18 xpack/plugins/interface/models.py:36 msgid "Welcome to the JumpServer open source fortress" msgstr "欢迎使用JumpServer开源堡垒机" @@ -1707,11 +1767,11 @@ msgstr "更新任务内容: {}" msgid "Disk used more than 80%: {} => {}" msgstr "磁盘使用率超过 80%: {} => {}" -#: orgs/api.py:60 +#: orgs/api.py:61 msgid "Organization contains undeleted resources" msgstr "组织包含未删除的资源" -#: orgs/api.py:64 +#: orgs/api.py:65 msgid "The current organization cannot be deleted" msgstr "当前组织不能被删除" @@ -1736,7 +1796,7 @@ msgstr "组织审计员" msgid "Role" msgstr "角色" -#: perms/const.py:7 perms/utils/user_asset_permission.py:28 +#: perms/const.py:7 perms/utils/asset/user_permission.py:28 msgid "Ungrouped" msgstr "未分组" @@ -1785,6 +1845,14 @@ msgstr "资产和节点至少选一个" msgid "System users" msgstr "系统用户" +#: perms/models/application_permission.py:21 users/models/user.py:160 +msgid "Application" +msgstr "应用程序" + +#: perms/models/application_permission.py:26 +msgid "Application permission" +msgstr "应用管理" + #: perms/models/asset_permission.py:37 settings/serializers/settings.py:56 msgid "All" msgstr "全部" @@ -1846,11 +1914,17 @@ msgstr "Kubernetes应用授权" msgid "RemoteApp permission" msgstr "远程应用授权" -#: perms/utils/user_asset_permission.py:30 +#: perms/serializers/application/permission.py:53 +msgid "" +"The application list contains applications that are different from the " +"permission type. ({})" +msgstr "" + +#: perms/utils/asset/user_permission.py:30 msgid "Favorite" msgstr "收藏夹" -#: perms/utils/user_asset_permission.py:514 +#: perms/utils/asset/user_permission.py:526 msgid "Please wait while your data is being initialized" msgstr "数据正在初始化,请稍等" @@ -2522,63 +2596,63 @@ msgstr "风险等级" msgid "Bulk create not support" msgstr "不支持批量创建" -#: terminal/models.py:28 +#: terminal/models.py:29 msgid "Remote Address" msgstr "远端地址" -#: terminal/models.py:29 +#: terminal/models.py:30 msgid "SSH Port" msgstr "SSH端口" -#: terminal/models.py:30 +#: terminal/models.py:31 msgid "HTTP Port" msgstr "HTTP端口" -#: terminal/models.py:31 +#: terminal/models.py:32 msgid "Command storage" msgstr "命令存储" -#: terminal/models.py:32 +#: terminal/models.py:33 msgid "Replay storage" msgstr "录像存储" -#: terminal/models.py:155 +#: terminal/models.py:156 msgid "Session Online" msgstr "在线会话" -#: terminal/models.py:156 +#: terminal/models.py:157 msgid "CPU Usage" msgstr "CPU使用" -#: terminal/models.py:157 +#: terminal/models.py:158 msgid "Memory Used" msgstr "内存使用" -#: terminal/models.py:158 +#: terminal/models.py:159 msgid "Connections" msgstr "连接数" -#: terminal/models.py:159 +#: terminal/models.py:160 msgid "Threads" msgstr "线程数" -#: terminal/models.py:160 +#: terminal/models.py:161 msgid "Boot Time" msgstr "运行时间" -#: terminal/models.py:192 +#: terminal/models.py:196 msgid "Login from" msgstr "登录来源" -#: terminal/models.py:196 +#: terminal/models.py:200 msgid "Replay" msgstr "回放" -#: terminal/models.py:201 +#: terminal/models.py:205 msgid "Date end" msgstr "结束日期" -#: terminal/models.py:349 +#: terminal/models.py:357 msgid "Args" msgstr "参数" @@ -2586,37 +2660,73 @@ msgstr "参数" msgid "Not found" msgstr "没有发现" -#: tickets/api/request_asset_perm.py:48 +#: terminal/utils.py:73 +#, 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/utils.py:83 +#, 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 detail\n" +"
\n" +" " +msgstr "" +"\n" +" 命令: %(command)s\n" +"
\n" +" 资产: %(host_name)s (%(host_ip)s)\n" +"
\n" +" 用户: %(user)s\n" +"
\n" +" 等级: %(risk_level)s\n" +"
\n" +" 会话: 会话详情\n" +"
\n" +" " + +#: tickets/api/request_asset_perm.py:47 #, python-format msgid "Ticket has %s" msgstr "工单已%s" -#: tickets/api/request_asset_perm.py:94 +#: tickets/api/request_asset_perm.py:81 msgid "Confirm assets first" msgstr "请先确认资产" -#: tickets/api/request_asset_perm.py:97 +#: tickets/api/request_asset_perm.py:84 msgid "Confirmed assets changed" msgstr "确认的资产变更了" -#: tickets/api/request_asset_perm.py:101 +#: tickets/api/request_asset_perm.py:88 msgid "Confirm system-users first" msgstr "请先确认系统用户" -#: tickets/api/request_asset_perm.py:105 +#: tickets/api/request_asset_perm.py:92 msgid "Confirmed system-users changed" msgstr "确认的系统用户变更了" -#: tickets/api/request_asset_perm.py:111 tickets/api/request_asset_perm.py:118 +#: tickets/api/request_asset_perm.py:98 tickets/api/request_asset_perm.py:105 #: xpack/plugins/cloud/models.py:211 msgid "Succeed" msgstr "成功" -#: tickets/api/request_asset_perm.py:125 +#: tickets/api/request_asset_perm.py:112 msgid "From request ticket: {} {}" msgstr "来自工单申请: {} {}" -#: tickets/api/request_asset_perm.py:127 +#: tickets/api/request_asset_perm.py:114 msgid "{} request assets, approved by {}" msgstr "{} 申请资产,通过人 {}" @@ -2928,10 +3038,6 @@ msgstr "系统管理员" msgid "System auditor" msgstr "系统审计员" -#: users/models/user.py:160 -msgid "Application" -msgstr "应用程序" - #: users/models/user.py:427 users/templates/users/user_profile.html:90 msgid "Force enable" msgstr "强制启用" @@ -3428,8 +3534,8 @@ msgstr "绑定一次性密码验证器" #: users/templates/users/user_otp_enable_bind.html:13 msgid "" -"Use the MFA Authenticator application to scan the following qr " -"code for a 6-bit verification code" +"Use the MFA Authenticator application to scan the following qr code for a 6-" +"bit verification code" msgstr "使用MFA验证器应用扫描以下二维码,获取6位验证码" #: users/templates/users/user_otp_enable_bind.html:22 @@ -3531,10 +3637,6 @@ msgid "" "operations according to the prompts" msgstr "账号保护已开启,请根据提示完成以下操作" -#: users/templates/users/user_verify_mfa.html:13 -msgid "Open MFA Authenticator and enter the 6-bit dynamic code" -msgstr "请打开MFA验证器,输入6位动态码" - # msgid "Update user" # msgstr "更新用户" #: users/utils.py:24 @@ -4252,9 +4354,6 @@ msgstr "社区版" #~ msgid "Auditors cannot be join in the user group" #~ msgstr "审计员不能被加入到用户组" -#~ msgid "Target URL" -#~ msgstr "目标URL" - #~ msgid "Login username" #~ msgstr "登录账号" @@ -4276,9 +4375,6 @@ msgstr "社区版" #~ msgid "Target address" #~ msgstr "目标地址" -#~ msgid "Operating parameter" -#~ msgstr "运行参数" - #~ msgid "Detail" #~ msgstr "详情" @@ -4308,9 +4404,6 @@ msgstr "社区版" #~ msgid "My DatabaseApp" #~ msgstr "我的数据库应用" -#~ msgid "RemoteApp list" -#~ msgstr "远程应用列表" - #~ msgid "Update RemoteApp" #~ msgstr "更新远程应用" diff --git a/apps/settings/serializers/settings.py b/apps/settings/serializers/settings.py index c25bd0196..7038ba4d5 100644 --- a/apps/settings/serializers/settings.py +++ b/apps/settings/serializers/settings.py @@ -82,6 +82,8 @@ class SecuritySettingSerializer(serializers.Serializer): SECURITY_PASSWORD_LOWER_CASE = serializers.BooleanField(required=False) SECURITY_PASSWORD_NUMBER = serializers.BooleanField(required=False) SECURITY_PASSWORD_SPECIAL_CHAR = serializers.BooleanField(required=False) + SECURITY_INSECURE_COMMAND = serializers.BooleanField(required=False) + SECURITY_INSECURE_COMMAND_EMAIL_RECEIVER = serializers.CharField(max_length=8192, required=False) class SettingsSerializer(serializers.Serializer): diff --git a/apps/terminal/api/command.py b/apps/terminal/api/command.py index d18c70858..fdafb1baf 100644 --- a/apps/terminal/api/command.py +++ b/apps/terminal/api/command.py @@ -1,25 +1,28 @@ # -*- coding: utf-8 -*- # import time +from django.conf import settings from django.utils import timezone from django.shortcuts import HttpResponse from rest_framework import viewsets from rest_framework import generics from rest_framework.fields import DateTimeField from rest_framework.response import Response +from rest_framework import status from django.template import loader - from orgs.utils import current_org -from common.permissions import IsOrgAdminOrAppUser, IsOrgAuditor +from common.permissions import IsOrgAdminOrAppUser, IsOrgAuditor, IsAppUser from common.utils import get_logger +from terminal.utils import send_command_alert_mail +from terminal.serializers import InsecureCommandAlertSerializer from ..backends import ( get_command_storage, get_multi_command_storage, SessionCommandSerializer, ) logger = get_logger(__name__) -__all__ = ['CommandViewSet', 'CommandExportApi'] +__all__ = ['CommandViewSet', 'CommandExportApi', 'InsecureCommandAlertAPI'] class CommandQueryMixin: @@ -134,3 +137,19 @@ class CommandExportApi(CommandQueryMixin, generics.ListAPIView): filename = 'command-report-{}.html'.format(int(time.time())) response['Content-Disposition'] = 'attachment; filename="%s"' % filename return response + + +class InsecureCommandAlertAPI(generics.CreateAPIView): + permission_classes = [IsAppUser] + serializer_class = InsecureCommandAlertSerializer + + def post(self, request, *args, **kwargs): + serializer = InsecureCommandAlertSerializer(data=request.data, many=True) + serializer.is_valid(raise_exception=True) + commands = serializer.validated_data + for command in commands: + if command['risk_level'] >= settings.SECURITY_INSECURE_COMMAND_LEVEL and \ + settings.SECURITY_INSECURE_COMMAND and \ + settings.SECURITY_INSECURE_COMMAND_EMAIL_RECEIVER: + send_command_alert_mail(command) + return Response() diff --git a/apps/terminal/backends/command/models.py b/apps/terminal/backends/command/models.py index d0ec04bec..7499322a7 100644 --- a/apps/terminal/backends/command/models.py +++ b/apps/terminal/backends/command/models.py @@ -27,6 +27,11 @@ class AbstractSessionCommand(OrgModelMixin): class Meta: abstract = True + @classmethod + def get_risk_level_str(cls, risk_level): + risk_mapper = dict(cls.RISK_LEVEL_CHOICES) + return risk_mapper.get(risk_level) + @classmethod def from_dict(cls, d): self = cls() diff --git a/apps/terminal/backends/command/serializers.py b/apps/terminal/backends/command/serializers.py index 4df584dbb..c4cf57b04 100644 --- a/apps/terminal/backends/command/serializers.py +++ b/apps/terminal/backends/command/serializers.py @@ -24,3 +24,11 @@ class SessionCommandSerializer(serializers.Serializer): def get_risk_level_display(obj): risk_mapper = dict(AbstractSessionCommand.RISK_LEVEL_CHOICES) return risk_mapper.get(obj.risk_level) + + +class InsecureCommandAlertSerializer(serializers.Serializer): + input = serializers.CharField() + asset = serializers.CharField() + user = serializers.CharField() + risk_level = serializers.IntegerField() + session = serializers.UUIDField() diff --git a/apps/terminal/models.py b/apps/terminal/models.py index 17c40e54b..3a1ff0763 100644 --- a/apps/terminal/models.py +++ b/apps/terminal/models.py @@ -12,6 +12,7 @@ from django.conf import settings from django.core.files.storage import default_storage from django.core.cache import cache +from assets.models import Asset from users.models import User from orgs.mixins.models import OrgModelMixin from common.mixins import CommonModelMixin @@ -227,6 +228,10 @@ class Session(OrgModelMixin): local_path = rel_path return local_path + @property + def asset_obj(self): + return Asset.objects.get(id=self.asset_id) + @property def _date_start_first_has_replay_rdp_session(self): if self.__class__._DATE_START_FIRST_HAS_REPLAY_RDP_SESSION is None: diff --git a/apps/terminal/serializers/__init__.py b/apps/terminal/serializers/__init__.py index 83e851bae..f1714dc21 100644 --- a/apps/terminal/serializers/__init__.py +++ b/apps/terminal/serializers/__init__.py @@ -3,3 +3,4 @@ from .terminal import * from .session import * from .storage import * +from .command import * diff --git a/apps/terminal/serializers/command.py b/apps/terminal/serializers/command.py new file mode 100644 index 000000000..d1e14aa49 --- /dev/null +++ b/apps/terminal/serializers/command.py @@ -0,0 +1,10 @@ +# ~*~ coding: utf-8 ~*~ +from rest_framework import serializers + + +class InsecureCommandAlertSerializer(serializers.Serializer): + input = serializers.CharField() + asset = serializers.CharField() + user = serializers.CharField() + risk_level = serializers.IntegerField() + session = serializers.UUIDField() diff --git a/apps/terminal/urls/api_urls.py b/apps/terminal/urls/api_urls.py index c60f97603..d1c860f03 100644 --- a/apps/terminal/urls/api_urls.py +++ b/apps/terminal/urls/api_urls.py @@ -31,6 +31,7 @@ urlpatterns = [ name='terminal-access-key'), path('terminals/config/', api.TerminalConfig.as_view(), name='terminal-config'), path('commands/export/', api.CommandExportApi.as_view(), name="command-export"), + path('commands/insecure-command/', api.InsecureCommandAlertAPI.as_view(), name="command-alert"), path('replay-storages//test-connective/', api.ReplayStorageTestConnectiveApi.as_view(), name='replay-storage-test-connective'), path('command-storages//test-connective/', api.CommandStorageTestConnectiveApi.as_view(), name='command-storage-test-connective') # v2: get session's replay diff --git a/apps/terminal/utils.py b/apps/terminal/utils.py index f48823f16..9c87695d0 100644 --- a/apps/terminal/utils.py +++ b/apps/terminal/utils.py @@ -4,12 +4,15 @@ import os from django.conf import settings from django.core.files.storage import default_storage +from django.utils.translation import ugettext as _ + import jms_storage -from common.utils import get_logger +from common.tasks import send_mail_async +from common.utils import get_logger, reverse +from settings.models import Setting -from .backends import server_replay_storage -from .models import ReplayStorage +from .models import ReplayStorage, Session, Command logger = get_logger(__name__) @@ -63,3 +66,38 @@ def get_session_replay_url(session): if local_path is None: local_path, url = download_session_replay(session) return local_path, url + + +def send_command_alert_mail(command): + session_obj = Session.objects.get(id=command['session']) + 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': command['input'] + } + recipient_list = settings.SECURITY_INSECURE_COMMAND_EMAIL_RECEIVER.split(',') + message = _(""" + Command: %(command)s +
+ Asset: %(host_name)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, + '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), + } + logger.debug(message) + + send_mail_async.delay(subject, message, recipient_list, html_message=message)