Compare commits

...

525 Commits
v3 ... v4.1.0

Author SHA1 Message Date
Bai
55557d1b2d ignore 2024-08-21 17:49:10 +08:00
Bai
b3a0d81740 fix: job periodic task double run 2024-08-15 20:17:20 +08:00
ibuler
2b160fbbc2 revert: entrypoint.sh 2024-08-15 20:14:24 +08:00
wangruidong
60fcf5fcd3 perf: luna connect asset name set custom value 2024-08-15 19:47:56 +08:00
Bai
7c2e50435d perf: i18n for ldap user import 2024-08-15 15:50:56 +08:00
ZhaoJiSen
57f91d0973 Merge pull request #13980 from jumpserver/pr@dev@no_account_found
perf: Lina translate
2024-08-15 14:49:41 +08:00
feng
49c033e003 perf: Lina translate 2024-08-15 14:47:55 +08:00
Ewall555
6476a8fee8 perf: Translate ticket cancel button 2024-08-15 14:35:43 +08:00
wangruidong
c10db2ab0f perf: LDAP import user Translate 2024-08-15 14:35:06 +08:00
wangruidong
647beffc01 fix: no accounts no send msg 2024-08-14 19:25:11 +08:00
feng
ac0c6ef3d5 perf: Storage update comment failed 2024-08-14 19:18:10 +08:00
feng
e13741827d fix: Domain detail asset amount mistake 2024-08-14 17:37:03 +08:00
wangruidong
29caf0154e perf: Translate batch approval 2024-08-14 17:36:23 +08:00
wangruidong
fbdcc437e6 perf: ticket msg field value set truncate string length 2024-08-14 16:45:43 +08:00
feng
b38e5df1aa perf: Translate 2024-08-14 16:37:57 +08:00
feng
0a39ba0a75 fix: Use only_sudo failed 2024-08-14 16:15:57 +08:00
wangruidong
c56e1bdbbe fix: call get_verify_state_failed_response NotImplementedError 2024-08-13 18:51:15 +08:00
feng
6b00ba271f perf: Replace Feishu to obtain user information interface 2024-08-13 18:13:08 +08:00
wangruidong
bddb1de2f8 perf: Comment translate 2024-08-13 18:04:29 +08:00
wangruidong
32ae77c42d perf: add TERMINAL_SSH_KEY_LIMIT_COUNT conf 2024-08-13 17:39:03 +08:00
feng
3b1701b1aa perf: Translate 2024-08-12 18:41:05 +08:00
feng
3b9bcc719e perf: Reset password: optimize form frame 2024-08-12 15:16:06 +08:00
feng
8e6aa4524d perf: Ip type translate 2024-08-09 17:10:11 +08:00
feng
cea63e6083 perf: Setting user attributes is invalid 2024-08-09 16:53:13 +08:00
feng
5d2d8ca487 perf: Translate 2024-08-08 19:17:34 +08:00
fit2bot
81146f44f7 perf: set default version 2024-08-08 17:54:43 +08:00
fit2bot
9adaa27f6c perf: Luna login expire message (#13917)
* perf: Luna login expire message

* perf: Login timeout open in a new window

---------

Co-authored-by: feng <1304903146@qq.com>
2024-08-08 17:54:02 +08:00
feng
01c565f93f perf: Activity log no display 2024-08-08 16:39:44 +08:00
fit2bot
cb97afffab chore: remove build test 2024-08-08 16:06:51 +08:00
github-actions[bot]
1b55bf1670 perf: Update Dockerfile with new base image tag 2024-08-08 16:06:28 +08:00
fit2bot
b1c68165bb perf: update check version to v1.0.3 2024-08-08 16:06:28 +08:00
wangruidong
5d3e633e83 perf: ldap import msg modify 2024-08-07 19:12:42 +08:00
Eric
c863bf63b1 perf: update lina i18n 2024-08-07 17:45:55 +08:00
wangruidong
c71a6ae4ba fix: ssh_key search failed 2024-08-07 17:04:38 +08:00
wangruidong
38e3d9de8b feat: Allow users to customize asset name and comment 2024-08-07 16:44:01 +08:00
Eric
0c73acd4b9 perf: support only su or sudo 2024-08-07 10:57:09 +08:00
wangruidong
581a5c73a6 perf: object storage builtin comment i18n 2024-08-06 10:44:15 +08:00
feng
e1ed1d7c4c perf: Reset password remove sensitive data 2024-08-05 18:25:11 +08:00
Eric
805e7d1d5f perf: Check whether the applet is available. 2024-08-05 18:18:54 +08:00
feng
1957c2983b perf: Ticket set serial number add lock 2024-08-05 17:53:43 +08:00
Bai
6b1ceae6c5 perf: delete blank line 2024-08-05 16:29:54 +08:00
wangruidong
2a5c41dfaf feat: support configuring multiple SSH keys for users 2024-08-05 15:22:54 +08:00
wangruidong
7a38c9136e feat: Allow users to customize asset name and comment 2024-08-05 14:50:24 +08:00
ZhaoJiSen
9a3fdf76fc Merge pull request #13876 from jumpserver/pr@dev@translate
perf: Translate
2024-08-05 14:33:41 +08:00
feng
136db61011 perf: Translate 2024-08-05 14:31:08 +08:00
ibuler
0d338f80c5 perf: ee dockerfile 2024-08-05 14:23:32 +08:00
feng
bd3909ad27 perf: Third-party user login settings default organization 2024-08-02 15:52:05 +08:00
Eric
96399f8315 perf: update tinker v0.1.7 2024-08-02 14:10:03 +08:00
ibuler
4e90d17484 perf: poetry mirror 2024-08-01 18:18:08 +08:00
ibuler
13de75c41f perf: docker file poetry mirror 2024-08-01 17:37:15 +08:00
ibuler
a77ebc5fee perf: pkg download
perf: resource download

perf: resource download
2024-08-01 16:15:36 +08:00
ibuler
99ce82a6a0 perf: build 2024-08-01 16:15:16 +08:00
wangruidong
ec95d25704 perf: Remove applets, no longer display remote application connection methods 2024-08-01 15:59:00 +08:00
Eric
7c6e83d124 perf: reformat code 2024-07-31 15:09:53 +08:00
ibuler
ad5e88f1e3 perf: display migrate log 2024-07-31 15:09:33 +08:00
wangruidong
b1e958d806 fix: stop job failed 2024-07-30 18:53:16 +08:00
feng
8506ae9edd perf: When account push change secret windows only modify the type equal to password 2024-07-30 18:33:42 +08:00
wangruidong
ceb2a9bb17 fix: Arbitrary File Read in Ansible Play 2024-07-30 18:19:01 +08:00
feng
8d83c953d3 perf: Support WeCom DingTalk FeiShu Lark Slack attribute mapping 2024-07-30 17:48:26 +08:00
Eric
9825f9fbd2 perf: Check if CORE_HOST should ignore SSL 2024-07-30 16:57:04 +08:00
feng
41b2ce06a8 perf: Approval process role selection supports multiple strategies 2024-07-30 16:06:01 +08:00
feng
920cfdac5c perf: Saml2 callback url miss port 2024-07-26 18:17:40 +08:00
Bai
8abf7876cc perf: graceful restart gunicorn worker timeout 30 2024-07-26 14:05:27 +08:00
wangruidong
2e625f2c33 feat: add assets amount field to platform page 2024-07-26 13:45:05 +08:00
halo
88037b2038 perf: Email service authentication username is optional 2024-07-26 11:23:15 +08:00
Bai
457021040a perf: Modifying the label matching logic of an AppletHost (random) 2024-07-25 19:04:57 +08:00
fit2bot
4887b21d35 fix: message publish_task args,kwargs can json encode (#13797)
* fix: message publish_task args,kwargs can json encode

* perf: Update Dockerfile with new base image tag

---------

Co-authored-by: wangruidong <940853815@qq.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-07-24 15:45:27 +08:00
fit2bot
03a66fd563 perf: Modify error message for desktop client login (#13763)
* perf: Modify error message for desktop client login

* perf: Update Dockerfile with new base image tag

---------

Co-authored-by: wangruidong <940853815@qq.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-07-24 10:59:54 +08:00
fit2bot
ef656a8dfd perf: change docker file build (#13761)
* perf: change docker file build

* perf: Update Dockerfile with new base image tag

---------

Co-authored-by: ibuler <ibuler@qq.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-07-23 16:38:00 +08:00
Eric
5e45129e32 perf: add luna i18n 2024-07-23 15:40:32 +08:00
feng
ea64b01da6 perf: You can modify sudo permissions multiple times 2024-07-22 17:27:20 +08:00
feng
c3b863c2be perf: You can modify sudo permissions multiple times 2024-07-22 17:27:20 +08:00
feng
6a7896b712 perf: Gpt3 to gpt-4o-mini 2024-07-19 11:56:07 +08:00
feng
83c1f8e4d3 perf: The gateway password contains ! Password parsing failed 2024-07-19 10:41:54 +08:00
Bai
9d3fdd37a3 perf: user authentication supports configuration redirection 2024-07-19 10:37:52 +08:00
Bai
419195895e perf: update readme 2024-07-18 19:43:38 +08:00
feng
c92188887d perf: Create authorization to add template account Push account parameters 2024-07-18 19:15:46 +08:00
feng
dcfc4e6e7b perf: The locked IP shows the username + translate 2024-07-17 18:10:22 +08:00
feng
836adab5d0 perf: Feishu lark support attributes settings 2024-07-17 16:59:57 +08:00
wangruidong
e93227a53c fix: The asset cannot be obtained during online synchronization 2024-07-17 15:52:40 +08:00
fit2bot
d6f6bb9c1b fix: session viewset api permission validation (#13750)
* fix: session viewset api permission validation

* fix: some api permission validation

---------

Co-authored-by: Bai <baijiangjie@gmail.com>
2024-07-17 15:35:34 +08:00
feng
85825165fc perf: Translate 2024-07-17 11:37:19 +08:00
fit2bot
66047c7926 perf: Migrate (#13741)
Co-authored-by: feng <1304903146@qq.com>
2024-07-17 10:18:53 +08:00
Bai
456bcd2d3f fix: i18n error 2024-07-17 10:01:21 +08:00
Bai
259f68a806 fix: i18n error 2024-07-17 09:54:47 +08:00
feng
4e6231ab19 perf: Notification remove kael magnus 2024-07-16 19:34:18 +08:00
fit2bot
d7bbfdcce6 perf: Translate (#13731)
Co-authored-by: feng <1304903146@qq.com>
2024-07-16 18:38:47 +08:00
吴小白
a0cc9e5db5 fix: deploy applet host 2024-07-16 12:49:33 +08:00
wangruidong
ea6cd853de perf: 社区版移除magnus 2024-07-16 10:40:33 +08:00
fit2bot
53a388a7e0 fix: View user perms bug (#13721)
Co-authored-by: feng <1304903146@qq.com>
2024-07-15 17:50:37 +08:00
fit2bot
13b1938efb perf: Community supports custom platforms (#13719)
Co-authored-by: feng <1304903146@qq.com>
2024-07-15 17:31:44 +08:00
ibuler
6677985e4a perf: support user email login 2024-07-15 16:23:52 +08:00
ibuler
cfa1034161 perf: community add postgre support 2024-07-15 16:19:24 +08:00
ibuler
815973fb63 perf: split user model to many file 2024-07-15 10:54:17 +08:00
吴小白
92d369aaca perf: remove receptor 2024-07-12 18:38:26 +08:00
jiangweidong
281a2d9679 fix: custom sms send success but prompt fails 2024-07-12 18:37:46 +08:00
feng
e9f4615caa perf: Optimize the password reset page experience for new users (the password field will be lengthened) 2024-07-12 15:17:49 +08:00
jiangweidong
c0d2efa72a perf: async sms task params can json 2024-07-12 15:16:41 +08:00
gerry-fit
247f4d5c19 perf: Enterprise Edition Hide Footer Copyright Content 2024-07-11 16:10:42 +08:00
fit2bot
29c29b17d4 perf: Translate (#13686)
Co-authored-by: feng <1304903146@qq.com>
2024-07-10 19:03:19 +08:00
wangruidong
5608f7d20d fix: 定时清理任务不生效问题 2024-07-10 16:13:47 +08:00
Bai
aa8ae36255 perf: README 2024-07-10 14:55:46 +08:00
feng
2292e6f2eb perf: save_passwd_change filter user source local and passwords not emtpy 2024-07-10 14:20:33 +08:00
fit2bot
bf82a1c721 fix: Operator write failed (#13677)
Co-authored-by: feng <1304903146@qq.com>
2024-07-10 11:24:26 +08:00
Bryan
8ef84bbc03 Update README.md 2024-07-10 11:13:42 +08:00
fit2bot
e36d51cc0b perf: country code api (#13672)
* perf: remove notification migrations

* perf: country code api

---------

Co-authored-by: ibuler <ibuler@qq.com>
2024-07-09 19:23:41 +08:00
feng
5c1d0238e1 39.102.214.101 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOzDdXgVjgKrT+ZF5DXcNZqJnkjwvt0M5FbVpvbTOU/v
perf: save_passwd_change filter user source local and passwords not emtpy
2024-07-09 19:08:22 +08:00
wangruidong
c6befe4c4b fix: creat linux asset protocol default value is sftp 2024-07-09 19:04:19 +08:00
Bai
5a57c296a1 feat: add db table data analyzer util 2024-07-09 18:49:51 +08:00
wangruidong
34ddfd24be fix: import role template csv failed 2024-07-09 18:15:44 +08:00
wangruidong
39051ef0fd fix: import role template csv failed 2024-07-09 17:04:59 +08:00
fit2bot
ddd813241c perf: JobExecutionViewSet add SECURITY_COMMAND_EXECUTION permission (#13662)
Co-authored-by: feng <1304903146@qq.com>
2024-07-09 16:34:15 +08:00
mmagi
60f7cbef9a fix: 主机硬件信息硬盘大小避免多次挂载重复计入 2024-07-09 15:52:15 +08:00
wangruidong
4adc981a21 perf: update date_updated when update user roles 2024-07-09 15:51:15 +08:00
mmagi
c42913c15e fix: win主机硬件信息内存单位与其他主机一致;cpu信息字段与其他主机一致 2024-07-09 15:49:35 +08:00
halo
bb6d60b46d perf: 优化创建子节点时锁置后 2024-07-09 15:15:06 +08:00
fit2bot
afe7f03c16 perf: login style change (#13539)
* perf: login style change

* perf: login style change

* perf: login style change

---------

Co-authored-by: zhaojisen <1301338853@qq.com>
2024-07-09 15:02:37 +08:00
fit2bot
ba8d3be9a6 fix: Operatelog plaintext storage AKSK (#13506)
* fix: Operatelog plaintext storage AKSK

* perf: Encrypt some field when saving operatelog

* fix: Operatelog plaintext storage AKSK

---------

Co-authored-by: jiangweidong <1053570670@qq.com>
2024-07-09 14:52:00 +08:00
Eric
d14d8869ac perf: add connection options for mongodb 2024-07-09 14:00:59 +08:00
wangruidong
2f7391efc3 perf: modify migrations 2024-07-09 11:38:47 +08:00
ibuler
75fa96b29c perf: remove notification migrations 2024-07-09 11:25:49 +08:00
maninhill
c56ab9bc1e chore: Update README.zh-CN.md 2024-07-09 11:11:20 +08:00
fit2bot
443e492fd4 perf: Asset type cloud add community version (#13640)
Co-authored-by: feng <1304903146@qq.com>
2024-07-09 10:59:56 +08:00
ibuler
b8c223d525 perf: can set xpack disable force 2024-07-09 10:56:20 +08:00
吴小白
a509afe24b fix: FromAsCasing keywords 2024-07-09 10:35:59 +08:00
fit2bot
9654add528 perf: Translate (#13633)
Co-authored-by: feng <1304903146@qq.com>
2024-07-08 15:43:56 +08:00
Bryan
d0a9409078 Update README.md 2024-07-08 14:51:07 +08:00
fit2bot
5836583490 fix: The account gather results do not have the last login time (#13625)
Co-authored-by: feng <1304903146@qq.com>
2024-07-08 11:42:24 +08:00
fit2bot
57d689bee6 perf: Translate (#13620)
Co-authored-by: feng <1304903146@qq.com>
2024-07-05 18:09:39 +08:00
ZhaoJiSen
8a3fb6bd4d Merge pull request #13616 from jumpserver/pr@dev@translate
perf: Translate
2024-07-05 16:50:00 +08:00
feng
78bd3f581a perf: Translate 2024-07-05 16:36:55 +08:00
fit2bot
d07c476507 perf: Translate (#13612)
Co-authored-by: feng <1304903146@qq.com>
2024-07-04 18:14:34 +08:00
fit2bot
50d196eda4 perf: Job api add filter options (#13610)
Co-authored-by: feng <1304903146@qq.com>
2024-07-04 16:03:51 +08:00
ibuler
823d9af91d perf: upgrade to v4, more international and more standardized. 2024-07-04 10:06:43 +08:00
Bryan
3731123369 Update README.md 2024-07-04 09:47:56 +08:00
Bryan
1a68c4b44a Update README.md 2024-07-04 09:47:56 +08:00
Bryan
0f79006b59 Update README.md 2024-07-04 09:47:56 +08:00
maninhill
c95ad5a31c chore: Update README.md 2024-07-04 09:44:01 +08:00
maninhill
e25a96d359 chore: Update README.md 2024-07-03 22:56:08 +08:00
maninhill
04284adc87 chore: Update README.md 2024-07-03 22:40:32 +08:00
maninhill
7ee7d50f22 chore: Update README.md 2024-07-03 18:54:56 +08:00
fit2bot
3d015398c3 perf: Luna translate (#13599)
Co-authored-by: feng <1304903146@qq.com>
2024-07-03 17:50:55 +08:00
wangruidong
da8b328f80 fix: bulk delete playbook 500 error 2024-07-03 17:15:50 +08:00
fit2bot
82a6702c90 perf: Translate (#13594)
Co-authored-by: feng <1304903146@qq.com>
2024-07-03 16:50:09 +08:00
fit2bot
ad267bcd35 perf: Translate (#13593)
Co-authored-by: feng <1304903146@qq.com>
Co-authored-by: feng626 <57284900+feng626@users.noreply.github.com>
2024-07-03 16:42:02 +08:00
maninhill
15dc922bca chore: Update README.md 2024-07-03 16:10:03 +08:00
Aaron3S
22405d46d6 feat: add chen translate 2024-07-03 15:54:19 +08:00
wangruidong
35b0741068 fix: modify render_to_json rbac 2024-07-03 15:53:25 +08:00
刘瑞斌
d7b8174fd0 chore: use unseq list 2024-07-03 15:35:14 +08:00
ibuler
43cfb11bca perf: tag export format use name:value style 2024-07-03 15:34:53 +08:00
wangruidong
f955cebaa0 perf: Translate 2024-07-03 15:17:10 +08:00
fit2bot
5d7ec054e6 perf: Community limit (#13584)
Co-authored-by: feng <1304903146@qq.com>
2024-07-03 15:01:37 +08:00
Bryan
6088a38eed Update README.md 2024-07-03 14:51:51 +08:00
fit2bot
e1a84e76bb perf: some translation (#13585)
* perf: applet host platform

* perf: some translation

---------

Co-authored-by: ibuler <ibuler@qq.com>
2024-07-03 14:51:21 +08:00
wangruidong
19f9179e7f perf: update migrations same with v3 2024-07-03 14:46:17 +08:00
Bryan
aa4a8d5b42 Update README.md 2024-07-03 14:44:28 +08:00
老广
10ba31086c Update README.md 2024-07-03 14:40:49 +08:00
fit2bot
fa8312bc65 perf: Translate (#13575)
Co-authored-by: feng <1304903146@qq.com>
2024-07-02 18:30:23 +08:00
maninhill
512e727dd4 chore: Update CONTRIBUTING.md 2024-07-02 18:25:57 +08:00
wangruidong
a529609275 fix: Resolve issue with update permissions preventing data import 2024-07-02 16:34:10 +08:00
fit2bot
a8973330fe fix: Account tempale cannot push params (#13571)
Co-authored-by: feng <1304903146@qq.com>
2024-07-02 16:12:27 +08:00
ibuler
d42acc3848 perf: applet host platform 2024-07-02 15:15:13 +08:00
fit2bot
912cefbc85 perf: Lina LoginLogTotal translate (#13569)
Co-authored-by: feng <1304903146@qq.com>
2024-07-02 15:10:33 +08:00
feng
2bb475d0ce perf: Account push log optimization 2024-07-02 14:55:38 +08:00
ibuler
22788ff2da perf: remove org api scope 2024-07-02 14:11:16 +08:00
fit2bot
5594b25ae0 perf: Login confirm return failed (#13560)
Co-authored-by: feng <1304903146@qq.com>
2024-07-02 11:02:30 +08:00
Aaron3S
4733d89807 perf: 优化 chen 翻译 2024-07-02 10:19:36 +08:00
wangruidong
c718fe1a9d perf: modify user login ACL msg 2024-07-01 19:30:42 +08:00
wangruidong
237b4a82c9 fix: handle 500 error when re-binding DingTalk user to another user 2024-07-01 18:03:47 +08:00
fit2bot
76e0cbb8ac perf: update lion i18n (#13556)
* perf: update lion i18n

* perf: update i18n

---------

Co-authored-by: Eric <xplzv@126.com>
2024-07-01 16:22:46 +08:00
fit2bot
b3a670d380 perf: Lina mfa translate (#13555)
Co-authored-by: feng <1304903146@qq.com>
Co-authored-by: feng626 <57284900+feng626@users.noreply.github.com>
2024-07-01 16:12:13 +08:00
wangruidong
db243d050e fix: playbook FileNotFoundError 2024-07-01 15:51:14 +08:00
wangruidong
cd2648291e perf: Translate 2024-07-01 15:15:53 +08:00
wangruidong
4a49bde1f0 perf: add compatibility for macOS environment 2024-07-01 15:02:32 +08:00
wangruidong
d9754496d0 perf: add bubblewrap 2024-07-01 15:02:32 +08:00
fit2bot
6753b5fd19 perf: Translate (#13550)
Co-authored-by: feng <1304903146@qq.com>
2024-07-01 11:42:33 +08:00
fit2bot
aeb320ba30 perf: Lina translate (#13548)
Co-authored-by: feng <1304903146@qq.com>
2024-07-01 10:15:06 +08:00
ibuler
e712e8ccfc perf: ansible version and set user lang 2024-06-28 18:59:44 +08:00
fit2bot
1d6f827296 perf: Migrate (#13540)
Co-authored-by: feng <1304903146@qq.com>
2024-06-28 18:36:24 +08:00
ibuler
772c9b385c perf: lang setting from core 2024-06-28 16:40:25 +08:00
wangruidong
f5053728e7 perf: Translate Tags 2024-06-28 15:28:57 +08:00
wangruidong
f67fd29499 perf: Community update user list API to exclude specific fields 2024-06-28 14:54:07 +08:00
fit2bot
138ea35620 fix: Got perm tree 500 (#13533)
Co-authored-by: feng <1304903146@qq.com>
2024-06-28 11:39:09 +08:00
wangruidong
bf56549f01 perf: Task log optimize 2024-06-28 10:25:10 +08:00
Eric
908181af64 perf: clean mp4 replay file
perf: refactor code to clean files
2024-06-27 18:12:37 +08:00
fit2bot
7b4d3c44f8 fix: Asset perm calculate failed (#13530)
Co-authored-by: feng <1304903146@qq.com>
Co-authored-by: feng626 <57284900+feng626@users.noreply.github.com>
2024-06-27 18:05:08 +08:00
feng
b7a6454d65 fix: Asset perm calculate failed 2024-06-27 17:56:41 +08:00
ibuler
6d81fa7fdf perf: change default login title 2024-06-27 17:55:57 +08:00
wangruidong
0e8833cce3 perf: Translate Client connection 2024-06-27 11:27:43 +08:00
fit2bot
24d9e65532 fix: Asset 003 migrate failed (#13519)
Co-authored-by: feng <1304903146@qq.com>
2024-06-26 21:42:43 +08:00
ibuler
bca9bdf619 perf: translate some word 2024-06-26 19:29:56 +08:00
fit2bot
cd39e20808 perf: Applet host provider add filterset (#13517)
Co-authored-by: feng <1304903146@qq.com>
2024-06-26 19:07:28 +08:00
fit2bot
9c8680d3f4 perf: Translate (#13514)
Co-authored-by: feng <1304903146@qq.com>
2024-06-26 17:06:23 +08:00
wangruidong
dd84ca8f85 fix: Virtualapp rbac config 2024-06-26 16:43:32 +08:00
Eric
96c1f689c0 perf: modify dbeave remoteapp dislay name 2024-06-26 16:19:09 +08:00
wangruidong
84855bfd7e perf: Translate Lark 2024-06-26 16:13:16 +08:00
fit2bot
40c5a218a9 perf: Translate (#13509)
Co-authored-by: feng <1304903146@qq.com>
Co-authored-by: feng626 <57284900+feng626@users.noreply.github.com>
2024-06-26 15:18:37 +08:00
wangruidong
8e87972a76 perf: Translate ticket action 2024-06-26 14:37:32 +08:00
fit2bot
3faee9b80c perf: change some translate (#13505)
* perf: some word translate


---------

Co-authored-by: ibuler <ibuler@qq.com>
2024-06-25 19:36:35 +08:00
fit2bot
5a1389a187 perf: Translate (#13504)
Co-authored-by: feng <1304903146@qq.com>
2024-06-25 19:10:32 +08:00
Eric
565c2f493c perf: add lion i18n 2024-06-25 19:04:40 +08:00
Bai
8d48593fc4 perf: Update README 2024-06-25 16:44:00 +08:00
fit2bot
b50c96fcd6 perf: Update README (#13497)
* perf: Update README

* perf: Update README

* perf: Update README

---------

Co-authored-by: Bai <baijiangjie@gmail.com>
2024-06-25 16:29:14 +08:00
ibuler
85700a2a26 perf: some word translate 2024-06-25 15:36:25 +08:00
Bryan
66615b7dd3 Update README.md 2024-06-25 15:34:31 +08:00
Bryan
2c1a1fa31e Update README.md 2024-06-25 15:34:31 +08:00
wangruidong
bbc442b56e perf: Translate CanDragSelect tips 2024-06-25 15:31:30 +08:00
Bryan
1ca579f4f0 Update README.md 2024-06-25 15:01:47 +08:00
Bryan
9e3b23179c Update README.md 2024-06-25 15:01:47 +08:00
Bryan
9fd861d047 Update README.md 2024-06-25 15:01:47 +08:00
fit2bot
4abfcb27d1 perf: Update README (#13491)
* perf: Update README

* perf: Update README

* perf: Update README

* perf: Update README

* perf: Update README

---------

Co-authored-by: Bai <baijiangjie@gmail.com>
Co-authored-by: Bryan <jiangjie.bai@fit2cloud.com>
2024-06-25 11:22:38 +08:00
老广
3463761693 Update README.md 2024-06-25 10:28:14 +08:00
Eric
c311adc1da chore: update mysqlclient 2.2.4 2024-06-24 20:12:09 +08:00
ibuler
ee258707c8 perf: change initial passwd to ChangeMe 2024-06-24 20:11:49 +08:00
Eric
17d96669fe perf: remove pymysql 2024-06-24 20:11:23 +08:00
fit2bot
3fade107d5 perf: Translate (#13489)
Co-authored-by: feng <1304903146@qq.com>
Co-authored-by: feng626 <57284900+feng626@users.noreply.github.com>
2024-06-24 20:10:34 +08:00
wangruidong
f91ec6fa6a perf: favor & disfavor trans 2024-06-24 19:38:19 +08:00
Bai
dfff41e9d6 perf: Update README 2024-06-24 19:25:41 +08:00
Bai
478e81b8fa perf: Update README 2024-06-24 19:25:41 +08:00
wangruidong
9b14f2aa1f perf: ftp log has_file trans 2024-06-24 19:18:26 +08:00
Bryan
18e648af6e Update README.md (#13481)
* Update README.md

* perf: Update README

* perf: Update README

* perf: Update README

* perf: Update README

* perf: Update README

* perf: Update README

* perf: Update README

* perf: Update README

* perf: Update README

* perf: Update README

* perf: Update README

* perf: Update README

* perf: Update README
2024-06-24 19:16:30 +08:00
老广
45bd69585a Update README.md 2024-06-24 18:24:21 +08:00
maninhill
42a0cde450 chore: Update README.md 2024-06-24 18:22:38 +08:00
Bai
a9ef21ea3f fix: poetry lock 2024-06-24 17:07:34 +08:00
Bai
13d24a12db fix: i18n messages 2024-06-24 17:07:34 +08:00
wangruidong
2bd09f246d fix: raise http 400 when batch delete in component settings 2024-06-24 16:25:54 +08:00
fit2bot
23c81cf5eb perf: Migrate asset dameng json (#13477)
Co-authored-by: feng <1304903146@qq.com>
2024-06-24 16:24:40 +08:00
Bryan
e95284335e Merge pull request #13472 from jumpserver/v4
Merge v4 to dev
2024-06-24 15:50:29 +08:00
Bai
1c7f82e65a Merge v4 to dev (Update poetry lock) 2024-06-24 15:47:13 +08:00
Bai
dfde50c768 Merge v4 to dev 2024-06-24 15:43:40 +08:00
ibuler
8bfbebf29e Merge branch 'v4' of github.com:jumpserver/jumpserver into v4 2024-06-24 14:51:42 +08:00
ibuler
8157f9891f perf: 优化批量删除判断 2024-06-24 14:50:53 +08:00
wangruidong
ad95adc833 perf: trans LDAP msg 2024-06-24 14:24:06 +08:00
ibuler
f7e55c9b89 merge: with remote 2024-06-24 11:06:32 +08:00
ibuler
11b125655d perf: passkey help msg 2024-06-24 11:05:41 +08:00
fit2bot
c6628a1959 perf: Translate (#13471)
Co-authored-by: feng <1304903146@qq.com>
2024-06-24 10:57:10 +08:00
fit2bot
ae7dbbedcc perf: Edit rbac perms (#13468)
Co-authored-by: feng <1304903146@qq.com>
Co-authored-by: feng626 <57284900+feng626@users.noreply.github.com>
2024-06-21 19:08:37 +08:00
fit2bot
407a77f61b perf: trans StopLogOutput 2024-06-21 18:05:39 +08:00
fit2bot
e06f9a03d6 perf: System setting perm (#13463)
Co-authored-by: feng <1304903146@qq.com>
2024-06-20 19:19:14 +08:00
fit2bot
07edbea54e perf: Update ah translate (#13459)
Co-authored-by: feng <1304903146@qq.com>
2024-06-20 16:56:41 +08:00
ibuler
856e501a15 Merge branch 'v4' of github.com:jumpserver/jumpserver into v4 2024-06-20 11:11:19 +08:00
ibuler
8cf900f9de perf: 生产授权树 2024-06-20 11:10:57 +08:00
fit2bot
a54605ac79 perf: Translate (#13454)
Co-authored-by: feng <1304903146@qq.com>
2024-06-19 19:36:47 +08:00
wangruidong
92790d711e perf: Add log download button 2024-06-19 15:56:02 +08:00
fit2bot
5b548d8d57 perf: Translate (#13450)
Co-authored-by: feng <1304903146@qq.com>
2024-06-19 14:48:48 +08:00
fit2bot
afdf777386 perf: Translate account (#13445)
Co-authored-by: feng <1304903146@qq.com>
2024-06-18 19:39:27 +08:00
ibuler
cd2af0dcf7 perf: english traslation 2024-06-18 18:47:06 +08:00
Bai
523468f7af fix: Add API Exception traceback log if settings.DEBUG_DEV enabled 2024-06-18 11:58:44 +08:00
Bai
9385d04812 fix: Add API Exception traceback log if settings.DEBUG_DEV enabled 2024-06-18 11:55:56 +08:00
fit2bot
2ee435a8ec perf: Translate (#13438)
Co-authored-by: feng <1304903146@qq.com>
2024-06-17 19:47:05 +08:00
fit2bot
f3a827b76b perf: Translate (#13437)
Co-authored-by: feng <1304903146@qq.com>
2024-06-17 19:22:45 +08:00
fit2bot
50ceca9f06 perf: Perms system settings (#13435)
Co-authored-by: feng <1304903146@qq.com>
2024-06-17 17:40:03 +08:00
Bai
8a5e86dfa7 fix: migrations assets 0003 json.loads error 2024-06-17 10:39:38 +08:00
fit2bot
6ffae48ab2 perf: Translate (#13431)
Co-authored-by: feng <1304903146@qq.com>
2024-06-14 19:15:41 +08:00
fit2bot
9ff78c8569 perf: Lina translate (#13427)
Co-authored-by: feng <1304903146@qq.com>
2024-06-14 15:16:00 +08:00
fit2bot
d6718d7b78 perf: Device asset remove_account_enabled false (#13426)
Co-authored-by: feng <1304903146@qq.com>
2024-06-14 14:47:13 +08:00
fit2bot
32966b260a perf: Refactor OperateLogStore separator logic for database compatibility (#13424)
Co-authored-by: feng <1304903146@qq.com>
Co-authored-by: feng626 <57284900+feng626@users.noreply.github.com>
2024-06-14 14:25:14 +08:00
feng
6c59888d77 perf: Refactor OperateLogStore separator logic for database compatibility 2024-06-14 14:09:53 +08:00
Bai
1c1d839b82 fix: i18n compilemessages 2024-06-14 09:53:08 +08:00
wangruidong
7d295cc675 perf: rbac applet modify translate 2024-06-13 18:26:10 +08:00
fit2bot
75496cbe91 perf: Account backup failed (#13420)
Co-authored-by: feng <1304903146@qq.com>
2024-06-13 18:20:00 +08:00
wangruidong
11f6a029de perf: modify translate 2024-06-13 17:45:39 +08:00
Bai
e40c66c7ed fix: select_for_update error for out join sql 2024-06-13 15:50:11 +08:00
ibuler
2a33337963 Merge branch 'v4' of github.com:jumpserver/jumpserver into v4 2024-06-13 13:04:07 +08:00
ibuler
bd1a768743 perf: change some translation 2024-06-13 13:02:03 +08:00
fit2bot
0c0ec098ae perf: Modify some translations (#13412)
Co-authored-by: wangruidong <940853815@qq.com>
2024-06-12 19:38:45 +08:00
fit2bot
37ad7b32e4 perf: Cloud account translate (#13413)
Co-authored-by: feng <1304903146@qq.com>
2024-06-12 19:38:07 +08:00
ibuler
2640963938 Merge branch 'v4' of github.com:jumpserver/jumpserver into v4 2024-06-12 19:29:14 +08:00
ibuler
6bc9181c25 fix: some bugs 2024-06-12 19:25:36 +08:00
fit2bot
d8379195e6 perf: Platform automation add remove account method (#13411)
Co-authored-by: feng <1304903146@qq.com>
2024-06-12 19:23:40 +08:00
Bai
9195c658a0 perf: Update djangojs.po file 2024-06-12 18:36:04 +08:00
wangruidong
3fb261b5c8 fix: Role details - multiple instances of English in permissions list 2024-06-12 17:30:03 +08:00
ibuler
aa16c3d3a1 Merge branch 'v4' of github.com:jumpserver/jumpserver into v4 2024-06-12 16:19:26 +08:00
ibuler
7be6cf2b73 perf: tags update 2024-06-12 16:19:16 +08:00
fit2bot
60738da053 perf: Automation remove account task fail (#13406)
Co-authored-by: feng <1304903146@qq.com>
2024-06-12 15:30:52 +08:00
Aaron3S
507ad10389 feat: add some translations for chen 2024-06-12 15:27:53 +08:00
wangruidong
67bc16238c perf: i18n 2024-06-12 10:25:22 +08:00
Aaron3S
db88f6c9b4 perf: 优化 chen 翻译文件 2024-06-11 18:19:30 +08:00
fit2bot
8b7f60d43e fix: Cloud sync related issues (#13396)
Co-authored-by: feng <1304903146@qq.com>
2024-06-11 17:42:13 +08:00
ibuler
cd1f6a9137 Merge branch 'v4' of github.com:jumpserver/jumpserver into v4 2024-06-06 16:56:47 +08:00
ibuler
7973d066a3 revert: asset permission real accounts serializer 2024-06-06 16:56:07 +08:00
wangruidong
ad65097a8f perf: Crontab i18n 2024-06-06 14:49:56 +08:00
ibuler
1b05f56598 Merge branch 'v4' of github.com:jumpserver/jumpserver into v4 2024-06-05 19:34:04 +08:00
ibuler
3468f8cd40 perf: 修改授权的账号 2024-06-05 19:33:40 +08:00
Bryan
5c81e974cd Update README.md 2024-06-05 18:00:13 +08:00
Bryan
b638cf7417 Update README.md 2024-06-05 17:53:26 +08:00
Bryan
1db1961cc0 Update README.md 2024-06-05 17:25:45 +08:00
Bryan
811afdcf1a Update README.md 2024-06-05 17:25:12 +08:00
Bryan
1f87ce2a47 Update README.md 2024-06-05 17:09:04 +08:00
Bryan
8213e38e6a Update README.md 2024-06-05 17:01:31 +08:00
ibuler
263bcbb566 Merge branch 'v4' of github.com:jumpserver/jumpserver into v4 2024-06-04 19:08:51 +08:00
ibuler
050ddc88f2 perf: labels 支持颜色 2024-06-04 19:08:16 +08:00
feng
38e8791d9f perf: Community Edition Remove db client 2024-06-04 16:24:37 +08:00
fit2bot
deb8474c1b feat: add oracle database web-cli connect method (#13358)
Co-authored-by: Aaron3S <chenyang@fit2cloud.com>
2024-06-04 14:51:47 +08:00
fit2bot
12740ead08 perf: ticket translate (#13357)
Co-authored-by: feng <1304903146@qq.com>
2024-06-04 11:01:33 +08:00
Bai
6322559bd7 perf: i18n updated 2024-06-03 19:15:40 +08:00
Aaron3S
6c5eb00fb6 feat: 增加 chen 翻译文件 2024-06-03 16:42:23 +08:00
feng
dad2f8eb65 perf: koko translate 2024-06-03 14:29:57 +08:00
Bai
c8679f48f5 perf: Update i18n 2024-06-03 11:44:16 +08:00
fit2bot
510dc1eaf2 perf: translate (#13347)
Co-authored-by: feng <1304903146@qq.com>
2024-06-03 10:26:12 +08:00
wangruidong
a313753757 perf: action i18n 2024-05-31 16:34:03 +08:00
wangruidong
53f106b30d perf: i18n 2024-05-31 14:39:56 +08:00
吴小白
0d27bfcfa9 perf: 添加 arm64 缺失依赖 2024-05-31 10:56:48 +08:00
wangruidong
ba6660216c perf: celery task log format 2024-05-31 10:15:11 +08:00
吴小白
3536af2051 perf: 按要求移除重复构建代码 2024-05-31 10:13:22 +08:00
fit2bot
21bb0a8162 fix: translate json (#13322)
Co-authored-by: feng <1304903146@qq.com>
2024-05-30 14:20:12 +08:00
jiangweidong
d718398791 feat: refactoring sync module (#13293) 2024-05-29 18:44:32 +08:00
吴小白
0b65e3ffda perf: 按要求移除重复构建代码 2024-05-28 18:50:11 +08:00
feng
91a1da57e9 perf: mfa interface optimization, mobile phone number can be empty 2024-05-28 17:27:17 +08:00
ibuler
f95cbd6977 merge: with remote 2024-05-27 16:46:13 +08:00
ibuler
f16ec02c40 perf: 修改翻译 2024-05-27 16:43:26 +08:00
wangruidong
0ea2339ad5 perf: notification i18n 2024-05-27 15:24:31 +08:00
Bai
8ebdd59e00 Merge branch 'v4_bain' into v4 2024-05-27 11:35:16 +08:00
Bai
c4e30737a4 perf: i18n bai 2024-05-27 11:34:53 +08:00
ibuler
f127aca5f8 Merge branch 'v4' of github.com:jumpserver/jumpserver into v4 2024-05-27 11:20:59 +08:00
ibuler
7333c8e094 perf: 修改 json 空格数量 2024-05-27 11:20:35 +08:00
Bai
a1e9382275 perf: i18n bai 2024-05-27 11:13:13 +08:00
ibuler
097a6c5c5f perf: 修改 label 为 tag 2024-05-27 11:07:36 +08:00
fit2bot
4e023057cc perf: ticket translate (#13291)
Co-authored-by: feng <1304903146@qq.com>
2024-05-27 11:00:54 +08:00
ibuler
4034e2152c Merge branch 'v4' of github.com:jumpserver/jumpserver into v4 2024-05-24 18:43:07 +08:00
ibuler
e8d6c6b711 merge: with remote 2024-05-24 18:42:37 +08:00
Bai
43215d27c5 perf: migrations i18n 2024-05-24 14:54:56 +08:00
Bai
e20db96331 Merge branch 'v4_baisse' into v4 2024-05-24 14:42:27 +08:00
Bai
564ad40b99 perf: i18n System Settings End 2024-05-24 14:41:28 +08:00
ibuler
32ef4c79da perf: 修改翻译 2024-05-23 19:00:28 +08:00
wangruidong
af4f6ebb26 perf: dashboard i18n 2024-05-23 18:23:10 +08:00
wangruidong
33b688b021 perf: modify task log i18n 2024-05-23 18:12:52 +08:00
fit2bot
b179770dbf perf: del extra translate (#13274)
Co-authored-by: feng <1304903146@qq.com>
Co-authored-by: feng626 <57284900+feng626@users.noreply.github.com>
2024-05-22 19:24:25 +08:00
Bai
e7f92ec0d7 merged: Merge to v4 (bai) 2024-05-22 18:12:35 +08:00
Bai
79449a8a02 perf: i18n System Settings -> Authentication-OIDC 2024-05-22 17:51:45 +08:00
fit2bot
f259509ef8 fix: notification migrate file (#13269)
Co-authored-by: feng <1304903146@qq.com>
2024-05-22 10:47:55 +08:00
fit2bot
82977f9023 perf: tickets notifications add default data migrate file (#13268)
Co-authored-by: feng <1304903146@qq.com>
2024-05-21 19:24:26 +08:00
Bai
4a5205c5ac perf: i18n System Settings -> Features 2024-05-21 16:11:13 +08:00
ibuler
714b4ef7f4 merge: with remote 2024-05-21 14:47:37 +08:00
ibuler
df091f0ee1 perf: 添加 terminal 的 migrate 2024-05-21 14:44:48 +08:00
wangruidong
7037cf56ec perf: i18n 2024-05-21 10:47:15 +08:00
Eric
f683d195e4 perf: update lina i18n 2024-05-20 19:06:28 +08:00
Bai
5ab55b823c perf: i18n System Settings -> General,Org,Notifications 2024-05-20 18:39:57 +08:00
吴小白
0f2c769e8d Merge pull request #13255 from jumpserver/pr@v4@fix_docker_build
fix: 修正企业镜像缺失依赖
2024-05-20 15:02:56 +08:00
吴小白
1d53f292ae fix: 修正企业镜像缺失依赖 2024-05-20 14:57:15 +08:00
fit2bot
a15335cac9 perf: lina ja translate (#13252)
Co-authored-by: feng <1304903146@qq.com>
2024-05-17 18:46:30 +08:00
wangruidong
f33cf07859 perf: i18n 2024-05-17 18:30:19 +08:00
fit2bot
bce55421ce perf: MenuAccountTemplates zh translate (#13250)
Co-authored-by: feng <1304903146@qq.com>
2024-05-17 17:56:09 +08:00
fit2bot
c3449cd6bc perf: account translate (#13249)
Co-authored-by: feng <1304903146@qq.com>
2024-05-17 16:47:02 +08:00
ibuler
4e903ce19b Merge branch 'v4' of github.com:jumpserver/jumpserver into v4 2024-05-17 16:32:08 +08:00
ibuler
90826b358c perf: 修改翻译 2024-05-17 16:31:39 +08:00
吴小白
7d46aa9892 perf: 优化发布机部署 2024-05-17 15:22:16 +08:00
ibuler
49d2bd93b7 perf: merge with remote 2024-05-17 09:59:12 +08:00
ibuler
9f103a88d6 perf: 修改 org name 2024-05-17 09:58:12 +08:00
fit2bot
ce33bdc370 perf: account related translate (#13241)
Co-authored-by: feng <1304903146@qq.com>
2024-05-16 19:39:03 +08:00
fit2bot
cdf1f81c8a perf: account automation translate (#13240)
Co-authored-by: feng <1304903146@qq.com>
2024-05-16 19:12:24 +08:00
Eric
79edff5fca perf: 支持 loki log 2024-05-16 19:00:47 +08:00
fit2bot
a7316bc7c1 perf: translate (#13228)
Co-authored-by: feng <1304903146@qq.com>
2024-05-15 18:43:31 +08:00
jiangweidong
09f802b00d perf: cloud sync module adjustment (#13197)
* perf: cloud sync module adjustment

* perf: cloud sync module adjustment
2024-05-14 10:36:17 +08:00
wangruidong
a644b84bb1 perf: dashboard zh,ja,zh_hant i18n 2024-05-13 18:31:54 +08:00
吴小白
b6f48111e3 feat: 更新 Dockerfile 2024-05-13 18:25:06 +08:00
wangruidong
3a6e4e7fb6 perf: file transfer boot step help tips i18n 2024-05-13 18:18:27 +08:00
wangruidong
e42a98ff95 perf: celery task log css optimize 2024-05-13 18:16:36 +08:00
ibuler
8fe511cec6 perf: remove *.mo 2024-05-13 17:35:00 +08:00
Bai
ffb3cd13cb perf: Delete locale dir 2024-05-13 17:26:38 +08:00
Bai
b1abf8a339 perf: Merge local v4 2024-05-13 15:58:59 +08:00
ibuler
89d20c8a4d perf: 修改一些翻译 2024-05-13 15:28:11 +08:00
ibuler
d66f923c0c perf: 修改翻译 2024-05-13 10:40:08 +08:00
ibuler
d3c14428a1 perf: remove an or a 2024-05-13 10:35:21 +08:00
ibuler
c104f85b18 perf: 修改翻译 2024-05-13 10:29:26 +08:00
fit2bot
755d8124ac perf: account backup translate (#13198)
Co-authored-by: feng <1304903146@qq.com>
2024-05-11 19:48:15 +08:00
Bai
a029cc8ed5 perf: i18n Personal Settings -> All sub menu 2024-05-11 18:55:03 +08:00
ibuler
111dfa8c29 perf: 修改大小写 2024-05-11 16:03:40 +08:00
ibuler
5f892c3afe perf: change i18n 2024-05-11 14:41:58 +08:00
fit2bot
313202fe41 perf: 合并 migrations (#13187)
* perf: 修改 Migrations

* perf: 合并 migrations

* perf: remove unuse

* perf: change to file

---------

Co-authored-by: ibuler <ibuler@qq.com>
2024-05-11 11:22:01 +08:00
Bai
af1adc3baa perf: i18n Personal Settings -> All sub menu 2024-05-11 11:17:02 +08:00
ibuler
be214c84d1 merge: with dev 2024-05-10 18:10:18 +08:00
fit2bot
082614e7b0 perf: A wave of migration Japan, Taiwan China font (#13188)
Co-authored-by: feng <1304903146@qq.com>
2024-05-10 15:13:40 +08:00
wangruidong
83835747c5 perf: i18n 2024-05-10 10:06:44 +08:00
Bai
2a7b48c83d perf: i18n Personal Settings -> Profile 2024-05-09 15:26:38 +08:00
ibuler
a9068496d9 perf: 打算压缩 migratons 2024-05-09 11:01:01 +08:00
fit2bot
8bad88e798 perf: 优化账号相关翻译 (#13177)
Co-authored-by: feng <1304903146@qq.com>
2024-05-08 18:04:46 +08:00
吴小白
9f45eeeb1f fix: 优化构建缓存 2024-05-07 11:43:40 +08:00
吴小白
60110982f1 fix: 修正构建错误 2024-04-30 11:24:17 +08:00
ibuler
259204bfe2 Merge branch 'v4' of github.com:jumpserver/jumpserver into v4 2024-04-30 10:42:31 +08:00
wangruidong
c55e9679db perf: dashboard i18n 2024-04-30 10:31:22 +08:00
ibuler
c05a3c315a Merge branch 'v4' of github.com:jumpserver/jumpserver into v4 2024-04-29 15:07:25 +08:00
ibuler
dbdf586f5b add i18n 2024-04-29 15:06:53 +08:00
Bai
b1bd4db3e9 perf: Update poetry.lock 2024-04-29 11:47:18 +08:00
fit2bot
7806a13db5 feat: 默认数据库使用 PostgreSQL (#13088)
Co-authored-by: 吴小白 <296015668@qq.com>
Co-authored-by: Bryan <jiangjie.bai@fit2cloud.com>
2024-04-29 11:46:16 +08:00
Bai
928f564109 merge: into dev from v4: poetry lock file updated 2024-04-29 11:20:37 +08:00
Bai
328f718fe8 merge: into dev from v4: i18n file 2024-04-29 11:16:09 +08:00
Bai
cb4402c610 merge: into dev from v4 2024-04-29 11:07:43 +08:00
feng626
fbc4cb9046 Revert "perf: remove ticket model" (#13145)
This reverts commit 94567b86f0.
2024-04-28 18:26:49 +08:00
feng
94567b86f0 perf: remove ticket model 2024-04-28 18:02:57 +08:00
ibuler
8aa707427f pref: remove user source choice 2024-04-28 16:01:09 +08:00
ibuler
7d64b8419f Merge branch 'v4' of github.com:jumpserver/jumpserver into v4 2024-04-28 14:04:55 +08:00
ibuler
fad9249810 perf: 再次修改菜单 2024-04-28 14:04:28 +08:00
wangruidong
bb4fbc3a1c perf: index page typo 2024-04-24 18:05:03 +08:00
ibuler
d7916a62f0 perf: 修改翻译 2024-04-23 18:11:05 +08:00
ibuler
da27e1b93c perf: 修改翻译 2024-04-23 14:16:21 +08:00
ibuler
99b24cad00 perf: add open sans font 2024-04-22 15:08:28 +08:00
ibuler
9dbdd6ac60 perf: change i18n 2024-04-18 20:12:01 +08:00
ibuler
f8953441e3 Merge branch 'v4' of github.com:jumpserver/jumpserver into v4 2024-04-17 14:09:25 +08:00
ibuler
5b41eddacc perf: 修改翻译 2024-04-17 13:49:43 +08:00
ibuler
a432af1a6d perf: 修改翻译 2024-04-15 16:34:02 +08:00
吴小白
f987515b89 perf: 优化发布机日志输出 2024-04-15 12:04:26 +08:00
ibuler
2afabd65f9 Merge branch 'v4' of github.com:jumpserver/jumpserver into v4 2024-04-09 18:43:29 +08:00
ibuler
85cb80cbfe perf: remove gpt category 2024-04-09 18:43:06 +08:00
吴小白
8500f186f6 perf: 优化镜像构建 2024-04-08 18:52:22 +08:00
ibuler
97f60a61e0 perf: 修改翻译 2024-04-08 14:32:14 +08:00
Bryan
08ac8b0857 Update README.md 2024-04-02 15:27:28 +08:00
ibuler
255817f5c6 perf: 修改翻译 2024-04-02 14:27:18 +08:00
ibuler
19b196eb1f Merge branch 'v4' of github.com:jumpserver/jumpserver into v4 2024-04-01 19:28:26 +08:00
ibuler
40db6485dd perf: change i18n 2024-04-01 19:28:08 +08:00
Bryan
b23e99885e Update README.md 2024-04-01 18:47:29 +08:00
Bryan
22fbbb92da Update README.md 2024-04-01 18:41:34 +08:00
Bryan
99c94166bb Update README.md 2024-04-01 18:38:59 +08:00
Bryan
169254a1c7 Update README.md 2024-04-01 18:22:11 +08:00
Bryan
bda6037b2a Update README.md 2024-04-01 18:21:35 +08:00
Bryan
1cf0b15528 Update README.md 2024-04-01 18:08:47 +08:00
Bryan
ff3865d1a7 Update README.md 2024-04-01 18:01:56 +08:00
Bryan
10435788bc Update README.md 2024-04-01 17:37:11 +08:00
Bai
02750e56d9 perf: Update README.md 2024-04-01 17:09:08 +08:00
ibuler
a1d53cba44 Merge branch 'v4' of github.com:jumpserver/jumpserver into v4 2024-03-29 19:01:01 +08:00
Bai
b921ca8c9d perf: Update README.md 2024-03-29 18:46:11 +08:00
ibuler
29b38632e2 Merge branch 'v4' of github.com:jumpserver/jumpserver into v4 2024-03-29 15:30:31 +08:00
ibuler
56193f833f perf: change some translation 2024-03-29 15:29:04 +08:00
Bryan
2c8b977001 Update README.md 2024-03-28 19:05:42 +08:00
Bryan
4827fcf243 Update README.md 2024-03-28 19:02:39 +08:00
Bryan
9140ed6969 Update README.md 2024-03-28 18:01:16 +08:00
Bryan
24e7597c67 Update README.md 2024-03-28 17:59:37 +08:00
Bryan
833dd654b2 Update README.md 2024-03-28 17:57:02 +08:00
Bryan
ae74154071 Update README.md 2024-03-28 17:52:37 +08:00
Bryan
fb1631c1c7 Update README.md 2024-03-28 17:49:53 +08:00
Bryan
1c6832b9b2 Update README.md 2024-03-28 17:11:55 +08:00
Bryan
77d06037bb Update README.md 2024-03-28 17:05:12 +08:00
Bai
136e62b97d perf: Update README.md 2024-03-28 17:02:52 +08:00
Bryan
24c36087dd Update README.md 2024-03-28 16:33:24 +08:00
Bryan
73f9d721fe Update README.md 2024-03-28 16:10:32 +08:00
Bryan
792f8b2d1f Update README.md 2024-03-28 16:08:05 +08:00
Bryan
6871d194a8 Update README.md 2024-03-28 16:07:22 +08:00
Bryan
12c26e4551 Update README.md 2024-03-28 15:56:55 +08:00
ibuler
3426f650fa Merge branch 'v4' of github.com:jumpserver/jumpserver into v4 2024-03-28 14:40:31 +08:00
ibuler
f224dc241e perf: 修改翻译 2024-03-28 14:31:27 +08:00
Bryan
f6effb3c40 Update README.md 2024-03-28 14:21:02 +08:00
Bryan
6bbdcc060d perf: Update README.md 2024-03-28 11:36:24 +08:00
Bryan
14411d8c86 Update README.md 2024-03-28 11:05:04 +08:00
Bryan
cca2bfee4e perf: Update README.md 2024-03-28 10:42:01 +08:00
Bryan
c6cc68601b perf: Update README.md 2024-03-28 10:40:48 +08:00
Bai
06f33e4bdc perf: Update README.md 2024-03-27 18:15:29 +08:00
ibuler
616b38158a Merge branch 'v4' of github.com:jumpserver/jumpserver into v4 2024-03-27 17:51:12 +08:00
ibuler
c22f88ae42 perf: 修改翻译 2024-03-27 17:50:44 +08:00
Bai
3bf401f029 perf: Update README.md 2024-03-26 19:34:06 +08:00
Bai
0b8b74b7a4 perf: Update README.md 2024-03-26 18:48:10 +08:00
Bai
e1bd0ee3d7 perf: Update README.md 2024-03-26 18:30:30 +08:00
Bai
4b0d95ed0c perf: Update README.md 2024-03-26 17:40:22 +08:00
Bai
fedb146025 perf: Update README.md 2024-03-26 16:57:52 +08:00
Bai
695a5eb470 perf: Update README.md 2024-03-26 16:53:04 +08:00
ibuler
f6e4d909ff Merge branch 'v4' of github.com:jumpserver/jumpserver into v4 2024-03-22 10:17:36 +08:00
ibuler
6c0299b05a perf: 优化语言更改 2024-03-21 19:13:00 +08:00
Bai
fb02095568 perf: Remove settigns.LITE 2024-03-19 19:22:29 +08:00
Bai
d5675ce498 perf: update poetry.lock 2024-03-19 18:10:02 +08:00
ibuler
ccbb860de1 Merge branch 'v4' of github.com:jumpserver/jumpserver into v4 2024-03-19 17:54:00 +08:00
ibuler
5e104a3dd2 perf: 修改翻译 2024-03-19 17:53:29 +08:00
Bai
51890c94cc perf: 对ce、ee依赖库进行分组 2024-03-19 16:35:15 +08:00
Bai
06259a2d63 perf: 对ce、ee依赖库进行分组 2024-03-19 16:31:45 +08:00
ibuler
d04ac09e82 perf: 修改 groups api 2024-03-15 19:18:49 +08:00
ibuler
cae9f03892 perf: 修改 platform 翻译 2024-03-13 18:40:35 +08:00
ibuler
bffcd6107c perf: 修改翻译 2024-03-12 18:47:44 +08:00
ibuler
056e0c816b perf: 修改翻译 2024-03-12 17:04:26 +08:00
ibuler
ea67312877 perf: 修改翻译 2024-03-11 19:20:18 +08:00
ibuler
327cdc8604 perf: 修改翻译 2024-03-11 14:33:14 +08:00
ibuler
6f37cc4d01 merge: with remote 2024-03-07 18:36:03 +08:00
ibuler
003dd49ed6 perf: 修改翻译 2024-03-07 18:33:13 +08:00
Bai
46d57f02e7 perf: i18n settings-systemtask done. 2024-03-07 17:29:03 +08:00
Bai
30915a93e5 perf: i18n settings-tools done. 2024-03-07 16:15:09 +08:00
Bai
c64480dc33 perf: i18n settings-Interface not done. 2024-03-06 17:49:42 +08:00
ibuler
4a9b1aff96 Merge branch 'v4' of github.com:jumpserver/jumpserver into v4 2024-03-06 17:08:31 +08:00
ibuler
542e94ec9c perf: 修改翻译 2024-03-06 17:08:24 +08:00
fit2bot
9341558f61 perf: translate (#12764)
Co-authored-by: feng <1304903146@qq.com>
2024-03-06 16:51:07 +08:00
ibuler
6ea13b2c0d perf: 修改翻译 2024-03-05 19:01:44 +08:00
ibuler
e57512f4fe perf: 添加配置支持 Lite 2024-03-04 19:18:26 +08:00
ibuler
348f67f4a4 Merge branch 'v4' of github.com:jumpserver/jumpserver into v4 2024-03-04 15:46:18 +08:00
ibuler
83bdf07600 perf: 修改翻译 2024-03-04 15:42:14 +08:00
fit2bot
dfe4eddbbc perf: translate (#12746)
Co-authored-by: feng <1304903146@qq.com>
Co-authored-by: feng626 <57284900+feng626@users.noreply.github.com>
2024-03-04 14:44:19 +08:00
ibuler
1caed59f76 merge: with remote 2024-03-04 14:03:05 +08:00
Bai
6db4e88a2c perf: 更新 poetry.lock 文件 2024-03-04 11:32:04 +08:00
fit2bot
133daeb664 perf: translate (#12739)
Co-authored-by: feng <1304903146@qq.com>
2024-03-01 15:42:21 +08:00
wangruidong
a4a8d1ecf0 perf: modify menu translate 2024-03-01 13:53:29 +08:00
ibuler
88a08a74f7 perf: 修改翻译 2024-02-29 14:57:38 +08:00
feng
c9e12a3027 perf: Modify some translations 2024-02-28 18:23:10 +08:00
fit2bot
82aa4a65ab perf: account translate (#12723)
Co-authored-by: feng <1304903146@qq.com>
Co-authored-by: feng626 <57284900+feng626@users.noreply.github.com>
2024-02-28 17:32:29 +08:00
ibuler
d46237f1bf merge: with remote 2024-02-28 16:32:46 +08:00
ibuler
1744f94910 perf: 修改翻译 2024-02-28 16:27:41 +08:00
Bai
e308812429 perf: i18n settings-Security done. 2024-02-27 19:20:48 +08:00
fit2bot
2328ef0b0c perf: account translate (#12719)
Co-authored-by: feng <1304903146@qq.com>
2024-02-27 19:17:40 +08:00
Bai
000c5770f2 perf: i18n settings-RemoteApp done. 2024-02-27 17:13:59 +08:00
Bai
9e1a3598ab perf: i18n settings-Components done. 2024-02-27 16:43:44 +08:00
Bai
7268f60343 perf: i18n settings-Storage done. 2024-02-27 14:59:22 +08:00
Bai
c8b274031f perf: i18n settings-Auth done. 2024-02-27 11:25:42 +08:00
Bai
10394dbb1c perf: i18n settings-Auth done. 2024-02-26 16:53:40 +08:00
Bai
859bb91fc7 perf: i18n settings-Features done. 2024-02-26 15:47:05 +08:00
fit2bot
0fd0d33704 perf: i18n settings-notifications done. (#12702)
Co-authored-by: Bai <baijiangjie@gmail.com>
Co-authored-by: Bryan <jiangjie.bai@fit2cloud.com>
2024-02-23 18:09:18 +08:00
fit2bot
ad0f489834 perf: translate (#12701)
Co-authored-by: feng <1304903146@qq.com>
2024-02-23 17:52:16 +08:00
fit2bot
b1fa870de7 perf: 工作台相关翻译 (#12700)
Co-authored-by: feng <1304903146@qq.com>
Co-authored-by: feng626 <57284900+feng626@users.noreply.github.com>
2024-02-23 17:22:47 +08:00
Bai
7c5e2ae8ea perf: i18n settings-org done. 2024-02-23 15:17:17 +08:00
Bai
c0e4065a45 perf: i18n settings-basic done. 2024-02-23 14:31:09 +08:00
fit2bot
35448eea9f perf: 翻译 (#12690)
Co-authored-by: feng <1304903146@qq.com>
2024-02-22 17:46:12 +08:00
wangruidong
430f45a3ec perf: permissions i18n modify 2024-02-22 17:36:45 +08:00
Bai
71b6fd5326 perf: 修改翻译 2024-02-22 17:29:46 +08:00
wangruidong
251db733b2 perf: i18n modify 2024-02-22 10:30:15 +08:00
ibuler
d799725b8a perf: 修改翻译 2024-02-20 19:01:32 +08:00
ibuler
9d80aed468 perf: 修改一些翻译 2024-02-06 15:51:39 +08:00
老广
96f92f0908 Merge pull request #12643 from jumpserver/pr@v4@perf_i18n
perf: 优化翻译
2024-02-05 14:18:48 +08:00
ibuler
314e4301f3 perf: 修改翻译 2024-02-05 14:13:07 +08:00
ibuler
b284bb60f5 merge: with dev 2024-02-05 09:49:43 +08:00
ibuler
f99396ec50 perf: 修改翻译 2024-02-04 19:31:51 +08:00
ibuler
886cf6ed1f perf: 暂存 2024-02-04 16:46:33 +08:00
ibuler
74dd6e97a2 perf: 优化翻译 2024-02-04 10:23:54 +08:00
fit2bot
46fde2f1aa perf: 整合翻译 (#12630)
* stash

* stash

* perf: 整合翻译

* perf: 整理了一遍

---------

Co-authored-by: ibuler <ibuler@qq.com>
2024-02-01 16:02:31 +08:00
fit2bot
e2a3c360ea perf: 修改一次性翻译长度 (#12557)
Co-authored-by: feng <1304903146@qq.com>
2024-01-17 11:38:58 +08:00
fit2bot
9968617758 perf: 修改优化结构 (#12554)
* perf: 修改优化结构

* perf: 修改结构

---------

Co-authored-by: ibuler <ibuler@qq.com>
2024-01-17 11:08:39 +08:00
feng
1cec27ed70 perf: 添加进度条 2024-01-17 10:36:45 +08:00
feng
f0dfff0625 feat: gpt translate 2024-01-16 16:19:37 +08:00
fit2bot
fdaec3c959 perf: Modify i18n for settings module. (#12543)
Co-authored-by: Bai <baijiangjie@gmail.com>
2024-01-15 04:41:50 -07:00
ibuler
fcb4c6a972 perf: Add sort json script 2024-01-15 17:12:13 +08:00
ibuler
513974bbed perf: remove some category 2024-01-15 16:38:16 +08:00
ibuler
00d6effd69 pref: stash 2024-01-11 18:33:52 +08:00
ibuler
c06c68d5da perf: 统一翻译 2024-01-11 14:40:44 +08:00
901 changed files with 42237 additions and 34334 deletions

View File

@@ -8,3 +8,4 @@ celerybeat.pid
.vagrant/
apps/xpack/.git
.history/
.idea

60
.github/workflows/build-base-image.yml vendored Normal file
View File

@@ -0,0 +1,60 @@
name: Build and Push Base Image
on:
push:
branches:
- 'pr*'
paths:
- 'poetry.lock'
- 'pyproject.toml'
- 'Dockerfile-base'
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract date
id: vars
run: echo "IMAGE_TAG=$(date +'%Y%m%d_%H%M%S')" >> $GITHUB_ENV
- name: Extract repository name
id: repo
run: echo "REPO=$(basename ${{ github.repository }})" >> $GITHUB_ENV
- name: Build and push multi-arch image
uses: docker/build-push-action@v6
with:
platforms: linux/amd64,linux/arm64
push: true
file: Dockerfile-base
tags: jumpserver/core-base:${{ env.IMAGE_TAG }}
- name: Update Dockerfile
run: |
sed -i 's|-base:.* AS stage-build|-base:${{ env.IMAGE_TAG }} AS stage-build|' Dockerfile
- name: Commit changes
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
git add Dockerfile
git commit -m "perf: Update Dockerfile with new base image tag"
git push
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,55 +0,0 @@
name: "Run Build Test"
on:
push:
paths:
- 'Dockerfile'
- 'Dockerfile-*'
- 'pyproject.toml'
- 'poetry.lock'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- name: Check Dockerfile
run: |
test -f Dockerfile-ce || cp -f Dockerfile Dockerfile-ce
- name: Build CE Image
uses: docker/build-push-action@v5
with:
context: .
push: false
file: Dockerfile-ce
tags: jumpserver/core-ce:test
platforms: linux/amd64
build-args: |
APT_MIRROR=http://deb.debian.org
PIP_MIRROR=https://pypi.org/simple
PIP_JMS_MIRROR=https://pypi.org/simple
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Prepare EE Image
run: |
sed -i 's@^FROM registry.fit2cloud.com@# FROM registry.fit2cloud.com@g' Dockerfile-ee
sed -i 's@^COPY --from=build-xpack@# COPY --from=build-xpack@g' Dockerfile-ee
- name: Build EE Image
uses: docker/build-push-action@v5
with:
context: .
push: false
file: Dockerfile-ee
tags: jumpserver/core-ee:test
platforms: linux/amd64
build-args: |
APT_MIRROR=http://deb.debian.org
PIP_MIRROR=https://pypi.org/simple
PIP_JMS_MIRROR=https://pypi.org/simple
cache-from: type=gha
cache-to: type=gha,mode=max

View File

@@ -0,0 +1,63 @@
name: "Run Build Test"
on:
push:
paths:
- 'Dockerfile'
- 'Dockerfile*'
- 'Dockerfile-*'
- 'pyproject.toml'
- 'poetry.lock'
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
component: [core]
version: [v4]
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Prepare Build
run: |
sed -i 's@^FROM registry.fit2cloud.com/jumpserver@FROM ghcr.io/jumpserver@g' Dockerfile-ee
- name: Build CE Image
uses: docker/build-push-action@v5
with:
context: .
push: true
file: Dockerfile
tags: ghcr.io/jumpserver/${{ matrix.component }}:${{ matrix.version }}-ce
platforms: linux/amd64
build-args: |
VERSION=${{ matrix.version }}
APT_MIRROR=http://deb.debian.org
PIP_MIRROR=https://pypi.org/simple
outputs: type=image,oci-mediatypes=true,compression=zstd,compression-level=3,force-compression=true
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Build EE Image
uses: docker/build-push-action@v5
with:
context: .
push: false
file: Dockerfile-ee
tags: ghcr.io/jumpserver/${{ matrix.component }}:${{ matrix.version }}
platforms: linux/amd64
build-args: |
VERSION=${{ matrix.version }}
APT_MIRROR=http://deb.debian.org
PIP_MIRROR=https://pypi.org/simple
outputs: type=image,oci-mediatypes=true,compression=zstd,compression-level=3,force-compression=true
cache-from: type=gha
cache-to: type=gha,mode=max

2
.gitignore vendored
View File

@@ -44,3 +44,5 @@ data/*
test.py
.history/
.test/
*.mo

View File

@@ -1,3 +1,4 @@
[settings]
line_length=120
known_first_party=common,users,assets,perms,authentication,jumpserver,notification,ops,orgs,rbac,settings,terminal,tickets

View File

@@ -1,5 +1,10 @@
# Contributing
As a contributor, you should agree that:
- The producer can adjust the open-source agreement to be more strict or relaxed as deemed necessary.
- Your contributed code may be used for commercial purposes, including but not limited to its cloud business operations.
## Create pull request
PR are always welcome, even if they only contain small fixes like typos or a few lines of code. If there will be a significant effort, please document it as an issue and get a discussion going before starting to work on it.

66
Dockerfile Normal file
View File

@@ -0,0 +1,66 @@
FROM jumpserver/core-base:20240808_054051 AS stage-build
ARG VERSION
WORKDIR /opt/jumpserver
ADD . .
RUN echo > /opt/jumpserver/config.yml \
&& \
if [ -n "${VERSION}" ]; then \
sed -i "s@VERSION = .*@VERSION = '${VERSION}'@g" apps/jumpserver/const.py; \
fi
RUN set -ex \
&& export SECRET_KEY=$(head -c100 < /dev/urandom | base64 | tr -dc A-Za-z0-9 | head -c 48) \
&& . /opt/py3/bin/activate \
&& cd apps \
&& python manage.py compilemessages
FROM python:3.11-slim-bullseye
ENV LANG=en_US.UTF-8 \
PATH=/opt/py3/bin:$PATH
ARG DEPENDENCIES=" \
libldap2-dev \
libx11-dev"
ARG TOOLS=" \
ca-certificates \
default-libmysqlclient-dev \
openssh-client \
sshpass \
bubblewrap"
ARG APT_MIRROR=http://deb.debian.org
RUN set -ex \
&& rm -f /etc/apt/apt.conf.d/docker-clean \
&& sed -i "s@http://.*.debian.org@${APT_MIRROR}@g" /etc/apt/sources.list \
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& apt-get update > /dev/null \
&& apt-get -y install --no-install-recommends ${DEPENDENCIES} \
&& apt-get -y install --no-install-recommends ${TOOLS} \
&& apt-get clean \
&& mkdir -p /root/.ssh/ \
&& echo "Host *\n\tStrictHostKeyChecking no\n\tUserKnownHostsFile /dev/null\n\tCiphers +aes128-cbc\n\tKexAlgorithms +diffie-hellman-group1-sha1\n\tHostKeyAlgorithms +ssh-rsa" > /root/.ssh/config \
&& echo "no" | dpkg-reconfigure dash \
&& sed -i "s@# export @export @g" ~/.bashrc \
&& sed -i "s@# alias @alias @g" ~/.bashrc
COPY --from=stage-build /opt /opt
COPY --from=stage-build /usr/local/bin /usr/local/bin
COPY --from=stage-build /opt/jumpserver/apps/libs/ansible/ansible.cfg /etc/ansible/
WORKDIR /opt/jumpserver
VOLUME /opt/jumpserver/data
ENTRYPOINT ["./entrypoint.sh"]
EXPOSE 8080
STOPSIGNAL SIGQUIT
CMD ["start", "all"]

54
Dockerfile-base Normal file
View File

@@ -0,0 +1,54 @@
FROM python:3.11-slim-bullseye
ARG TARGETARCH
# Install APT dependencies
ARG DEPENDENCIES=" \
ca-certificates \
wget \
g++ \
make \
pkg-config \
default-libmysqlclient-dev \
freetds-dev \
gettext \
libkrb5-dev \
libldap2-dev \
libsasl2-dev"
ARG APT_MIRROR=http://deb.debian.org
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=core \
--mount=type=cache,target=/var/lib/apt,sharing=locked,id=core \
set -ex \
&& rm -f /etc/apt/apt.conf.d/docker-clean \
&& echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache \
&& sed -i "s@http://.*.debian.org@${APT_MIRROR}@g" /etc/apt/sources.list \
&& apt-get update > /dev/null \
&& apt-get -y install --no-install-recommends ${DEPENDENCIES} \
&& echo "no" | dpkg-reconfigure dash
# Install bin tools
ARG CHECK_VERSION=v1.0.3
RUN set -ex \
&& wget https://github.com/jumpserver-dev/healthcheck/releases/download/${CHECK_VERSION}/check-${CHECK_VERSION}-linux-${TARGETARCH}.tar.gz \
&& tar -xf check-${CHECK_VERSION}-linux-${TARGETARCH}.tar.gz \
&& mv check /usr/local/bin/ \
&& chown root:root /usr/local/bin/check \
&& chmod 755 /usr/local/bin/check \
&& rm -f check-${CHECK_VERSION}-linux-${TARGETARCH}.tar.gz
# Install Python dependencies
WORKDIR /opt/jumpserver
ARG PIP_MIRROR=https://pypi.org/simple
RUN --mount=type=cache,target=/root/.cache,sharing=locked,id=core \
--mount=type=bind,source=poetry.lock,target=poetry.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
set -ex \
&& python3 -m venv /opt/py3 \
&& pip install poetry -i ${PIP_MIRROR} \
&& poetry config virtualenvs.create false \
&& . /opt/py3/bin/activate \
&& poetry install --only main

View File

@@ -1,137 +0,0 @@
FROM python:3.11-slim-bullseye as stage-1
ARG TARGETARCH
ARG VERSION
ENV VERSION=$VERSION
WORKDIR /opt/jumpserver
ADD . .
RUN echo > /opt/jumpserver/config.yml \
&& cd utils && bash -ixeu build.sh
FROM python:3.11-slim-bullseye as stage-2
ARG TARGETARCH
ARG BUILD_DEPENDENCIES=" \
g++ \
make \
pkg-config"
ARG DEPENDENCIES=" \
freetds-dev \
libffi-dev \
libjpeg-dev \
libkrb5-dev \
libldap2-dev \
libpq-dev \
libsasl2-dev \
libssl-dev \
libxml2-dev \
libxmlsec1-dev \
libxmlsec1-openssl \
freerdp2-dev \
libaio-dev"
ARG TOOLS=" \
ca-certificates \
curl \
default-libmysqlclient-dev \
default-mysql-client \
git \
git-lfs \
unzip \
xz-utils \
wget"
ARG APT_MIRROR=http://mirrors.ustc.edu.cn
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=core-apt \
--mount=type=cache,target=/var/lib/apt,sharing=locked,id=core-apt \
sed -i "s@http://.*.debian.org@${APT_MIRROR}@g" /etc/apt/sources.list \
&& rm -f /etc/apt/apt.conf.d/docker-clean \
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& apt-get update \
&& apt-get -y install --no-install-recommends ${BUILD_DEPENDENCIES} \
&& apt-get -y install --no-install-recommends ${DEPENDENCIES} \
&& apt-get -y install --no-install-recommends ${TOOLS} \
&& echo "no" | dpkg-reconfigure dash
WORKDIR /opt/jumpserver
ARG PIP_MIRROR=https://pypi.tuna.tsinghua.edu.cn/simple
RUN --mount=type=cache,target=/root/.cache \
--mount=type=bind,source=poetry.lock,target=/opt/jumpserver/poetry.lock \
--mount=type=bind,source=pyproject.toml,target=/opt/jumpserver/pyproject.toml \
set -ex \
&& python3 -m venv /opt/py3 \
&& pip install poetry -i ${PIP_MIRROR} \
&& poetry config virtualenvs.create false \
&& . /opt/py3/bin/activate \
&& poetry install
FROM python:3.11-slim-bullseye
ARG TARGETARCH
ENV LANG=zh_CN.UTF-8 \
PATH=/opt/py3/bin:$PATH
ARG DEPENDENCIES=" \
libjpeg-dev \
libpq-dev \
libx11-dev \
freerdp2-dev \
libxmlsec1-openssl"
ARG TOOLS=" \
ca-certificates \
curl \
default-libmysqlclient-dev \
default-mysql-client \
iputils-ping \
locales \
netcat-openbsd \
nmap \
openssh-client \
patch \
sshpass \
telnet \
vim \
bubblewrap \
wget"
ARG APT_MIRROR=http://mirrors.ustc.edu.cn
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=core-apt \
--mount=type=cache,target=/var/lib/apt,sharing=locked,id=core-apt \
sed -i "s@http://.*.debian.org@${APT_MIRROR}@g" /etc/apt/sources.list \
&& rm -f /etc/apt/apt.conf.d/docker-clean \
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& apt-get update \
&& apt-get -y install --no-install-recommends ${DEPENDENCIES} \
&& apt-get -y install --no-install-recommends ${TOOLS} \
&& mkdir -p /root/.ssh/ \
&& echo "Host *\n\tStrictHostKeyChecking no\n\tUserKnownHostsFile /dev/null\n\tCiphers +aes128-cbc\n\tKexAlgorithms +diffie-hellman-group1-sha1\n\tHostKeyAlgorithms +ssh-rsa" > /root/.ssh/config \
&& echo "no" | dpkg-reconfigure dash \
&& echo "zh_CN.UTF-8" | dpkg-reconfigure locales \
&& sed -i "s@# export @export @g" ~/.bashrc \
&& sed -i "s@# alias @alias @g" ~/.bashrc
ARG RECEPTOR_VERSION=v1.4.5
RUN set -ex \
&& wget -O /opt/receptor.tar.gz https://github.com/ansible/receptor/releases/download/${RECEPTOR_VERSION}/receptor_${RECEPTOR_VERSION/v/}_linux_${TARGETARCH}.tar.gz \
&& tar -xf /opt/receptor.tar.gz -C /usr/local/bin/ \
&& chown root:root /usr/local/bin/receptor \
&& chmod 755 /usr/local/bin/receptor \
&& rm -f /opt/receptor.tar.gz
COPY --from=stage-2 /opt/py3 /opt/py3
COPY --from=stage-1 /opt/jumpserver/release/jumpserver /opt/jumpserver
COPY --from=stage-1 /opt/jumpserver/release/jumpserver/apps/libs/ansible/ansible.cfg /etc/ansible/
WORKDIR /opt/jumpserver
ARG VERSION
ENV VERSION=$VERSION
VOLUME /opt/jumpserver/data
EXPOSE 8080
ENTRYPOINT ["./entrypoint.sh"]

View File

@@ -1,5 +1,35 @@
ARG VERSION
FROM registry.fit2cloud.com/jumpserver/xpack:${VERSION} as build-xpack
FROM registry.fit2cloud.com/jumpserver/core-ce:${VERSION}
ARG VERSION=dev
FROM registry.fit2cloud.com/jumpserver/xpack:${VERSION} AS build-xpack
FROM jumpserver/core:${VERSION}-ce
COPY --from=build-xpack /opt/xpack /opt/jumpserver/apps/xpack
ARG TOOLS=" \
g++ \
curl \
iputils-ping \
netcat-openbsd \
nmap \
telnet \
vim \
wget"
ARG APT_MIRROR=http://deb.debian.org
RUN set -ex \
&& rm -f /etc/apt/apt.conf.d/docker-clean \
&& echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache \
&& sed -i "s@http://.*.debian.org@${APT_MIRROR}@g" /etc/apt/sources.list \
&& apt-get update \
&& apt-get -y install --no-install-recommends ${TOOLS} \
&& echo "no" | dpkg-reconfigure dash
WORKDIR /opt/jumpserver
ARG PIP_MIRROR=https://pypi.org/simple
COPY poetry.lock pyproject.toml ./
RUN set -ex \
&& . /opt/py3/bin/activate \
&& pip install poetry -i ${PIP_MIRROR} \
&& poetry install --only xpack
COPY --from=build-xpack /opt/xpack /opt/jumpserver/apps/xpack

182
README.md
View File

@@ -1,125 +1,113 @@
<p align="center">
<a href="https://jumpserver.org"><img src="https://download.jumpserver.org/images/jumpserver-logo.svg" alt="JumpServer" width="300" /></a>
</p>
<h3 align="center">广受欢迎的开源堡垒机</h3>
<div align="center">
<a name="readme-top"></a>
<a href="https://jumpserver.org/index-en.html"><img src="https://download.jumpserver.org/images/jumpserver-logo.svg" alt="JumpServer" width="300" /></a>
## An open-source PAM tool (Bastion Host)
<p align="center">
<a href="https://www.gnu.org/licenses/gpl-3.0.html"><img src="https://img.shields.io/github/license/jumpserver/jumpserver" alt="License: GPLv3"></a>
<a href="https://hub.docker.com/u/jumpserver"><img src="https://img.shields.io/docker/pulls/jumpserver/jms_all.svg" alt="Docker pulls"></a>
<a href="https://github.com/jumpserver/jumpserver/releases/latest"><img src="https://img.shields.io/github/v/release/jumpserver/jumpserver" alt="Latest release"></a>
<a href="https://github.com/jumpserver/jumpserver"><img src="https://img.shields.io/github/stars/jumpserver/jumpserver?color=%231890FF&style=flat-square" alt="Stars"></a>
</p>
[![][license-shield]][license-link]
[![][discord-shield]][discord-link]
[![][docker-shield]][docker-link]
[![][github-release-shield]][github-release-link]
[![][github-stars-shield]][github-stars-link]
**English** · [简体中文](./README.zh-CN.md)
</div>
<br/>
<p align="center">
9 年时间,倾情投入,用心做好一款开源堡垒机。
</p>
## What is JumpServer?
------------------------------
JumpServer 是广受欢迎的开源堡垒机,是符合 4A 规范的专业运维安全审计系统。
JumpServer is an open-source Privileged Access Management (PAM) tool that provides DevOps and IT teams with on-demand and secure access to SSH, RDP, Kubernetes, Database and RemoteApp endpoints through a web browser.
JumpServer 堡垒机帮助企业以更安全的方式管控和登录各种类型的资产,包括:
![JumpServer Overview](https://github.com/jumpserver/jumpserver/assets/32935519/35a371cb-8590-40ed-88ec-f351f8cf9045)
- **SSH**: Linux / Unix / 网络设备 等;
- **Windows**: Web 方式连接 / 原生 RDP 连接;
- **数据库**: MySQL / MariaDB / PostgreSQL / Oracle / SQLServer / ClickHouse 等;
- **NoSQL**: Redis / MongoDB 等;
- **GPT**: ChatGPT 等;
- **云服务**: Kubernetes / VMware vSphere 等;
- **Web 站点**: 各类系统的 Web 管理后台;
- **应用**: 通过 Remote App 连接各类应用。
## Quickstart
## 产品特色
Prepare a clean Linux Server ( 64 bit, >= 4c8g )
- **开源**: 零门槛,线上快速获取和安装;
- **无插件**: 仅需浏览器,极致的 Web Terminal 使用体验;
- **分布式**: 支持分布式部署和横向扩展,轻松支持大规模并发访问;
- **多云支持**: 一套系统,同时管理不同云上面的资产;
- **多租户**: 一套系统,多个子公司或部门同时使用;
- **云端存储**: 审计录像云端存储,永不丢失;
```sh
curl -sSL https://github.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh | bash
```
## UI 展示
Access JumpServer in your browser at `http://your-jumpserver-ip/`
- Username: `admin`
- Password: `ChangeMe`
![UI展示](https://docs.jumpserver.org/zh/v3/img/dashboard.png)
## Screenshots
## 在线体验
<table style="border-collapse: collapse; border: 1px solid black;">
<tr>
<td style="padding: 5px;background-color:#fff;"><img src= "https://github.com/jumpserver/jumpserver/assets/32935519/99fabe5b-0475-4a53-9116-4c370a1426c4" alt="JumpServer Console" /></td>
<td style="padding: 5px;background-color:#fff;"><img src= "https://github.com/jumpserver/jumpserver/assets/32935519/a424d731-1c70-4108-a7d8-5bbf387dda9a" alt="JumpServer Audits" /></td>
</tr>
- 环境地址:<https://demo.jumpserver.org/>
<tr>
<td style="padding: 5px;background-color:#fff;"><img src= "https://github.com/jumpserver/jumpserver/assets/32935519/393d2c27-a2d0-4dea-882d-00ed509e00c9" alt="JumpServer Workbench" /></td>
<td style="padding: 5px;background-color:#fff;"><img src= "https://github.com/jumpserver/jumpserver/assets/32935519/3a2611cd-8902-49b8-b82b-2a6dac851f3e" alt="JumpServer Settings" /></td>
</tr>
| :warning: 注意 |
|:-----------------------------|
| 该环境仅作体验目的使用,我们会定时清理、重置数据! |
| 请勿修改体验环境用户的密码! |
| 请勿在环境中添加业务生产环境地址、用户名密码等敏感信息! |
<tr>
<td style="padding: 5px;background-color:#fff;"><img src= "https://github.com/jumpserver/jumpserver/assets/32935519/1e236093-31f7-4563-8eb1-e36d865f1568" alt="JumpServer SSH" /></td>
<td style="padding: 5px;background-color:#fff;"><img src= "https://github.com/jumpserver/jumpserver/assets/32935519/69373a82-f7ab-41e8-b763-bbad2ba52167" alt="JumpServer RDP" /></td>
</tr>
<tr>
<td style="padding: 5px;background-color:#fff;"><img src= "https://github.com/jumpserver/jumpserver/assets/32935519/5bed98c6-cbe8-4073-9597-d53c69dc3957" alt="JumpServer K8s" /></td>
<td style="padding: 5px;background-color:#fff;"><img src= "https://github.com/jumpserver/jumpserver/assets/32935519/b80ad654-548f-42bc-ba3d-c1cfdf1b46d6" alt="JumpServer DB" /></td>
</tr>
</table>
## 快速开始
## Components
- [快速入门](https://docs.jumpserver.org/zh/v3/quick_start/)
- [产品文档](https://docs.jumpserver.org)
- [在线学习](https://edu.fit2cloud.com/page/2635362)
- [知识库](https://kb.fit2cloud.com/categories/jumpserver)
JumpServer consists of multiple key components, which collectively form the functional framework of JumpServer, providing users with comprehensive capabilities for operations management and security control.
## 案例研究
| Project | Status | Description |
|--------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------|
| [Lina](https://github.com/jumpserver/lina) | <a href="https://github.com/jumpserver/lina/releases"><img alt="Lina release" src="https://img.shields.io/github/release/jumpserver/lina.svg" /></a> | JumpServer Web UI |
| [Luna](https://github.com/jumpserver/luna) | <a href="https://github.com/jumpserver/luna/releases"><img alt="Luna release" src="https://img.shields.io/github/release/jumpserver/luna.svg" /></a> | JumpServer Web Terminal |
| [KoKo](https://github.com/jumpserver/koko) | <a href="https://github.com/jumpserver/koko/releases"><img alt="Koko release" src="https://img.shields.io/github/release/jumpserver/koko.svg" /></a> | JumpServer Character Protocol Connector |
| [Lion](https://github.com/jumpserver/lion) | <a href="https://github.com/jumpserver/lion/releases"><img alt="Lion release" src="https://img.shields.io/github/release/jumpserver/lion.svg" /></a> | JumpServer Graphical Protocol Connector |
| [Chen](https://github.com/jumpserver/chen) | <a href="https://github.com/jumpserver/chen/releases"><img alt="Chen release" src="https://img.shields.io/github/release/jumpserver/chen.svg" /> | JumpServer Web DB |
| [Razor](https://github.com/jumpserver/razor) | <img alt="Chen" src="https://img.shields.io/badge/release-private-red" /> | JumpServer EE RDP Proxy Connector |
| [Tinker](https://github.com/jumpserver/tinker) | <img alt="Tinker" src="https://img.shields.io/badge/release-private-red" /> | JumpServer EE Remote Application Connector (Windows) |
| [Panda](https://github.com/jumpserver/Panda) | <img alt="Panda" src="https://img.shields.io/badge/release-private-red" /> | JumpServer EE Remote Application Connector (Linux) |
| [Magnus](https://github.com/jumpserver/magnus) | <img alt="Magnus" src="https://img.shields.io/badge/release-private-red" /> | JumpServer EE Database Proxy Connector |
- [腾讯音乐娱乐集团基于JumpServer的安全运维审计解决方案](https://blog.fit2cloud.com/?p=a04cdf0d-6704-4d18-9b40-9180baecd0e2)
- [腾讯海外游戏基于JumpServer构建游戏安全运营能力](https://blog.fit2cloud.com/?p=3704)
- [万华化学通过JumpServer管理全球化分布式IT资产并且实现与云管平台的联动](https://blog.fit2cloud.com/?p=3504)
- [雪花啤酒JumpServer堡垒机使用体会](https://blog.fit2cloud.com/?p=3412)
- [顺丰科技JumpServer 堡垒机护航顺丰科技超大规模资产安全运维](https://blog.fit2cloud.com/?p=1147)
- [沐瞳游戏通过JumpServer管控多项目分布式资产](https://blog.fit2cloud.com/?p=3213)
- [携程JumpServer 堡垒机部署与运营实战](https://blog.fit2cloud.com/?p=851)
- [大智慧JumpServer 堡垒机让“大智慧”的混合 IT 运维更智慧](https://blog.fit2cloud.com/?p=882)
- [小红书JumpServer 堡垒机大规模资产跨版本迁移之路](https://blog.fit2cloud.com/?p=516)
- [中手游JumpServer堡垒机助力中手游提升多云环境下安全运维能力](https://blog.fit2cloud.com/?p=732)
- [中通快递JumpServer主机安全运维实践](https://blog.fit2cloud.com/?p=708)
- [东方明珠JumpServer高效管控异构化、分布式云端资产](https://blog.fit2cloud.com/?p=687)
- [江苏农信JumpServer堡垒机助力行业云安全运维](https://blog.fit2cloud.com/?p=666)
## Contributing
## 社区交流
Welcome to submit PR to contribute. Please refer to [CONTRIBUTING.md][contributing-link] for guidelines.
如果您在使用过程中有任何疑问或对建议,欢迎提交 [GitHub Issue](https://github.com/jumpserver/jumpserver/issues/new/choose)。
## Security
您也可以到我们的 [社区论坛](https://bbs.fit2cloud.com/c/js/5) 当中进行交流沟通。
JumpServer is a mission critical product. Please refer to the Basic Security Recommendations for installation and deployment. If you encounter any security-related issues, please contact us directly:
### 参与贡献
- Email: support@fit2cloud.com
欢迎提交 PR 参与贡献。 参考 [CONTRIBUTING.md](https://github.com/jumpserver/jumpserver/blob/dev/CONTRIBUTING.md)
## 组件项目
| 项目 | 状态 | 描述 |
|--------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------|
| [Lina](https://github.com/jumpserver/lina) | <a href="https://github.com/jumpserver/lina/releases"><img alt="Lina release" src="https://img.shields.io/github/release/jumpserver/lina.svg" /></a> | JumpServer Web UI 项目 |
| [Luna](https://github.com/jumpserver/luna) | <a href="https://github.com/jumpserver/luna/releases"><img alt="Luna release" src="https://img.shields.io/github/release/jumpserver/luna.svg" /></a> | JumpServer Web Terminal 项目 |
| [KoKo](https://github.com/jumpserver/koko) | <a href="https://github.com/jumpserver/koko/releases"><img alt="Koko release" src="https://img.shields.io/github/release/jumpserver/koko.svg" /></a> | JumpServer 字符协议 Connector 项目 |
| [Lion](https://github.com/jumpserver/lion-release) | <a href="https://github.com/jumpserver/lion-release/releases"><img alt="Lion release" src="https://img.shields.io/github/release/jumpserver/lion-release.svg" /></a> | JumpServer 图形协议 Connector 项目,依赖 [Apache Guacamole](https://guacamole.apache.org/) |
| [Razor](https://github.com/jumpserver/razor) | <img alt="Chen" src="https://img.shields.io/badge/release-私有发布-red" /> | JumpServer RDP 代理 Connector 项目 |
| [Tinker](https://github.com/jumpserver/tinker) | <img alt="Tinker" src="https://img.shields.io/badge/release-私有发布-red" /> | JumpServer 远程应用 Connector 项目 (Windows) |
| [Panda](https://github.com/jumpserver/Panda) | <img alt="Panda" src="https://img.shields.io/badge/release-私有发布-red" /> | JumpServer 远程应用 Connector 项目 (Linux) |
| [Magnus](https://github.com/jumpserver/magnus-release) | <a href="https://github.com/jumpserver/magnus-release/releases"><img alt="Magnus release" src="https://img.shields.io/github/release/jumpserver/magnus-release.svg" /> | JumpServer 数据库代理 Connector 项目 |
| [Chen](https://github.com/jumpserver/chen-release) | <a href="https://github.com/jumpserver/chen-release/releases"><img alt="Chen release" src="https://img.shields.io/github/release/jumpserver/chen-release.svg" /> | JumpServer Web DB 项目,替代原来的 OmniDB |
| [Kael](https://github.com/jumpserver/kael) | <a href="https://github.com/jumpserver/kael/releases"><img alt="Kael release" src="https://img.shields.io/github/release/jumpserver/kael.svg" /> | JumpServer 连接 GPT 资产的组件项目 |
| [Wisp](https://github.com/jumpserver/wisp) | <a href="https://github.com/jumpserver/wisp/releases"><img alt="Magnus release" src="https://img.shields.io/github/release/jumpserver/wisp.svg" /> | JumpServer 各系统终端组件和 Core API 通信的组件项目 |
| [Clients](https://github.com/jumpserver/clients) | <a href="https://github.com/jumpserver/clients/releases"><img alt="Clients release" src="https://img.shields.io/github/release/jumpserver/clients.svg" /> | JumpServer 客户端 项目 |
| [Installer](https://github.com/jumpserver/installer) | <a href="https://github.com/jumpserver/installer/releases"><img alt="Installer release" src="https://img.shields.io/github/release/jumpserver/installer.svg" /> | JumpServer 安装包 项目 |
## 安全说明
JumpServer是一款安全产品请参考 [基本安全建议](https://docs.jumpserver.org/zh/master/install/install_security/)
进行安装部署。如果您发现安全相关问题,请直接联系我们:
- 邮箱support@fit2cloud.com
- 电话400-052-0755
## License & Copyright
## License
Copyright (c) 2014-2024 飞致云 FIT2CLOUD, All rights reserved.
Licensed under The GNU General Public License version 3 (GPLv3) (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
Licensed under The GNU General Public License version 3 (GPLv3) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
https://www.gnu.org/licenses/gpl-3.0.html
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "
AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
language governing permissions and limitations under the License.
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an " AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
<!-- JumpServer official link -->
[docs-link]: https://jumpserver.com/docs
[discord-link]: https://discord.com/invite/W6vYXmAQG2
[contributing-link]: https://github.com/jumpserver/jumpserver/blob/dev/CONTRIBUTING.md
<!-- JumpServer Other link-->
[license-link]: https://www.gnu.org/licenses/gpl-3.0.html
[docker-link]: https://hub.docker.com/u/jumpserver
[github-release-link]: https://github.com/jumpserver/jumpserver/releases/latest
[github-stars-link]: https://github.com/jumpserver/jumpserver
[github-issues-link]: https://github.com/jumpserver/jumpserver/issues
<!-- Shield link-->
[github-release-shield]: https://img.shields.io/github/v/release/jumpserver/jumpserver
[github-stars-shield]: https://img.shields.io/github/stars/jumpserver/jumpserver?color=%231890FF&style=flat-square
[docker-shield]: https://img.shields.io/docker/pulls/jumpserver/jms_all.svg
[license-shield]: https://img.shields.io/github/license/jumpserver/jumpserver
[discord-shield]: https://img.shields.io/discord/1194233267294052363?style=flat&logo=discord&logoColor=%23f5f5f5&labelColor=%235462eb&color=%235462eb
<!-- Image link -->

121
README.zh-CN.md Normal file
View File

@@ -0,0 +1,121 @@
<p align="center">
<a href="https://jumpserver.org"><img src="https://download.jumpserver.org/images/jumpserver-logo.svg" alt="JumpServer" width="300" /></a>
</p>
<h3 align="center">广受欢迎的开源堡垒机</h3>
<p align="center">
<a href="https://www.gnu.org/licenses/gpl-3.0.html"><img src="https://img.shields.io/github/license/jumpserver/jumpserver" alt="License: GPLv3"></a>
<a href="https://hub.docker.com/u/jumpserver"><img src="https://img.shields.io/docker/pulls/jumpserver/jms_all.svg" alt="Docker pulls"></a>
<a href="https://github.com/jumpserver/jumpserver/releases/latest"><img src="https://img.shields.io/github/v/release/jumpserver/jumpserver" alt="Latest release"></a>
<a href="https://github.com/jumpserver/jumpserver"><img src="https://img.shields.io/github/stars/jumpserver/jumpserver?color=%231890FF&style=flat-square" alt="Stars"></a>
</p>
<p align="center">
10 年时间,倾情投入,用心做好一款开源堡垒机。
</p>
------------------------------
## JumpServer 是什么?
JumpServer 是广受欢迎的开源堡垒机,是符合 4A 规范的专业运维安全审计系统。JumpServer 堡垒机帮助企业以更安全的方式管控和登录各种类型的资产,包括:
- **SSH**: Linux / Unix / 网络设备 等;
- **Windows**: Web 方式连接 / 原生 RDP 连接;
- **数据库**: MySQL / MariaDB / PostgreSQL / Oracle / SQLServer / ClickHouse 等;
- **NoSQL**: Redis / MongoDB 等;
- **GPT**: ChatGPT 等;
- **云服务**: Kubernetes / VMware vSphere 等;
- **Web 站点**: 各类系统的 Web 管理后台;
- **应用**: 通过 Remote App 连接各类应用。
## 产品特色
- **开源**: 零门槛,线上快速获取和安装;
- **无插件**: 仅需浏览器,极致的 Web Terminal 使用体验;
- **分布式**: 支持分布式部署和横向扩展,轻松支持大规模并发访问;
- **多云支持**: 一套系统,同时管理不同云上面的资产;
- **多租户**: 一套系统,多个子公司或部门同时使用;
- **云端存储**: 审计录像云端存储,永不丢失;
## 快速开始
- [快速入门](https://docs.jumpserver.org/zh/v3/quick_start/)
- [产品文档](https://docs.jumpserver.org)
- [在线学习](https://edu.fit2cloud.com/page/2635362)
- [知识库](https://kb.fit2cloud.com/categories/jumpserver)
## UI 展示
![UI展示](https://docs.jumpserver.org/zh/v3/img/dashboard.png)
## 在线体验
- 环境地址:<https://demo.jumpserver.org/>
| :warning: 注意 |
|:-----------------------------|
| 该环境仅作体验目的使用,我们会定时清理、重置数据! |
| 请勿修改体验环境用户的密码! |
| 请勿在环境中添加业务生产环境地址、用户名密码等敏感信息! |
## 案例研究
- [腾讯音乐娱乐集团基于JumpServer的安全运维审计解决方案](https://blog.fit2cloud.com/?p=a04cdf0d-6704-4d18-9b40-9180baecd0e2)
- [腾讯海外游戏基于JumpServer构建游戏安全运营能力](https://blog.fit2cloud.com/?p=3704)
- [万华化学通过JumpServer管理全球化分布式IT资产并且实现与云管平台的联动](https://blog.fit2cloud.com/?p=3504)
- [雪花啤酒JumpServer堡垒机使用体会](https://blog.fit2cloud.com/?p=3412)
- [顺丰科技JumpServer 堡垒机护航顺丰科技超大规模资产安全运维](https://blog.fit2cloud.com/?p=1147)
- [沐瞳游戏通过JumpServer管控多项目分布式资产](https://blog.fit2cloud.com/?p=3213)
- [携程JumpServer 堡垒机部署与运营实战](https://blog.fit2cloud.com/?p=851)
- [大智慧JumpServer 堡垒机让“大智慧”的混合 IT 运维更智慧](https://blog.fit2cloud.com/?p=882)
- [小红书JumpServer 堡垒机大规模资产跨版本迁移之路](https://blog.fit2cloud.com/?p=516)
- [中手游JumpServer堡垒机助力中手游提升多云环境下安全运维能力](https://blog.fit2cloud.com/?p=732)
- [中通快递JumpServer主机安全运维实践](https://blog.fit2cloud.com/?p=708)
- [东方明珠JumpServer高效管控异构化、分布式云端资产](https://blog.fit2cloud.com/?p=687)
- [江苏农信JumpServer堡垒机助力行业云安全运维](https://blog.fit2cloud.com/?p=666)
## 社区交流
如果您在使用过程中有任何疑问或对建议,欢迎提交 [GitHub Issue](https://github.com/jumpserver/jumpserver/issues/new/choose)。
您也可以到我们的 [社区论坛](https://bbs.fit2cloud.com/c/js/5) 当中进行交流沟通。
## 参与贡献
欢迎提交 PR 参与贡献。 参考 [CONTRIBUTING.md](https://github.com/jumpserver/jumpserver/blob/dev/CONTRIBUTING.md)
## 组件项目
| Project | Status | Description |
|--------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------|
| [Lina](https://github.com/jumpserver/lina) | <a href="https://github.com/jumpserver/lina/releases"><img alt="Lina release" src="https://img.shields.io/github/release/jumpserver/lina.svg" /></a> | JumpServer Web UI |
| [Luna](https://github.com/jumpserver/luna) | <a href="https://github.com/jumpserver/luna/releases"><img alt="Luna release" src="https://img.shields.io/github/release/jumpserver/luna.svg" /></a> | JumpServer Web Terminal |
| [KoKo](https://github.com/jumpserver/koko) | <a href="https://github.com/jumpserver/koko/releases"><img alt="Koko release" src="https://img.shields.io/github/release/jumpserver/koko.svg" /></a> | JumpServer Character Protocol Connector |
| [Lion](https://github.com/jumpserver/lion) | <a href="https://github.com/jumpserver/lion/releases"><img alt="Lion release" src="https://img.shields.io/github/release/jumpserver/lion.svg" /></a> | JumpServer Graphical Protocol Connector |
| [Chen](https://github.com/jumpserver/chen) | <a href="https://github.com/jumpserver/chen/releases"><img alt="Chen release" src="https://img.shields.io/github/release/jumpserver/chen.svg" /> | JumpServer Web DB |
| [Razor](https://github.com/jumpserver/razor) | <img alt="Chen" src="https://img.shields.io/badge/release-private-red" /> | JumpServer EE RDP Proxy Connector |
| [Tinker](https://github.com/jumpserver/tinker) | <img alt="Tinker" src="https://img.shields.io/badge/release-private-red" /> | JumpServer EE Remote Application Connector (Windows) |
| [Panda](https://github.com/jumpserver/Panda) | <img alt="Panda" src="https://img.shields.io/badge/release-private-red" /> | JumpServer EE Remote Application Connector (Linux) |
| [Magnus](https://github.com/jumpserver/magnus) | <img alt="Magnus" src="https://img.shields.io/badge/release-private-red" /> | JumpServer EE Database Proxy Connector |
## 安全说明
JumpServer是一款安全产品请参考 [基本安全建议](https://docs.jumpserver.org/zh/master/install/install_security/)
进行安装部署。如果您发现安全相关问题,请直接联系我们:
- 邮箱support@fit2cloud.com
- 电话400-052-0755
## License & Copyright
Copyright (c) 2014-2024 飞致云 FIT2CLOUD, All rights reserved.
Licensed under The GNU General Public License version 3 (GPLv3) (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
https://www.gnu.org/licenses/gpl-3.0.html
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "
AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
language governing permissions and limitations under the License.

View File

@@ -1,94 +0,0 @@
<p align="center"><a href="https://jumpserver.org"><img src="https://download.jumpserver.org/images/jumpserver-logo.svg" alt="JumpServer" width="300" /></a></p>
<h3 align="center">Open Source Bastion Host</h3>
<p align="center">
<a href="https://www.gnu.org/licenses/gpl-3.0.html"><img src="https://img.shields.io/github/license/jumpserver/jumpserver" alt="License: GPLv3"></a>
<a href="https://shields.io/github/downloads/jumpserver/jumpserver/total"><img src="https://shields.io/github/downloads/jumpserver/jumpserver/total" alt=" release"></a>
<a href="https://hub.docker.com/u/jumpserver"><img src="https://img.shields.io/docker/pulls/jumpserver/jms_all.svg" alt="Codacy"></a>
<a href="https://github.com/jumpserver/jumpserver"><img src="https://img.shields.io/github/stars/jumpserver/jumpserver?color=%231890FF&style=flat-square" alt="Stars"></a>
</p>
JumpServer is the world's first open-source Bastion Host and is licensed under the GPLv3. It is a 4A-compliant professional operation and maintenance security audit system.
JumpServer uses Python / Django for development, follows Web 2.0 specifications, and is equipped with an industry-leading Web Terminal solution that provides a beautiful user interface and great user experience
JumpServer adopts a distributed architecture to support multi-branch deployment across multiple cross-regional areas. The central node provides APIs, and login nodes are deployed in each branch. It can be scaled horizontally without concurrency restrictions.
Change the world by taking every little step
----
### Advantages
- Open Source: huge transparency and free to access with quick installation process.
- Distributed: support large-scale concurrent access with ease.
- No Plugin required: all you need is a browser, the ultimate Web Terminal experience.
- Multi-Cloud supported: a unified system to manage assets on different clouds at the same time
- Cloud storage: audit records are stored in the cloud. Data lost no more!
- Multi-Tenant system: multiple subsidiary companies or departments access the same system simultaneously.
- Many applications supported: link to databases, windows remote applications, and Kubernetes cluster, etc.
### JumpServer Component Projects
- [Lina](https://github.com/jumpserver/lina) JumpServer Web UI
- [Luna](https://github.com/jumpserver/luna) JumpServer Web Terminal
- [KoKo](https://github.com/jumpserver/koko) JumpServer Character protocaol Connector, replace original Python Version [Coco](https://github.com/jumpserver/coco)
- [Lion](https://github.com/jumpserver/lion-release) JumpServer Graphics protocol Connectorrely on [Apache Guacamole](https://guacamole.apache.org/)
### Contribution
If you have any good ideas or helping us to fix bugs, please submit a Pull Request and accept our thanks :)
Thanks to the following contributors for making JumpServer better everyday!
<a href="https://github.com/jumpserver/jumpserver/graphs/contributors">
<img src="https://contrib.rocks/image?repo=jumpserver/jumpserver" />
</a>
<a href="https://github.com/jumpserver/koko/graphs/contributors">
<img src="https://contrib.rocks/image?repo=jumpserver/koko" />
</a>
<a href="https://github.com/jumpserver/lina/graphs/contributors">
<img src="https://contrib.rocks/image?repo=jumpserver/lina" />
</a>
<a href="https://github.com/jumpserver/luna/graphs/contributors">
<img src="https://contrib.rocks/image?repo=jumpserver/luna" />
</a>
### Thanks to
- [Apache Guacamole](https://guacamole.apache.org/) Web page connection RDP, SSH, VNC protocol equipment. JumpServer graphical connection dependent.
- [OmniDB](https://omnidb.org/) Web page connection to databases. JumpServer Web database dependent.
### JumpServer Enterprise Version
- [Apply for it](https://jinshuju.net/f/kyOYpi)
### Case Study
- [JumpServer 堡垒机护航顺丰科技超大规模资产安全运维](https://blog.fit2cloud.com/?p=1147)
- [JumpServer 堡垒机让“大智慧”的混合 IT 运维更智慧](https://blog.fit2cloud.com/?p=882)
- [携程 JumpServer 堡垒机部署与运营实战](https://blog.fit2cloud.com/?p=851)
- [小红书的JumpServer堡垒机大规模资产跨版本迁移之路](https://blog.fit2cloud.com/?p=516)
- [JumpServer堡垒机助力中手游提升多云环境下安全运维能力](https://blog.fit2cloud.com/?p=732)
- [中通快递JumpServer主机安全运维实践](https://blog.fit2cloud.com/?p=708)
- [东方明珠JumpServer高效管控异构化、分布式云端资产](https://blog.fit2cloud.com/?p=687)
- [江苏农信JumpServer堡垒机助力行业云安全运维](https://blog.fit2cloud.com/?p=666)。
### For safety instructions
JumpServer is a security product. Please refer to [Basic Security Recommendations](https://docs.jumpserver.org/zh/master/install/install_security/) for deployment and installation.
If you find a security problem, please contact us directly
- ibuler@fit2cloud.com
- support@fit2cloud.com
- 400-052-0755
### License & Copyright
Copyright (c) 2014-2024 FIT2CLOUD Tech, Inc., All rights reserved.
Licensed under The GNU General Public License version 3 (GPLv3) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
https://www.gnu.org/licenses/gpl-3.0.htmll
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

View File

@@ -4,6 +4,7 @@ from django.apps import AppConfig
class AccountsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'accounts'
verbose_name = 'App Accounts'
def ready(self):
from . import signal_handlers # noqa

View File

@@ -3,6 +3,7 @@ import time
from collections import defaultdict, OrderedDict
from django.conf import settings
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
from xlsxwriter import Workbook
@@ -17,7 +18,7 @@ from terminal.models.component.storage import ReplayStorage
from users.models import User
PATH = os.path.join(os.path.dirname(settings.BASE_DIR), 'tmp')
split_help_text = _('The account key will be split into two parts and sent')
class RecipientsNotFound(Exception):
pass
@@ -115,8 +116,8 @@ class AssetAccountHandler(BaseAccountHandler):
data = AccountSecretSerializer(_accounts, many=True).data
cls.handler_secret(data, section)
data_map.update(cls.add_rows(data, header_fields, sheet_name))
print('\n\033[33m- 共备份 {} 条账号\033[0m'.format(accounts.count()))
number_of_backup_accounts = _('Number of backup accounts')
print('\n\033[33m- {}: {}\033[0m'.format(number_of_backup_accounts, accounts.count()))
return data_map
@@ -127,9 +128,10 @@ class AccountBackupHandler:
self.is_frozen = False # 任务状态冻结标志
def create_excel(self, section='complete'):
hint = _('Generating asset or application related backup information files')
print(
'\n'
'\033[32m>>> 正在生成资产或应用相关备份信息文件\033[0m'
f'\033[32m>>> {hint}\033[0m'
''
)
# Print task start date
@@ -151,7 +153,9 @@ class AccountBackupHandler:
wb.close()
files.append(filename)
timedelta = round((time.time() - time_start), 2)
print('创建备份文件完成: 用时 {}s'.format(timedelta))
time_cost = _('Time cost')
file_created = _('Backup file creation completed')
print('{}: {} {}s'.format(file_created, time_cost, timedelta))
return files
def send_backup_mail(self, files, recipients):
@@ -160,7 +164,7 @@ class AccountBackupHandler:
recipients = User.objects.filter(id__in=list(recipients))
print(
'\n'
'\033[32m>>> 开始发送备份邮件\033[0m'
f'\033[32m>>> {_("Start sending backup emails")}\033[0m'
''
)
plan_name = self.plan_name
@@ -172,7 +176,8 @@ class AccountBackupHandler:
encrypt_and_compress_zip_file(attachment, user.secret_key, files)
attachment_list = [attachment, ]
AccountBackupExecutionTaskMsg(plan_name, user).publish(attachment_list)
print('邮件已发送至{}({})'.format(user, user.email))
email_sent_to = _('Email sent to')
print('{} {}({})'.format(email_sent_to, user, user.email))
for file in files:
os.remove(file)
@@ -182,20 +187,22 @@ class AccountBackupHandler:
recipients = ReplayStorage.objects.filter(id__in=list(recipients))
print(
'\n'
'\033[32m>>> 开始发送备份文件到sftp服务器\033[0m'
'\033[32m>>> 📃 ---> sftp \033[0m'
''
)
plan_name = self.plan_name
encrypt_file = _('Encrypting files using encryption password')
for rec in recipients:
attachment = os.path.join(PATH, f'{plan_name}-{local_now_filename()}-{time.time()}.zip')
if password:
print('\033[32m>>> 使用加密密码对文件进行加密中\033[0m')
print(f'\033[32m>>> {encrypt_file}\033[0m')
encrypt_and_compress_zip_file(attachment, password, files)
else:
zip_files(attachment, files)
attachment_list = attachment
AccountBackupByObjStorageExecutionTaskMsg(plan_name, rec).publish(attachment_list)
print('备份文件将发送至{}({})'.format(rec.name, rec.id))
file_sent_to = _('The backup file will be sent to')
print('{}: {}({})'.format(file_sent_to, rec.name, rec.id))
for file in files:
os.remove(file)
@@ -203,14 +210,15 @@ class AccountBackupHandler:
self.execution.reason = reason[:1024]
self.execution.is_success = is_success
self.execution.save()
print('\n已完成对任务状态的更新\n')
finish = _('Finish')
print(f'\n{finish}\n')
@staticmethod
def step_finished(is_success):
if is_success:
print('任务执行成功')
print(_('Success'))
else:
print('任务执行失败')
print(_('Failed'))
def _run(self):
is_success = False
@@ -223,8 +231,6 @@ class AccountBackupHandler:
self.backup_by_obj_storage()
except Exception as e:
self.is_frozen = True
print('任务执行被异常中断')
print('下面打印发生异常的 Traceback 信息 : ')
print(e)
error = str(e)
else:
@@ -239,15 +245,16 @@ class AccountBackupHandler:
zip_encrypt_password = AccountBackupAutomation.objects.get(id=object_id).zip_encrypt_password
obj_recipients_part_one = self.execution.snapshot.get('obj_recipients_part_one', [])
obj_recipients_part_two = self.execution.snapshot.get('obj_recipients_part_two', [])
no_assigned_sftp_server = _('The backup task has no assigned sftp server')
if not obj_recipients_part_one and not obj_recipients_part_two:
print(
'\n'
'\033[31m>>> 该备份任务未分配sftp服务器\033[0m'
f'\033[31m>>> {no_assigned_sftp_server}\033[0m'
''
)
raise RecipientsNotFound('Not Found Recipients')
if obj_recipients_part_one and obj_recipients_part_two:
print('\033[32m>>> 账号的密钥将被拆分成前后两部分发送\033[0m')
print(f'\033[32m>>> {split_help_text}\033[0m')
files = self.create_excel(section='front')
self.send_backup_obj_storage(files, obj_recipients_part_one, zip_encrypt_password)
@@ -259,17 +266,19 @@ class AccountBackupHandler:
self.send_backup_obj_storage(files, recipients, zip_encrypt_password)
def backup_by_email(self):
warn_text = _('The backup task has no assigned recipient')
recipients_part_one = self.execution.snapshot.get('recipients_part_one', [])
recipients_part_two = self.execution.snapshot.get('recipients_part_two', [])
if not recipients_part_one and not recipients_part_two:
print(
'\n'
'\033[31m>>> 该备份任务未分配收件人\033[0m'
f'\033[31m>>> {warn_text}\033[0m'
''
)
raise RecipientsNotFound('Not Found Recipients')
if recipients_part_one and recipients_part_two:
print('\033[32m>>> 账号的密钥将被拆分成前后两部分发送\033[0m')
print(f'\033[32m>>> {split_help_text}\033[0m')
files = self.create_excel(section='front')
self.send_backup_mail(files, recipients_part_one)
@@ -281,15 +290,18 @@ class AccountBackupHandler:
self.send_backup_mail(files, recipients)
def run(self):
print('任务开始: {}'.format(local_now_display()))
plan_start = _('Plan start')
plan_end = _('Plan end')
time_cost = _('Time cost')
error = _('An exception occurred during task execution')
print('{}: {}'.format(plan_start, local_now_display()))
time_start = time.time()
try:
self._run()
except Exception as e:
print('任务运行出现异常')
print('下面显示异常 Traceback 信息: ')
print(error)
print(e)
finally:
print('\n任务结束: {}'.format(local_now_display()))
print('\n{}: {}'.format(plan_end, local_now_display()))
timedelta = round((time.time() - time_start), 2)
print('用时: {}s'.format(timedelta))
print('{}: {}s'.format(time_cost, timedelta))

View File

@@ -3,6 +3,7 @@
import time
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from common.utils.timezone import local_now_display
from .handlers import AccountBackupHandler
@@ -19,7 +20,8 @@ class AccountBackupManager:
def do_run(self):
execution = self.execution
print('\n\033[33m# 账号备份计划正在执行\033[0m')
account_backup_execution_being_executed = _('The account backup plan is being executed')
print(f'\n\033[33m# {account_backup_execution_being_executed}\033[0m')
handler = AccountBackupHandler(execution)
handler.run()
@@ -32,9 +34,11 @@ class AccountBackupManager:
self.date_end = timezone.now()
print('\n\n' + '-' * 80)
print('计划执行结束 {}\n'.format(local_now_display()))
plan_execution_end = _('Plan execution end')
print('{} {}\n'.format(plan_execution_end, local_now_display()))
self.timedelta = self.time_end - self.time_start
print('用时: {}s'.format(self.timedelta))
time_cost = _('Time cost')
print('{}: {}s'.format(time_cost, self.timedelta))
self.execution.timedelta = self.timedelta
self.execution.save()

View File

@@ -35,6 +35,17 @@
- user_info.failed
- params.groups
- name: "Set {{ account.username }} sudo setting"
ansible.builtin.lineinfile:
dest: /etc/sudoers
state: present
regexp: "^{{ account.username }} ALL="
line: "{{ account.username + ' ALL=(ALL) NOPASSWD: ' + params.sudo }}"
validate: visudo -cf %s
when:
- user_info.failed or params.modify_sudo
- params.sudo
- name: "Change {{ account.username }} password"
ansible.builtin.user:
name: "{{ account.username }}"
@@ -59,17 +70,6 @@
exclusive: "{{ ssh_params.exclusive }}"
when: account.secret_type == "ssh_key"
- name: "Set {{ account.username }} sudo setting"
ansible.builtin.lineinfile:
dest: /etc/sudoers
state: present
regexp: "^{{ account.username }} ALL="
line: "{{ account.username + ' ALL=(ALL) NOPASSWD: ' + params.sudo }}"
validate: visudo -cf %s
when:
- user_info.failed
- params.sudo
- name: Refresh connection
ansible.builtin.meta: reset_connection

View File

@@ -5,6 +5,12 @@ type:
- AIX
method: change_secret
params:
- name: modify_sudo
type: bool
label: "{{ 'Modify sudo label' | trans }}"
default: False
help_text: "{{ 'Modify params sudo help text' | trans }}"
- name: sudo
type: str
label: 'Sudo'
@@ -34,6 +40,11 @@ i18n:
ja: 'Ansible user モジュールを使用してアカウントのパスワード変更 (DES)'
en: 'Using Ansible module user to change account secret (DES)'
Modify params sudo help text:
zh: '如果用户存在可以修改sudo权限'
ja: 'ユーザーが存在する場合、sudo権限を変更できます'
en: 'If the user exists, sudo permissions can be modified'
Params sudo help text:
zh: '使用逗号分隔多个命令,如: /bin/whoami,/sbin/ifconfig'
ja: 'コンマで区切って複数のコマンドを入力してください。例: /bin/whoami,/sbin/ifconfig'
@@ -49,6 +60,11 @@ i18n:
ja: 'グループを入力してください。複数のグループはコンマで区切ってください(既存のグループを入力してください)'
en: 'Please enter the group. Multiple groups are separated by commas (please enter the existing group)'
Modify sudo label:
zh: '修改 sudo 权限'
ja: 'sudo 権限を変更'
en: 'Modify sudo'
Params home label:
zh: '家目录'
ja: 'ホームディレクトリ'

View File

@@ -35,6 +35,17 @@
- user_info.failed
- params.groups
- name: "Set {{ account.username }} sudo setting"
ansible.builtin.lineinfile:
dest: /etc/sudoers
state: present
regexp: "^{{ account.username }} ALL="
line: "{{ account.username + ' ALL=(ALL) NOPASSWD: ' + params.sudo }}"
validate: visudo -cf %s
when:
- user_info.failed or params.modify_sudo
- params.sudo
- name: "Change {{ account.username }} password"
ansible.builtin.user:
name: "{{ account.username }}"
@@ -59,17 +70,6 @@
exclusive: "{{ ssh_params.exclusive }}"
when: account.secret_type == "ssh_key"
- name: "Set {{ account.username }} sudo setting"
ansible.builtin.lineinfile:
dest: /etc/sudoers
state: present
regexp: "^{{ account.username }} ALL="
line: "{{ account.username + ' ALL=(ALL) NOPASSWD: ' + params.sudo }}"
validate: visudo -cf %s
when:
- user_info.failed
- params.sudo
- name: Refresh connection
ansible.builtin.meta: reset_connection

View File

@@ -6,6 +6,12 @@ type:
- linux
method: change_secret
params:
- name: modify_sudo
type: bool
label: "{{ 'Modify sudo label' | trans }}"
default: False
help_text: "{{ 'Modify params sudo help text' | trans }}"
- name: sudo
type: str
label: 'Sudo'
@@ -36,6 +42,11 @@ i18n:
ja: 'Ansible user モジュールを使用して アカウントのパスワード変更 (SHA512)'
en: 'Using Ansible module user to change account secret (SHA512)'
Modify params sudo help text:
zh: '如果用户存在可以修改sudo权限'
ja: 'ユーザーが存在する場合、sudo権限を変更できます'
en: 'If the user exists, sudo permissions can be modified'
Params sudo help text:
zh: '使用逗号分隔多个命令,如: /bin/whoami,/sbin/ifconfig'
ja: 'コンマで区切って複数のコマンドを入力してください。例: /bin/whoami,/sbin/ifconfig'
@@ -51,6 +62,11 @@ i18n:
ja: 'グループを入力してください。複数のグループはコンマで区切ってください(既存のグループを入力してください)'
en: 'Please enter the group. Multiple groups are separated by commas (please enter the existing group)'
Modify sudo label:
zh: '修改 sudo 权限'
ja: 'sudo 権限を変更'
en: 'Modify sudo'
Params home label:
zh: '家目录'
ja: 'ホームディレクトリ'

View File

@@ -8,7 +8,7 @@ from django.utils.translation import gettext_lazy as _
from xlsxwriter import Workbook
from accounts.const import AutomationTypes, SecretType, SSHKeyStrategy, SecretStrategy, ChangeSecretRecordStatusChoice
from accounts.models import ChangeSecretRecord
from accounts.models import ChangeSecretRecord, BaseAccountQuerySet
from accounts.notifications import ChangeSecretExecutionTaskMsg, ChangeSecretFailedMsg
from accounts.serializers import ChangeSecretRecordBackUpSerializer
from assets.const import HostTypes
@@ -68,10 +68,10 @@ class ChangeSecretManager(AccountBasePlaybookManager):
else:
return self.secret_generator(secret_type).get_secret()
def get_accounts(self, privilege_account):
def get_accounts(self, privilege_account) -> BaseAccountQuerySet | None:
if not privilege_account:
print(f'not privilege account')
return []
print('Not privilege account')
return
asset = privilege_account.asset
accounts = asset.accounts.all()
@@ -97,10 +97,9 @@ class ChangeSecretManager(AccountBasePlaybookManager):
return host
accounts = self.get_accounts(account)
error_msg = _("No pending accounts found")
if not accounts:
print('没有发现待处理的账号: %s 用户ID: %s 类型: %s' % (
asset.name, self.account_ids, self.secret_type
))
print(f'{asset}: {error_msg}')
return []
records = []
@@ -109,6 +108,9 @@ class ChangeSecretManager(AccountBasePlaybookManager):
print(f'Windows {asset} does not support ssh key push')
return inventory_hosts
if asset.type == HostTypes.WINDOWS:
accounts = accounts.filter(secret_type=SecretType.PASSWORD)
host['ssh_params'] = {}
for account in accounts:
h = deepcopy(host)
@@ -227,6 +229,9 @@ class ChangeSecretManager(AccountBasePlaybookManager):
def run(self, *args, **kwargs):
if self.secret_type and not self.check_secret():
self.execution.status = 'success'
self.execution.date_finished = timezone.now()
self.execution.save()
return
super().run(*args, **kwargs)
recorders = list(self.name_recorder_mapper.values())

View File

@@ -31,7 +31,7 @@ class GatherAccountsFilter:
def posix_filter(info):
username_pattern = re.compile(r'^(\S+)')
ip_pattern = re.compile(r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})')
login_time_pattern = re.compile(r'\w{3} \d{2} \d{2}:\d{2}:\d{2} \d{4}')
login_time_pattern = re.compile(r'\w{3} \w{3}\s+\d{1,2} \d{2}:\d{2}:\d{2} \d{4}')
result = {}
for line in info:
usernames = username_pattern.findall(line)
@@ -46,7 +46,8 @@ class GatherAccountsFilter:
result[username].update({'address': ip_addr})
login_times = login_time_pattern.findall(line)
if login_times:
date = timezone.datetime.strptime(f'{login_times[0]} +0800', '%b %d %H:%M:%S %Y %z')
datetime_str = login_times[0].split(' ', 1)[1] + " +0800"
date = timezone.datetime.strptime(datetime_str, '%b %d %H:%M:%S %Y %z')
result[username].update({'date': date})
return result

View File

@@ -35,6 +35,17 @@
- user_info.failed
- params.groups
- name: "Set {{ account.username }} sudo setting"
ansible.builtin.lineinfile:
dest: /etc/sudoers
state: present
regexp: "^{{ account.username }} ALL="
line: "{{ account.username + ' ALL=(ALL) NOPASSWD: ' + params.sudo }}"
validate: visudo -cf %s
when:
- user_info.failed or params.modify_sudo
- params.sudo
- name: "Change {{ account.username }} password"
ansible.builtin.user:
name: "{{ account.username }}"
@@ -59,17 +70,6 @@
exclusive: "{{ ssh_params.exclusive }}"
when: account.secret_type == "ssh_key"
- name: "Set {{ account.username }} sudo setting"
ansible.builtin.lineinfile:
dest: /etc/sudoers
state: present
regexp: "^{{ account.username }} ALL="
line: "{{ account.username + ' ALL=(ALL) NOPASSWD: ' + params.sudo }}"
validate: visudo -cf %s
when:
- user_info.failed
- params.sudo
- name: Refresh connection
ansible.builtin.meta: reset_connection

View File

@@ -5,6 +5,12 @@ type:
- AIX
method: push_account
params:
- name: modify_sudo
type: bool
label: "{{ 'Modify sudo label' | trans }}"
default: False
help_text: "{{ 'Modify params sudo help text' | trans }}"
- name: sudo
type: str
label: 'Sudo'
@@ -34,6 +40,11 @@ i18n:
ja: 'Ansible user モジュールを使用して Aix アカウントをプッシュする (DES)'
en: 'Using Ansible module user to push account (DES)'
Modify params sudo help text:
zh: '如果用户存在可以修改sudo权限'
ja: 'ユーザーが存在する場合、sudo権限を変更できます'
en: 'If the user exists, sudo permissions can be modified'
Params sudo help text:
zh: '使用逗号分隔多个命令,如: /bin/whoami,/sbin/ifconfig'
ja: 'コンマで区切って複数のコマンドを入力してください。例: /bin/whoami,/sbin/ifconfig'
@@ -49,6 +60,11 @@ i18n:
ja: 'グループを入力してください。複数のグループはコンマで区切ってください(既存のグループを入力してください)'
en: 'Please enter the group. Multiple groups are separated by commas (please enter the existing group)'
Modify sudo label:
zh: '修改 sudo 权限'
ja: 'sudo 権限を変更'
en: 'Modify sudo'
Params home label:
zh: '家目录'
ja: 'ホームディレクトリ'

View File

@@ -35,6 +35,17 @@
- user_info.failed
- params.groups
- name: "Set {{ account.username }} sudo setting"
ansible.builtin.lineinfile:
dest: /etc/sudoers
state: present
regexp: "^{{ account.username }} ALL="
line: "{{ account.username + ' ALL=(ALL) NOPASSWD: ' + params.sudo }}"
validate: visudo -cf %s
when:
- user_info.failed or params.modify_sudo
- params.sudo
- name: "Change {{ account.username }} password"
ansible.builtin.user:
name: "{{ account.username }}"
@@ -59,17 +70,6 @@
exclusive: "{{ ssh_params.exclusive }}"
when: account.secret_type == "ssh_key"
- name: "Set {{ account.username }} sudo setting"
ansible.builtin.lineinfile:
dest: /etc/sudoers
state: present
regexp: "^{{ account.username }} ALL="
line: "{{ account.username + ' ALL=(ALL) NOPASSWD: ' + params.sudo }}"
validate: visudo -cf %s
when:
- user_info.failed
- params.sudo
- name: Refresh connection
ansible.builtin.meta: reset_connection

View File

@@ -6,6 +6,12 @@ type:
- linux
method: push_account
params:
- name: modify_sudo
type: bool
label: "{{ 'Modify sudo label' | trans }}"
default: False
help_text: "{{ 'Modify params sudo help text' | trans }}"
- name: sudo
type: str
label: 'Sudo'
@@ -36,6 +42,11 @@ i18n:
ja: 'Ansible user モジュールを使用してアカウントをプッシュする (sha512)'
en: 'Using Ansible module user to push account (sha512)'
Modify params sudo help text:
zh: '如果用户存在可以修改sudo权限'
ja: 'ユーザーが存在する場合、sudo権限を変更できます'
en: 'If the user exists, sudo permissions can be modified'
Params sudo help text:
zh: '使用逗号分隔多个命令,如: /bin/whoami,/sbin/ifconfig'
ja: 'コンマで区切って複数のコマンドを入力してください。例: /bin/whoami,/sbin/ifconfig'
@@ -51,6 +62,11 @@ i18n:
ja: 'グループを入力してください。複数のグループはコンマで区切ってください(既存のグループを入力してください)'
en: 'Please enter the group. Multiple groups are separated by commas (please enter the existing group)'
Modify sudo label:
zh: '修改 sudo 权限'
ja: 'sudo 権限を変更'
en: 'Modify sudo'
Params home label:
zh: '家目录'
ja: 'ホームディレクトリ'

View File

@@ -2,6 +2,7 @@
gather_facts: no
vars:
ansible_python_interpreter: /opt/py3/bin/python
check_ssl: "{{ jms_asset.spec_info.use_ssl and not jms_asset.spec_info.allow_invalid_cert }}"
tasks:
- name: "Remove account"

View File

@@ -12,11 +12,13 @@
path: "{{ user_home_dir.stdout }}"
register: home_dir
when: user_home_dir.stdout != ""
ignore_errors: yes
- name: "Rename user home directory if it exists"
ansible.builtin.command:
cmd: "mv {{ user_home_dir.stdout }} {{ user_home_dir.stdout }}.bak"
when: home_dir.stat | default(false) and user_home_dir.stdout != ""
ignore_errors: yes
- name: "Remove account"
ansible.builtin.user:

View File

@@ -1,10 +1,8 @@
# Generated by Django 3.2.14 on 2022-12-28 07:29
# Generated by Django 4.1.13 on 2024-05-09 03:16
import uuid
import django.db.models.deletion
import simple_history.models
from django.conf import settings
from django.db import migrations, models
import common.db.encoder
@@ -15,8 +13,6 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('assets', '0098_auto_20220430_2126'),
]
operations = [
@@ -32,60 +28,81 @@ class Migration(migrations.Migration):
('org_id',
models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('connectivity',
models.CharField(choices=[('-', 'Unknown'), ('ok', 'Ok'), ('err', 'Error')], default='-',
models.CharField(choices=[('-', 'Unknown'), ('ok', 'OK'), ('err', 'Error')], default='-',
max_length=16, verbose_name='Connectivity')),
('date_verified', models.DateTimeField(null=True, verbose_name='Date verified')),
('_secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Secret')),
('name', models.CharField(max_length=128, verbose_name='Name')),
('username', models.CharField(blank=True, db_index=True, max_length=128, verbose_name='Username')),
('secret_type', models.CharField(
choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'),
('token', 'Token'), ('api_key', 'API key')], default='password', max_length=16,
verbose_name='Secret type')),
('secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Secret')),
('privileged', models.BooleanField(default=False, verbose_name='Privileged')),
('is_active', models.BooleanField(default=True, verbose_name='Is active')),
('version', models.IntegerField(default=0, verbose_name='Version')),
('source', models.CharField(default='local', max_length=30, verbose_name='Source')),
('asset', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='accounts',
to='assets.asset', verbose_name='Asset')),
('su_from',
models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='su_to',
to='accounts.account', verbose_name='Su from')),
('source_id', models.CharField(blank=True, max_length=128, null=True, verbose_name='Source ID')),
],
options={
'verbose_name': 'Account',
'permissions': [('view_accountsecret', 'Can view asset account secret'),
('view_historyaccount', 'Can view asset history account'),
('view_historyaccountsecret', 'Can view asset history account secret')],
'unique_together': {('username', 'asset', 'secret_type'), ('name', 'asset')},
('view_historyaccountsecret', 'Can view asset history account secret'),
('verify_account', 'Can verify account'), ('push_account', 'Can push account'),
('remove_account', 'Can remove account')],
},
),
migrations.CreateModel(
name='HistoricalAccount',
name='AccountBackupAutomation',
fields=[
('id', models.UUIDField(db_index=True, default=uuid.uuid4)),
('secret_type', models.CharField(
choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'),
('token', 'Token'), ('api_key', 'API key')], default='password', max_length=16,
verbose_name='Secret type')),
('secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Secret')),
('version', models.IntegerField(default=0, verbose_name='Version')),
('history_id', models.AutoField(primary_key=True, serialize=False)),
('history_date', models.DateTimeField(db_index=True)),
('history_change_reason', models.CharField(max_length=100, null=True)),
('history_type',
models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
('history_user',
models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+',
to=settings.AUTH_USER_MODEL)),
('created_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by')),
('updated_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Updated by')),
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('comment', models.TextField(blank=True, default='', verbose_name='Comment')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('org_id',
models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('name', models.CharField(max_length=128, verbose_name='Name')),
('is_periodic', models.BooleanField(default=False, verbose_name='Periodic run')),
('interval', models.IntegerField(blank=True, default=24, null=True, verbose_name='Interval')),
('crontab', models.CharField(blank=True, max_length=128, null=True, verbose_name='Crontab')),
('types', models.JSONField(default=list)),
('backup_type',
models.CharField(choices=[('email', 'Email'), ('object_storage', 'SFTP')], default='email',
max_length=128, verbose_name='Backup type')),
('is_password_divided_by_email', models.BooleanField(default=True, verbose_name='Password divided')),
('is_password_divided_by_obj_storage',
models.BooleanField(default=True, verbose_name='Password divided')),
('zip_encrypt_password', common.db.fields.EncryptCharField(blank=True, max_length=4096, null=True,
verbose_name='Zip encrypt password')),
],
options={
'verbose_name': 'historical Account',
'verbose_name_plural': 'historical Accounts',
'ordering': ('-history_date', '-history_id'),
'get_latest_by': ('history_date', 'history_id'),
'verbose_name': 'Account backup plan',
'ordering': ['name'],
},
),
migrations.CreateModel(
name='AccountBackupExecution',
fields=[
('org_id',
models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('date_start', models.DateTimeField(auto_now_add=True, verbose_name='Date start')),
('timedelta', models.FloatField(default=0.0, null=True, verbose_name='Time')),
('snapshot',
models.JSONField(blank=True, default=dict, encoder=common.db.encoder.ModelJSONFieldEncoder, null=True,
verbose_name='Account backup snapshot')),
('trigger', models.CharField(choices=[('manual', 'Manual trigger'), ('timing', 'Timing trigger')],
default='manual', max_length=128, verbose_name='Trigger mode')),
('reason', models.CharField(blank=True, max_length=1024, null=True, verbose_name='Reason')),
('is_success', models.BooleanField(default=False, verbose_name='Is success')),
],
options={
'verbose_name': 'Account backup execution',
'ordering': ('-date_start',),
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
migrations.CreateModel(
name='AccountTemplate',
@@ -98,21 +115,108 @@ class Migration(migrations.Migration):
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('org_id',
models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('_secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Secret')),
('secret_strategy',
models.CharField(choices=[('specific', 'Specific secret'), ('random', 'Random generate')],
default='specific', max_length=16, verbose_name='Secret strategy')),
('password_rules', models.JSONField(default=dict, verbose_name='Password rules')),
('name', models.CharField(max_length=128, verbose_name='Name')),
('username', models.CharField(blank=True, db_index=True, max_length=128, verbose_name='Username')),
('secret_type', models.CharField(
choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'),
('token', 'Token'), ('api_key', 'API key')], default='password', max_length=16,
verbose_name='Secret type')),
('secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Secret')),
('privileged', models.BooleanField(default=False, verbose_name='Privileged')),
('is_active', models.BooleanField(default=True, verbose_name='Is active')),
('auto_push', models.BooleanField(default=False, verbose_name='Auto push')),
('push_params', models.JSONField(default=dict, verbose_name='Push params')),
],
options={
'verbose_name': 'Account template',
'permissions': [('view_accounttemplatesecret', 'Can view asset account template secret'),
('change_accounttemplatesecret', 'Can change asset account template secret')],
'unique_together': {('name', 'org_id')},
'permissions': [('view_accounttemplatesecret', 'Can view asset account template secret')],
},
),
migrations.CreateModel(
name='ChangeSecretRecord',
fields=[
('created_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by')),
('updated_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Updated by')),
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('comment', models.TextField(blank=True, default='', verbose_name='Comment')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('old_secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Old secret')),
('new_secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='New secret')),
('date_started', models.DateTimeField(blank=True, null=True, verbose_name='Date started')),
('date_finished', models.DateTimeField(blank=True, null=True, verbose_name='Date finished')),
('status', models.CharField(default='pending', max_length=16, verbose_name='Status')),
('error', models.TextField(blank=True, null=True, verbose_name='Error')),
],
options={
'verbose_name': 'Change secret record',
'ordering': ('-date_created',),
},
),
migrations.CreateModel(
name='GatheredAccount',
fields=[
('created_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by')),
('updated_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Updated by')),
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('comment', models.TextField(blank=True, default='', verbose_name='Comment')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('org_id',
models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('present', models.BooleanField(default=True, verbose_name='Present')),
('date_last_login', models.DateTimeField(null=True, verbose_name='Date login')),
('username', models.CharField(blank=True, db_index=True, max_length=32, verbose_name='Username')),
('address_last_login', models.CharField(default='', max_length=39, verbose_name='Address login')),
],
options={
'verbose_name': 'Gather asset accounts',
'ordering': ['asset'],
},
),
migrations.CreateModel(
name='HistoricalAccount',
fields=[
('id', models.UUIDField(db_index=True, default=uuid.uuid4)),
('_secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Secret')),
('secret_type', models.CharField(
choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'),
('token', 'Token'), ('api_key', 'API key')], default='password', max_length=16,
verbose_name='Secret type')),
('version', models.IntegerField(default=0, verbose_name='Version')),
('history_id', models.AutoField(primary_key=True, serialize=False)),
('history_date', models.DateTimeField(db_index=True)),
('history_change_reason', models.CharField(max_length=100, null=True)),
('history_type',
models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
],
options={
'verbose_name': 'historical Account',
'verbose_name_plural': 'historical Accounts',
'ordering': ('-history_date', '-history_id'),
'get_latest_by': ('history_date', 'history_id'),
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
migrations.CreateModel(
name='VirtualAccount',
fields=[
('created_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by')),
('updated_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Updated by')),
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('org_id',
models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('alias', models.CharField(
choices=[('@INPUT', 'Manual input'), ('@USER', 'Dynamic user'), ('@ANON', 'Anonymous account'),
('@SPEC', 'Specified account')], max_length=128, verbose_name='Alias')),
('secret_from_login', models.BooleanField(default=None, null=True, verbose_name='Secret from login')),
],
options={'verbose_name': 'Virtual account'},
),
]

View File

@@ -1,44 +1,103 @@
# Generated by Django 3.2.14 on 2022-12-28 10:39
# Generated by Django 4.1.13 on 2024-05-09 03:16
import common.db.encoder
import common.db.fields
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import uuid
from django.db import migrations, models
import common.db.fields
class Migration(migrations.Migration):
initial = True
dependencies = [
('assets', '0106_auto_20221228_1838'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('assets', '0001_initial'),
('accounts', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='AccountBackupAutomation',
name='AccountBaseAutomation',
fields=[
('created_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by')),
('updated_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Updated by')),
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('comment', models.TextField(blank=True, default='', verbose_name='Comment')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('org_id',
models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('name', models.CharField(max_length=128, verbose_name='Name')),
('is_periodic', models.BooleanField(default=False, verbose_name='Periodic perform')),
('interval', models.IntegerField(blank=True, default=24, null=True, verbose_name='Cycle perform')),
('crontab', models.CharField(blank=True, max_length=128, null=True, verbose_name='Regularly perform')),
('types', models.JSONField(default=list)),
('recipients', models.ManyToManyField(blank=True, related_name='recipient_escape_route_plans',
to=settings.AUTH_USER_MODEL, verbose_name='Recipient')),
],
options={
'verbose_name': 'Account backup plan',
'ordering': ['name'],
'unique_together': {('name', 'org_id')},
'verbose_name': 'Account automation task',
'proxy': True,
'indexes': [],
'constraints': [],
},
)
bases=('assets.baseautomation',),
),
migrations.CreateModel(
name='AutomationExecution',
fields=[
],
options={
'verbose_name': 'Automation execution',
'verbose_name_plural': 'Automation executions',
'permissions': [('view_changesecretexecution', 'Can view change secret execution'), ('add_changesecretexecution', 'Can add change secret execution'), ('view_gatheraccountsexecution', 'Can view gather accounts execution'), ('add_gatheraccountsexecution', 'Can add gather accounts execution'), ('view_pushaccountexecution', 'Can view push account execution'), ('add_pushaccountexecution', 'Can add push account execution')],
'proxy': True,
'indexes': [],
'constraints': [],
},
bases=('assets.automationexecution',),
),
migrations.CreateModel(
name='ChangeSecretAutomation',
fields=[
('baseautomation_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='assets.baseautomation')),
('secret_type', models.CharField(choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'), ('token', 'Token'), ('api_key', 'API key')], default='password', max_length=16, verbose_name='Secret type')),
('secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Secret')),
('secret_strategy', models.CharField(choices=[('specific', 'Specific secret'), ('random', 'Random generate')], default='specific', max_length=16, verbose_name='Secret strategy')),
('password_rules', models.JSONField(default=dict, verbose_name='Password rules')),
('ssh_key_change_strategy', models.CharField(choices=[('add', 'Append SSH KEY'), ('set', 'Empty and append SSH KEY'), ('set_jms', 'Replace (Replace only keys pushed by JumpServer) ')], default='add', max_length=16, verbose_name='SSH key change strategy')),
],
options={
'verbose_name': 'Change secret automation',
},
bases=('accounts.accountbaseautomation', models.Model),
),
migrations.CreateModel(
name='GatherAccountsAutomation',
fields=[
('baseautomation_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='assets.baseautomation')),
('is_sync_account', models.BooleanField(blank=True, default=False, verbose_name='Is sync account')),
],
options={
'verbose_name': 'Gather account automation',
},
bases=('accounts.accountbaseautomation',),
),
migrations.CreateModel(
name='PushAccountAutomation',
fields=[
('baseautomation_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='assets.baseautomation')),
('secret_type', models.CharField(choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'), ('token', 'Token'), ('api_key', 'API key')], default='password', max_length=16, verbose_name='Secret type')),
('secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Secret')),
('secret_strategy', models.CharField(choices=[('specific', 'Specific secret'), ('random', 'Random generate')], default='specific', max_length=16, verbose_name='Secret strategy')),
('password_rules', models.JSONField(default=dict, verbose_name='Password rules')),
('ssh_key_change_strategy', models.CharField(choices=[('add', 'Append SSH KEY'), ('set', 'Empty and append SSH KEY'), ('set_jms', 'Replace (Replace only keys pushed by JumpServer) ')], default='add', max_length=16, verbose_name='SSH key change strategy')),
('triggers', models.JSONField(default=list, max_length=16, verbose_name='Triggers')),
('username', models.CharField(max_length=128, verbose_name='Username')),
('action', models.CharField(max_length=16, verbose_name='Action')),
],
options={
'verbose_name': 'Push asset account',
},
bases=('accounts.accountbaseautomation', models.Model),
),
migrations.CreateModel(
name='VerifyAccountAutomation',
fields=[
('baseautomation_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='assets.baseautomation')),
],
options={
'verbose_name': 'Verify asset account',
},
bases=('accounts.accountbaseautomation',),
),
migrations.AlterUniqueTogether(
name='virtualaccount',
unique_together={('alias', 'org_id')},
),
]

View File

@@ -1,198 +1,116 @@
# Generated by Django 3.2.16 on 2022-12-30 08:08
# Generated by Django 4.1.13 on 2024-05-09 03:16
import uuid
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
import common.db.encoder
import common.db.fields
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('assets', '0107_automation'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('assets', '0001_initial'),
('terminal', '0001_initial'),
('accounts', '0002_auto_20220616_0021'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='AccountBaseAutomation',
fields=[
],
options={
'verbose_name': 'Account automation task',
'proxy': True,
'indexes': [],
'constraints': [],
},
bases=('assets.baseautomation',),
migrations.AddField(
model_name='historicalaccount',
name='history_user',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL),
),
migrations.CreateModel(
name='AutomationExecution',
fields=[
],
options={
'verbose_name': 'Automation execution',
'verbose_name_plural': 'Automation executions',
'permissions': [('view_changesecretexecution', 'Can view change secret execution'),
('add_changesecretexecution', 'Can add change secret execution'),
('view_gatheraccountsexecution', 'Can view gather accounts execution'),
('add_gatheraccountsexecution', 'Can add gather accounts execution')],
'proxy': True,
'indexes': [],
'constraints': [],
},
bases=('assets.automationexecution',),
migrations.AddField(
model_name='gatheredaccount',
name='asset',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='assets.asset', verbose_name='Asset'),
),
migrations.CreateModel(
name='PushAccountAutomation',
fields=[
('baseautomation_ptr',
models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True,
primary_key=True, serialize=False, to='assets.baseautomation')),
('secret_type', models.CharField(
choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'),
('token', 'Token'), ('api_key', 'API key')], default='password', max_length=16,
verbose_name='Secret type')),
('secret_strategy', models.CharField(choices=[('specific', 'Specific password'),
('random_one', 'All assets use the same random password'),
('random_all',
'All assets use different random password')],
default='specific', max_length=16,
verbose_name='Secret strategy')),
('secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Secret')),
('password_rules', models.JSONField(default=dict, verbose_name='Password rules')),
('ssh_key_change_strategy', models.CharField(
choices=[('add', 'Append SSH KEY'), ('set', 'Empty and append SSH KEY'),
('set_jms', 'Replace (The key generated by JumpServer) ')], default='add', max_length=16,
verbose_name='SSH key change strategy')),
('triggers', models.JSONField(default=list, max_length=16, verbose_name='Triggers')),
('username', models.CharField(max_length=128, verbose_name='Username')),
('action', models.CharField(max_length=16, verbose_name='Action')),
],
options={
'verbose_name': 'Push asset account',
},
bases=('accounts.accountbaseautomation', models.Model),
migrations.AddField(
model_name='changesecretrecord',
name='account',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='accounts.account'),
),
migrations.CreateModel(
name='GatherAccountsAutomation',
fields=[
('baseautomation_ptr',
models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True,
primary_key=True, serialize=False, to='assets.baseautomation')),
],
options={
'verbose_name': 'Gather asset accounts',
},
bases=('accounts.accountbaseautomation',),
migrations.AddField(
model_name='changesecretrecord',
name='asset',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='assets.asset'),
),
migrations.CreateModel(
name='VerifyAccountAutomation',
fields=[
('baseautomation_ptr',
models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True,
primary_key=True, serialize=False, to='assets.baseautomation')),
],
options={
'verbose_name': 'Verify asset account',
},
bases=('accounts.accountbaseautomation',),
migrations.AddField(
model_name='changesecretrecord',
name='execution',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='accounts.automationexecution'),
),
migrations.CreateModel(
name='ChangeSecretRecord',
fields=[
('created_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by')),
('updated_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Updated by')),
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('comment', models.TextField(blank=True, default='', verbose_name='Comment')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('old_secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Old secret')),
('new_secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='New secret')),
('date_started', models.DateTimeField(blank=True, null=True, verbose_name='Date started')),
('date_finished', models.DateTimeField(blank=True, null=True, verbose_name='Date finished')),
('status', models.CharField(default='pending', max_length=16, verbose_name='Status')),
('error', models.TextField(blank=True, null=True, verbose_name='Error')),
('account',
models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='accounts.account')),
('asset', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='assets.asset')),
('execution',
models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='accounts.automationexecution')),
],
options={
'verbose_name': 'Change secret record',
},
migrations.AddField(
model_name='accounttemplate',
name='platforms',
field=models.ManyToManyField(blank=True, related_name='account_templates', to='assets.platform', verbose_name='Platforms'),
),
migrations.CreateModel(
name='AccountBackupExecution',
fields=[
('org_id',
models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('date_start', models.DateTimeField(auto_now_add=True, verbose_name='Date start')),
('timedelta', models.FloatField(default=0.0, null=True, verbose_name='Time')),
('plan_snapshot',
models.JSONField(blank=True, default=dict, encoder=common.db.encoder.ModelJSONFieldEncoder, null=True,
verbose_name='Account backup snapshot')),
('trigger', models.CharField(choices=[('manual', 'Manual trigger'), ('timing', 'Timing trigger')],
default='manual', max_length=128, verbose_name='Trigger mode')),
('reason', models.CharField(blank=True, max_length=1024, null=True, verbose_name='Reason')),
('is_success', models.BooleanField(default=False, verbose_name='Is success')),
('plan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='execution',
to='accounts.accountbackupautomation', verbose_name='Account backup plan')),
],
options={
'verbose_name': 'Account backup execution',
'ordering': ('-date_start',),
},
migrations.AddField(
model_name='accounttemplate',
name='su_from',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='su_to', to='accounts.accounttemplate', verbose_name='Su from'),
),
migrations.CreateModel(
name='ChangeSecretAutomation',
fields=[
('baseautomation_ptr',
models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True,
primary_key=True, serialize=False, to='assets.baseautomation')),
('secret_type', models.CharField(
choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'),
('token', 'Token'), ('api_key', 'API key')], default='password', max_length=16,
verbose_name='Secret type')),
('secret_strategy', models.CharField(choices=[('specific', 'Specific password'),
('random_one', 'All assets use the same random password'),
('random_all',
'All assets use different random password')],
default='specific', max_length=16,
verbose_name='Secret strategy')),
('secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Secret')),
('password_rules', models.JSONField(default=dict, verbose_name='Password rules')),
('ssh_key_change_strategy', models.CharField(
choices=[('add', 'Append SSH KEY'), ('set', 'Empty and append SSH KEY'),
('set_jms', 'Replace (The key generated by JumpServer) ')], default='add', max_length=16,
verbose_name='SSH key change strategy')),
('recipients',
models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, verbose_name='Recipient')),
],
options={
'verbose_name': 'Change secret automation',
},
bases=('accounts.accountbaseautomation', models.Model),
migrations.AddField(
model_name='accountbackupexecution',
name='plan',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='execution', to='accounts.accountbackupautomation', verbose_name='Account backup plan'),
),
migrations.AlterModelOptions(
name='automationexecution',
options={'permissions': [('view_changesecretexecution', 'Can view change secret execution'),
('add_changesecretexecution', 'Can add change secret execution'),
('view_gatheraccountsexecution', 'Can view gather accounts execution'),
('add_gatheraccountsexecution', 'Can add gather accounts execution'),
('view_pushaccountexecution', 'Can view push account execution'),
('add_pushaccountexecution', 'Can add push account execution')],
'verbose_name': 'Automation execution', 'verbose_name_plural': 'Automation executions'},
migrations.AddField(
model_name='accountbackupautomation',
name='obj_recipients_part_one',
field=models.ManyToManyField(blank=True, related_name='obj_recipient_part_one_plans', to='terminal.replaystorage', verbose_name='Object storage recipient part one'),
),
migrations.AlterModelOptions(
name='changesecretrecord',
options={'ordering': ('-date_started',), 'verbose_name': 'Change secret record'},
migrations.AddField(
model_name='accountbackupautomation',
name='obj_recipients_part_two',
field=models.ManyToManyField(blank=True, related_name='obj_recipient_part_two_plans', to='terminal.replaystorage', verbose_name='Object storage recipient part two'),
),
migrations.AddField(
model_name='accountbackupautomation',
name='recipients_part_one',
field=models.ManyToManyField(blank=True, related_name='recipient_part_one_plans', to=settings.AUTH_USER_MODEL, verbose_name='Recipient part one'),
),
migrations.AddField(
model_name='accountbackupautomation',
name='recipients_part_two',
field=models.ManyToManyField(blank=True, related_name='recipient_part_two_plans', to=settings.AUTH_USER_MODEL, verbose_name='Recipient part two'),
),
migrations.AddField(
model_name='account',
name='asset',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='accounts', to='assets.asset', verbose_name='Asset'),
),
migrations.AddField(
model_name='account',
name='su_from',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='su_to', to='accounts.account', verbose_name='Su from'),
),
migrations.AlterUniqueTogether(
name='gatheredaccount',
unique_together={('username', 'asset')},
),
migrations.AddField(
model_name='gatheraccountsautomation',
name='recipients',
field=models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, verbose_name='Recipient'),
),
migrations.AddField(
model_name='changesecretautomation',
name='recipients',
field=models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, verbose_name='Recipient'),
),
migrations.AlterUniqueTogether(
name='accounttemplate',
unique_together={('name', 'org_id')},
),
migrations.AlterUniqueTogether(
name='accountbackupautomation',
unique_together={('name', 'org_id')},
),
migrations.AlterUniqueTogether(
name='account',
unique_together={('name', 'asset'), ('username', 'asset', 'secret_type')},
),
]

View File

@@ -1,23 +0,0 @@
# Generated by Django 3.2.16 on 2023-01-06 07:07
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts', '0003_automation'),
]
operations = [
migrations.AlterField(
model_name='changesecretautomation',
name='secret_strategy',
field=models.CharField(choices=[('specific', 'Specific secret'), ('random', 'Random generate')], default='specific', max_length=16, verbose_name='Secret strategy'),
),
migrations.AlterField(
model_name='pushaccountautomation',
name='secret_strategy',
field=models.CharField(choices=[('specific', 'Specific secret'), ('random', 'Random generate')], default='specific', max_length=16, verbose_name='Secret strategy'),
),
]

View File

@@ -1,17 +0,0 @@
# Generated by Django 3.2.16 on 2023-01-10 06:45
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('accounts', '0004_auto_20230106_1507'),
]
operations = [
migrations.AlterModelOptions(
name='changesecretrecord',
options={'ordering': ('-date_created',), 'verbose_name': 'Change secret record'},
),
]

View File

@@ -1,38 +0,0 @@
# Generated by Django 3.2.16 on 2023-02-07 04:41
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration):
dependencies = [
('assets', '0108_alter_platform_charset'),
('accounts', '0005_alter_changesecretrecord_options'),
]
operations = [
migrations.CreateModel(
name='GatheredAccount',
fields=[
('created_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by')),
('updated_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Updated by')),
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('comment', models.TextField(blank=True, default='', verbose_name='Comment')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('present', models.BooleanField(default=True, verbose_name='Present')),
('date_last_login', models.DateTimeField(null=True, verbose_name='Date last login')),
('username', models.CharField(blank=True, db_index=True, max_length=32, verbose_name='Username')),
('address_last_login', models.CharField(default='', max_length=39, verbose_name='Address last login')),
('asset', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='assets.asset', verbose_name='Asset')),
],
options={
'verbose_name': 'Gather account',
'ordering': ['asset'],
'unique_together': {('username', 'asset')},
},
),
]

View File

@@ -1,23 +0,0 @@
# Generated by Django 3.2.16 on 2023-02-16 11:07
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('accounts', '0006_gatheredaccount'),
]
operations = [
migrations.AlterModelOptions(
name='account',
options={'permissions': [
('view_accountsecret', 'Can view asset account secret'),
('view_historyaccount', 'Can view asset history account'),
('view_historyaccountsecret', 'Can view asset history account secret'),
('verify_account', 'Can verify account'),
('push_account', 'Can push account'),
('remove_account', 'Can remove account'),
], 'verbose_name': 'Account'},
),
]

View File

@@ -1,17 +0,0 @@
# Generated by Django 3.2.16 on 2023-02-23 09:59
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('accounts', '0007_alter_account_options'),
]
operations = [
migrations.AlterModelOptions(
name='gatheredaccount',
options={'ordering': ['asset'], 'verbose_name': 'Gather account automation'},
),
]

View File

@@ -1,69 +0,0 @@
# Generated by Django 3.2.16 on 2023-03-07 07:36
from django.db import migrations
from django.db.models import Q
def get_nodes_all_assets(apps, *nodes):
node_model = apps.get_model('assets', 'Node')
asset_model = apps.get_model('assets', 'Asset')
node_ids = set()
descendant_node_query = Q()
for n in nodes:
node_ids.add(n.id)
descendant_node_query |= Q(key__istartswith=f'{n.key}:')
if descendant_node_query:
_ids = node_model.objects.order_by().filter(descendant_node_query).values_list('id', flat=True)
node_ids.update(_ids)
return asset_model.objects.order_by().filter(nodes__id__in=node_ids).distinct()
def get_all_assets(apps, snapshot):
node_model = apps.get_model('assets', 'Node')
asset_model = apps.get_model('assets', 'Asset')
asset_ids = snapshot.get('assets', [])
node_ids = snapshot.get('nodes', [])
nodes = node_model.objects.filter(id__in=node_ids)
node_asset_ids = get_nodes_all_assets(apps, *nodes).values_list('id', flat=True)
asset_ids = set(list(asset_ids) + list(node_asset_ids))
return asset_model.objects.filter(id__in=asset_ids)
def migrate_account_usernames_to_ids(apps, schema_editor):
db_alias = schema_editor.connection.alias
execution_model = apps.get_model('accounts', 'AutomationExecution')
account_model = apps.get_model('accounts', 'Account')
executions = execution_model.objects.using(db_alias).all()
executions_update = []
for execution in executions:
snapshot = execution.snapshot
accounts = account_model.objects.none()
account_usernames = snapshot.get('accounts', [])
for asset in get_all_assets(apps, snapshot):
accounts = accounts | asset.accounts.all()
secret_type = snapshot.get('secret_type')
if secret_type:
ids = accounts.filter(
username__in=account_usernames,
secret_type=secret_type
).values_list('id', flat=True)
else:
ids = accounts.filter(
username__in=account_usernames
).values_list('id', flat=True)
snapshot['accounts'] = [str(_id) for _id in ids]
execution.snapshot = snapshot
executions_update.append(execution)
execution_model.objects.bulk_update(executions_update, ['snapshot'])
class Migration(migrations.Migration):
dependencies = [
('accounts', '0008_alter_gatheredaccount_options'),
]
operations = [
migrations.RunPython(migrate_account_usernames_to_ids),
]

View File

@@ -1,22 +0,0 @@
# Generated by Django 3.2.16 on 2023-03-23 08:39
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts', '0009_account_usernames_to_ids'),
]
operations = [
migrations.AddField(
model_name='gatheraccountsautomation',
name='is_sync_account',
field=models.BooleanField(blank=True, default=False, verbose_name='Is sync account'),
),
migrations.AddField(
model_name='account',
name='source_id',
field=models.CharField(max_length=128, null=True, blank=True, verbose_name='Source ID'),
),
]

View File

@@ -1,29 +0,0 @@
# Generated by Django 3.2.17 on 2023-05-06 06:43
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('accounts', '0010_gatheraccountsautomation_is_sync_account'),
]
operations = [
migrations.AddField(
model_name='accounttemplate',
name='su_from',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='su_to', to='accounts.accounttemplate', verbose_name='Su from'),
),
migrations.AlterField(
model_name='changesecretautomation',
name='ssh_key_change_strategy',
field=models.CharField(choices=[('add', 'Append SSH KEY'), ('set', 'Empty and append SSH KEY'), ('set_jms', 'Replace (Replace only keys pushed by JumpServer) ')], default='add', max_length=16, verbose_name='SSH key change strategy'),
),
migrations.AlterField(
model_name='pushaccountautomation',
name='ssh_key_change_strategy',
field=models.CharField(choices=[('add', 'Append SSH KEY'), ('set', 'Empty and append SSH KEY'), ('set_jms', 'Replace (Replace only keys pushed by JumpServer) ')], default='add', max_length=16, verbose_name='SSH key change strategy'),
),
]

View File

@@ -1,28 +0,0 @@
# Generated by Django 3.2.19 on 2023-06-21 06:56
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts', '0011_auto_20230506_1443'),
]
operations = [
migrations.RenameField(
model_name='account',
old_name='secret',
new_name='_secret',
),
migrations.RenameField(
model_name='accounttemplate',
old_name='secret',
new_name='_secret',
),
migrations.RenameField(
model_name='historicalaccount',
old_name='secret',
new_name='_secret',
),
]

View File

@@ -1,77 +0,0 @@
# Generated by Django 4.1.10 on 2023-08-03 08:28
from django.conf import settings
from django.db import migrations, models
import common.db.encoder
def migrate_recipients(apps, schema_editor):
account_backup_model = apps.get_model('accounts', 'AccountBackupAutomation')
execution_model = apps.get_model('accounts', 'AccountBackupExecution')
for account_backup in account_backup_model.objects.all():
recipients = list(account_backup.recipients.all())
if not recipients:
continue
account_backup.recipients_part_one.set(recipients)
objs = []
for execution in execution_model.objects.all():
snapshot = execution.snapshot
recipients = snapshot.pop('recipients', {})
snapshot.update({'recipients_part_one': recipients, 'recipients_part_two': {}})
objs.append(execution)
execution_model.objects.bulk_update(objs, ['snapshot'])
def migrate_snapshot(apps, schema_editor):
model = apps.get_model('accounts', 'AccountBackupExecution')
objs = []
for execution in model.objects.all():
execution.snapshot = execution.plan_snapshot
objs.append(execution)
model.objects.bulk_update(objs, ['snapshot'])
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('accounts', '0012_auto_20230621_1456'),
]
operations = [
migrations.AddField(
model_name='accountbackupautomation',
name='recipients_part_one',
field=models.ManyToManyField(
blank=True, related_name='recipient_part_one_plans',
to=settings.AUTH_USER_MODEL, verbose_name='Recipient part one'
),
),
migrations.AddField(
model_name='accountbackupautomation',
name='recipients_part_two',
field=models.ManyToManyField(
blank=True, related_name='recipient_part_two_plans',
to=settings.AUTH_USER_MODEL, verbose_name='Recipient part two'
),
),
migrations.AddField(
model_name='accountbackupexecution',
name='snapshot',
field=models.JSONField(
default=dict, encoder=common.db.encoder.ModelJSONFieldEncoder,
null=True, blank=True, verbose_name='Account backup snapshot'
),
),
migrations.RunPython(migrate_snapshot),
migrations.RunPython(migrate_recipients),
migrations.RemoveField(
model_name='accountbackupexecution',
name='plan_snapshot',
),
migrations.RemoveField(
model_name='accountbackupautomation',
name='recipients',
),
]

View File

@@ -1,31 +0,0 @@
# Generated by Django 4.1.10 on 2023-08-01 09:12
import uuid
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts', '0013_account_backup_recipients'),
]
operations = [
migrations.CreateModel(
name='VirtualAccount',
fields=[
('created_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by')),
('updated_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Updated by')),
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('alias', models.CharField(choices=[('@INPUT', 'Manual input'), ('@USER', 'Dynamic user'), ('@ANON', 'Anonymous account'), ('@SPEC', 'Specified account')], max_length=128, verbose_name='Alias')),
('secret_from_login', models.BooleanField(default=None, null=True, verbose_name='Secret from login')),
],
options={
'unique_together': {('alias', 'org_id')},
},
),
]

View File

@@ -1,34 +0,0 @@
# Generated by Django 4.1.10 on 2023-08-25 03:19
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('assets', '0122_auto_20230803_1553'),
('accounts', '0014_virtualaccount'),
]
operations = [
migrations.AddField(
model_name='accounttemplate',
name='auto_push',
field=models.BooleanField(default=False, verbose_name='Auto push'),
),
migrations.AddField(
model_name='accounttemplate',
name='platforms',
field=models.ManyToManyField(related_name='account_templates', to='assets.platform', verbose_name='Platforms', blank=True),
),
migrations.AddField(
model_name='accounttemplate',
name='push_params',
field=models.JSONField(default=dict, verbose_name='Push params'),
),
migrations.AddField(
model_name='accounttemplate',
name='secret_strategy',
field=models.CharField(choices=[('specific', 'Specific secret'), ('random', 'Random generate')], default='specific', max_length=16, verbose_name='Secret strategy'),
),
]

View File

@@ -1,18 +0,0 @@
# Generated by Django 4.1.10 on 2023-09-18 08:09
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts', '0015_auto_20230825_1120'),
]
operations = [
migrations.AddField(
model_name='accounttemplate',
name='password_rules',
field=models.JSONField(default=dict, verbose_name='Password rules'),
),
]

View File

@@ -1,25 +0,0 @@
# Generated by Django 4.1.10 on 2023-10-24 05:59
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('accounts', '0016_accounttemplate_password_rules'),
]
operations = [
migrations.AlterModelOptions(
name='automationexecution',
options={
'permissions': [
('view_changesecretexecution', 'Can view change secret execution'),
('add_changesecretexecution', 'Can add change secret execution'),
('view_gatheraccountsexecution', 'Can view gather accounts execution'),
('add_gatheraccountsexecution', 'Can add gather accounts execution'),
('view_pushaccountexecution', 'Can view push account execution'),
('add_pushaccountexecution', 'Can add push account execution')
],
'verbose_name': 'Automation execution', 'verbose_name_plural': 'Automation executions'},
),
]

View File

@@ -1,45 +0,0 @@
# Generated by Django 4.1.10 on 2023-11-03 07:10
import common.db.fields
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('terminal', '0067_alter_replaystorage_type'),
('accounts', '0017_alter_automationexecution_options'),
]
operations = [
migrations.AddField(
model_name='accountbackupautomation',
name='backup_type',
field=models.CharField(choices=[('email', 'Email'), ('object_storage', 'Object Storage')], default='email', max_length=128),
),
migrations.AddField(
model_name='accountbackupautomation',
name='is_password_divided_by_email',
field=models.BooleanField(default=True),
),
migrations.AddField(
model_name='accountbackupautomation',
name='is_password_divided_by_obj_storage',
field=models.BooleanField(default=True),
),
migrations.AddField(
model_name='accountbackupautomation',
name='obj_recipients_part_one',
field=models.ManyToManyField(blank=True, related_name='obj_recipient_part_one_plans', to='terminal.replaystorage', verbose_name='Object Storage Recipient part one'),
),
migrations.AddField(
model_name='accountbackupautomation',
name='obj_recipients_part_two',
field=models.ManyToManyField(blank=True, related_name='obj_recipient_part_two_plans', to='terminal.replaystorage', verbose_name='Object Storage Recipient part two'),
),
migrations.AddField(
model_name='accountbackupautomation',
name='zip_encrypt_password',
field=common.db.fields.EncryptCharField(blank=True, max_length=4096, null=True, verbose_name='Zip Encrypt Password'),
),
]

View File

@@ -1,20 +0,0 @@
# Generated by Django 4.1.10 on 2023-10-31 06:12
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('accounts', '0018_accountbackupautomation_backup_type_and_more'),
]
operations = [
migrations.AddField(
model_name='gatheraccountsautomation',
name='recipients',
field=models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, verbose_name='Recipient'),
),
]

View File

@@ -1,28 +0,0 @@
# Generated by Django 4.1.10 on 2023-11-16 02:13
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts', '0019_gatheraccountsautomation_recipients'),
]
operations = [
migrations.AlterField(
model_name='accountbackupautomation',
name='backup_type',
field=models.CharField(choices=[('email', 'Email'), ('object_storage', 'SFTP')], default='email', max_length=128, verbose_name='Backup Type'),
),
migrations.AlterField(
model_name='accountbackupautomation',
name='is_password_divided_by_email',
field=models.BooleanField(default=True, verbose_name='Is Password Divided'),
),
migrations.AlterField(
model_name='accountbackupautomation',
name='is_password_divided_by_obj_storage',
field=models.BooleanField(default=True, verbose_name='Is Password Divided'),
),
]

View File

@@ -119,7 +119,8 @@ class Account(AbsConnectivity, LabeledMixin, BaseAccount):
return auth
auth.update(self.make_account_ansible_vars(su_from))
become_method = platform.su_method if platform.su_method else 'sudo'
become_method = platform.ansible_become_method
password = su_from.secret if become_method == 'sudo' else self.secret
auth['ansible_become'] = True
auth['ansible_become_method'] = become_method

View File

@@ -24,9 +24,9 @@ logger = get_logger(__file__)
class AccountBackupAutomation(PeriodTaskModelMixin, JMSOrgBaseModel):
types = models.JSONField(default=list)
backup_type = models.CharField(max_length=128, choices=AccountBackupType.choices,
default=AccountBackupType.email.value, verbose_name=_('Backup Type'))
is_password_divided_by_email = models.BooleanField(default=True, verbose_name=_('Is Password Divided'))
is_password_divided_by_obj_storage = models.BooleanField(default=True, verbose_name=_('Is Password Divided'))
default=AccountBackupType.email.value, verbose_name=_('Backup type'))
is_password_divided_by_email = models.BooleanField(default=True, verbose_name=_('Password divided'))
is_password_divided_by_obj_storage = models.BooleanField(default=True, verbose_name=_('Password divided'))
recipients_part_one = models.ManyToManyField(
'users.User', related_name='recipient_part_one_plans', blank=True,
verbose_name=_("Recipient part one")
@@ -37,14 +37,15 @@ class AccountBackupAutomation(PeriodTaskModelMixin, JMSOrgBaseModel):
)
obj_recipients_part_one = models.ManyToManyField(
'terminal.ReplayStorage', related_name='obj_recipient_part_one_plans', blank=True,
verbose_name=_("Object Storage Recipient part one")
verbose_name=_("Object storage recipient part one")
)
obj_recipients_part_two = models.ManyToManyField(
'terminal.ReplayStorage', related_name='obj_recipient_part_two_plans', blank=True,
verbose_name=_("Object Storage Recipient part two")
verbose_name=_("Object storage recipient part two")
)
zip_encrypt_password = fields.EncryptCharField(
max_length=4096, blank=True, null=True, verbose_name=_('Zip encrypt password')
)
zip_encrypt_password = fields.EncryptCharField(max_length=4096, blank=True, null=True,
verbose_name=_('Zip Encrypt Password'))
def __str__(self):
return f'{self.name}({self.org_id})'

View File

@@ -12,10 +12,10 @@ __all__ = ['GatherAccountsAutomation', 'GatheredAccount']
class GatheredAccount(JMSOrgBaseModel):
present = models.BooleanField(default=True, verbose_name=_("Present"))
date_last_login = models.DateTimeField(null=True, verbose_name=_("Date last login"))
date_last_login = models.DateTimeField(null=True, verbose_name=_("Date login"))
asset = models.ForeignKey('assets.Asset', on_delete=models.CASCADE, verbose_name=_("Asset"))
username = models.CharField(max_length=32, blank=True, db_index=True, verbose_name=_('Username'))
address_last_login = models.CharField(max_length=39, default='', verbose_name=_("Address last login"))
address_last_login = models.CharField(max_length=39, default='', verbose_name=_("Address login"))
@property
def address(self):
@@ -41,7 +41,7 @@ class GatheredAccount(JMSOrgBaseModel):
Account.objects.bulk_create(account_objs)
class Meta:
verbose_name = _('Gather account automation')
verbose_name = _("Gather asset accounts")
unique_together = [
('username', 'asset'),
]
@@ -72,4 +72,4 @@ class GatherAccountsAutomation(AccountBaseAutomation):
super().save(*args, **kwargs)
class Meta:
verbose_name = _("Gather asset accounts")
verbose_name = _('Gather account automation')

View File

@@ -29,7 +29,6 @@ class AccountTemplate(LabeledMixin, BaseAccount, SecretWithRandomMixin):
)
permissions = [
('view_accounttemplatesecret', _('Can view asset account template secret')),
('change_accounttemplatesecret', _('Can change asset account template secret')),
]
def __str__(self):

View File

@@ -15,6 +15,7 @@ class VirtualAccount(JMSOrgBaseModel):
class Meta:
unique_together = [('alias', 'org_id')]
verbose_name = _('Virtual account')
@property
def name(self):

View File

@@ -31,7 +31,9 @@ class AccountCreateUpdateSerializerMixin(serializers.Serializer):
default=False, label=_("Push now"), write_only=True
)
params = serializers.JSONField(
decoder=None, encoder=None, required=False, style={'base_template': 'textarea.html'}
decoder=None, encoder=None, required=False,
style={'base_template': 'textarea.html'},
label=_('Params'),
)
on_invalid = LabeledChoiceField(
choices=AccountInvalidPolicy.choices, default=AccountInvalidPolicy.ERROR,
@@ -79,18 +81,28 @@ class AccountCreateUpdateSerializerMixin(serializers.Serializer):
@staticmethod
def get_template_attr_for_account(template):
# Set initial data from template
field_names = [
'name', 'username', 'secret',
'secret_type', 'privileged', 'is_active'
'name', 'username',
'secret_type', 'secret',
'privileged', 'is_active'
]
field_map = {
'push_params': 'params',
'auto_push': 'push_now'
}
field_names.extend(field_map.keys())
attrs = {}
for name in field_names:
value = getattr(template, name, None)
if value is None:
continue
attrs[name] = value
attr_name = field_map.get(name, name)
attrs[attr_name] = value
attrs['secret'] = template.get_secret()
return attrs
@@ -173,7 +185,8 @@ class AccountCreateUpdateSerializerMixin(serializers.Serializer):
params = validated_data.pop('params', None)
self.clean_auth_fields(validated_data)
instance, stat = self.do_create(validated_data)
self.push_account_if_need(instance, push_now, params, stat)
if instance.source == Source.LOCAL:
self.push_account_if_need(instance, push_now, params, stat)
return instance
def update(self, instance, validated_data):
@@ -225,7 +238,7 @@ class AccountSerializer(AccountCreateUpdateSerializerMixin, BaseAccountSerialize
fields = BaseAccountSerializer.Meta.fields + [
'su_from', 'asset', 'version',
'source', 'source_id', 'connectivity',
] + list(set(AccountCreateUpdateSerializerMixin.Meta.fields) - {'params'})
] + AccountCreateUpdateSerializerMixin.Meta.fields
read_only_fields = BaseAccountSerializer.Meta.read_only_fields + [
'connectivity'
]
@@ -275,8 +288,8 @@ class AssetAccountBulkSerializer(
fields = [
'name', 'username', 'secret', 'secret_type', 'passphrase',
'privileged', 'is_active', 'comment', 'template',
'on_invalid', 'push_now', 'assets', 'su_from_username',
'source', 'source_id',
'on_invalid', 'push_now', 'params', 'assets',
'su_from_username', 'source', 'source_id',
]
extra_kwargs = {
'name': {'required': False},
@@ -414,16 +427,23 @@ class AssetAccountBulkSerializer(
return results
@staticmethod
def push_accounts_if_need(results, push_now):
def push_accounts_if_need(results, push_now, params):
if not push_now:
return
accounts = [str(v['instance']) for v in results if v.get('instance')]
push_accounts_to_assets_task.delay(accounts)
account_ids = [v['instance'] for v in results if v.get('instance')]
accounts = Account.objects.filter(id__in=account_ids, source=Source.LOCAL)
if not accounts.exists():
return
account_ids = [str(_id) for _id in accounts.values_list('id', flat=True)]
push_accounts_to_assets_task.delay(account_ids, params)
def create(self, validated_data):
params = validated_data.pop('params', None)
push_now = validated_data.pop('push_now', False)
results = self.perform_bulk_create(validated_data)
self.push_accounts_if_need(results, push_now)
self.push_accounts_if_need(results, push_now, params)
for res in results:
res['asset'] = str(res['asset'])
return results

View File

@@ -35,8 +35,7 @@ class AccountBackupSerializer(PeriodTaskSerializerMixin, BulkOrgResourceModelSer
]
extra_kwargs = {
'name': {'required': True},
'periodic_display': {'label': _('Periodic perform')},
'executed_amount': {'label': _('Executed amount')},
'executed_amount': {'label': _('Executions')},
'recipients': {
'label': _('Recipient'),
'help_text': _('Currently only mail sending is supported')

View File

@@ -9,26 +9,34 @@ from common.serializers import ResourceLabelsMixin
from common.serializers.fields import EncryptedField, LabeledChoiceField
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
__all__ = ['AuthValidateMixin', 'BaseAccountSerializer']
__all__ = ["AuthValidateMixin", "BaseAccountSerializer"]
class AuthValidateMixin(serializers.Serializer):
secret_type = LabeledChoiceField(
choices=SecretType.choices, label=_('Secret type'), default='password'
choices=SecretType.choices, label=_("Secret type"), default="password"
)
secret = EncryptedField(
label=_('Secret'), required=False, max_length=40960, allow_blank=True,
allow_null=True, write_only=True,
label=_("Secret"),
required=False,
max_length=40960,
allow_blank=True,
allow_null=True,
write_only=True,
)
passphrase = serializers.CharField(
allow_blank=True, allow_null=True, required=False, max_length=512,
write_only=True, label=_('Key password')
allow_blank=True,
allow_null=True,
required=False,
max_length=512,
write_only=True,
label=_("Passphrase"),
)
@staticmethod
def handle_secret(secret, secret_type, passphrase=None):
if not secret:
return ''
return ""
if secret_type == SecretType.PASSWORD:
validate_password_for_ansible(secret)
return secret
@@ -40,17 +48,15 @@ class AuthValidateMixin(serializers.Serializer):
return secret
def clean_auth_fields(self, validated_data):
secret_type = validated_data.get('secret_type')
passphrase = validated_data.get('passphrase')
secret = validated_data.pop('secret', None)
validated_data['secret'] = self.handle_secret(
secret, secret_type, passphrase
)
for field in ('secret',):
secret_type = validated_data.get("secret_type")
passphrase = validated_data.get("passphrase")
secret = validated_data.pop("secret", None)
validated_data["secret"] = self.handle_secret(secret, secret_type, passphrase)
for field in ("secret",):
value = validated_data.get(field)
if not value:
validated_data.pop(field, None)
validated_data.pop('passphrase', None)
validated_data.pop("passphrase", None)
def create(self, validated_data):
self.clean_auth_fields(validated_data)
@@ -61,22 +67,34 @@ class AuthValidateMixin(serializers.Serializer):
return super().update(instance, validated_data)
class BaseAccountSerializer(AuthValidateMixin, ResourceLabelsMixin, BulkOrgResourceModelSerializer):
class BaseAccountSerializer(
AuthValidateMixin, ResourceLabelsMixin, BulkOrgResourceModelSerializer
):
class Meta:
model = BaseAccount
fields_mini = ['id', 'name', 'username']
fields_mini = ["id", "name", "username"]
fields_small = fields_mini + [
'secret_type', 'secret', 'passphrase',
'privileged', 'is_active',
"secret_type",
"secret",
"passphrase",
"privileged",
"is_active",
"spec_info",
]
fields_other = ['created_by', 'date_created', 'date_updated', 'comment']
fields = fields_small + fields_other + ['labels']
fields_other = ["created_by", "date_created", "date_updated", "comment"]
fields = fields_small + fields_other + ["labels"]
read_only_fields = [
'date_verified', 'created_by', 'date_created',
"spec_info",
"date_verified",
"created_by",
"date_created",
]
extra_kwargs = {
'username': {'help_text': _(
"Tip: If no username is required for authentication, fill in `null`, "
"If AD account, like `username@domain`"
)},
"spec_info": {"label": _("Spec info")},
"username": {
"help_text": _(
"* If no username is required for authentication, enter null. "
"For AD accounts, use the format username@domain."
)
},
}

View File

@@ -25,7 +25,8 @@ class BaseAutomationSerializer(PeriodTaskSerializerMixin, BulkOrgResourceModelSe
class Meta:
read_only_fields = [
'date_created', 'date_updated', 'created_by', 'periodic_display', 'executed_amount'
'date_created', 'date_updated', 'created_by',
'periodic_display', 'executed_amount'
]
fields = read_only_fields + [
'id', 'name', 'is_periodic', 'interval', 'crontab', 'comment',
@@ -34,8 +35,7 @@ class BaseAutomationSerializer(PeriodTaskSerializerMixin, BulkOrgResourceModelSe
extra_kwargs = {
'name': {'required': True},
'type': {'read_only': True},
'periodic_display': {'label': _('Periodic perform')},
'executed_amount': {'label': _('Executed amount')},
'executed_amount': {'label': _('Executions')},
}
def validate_name(self, name):

View File

@@ -54,10 +54,13 @@ class ChangeSecretAutomationSerializer(AuthValidateMixin, BaseAutomationSerializ
'ssh_key_change_strategy', 'passphrase', 'recipients', 'params'
]
extra_kwargs = {**BaseAutomationSerializer.Meta.extra_kwargs, **{
'accounts': {'required': True},
'accounts': {'required': True, 'help_text': _('Please enter your account username')},
'recipients': {'label': _('Recipient'), 'help_text': _(
"Currently only mail sending is supported"
)},
'params': {'help_text': _(
"Secret parameter settings, currently only effective for assets of the host type."
)},
}}
@property

View File

@@ -7,7 +7,6 @@ from .change_secret import (
class PushAccountAutomationSerializer(ChangeSecretAutomationSerializer):
class Meta(ChangeSecretAutomationSerializer.Meta):
model = PushAccountAutomation
fields = [

View File

@@ -6,6 +6,7 @@ from django.dispatch import receiver
from django.utils.translation import gettext_noop
from accounts.backends import vault_client
from accounts.const import Source
from audits.const import ActivityChoices
from audits.signal_handlers import create_activities
from common.decorators import merge_delay_run
@@ -32,7 +33,7 @@ def push_accounts_if_need(accounts=()):
template_accounts = defaultdict(list)
for ac in accounts:
# 再强调一次吧
if ac.source != 'template':
if ac.source != Source.TEMPLATE:
continue
template_accounts[ac.source_id].append(ac)
@@ -61,7 +62,7 @@ def create_accounts_activities(account, action='create'):
@receiver(post_save, sender=Account)
def on_account_create_by_template(sender, instance, created=False, **kwargs):
if not created or instance.source != 'template':
if not created or instance.source != Source.TEMPLATE:
return
push_accounts_if_need.delay(accounts=(instance,))
create_accounts_activities(instance, action='create')

View File

@@ -4,4 +4,4 @@ from django.utils.translation import gettext_lazy as _
class AclsConfig(AppConfig):
name = 'acls'
verbose_name = _('Acls')
verbose_name = _('App Acls')

View File

@@ -6,5 +6,5 @@ class ActionChoices(models.TextChoices):
reject = 'reject', _('Reject')
accept = 'accept', _('Accept')
review = 'review', _('Review')
warning = 'warning', _('Warning')
notice = 'notice', _('Notifications')
warning = 'warning', _('Warn')
notice = 'notice', _('Notify')

View File

@@ -1,75 +1,129 @@
# Generated by Django 3.1 on 2021-03-11 09:53
import uuid
# Generated by Django 4.1.13 on 2024-05-09 03:16
import common.db.fields
import django.core.validators
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
import uuid
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='LoginACL',
name='CommandFilterACL',
fields=[
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')),
('created_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by')),
('updated_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Updated by')),
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('name', models.CharField(max_length=128, verbose_name='Name')),
('priority', models.IntegerField(default=50, help_text='1-100, the lower the value will be match first',
validators=[django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(100)],
verbose_name='Priority')),
('is_active', models.BooleanField(default=True, verbose_name='Active')),
('comment', models.TextField(blank=True, default='', verbose_name='Comment')),
('ip_group', models.JSONField(default=list, verbose_name='Login IP')),
('action',
models.CharField(choices=[('reject', 'Reject'), ('allow', 'Allow')], default='reject', max_length=64,
verbose_name='Action')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='login_acls',
to=settings.AUTH_USER_MODEL, verbose_name='User')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('priority', models.IntegerField(default=50, help_text='1-100, the lower the value will be match first', validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(100)], verbose_name='Priority')),
('action', models.CharField(default='reject', max_length=64, verbose_name='Action')),
('is_active', models.BooleanField(default=True, verbose_name='Active')),
('users', common.db.fields.JSONManyToManyField(default=dict, to='users.User', verbose_name='Users')),
('name', models.CharField(max_length=128, verbose_name='Name')),
('assets', common.db.fields.JSONManyToManyField(default=dict, to='assets.Asset', verbose_name='Assets')),
('accounts', models.JSONField(default=list, verbose_name='Accounts')),
],
options={
'verbose_name': 'Command acl',
'ordering': ('priority', '-is_active', 'name'),
'abstract': False,
},
),
migrations.CreateModel(
name='CommandGroup',
fields=[
('created_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by')),
('updated_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Updated by')),
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('comment', models.TextField(blank=True, default='', verbose_name='Comment')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('name', models.CharField(max_length=128, verbose_name='Name')),
('type', models.CharField(choices=[('command', 'Command'), ('regex', 'Regex')], default='command', max_length=16, verbose_name='Type')),
('content', models.TextField(help_text='One command per line', verbose_name='Content')),
('ignore_case', models.BooleanField(default=True, verbose_name='Ignore case')),
],
options={
'verbose_name': 'Command group',
},
),
migrations.CreateModel(
name='ConnectMethodACL',
fields=[
('created_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by')),
('updated_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Updated by')),
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('comment', models.TextField(blank=True, default='', verbose_name='Comment')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('name', models.CharField(max_length=128, unique=True, verbose_name='Name')),
('priority', models.IntegerField(default=50, help_text='1-100, the lower the value will be match first', validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(100)], verbose_name='Priority')),
('action', models.CharField(default='reject', max_length=64, verbose_name='Action')),
('is_active', models.BooleanField(default=True, verbose_name='Active')),
('users', common.db.fields.JSONManyToManyField(default=dict, to='users.User', verbose_name='Users')),
('connect_methods', models.JSONField(default=list, verbose_name='Connect methods')),
],
options={
'verbose_name': 'Connect method acl',
'ordering': ('priority', '-is_active', 'name'),
'abstract': False,
},
),
migrations.CreateModel(
name='LoginACL',
fields=[
('created_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by')),
('updated_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Updated by')),
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('comment', models.TextField(blank=True, default='', verbose_name='Comment')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('name', models.CharField(max_length=128, unique=True, verbose_name='Name')),
('priority', models.IntegerField(default=50, help_text='1-100, the lower the value will be match first', validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(100)], verbose_name='Priority')),
('action', models.CharField(default='reject', max_length=64, verbose_name='Action')),
('is_active', models.BooleanField(default=True, verbose_name='Active')),
('users', common.db.fields.JSONManyToManyField(default=dict, to='users.User', verbose_name='Users')),
('rules', models.JSONField(default=dict, verbose_name='Rule')),
],
options={
'verbose_name': 'Login acl',
'ordering': ('priority', '-is_active', 'name'),
'abstract': False,
},
),
migrations.CreateModel(
name='LoginAssetACL',
fields=[
('org_id',
models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')),
('created_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by')),
('updated_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Updated by')),
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('name', models.CharField(max_length=128, verbose_name='Name')),
('priority', models.IntegerField(default=50, help_text='1-100, the lower the value will be match first',
validators=[django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(100)],
verbose_name='Priority')),
('is_active', models.BooleanField(default=True, verbose_name='Active')),
('comment', models.TextField(blank=True, default='', verbose_name='Comment')),
('users', models.JSONField(verbose_name='User')),
('system_users', models.JSONField(verbose_name='System User')),
('assets', models.JSONField(verbose_name='Asset')),
('action',
models.CharField(choices=[('login_confirm', 'Login confirm')], default='login_confirm', max_length=64,
verbose_name='Action')),
('reviewers',
models.ManyToManyField(blank=True, related_name='review_login_asset_acls', to=settings.AUTH_USER_MODEL,
verbose_name='Reviewers')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('priority', models.IntegerField(default=50, help_text='1-100, the lower the value will be match first', validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(100)], verbose_name='Priority')),
('action', models.CharField(default='reject', max_length=64, verbose_name='Action')),
('is_active', models.BooleanField(default=True, verbose_name='Active')),
('users', common.db.fields.JSONManyToManyField(default=dict, to='users.User', verbose_name='Users')),
('name', models.CharField(max_length=128, verbose_name='Name')),
('assets', common.db.fields.JSONManyToManyField(default=dict, to='assets.Asset', verbose_name='Assets')),
('accounts', models.JSONField(default=list, verbose_name='Accounts')),
('rules', models.JSONField(default=dict, verbose_name='Rule')),
],
options={
'verbose_name': 'Login asset acl',
'ordering': ('priority', '-is_active', 'name'),
'unique_together': {('name', 'org_id')},
'abstract': False,
},
),
]

View File

@@ -1,98 +1,54 @@
# Generated by Django 3.1.12 on 2021-09-26 02:47
import django
# Generated by Django 4.1.13 on 2024-05-09 03:16
from django.conf import settings
from django.db import migrations, models, transaction
LOGIN_CONFIRM_ZH = '登录复核'
LOGIN_CONFIRM_EN = 'Login confirm'
DEFAULT_TIME_PERIODS = [{'id': i, 'value': '00:00~00:00'} for i in range(7)]
def has_zh(name: str) -> bool:
for i in name:
if u'\u4e00' <= i <= u'\u9fff':
return True
return False
def migrate_login_confirm(apps, schema_editor):
login_acl_model = apps.get_model("acls", "LoginACL")
login_confirm_model = apps.get_model("authentication", "LoginConfirmSetting")
with transaction.atomic():
for instance in login_confirm_model.objects.filter(is_active=True):
user = instance.user
reviewers = instance.reviewers.all()
login_confirm = LOGIN_CONFIRM_ZH if has_zh(user.name) else LOGIN_CONFIRM_EN
date_created = instance.date_created.strftime('%Y-%m-%d %H:%M:%S')
if reviewers.count() == 0:
continue
data = {
'user': user,
'name': f'{user.name}-{login_confirm} ({date_created})',
'created_by': instance.created_by,
'action': 'confirm',
'rules': {'ip_group': ['*'], 'time_period': DEFAULT_TIME_PERIODS}
}
instance = login_acl_model.objects.create(**data)
instance.reviewers.set(reviewers)
def migrate_ip_group(apps, schema_editor):
login_acl_model = apps.get_model("acls", "LoginACL")
updates = list()
with transaction.atomic():
for instance in login_acl_model.objects.exclude(action='confirm'):
instance.rules = {'ip_group': instance.ip_group, 'time_period': DEFAULT_TIME_PERIODS}
updates.append(instance)
login_acl_model.objects.bulk_update(updates, ['rules', ])
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('acls', '0001_initial'),
('authentication', '0004_ssotoken'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AlterField(
model_name='loginacl',
name='action',
field=models.CharField(choices=[('reject', 'Reject'), ('allow', 'Allow'), ('confirm', 'Login confirm')],
default='reject', max_length=64, verbose_name='Action'),
migrations.AddField(
model_name='loginassetacl',
name='reviewers',
field=models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, verbose_name='Reviewers'),
),
migrations.AddField(
model_name='loginacl',
name='reviewers',
field=models.ManyToManyField(blank=True, related_name='login_confirm_acls',
to=settings.AUTH_USER_MODEL, verbose_name='Reviewers'),
),
migrations.AlterField(
model_name='loginacl',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE,
related_name='login_acls', to=settings.AUTH_USER_MODEL, verbose_name='User'),
field=models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, verbose_name='Reviewers'),
),
migrations.AddField(
model_name='loginacl',
name='rules',
field=models.JSONField(default=dict, verbose_name='Rule'),
model_name='connectmethodacl',
name='reviewers',
field=models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, verbose_name='Reviewers'),
),
migrations.RunPython(migrate_login_confirm),
migrations.RunPython(migrate_ip_group),
migrations.RemoveField(
model_name='loginacl',
name='ip_group',
migrations.AlterUniqueTogether(
name='commandgroup',
unique_together={('org_id', 'name')},
),
migrations.AlterModelOptions(
name='loginacl',
options={'ordering': ('priority', '-is_active', 'name'), 'verbose_name': 'Login acl'},
migrations.AddField(
model_name='commandfilteracl',
name='command_groups',
field=models.ManyToManyField(related_name='command_filters', to='acls.commandgroup', verbose_name='Command group'),
),
migrations.AlterModelOptions(
migrations.AddField(
model_name='commandfilteracl',
name='reviewers',
field=models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, verbose_name='Reviewers'),
),
migrations.AlterUniqueTogether(
name='loginassetacl',
options={'ordering': ('priority', '-is_active', 'name'), 'verbose_name': 'Login asset acl'},
unique_together={('name', 'org_id')},
),
migrations.AlterUniqueTogether(
name='commandfilteracl',
unique_together={('name', 'org_id')},
),
]

View File

@@ -1,20 +0,0 @@
# Generated by Django 3.1.13 on 2021-11-30 02:37
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('acls', '0002_auto_20210926_1047'),
]
operations = [
migrations.AlterModelOptions(
name='loginacl',
options={'ordering': ('priority', '-is_active', 'name'), 'verbose_name': 'Login acl'},
),
migrations.AlterModelOptions(
name='loginassetacl',
options={'ordering': ('priority', '-is_active', 'name'), 'verbose_name': 'Login asset acl'},
),
]

View File

@@ -1,33 +0,0 @@
# Generated by Django 3.2.13 on 2022-08-31 08:58
from django.db import migrations, models
def migrate_system_users_to_accounts(apps, schema_editor):
login_asset_acl_model = apps.get_model('acls', 'LoginAssetACL')
qs = login_asset_acl_model.objects.all()
login_asset_acls = []
for instance in qs:
instance.accounts = instance.system_users
login_asset_acls.append(instance)
login_asset_acl_model.objects.bulk_update(login_asset_acls, ['accounts'])
class Migration(migrations.Migration):
dependencies = [
('acls', '0003_auto_20211130_1037'),
]
operations = [
migrations.AddField(
model_name='loginassetacl',
name='accounts',
field=models.JSONField(verbose_name='Account'),
),
migrations.RunPython(migrate_system_users_to_accounts),
migrations.RemoveField(
model_name='loginassetacl',
name='system_users',
),
]

View File

@@ -1,34 +0,0 @@
# Generated by Django 3.2.14 on 2022-12-01 10:46
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('acls', '0004_auto_20220831_1658'),
]
operations = [
migrations.AlterField(
model_name='loginacl',
name='action',
field=models.CharField(default='reject', max_length=64, verbose_name='Action'),
),
migrations.AlterField(
model_name='loginacl',
name='reviewers',
field=models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, verbose_name='Reviewers'),
),
migrations.AlterField(
model_name='loginassetacl',
name='action',
field=models.CharField(default='reject', max_length=64, verbose_name='Action'),
),
migrations.AlterField(
model_name='loginassetacl',
name='reviewers',
field=models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, verbose_name='Reviewers'),
),
]

View File

@@ -1,70 +0,0 @@
# Generated by Django 3.2.14 on 2022-12-01 11:39
import uuid
import django.core.validators
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('acls', '0005_auto_20221201_1846'),
]
operations = [
migrations.CreateModel(
name='CommandGroup',
fields=[
('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')),
('updated_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Updated by')),
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('org_id',
models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('name', models.CharField(max_length=128, verbose_name='Name')),
('type', models.CharField(choices=[('command', 'Command'), ('regex', 'Regex')], default='command',
max_length=16, verbose_name='Type')),
('content', models.TextField(help_text='One line one command', verbose_name='Content')),
('comment', models.TextField(blank=True, default='', verbose_name='Comment')),
('ignore_case', models.BooleanField(default=True, verbose_name='Ignore case')),
],
options={
'verbose_name': 'Command filter rule',
'unique_together': {('org_id', 'name')},
},
),
migrations.CreateModel(
name='CommandFilterACL',
fields=[
('org_id',
models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')),
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('name', models.CharField(max_length=128, verbose_name='Name')),
('priority', models.IntegerField(default=50, help_text='1-100, the lower the value will be match first',
validators=[django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(100)],
verbose_name='Priority')),
('action', models.CharField(default='reject', max_length=64, verbose_name='Action')),
('is_active', models.BooleanField(default=True, verbose_name='Active')),
('comment', models.TextField(blank=True, default='', verbose_name='Comment')),
('users', models.JSONField(verbose_name='User')),
('accounts', models.JSONField(verbose_name='Account')),
('assets', models.JSONField(verbose_name='Asset')),
('commands', models.ManyToManyField(to='acls.CommandGroup', verbose_name='Commands')),
(
'reviewers',
models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, verbose_name='Reviewers')),
],
options={
'verbose_name': 'Command acl',
'ordering': ('priority', '-is_active', 'name'),
'unique_together': {('name', 'org_id')},
},
),
]

View File

@@ -1,21 +0,0 @@
# Generated by Django 3.2.14 on 2022-12-02 02:48
from django.db import migrations
def migrate_login_type(apps, schema_editor):
login_asset_model = apps.get_model('acls', 'LoginAssetACL')
login_asset_model.objects.filter(action='login_confirm').update(action='review')
login_system_model = apps.get_model('acls', 'LoginACL')
login_system_model.objects.filter(action='confirm').update(action='review')
class Migration(migrations.Migration):
dependencies = [
('acls', '0006_commandfilteracl_commandgroup'),
]
operations = [
migrations.RunPython(migrate_login_type),
]

View File

@@ -1,33 +0,0 @@
# Generated by Django 3.2.14 on 2022-12-02 04:25
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('acls', '0007_auto_20221202_1048'),
]
operations = [
migrations.AlterModelOptions(
name='commandgroup',
options={'verbose_name': 'Command group'},
),
migrations.RenameField(
model_name='commandfilteracl',
old_name='commands',
new_name='command_groups',
),
migrations.AlterModelOptions(
name='commandfilteracl',
options={'ordering': ('priority', '-is_active', 'name'), 'verbose_name': 'Command acl'},
),
migrations.AlterModelOptions(
name='loginacl',
options={'ordering': ('priority', '-is_active', 'name'), 'verbose_name': 'Login acl'},
),
migrations.AlterModelOptions(
name='loginassetacl',
options={'ordering': ('priority', '-is_active', 'name'), 'verbose_name': 'Login asset acl'},
),
]

View File

@@ -1,53 +0,0 @@
# Generated by Django 3.2.14 on 2022-12-20 11:56
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('acls', '0008_commandgroup_comment'),
]
operations = [
migrations.AddField(
model_name='commandfilteracl',
name='updated_by',
field=models.CharField(blank=True, max_length=128, null=True, verbose_name='Updated by'),
),
migrations.AddField(
model_name='loginacl',
name='updated_by',
field=models.CharField(blank=True, max_length=128, null=True, verbose_name='Updated by'),
),
migrations.AddField(
model_name='loginassetacl',
name='updated_by',
field=models.CharField(blank=True, max_length=128, null=True, verbose_name='Updated by'),
),
migrations.AlterField(
model_name='commandfilteracl',
name='created_by',
field=models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by'),
),
migrations.AlterField(
model_name='commandgroup',
name='created_by',
field=models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by'),
),
migrations.AlterField(
model_name='commandgroup',
name='updated_by',
field=models.CharField(blank=True, max_length=128, null=True, verbose_name='Updated by'),
),
migrations.AlterField(
model_name='loginacl',
name='created_by',
field=models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by'),
),
migrations.AlterField(
model_name='loginassetacl',
name='created_by',
field=models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by'),
),
]

View File

@@ -1,18 +0,0 @@
# Generated by Django 3.2.16 on 2023-01-10 06:45
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('acls', '0009_auto_20221220_1956'),
]
operations = [
migrations.AlterField(
model_name='commandfilteracl',
name='command_groups',
field=models.ManyToManyField(to='acls.CommandGroup', verbose_name='Command group'),
),
]

View File

@@ -1,44 +0,0 @@
# Generated by Django 3.2.17 on 2023-04-25 09:04
from django.db import migrations, models
import common.db.fields
class Migration(migrations.Migration):
dependencies = [
('acls', '0010_alter_commandfilteracl_command_groups'),
]
operations = [
migrations.AddField(
model_name='commandfilteracl',
name='new_accounts',
field=models.JSONField(default=list, verbose_name='Accounts'),
),
migrations.AddField(
model_name='commandfilteracl',
name='new_assets',
field=common.db.fields.JSONManyToManyField(default=dict, to='assets.Asset', verbose_name='Assets'),
),
migrations.AddField(
model_name='commandfilteracl',
name='new_users',
field=common.db.fields.JSONManyToManyField(default=dict, to='users.User', verbose_name='Users'),
),
migrations.AddField(
model_name='loginassetacl',
name='new_accounts',
field=models.JSONField(default=list, verbose_name='Accounts')
),
migrations.AddField(
model_name='loginassetacl',
name='new_assets',
field=common.db.fields.JSONManyToManyField(default=dict, to='assets.Asset', verbose_name='Assets'),
),
migrations.AddField(
model_name='loginassetacl',
name='new_users',
field=common.db.fields.JSONManyToManyField(default=dict, to='users.User', verbose_name='Users'),
),
]

View File

@@ -1,41 +0,0 @@
# Generated by Django 3.2.17 on 2023-04-26 03:11
from django.db import migrations
def migrate_base_acl_users_assets_accounts(apps, *args):
cmd_acl_model = apps.get_model('acls', 'CommandFilterACL')
login_asset_acl_model = apps.get_model('acls', 'LoginAssetACL')
for model in [cmd_acl_model, login_asset_acl_model]:
for obj in model.objects.all():
user_names = (obj.users or {}).get('username_group', [])
obj.new_users = {
"type": "attrs",
"attrs": [{"name": "username", "value": user_names, "match": "in"}]
}
asset_names = (obj.assets or {}).get('name_group', [])
asset_attrs = []
if asset_names:
asset_attrs.append({"name": "name", "value": asset_names, "match": "in"})
asset_address = (obj.assets or {}).get('address_group', [])
if asset_address:
asset_attrs.append({"name": "address", "value": asset_address, "match": "ip_in"})
obj.new_assets = {"type": "attrs", "attrs": asset_attrs}
account_usernames = (obj.accounts or {}).get('username_group', [])
if '*' in account_usernames:
account_usernames = ['@ALL']
obj.new_accounts = account_usernames
obj.save()
class Migration(migrations.Migration):
dependencies = [
('acls', '0011_auto_20230425_1704'),
]
operations = [
migrations.RunPython(migrate_base_acl_users_assets_accounts)
]

View File

@@ -1,66 +0,0 @@
# Generated by Django 3.2.17 on 2023-04-26 09:59
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('acls', '0012_auto_20230426_1111'),
]
operations = [
migrations.RemoveField(
model_name='commandfilteracl',
name='accounts',
),
migrations.RemoveField(
model_name='commandfilteracl',
name='assets',
),
migrations.RemoveField(
model_name='commandfilteracl',
name='users',
),
migrations.RemoveField(
model_name='loginassetacl',
name='accounts',
),
migrations.RemoveField(
model_name='loginassetacl',
name='assets',
),
migrations.RemoveField(
model_name='loginassetacl',
name='users',
),
migrations.RenameField(
model_name='commandfilteracl',
old_name='new_accounts',
new_name='accounts',
),
migrations.RenameField(
model_name='commandfilteracl',
old_name='new_assets',
new_name='assets',
),
migrations.RenameField(
model_name='commandfilteracl',
old_name='new_users',
new_name='users',
),
migrations.RenameField(
model_name='loginassetacl',
old_name='new_accounts',
new_name='accounts',
),
migrations.RenameField(
model_name='loginassetacl',
old_name='new_assets',
new_name='assets',
),
migrations.RenameField(
model_name='loginassetacl',
old_name='new_users',
new_name='users',
),
]

View File

@@ -1,18 +0,0 @@
# Generated by Django 3.2.17 on 2023-05-26 09:00
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('acls', '0013_auto_20230426_1759'),
]
operations = [
migrations.AddField(
model_name='loginassetacl',
name='rules',
field=models.JSONField(default=dict, verbose_name='Rule'),
),
]

View File

@@ -1,46 +0,0 @@
# Generated by Django 3.2.17 on 2023-06-06 06:23
import uuid
import django.core.validators
from django.conf import settings
from django.db import migrations, models
import common.db.fields
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('acls', '0014_loginassetacl_rules'),
]
operations = [
migrations.CreateModel(
name='ConnectMethodACL',
fields=[
('created_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by')),
('updated_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Updated by')),
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('comment', models.TextField(blank=True, default='', verbose_name='Comment')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('name', models.CharField(max_length=128, unique=True, verbose_name='Name')),
('priority', models.IntegerField(default=50, help_text='1-100, the lower the value will be match first',
validators=[django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(100)],
verbose_name='Priority')),
('action', models.CharField(default='reject', max_length=64, verbose_name='Action')),
('is_active', models.BooleanField(default=True, verbose_name='Active')),
('users', common.db.fields.JSONManyToManyField(default=dict, to='users.User', verbose_name='Users')),
('connect_methods', models.JSONField(default=list, verbose_name='Connect methods')),
(
'reviewers',
models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, verbose_name='Reviewers')),
],
options={
'ordering': ('priority', '-is_active', 'name'),
'abstract': False,
},
),
]

View File

@@ -1,47 +0,0 @@
# Generated by Django 3.2.17 on 2023-06-06 10:57
from django.db import migrations, models
import common.db.fields
def migrate_users_login_acls(apps, schema_editor):
login_acl_model = apps.get_model('acls', 'LoginACL')
name_used = []
login_acls = []
for login_acl in login_acl_model.objects.all().select_related('user'):
name = '{}_{}'.format(login_acl.name, login_acl.user.username)
if name.lower() in name_used:
name += '_{}'.format(str(login_acl.user_id)[:4])
name_used.append(name.lower())
login_acl.name = name
login_acl.users = {
"type": "ids", "ids": [str(login_acl.user_id)]
}
login_acls.append(login_acl)
login_acl_model.objects.bulk_update(login_acls, ['name', 'users'])
class Migration(migrations.Migration):
dependencies = [
('acls', '0015_connectmethodacl'),
]
operations = [
migrations.AddField(
model_name='loginacl',
name='users',
field=common.db.fields.JSONManyToManyField(default=dict, to='users.User', verbose_name='Users'),
),
migrations.RunPython(migrate_users_login_acls),
migrations.RemoveField(
model_name='loginacl',
name='user',
),
migrations.AlterField(
model_name='loginacl',
name='name',
field=models.CharField(max_length=128, unique=True, verbose_name='Name'),
),
]

View File

@@ -1,16 +0,0 @@
# Generated by Django 3.2.19 on 2023-06-13 07:49
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('acls', '0016_auto_20230606_1857'),
]
operations = [
migrations.AlterModelOptions(
name='connectmethodacl',
options={'ordering': ('priority', '-is_active', 'name'), 'verbose_name': 'Connect method acl'},
),
]

View File

@@ -1,18 +0,0 @@
# Generated by Django 4.1.10 on 2023-10-18 10:44
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('acls', '0017_alter_connectmethodacl_options'),
]
operations = [
migrations.AlterField(
model_name='commandfilteracl',
name='command_groups',
field=models.ManyToManyField(related_name='command_filters', to='acls.commandgroup', verbose_name='Command group'),
),
]

View File

@@ -23,7 +23,7 @@ class CommandGroup(JMSOrgBaseModel):
max_length=16, default=TypeChoices.command, choices=TypeChoices.choices,
verbose_name=_("Type")
)
content = models.TextField(verbose_name=_("Content"), help_text=_("One line one command"))
content = models.TextField(verbose_name=_("Content"), help_text=_("One command per line"))
ignore_case = models.BooleanField(default=True, verbose_name=_('Ignore case'))
TypeChoices = TypeChoices

View File

@@ -39,7 +39,7 @@ class UserLoginReminderMsg(UserMessage):
class AssetLoginReminderMsg(UserMessage):
subject = _('Asset login reminder')
subject = _('User login alert for asset')
def __init__(self, user, asset: Asset, login_user: User, account: Account, input_username):
self.asset = asset

View File

@@ -1,13 +1,16 @@
{% load i18n %}
<h3>{% trans 'Respectful' %}: {{ recipient.name }}[{{ recipient.username }}]</h3>
<h3>{% trans 'Dear' %}: {{ recipient.name }}[{{ recipient.username }}]</h3>
<hr>
<p><strong>{% trans 'User' %}:</strong> [{{ name }}({{ username }})]</p>
<p><strong>{% trans 'Assets' %}:</strong> [{{ asset }}]</p>
<p><strong>{% trans 'Account' %}:</strong> [{{ account_name }}({{ account }})]</p>
<p>{% trans 'We would like to inform you that a user has recently logged into the following asset:' %}<p>
<p><strong>{% trans 'Asset details' %}:</strong></p>
<ul>
<li><strong>{% trans 'User' %}:</strong> [{{ name }}({{ username }})]</li>
<li><strong>{% trans 'Assets' %}:</strong> [{{ asset }}]</li>
<li><strong>{% trans 'Account' %}:</strong> [{{ account_name }}({{ account }})]</li>
</ul>
<hr>
<p>{% trans 'The user has just logged in to the asset. Please ensure that this is an authorized operation. If you suspect that this is an unauthorized access, please take appropriate measures immediately.' %}</p>
<p>{% trans 'Thank you' %}</p>
<p>{% trans 'Please review the login activity to ensure the security and proper usage of the asset. If you did not authorize this login or if you notice any suspicious activity, please take the necessary actions immediately.' %}</p>
<p>{% trans 'Thank you for your attention to this matter' %}</p>

View File

@@ -1,14 +1,16 @@
{% load i18n %}
<h3>{% trans 'Respectful' %}: {{ recipient.name }}[{{ recipient.username }}]</h3>
<h3>{% trans 'Dear' %}: {{ recipient.name }}[{{ recipient.username }}]</h3>
<hr>
<p><strong>{% trans 'User' %}:</strong> [{{ username }}]</p>
<p><strong>IP:</strong> [{{ ip }}]</p>
<p><strong>{% trans 'Login city' %}:</strong> [{{ city }}]</p>
<p><strong>{% trans 'User agent' %}:</strong> [{{ user_agent }}]</p>
<p>{% trans 'We would like to inform you that a user has recently logged:' %}<p>
<p><strong>{% trans 'User details' %}:</strong></p>
<ul>
<li><strong>{% trans 'User' %}:</strong> [{{ username }}]</li>
<li><strong>IP:</strong> [{{ ip }}]</li>
<li><strong>{% trans 'Login city' %}:</strong> [{{ city }}]</li>
<li><strong>{% trans 'User agent' %}:</strong> [{{ user_agent }}]</li>
</ul>
<hr>
<p>{% trans 'The user has just successfully logged into the system. Please ensure that this is an authorized operation. If you suspect that this is an unauthorized access, please take appropriate measures immediately.' %}</p>
<p>{% trans 'Thank you' %}</p>
<p>{% trans 'Please review the login activity to ensure the security and proper usage of the asset. If you did not authorize this login or if you notice any suspicious activity, please take the necessary actions immediately.' %}</p>
<p>{% trans 'Thank you for your attention to this matter' %}</p>

View File

@@ -1,12 +0,0 @@
from __future__ import unicode_literals
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class ApplicationsConfig(AppConfig):
name = 'applications'
verbose_name = _('Applications')
def ready(self):
super().ready()

View File

@@ -1,42 +0,0 @@
# Generated by Django 2.1.7 on 2019-05-20 11:04
import common.db.fields
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration):
initial = True
dependencies = [
('assets', '0026_auto_20190325_2035'),
]
operations = [
migrations.CreateModel(
name='RemoteApp',
fields=[
('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('name', models.CharField(max_length=128, verbose_name='Name')),
('type', models.CharField(choices=[('Browser', (('chrome', 'Chrome'),)), ('Database tools', (('mysql_workbench', 'MySQL Workbench'),)), ('Virtualization tools', (('vmware_client', 'vSphere Client'),)), ('custom', 'Custom')], default='chrome', max_length=128, verbose_name='App type')),
('path', models.CharField(max_length=128, verbose_name='App path')),
('params', common.db.fields.EncryptJsonDictTextField(blank=True, default={}, max_length=4096, null=True, verbose_name='Parameters')),
('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')),
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
('comment', models.TextField(blank=True, default='', max_length=128, verbose_name='Comment')),
('asset', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='assets.Asset', verbose_name='Asset')),
('system_user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='assets.SystemUser', verbose_name='System user')),
],
options={
'verbose_name': 'RemoteApp',
'ordering': ('name',),
},
),
migrations.AlterUniqueTogether(
name='remoteapp',
unique_together={('org_id', 'name')},
),
]

View File

@@ -1,18 +0,0 @@
# Generated by Django 2.1.7 on 2019-09-09 09:57
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('applications', '0001_initial'),
('perms', '0009_remoteapppermission_system_users'),
]
operations = [
migrations.RemoveField(
model_name='remoteapp',
name='system_user',
),
]

View File

@@ -1,18 +0,0 @@
# Generated by Django 2.1.11 on 2019-12-10 08:59
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('applications', '0002_remove_remoteapp_system_user'),
]
operations = [
migrations.AlterField(
model_name='remoteapp',
name='type',
field=models.CharField(choices=[('chrome', 'Chrome'), ('mysql_workbench', 'MySQL Workbench'), ('vmware_client', 'vSphere Client'), ('custom', 'Custom')], default='chrome', max_length=128, verbose_name='App type'),
),
]

View File

@@ -1,38 +0,0 @@
# Generated by Django 2.1.11 on 2019-12-18 09:05
from django.db import migrations, models
import uuid
class Migration(migrations.Migration):
dependencies = [
('applications', '0003_auto_20191210_1659'),
]
operations = [
migrations.CreateModel(
name='DatabaseApp',
fields=[
('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')),
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('name', models.CharField(max_length=128, verbose_name='Name')),
('type', models.CharField(choices=[('mysql', 'MySQL')], default='mysql', max_length=128, verbose_name='Type')),
('host', models.CharField(db_index=True, max_length=128, verbose_name='Host')),
('port', models.IntegerField(default=3306, verbose_name='Port')),
('database', models.CharField(blank=True, db_index=True, max_length=128, null=True, verbose_name='Database')),
('comment', models.TextField(blank=True, default='', max_length=128, verbose_name='Comment')),
],
options={
'verbose_name': 'DatabaseApp',
'ordering': ('name',),
},
),
migrations.AlterUniqueTogether(
name='databaseapp',
unique_together={('org_id', 'name')},
),
]

View File

@@ -1,34 +0,0 @@
# Generated by Django 2.2.13 on 2020-08-07 07:13
from django.db import migrations, models
import uuid
class Migration(migrations.Migration):
dependencies = [
('applications', '0004_auto_20191218_1705'),
]
operations = [
migrations.CreateModel(
name='K8sApp',
fields=[
('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')),
('updated_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Updated by')),
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('name', models.CharField(max_length=128, verbose_name='Name')),
('type', models.CharField(choices=[('k8s', 'Kubernetes')], default='k8s', max_length=128, verbose_name='Type')),
('cluster', models.CharField(max_length=1024, verbose_name='Cluster')),
('comment', models.TextField(blank=True, default='', max_length=128, verbose_name='Comment')),
],
options={
'verbose_name': 'KubernetesApp',
'ordering': ('name',),
'unique_together': {('org_id', 'name')},
},
),
]

View File

@@ -1,139 +0,0 @@
# Generated by Django 2.2.13 on 2020-10-19 12:01
from django.db import migrations, models
import django.db.models.deletion
import uuid
CATEGORY_DB_LIST = ['mysql', 'oracle', 'postgresql', 'mariadb']
CATEGORY_REMOTE_LIST = ['chrome', 'mysql_workbench', 'vmware_client', 'custom']
CATEGORY_CLOUD_LIST = ['k8s']
CATEGORY_DB = 'db'
CATEGORY_REMOTE = 'remote_app'
CATEGORY_CLOUD = 'cloud'
CATEGORY_LIST = [CATEGORY_DB, CATEGORY_REMOTE, CATEGORY_CLOUD]
def get_application_category(old_app):
_type = old_app.type
if _type in CATEGORY_DB_LIST:
category = CATEGORY_DB
elif _type in CATEGORY_REMOTE_LIST:
category = CATEGORY_REMOTE
elif _type in CATEGORY_CLOUD_LIST:
category = CATEGORY_CLOUD
else:
category = None
return category
def common_to_application_json(old_app):
category = get_application_category(old_app)
date_updated = old_app.date_updated if hasattr(old_app, 'date_updated') else old_app.date_created
return {
'id': old_app.id,
'name': old_app.name,
'type': old_app.type,
'category': category,
'comment': old_app.comment,
'created_by': old_app.created_by,
'date_created': old_app.date_created,
'date_updated': date_updated,
'org_id': old_app.org_id
}
def db_to_application_json(database):
app_json = common_to_application_json(database)
app_json.update({
'attrs': {
'host': database.host,
'port': database.port,
'database': database.database
}
})
return app_json
def remote_to_application_json(remote):
app_json = common_to_application_json(remote)
attrs = {
'asset': str(remote.asset.id),
'path': remote.path,
}
attrs.update(remote.params)
app_json.update({
'attrs': attrs
})
return app_json
def k8s_to_application_json(k8s):
app_json = common_to_application_json(k8s)
app_json.update({
'attrs': {
'cluster': k8s.cluster
}
})
return app_json
def migrate_and_integrate_applications(apps, schema_editor):
db_alias = schema_editor.connection.alias
database_app_model = apps.get_model("applications", "DatabaseApp")
remote_app_model = apps.get_model("applications", "RemoteApp")
k8s_app_model = apps.get_model("applications", "K8sApp")
database_apps = database_app_model.objects.using(db_alias).all()
remote_apps = remote_app_model.objects.using(db_alias).all()
k8s_apps = k8s_app_model.objects.using(db_alias).all()
database_applications = [db_to_application_json(db_app) for db_app in database_apps]
remote_applications = [remote_to_application_json(remote_app) for remote_app in remote_apps]
k8s_applications = [k8s_to_application_json(k8s_app) for k8s_app in k8s_apps]
applications_json = database_applications + remote_applications + k8s_applications
application_model = apps.get_model("applications", "Application")
applications = [
application_model(**application_json)
for application_json in applications_json
if application_json['category'] in CATEGORY_LIST
]
for application in applications:
if application_model.objects.using(db_alias).filter(name=application.name).exists():
application.name = '{}-{}'.format(application.name, application.type)
application.save()
class Migration(migrations.Migration):
dependencies = [
('assets', '0057_fill_node_value_assets_amount_and_parent_key'),
('applications', '0005_k8sapp'),
]
operations = [
migrations.CreateModel(
name='Application',
fields=[
('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')),
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('name', models.CharField(max_length=128, verbose_name='Name')),
('category', models.CharField(choices=[('db', 'Database'), ('remote_app', 'Remote app'), ('cloud', 'Cloud')], max_length=16, verbose_name='Category')),
('type', models.CharField(choices=[('mysql', 'MySQL'), ('oracle', 'Oracle'), ('postgresql', 'PostgreSQL'), ('mariadb', 'MariaDB'), ('chrome', 'Chrome'), ('mysql_workbench', 'MySQL Workbench'), ('vmware_client', 'vSphere Client'), ('custom', 'Custom'), ('k8s', 'Kubernetes')], max_length=16, verbose_name='Type')),
('attrs', models.JSONField(default=dict)),
('comment', models.TextField(blank=True, default='', max_length=128, verbose_name='Comment')),
('domain', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='applications', to='assets.Domain', verbose_name='Domain')),
],
options={
'ordering': ('name',),
'unique_together': {('org_id', 'name')},
},
),
migrations.RunPython(migrate_and_integrate_applications),
]

View File

@@ -1,18 +0,0 @@
# Generated by Django 3.1 on 2020-11-19 03:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('applications', '0006_application'),
]
operations = [
migrations.AlterField(
model_name='application',
name='attrs',
field=models.JSONField(),
),
]

View File

@@ -1,28 +0,0 @@
# Generated by Django 3.1 on 2021-01-03 20:35
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('perms', '0017_auto_20210104_0435'),
('applications', '0007_auto_20201119_1110'),
]
operations = [
migrations.DeleteModel(
name='DatabaseApp',
),
migrations.DeleteModel(
name='K8sApp',
),
migrations.AlterField(
model_name='application',
name='attrs',
field=models.JSONField(default=dict, verbose_name='Attrs'),
),
migrations.DeleteModel(
name='RemoteApp',
),
]

View File

@@ -1,25 +0,0 @@
# Generated by Django 3.1.6 on 2021-06-23 09:48
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('assets', '0070_auto_20210426_1515'),
('applications', '0008_auto_20210104_0435'),
]
operations = [
migrations.CreateModel(
name='ApplicationUser',
fields=[
],
options={
'proxy': True,
'indexes': [],
'constraints': [],
},
bases=('assets.systemuser',),
),
]

View File

@@ -1,96 +0,0 @@
# Generated by Django 3.1.12 on 2021-08-26 09:07
import uuid
import django.core.validators
import django.db.models.deletion
import simple_history.models
from django.conf import settings
from django.db import migrations, models
import common.db.fields
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('assets', '0076_delete_assetuser'),
('applications', '0009_applicationuser'),
]
operations = [
migrations.CreateModel(
name='HistoricalAccount',
fields=[
('org_id',
models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('id', models.UUIDField(db_index=True, default=uuid.uuid4)),
('name', models.CharField(max_length=128, verbose_name='Name')),
('username', models.CharField(blank=True, db_index=True, max_length=128, validators=[
django.core.validators.RegexValidator('^[0-9a-zA-Z_@\\-\\.]*$', 'Special char not allowed')],
verbose_name='Username')),
('password',
common.db.fields.EncryptCharField(blank=True, max_length=256, null=True, verbose_name='Password')),
('private_key',
common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='SSH private key')),
('public_key', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='SSH public key')),
('comment', models.TextField(blank=True, default='', verbose_name='Comment')),
('date_created', models.DateTimeField(blank=True, editable=False, verbose_name='Date created')),
('date_updated', models.DateTimeField(blank=True, editable=False, verbose_name='Date updated')),
('created_by', models.CharField(max_length=128, null=True, verbose_name='Created by')),
('version', models.IntegerField(default=1, verbose_name='Version')),
('history_id', models.AutoField(primary_key=True, serialize=False)),
('history_date', models.DateTimeField()),
('history_change_reason', models.CharField(max_length=100, null=True)),
('history_type',
models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
('app', models.ForeignKey(blank=True, db_constraint=False, null=True,
on_delete=django.db.models.deletion.DO_NOTHING, related_name='+',
to='applications.application', verbose_name='Database')),
('history_user',
models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+',
to=settings.AUTH_USER_MODEL)),
('systemuser', models.ForeignKey(blank=True, db_constraint=False, null=True,
on_delete=django.db.models.deletion.DO_NOTHING, related_name='+',
to='assets.systemuser', verbose_name='System user')),
],
options={
'verbose_name': 'historical Account',
'ordering': ('-history_date', '-history_id'),
'get_latest_by': 'history_date',
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
migrations.CreateModel(
name='Account',
fields=[
('org_id',
models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('name', models.CharField(max_length=128, verbose_name='Name')),
('username', models.CharField(blank=True, db_index=True, max_length=128, validators=[
django.core.validators.RegexValidator('^[0-9a-zA-Z_@\\-\\.]*$', 'Special char not allowed')],
verbose_name='Username')),
('password',
common.db.fields.EncryptCharField(blank=True, max_length=256, null=True, verbose_name='Password')),
('private_key',
common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='SSH private key')),
('public_key', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='SSH public key')),
('comment', models.TextField(blank=True, default='', verbose_name='Comment')),
('date_created', models.DateTimeField(auto_now_add=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('created_by', models.CharField(max_length=128, null=True, verbose_name='Created by')),
('version', models.IntegerField(default=1, verbose_name='Version')),
('app', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE,
to='applications.application', verbose_name='Database')),
('systemuser',
models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='assets.systemuser',
verbose_name='System user')),
],
options={
'verbose_name': 'Account',
'unique_together': {('username', 'app', 'systemuser')},
},
bases=(models.Model,),
),
]

View File

@@ -1,40 +0,0 @@
# Generated by Django 3.1.12 on 2021-08-26 09:59
from django.db import migrations, transaction
from django.db.models import F
def migrate_app_account(apps, schema_editor):
db_alias = schema_editor.connection.alias
app_perm_model = apps.get_model("perms", "ApplicationPermission")
app_account_model = apps.get_model("applications", 'Account')
queryset = app_perm_model.objects \
.exclude(system_users__isnull=True) \
.exclude(applications__isnull=True) \
.annotate(systemuser=F('system_users')) \
.annotate(app=F('applications')) \
.values('app', 'systemuser', 'org_id')
accounts = []
for p in queryset:
if not p['app']:
continue
account = app_account_model(
app_id=p['app'], systemuser_id=p['systemuser'],
version=1, org_id=p['org_id']
)
accounts.append(account)
app_account_model.objects.using(db_alias).bulk_create(accounts, ignore_conflicts=True)
class Migration(migrations.Migration):
dependencies = [
('applications', '0010_appaccount_historicalappaccount'),
]
operations = [
migrations.RunPython(migrate_app_account)
]

View File

@@ -1,23 +0,0 @@
# Generated by Django 3.1.13 on 2021-10-14 14:09
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('applications', '0011_auto_20210826_1759'),
]
operations = [
migrations.AlterField(
model_name='account',
name='username',
field=models.CharField(blank=True, db_index=True, max_length=128, verbose_name='Username'),
),
migrations.AlterField(
model_name='historicalaccount',
name='username',
field=models.CharField(blank=True, db_index=True, max_length=128, verbose_name='Username'),
),
]

View File

@@ -1,17 +0,0 @@
# Generated by Django 3.1.13 on 2021-10-26 09:11
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('applications', '0012_auto_20211014_2209'),
]
operations = [
migrations.AlterModelOptions(
name='application',
options={'ordering': ('name',), 'verbose_name': 'Application'},
),
]

Some files were not shown because too many files have changed in this diff Show More