├── .gitignore ├── LICENSE ├── README.md ├── connect.py ├── docs └── README.md ├── install ├── developer_doc.txt ├── initial_data.yaml ├── install.py ├── next.py ├── requirements.txt └── zzjumpserver.sh ├── jasset ├── __init__.py ├── admin.py ├── asset_api.py ├── forms.py ├── models.py ├── tests.py ├── urls.py └── views.py ├── jlog ├── __init__.py ├── admin.py ├── log_api.py ├── models.py ├── tests.py ├── urls.py └── views.py ├── jperm ├── README.md ├── __init__.py ├── admin.py ├── ansible_api.py ├── models.py ├── perm_api.py ├── playbooks │ ├── add_init_users │ │ └── add_users.yml │ └── test.yml ├── template_filter.py ├── tests.py ├── urls.py ├── utils.py └── views.py ├── jumpserver.conf ├── jumpserver ├── __init__.py ├── api.py ├── context_processors.py ├── models.py ├── settings.py ├── tasks.py ├── templatetags │ ├── __init__.py │ └── mytags.py ├── urls.py ├── views.py └── wsgi.py ├── juser ├── __init__.py ├── admin.py ├── models.py ├── urls.py ├── user_api.py └── views.py ├── keys └── README.md ├── logs └── README.md ├── manage.py ├── run_websocket.py ├── service.sh ├── static ├── css │ ├── animate.css │ ├── bootstrap.min.css │ ├── colorbox.css │ ├── images │ │ ├── controls.png │ │ └── loading.gif │ ├── magnific │ │ └── magnific-popup.css │ ├── patterns │ │ ├── congruent_pentagon.png │ │ ├── header-profile-skin-1.png │ │ ├── header-profile-skin-2.png │ │ ├── header-profile-skin-3.png │ │ ├── header-profile.png │ │ ├── otis_redding.png │ │ ├── shattered.png │ │ └── triangular.png │ ├── plugins │ │ ├── bootstrap.min.css │ │ ├── chosen │ │ │ ├── chosen-sprite.png │ │ │ ├── chosen-sprite@2x.png │ │ │ └── chosen.css │ │ ├── datepicker │ │ │ └── datepicker3.css │ │ ├── dropzone │ │ │ ├── basic.css │ │ │ └── dropzone.css │ │ ├── fullcalendar │ │ │ ├── fullcalendar.css │ │ │ └── fullcalendar.print.css │ │ ├── iCheck │ │ │ ├── custom.css │ │ │ ├── green.png │ │ │ └── green@2x.png │ │ ├── images │ │ │ ├── bootstrap-colorpicker │ │ │ │ ├── alpha-horizontal.png │ │ │ │ ├── alpha.png │ │ │ │ ├── hue-horizontal.png │ │ │ │ ├── hue.png │ │ │ │ └── saturation.png │ │ │ ├── sort.png │ │ │ ├── sort_asc.png │ │ │ ├── sort_desc.png │ │ │ ├── sprite-skin-flat.png │ │ │ ├── sprite-skin-flat2.png │ │ │ ├── sprite-skin-nice.png │ │ │ ├── sprite-skin-simple.png │ │ │ ├── spritemap.png │ │ │ └── spritemap@2x.png │ │ └── steps │ │ │ └── jquery.steps.css │ ├── style.css │ └── vaildator │ │ ├── images │ │ ├── loading.gif │ │ ├── validator_default.png │ │ └── validator_simple.png │ │ └── jquery.validator.css ├── files │ └── excels │ │ └── asset.xlsx ├── font-awesome │ ├── css │ │ ├── font-awesome.css │ │ └── font-awesome.min.css │ ├── fonts │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ └── fontawesome-webfont.woff │ ├── less │ │ ├── bordered-pulled.less │ │ ├── core.less │ │ ├── fixed-width.less │ │ ├── font-awesome.less │ │ ├── icons.less │ │ ├── larger.less │ │ ├── list.less │ │ ├── mixins.less │ │ ├── path.less │ │ ├── rotated-flipped.less │ │ ├── spinning.less │ │ ├── stacked.less │ │ └── variables.less │ └── scss │ │ ├── _bordered-pulled.scss │ │ ├── _core.scss │ │ ├── _fixed-width.scss │ │ ├── _icons.scss │ │ ├── _larger.scss │ │ ├── _list.scss │ │ ├── _mixins.scss │ │ ├── _path.scss │ │ ├── _rotated-flipped.scss │ │ ├── _spinning.scss │ │ ├── _stacked.scss │ │ ├── _variables.scss │ │ └── font-awesome.scss ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff ├── img │ ├── a1.jpg │ ├── a2.jpg │ ├── a3.jpg │ ├── a4.jpg │ ├── a5.jpg │ ├── a6.jpg │ ├── a7.jpg │ ├── a8.jpg │ ├── admin.bak.png │ ├── admin.png │ ├── angular_logo.png │ ├── email_1.jpg │ ├── email_2.jpg │ ├── email_3.jpg │ ├── facio.ico │ ├── html_logo.png │ ├── logo.png │ ├── mvc_logo.png │ ├── p1.jpg │ ├── p2.jpg │ ├── p3.jpg │ ├── p4.jpg │ ├── p5.jpg │ ├── p6.jpg │ ├── p7.jpg │ ├── p8.jpg │ ├── p_big1.jpg │ ├── p_big2.jpg │ ├── p_big3.jpg │ ├── profile.jpg │ ├── profile_big.jpg │ ├── profile_small.jpg │ ├── root.png │ ├── spritemap.png │ ├── user.png │ └── zender_logo.png └── js │ ├── base.js │ ├── bootstrap-dialog.js │ ├── bootstrap.min.js │ ├── cropper │ └── cropper.min.js │ ├── datapicker │ └── bootstrap-datepicker.js │ ├── demo │ └── peity-demo.js │ ├── dropzone │ └── dropzone.js │ ├── echarts │ ├── chart │ │ ├── bar.js │ │ ├── chord.js │ │ ├── eventRiver.js │ │ ├── force.js │ │ ├── funnel.js │ │ ├── gauge.js │ │ ├── heatmap.js │ │ ├── k.js │ │ ├── line.js │ │ ├── map.js │ │ ├── pie.js │ │ ├── radar.js │ │ ├── scatter.js │ │ ├── tree.js │ │ ├── treemap.js │ │ ├── venn.js │ │ └── wordCloud.js │ ├── echarts-all.js │ └── echarts.js │ ├── highcharts │ ├── adapters │ │ ├── standalone-framework.js │ │ └── standalone-framework.src.js │ ├── highcharts-3d.js │ ├── highcharts-3d.src.js │ ├── highcharts-all.js │ ├── highcharts-more.js │ ├── highcharts-more.src.js │ ├── highcharts.js │ ├── highcharts.src.js │ ├── modules │ │ ├── canvas-tools.js │ │ ├── canvas-tools.src.js │ │ ├── data.js │ │ ├── data.src.js │ │ ├── drilldown.js │ │ ├── drilldown.src.js │ │ ├── exporting.js │ │ ├── exporting.src.js │ │ ├── funnel.js │ │ ├── funnel.src.js │ │ ├── heatmap.js │ │ ├── heatmap.src.js │ │ ├── no-data-to-display.js │ │ ├── no-data-to-display.src.js │ │ ├── solid-gauge.js │ │ └── solid-gauge.src.js │ └── themes │ │ ├── dark-blue.js │ │ ├── dark-green.js │ │ ├── dark-unica.js │ │ ├── gray.js │ │ ├── grid-light.js │ │ ├── grid.js │ │ ├── sand-signika.js │ │ └── skies.js │ ├── inspinia.js │ ├── jquery-2.1.1.js │ ├── jquery-ui-1.10.4.min.js │ ├── jquery-ui.custom.min.js │ ├── jquery.colorbox.js │ ├── jquery.shiftcheckbox.js │ ├── layer │ ├── extend │ │ └── layer.ext.js │ ├── layer.js │ └── skin │ │ ├── default │ │ ├── icon-ext.png │ │ ├── icon.png │ │ ├── loading-0.gif │ │ ├── loading-1.gif │ │ └── loading-2.gif │ │ ├── layer.css │ │ └── layer.ext.css │ ├── magnific │ └── jquery.magnific-popup.min.js │ ├── mindmup-editabletable.js │ ├── plugins │ ├── chosen │ │ └── chosen.jquery.js │ ├── fullcalendar │ │ ├── fullcalendar.min.js │ │ └── moment.min.js │ ├── iCheck │ │ └── icheck.min.js │ ├── metisMenu │ │ └── jquery.metisMenu.js │ ├── pace │ │ └── pace.min.js │ ├── peity │ │ └── jquery.peity.min.js │ ├── slimscroll │ │ ├── jquery.slimscroll.js │ │ └── jquery.slimscroll.min.js │ ├── steps │ │ └── jquery.steps.min.js │ └── validate │ │ └── jquery.validate.min.js │ ├── term.js │ ├── validator │ ├── images │ │ ├── loading.gif │ │ ├── validator_default.png │ │ └── validator_simple.png │ ├── jquery.validator.js │ └── zh_CN.js │ └── wssh.js └── templates ├── 404.html ├── 500.html ├── base.html ├── download.html ├── error.html ├── exec_cmd.html ├── filter_ajax_api.html ├── foot_script.html ├── footer.html ├── head_script.html ├── index.html ├── index_cu.html ├── jasset ├── asset_add.html ├── asset_add_batch.html ├── asset_cu_list.html ├── asset_detail.html ├── asset_edit.html ├── asset_edit_batch.html ├── asset_excel_download.html ├── asset_list.html ├── asset_update_status.html ├── error.html ├── group_add.html ├── group_edit.html ├── group_list.html ├── idc_add.html ├── idc_edit.html ├── idc_list.html ├── show_all_ajax.html └── test.html ├── jlog ├── base.jinja2 ├── dynamic.jinja2 ├── exec_detail.html ├── file_detail.html ├── log_exec.html ├── log_file.html ├── log_offline.html ├── log_online.html ├── log_search.html ├── static.jinja2 ├── user_history.html └── web_terminal.html ├── jperm ├── perm_log.html ├── perm_role_add.html ├── perm_role_detail.html ├── perm_role_edit.html ├── perm_role_list.html ├── perm_role_push.html ├── perm_rule_add.html ├── perm_rule_detail.html ├── perm_rule_edit.html ├── perm_rule_list.html ├── perm_sudo_add.html ├── perm_sudo_edit.html ├── perm_sudo_list.html └── role_sudo.j2 ├── juser ├── change_info.html ├── forget_password.html ├── group_add.html ├── group_detail.html ├── group_edit.html ├── group_list.html ├── profile.html ├── reset_password.html ├── run_command.html ├── user_add.html ├── user_detail.html ├── user_edit.html └── user_list.html ├── link_css.html ├── log_watch.html ├── login.html ├── nav.html ├── nav_bar_header.html ├── nav_cat_bar.html ├── nav_li_profile.html ├── paginator.html ├── setting.html ├── skin_config.html ├── success.html └── upload.html /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | .idea 3 | test.py 4 | .DS_Store 5 | db.sqlite3 6 | # C extensions 7 | *.so 8 | 9 | # Packages 10 | *.egg 11 | *.egg-info 12 | dist 13 | build 14 | eggs 15 | parts 16 | bin 17 | var 18 | sdist 19 | develop-eggs 20 | .installed.cfg 21 | lib 22 | lib64 23 | __pycache__ 24 | 25 | # Installer logs 26 | pip-log.txt 27 | 28 | # Unit test / coverage reports 29 | .coverage 30 | .tox 31 | nosetests.xml 32 | 33 | # Translations 34 | *.mo 35 | 36 | # Mr Developer 37 | .mr.developer.cfg 38 | .project 39 | .pydevproject 40 | .settings 41 | *.log 42 | logs/* 43 | keys/* 44 | jumpserver.conf 45 | nohup.out 46 | tmp/* 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### 项目已迁移到 https://github.com/jumpserver/jumpserver 组织项目中,本仓库从今天起不再更新 2 | ### 已下载安装的项目请更改配置文件,使用新仓库更新 3 | 4 | > cd /opt/jumpserver/.git 5 | > 6 | > vim config 7 | > 8 | >[remote "origin"] 9 | > 10 | > fetch = +refs/heads/*:refs/remotes/origin/* 11 | > 12 | > url = https://github.com/jumpserver/jumpserver.git 13 | > 14 | 15 | 16 | ## 写在前面 17 | - 目前本版本处于beta阶段,请不要用于生产环境,除非你知道你在做什么 18 | - 本版本暂时没加入LDAP接口,稳定版会将LDAP和无Agent方式抽象成API,2.x版本支持LDAP,请移步release中下载 19 | 20 | #欢迎使用Jumpserver 21 | **Jumpserver** 是一款由python编写开源的跳板机(堡垒机)系统,实现了跳板机应有的功能。基于ssh协议来管理,客户端无需安装agent。 22 | 支持常见系统: 23 | 1. redhat centos 24 | 2. debian 25 | 3. suse ubuntu 26 | 4. freebsd 27 | 5. 其他ssh协议硬件设备 28 | 29 | ###截图: 30 | 31 | 首页 32 | 33 | ![webterminal](https://github.com/ibuler/static/raw/master/jumpserver3/index.jpg) 34 | 35 | WebTerminal: 36 | 37 | ![webterminal](https://github.com/ibuler/static/raw/master/jumpserver3/webTerminal.gif) 38 | 39 | Web批量执行命令 40 | 41 | ![WebExecCommand](https://github.com/ibuler/static/raw/master/jumpserver3/webExec.gif) 42 | 43 | 录像回放 44 | 45 | ![录像](https://github.com/ibuler/static/raw/master/jumpserver3/record.gif) 46 | 47 | 跳转和批量命令 48 | 49 | ![跳转](https://github.com/ibuler/static/raw/master/jumpserver3/connect.gif) 50 | 51 | 命令统计 52 | 53 | ![跳转](https://github.com/ibuler/static/raw/master/jumpserver3/command.jpg) 54 | 55 | ### 文档 56 | 57 | * [访问wiki](https://github.com/ibuler/jumpserver/wiki) 58 | * [快速安装](https://github.com/ibuler/jumpserver/wiki/Quickinstall) 59 | * [名词解释](https://github.com/ibuler/jumpserver/wiki/Termexplain) 60 | * [快速开始](https://github.com/ibuler/jumpserver/wiki/Quickstart) 61 | * [FAQ](https://github.com/ibuler/jumpserver/wiki/FAQs) 62 | 63 | ### 特点 64 | 65 | * 完全开源,GPL授权 66 | * Python编写,容易再次开发 67 | * 实现了跳板机基本功能,认证、授权、审计 68 | * 集成了Ansible,批量命令等 69 | * 支持WebTerminal 70 | * Bootstrap编写,界面美观 71 | * 自动收集硬件信息 72 | * 录像回放 73 | * 命令搜索 74 | * 实时监控 75 | * 批量上传下载 76 | 77 | ### 其它 78 | 79 | [Jumpserver官网](http://www.jumpserver.org) 80 | 81 | [论坛](http://bbs.jumpserver.org) 82 | 83 | [demo站点](http://demo.jumpserver.org) 84 | 85 | 交流群: 399218702 86 | 87 | ### 团队 88 | 89 | ![](https://github.com/ibuler/static/raw/master/jumpserver3/team.jpg) 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | 快速安装 2 | ------ 3 | ####环境 4 | CentOS 6.x x86_64 5 | iptables stop 6 | selinux disable 7 | 8 | 9 | ####开始 10 | **1. 安装git** 11 | 12 | > yum -y install git 13 | 14 | **2. 下载jumpserver** 15 | 16 | > git clone https://github.com/ibuler/jumpserver.git 17 | 18 | **3. 执行快速安装脚本** 19 | 20 | > cd jumpserver/install && python install.py 21 | 22 | 23 | *根据提示输入相关信息,完成安装,完成安装后,请访问web,继续查看后续文档* 24 | 25 | 26 | 27 | 名词解释 28 | ------ 29 | 30 | 31 | * **用户** 用户是授权和登陆的主体,将来为每个员工建立一个账户,用来登录跳板机, 32 | 将资产授权给该用户,查看用户登陆记录命令历史等 33 | 34 | * **用户组** 多个用户可以组合成用户组,为了方便进行授权,可以将一个部门或几个用户 35 | 组建成用户组,在授权中使用组授权,该组中的用户拥有所有授权的主机权限 36 | 37 | * **资产** 资产通常是我们的服务器、网络设备等,将资产授权给用户,用户则会有权限登 38 | 录资产,执行命令等 39 | 40 | * **管理账户** 添加资产时需要添加一个管理账户,该账户是该资产上已有的有管理权限的用户, 41 | 如root,或者有 NOPASSWD: ALL sudo权限的用户,该管理账户用来向资产推送系统用户, 42 | 为系统用户添加sudo,获取资产的一些硬件信息 43 | 44 | * **资产组** 同用户组,是资产组成的集合,为了方便授权 45 | 46 | * **机房** 又称IDC,不解释 47 | 48 | * **Sudo** 这里的sudo其实是Linux中的sudo命令别名,一个sudo别名包含多个命令, 49 | 系统用户关联sudo就代表该系统用户有权限sudo执行这些命令 50 | 51 | * **系统用户** 系统用户是服务器上建立的一些真实存在的可以ssh登陆的用户,如 dev, 52 | sa, dba等,系统用户可使用jumpserver推送到服务器上,也可以利用自己公司 53 | 的工具进行推送,授权时将用户、资产、系统用户关联起来则表明用户有权限登陆该资产的 54 | 这个系统用户 如:用户 **小明** 以 **dev** 系统用户登陆 **172.16.1.1**资产 55 | 56 | * **授权规则** 授权规则是将 **资产** **系统用户** 和 **用户** 关联起来,用来完成授权。 57 | 这样用户就可以以某个系统用户账号登陆资产 58 | 59 | * **日志审计** 60 | * **在线** 查看当前在线的用户(非web在线),可以监控用户的命令执行,强制结束用户 61 | 登录。 62 | * **登录历史** 查看以往用户的登录历史,可以查看用户登陆操作的命令,可以回放用户 63 | 执行命令的录像 64 | * **命令记录** 查看用户批量执行命令的历史,包含执行命令的主机,执行的命令,执行的结果 65 | 66 | * **上传下载** 查看用户上传下载文件的记录 67 | 68 | 69 | 快速开始 70 | ------ 71 | 72 | ##### 1. 添加用户 73 | **用户管理 - 查看用户 - 添加用户** 填写基本信息,完成用户添加 74 | 75 | 用户添加完成后,根据提示记住用户账号密码,换个浏览器登录下载key, 76 | ssh登录jumpserver测试 77 | 78 | ##### 2. 添加资产 79 | **资产管理 - 查看资产 - 添加资产** 填写基本信息,完成资产添加 80 | 81 | ##### 3. 添加sudo 82 | **授权管理 - Sudo - 添加别名** 输入别名名称和命令,完成sudo添加 83 | 84 | ##### 4. 添加系统用户 85 | **授权管理 - 系统用户 - 添加** 输入基本信息,完成系统用户添加 86 | 87 | ##### 5. 推送系统用户 88 | **授权管理 - 推送** - 选择需要推送的资产或资产组完成推送 89 | 90 | 推送只支持服务器,使用密钥是指用户从跳板机跳转时使用key,反之使用密码, 91 | 授权时会检查推送记录,如果没有推送过则无法完成系统用户在该资产上的授权。 92 | 如果资产时网络设备,请不要选择密码和秘钥,模拟一下推送,目的是为了生成 93 | 推送记录。 94 | 95 | ##### 6. 添加授权规则 96 | **授权管理 - 授权规则 - 添加规则** 选择刚才添加的用户,资产,系统用户完成授权 97 | 98 | ##### 7. 测试登录 99 | **用户下载key** 登录跳板机,会自动运行connect.py,根据提示登录服务器 100 | 101 | **用户登陆web** 查看授权的主机,点击后面的链接,测试是否可以登录服务器 102 | 103 | ##### 8. 监控和结束会话 104 | **日志审计 - 在线** 查看当前登录的用户登录情况,点击监控查看用户执行的命令, 105 | 点击阻断,结束用户的会话 106 | 107 | ##### 9. 查看历史记录 108 | **日志审计 - 登录历史** 查看登录历史,点击统计查看命令历史,点击回放查看录像 109 | 110 | ##### 10. 执行命令 111 | 同7 测试命令的执行,命令记录查看 批量执行命令的日志 112 | 113 | ##### 11. 上传下载 114 | 同7 测试文件的上传下载,日志审计 - 上传下载 查看上传下载记录 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /install/developer_doc.txt: -------------------------------------------------------------------------------- 1 | # coding: utf8 2 | 3 | Jumpserver开发者文档 4 | 5 | 开发规范: 6 | 1. 遵守PE8规范 1) 命名规范 2) 导入模块规范 3) 空行规范 4) 长度规范 7 | 2. 缩进统一4个空格 8 | 3. 变量命名明了易懂多个单词下划线隔开 9 | 4. 注释到位 10 | 11 | 12 | 框架说明: 13 | 1. 项目名称 Jumpserver 14 | 2. APP: 15 | juser 用户管理 16 | jasset 资产管理(设备管理) 17 | jpermission 授权管理 18 | jlog 日志管理 19 | 3. connect.py 用户登录入口程序 20 | 4. logs 日志保存目录 21 | 5. jumpserver.conf 配置文件 22 | 6. docs 文档目录 23 | 7. static 静态文件目录 24 | 8. templates 模板目录 25 | 26 | 27 | connect.py逻辑说明: 28 | 用户登录系统,运行该脚本,p调用get_user_host函数查看有权限的服务器ip 29 | 输入部分IP,verify_connect匹配该部分ip,如果是匹配到多个,就显示ip 30 | 匹配到0了就显示没有权限或者主机, 31 | 匹配到1个则继续 32 | 查询该服务器是否支持ldap 如果是,获得ldap用户密码登陆 33 | 如果否,查询授权表,查看该服务器授权的系统用户,并返回对应账号密码,登陆 34 | connect函数是登陆函数,采用paramiko 使用channel登陆,posix_shell 来完成交互,并记录日志 35 | signal模块来完成窗口改变导致的tty大小随之改变 36 | PyCrypt是对称加密类 -------------------------------------------------------------------------------- /install/initial_data.yaml: -------------------------------------------------------------------------------- 1 | - model: juser.user 2 | pk: 5000 3 | fields: 4 | username: admin 5 | name: admin 6 | password: pbkdf2_sha256$20000$jBIDGPB2j5JT$orxqGgzzjzykColYm1BswPjgHOiERjZkcgkuVIkD2Hc= 7 | email: admin@jumpserver.org 8 | role: SU 9 | is_active: 1 10 | -------------------------------------------------------------------------------- /install/next.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding: utf-8 3 | 4 | import sys 5 | import os 6 | import django 7 | from django.core.management import execute_from_command_line 8 | import shutil 9 | import urllib 10 | import socket 11 | 12 | jms_dir = os.path.dirname(os.path.abspath(os.path.dirname(__file__))) 13 | sys.path.append(jms_dir) 14 | 15 | os.environ['DJANGO_SETTINGS_MODULE'] = 'jumpserver.settings' 16 | if django.get_version() != '1.6': 17 | setup = django.setup() 18 | 19 | from juser.user_api import db_add_user, get_object, User 20 | from install import color_print 21 | from jumpserver.api import get_mac_address, bash 22 | 23 | socket.setdefaulttimeout(2) 24 | 25 | 26 | class Setup(object): 27 | """ 28 | 安装jumpserver向导 29 | """ 30 | 31 | def __init__(self): 32 | self.admin_user = 'admin' 33 | self.admin_pass = '5Lov@wife' 34 | 35 | @staticmethod 36 | def _pull(): 37 | color_print('开始更新jumpserver', 'green') 38 | # bash('git pull') 39 | try: 40 | mac = get_mac_address() 41 | version = urllib.urlopen('http://jumpserver.org/version/?id=%s' % mac) 42 | except: 43 | pass 44 | os.chdir(jms_dir) 45 | os.chmod('logs', 0777) 46 | os.chmod('keys', 0777) 47 | 48 | def _input_admin(self): 49 | while True: 50 | print 51 | admin_user = raw_input('请输入管理员用户名 [%s]: ' % self.admin_user).strip() 52 | admin_pass = raw_input('请输入管理员密码: [%s]: ' % self.admin_pass).strip() 53 | admin_pass_again = raw_input('请再次输入管理员密码: [%s]: ' % self.admin_pass).strip() 54 | 55 | if admin_user: 56 | self.admin_user = admin_user 57 | 58 | if not admin_pass_again: 59 | admin_pass_again = self.admin_pass 60 | 61 | if admin_pass: 62 | self.admin_pass = admin_pass 63 | 64 | if self.admin_pass != admin_pass_again: 65 | color_print('两次密码不相同请重新输入') 66 | else: 67 | break 68 | print 69 | 70 | @staticmethod 71 | def _sync_db(): 72 | os.chdir(jms_dir) 73 | execute_from_command_line(['manage.py', 'syncdb', '--noinput']) 74 | 75 | def _create_admin(self): 76 | user = get_object(User, username=self.admin_user) 77 | if user: 78 | user.delete() 79 | db_add_user(username=self.admin_user, password=self.admin_pass, role='SU', name='admin', groups='', 80 | admin_groups='', email='admin@jumpserver.org', uuid='MayBeYouAreTheFirstUser', is_active=True) 81 | os.system('id %s &> /dev/null || useradd %s' % (self.admin_user, self.admin_user)) 82 | 83 | @staticmethod 84 | def _cp_zzsh(): 85 | os.chdir(os.path.join(jms_dir, 'install')) 86 | shutil.copy('zzjumpserver.sh', '/etc/profile.d/') 87 | bash("sed -i 's#/opt/jumpserver#%s#g' /etc/profile.d/zzjumpserver.sh" % jms_dir) 88 | 89 | @staticmethod 90 | def _run_service(): 91 | os.system('sh %s start' % os.path.join(jms_dir, 'service.sh')) 92 | print 93 | color_print('安装成功,请访问web, 祝你使用愉快。\n请访问 https://github.com/ibuler/jumpserver 查看文档', 'green') 94 | 95 | def start(self): 96 | print "开始安装Jumpserver, 要求环境为 CentOS 6.5 x86_64" 97 | self._pull() 98 | self._sync_db() 99 | self._input_admin() 100 | self._create_admin() 101 | self._cp_zzsh() 102 | self._run_service() 103 | 104 | 105 | if __name__ == '__main__': 106 | setup = Setup() 107 | setup.start() 108 | -------------------------------------------------------------------------------- /install/requirements.txt: -------------------------------------------------------------------------------- 1 | #sphinx-me==0.3 2 | django==1.6 3 | pycrypto==2.6.1 4 | paramiko==1.16.0 5 | ecdsa==0.13 6 | MySQL-python==1.2.5 7 | #django-uuidfield==0.5.0 8 | psutil==3.3.0 9 | xlsxwriter==0.7.7 10 | xlrd==0.9.4 11 | django-bootstrap-form==3.2 12 | tornado==4.3 13 | ansible==1.9.4 14 | pyinotify==0.9.6 15 | passlib==1.6.5 16 | argparse==1.4.0 17 | django_crontab==0.6.0 -------------------------------------------------------------------------------- /install/zzjumpserver.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export LANG='zh_CN.UTF-8' 4 | 5 | if [ "$USER" != "admin" ] && [ "$USER" != "root" ];then 6 | python /opt/jumpserver/connect.py 7 | if [ $USER == 'guanghongwei' ];then 8 | echo 9 | else 10 | exit 3 11 | echo 12 | fi 13 | fi 14 | -------------------------------------------------------------------------------- /jasset/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/jasset/__init__.py -------------------------------------------------------------------------------- /jasset/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /jasset/forms.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | from django import forms 3 | 4 | from jasset.models import IDC, Asset, AssetGroup 5 | 6 | 7 | class AssetForm(forms.ModelForm): 8 | 9 | class Meta: 10 | model = Asset 11 | 12 | fields = [ 13 | "ip", "other_ip", "hostname", "port", "group", "username", "password", "use_default_auth", 14 | "idc", "mac", "remote_ip", "brand", "cpu", "memory", "disk", "system_type", "system_version", 15 | "cabinet", "position", "number", "status", "asset_type", "env", "sn", "is_active", "comment", 16 | "system_arch" 17 | ] 18 | 19 | 20 | class AssetGroupForm(forms.ModelForm): 21 | class Meta: 22 | model = AssetGroup 23 | fields = [ 24 | "name", "comment" 25 | ] 26 | 27 | 28 | class IdcForm(forms.ModelForm): 29 | class Meta: 30 | model = IDC 31 | fields = ['name', "bandwidth", "operator", 'linkman', 'phone', 'address', 'network', 'comment'] 32 | widgets = { 33 | 'name': forms.TextInput(attrs={'placeholder': 'Name'}), 34 | 'network': forms.Textarea( 35 | attrs={'placeholder': '192.168.1.0/24\n192.168.2.0/24'}) 36 | } 37 | 38 | 39 | -------------------------------------------------------------------------------- /jasset/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /jasset/urls.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | from django.conf.urls import patterns, include, url 3 | from jasset.views import * 4 | 5 | urlpatterns = patterns('', 6 | url(r'^asset/add/$', asset_add, name='asset_add'), 7 | url(r"^asset/add_batch/$", asset_add_batch, name='asset_add_batch'), 8 | url(r'^asset/list/$', asset_list, name='asset_list'), 9 | url(r'^asset/del/$', asset_del, name='asset_del'), 10 | url(r"^asset/detail/$", asset_detail, name='asset_detail'), 11 | url(r'^asset/edit/$', asset_edit, name='asset_edit'), 12 | url(r'^asset/edit_batch/$', asset_edit_batch, name='asset_edit_batch'), 13 | url(r'^asset/update/$', asset_update, name='asset_update'), 14 | url(r'^asset/update_batch/$', asset_update_batch, name='asset_update_batch'), 15 | url(r'^asset/upload/$', asset_upload, name='asset_upload'), 16 | url(r'^group/del/$', group_del, name='asset_group_del'), 17 | url(r'^group/add/$', group_add, name='asset_group_add'), 18 | url(r'^group/list/$', group_list, name='asset_group_list'), 19 | url(r'^group/edit/$', group_edit, name='asset_group_edit'), 20 | url(r'^idc/add/$', idc_add, name='idc_add'), 21 | url(r'^idc/list/$', idc_list, name='idc_list'), 22 | url(r'^idc/edit/$', idc_edit, name='idc_edit'), 23 | url(r'^idc/del/$', idc_del, name='idc_del'), 24 | ) -------------------------------------------------------------------------------- /jlog/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/jlog/__init__.py -------------------------------------------------------------------------------- /jlog/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /jlog/log_api.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | 4 | from argparse import ArgumentParser, FileType 5 | from contextlib import closing 6 | from io import open as copen 7 | from json import dumps 8 | from math import ceil 9 | import datetime 10 | import time 11 | import re 12 | import os 13 | from os.path import basename, dirname, exists, join 14 | from struct import unpack 15 | from subprocess import Popen 16 | from sys import platform, prefix, stderr 17 | from tempfile import NamedTemporaryFile 18 | 19 | from jinja2 import FileSystemLoader, Template 20 | from jinja2.environment import Environment 21 | 22 | from jumpserver.api import BASE_DIR 23 | from jlog.models import Log 24 | 25 | 26 | DEFAULT_TEMPLATE = join(BASE_DIR, 'templates', 'jlog', 'static.jinja2') 27 | rz_pat = re.compile(r'\x18B\w+\r\x8a(\x11)?') 28 | 29 | 30 | def escapeString(string): 31 | string = rz_pat.sub('', string) 32 | try: 33 | string = string.encode('unicode_escape').decode('utf-8', 'ignore') 34 | except (UnicodeEncodeError, UnicodeDecodeError): 35 | string = string.decode('utf-8', 'ignore') 36 | string = string.replace("'", "\\'") 37 | string = '\'' + string + '\'' 38 | return string 39 | 40 | 41 | def getTiming(timef): 42 | timing = None 43 | with closing(timef): 44 | timing = [l.strip().split(' ') for l in timef] 45 | timing = [(int(ceil(float(r[0]) * 1000)), int(r[1])) for r in timing] 46 | return timing 47 | 48 | 49 | def scriptToJSON(scriptf, timing=None): 50 | ret = [] 51 | 52 | with closing(scriptf): 53 | scriptf.readline() # ignore first header line from script file 54 | offset = 0 55 | for t in timing: 56 | dt = scriptf.read(t[1]) 57 | data = escapeString(dt) 58 | # print ('###### (%s, %s)' % (t[1], repr(data))) 59 | offset += t[0] 60 | ret.append((data, offset)) 61 | return dumps(ret) 62 | 63 | 64 | def renderTemplate(script_path, time_file_path, dimensions=(24, 80), templatename=DEFAULT_TEMPLATE): 65 | with copen(script_path, encoding='utf-8', errors='replace', newline='\r\n') as scriptf: 66 | # with open(script_path) as scriptf: 67 | with open(time_file_path) as timef: 68 | timing = getTiming(timef) 69 | json = scriptToJSON(scriptf, timing) 70 | 71 | fsl = FileSystemLoader(dirname(templatename), 'utf-8') 72 | e = Environment() 73 | e.loader = fsl 74 | 75 | templatename = basename(templatename) 76 | rendered = e.get_template(templatename).render(json=json, 77 | dimensions=dimensions) 78 | 79 | return rendered 80 | 81 | 82 | def kill_invalid_connection(): 83 | long_time_logs = [] 84 | unfinished_logs = Log.objects.filter(is_finished=False) 85 | now = datetime.datetime.now() 86 | now_timestamp = int(time.mktime(now.timetuple())) 87 | for log in unfinished_logs: 88 | if (now - log.start_time).days > 1: 89 | long_time_logs.append(log) 90 | 91 | for log in long_time_logs: 92 | try: 93 | log_file_mtime = int(os.stat(log.log_path).st_mtime) 94 | except OSError: 95 | log_file_mtime = 0 96 | 97 | if (now_timestamp - log_file_mtime) > 3600: 98 | try: 99 | os.kill(int(log.pid), 9) 100 | except OSError: 101 | pass 102 | 103 | log.is_finished = True 104 | log.end_time = now 105 | log.save() 106 | 107 | -------------------------------------------------------------------------------- /jlog/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | 4 | class Log(models.Model): 5 | user = models.CharField(max_length=20, null=True) 6 | host = models.CharField(max_length=200, null=True) 7 | remote_ip = models.CharField(max_length=100) 8 | login_type = models.CharField(max_length=100) 9 | log_path = models.CharField(max_length=100) 10 | start_time = models.DateTimeField(null=True) 11 | pid = models.IntegerField() 12 | is_finished = models.BooleanField(default=False) 13 | end_time = models.DateTimeField(null=True) 14 | 15 | def __unicode__(self): 16 | return self.log_path 17 | 18 | 19 | class Alert(models.Model): 20 | msg = models.CharField(max_length=20) 21 | time = models.DateTimeField(null=True) 22 | is_finished = models.BigIntegerField(default=False) 23 | 24 | 25 | class TtyLog(models.Model): 26 | log = models.ForeignKey(Log) 27 | datetime = models.DateTimeField(auto_now=True) 28 | cmd = models.CharField(max_length=200) 29 | 30 | 31 | class ExecLog(models.Model): 32 | user = models.CharField(max_length=100) 33 | host = models.TextField() 34 | cmd = models.TextField() 35 | remote_ip = models.CharField(max_length=100) 36 | result = models.TextField(default='') 37 | datetime = models.DateTimeField(auto_now=True) 38 | 39 | 40 | class FileLog(models.Model): 41 | user = models.CharField(max_length=100) 42 | host = models.TextField() 43 | filename = models.TextField() 44 | type = models.CharField(max_length=20) 45 | remote_ip = models.CharField(max_length=100) 46 | result = models.TextField(default='') 47 | datetime = models.DateTimeField(auto_now=True) 48 | 49 | 50 | -------------------------------------------------------------------------------- /jlog/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /jlog/urls.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | from django.conf.urls import patterns, include, url 3 | from jlog.views import * 4 | 5 | urlpatterns = patterns('', 6 | url(r'^list/(\w+)/$', log_list, name='log_list'), 7 | url(r'^detail/(\w+)/$', log_detail, name='log_detail'), 8 | url(r'^history/$', log_history, name='log_history'), 9 | url(r'^log_kill/', log_kill, name='log_kill'), 10 | url(r'^record/$', log_record, name='log_record'), 11 | ) -------------------------------------------------------------------------------- /jperm/README.md: -------------------------------------------------------------------------------- 1 | # Jperm App 2 | 3 | --- 4 | 5 | ### 模块 ansible_api 6 | 7 | > 使用说明 8 | 9 | + 依赖rpm安装包: ansible、 sshpass 10 | + 依赖pip安装包: passlib 11 | + 关于ansible配置: 需要启用配置文件(/etc/ansible/ansible.cfg)的 host_key_checking = False 12 | 13 | -------------------------------------------------------------------------------- /jperm/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/jperm/__init__.py -------------------------------------------------------------------------------- /jperm/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /jperm/models.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | from django.db import models 4 | from jasset.models import Asset, AssetGroup 5 | from juser.models import User, UserGroup 6 | 7 | 8 | class PermLog(models.Model): 9 | datetime = models.DateTimeField(auto_now_add=True) 10 | action = models.CharField(max_length=100, null=True, blank=True, default='') 11 | results = models.CharField(max_length=1000, null=True, blank=True, default='') 12 | is_success = models.BooleanField(default=False) 13 | is_finish = models.BooleanField(default=False) 14 | 15 | 16 | class PermSudo(models.Model): 17 | name = models.CharField(max_length=100, unique=True) 18 | date_added = models.DateTimeField(auto_now=True) 19 | commands = models.TextField() 20 | comment = models.CharField(max_length=100, null=True, blank=True, default='') 21 | 22 | def __unicode__(self): 23 | return self.name 24 | 25 | 26 | class PermRole(models.Model): 27 | name = models.CharField(max_length=100, unique=True) 28 | comment = models.CharField(max_length=100, null=True, blank=True, default='') 29 | password = models.CharField(max_length=100) 30 | key_path = models.CharField(max_length=100) 31 | date_added = models.DateTimeField(auto_now=True) 32 | sudo = models.ManyToManyField(PermSudo, related_name='perm_role') 33 | 34 | def __unicode__(self): 35 | return self.name 36 | 37 | 38 | class PermRule(models.Model): 39 | date_added = models.DateTimeField(auto_now=True) 40 | name = models.CharField(max_length=100, unique=True) 41 | comment = models.CharField(max_length=100) 42 | asset = models.ManyToManyField(Asset, related_name='perm_rule') 43 | asset_group = models.ManyToManyField(AssetGroup, related_name='perm_rule') 44 | user = models.ManyToManyField(User, related_name='perm_rule') 45 | user_group = models.ManyToManyField(UserGroup, related_name='perm_rule') 46 | role = models.ManyToManyField(PermRole, related_name='perm_rule') 47 | 48 | def __unicode__(self): 49 | return self.name 50 | 51 | 52 | class PermPush(models.Model): 53 | asset = models.ForeignKey(Asset, related_name='perm_push') 54 | role = models.ForeignKey(PermRole, related_name='perm_push') 55 | is_public_key = models.BooleanField(default=False) 56 | is_password = models.BooleanField(default=False) 57 | success = models.BooleanField(default=False) 58 | result = models.TextField(default='') 59 | date_added = models.DateTimeField(auto_now=True) 60 | 61 | -------------------------------------------------------------------------------- /jperm/playbooks/add_init_users/add_users.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: 'add_users_group' 4 | gather_facts: no 5 | tasks: 6 | - name: add SA user 7 | command: uname -a 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /jperm/playbooks/test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: test 4 | gather_facts: no 5 | tasks: 6 | - name: just for test 7 | command: uname -a 8 | 9 | 10 | -------------------------------------------------------------------------------- /jperm/template_filter.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/jperm/template_filter.py -------------------------------------------------------------------------------- /jperm/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /jperm/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, include, url 2 | from jperm.views import * 3 | 4 | urlpatterns = patterns('jperm.views', 5 | url(r'^rule/list/$', perm_rule_list, name='rule_list'), 6 | url(r'^rule/add/$', perm_rule_add, name='rule_add'), 7 | url(r'^rule/detail/$', perm_rule_detail, name='rule_detail'), 8 | url(r'^rule/edit/$', perm_rule_edit, name='rule_edit'), 9 | url(r'^rule/del/$', perm_rule_delete, name='rule_del'), 10 | url(r'^role/list/$', perm_role_list, name='role_list'), 11 | url(r'^role/add/$', perm_role_add, name='role_add'), 12 | url(r'^role/del/$', perm_role_delete, name='role_del'), 13 | url(r'^role/detail/$', perm_role_detail, name='role_detail'), 14 | url(r'^role/edit/$', perm_role_edit, name='role_edit'), 15 | url(r'^role/push/$', perm_role_push, name='role_push'), 16 | url(r'^role/recycle/$', perm_role_recycle, name='role_recycle'), 17 | url(r'^role/get/$', perm_role_get, name='role_get'), 18 | url(r'^sudo/list/$', perm_sudo_list, name='sudo_list'), 19 | url(r'^sudo/add/$', perm_sudo_add, name='sudo_add'), 20 | url(r'^sudo/del/$', perm_sudo_delete, name='sudo_del'), 21 | url(r'^sudo/edit/$', perm_sudo_edit, name='sudo_edit'), 22 | ) 23 | -------------------------------------------------------------------------------- /jperm/utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import os.path 4 | import shutil 5 | from paramiko import SSHException 6 | from paramiko.rsakey import RSAKey 7 | from jumpserver.api import mkdir 8 | from uuid import uuid4 9 | from jumpserver.api import CRYPTOR 10 | 11 | from jumpserver.api import logger 12 | 13 | 14 | from jumpserver.settings import KEY_DIR 15 | 16 | 17 | def get_rand_pass(): 18 | """ 19 | get a reandom password. 20 | """ 21 | CRYPTOR.gen_rand_pass(20) 22 | 23 | 24 | def updates_dict(*args): 25 | """ 26 | surport update multi dict 27 | """ 28 | result = {} 29 | for d in args: 30 | result.update(d) 31 | return result 32 | 33 | 34 | def gen_keys(key="", key_path_dir=""): 35 | """ 36 | 在KEY_DIR下创建一个 uuid命名的目录, 37 | 并且在该目录下 生产一对秘钥 38 | :return: 返回目录名(uuid) 39 | """ 40 | key_basename = "key-" + uuid4().hex 41 | if not key_path_dir: 42 | key_path_dir = os.path.join(KEY_DIR, 'role_key', key_basename) 43 | private_key = os.path.join(key_path_dir, 'id_rsa') 44 | public_key = os.path.join(key_path_dir, 'id_rsa.pub') 45 | mkdir(key_path_dir, mode=0755) 46 | if not key: 47 | key = RSAKey.generate(2048) 48 | key.write_private_key_file(private_key) 49 | else: 50 | key_file = os.path.join(key_path_dir, 'id_rsa') 51 | with open(key_file, 'w') as f: 52 | f.write(key) 53 | f.close() 54 | with open(key_file) as f: 55 | try: 56 | key = RSAKey.from_private_key(f) 57 | except SSHException, e: 58 | shutil.rmtree(key_path_dir, ignore_errors=True) 59 | raise SSHException(e) 60 | os.chmod(private_key, 0644) 61 | 62 | with open(public_key, 'w') as content_file: 63 | for data in [key.get_name(), 64 | " ", 65 | key.get_base64(), 66 | " %s@%s" % ("jumpserver", os.uname()[1])]: 67 | content_file.write(data) 68 | return key_path_dir 69 | 70 | 71 | if __name__ == "__main__": 72 | print gen_keys() 73 | 74 | 75 | -------------------------------------------------------------------------------- /jumpserver.conf: -------------------------------------------------------------------------------- 1 | [base] 2 | url = http://192.168.244.129 3 | key = 88aaaf7ffe3c6c04 4 | log = debug 5 | 6 | [db] 7 | host = 127.0.0.1 8 | port = 3306 9 | user = jumpserver 10 | password = mysql234 11 | database = jumpserver 12 | 13 | [websocket] 14 | web_socket_host = 192.168.244.129:3000 15 | 16 | [mail] 17 | mail_enable = 1 18 | email_host = smtp.qq.com 19 | email_port = 25 20 | email_host_user = xxxxxxxx@qq.com 21 | email_host_password = xxxxxx 22 | email_use_tls = False 23 | 24 | -------------------------------------------------------------------------------- /jumpserver/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/jumpserver/__init__.py -------------------------------------------------------------------------------- /jumpserver/context_processors.py: -------------------------------------------------------------------------------- 1 | from juser.models import User 2 | from jasset.models import Asset 3 | from jumpserver.api import * 4 | 5 | 6 | def name_proc(request): 7 | user_id = request.user.id 8 | role_id = {'SU': 2, 'GA': 1, 'CU': 0}.get(request.user.role, 0) 9 | # role_id = 'SU' 10 | user_total_num = User.objects.all().count() 11 | user_active_num = User.objects.filter().count() 12 | host_total_num = Asset.objects.all().count() 13 | host_active_num = Asset.objects.filter(is_active=True).count() 14 | request.session.set_expiry(3600) 15 | 16 | info_dic = {'session_user_id': user_id, 17 | 'session_role_id': role_id, 18 | 'user_total_num': user_total_num, 19 | 'user_active_num': user_active_num, 20 | 'host_total_num': host_total_num, 21 | 'host_active_num': host_active_num, 22 | } 23 | 24 | return info_dic 25 | 26 | -------------------------------------------------------------------------------- /jumpserver/models.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | from django.db import models 4 | 5 | 6 | class Setting(models.Model): 7 | name = models.CharField(max_length=100) 8 | field1 = models.CharField(max_length=100, null=True, blank=True) 9 | field2 = models.CharField(max_length=100, null=True, blank=True) 10 | field3 = models.CharField(max_length=100, null=True, blank=True) 11 | field4 = models.CharField(max_length=100, null=True, blank=True) 12 | field5 = models.CharField(max_length=100, null=True, blank=True) 13 | 14 | class Meta: 15 | db_table = u'setting' 16 | 17 | def __unicode__(self): 18 | return self.name 19 | -------------------------------------------------------------------------------- /jumpserver/tasks.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from ansible.playbook import PlayBook 4 | from ansible import callbacks, utils 5 | 6 | 7 | def playbook_run(inventory, playbook, default_user=None, default_port=None, default_pri_key_path=None): 8 | stats = callbacks.AggregateStats() 9 | playbook_cb = callbacks.PlaybookCallbacks(verbose=utils.VERBOSITY) 10 | runner_cb = callbacks.PlaybookRunnerCallbacks(stats, verbose=utils.VERBOSITY) 11 | # run the playbook 12 | print default_user, default_port, default_pri_key_path, inventory, playbook 13 | if default_user and default_port and default_pri_key_path: 14 | playbook = PlayBook(host_list=inventory, 15 | playbook=playbook, 16 | forks=5, 17 | remote_user=default_user, 18 | remote_port=default_port, 19 | private_key_file=default_pri_key_path, 20 | callbacks=playbook_cb, 21 | runner_callbacks=runner_cb, 22 | stats=stats, 23 | become=True, 24 | become_user='root') 25 | else: 26 | playbook = PlayBook(host_list=inventory, 27 | playbook=playbook, 28 | forks=5, 29 | callbacks=playbook_cb, 30 | runner_callbacks=runner_cb, 31 | stats=stats, 32 | become=True, 33 | become_user='root') 34 | results = playbook.run() 35 | print results 36 | results_r = {'unreachable': [], 'failures': [], 'success': []} 37 | for hostname, result in results.items(): 38 | if result.get('unreachable', 2): 39 | results_r['unreachable'].append(hostname) 40 | print "%s >>> unreachable" % hostname 41 | elif result.get('failures', 2): 42 | results_r['failures'].append(hostname) 43 | print "%s >>> Failed" % hostname 44 | else: 45 | results_r['success'].append(hostname) 46 | print "%s >>> Success" % hostname 47 | return results_r 48 | 49 | -------------------------------------------------------------------------------- /jumpserver/templatetags/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'Hudie' 2 | -------------------------------------------------------------------------------- /jumpserver/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, include, url 2 | 3 | 4 | urlpatterns = patterns('jumpserver.views', 5 | # Examples: 6 | url(r'^$', 'index', name='index'), 7 | # url(r'^api/user/$', 'api_user'), 8 | url(r'^skin_config/$', 'skin_config', name='skin_config'), 9 | url(r'^login/$', 'Login', name='login'), 10 | url(r'^logout/$', 'Logout', name='logout'), 11 | url(r'^exec_cmd/$', 'exec_cmd', name='exec_cmd'), 12 | url(r'^file/upload/$', 'upload', name='file_upload'), 13 | url(r'^file/download/$', 'download', name='file_download'), 14 | url(r'^setting', 'setting', name='setting'), 15 | url(r'^terminal/$', 'web_terminal', name='terminal'), 16 | url(r'^juser/', include('juser.urls')), 17 | url(r'^jasset/', include('jasset.urls')), 18 | url(r'^jlog/', include('jlog.urls')), 19 | url(r'^jperm/', include('jperm.urls')), 20 | ) 21 | -------------------------------------------------------------------------------- /jumpserver/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for jumpserver project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "jumpserver.settings") 12 | 13 | from django.core.wsgi import get_wsgi_application 14 | application = get_wsgi_application() 15 | -------------------------------------------------------------------------------- /juser/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/juser/__init__.py -------------------------------------------------------------------------------- /juser/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /juser/models.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | from django.db import models 4 | from django.contrib.auth.models import AbstractUser 5 | import time 6 | # from jasset.models import Asset, AssetGroup 7 | 8 | 9 | class UserGroup(models.Model): 10 | name = models.CharField(max_length=80, unique=True) 11 | comment = models.CharField(max_length=160, blank=True, null=True) 12 | 13 | def __unicode__(self): 14 | return self.name 15 | 16 | 17 | class User(AbstractUser): 18 | USER_ROLE_CHOICES = ( 19 | ('SU', 'SuperUser'), 20 | ('GA', 'GroupAdmin'), 21 | ('CU', 'CommonUser'), 22 | ) 23 | name = models.CharField(max_length=80) 24 | uuid = models.CharField(max_length=100) 25 | role = models.CharField(max_length=2, choices=USER_ROLE_CHOICES, default='CU') 26 | group = models.ManyToManyField(UserGroup) 27 | ssh_key_pwd = models.CharField(max_length=200) 28 | # is_active = models.BooleanField(default=True) 29 | # last_login = models.DateTimeField(null=True) 30 | # date_joined = models.DateTimeField(null=True) 31 | 32 | def __unicode__(self): 33 | return self.username 34 | 35 | 36 | class AdminGroup(models.Model): 37 | """ 38 | under the user control group 39 | 用户可以管理的用户组,或组的管理员是该用户 40 | """ 41 | 42 | user = models.ForeignKey(User) 43 | group = models.ForeignKey(UserGroup) 44 | 45 | def __unicode__(self): 46 | return '%s: %s' % (self.user.username, self.group.name) 47 | 48 | 49 | class Document(models.Model): 50 | def upload_to(self, filename): 51 | return 'upload/'+str(self.user.id)+time.strftime('/%Y/%m/%d/', time.localtime())+filename 52 | 53 | docfile = models.FileField(upload_to=upload_to) 54 | user = models.ForeignKey(User) 55 | -------------------------------------------------------------------------------- /juser/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, include, url 2 | from jumpserver.api import view_splitter 3 | from juser.views import * 4 | 5 | urlpatterns = patterns('juser.views', 6 | # Examples: 7 | # url(r'^$', 'jumpserver.views.home', name='home'), 8 | # url(r'^blog/', include('blog.urls')), 9 | url(r'^group/add/$', 'group_add', name='user_group_add'), 10 | url(r'^group/list/$', 'group_list', name='user_group_list'), 11 | url(r'^group/del/$', 'group_del', name='user_group_del'), 12 | url(r'^group/edit/$', 'group_edit', name='user_group_edit'), 13 | url(r'^user/add/$', 'user_add', name='user_add'), 14 | url(r'^user/del/$', 'user_del', name='user_del'), 15 | url(r'^user/list/$', 'user_list', name='user_list'), 16 | url(r'^user/edit/$', 'user_edit', name='user_edit'), 17 | url(r'^user/detail/$', 'user_detail', name='user_detail'), 18 | url(r'^user/profile/$', 'profile', name='user_profile'), 19 | url(r'^user/update/$', 'change_info', name='user_update'), 20 | url(r'^mail/retry/$', 'send_mail_retry', name='mail_retry'), 21 | url(r'^password/reset/$', 'reset_password', name='password_reset'), 22 | url(r'^password/forget/$', 'forget_password', name='password_forget'), 23 | url(r'^key/gen/$', 'regen_ssh_key', name='key_gen'), 24 | url(r'^key/down/$', 'down_key', name='key_down'), 25 | ) 26 | -------------------------------------------------------------------------------- /keys/README.md: -------------------------------------------------------------------------------- 1 | 看山是山,看水是水 2 | 看山不是山,看水不是水 3 | 看山是山,看水是水 4 | -------------------------------------------------------------------------------- /logs/README.md: -------------------------------------------------------------------------------- 1 | 永远年轻,永远热泪盈眶 2 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "jumpserver.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /service.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # jumpserver Startup script for the jumpserver Server 3 | # 4 | # chkconfig: - 85 12 5 | # description: Open source detecting system 6 | # processname: jumpserver 7 | # Date: 2015-04-12 8 | # Version: 2.0.0 9 | # Site: http://www.jumpserver.org 10 | # Author: Jumpserver Team 11 | 12 | . /etc/init.d/functions 13 | export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/opt/node/bin 14 | 15 | base_dir=$(dirname $0) 16 | 17 | PROC_NAME="jumpsever" 18 | lockfile=/var/lock/subsys/${PROC_NAME} 19 | 20 | 21 | start() { 22 | jump_start=$"Starting ${PROC_NAME} service:" 23 | 24 | if [ -f $lockfile ];then 25 | echo "jumpserver is running..." 26 | success "$jump_start" 27 | else 28 | daemon python $base_dir/manage.py runserver 0.0.0.0:80 &>> /tmp/jumpserver.log 2>&1 & 29 | daemon python $base_dir/run_websocket.py &> /dev/null 2>&1 & 30 | sleep 4 31 | 32 | echo -n "$jump_start" 33 | nums=0 34 | for i in manage.py run_websocket.py;do 35 | ps aux | grep "$i" | grep -v 'grep' &> /dev/null && let nums+=1 || echo "$i not running" 36 | done 37 | 38 | if [ "x$nums" == "x2" ];then 39 | success "$jump_start" 40 | touch "$lockfile" 41 | echo 42 | else 43 | failure "$jump_start" 44 | echo 45 | fi 46 | fi 47 | 48 | 49 | } 50 | 51 | 52 | stop() { 53 | 54 | echo -n $"Stopping ${PROC_NAME} service:" 55 | 56 | ps aux | grep -E 'manage.py|run_websocket.py' | grep -v grep | awk '{print $2}' | xargs kill -9 &> /dev/null 57 | ret=$? 58 | 59 | if [ $ret -eq 0 ]; then 60 | echo_success 61 | echo 62 | rm -f "$lockfile" 63 | else 64 | echo_failure 65 | echo 66 | rm -f "$lockfile" 67 | fi 68 | 69 | } 70 | 71 | 72 | 73 | restart(){ 74 | stop 75 | start 76 | } 77 | 78 | # See how we were called. 79 | case "$1" in 80 | start) 81 | start 82 | ;; 83 | stop) 84 | stop 85 | ;; 86 | 87 | restart) 88 | restart 89 | ;; 90 | 91 | *) 92 | echo $"Usage: $0 {start|stop|restart}" 93 | exit 2 94 | esac 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /static/css/colorbox.css: -------------------------------------------------------------------------------- 1 | /* 2 | Colorbox Core Style: 3 | The following CSS is consistent between example themes and should not be altered. 4 | */ 5 | #colorbox, #cboxOverlay, #cboxWrapper{position:absolute; top:0; left:0; z-index:9999; overflow:hidden;} 6 | #cboxWrapper {max-width:none;} 7 | #cboxOverlay{position:fixed; width:100%; height:100%;} 8 | #cboxMiddleLeft, #cboxBottomLeft{clear:left;} 9 | #cboxContent{position:relative;} 10 | #cboxLoadedContent{overflow:auto; -webkit-overflow-scrolling: touch;} 11 | #cboxTitle{margin:0;} 12 | #cboxLoadingOverlay, #cboxLoadingGraphic{position:absolute; top:0; left:0; width:100%; height:100%;} 13 | #cboxPrevious, #cboxNext, #cboxClose, #cboxSlideshow{cursor:pointer;} 14 | .cboxPhoto{float:left; margin:auto; border:0; display:block; max-width:none; -ms-interpolation-mode:bicubic;} 15 | .cboxIframe{width:100%; height:100%; display:block; border:0; padding:0; margin:0;} 16 | #colorbox, #cboxContent, #cboxLoadedContent{box-sizing:content-box; -moz-box-sizing:content-box; -webkit-box-sizing:content-box;} 17 | 18 | /* 19 | User Style: 20 | Change the following styles to modify the appearance of Colorbox. They are 21 | ordered & tabbed in a way that represents the nesting of the generated HTML. 22 | */ 23 | #cboxOverlay{background:#fff; opacity: 0.9; filter: alpha(opacity = 90);} 24 | #colorbox{outline:0;} 25 | #cboxContent{margin-top:32px; overflow:visible; background:#000;} 26 | .cboxIframe{background:#fff;} 27 | #cboxError{padding:50px; border:1px solid #ccc;} 28 | #cboxLoadedContent{background:#000; padding:1px;} 29 | #cboxLoadingGraphic{background:url(images/loading.gif) no-repeat center center;} 30 | #cboxLoadingOverlay{background:#000;} 31 | #cboxTitle{position:absolute; top:-22px; left:0; color:#000;} 32 | #cboxCurrent{position:absolute; top:-22px; right:205px; text-indent:-9999px;} 33 | 34 | /* these elements are buttons, and may need to have additional styles reset to avoid unwanted base styles */ 35 | #cboxPrevious, #cboxNext, #cboxSlideshow, #cboxClose {border:0; padding:0; margin:0; overflow:visible; text-indent:-9999px; width:20px; height:20px; position:absolute; top:-20px; background:url(images/controls.png) no-repeat 0 0;} 36 | 37 | /* avoid outlines on :active (mouseclick), but preserve outlines on :focus (tabbed navigating) */ 38 | #cboxPrevious:active, #cboxNext:active, #cboxSlideshow:active, #cboxClose:active {outline:0;} 39 | 40 | #cboxPrevious{background-position:0px 0px; right:44px;} 41 | #cboxPrevious:hover{background-position:0px -25px;} 42 | #cboxNext{background-position:-25px 0px; right:22px;} 43 | #cboxNext:hover{background-position:-25px -25px;} 44 | #cboxClose{background-position:-50px 0px; right:0;} 45 | #cboxClose:hover{background-position:-50px -25px;} 46 | .cboxSlideshow_on #cboxPrevious, .cboxSlideshow_off #cboxPrevious{right:66px;} 47 | .cboxSlideshow_on #cboxSlideshow{background-position:-75px -25px; right:44px;} 48 | .cboxSlideshow_on #cboxSlideshow:hover{background-position:-100px -25px;} 49 | .cboxSlideshow_off #cboxSlideshow{background-position:-100px 0px; right:44px;} 50 | .cboxSlideshow_off #cboxSlideshow:hover{background-position:-75px -25px;} 51 | -------------------------------------------------------------------------------- /static/css/images/controls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/images/controls.png -------------------------------------------------------------------------------- /static/css/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/images/loading.gif -------------------------------------------------------------------------------- /static/css/patterns/congruent_pentagon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/patterns/congruent_pentagon.png -------------------------------------------------------------------------------- /static/css/patterns/header-profile-skin-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/patterns/header-profile-skin-1.png -------------------------------------------------------------------------------- /static/css/patterns/header-profile-skin-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/patterns/header-profile-skin-2.png -------------------------------------------------------------------------------- /static/css/patterns/header-profile-skin-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/patterns/header-profile-skin-3.png -------------------------------------------------------------------------------- /static/css/patterns/header-profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/patterns/header-profile.png -------------------------------------------------------------------------------- /static/css/patterns/otis_redding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/patterns/otis_redding.png -------------------------------------------------------------------------------- /static/css/patterns/shattered.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/patterns/shattered.png -------------------------------------------------------------------------------- /static/css/patterns/triangular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/patterns/triangular.png -------------------------------------------------------------------------------- /static/css/plugins/chosen/chosen-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/plugins/chosen/chosen-sprite.png -------------------------------------------------------------------------------- /static/css/plugins/chosen/chosen-sprite@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/plugins/chosen/chosen-sprite@2x.png -------------------------------------------------------------------------------- /static/css/plugins/dropzone/basic.css: -------------------------------------------------------------------------------- 1 | /* The MIT License */ 2 | .dropzone, 3 | .dropzone *, 4 | .dropzone-previews, 5 | .dropzone-previews * { 6 | -webkit-box-sizing: border-box; 7 | -moz-box-sizing: border-box; 8 | box-sizing: border-box; 9 | } 10 | .dropzone { 11 | position: relative; 12 | border: 1px solid rgba(0,0,0,0.08); 13 | background: rgba(0,0,0,0.02); 14 | padding: 1em; 15 | } 16 | .dropzone.dz-clickable { 17 | cursor: pointer; 18 | } 19 | .dropzone.dz-clickable .dz-message, 20 | .dropzone.dz-clickable .dz-message span { 21 | cursor: pointer; 22 | } 23 | .dropzone.dz-clickable * { 24 | cursor: default; 25 | } 26 | .dropzone .dz-message { 27 | opacity: 1; 28 | -ms-filter: none; 29 | filter: none; 30 | } 31 | .dropzone.dz-drag-hover { 32 | border-color: rgba(0,0,0,0.15); 33 | background: rgba(0,0,0,0.04); 34 | } 35 | .dropzone.dz-started .dz-message { 36 | display: none; 37 | } 38 | .dropzone .dz-preview, 39 | .dropzone-previews .dz-preview { 40 | background: rgba(255,255,255,0.8); 41 | position: relative; 42 | display: inline-block; 43 | margin: 17px; 44 | vertical-align: top; 45 | border: 1px solid #acacac; 46 | padding: 6px 6px 6px 6px; 47 | } 48 | .dropzone .dz-preview.dz-file-preview [data-dz-thumbnail], 49 | .dropzone-previews .dz-preview.dz-file-preview [data-dz-thumbnail] { 50 | display: none; 51 | } 52 | .dropzone .dz-preview .dz-details, 53 | .dropzone-previews .dz-preview .dz-details { 54 | width: 100px; 55 | height: 100px; 56 | position: relative; 57 | background: #ebebeb; 58 | padding: 5px; 59 | margin-bottom: 22px; 60 | } 61 | .dropzone .dz-preview .dz-details .dz-filename, 62 | .dropzone-previews .dz-preview .dz-details .dz-filename { 63 | overflow: hidden; 64 | height: 100%; 65 | } 66 | .dropzone .dz-preview .dz-details img, 67 | .dropzone-previews .dz-preview .dz-details img { 68 | position: absolute; 69 | top: 0; 70 | left: 0; 71 | width: 100px; 72 | height: 100px; 73 | } 74 | .dropzone .dz-preview .dz-details .dz-size, 75 | .dropzone-previews .dz-preview .dz-details .dz-size { 76 | position: absolute; 77 | bottom: -28px; 78 | left: 3px; 79 | height: 28px; 80 | line-height: 28px; 81 | } 82 | .dropzone .dz-preview.dz-error .dz-error-mark, 83 | .dropzone-previews .dz-preview.dz-error .dz-error-mark { 84 | display: block; 85 | } 86 | .dropzone .dz-preview.dz-success .dz-success-mark, 87 | .dropzone-previews .dz-preview.dz-success .dz-success-mark { 88 | display: block; 89 | } 90 | .dropzone .dz-preview:hover .dz-details img, 91 | .dropzone-previews .dz-preview:hover .dz-details img { 92 | display: none; 93 | } 94 | .dropzone .dz-preview .dz-success-mark, 95 | .dropzone-previews .dz-preview .dz-success-mark, 96 | .dropzone .dz-preview .dz-error-mark, 97 | .dropzone-previews .dz-preview .dz-error-mark { 98 | display: none; 99 | position: absolute; 100 | width: 40px; 101 | height: 40px; 102 | font-size: 30px; 103 | text-align: center; 104 | right: -10px; 105 | top: -10px; 106 | } 107 | .dropzone .dz-preview .dz-success-mark, 108 | .dropzone-previews .dz-preview .dz-success-mark { 109 | color: #8cc657; 110 | } 111 | .dropzone .dz-preview .dz-error-mark, 112 | .dropzone-previews .dz-preview .dz-error-mark { 113 | color: #ee162d; 114 | } 115 | .dropzone .dz-preview .dz-progress, 116 | .dropzone-previews .dz-preview .dz-progress { 117 | position: absolute; 118 | top: 100px; 119 | left: 6px; 120 | right: 6px; 121 | height: 6px; 122 | background: #d7d7d7; 123 | display: none; 124 | } 125 | .dropzone .dz-preview .dz-progress .dz-upload, 126 | .dropzone-previews .dz-preview .dz-progress .dz-upload { 127 | display: block; 128 | position: absolute; 129 | top: 0; 130 | bottom: 0; 131 | left: 0; 132 | width: 0%; 133 | background-color: #8cc657; 134 | } 135 | .dropzone .dz-preview.dz-processing .dz-progress, 136 | .dropzone-previews .dz-preview.dz-processing .dz-progress { 137 | display: block; 138 | } 139 | .dropzone .dz-preview .dz-error-message, 140 | .dropzone-previews .dz-preview .dz-error-message { 141 | display: none; 142 | position: absolute; 143 | top: -5px; 144 | left: -20px; 145 | background: rgba(245,245,245,0.8); 146 | padding: 8px 10px; 147 | color: #800; 148 | min-width: 140px; 149 | max-width: 500px; 150 | z-index: 500; 151 | } 152 | .dropzone .dz-preview:hover.dz-error .dz-error-message, 153 | .dropzone-previews .dz-preview:hover.dz-error .dz-error-message { 154 | display: block; 155 | } 156 | -------------------------------------------------------------------------------- /static/css/plugins/iCheck/custom.css: -------------------------------------------------------------------------------- 1 | /* iCheck plugin Square skin, green 2 | ----------------------------------- */ 3 | .icheckbox_square-green, 4 | .iradio_square-green { 5 | display: inline-block; 6 | *display: inline; 7 | vertical-align: middle; 8 | margin: 0; 9 | padding: 0; 10 | width: 22px; 11 | height: 22px; 12 | background: url(green.png) no-repeat; 13 | border: none; 14 | cursor: pointer; 15 | } 16 | 17 | .icheckbox_square-green { 18 | background-position: 0 0; 19 | } 20 | .icheckbox_square-green.hover { 21 | background-position: -24px 0; 22 | } 23 | .icheckbox_square-green.checked { 24 | background-position: -48px 0; 25 | } 26 | .icheckbox_square-green.disabled { 27 | background-position: -72px 0; 28 | cursor: default; 29 | } 30 | .icheckbox_square-green.checked.disabled { 31 | background-position: -96px 0; 32 | } 33 | 34 | .iradio_square-green { 35 | background-position: -120px 0; 36 | } 37 | .iradio_square-green.hover { 38 | background-position: -144px 0; 39 | } 40 | .iradio_square-green.checked { 41 | background-position: -168px 0; 42 | } 43 | .iradio_square-green.disabled { 44 | background-position: -192px 0; 45 | cursor: default; 46 | } 47 | .iradio_square-green.checked.disabled { 48 | background-position: -216px 0; 49 | } 50 | 51 | /* HiDPI support */ 52 | @media (-o-min-device-pixel-ratio: 5/4), (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) { 53 | .icheckbox_square-green, 54 | .iradio_square-green { 55 | background-image: url(green@2x.png); 56 | -webkit-background-size: 240px 24px; 57 | background-size: 240px 24px; 58 | } 59 | } -------------------------------------------------------------------------------- /static/css/plugins/iCheck/green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/plugins/iCheck/green.png -------------------------------------------------------------------------------- /static/css/plugins/iCheck/green@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/plugins/iCheck/green@2x.png -------------------------------------------------------------------------------- /static/css/plugins/images/bootstrap-colorpicker/alpha-horizontal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/plugins/images/bootstrap-colorpicker/alpha-horizontal.png -------------------------------------------------------------------------------- /static/css/plugins/images/bootstrap-colorpicker/alpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/plugins/images/bootstrap-colorpicker/alpha.png -------------------------------------------------------------------------------- /static/css/plugins/images/bootstrap-colorpicker/hue-horizontal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/plugins/images/bootstrap-colorpicker/hue-horizontal.png -------------------------------------------------------------------------------- /static/css/plugins/images/bootstrap-colorpicker/hue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/plugins/images/bootstrap-colorpicker/hue.png -------------------------------------------------------------------------------- /static/css/plugins/images/bootstrap-colorpicker/saturation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/plugins/images/bootstrap-colorpicker/saturation.png -------------------------------------------------------------------------------- /static/css/plugins/images/sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/plugins/images/sort.png -------------------------------------------------------------------------------- /static/css/plugins/images/sort_asc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/plugins/images/sort_asc.png -------------------------------------------------------------------------------- /static/css/plugins/images/sort_desc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/plugins/images/sort_desc.png -------------------------------------------------------------------------------- /static/css/plugins/images/sprite-skin-flat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/plugins/images/sprite-skin-flat.png -------------------------------------------------------------------------------- /static/css/plugins/images/sprite-skin-flat2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/plugins/images/sprite-skin-flat2.png -------------------------------------------------------------------------------- /static/css/plugins/images/sprite-skin-nice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/plugins/images/sprite-skin-nice.png -------------------------------------------------------------------------------- /static/css/plugins/images/sprite-skin-simple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/plugins/images/sprite-skin-simple.png -------------------------------------------------------------------------------- /static/css/plugins/images/spritemap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/plugins/images/spritemap.png -------------------------------------------------------------------------------- /static/css/plugins/images/spritemap@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/plugins/images/spritemap@2x.png -------------------------------------------------------------------------------- /static/css/vaildator/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/vaildator/images/loading.gif -------------------------------------------------------------------------------- /static/css/vaildator/images/validator_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/vaildator/images/validator_default.png -------------------------------------------------------------------------------- /static/css/vaildator/images/validator_simple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/css/vaildator/images/validator_simple.png -------------------------------------------------------------------------------- /static/css/vaildator/jquery.validator.css: -------------------------------------------------------------------------------- 1 | /*! nice Validator 0.7.3 2 | * (c) 2012-2014 Jony Zhang , MIT Licensed 3 | * http://niceue.com/validator/ 4 | */ 5 | .n-inline-block,.nice-validator input,.nice-validator select,.nice-validator textarea,.msg-wrap,.n-icon,.n-msg{display:inline-block;*display:inline;*zoom:1} 6 | .msg-box{position:relative;*zoom:1} 7 | .msg-wrap{position:relative;white-space:nowrap} 8 | .msg-wrap,.n-icon,.n-msg{vertical-align:top} 9 | .n-arrow{position:absolute;overflow:hidden;} 10 | .n-arrow b,.n-arrow i{position:absolute;left:0;top:0;border:0;margin:0;padding:0;overflow:hidden;font-weight:400;font-style:normal;font-size:12px;font-family:serif;line-height:14px;_line-height:15px} 11 | .n-arrow i{text-shadow:none} 12 | .n-icon{width:16px;height:16px;overflow:hidden;background-repeat:no-repeat} 13 | .n-msg{display:inline-block;line-height:15px;margin-left:2px;*margin-top:-1px;_margin-top:0;font-size:12px;font-family:simsun} 14 | .n-error{color:#c33} 15 | .n-ok{color:#390} 16 | .n-tip,.n-loading{color:#808080} 17 | .n-error .n-icon{background-position:0 0} 18 | .n-ok .n-icon{background-position:-16px 0} 19 | .n-tip .n-icon{background-position:-32px 0} 20 | .n-loading .n-icon{background:url("images/loading.gif") 0 center no-repeat !important} 21 | .n-top,.n-right,.n-bottom,.n-left{display:inline-block;line-height:0;vertical-align:top;outline:0} 22 | .n-top .n-arrow,.n-bottom .n-arrow{height:6px;width:12px;left:8px} 23 | .n-left .n-arrow,.n-right .n-arrow{width:6px;height:12px;top:6px} 24 | .n-top{vertical-align:top;} 25 | .n-top .msg-wrap{margin-bottom:6px} 26 | .n-top .n-arrow{bottom:-6px;} 27 | .n-top .n-arrow b{top:-6px} 28 | .n-top .n-arrow i{top:-7px} 29 | .n-bottom{vertical-align:bottom;} 30 | .n-bottom .msg-wrap{margin-top:6px} 31 | .n-bottom .n-arrow{top:-6px;} 32 | .n-bottom .n-arrow b{top:-1px} 33 | .n-bottom .n-arrow i{top:0} 34 | .n-left .msg-wrap{right:100%;margin-right:6px} 35 | .n-left .n-arrow{right:-6px;} 36 | .n-left .n-arrow b{left:-6px} 37 | .n-left .n-arrow i{left:-7px} 38 | .n-right .msg-wrap{margin-left:6px} 39 | .n-right .n-arrow{left:-6px;} 40 | .n-right .n-arrow b{left:1px} 41 | .n-right .n-arrow i{left:2px} 42 | .n-default .n-left,.n-default .n-right{margin-top:5px} 43 | .n-default .n-top .msg-wrap{bottom:100%} 44 | .n-default .n-bottom .msg-wrap{top:100%} 45 | .n-default .msg-wrap{position:absolute;z-index:1;} 46 | .n-default .msg-wrap .n-icon{background-image:url("images/validator_default.png")} 47 | .n-default .n-tip .n-icon{display:none} 48 | .n-simple .msg-wrap{position:absolute;z-index:1;} 49 | .n-simple .msg-wrap .n-icon{background-image:url("images/validator_simple.png")} 50 | .n-simple .n-top .msg-wrap{bottom:100%} 51 | .n-simple .n-bottom .msg-wrap{top:100%} 52 | .n-simple .n-left,.n-simple .n-right{margin-top:5px} 53 | .n-simple .n-bottom .msg-wrap{margin-top:3px} 54 | .n-simple .n-tip .n-icon{display:none} 55 | .n-yellow .msg-wrap{position:absolute;z-index:1;padding:4px 6px;font-size:12px;border:1px solid transparent;background-color:#fffcef;border-color:#ffbb76;color:#db7c22;box-shadow:0 1px 3px #ccc;border-radius:2px;} 56 | .n-yellow .msg-wrap .n-arrow b{color:#ffbb76;text-shadow:0 0 2px #ccc} 57 | .n-yellow .msg-wrap .n-arrow i{color:#fffcef} 58 | .n-yellow .msg-wrap .n-icon{background-image:url("images/validator_simple.png")} 59 | .n-yellow .n-top .msg-wrap{bottom:100%} 60 | .n-yellow .n-bottom .msg-wrap{top:100%} 61 | .n-yellow .n-tip,.n-yellow .n-ok,.n-yellow .n-loading{background-color:#f8fdff;border-color:#ddd;color:#333;box-shadow:0 1px 3px #ccc;} 62 | .n-yellow .n-tip .n-arrow b,.n-yellow .n-ok .n-arrow b,.n-yellow .n-loading .n-arrow b{color:#ddd;text-shadow:0 0 2px #ccc} 63 | .n-yellow .n-tip .n-arrow i,.n-yellow .n-ok .n-arrow i,.n-yellow .n-loading .n-arrow i{color:#f8fdff} 64 | .n-yellow .n-tip .n-icon{display:none} 65 | -------------------------------------------------------------------------------- /static/files/excels/asset.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/files/excels/asset.xlsx -------------------------------------------------------------------------------- /static/font-awesome/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/font-awesome/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /static/font-awesome/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/font-awesome/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /static/font-awesome/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/font-awesome/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /static/font-awesome/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/font-awesome/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /static/font-awesome/less/bordered-pulled.less: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-border { 5 | padding: .2em .25em .15em; 6 | border: solid .08em @fa-border-color; 7 | border-radius: .1em; 8 | } 9 | 10 | .pull-right { float: right; } 11 | .pull-left { float: left; } 12 | 13 | .@{fa-css-prefix} { 14 | &.pull-left { margin-right: .3em; } 15 | &.pull-right { margin-left: .3em; } 16 | } 17 | -------------------------------------------------------------------------------- /static/font-awesome/less/core.less: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix} { 5 | display: inline-block; 6 | font: normal normal normal 14px/1 FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | } 12 | -------------------------------------------------------------------------------- /static/font-awesome/less/fixed-width.less: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .@{fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /static/font-awesome/less/font-awesome.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | 6 | @import "variables.less"; 7 | @import "mixins.less"; 8 | @import "path.less"; 9 | @import "core.less"; 10 | @import "larger.less"; 11 | @import "fixed-width.less"; 12 | @import "list.less"; 13 | @import "bordered-pulled.less"; 14 | @import "spinning.less"; 15 | @import "rotated-flipped.less"; 16 | @import "stacked.less"; 17 | @import "icons.less"; 18 | -------------------------------------------------------------------------------- /static/font-awesome/less/larger.less: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | /* makes the font 33% larger relative to the icon container */ 5 | .@{fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -15%; 9 | } 10 | .@{fa-css-prefix}-2x { font-size: 2em; } 11 | .@{fa-css-prefix}-3x { font-size: 3em; } 12 | .@{fa-css-prefix}-4x { font-size: 4em; } 13 | .@{fa-css-prefix}-5x { font-size: 5em; } 14 | -------------------------------------------------------------------------------- /static/font-awesome/less/list.less: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-ul { 5 | padding-left: 0; 6 | margin-left: @fa-li-width; 7 | list-style-type: none; 8 | > li { position: relative; } 9 | } 10 | .@{fa-css-prefix}-li { 11 | position: absolute; 12 | left: -@fa-li-width; 13 | width: @fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.@{fa-css-prefix}-lg { 17 | left: (-@fa-li-width + (4em / 14)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /static/font-awesome/less/mixins.less: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | .fa-icon() { 5 | display: inline-block; 6 | font: normal normal normal 14px/1 FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | } 12 | 13 | .fa-icon-rotate(@degrees, @rotation) { 14 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation); 15 | -webkit-transform: rotate(@degrees); 16 | -ms-transform: rotate(@degrees); 17 | transform: rotate(@degrees); 18 | } 19 | 20 | .fa-icon-flip(@horiz, @vert, @rotation) { 21 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation, mirror=1); 22 | -webkit-transform: scale(@horiz, @vert); 23 | -ms-transform: scale(@horiz, @vert); 24 | transform: scale(@horiz, @vert); 25 | } 26 | -------------------------------------------------------------------------------- /static/font-awesome/less/path.less: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: 'FontAwesome'; 6 | src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}'); 7 | src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'), 8 | url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'), 9 | url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'), 10 | url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg'); 11 | // src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts 12 | font-weight: normal; 13 | font-style: normal; 14 | } 15 | -------------------------------------------------------------------------------- /static/font-awesome/less/rotated-flipped.less: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); } 5 | .@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); } 6 | .@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); } 7 | 8 | .@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); } 9 | .@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); } 10 | 11 | // Hook for IE8-9 12 | // ------------------------- 13 | 14 | :root .@{fa-css-prefix}-rotate-90, 15 | :root .@{fa-css-prefix}-rotate-180, 16 | :root .@{fa-css-prefix}-rotate-270, 17 | :root .@{fa-css-prefix}-flip-horizontal, 18 | :root .@{fa-css-prefix}-flip-vertical { 19 | filter: none; 20 | } 21 | -------------------------------------------------------------------------------- /static/font-awesome/less/spinning.less: -------------------------------------------------------------------------------- 1 | // Spinning Icons 2 | // -------------------------- 3 | 4 | .@{fa-css-prefix}-spin { 5 | -webkit-animation: fa-spin 2s infinite linear; 6 | animation: fa-spin 2s infinite linear; 7 | } 8 | 9 | @-webkit-keyframes fa-spin { 10 | 0% { 11 | -webkit-transform: rotate(0deg); 12 | transform: rotate(0deg); 13 | } 14 | 100% { 15 | -webkit-transform: rotate(359deg); 16 | transform: rotate(359deg); 17 | } 18 | } 19 | 20 | @keyframes fa-spin { 21 | 0% { 22 | -webkit-transform: rotate(0deg); 23 | transform: rotate(0deg); 24 | } 25 | 100% { 26 | -webkit-transform: rotate(359deg); 27 | transform: rotate(359deg); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /static/font-awesome/less/stacked.less: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .@{fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .@{fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .@{fa-css-prefix}-inverse { color: @fa-inverse; } 21 | -------------------------------------------------------------------------------- /static/font-awesome/scss/_bordered-pulled.scss: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-border { 5 | padding: .2em .25em .15em; 6 | border: solid .08em $fa-border-color; 7 | border-radius: .1em; 8 | } 9 | 10 | .pull-right { float: right; } 11 | .pull-left { float: left; } 12 | 13 | .#{$fa-css-prefix} { 14 | &.pull-left { margin-right: .3em; } 15 | &.pull-right { margin-left: .3em; } 16 | } 17 | -------------------------------------------------------------------------------- /static/font-awesome/scss/_core.scss: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix} { 5 | display: inline-block; 6 | font: normal normal normal 14px/1 FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | } 12 | -------------------------------------------------------------------------------- /static/font-awesome/scss/_fixed-width.scss: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .#{$fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /static/font-awesome/scss/_larger.scss: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | /* makes the font 33% larger relative to the icon container */ 5 | .#{$fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -15%; 9 | } 10 | .#{$fa-css-prefix}-2x { font-size: 2em; } 11 | .#{$fa-css-prefix}-3x { font-size: 3em; } 12 | .#{$fa-css-prefix}-4x { font-size: 4em; } 13 | .#{$fa-css-prefix}-5x { font-size: 5em; } 14 | -------------------------------------------------------------------------------- /static/font-awesome/scss/_list.scss: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-ul { 5 | padding-left: 0; 6 | margin-left: $fa-li-width; 7 | list-style-type: none; 8 | > li { position: relative; } 9 | } 10 | .#{$fa-css-prefix}-li { 11 | position: absolute; 12 | left: -$fa-li-width; 13 | width: $fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.#{$fa-css-prefix}-lg { 17 | left: -$fa-li-width + (4em / 14); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /static/font-awesome/scss/_mixins.scss: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | @mixin fa-icon() { 5 | display: inline-block; 6 | font: normal normal normal 14px/1 FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | } 12 | 13 | @mixin fa-icon-rotate($degrees, $rotation) { 14 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}); 15 | -webkit-transform: rotate($degrees); 16 | -ms-transform: rotate($degrees); 17 | transform: rotate($degrees); 18 | } 19 | 20 | @mixin fa-icon-flip($horiz, $vert, $rotation) { 21 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}); 22 | -webkit-transform: scale($horiz, $vert); 23 | -ms-transform: scale($horiz, $vert); 24 | transform: scale($horiz, $vert); 25 | } 26 | -------------------------------------------------------------------------------- /static/font-awesome/scss/_path.scss: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: 'FontAwesome'; 6 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}'); 7 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'), 8 | url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'), 9 | url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'), 10 | url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg'); 11 | //src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts 12 | font-weight: normal; 13 | font-style: normal; 14 | } 15 | -------------------------------------------------------------------------------- /static/font-awesome/scss/_rotated-flipped.scss: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); } 5 | .#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); } 6 | .#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); } 7 | 8 | .#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); } 9 | .#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); } 10 | 11 | // Hook for IE8-9 12 | // ------------------------- 13 | 14 | :root .#{$fa-css-prefix}-rotate-90, 15 | :root .#{$fa-css-prefix}-rotate-180, 16 | :root .#{$fa-css-prefix}-rotate-270, 17 | :root .#{$fa-css-prefix}-flip-horizontal, 18 | :root .#{$fa-css-prefix}-flip-vertical { 19 | filter: none; 20 | } 21 | -------------------------------------------------------------------------------- /static/font-awesome/scss/_spinning.scss: -------------------------------------------------------------------------------- 1 | // Spinning Icons 2 | // -------------------------- 3 | 4 | .#{$fa-css-prefix}-spin { 5 | -webkit-animation: fa-spin 2s infinite linear; 6 | animation: fa-spin 2s infinite linear; 7 | } 8 | 9 | @-webkit-keyframes fa-spin { 10 | 0% { 11 | -webkit-transform: rotate(0deg); 12 | transform: rotate(0deg); 13 | } 14 | 100% { 15 | -webkit-transform: rotate(359deg); 16 | transform: rotate(359deg); 17 | } 18 | } 19 | 20 | @keyframes fa-spin { 21 | 0% { 22 | -webkit-transform: rotate(0deg); 23 | transform: rotate(0deg); 24 | } 25 | 100% { 26 | -webkit-transform: rotate(359deg); 27 | transform: rotate(359deg); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /static/font-awesome/scss/_stacked.scss: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .#{$fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .#{$fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .#{$fa-css-prefix}-inverse { color: $fa-inverse; } 21 | -------------------------------------------------------------------------------- /static/font-awesome/scss/font-awesome.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | 6 | @import "variables"; 7 | @import "mixins"; 8 | @import "path"; 9 | @import "core"; 10 | @import "larger"; 11 | @import "fixed-width"; 12 | @import "list"; 13 | @import "bordered-pulled"; 14 | @import "spinning"; 15 | @import "rotated-flipped"; 16 | @import "stacked"; 17 | @import "icons"; 18 | -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /static/img/a1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/a1.jpg -------------------------------------------------------------------------------- /static/img/a2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/a2.jpg -------------------------------------------------------------------------------- /static/img/a3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/a3.jpg -------------------------------------------------------------------------------- /static/img/a4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/a4.jpg -------------------------------------------------------------------------------- /static/img/a5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/a5.jpg -------------------------------------------------------------------------------- /static/img/a6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/a6.jpg -------------------------------------------------------------------------------- /static/img/a7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/a7.jpg -------------------------------------------------------------------------------- /static/img/a8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/a8.jpg -------------------------------------------------------------------------------- /static/img/admin.bak.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/admin.bak.png -------------------------------------------------------------------------------- /static/img/admin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/admin.png -------------------------------------------------------------------------------- /static/img/angular_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/angular_logo.png -------------------------------------------------------------------------------- /static/img/email_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/email_1.jpg -------------------------------------------------------------------------------- /static/img/email_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/email_2.jpg -------------------------------------------------------------------------------- /static/img/email_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/email_3.jpg -------------------------------------------------------------------------------- /static/img/facio.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/facio.ico -------------------------------------------------------------------------------- /static/img/html_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/html_logo.png -------------------------------------------------------------------------------- /static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/logo.png -------------------------------------------------------------------------------- /static/img/mvc_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/mvc_logo.png -------------------------------------------------------------------------------- /static/img/p1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/p1.jpg -------------------------------------------------------------------------------- /static/img/p2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/p2.jpg -------------------------------------------------------------------------------- /static/img/p3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/p3.jpg -------------------------------------------------------------------------------- /static/img/p4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/p4.jpg -------------------------------------------------------------------------------- /static/img/p5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/p5.jpg -------------------------------------------------------------------------------- /static/img/p6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/p6.jpg -------------------------------------------------------------------------------- /static/img/p7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/p7.jpg -------------------------------------------------------------------------------- /static/img/p8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/p8.jpg -------------------------------------------------------------------------------- /static/img/p_big1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/p_big1.jpg -------------------------------------------------------------------------------- /static/img/p_big2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/p_big2.jpg -------------------------------------------------------------------------------- /static/img/p_big3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/p_big3.jpg -------------------------------------------------------------------------------- /static/img/profile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/profile.jpg -------------------------------------------------------------------------------- /static/img/profile_big.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/profile_big.jpg -------------------------------------------------------------------------------- /static/img/profile_small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/profile_small.jpg -------------------------------------------------------------------------------- /static/img/root.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/root.png -------------------------------------------------------------------------------- /static/img/spritemap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/spritemap.png -------------------------------------------------------------------------------- /static/img/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/user.png -------------------------------------------------------------------------------- /static/img/zender_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/img/zender_logo.png -------------------------------------------------------------------------------- /static/js/demo/peity-demo.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | $("span.pie").peity("pie", { 3 | fill: ['#1ab394', '#d7d7d7', '#ffffff'] 4 | }) 5 | 6 | $(".line").peity("line",{ 7 | fill: '#1ab394', 8 | stroke:'#169c81', 9 | }) 10 | 11 | $(".bar").peity("bar", { 12 | fill: ["#1ab394", "#d7d7d7"] 13 | }) 14 | 15 | $(".bar_dashboard").peity("bar", { 16 | fill: ["#1ab394", "#d7d7d7"], 17 | width:100 18 | }) 19 | 20 | var updatingChart = $(".updating-chart").peity("line", { fill: '#1ab394',stroke:'#169c81', width: 64 }) 21 | 22 | setInterval(function() { 23 | var random = Math.round(Math.random() * 10) 24 | var values = updatingChart.text().split(",") 25 | values.shift() 26 | values.push(random) 27 | 28 | updatingChart 29 | .text(values.join(",")) 30 | .change() 31 | }, 1000); 32 | 33 | }); 34 | -------------------------------------------------------------------------------- /static/js/echarts/chart/heatmap.js: -------------------------------------------------------------------------------- 1 | define("echarts/chart/heatmap",["require","./base","../layer/heatmap","../config","../util/ecData","zrender/tool/util","zrender/tool/color","zrender/shape/Image","../chart"],function(e){function t(e,t,n,a,o){i.call(this,e,t,n,a,o),this.refresh(a)}var i=e("./base"),n=e("../layer/heatmap"),a=e("../config"),o=(e("../util/ecData"),e("zrender/tool/util")),r=(e("zrender/tool/color"),e("zrender/shape/Image"));return a.heatmap={zlevel:0,z:2,clickable:!0},t.prototype={type:a.CHART_TYPE_HEATMAP,refresh:function(e){this.clear(),e&&(this.option=e,this.series=e.series),this._init()},_init:function(){var e=this.series;this.backupShapeList();for(var t=e.length,i=0;t>i;++i)if(e[i].type===a.CHART_TYPE_HEATMAP){e[i]=this.reformOption(e[i]);var o=new n(e[i]),s=o.getCanvas(e[i].data,this.zr.getWidth(),this.zr.getHeight()),l=new r({position:[0,0],scale:[1,1],hoverable:this.option.hoverable,style:{x:0,y:0,image:s,width:s.width,height:s.height}});this.shapeList.push(l)}this.addShapeList()}},o.inherits(t,i),e("../chart").define("heatmap",t),t}),define("echarts/layer/heatmap",["require"],function(){function e(e){if(this.option=e,e)for(var i in t)this.option[i]=void 0!==e[i]?e[i]:t[i];else this.option=t}var t={blurSize:30,gradientColors:["blue","cyan","lime","yellow","red"],minAlpha:.05,valueScale:1,opacity:1},i=20,n=256;return e.prototype={getCanvas:function(e,t,a){var o=this._getBrush(),r=this._getGradient(),s=i+this.option.blurSize,l=document.createElement("canvas");l.width=t,l.height=a;for(var h=l.getContext("2d"),m=e.length,V=0;m>V;++V){var d=e[V],U=d[0],p=d[1],c=d[2],u=Math.min(1,Math.max(c*this.option.valueScale||this.option.minAlpha,this.option.minAlpha));h.globalAlpha=u,h.drawImage(o,U-s,p-s)}for(var g=h.getImageData(0,0,l.width,l.height),y=g.data,m=y.length/4;m--;){var b=4*m+3,u=y[b]/256,f=Math.floor(u*(n-1));y[b-3]=r[4*f],y[b-2]=r[4*f+1],y[b-1]=r[4*f+2],y[b]*=this.option.opacity}return h.putImageData(g,0,0),l},_getBrush:function(){if(!this._brushCanvas){this._brushCanvas=document.createElement("canvas");var e=i+this.option.blurSize,t=2*e;this._brushCanvas.width=t,this._brushCanvas.height=t;var n=this._brushCanvas.getContext("2d");n.shadowOffsetX=t,n.shadowBlur=this.option.blurSize,n.shadowColor="black",n.beginPath(),n.arc(-e,e,i,0,2*Math.PI,!0),n.closePath(),n.fill()}return this._brushCanvas},_getGradient:function(){if(!this._gradientPixels){var e=n,t=document.createElement("canvas");t.width=1,t.height=e;for(var i=t.getContext("2d"),a=i.createLinearGradient(0,0,0,e),o=this.option.gradientColors.length,r=0;o>r;++r)"string"==typeof this.option.gradientColors[r]?a.addColorStop((r+1)/o,this.option.gradientColors[r]):a.addColorStop(this.option.gradientColors[r].offset,this.option.gradientColors[r].color);i.fillStyle=a,i.fillRect(0,0,1,e),this._gradientPixels=i.getImageData(0,0,1,e).data}return this._gradientPixels}},e}),define("echarts/layer/heatmap",["require"],function(){function e(e){if(this.option=e,e)for(var i in t)this.option[i]=void 0!==e[i]?e[i]:t[i];else this.option=t}var t={blurSize:30,gradientColors:["blue","cyan","lime","yellow","red"],minAlpha:.05,valueScale:1,opacity:1},i=20,n=256;return e.prototype={getCanvas:function(e,t,a){var o=this._getBrush(),r=this._getGradient(),s=i+this.option.blurSize,l=document.createElement("canvas");l.width=t,l.height=a;for(var h=l.getContext("2d"),m=e.length,V=0;m>V;++V){var d=e[V],U=d[0],p=d[1],c=d[2],u=Math.min(1,Math.max(c*this.option.valueScale||this.option.minAlpha,this.option.minAlpha));h.globalAlpha=u,h.drawImage(o,U-s,p-s)}for(var g=h.getImageData(0,0,l.width,l.height),y=g.data,m=y.length/4;m--;){var b=4*m+3,u=y[b]/256,f=Math.floor(u*(n-1));y[b-3]=r[4*f],y[b-2]=r[4*f+1],y[b-1]=r[4*f+2],y[b]*=this.option.opacity}return h.putImageData(g,0,0),l},_getBrush:function(){if(!this._brushCanvas){this._brushCanvas=document.createElement("canvas");var e=i+this.option.blurSize,t=2*e;this._brushCanvas.width=t,this._brushCanvas.height=t;var n=this._brushCanvas.getContext("2d");n.shadowOffsetX=t,n.shadowBlur=this.option.blurSize,n.shadowColor="black",n.beginPath(),n.arc(-e,e,i,0,2*Math.PI,!0),n.closePath(),n.fill()}return this._brushCanvas},_getGradient:function(){if(!this._gradientPixels){var e=n,t=document.createElement("canvas");t.width=1,t.height=e;for(var i=t.getContext("2d"),a=i.createLinearGradient(0,0,0,e),o=this.option.gradientColors.length,r=0;o>r;++r)"string"==typeof this.option.gradientColors[r]?a.addColorStop((r+1)/o,this.option.gradientColors[r]):a.addColorStop(this.option.gradientColors[r].offset,this.option.gradientColors[r].color);i.fillStyle=a,i.fillRect(0,0,1,e),this._gradientPixels=i.getImageData(0,0,1,e).data}return this._gradientPixels}},e}); -------------------------------------------------------------------------------- /static/js/highcharts/modules/data.js: -------------------------------------------------------------------------------- 1 | /* 2 | Data plugin for Highcharts 3 | 4 | (c) 2012-2014 Torstein Honsi 5 | 6 | License: www.highcharts.com/license 7 | */ 8 | (function(j){var m=j.each,n=function(a,b){this.init(a,b)};j.extend(n.prototype,{init:function(a,b){this.options=a;this.chartOptions=b;this.columns=a.columns||this.rowsToColumns(a.rows)||[];this.columns.length?this.dataFound():(this.parseCSV(),this.parseTable(),this.parseGoogleSpreadsheet())},getColumnDistribution:function(){var a=this.chartOptions,b=a&&a.chart&&a.chart.type,c=[];m(a&&a.series||[],function(a){c.push((j.seriesTypes[a.type||b||"line"].prototype.pointArrayMap||[0]).length)});this.valueCount= 9 | {global:(j.seriesTypes[b||"line"].prototype.pointArrayMap||[0]).length,individual:c}},dataFound:function(){if(this.options.switchRowsAndColumns)this.columns=this.rowsToColumns(this.columns);this.parseTypes();this.findHeaderRow();this.parsed();this.complete()},parseCSV:function(){var a=this,b=this.options,c=b.csv,d=this.columns,e=b.startRow||0,h=b.endRow||Number.MAX_VALUE,i=b.startColumn||0,g=b.endColumn||Number.MAX_VALUE,f,k,o=0;c&&(k=c.replace(/\r\n/g,"\n").replace(/\r/g,"\n").split(b.lineDelimiter|| 10 | "\n"),f=b.itemDelimiter||(c.indexOf("\t")!==-1?"\t":","),m(k,function(b,c){var k=a.trim(b),j=k.indexOf("#")===0;c>=e&&c<=h&&!j&&k!==""&&(k=b.split(f),m(k,function(b,a){a>=i&&a<=g&&(d[a-i]||(d[a-i]=[]),d[a-i][o]=b)}),o+=1)}),this.dataFound())},parseTable:function(){var a=this.options,b=a.table,c=this.columns,d=a.startRow||0,e=a.endRow||Number.MAX_VALUE,h=a.startColumn||0,i=a.endColumn||Number.MAX_VALUE;b&&(typeof b==="string"&&(b=document.getElementById(b)),m(b.getElementsByTagName("tr"),function(a, 11 | b){b>=d&&b<=e&&m(a.children,function(a,e){if((a.tagName==="TD"||a.tagName==="TH")&&e>=h&&e<=i)c[e-h]||(c[e-h]=[]),c[e-h][b-d]=a.innerHTML})}),this.dataFound())},parseGoogleSpreadsheet:function(){var a=this,b=this.options,c=b.googleSpreadsheetKey,d=this.columns,e=b.startRow||0,h=b.endRow||Number.MAX_VALUE,i=b.startColumn||0,g=b.endColumn||Number.MAX_VALUE,f,k;c&&jQuery.ajax({dataType:"json",url:"https://spreadsheets.google.com/feeds/cells/"+c+"/"+(b.googleSpreadsheetWorksheet||"od6")+"/public/values?alt=json-in-script&callback=?", 12 | error:b.error,success:function(b){var b=b.feed.entry,c,j=b.length,m=0,n=0,l;for(l=0;l=i&&l<=g)d[l-i]=[],d[l-i].length=Math.min(n,h-e);for(l=0;l=i&&k<=g&&f>=e&&f<=h)d[k-i][f-e]=c.content.$t;a.dataFound()}})},findHeaderRow:function(){m(this.columns,function(){});this.headerRow=0},trim:function(a){return typeof a==="string"?a.replace(/^\s+|\s+$/g,""):a},parseTypes:function(){for(var a= 13 | this.columns,b=a.length,c,d,e,h;b--;)for(c=a[b].length;c--;)d=a[b][c],e=parseFloat(d),h=this.trim(d),h==e?(a[b][c]=e,e>31536E6?a[b].isDatetime=!0:a[b].isNumeric=!0):(d=this.parseDate(d),b===0&&typeof d==="number"&&!isNaN(d)?(a[b][c]=d,a[b].isDatetime=!0):a[b][c]=h===""?null:h)},dateFormats:{"YYYY-mm-dd":{regex:"^([0-9]{4})-([0-9]{2})-([0-9]{2})$",parser:function(a){return Date.UTC(+a[1],a[2]-1,+a[3])}}},parseDate:function(a){var b=this.options.parseDate,c,d,e;b&&(c=b(a));if(typeof a==="string")for(d in this.dateFormats)b= 14 | this.dateFormats[d],(e=a.match(b.regex))&&(c=b.parser(e));return c},rowsToColumns:function(a){var b,c,d,e,h;if(a){h=[];c=a.length;for(b=0;b1&&(b=a.shift(),this.headerRow===0&&b.shift(),b.isDatetime?c="datetime":b.isNumeric|| 15 | (c="category"));for(g=0;g1&&i[f].push(a[g+1][f]!==void 0?a[g+1][f]:null),e>2&&i[f].push(a[g+2][f]!==void 0?a[g+2][f]:null),e>3&&i[f].push(a[g+3][f]!==void 0?a[g+3][f]:null),e>4&&i[f].push(a[g+4][f]!==void 0?a[g+4][f]:null);h[k]={name:a[g].name,data:i};g+= 16 | e}d.complete({xAxis:{type:c},series:h})}}});j.Data=n;j.data=function(a,b){return new n(a,b)};j.wrap(j.Chart.prototype,"init",function(a,b,c){var d=this;b&&b.data?j.data(j.extend(b.data,{complete:function(e){b.hasOwnProperty("series")&&(typeof b.series==="object"?m(b.series,function(a,c){b.series[c]=j.merge(a,e.series[c])}):delete b.series);b=j.merge(e,b);a.call(d,b,c)}}),b):a.call(d,b,c)})})(Highcharts); 17 | -------------------------------------------------------------------------------- /static/js/highcharts/modules/funnel.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Highcharts funnel module 4 | 5 | (c) 2010-2014 Torstein Honsi 6 | 7 | License: www.highcharts.com/license 8 | */ 9 | (function(b){var d=b.getOptions(),v=d.plotOptions,q=b.seriesTypes,E=b.merge,D=function(){},A=b.each;v.funnel=E(v.pie,{animation:!1,center:["50%","50%"],width:"90%",neckWidth:"30%",height:"100%",neckHeight:"25%",reversed:!1,dataLabels:{connectorWidth:1,connectorColor:"#606060"},size:!0,states:{select:{color:"#C0C0C0",borderColor:"#000000",shadow:!1}}});q.funnel=b.extendClass(q.pie,{type:"funnel",animate:D,singularTooltips:!0,translate:function(){var a=function(j,a){return/%$/.test(j)?a*parseInt(j, 10 | 10)/100:parseInt(j,10)},B=0,f=this.chart,c=this.options,g=c.reversed,b=f.plotWidth,n=f.plotHeight,o=0,f=c.center,h=a(f[0],b),d=a(f[0],n),q=a(c.width,b),k,r,e=a(c.height,n),s=a(c.neckWidth,b),t=a(c.neckHeight,n),w=e-t,a=this.data,x,y,v=c.dataLabels.position==="left"?1:0,z,l,C,p,i,u,m;this.getWidthAt=r=function(j){return j>e-t||e===t?s:s+(q-s)*((e-t-j)/(e-t))};this.getX=function(j,a){return h+(a?-1:1)*(r(g?n-j:j)/2+c.dataLabels.distance)};this.center=[h,d,e];this.centerX=h;A(a,function(a){B+=a.y}); 11 | A(a,function(a){m=null;y=B?a.y/B:0;l=d-e/2+o*e;i=l+y*e;k=r(l);z=h-k/2;C=z+k;k=r(i);p=h-k/2;u=p+k;l>w?(z=p=h-s/2,C=u=h+s/2):i>w&&(m=i,k=r(w),p=h-k/2,u=p+k,i=w);g&&(l=e-l,i=e-i,m=m?e-m:null);x=["M",z,l,"L",C,l,u,i];m&&x.push(u,m,p,m);x.push(p,i,"Z");a.shapeType="path";a.shapeArgs={d:x};a.percentage=y*100;a.plotX=h;a.plotY=(l+(m||i))/2;a.tooltipPos=[h,a.plotY];a.slice=D;a.half=v;o+=y})},drawPoints:function(){var a=this,b=a.options,f=a.chart.renderer;A(a.data,function(c){var g=c.graphic,d=c.shapeArgs; 12 | g?g.animate(d):c.graphic=f.path(d).attr({fill:c.color,stroke:b.borderColor,"stroke-width":b.borderWidth}).add(a.group)})},sortByAngle:function(a){a.sort(function(a,b){return a.plotY-b.plotY})},drawDataLabels:function(){var a=this.data,b=this.options.dataLabels.distance,f,c,g,d=a.length,n,o;for(this.center[2]-=2*b;d--;)g=a[d],c=(f=g.half)?1:-1,o=g.plotY,n=this.getX(o,f),g.labelPos=[0,o,n+(b-5)*c,o,n+b*c,o,f?"right":"left",0];q.pie.prototype.drawDataLabels.call(this)}});d.plotOptions.pyramid=b.merge(d.plotOptions.funnel, 13 | {neckWidth:"0%",neckHeight:"0%",reversed:!0});b.seriesTypes.pyramid=b.extendClass(b.seriesTypes.funnel,{type:"pyramid"})})(Highcharts); 14 | -------------------------------------------------------------------------------- /static/js/highcharts/modules/no-data-to-display.js: -------------------------------------------------------------------------------- 1 | /* 2 | Highcharts JS v4.0.1 (2014-04-24) 3 | Plugin for displaying a message when there is no data visible in chart. 4 | 5 | (c) 2010-2014 Highsoft AS 6 | Author: Oystein Moseng 7 | 8 | License: www.highcharts.com/license 9 | */ 10 | (function(c){function f(){return!!this.points.length}function g(){this.hasData()?this.hideNoData():this.showNoData()}var d=c.seriesTypes,e=c.Chart.prototype,h=c.getOptions(),i=c.extend;i(h.lang,{noData:"No data to display"});h.noData={position:{x:0,y:0,align:"center",verticalAlign:"middle"},attr:{},style:{fontWeight:"bold",fontSize:"12px",color:"#60606a"}};if(d.pie)d.pie.prototype.hasData=f;if(d.gauge)d.gauge.prototype.hasData=f;if(d.waterfall)d.waterfall.prototype.hasData=f;c.Series.prototype.hasData= 11 | function(){return this.dataMax!==void 0&&this.dataMin!==void 0};e.showNoData=function(a){var b=this.options,a=a||b.lang.noData,b=b.noData;if(!this.noDataLabel)this.noDataLabel=this.renderer.label(a,0,0,null,null,null,null,null,"no-data").attr(b.attr).css(b.style).add(),this.noDataLabel.align(i(this.noDataLabel.getBBox(),b.position),!1,"plotBox")};e.hideNoData=function(){if(this.noDataLabel)this.noDataLabel=this.noDataLabel.destroy()};e.hasData=function(){for(var a=this.series,b=a.length;b--;)if(a[b].hasData()&& 12 | !a[b].options.isInternal)return!0;return!1};e.callbacks.push(function(a){c.addEvent(a,"load",g);c.addEvent(a,"redraw",g)})})(Highcharts); 13 | -------------------------------------------------------------------------------- /static/js/highcharts/modules/no-data-to-display.src.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license Highcharts JS v4.0.1 (2014-04-24) 3 | * Plugin for displaying a message when there is no data visible in chart. 4 | * 5 | * (c) 2010-2014 Highsoft AS 6 | * Author: Oystein Moseng 7 | * 8 | * License: www.highcharts.com/license 9 | */ 10 | 11 | (function (H) { // docs 12 | 13 | var seriesTypes = H.seriesTypes, 14 | chartPrototype = H.Chart.prototype, 15 | defaultOptions = H.getOptions(), 16 | extend = H.extend; 17 | 18 | // Add language option 19 | extend(defaultOptions.lang, { 20 | noData: 'No data to display' 21 | }); 22 | 23 | // Add default display options for message 24 | defaultOptions.noData = { 25 | position: { 26 | x: 0, 27 | y: 0, 28 | align: 'center', 29 | verticalAlign: 'middle' 30 | }, 31 | attr: { 32 | }, 33 | style: { 34 | fontWeight: 'bold', 35 | fontSize: '12px', 36 | color: '#60606a' 37 | } 38 | }; 39 | 40 | /** 41 | * Define hasData functions for series. These return true if there are data points on this series within the plot area 42 | */ 43 | function hasDataPie() { 44 | return !!this.points.length; /* != 0 */ 45 | } 46 | 47 | if (seriesTypes.pie) { 48 | seriesTypes.pie.prototype.hasData = hasDataPie; 49 | } 50 | 51 | if (seriesTypes.gauge) { 52 | seriesTypes.gauge.prototype.hasData = hasDataPie; 53 | } 54 | 55 | if (seriesTypes.waterfall) { 56 | seriesTypes.waterfall.prototype.hasData = hasDataPie; 57 | } 58 | 59 | H.Series.prototype.hasData = function () { 60 | return this.dataMax !== undefined && this.dataMin !== undefined; 61 | }; 62 | 63 | /** 64 | * Display a no-data message. 65 | * 66 | * @param {String} str An optional message to show in place of the default one 67 | */ 68 | chartPrototype.showNoData = function (str) { 69 | var chart = this, 70 | options = chart.options, 71 | text = str || options.lang.noData, 72 | noDataOptions = options.noData; 73 | 74 | if (!chart.noDataLabel) { 75 | chart.noDataLabel = chart.renderer.label(text, 0, 0, null, null, null, null, null, 'no-data') 76 | .attr(noDataOptions.attr) 77 | .css(noDataOptions.style) 78 | .add(); 79 | chart.noDataLabel.align(extend(chart.noDataLabel.getBBox(), noDataOptions.position), false, 'plotBox'); 80 | } 81 | }; 82 | 83 | /** 84 | * Hide no-data message 85 | */ 86 | chartPrototype.hideNoData = function () { 87 | var chart = this; 88 | if (chart.noDataLabel) { 89 | chart.noDataLabel = chart.noDataLabel.destroy(); 90 | } 91 | }; 92 | 93 | /** 94 | * Returns true if there are data points within the plot area now 95 | */ 96 | chartPrototype.hasData = function () { 97 | var chart = this, 98 | series = chart.series, 99 | i = series.length; 100 | 101 | while (i--) { 102 | if (series[i].hasData() && !series[i].options.isInternal) { 103 | return true; 104 | } 105 | } 106 | 107 | return false; 108 | }; 109 | 110 | /** 111 | * Show no-data message if there is no data in sight. Otherwise, hide it. 112 | */ 113 | function handleNoData() { 114 | var chart = this; 115 | if (chart.hasData()) { 116 | chart.hideNoData(); 117 | } else { 118 | chart.showNoData(); 119 | } 120 | } 121 | 122 | /** 123 | * Add event listener to handle automatic display of no-data message 124 | */ 125 | chartPrototype.callbacks.push(function (chart) { 126 | H.addEvent(chart, 'load', handleNoData); 127 | H.addEvent(chart, 'redraw', handleNoData); 128 | }); 129 | 130 | }(Highcharts)); 131 | -------------------------------------------------------------------------------- /static/js/highcharts/modules/solid-gauge.js: -------------------------------------------------------------------------------- 1 | /* 2 | Highcharts JS v4.0.1 (2014-04-24) 3 | Solid angular gauge module 4 | 5 | (c) 2010-2014 Torstein Honsi 6 | 7 | License: www.highcharts.com/license 8 | */ 9 | (function(a){var l=a.getOptions().plotOptions,o=a.pInt,p=a.pick,j=a.each,m;l.solidgauge=a.merge(l.gauge,{colorByPoint:!0});m={initDataClasses:function(b){var h=this,e=this.chart,c,k=0,f=this.options;this.dataClasses=c=[];j(b.dataClasses,function(g,d){var i,g=a.merge(g);c.push(g);if(!g.color)f.dataClassColor==="category"?(i=e.options.colors,g.color=i[k++],k===i.length&&(k=0)):g.color=h.tweenColors(a.Color(f.minColor),a.Color(f.maxColor),d/(b.dataClasses.length-1))})},initStops:function(b){this.stops= 10 | b.stops||[[0,this.options.minColor],[1,this.options.maxColor]];j(this.stops,function(b){b.color=a.Color(b[1])})},toColor:function(b,h){var e,c=this.stops,a,f=this.dataClasses,g,d;if(f)for(d=f.length;d--;){if(g=f[d],a=g.from,c=g.to,(a===void 0||b>=a)&&(c===void 0||b<=c)){e=g.color;if(h)h.dataClass=d;break}}else{this.isLog&&(b=this.val2lin(b));e=1-(this.max-b)/(this.max-this.min);for(d=c.length;d--;)if(e>c[d][0])break;a=c[d]||c[d+1];c=c[d+1]||a;e=1-(c[0]-e)/(c[0]-a[0]||1);e=this.tweenColors(a.color, 11 | c.color,e)}return e},tweenColors:function(b,a,e){var c=a.rgba[3]!==1||b.rgba[3]!==1;return b.rgba.length===0||a.rgba.length===0?"none":(c?"rgba(":"rgb(")+Math.round(a.rgba[0]+(b.rgba[0]-a.rgba[0])*(1-e))+","+Math.round(a.rgba[1]+(b.rgba[1]-a.rgba[1])*(1-e))+","+Math.round(a.rgba[2]+(b.rgba[2]-a.rgba[2])*(1-e))+(c?","+(a.rgba[3]+(b.rgba[3]-a.rgba[3])*(1-e)):"")+")"}};a.seriesTypes.solidgauge=a.extendClass(a.seriesTypes.gauge,{type:"solidgauge",bindAxes:function(){var b;a.seriesTypes.gauge.prototype.bindAxes.call(this); 12 | b=this.yAxis;a.extend(b,m);b.options.dataClasses&&b.initDataClasses(b.options);b.initStops(b.options)},drawPoints:function(){var b=this,h=b.yAxis,e=h.center,c=b.options,k=b.chart.renderer;a.each(b.points,function(f){var g=f.graphic,d=h.startAngleRad+h.translate(f.y,null,null,null,!0),i=o(p(c.radius,100))*e[2]/200,l=o(p(c.innerRadius,60))*e[2]/200,n=h.toColor(f.y,f),j;if(n!=="none")j=f.color,f.color=n;c.wrap===!1&&(d=Math.max(h.startAngleRad,Math.min(h.endAngleRad,d)));d=d*180/Math.PI;d={x:e[0],y:e[1], 13 | r:i,innerR:l,start:h.startAngleRad,end:d/(180/Math.PI)};g?(i=d.d,g.attr({fill:f.color}).animate(d,{step:function(b,c){g.attr("fill",m.tweenColors(a.Color(j),a.Color(n),c.pos))}}),d.d=i):f.graphic=k.arc(d).attr({stroke:c.borderColor||"none","stroke-width":c.borderWidth||0,fill:f.color}).add(b.group)})},animate:null})})(Highcharts); 14 | -------------------------------------------------------------------------------- /static/js/highcharts/themes/dark-unica.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Dark theme for Highcharts JS 3 | * @author Torstein Honsi 4 | */ 5 | 6 | // Load the fonts 7 | Highcharts.createElement('link', { 8 | href: 'http://fonts.googleapis.com/css?family=Unica+One', 9 | rel: 'stylesheet', 10 | type: 'text/css' 11 | }, null, document.getElementsByTagName('head')[0]); 12 | 13 | Highcharts.theme = { 14 | colors: ["#2b908f", "#90ee7e", "#f45b5b", "#7798BF", "#aaeeee", "#ff0066", "#eeaaee", 15 | "#55BF3B", "#DF5353", "#7798BF", "#aaeeee"], 16 | chart: { 17 | backgroundColor: { 18 | linearGradient: { x1: 0, y1: 0, x2: 1, y2: 1 }, 19 | stops: [ 20 | [0, '#2a2a2b'], 21 | [1, '#3e3e40'] 22 | ] 23 | }, 24 | style: { 25 | fontFamily: "'Unica One', sans-serif" 26 | }, 27 | plotBorderColor: '#606063' 28 | }, 29 | title: { 30 | style: { 31 | color: '#E0E0E3', 32 | textTransform: 'uppercase', 33 | fontSize: '20px' 34 | } 35 | }, 36 | subtitle: { 37 | style: { 38 | color: '#E0E0E3', 39 | textTransform: 'uppercase' 40 | } 41 | }, 42 | xAxis: { 43 | gridLineColor: '#707073', 44 | labels: { 45 | style: { 46 | color: '#E0E0E3' 47 | } 48 | }, 49 | lineColor: '#707073', 50 | minorGridLineColor: '#505053', 51 | tickColor: '#707073', 52 | title: { 53 | style: { 54 | color: '#A0A0A3' 55 | 56 | } 57 | } 58 | }, 59 | yAxis: { 60 | gridLineColor: '#707073', 61 | labels: { 62 | style: { 63 | color: '#E0E0E3' 64 | } 65 | }, 66 | lineColor: '#707073', 67 | minorGridLineColor: '#505053', 68 | tickColor: '#707073', 69 | tickWidth: 1, 70 | title: { 71 | style: { 72 | color: '#A0A0A3' 73 | } 74 | } 75 | }, 76 | tooltip: { 77 | backgroundColor: 'rgba(0, 0, 0, 0.85)', 78 | style: { 79 | color: '#F0F0F0' 80 | } 81 | }, 82 | plotOptions: { 83 | series: { 84 | dataLabels: { 85 | color: '#B0B0B3' 86 | }, 87 | marker: { 88 | lineColor: '#333' 89 | } 90 | }, 91 | boxplot: { 92 | fillColor: '#505053' 93 | }, 94 | candlestick: { 95 | lineColor: 'white' 96 | }, 97 | errorbar: { 98 | color: 'white' 99 | } 100 | }, 101 | legend: { 102 | itemStyle: { 103 | color: '#E0E0E3' 104 | }, 105 | itemHoverStyle: { 106 | color: '#FFF' 107 | }, 108 | itemHiddenStyle: { 109 | color: '#606063' 110 | } 111 | }, 112 | credits: { 113 | style: { 114 | color: '#666' 115 | } 116 | }, 117 | labels: { 118 | style: { 119 | color: '#707073' 120 | } 121 | }, 122 | 123 | drilldown: { 124 | activeAxisLabelStyle: { 125 | color: '#F0F0F3' 126 | }, 127 | activeDataLabelStyle: { 128 | color: '#F0F0F3' 129 | } 130 | }, 131 | 132 | navigation: { 133 | buttonOptions: { 134 | symbolStroke: '#DDDDDD', 135 | theme: { 136 | fill: '#505053' 137 | } 138 | } 139 | }, 140 | 141 | // scroll charts 142 | rangeSelector: { 143 | buttonTheme: { 144 | fill: '#505053', 145 | stroke: '#000000', 146 | style: { 147 | color: '#CCC' 148 | }, 149 | states: { 150 | hover: { 151 | fill: '#707073', 152 | stroke: '#000000', 153 | style: { 154 | color: 'white' 155 | } 156 | }, 157 | select: { 158 | fill: '#000003', 159 | stroke: '#000000', 160 | style: { 161 | color: 'white' 162 | } 163 | } 164 | } 165 | }, 166 | inputBoxBorderColor: '#505053', 167 | inputStyle: { 168 | backgroundColor: '#333', 169 | color: 'silver' 170 | }, 171 | labelStyle: { 172 | color: 'silver' 173 | } 174 | }, 175 | 176 | navigator: { 177 | handles: { 178 | backgroundColor: '#666', 179 | borderColor: '#AAA' 180 | }, 181 | outlineColor: '#CCC', 182 | maskFill: 'rgba(255,255,255,0.1)', 183 | series: { 184 | color: '#7798BF', 185 | lineColor: '#A6C7ED' 186 | }, 187 | xAxis: { 188 | gridLineColor: '#505053' 189 | } 190 | }, 191 | 192 | scrollbar: { 193 | barBackgroundColor: '#808083', 194 | barBorderColor: '#808083', 195 | buttonArrowColor: '#CCC', 196 | buttonBackgroundColor: '#606063', 197 | buttonBorderColor: '#606063', 198 | rifleColor: '#FFF', 199 | trackBackgroundColor: '#404043', 200 | trackBorderColor: '#404043' 201 | }, 202 | 203 | // special colors for some of the 204 | legendBackgroundColor: 'rgba(0, 0, 0, 0.5)', 205 | background2: '#505053', 206 | dataLabelsColor: '#B0B0B3', 207 | textColor: '#C0C0C0', 208 | contrastTextColor: '#F0F0F3', 209 | maskColor: 'rgba(255,255,255,0.3)' 210 | }; 211 | 212 | // Apply the theme 213 | Highcharts.setOptions(Highcharts.theme); 214 | -------------------------------------------------------------------------------- /static/js/highcharts/themes/grid-light.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Grid-light theme for Highcharts JS 3 | * @author Torstein Honsi 4 | */ 5 | 6 | // Load the fonts 7 | Highcharts.createElement('link', { 8 | href: 'http://fonts.googleapis.com/css?family=Dosis:400,600', 9 | rel: 'stylesheet', 10 | type: 'text/css' 11 | }, null, document.getElementsByTagName('head')[0]); 12 | 13 | Highcharts.theme = { 14 | colors: ["#7cb5ec", "#f7a35c", "#90ee7e", "#7798BF", "#aaeeee", "#ff0066", "#eeaaee", 15 | "#55BF3B", "#DF5353", "#7798BF", "#aaeeee"], 16 | chart: { 17 | backgroundColor: null, 18 | style: { 19 | fontFamily: "Dosis, sans-serif" 20 | } 21 | }, 22 | title: { 23 | style: { 24 | fontSize: '16px', 25 | fontWeight: 'bold', 26 | textTransform: 'uppercase' 27 | } 28 | }, 29 | tooltip: { 30 | borderWidth: 0, 31 | backgroundColor: 'rgba(219,219,216,0.8)', 32 | shadow: false 33 | }, 34 | legend: { 35 | itemStyle: { 36 | fontWeight: 'bold', 37 | fontSize: '13px' 38 | } 39 | }, 40 | xAxis: { 41 | gridLineWidth: 1, 42 | labels: { 43 | style: { 44 | fontSize: '12px' 45 | } 46 | } 47 | }, 48 | yAxis: { 49 | minorTickInterval: 'auto', 50 | title: { 51 | style: { 52 | textTransform: 'uppercase' 53 | } 54 | }, 55 | labels: { 56 | style: { 57 | fontSize: '12px' 58 | } 59 | } 60 | }, 61 | plotOptions: { 62 | candlestick: { 63 | lineColor: '#404048' 64 | } 65 | }, 66 | 67 | 68 | // General 69 | background2: '#F0F0EA' 70 | 71 | }; 72 | 73 | // Apply the theme 74 | Highcharts.setOptions(Highcharts.theme); 75 | -------------------------------------------------------------------------------- /static/js/highcharts/themes/grid.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Grid theme for Highcharts JS 3 | * @author Torstein Honsi 4 | */ 5 | 6 | Highcharts.theme = { 7 | colors: ['#058DC7', '#50B432', '#ED561B', '#DDDF00', '#24CBE5', '#64E572', '#FF9655', '#FFF263', '#6AF9C4'], 8 | chart: { 9 | backgroundColor: { 10 | linearGradient: { x1: 0, y1: 0, x2: 1, y2: 1 }, 11 | stops: [ 12 | [0, 'rgb(255, 255, 255)'], 13 | [1, 'rgb(240, 240, 255)'] 14 | ] 15 | }, 16 | borderWidth: 2, 17 | plotBackgroundColor: 'rgba(255, 255, 255, .9)', 18 | plotShadow: true, 19 | plotBorderWidth: 1 20 | }, 21 | title: { 22 | style: { 23 | color: '#000', 24 | font: 'bold 16px "Trebuchet MS", Verdana, sans-serif' 25 | } 26 | }, 27 | subtitle: { 28 | style: { 29 | color: '#666666', 30 | font: 'bold 12px "Trebuchet MS", Verdana, sans-serif' 31 | } 32 | }, 33 | xAxis: { 34 | gridLineWidth: 1, 35 | lineColor: '#000', 36 | tickColor: '#000', 37 | labels: { 38 | style: { 39 | color: '#000', 40 | font: '11px Trebuchet MS, Verdana, sans-serif' 41 | } 42 | }, 43 | title: { 44 | style: { 45 | color: '#333', 46 | fontWeight: 'bold', 47 | fontSize: '12px', 48 | fontFamily: 'Trebuchet MS, Verdana, sans-serif' 49 | 50 | } 51 | } 52 | }, 53 | yAxis: { 54 | minorTickInterval: 'auto', 55 | lineColor: '#000', 56 | lineWidth: 1, 57 | tickWidth: 1, 58 | tickColor: '#000', 59 | labels: { 60 | style: { 61 | color: '#000', 62 | font: '11px Trebuchet MS, Verdana, sans-serif' 63 | } 64 | }, 65 | title: { 66 | style: { 67 | color: '#333', 68 | fontWeight: 'bold', 69 | fontSize: '12px', 70 | fontFamily: 'Trebuchet MS, Verdana, sans-serif' 71 | } 72 | } 73 | }, 74 | legend: { 75 | itemStyle: { 76 | font: '9pt Trebuchet MS, Verdana, sans-serif', 77 | color: 'black' 78 | 79 | }, 80 | itemHoverStyle: { 81 | color: '#039' 82 | }, 83 | itemHiddenStyle: { 84 | color: 'gray' 85 | } 86 | }, 87 | labels: { 88 | style: { 89 | color: '#99b' 90 | } 91 | }, 92 | 93 | navigation: { 94 | buttonOptions: { 95 | theme: { 96 | stroke: '#CCCCCC' 97 | } 98 | } 99 | } 100 | }; 101 | 102 | // Apply the theme 103 | var highchartsOptions = Highcharts.setOptions(Highcharts.theme); 104 | -------------------------------------------------------------------------------- /static/js/highcharts/themes/sand-signika.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sand-Signika theme for Highcharts JS 3 | * @author Torstein Honsi 4 | */ 5 | 6 | // Load the fonts 7 | Highcharts.createElement('link', { 8 | href: 'http://fonts.googleapis.com/css?family=Signika:400,700', 9 | rel: 'stylesheet', 10 | type: 'text/css' 11 | }, null, document.getElementsByTagName('head')[0]); 12 | 13 | // Add the background image to the container 14 | Highcharts.wrap(Highcharts.Chart.prototype, 'getContainer', function (proceed) { 15 | proceed.call(this); 16 | this.container.style.background = 'url(http://www.highcharts.com/samples/graphics/sand.png)'; 17 | }); 18 | 19 | 20 | Highcharts.theme = { 21 | colors: ["#f45b5b", "#8085e9", "#8d4654", "#7798BF", "#aaeeee", "#ff0066", "#eeaaee", 22 | "#55BF3B", "#DF5353", "#7798BF", "#aaeeee"], 23 | chart: { 24 | backgroundColor: null, 25 | style: { 26 | fontFamily: "Signika, serif" 27 | } 28 | }, 29 | title: { 30 | style: { 31 | color: 'black', 32 | fontSize: '16px', 33 | fontWeight: 'bold' 34 | } 35 | }, 36 | subtitle: { 37 | style: { 38 | color: 'black' 39 | } 40 | }, 41 | tooltip: { 42 | borderWidth: 0 43 | }, 44 | legend: { 45 | itemStyle: { 46 | fontWeight: 'bold', 47 | fontSize: '13px' 48 | } 49 | }, 50 | xAxis: { 51 | labels: { 52 | style: { 53 | color: '#6e6e70' 54 | } 55 | } 56 | }, 57 | yAxis: { 58 | labels: { 59 | style: { 60 | color: '#6e6e70' 61 | } 62 | } 63 | }, 64 | plotOptions: { 65 | series: { 66 | shadow: true 67 | }, 68 | candlestick: { 69 | lineColor: '#404048' 70 | } 71 | }, 72 | 73 | // Highstock specific 74 | navigator: { 75 | xAxis: { 76 | gridLineColor: '#D0D0D8' 77 | } 78 | }, 79 | rangeSelector: { 80 | buttonTheme: { 81 | fill: 'white', 82 | stroke: '#C0C0C8', 83 | 'stroke-width': 1, 84 | states: { 85 | select: { 86 | fill: '#D0D0D8' 87 | } 88 | } 89 | } 90 | }, 91 | scrollbar: { 92 | trackBorderColor: '#C0C0C8' 93 | }, 94 | 95 | // General 96 | background2: '#E0E0E8' 97 | 98 | }; 99 | 100 | // Apply the theme 101 | Highcharts.setOptions(Highcharts.theme); 102 | -------------------------------------------------------------------------------- /static/js/highcharts/themes/skies.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Skies theme for Highcharts JS 3 | * @author Torstein Honsi 4 | */ 5 | 6 | Highcharts.theme = { 7 | colors: ["#514F78", "#42A07B", "#9B5E4A", "#72727F", "#1F949A", "#82914E", "#86777F", "#42A07B"], 8 | chart: { 9 | className: 'skies', 10 | borderWidth: 0, 11 | plotShadow: true, 12 | plotBackgroundImage: 'http://www.highcharts.com/demo/gfx/skies.jpg', 13 | plotBackgroundColor: { 14 | linearGradient: [0, 0, 250, 500], 15 | stops: [ 16 | [0, 'rgba(255, 255, 255, 1)'], 17 | [1, 'rgba(255, 255, 255, 0)'] 18 | ] 19 | }, 20 | plotBorderWidth: 1 21 | }, 22 | title: { 23 | style: { 24 | color: '#3E576F', 25 | font: '16px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 26 | } 27 | }, 28 | subtitle: { 29 | style: { 30 | color: '#6D869F', 31 | font: '12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 32 | } 33 | }, 34 | xAxis: { 35 | gridLineWidth: 0, 36 | lineColor: '#C0D0E0', 37 | tickColor: '#C0D0E0', 38 | labels: { 39 | style: { 40 | color: '#666', 41 | fontWeight: 'bold' 42 | } 43 | }, 44 | title: { 45 | style: { 46 | color: '#666', 47 | font: '12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 48 | } 49 | } 50 | }, 51 | yAxis: { 52 | alternateGridColor: 'rgba(255, 255, 255, .5)', 53 | lineColor: '#C0D0E0', 54 | tickColor: '#C0D0E0', 55 | tickWidth: 1, 56 | labels: { 57 | style: { 58 | color: '#666', 59 | fontWeight: 'bold' 60 | } 61 | }, 62 | title: { 63 | style: { 64 | color: '#666', 65 | font: '12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 66 | } 67 | } 68 | }, 69 | legend: { 70 | itemStyle: { 71 | font: '9pt Trebuchet MS, Verdana, sans-serif', 72 | color: '#3E576F' 73 | }, 74 | itemHoverStyle: { 75 | color: 'black' 76 | }, 77 | itemHiddenStyle: { 78 | color: 'silver' 79 | } 80 | }, 81 | labels: { 82 | style: { 83 | color: '#3E576F' 84 | } 85 | } 86 | }; 87 | 88 | // Apply the theme 89 | var highchartsOptions = Highcharts.setOptions(Highcharts.theme); 90 | -------------------------------------------------------------------------------- /static/js/layer/extend/layer.ext.js: -------------------------------------------------------------------------------- 1 | /*! layer弹层组件拓展类 */ 2 | ;!function(){layer.use("skin/layer.ext.css",function(){layer.layui_layer_extendlayerextjs=!0});var a=layer.cache||{},b=function(b){return a.skin?" "+a.skin+" "+a.skin+"-"+b:""};layer.prompt=function(a,c){a=a||{},"function"==typeof a&&(c=a);var d,e=2==a.formType?'":function(){return''}();return layer.open($.extend({btn:["确定","取消"],content:e,skin:"layui-layer-prompt"+b("prompt"),success:function(a){d=a.find(".layui-layer-input"),d.focus()},yes:function(b){var e=d.val();""===e?d.focus():e.length>(a.maxlength||500)?layer.tips("最多输入"+(a.maxlength||500)+"个字数",d,{tips:1}):c&&c(e,b,d)}},a))},layer.tab=function(a){a=a||{};var c=a.tab||{};return layer.open($.extend({type:1,skin:"layui-layer-tab"+b("tab"),title:function(){var a=c.length,b=1,d="";if(a>0)for(d=''+c[0].title+"";a>b;b++)d+=""+c[b].title+"";return d}(),content:'
    '+function(){var a=c.length,b=1,d="";if(a>0)for(d='
  • '+(c[0].content||"no content")+"
  • ";a>b;b++)d+='
  • '+(c[b].content||"no content")+"
  • ";return d}()+"
",success:function(a){var b=a.find(".layui-layer-title").children(),c=a.find(".layui-layer-tabmain").children();b.on("mousedown",function(a){a.stopPropagation?a.stopPropagation():a.cancelBubble=!0;var b=$(this),d=b.index();b.addClass("layui-layer-tabnow").siblings().removeClass("layui-layer-tabnow"),c.eq(d).show().siblings().hide()})}},a))},layer.photos=function(a,c,d){function e(a,b,c){var d=new Image;d.onload=function(){d.onload=null,b(d)},d.onerror=function(a){d.onerror=null,c(a)},d.src=a}var f={};if(a=a||{},a.photos){var g=a.photos.constructor===Object,h=g?a.photos:{},i=h.data||[],j=h.start||0;if(f.imgIndex=j+1,g){if(0===i.length)return void layer.msg("没有图片")}else{var k=$(a.photos),l=k.find(a.img||"img");if(0===l.length)return;if(c||k.find(h.img||"img").each(function(b){var c=$(this);i.push({alt:c.attr("alt"),pid:c.attr("layer-pid"),src:c.attr("layer-src")||c.attr("src"),thumb:c.attr("src")}),c.on("click",function(){layer.photos($.extend(a,{photos:{start:b,data:i,tab:a.tab},full:a.full}),!0)})}),!c)return}f.imgprev=function(a){f.imgIndex--,f.imgIndex<1&&(f.imgIndex=i.length),f.tabimg(a)},f.imgnext=function(a,b){f.imgIndex++,f.imgIndex>i.length&&(f.imgIndex=1,b)||f.tabimg(a)},f.keyup=function(a){if(!f.end){var b=a.keyCode;a.preventDefault(),37===b?f.imgprev(!0):39===b?f.imgnext(!0):27===b&&layer.close(f.index)}},f.tabimg=function(b){i.length<=1||(h.start=f.imgIndex-1,layer.close(f.index),layer.photos(a,!0,b))},f.event=function(){f.bigimg.hover(function(){f.imgsee.show()},function(){f.imgsee.hide()}),f.bigimg.find(".layui-layer-imgprev").on("click",function(a){a.preventDefault(),f.imgprev()}),f.bigimg.find(".layui-layer-imgnext").on("click",function(a){a.preventDefault(),f.imgnext()}),$(document).on("keyup",f.keyup)},f.loadi=layer.load(1,{shade:"shade"in a?!1:.9,scrollbar:!1}),e(i[j].src,function(c){layer.close(f.loadi),f.index=layer.open($.extend({type:1,area:function(){var b=[c.width,c.height],d=[$(window).width()-100,$(window).height()-100];return!a.full&&b[0]>d[0]&&(b[0]=d[0],b[1]=b[0]*d[1]/b[0]),[b[0]+"px",b[1]+"px"]}(),title:!1,shade:.9,shadeClose:!0,closeBtn:!1,move:".layui-layer-phimg img",moveType:1,scrollbar:!1,moveOut:!0,shift:5*Math.random()|0,skin:"layui-layer-photos"+b("photos"),content:'
'+(i[j].alt||
'+(i.length>1?'':"")+'
'+(i[j].alt||"")+""+f.imgIndex+"/"+i.length+"
",success:function(b,c){f.bigimg=b.find(".layui-layer-phimg"),f.imgsee=b.find(".layui-layer-imguide,.layui-layer-imgbar"),f.event(b),a.tab&&a.tab(i[j],b)},end:function(){f.end=!0,$(document).off("keyup",f.keyup)}},a))},function(){layer.close(f.loadi),layer.msg("当前图片地址异常
是否继续查看下一张?",{time:3e4,btn:["下一张","不看了"],yes:function(){i.length>1&&f.imgnext(!0,!0)}})})}}}(); -------------------------------------------------------------------------------- /static/js/layer/skin/default/icon-ext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/js/layer/skin/default/icon-ext.png -------------------------------------------------------------------------------- /static/js/layer/skin/default/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/js/layer/skin/default/icon.png -------------------------------------------------------------------------------- /static/js/layer/skin/default/loading-0.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/js/layer/skin/default/loading-0.gif -------------------------------------------------------------------------------- /static/js/layer/skin/default/loading-1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/js/layer/skin/default/loading-1.gif -------------------------------------------------------------------------------- /static/js/layer/skin/default/loading-2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/js/layer/skin/default/loading-2.gif -------------------------------------------------------------------------------- /static/js/layer/skin/layer.ext.css: -------------------------------------------------------------------------------- 1 | /*! 2 | 3 | @Name: layer拓展样式 4 | @Date: 2012.12.13 5 | @Author: 贤心 6 | @blog: sentsin.com 7 | 8 | */.layui-layer-imgbar,.layui-layer-imgtit a,.layui-layer-tab .layui-layer-title span{text-overflow:ellipsis;white-space:nowrap}.layui-layer-iconext{background:url(default/icon-ext.png) no-repeat}html #layui_layer_skinlayerextcss{display:none;position:absolute;width:1989px}.layui-layer-prompt .layui-layer-input{display:block;width:220px;height:30px;margin:0 auto;line-height:30px;padding:0 5px;border:1px solid #ccc;box-shadow:1px 1px 5px rgba(0,0,0,.1) inset;color:#333}.layui-layer-prompt textarea.layui-layer-input{width:300px;height:100px;line-height:20px}.layui-layer-tab{box-shadow:1px 1px 50px rgba(0,0,0,.4)}.layui-layer-tab .layui-layer-title{padding-left:0;border-bottom:1px solid #ccc;background-color:#eee;overflow:visible}.layui-layer-tab .layui-layer-title span{position:relative;float:left;min-width:80px;max-width:260px;padding:0 20px;text-align:center;cursor:default;overflow:hidden}.layui-layer-tab .layui-layer-title span.layui-layer-tabnow{height:43px;border-left:1px solid #ccc;border-right:1px solid #ccc;background-color:#fff;z-index:10}.layui-layer-tab .layui-layer-title span:first-child{border-left:none}.layui-layer-tabmain{line-height:24px;clear:both}.layui-layer-tabmain .layui-layer-tabli{display:none}.layui-layer-tabmain .layui-layer-tabli.xubox_tab_layer{display:block}.xubox_tabclose{position:absolute;right:10px;top:5px;cursor:pointer}.layui-layer-photos{-webkit-animation-duration:1s;animation-duration:1s;background:url(default/xubox_loading1.gif) center center no-repeat #000}.layui-layer-photos .layui-layer-content{overflow:hidden;text-align:center}.layui-layer-photos .layui-layer-phimg img{position:relative;width:100%;display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-imgbar,.layui-layer-imguide{display:none}.layui-layer-imgnext,.layui-layer-imgprev{position:absolute;top:50%;width:27px;_width:44px;height:44px;margin-top:-22px;outline:0;blr:expression(this.onFocus=this.blur())}.layui-layer-imgprev{left:10px;background-position:-5px -5px;_background-position:-70px -5px}.layui-layer-imgprev:hover{background-position:-33px -5px;_background-position:-120px -5px}.layui-layer-imgnext{right:10px;_right:8px;background-position:-5px -50px;_background-position:-70px -50px}.layui-layer-imgnext:hover{background-position:-33px -50px;_background-position:-120px -50px}.layui-layer-imgbar{position:absolute;left:0;bottom:0;width:100%;height:32px;line-height:32px;background-color:rgba(0,0,0,.8);background-color:#000\9;filter:Alpha(opacity=80);color:#fff;overflow:hidden;font-size:0}.layui-layer-imgtit *{display:inline-block;*display:inline;*zoom:1;vertical-align:top;font-size:12px}.layui-layer-imgtit a{max-width:65%;overflow:hidden;color:#fff}.layui-layer-imgtit a:hover{color:#fff;text-decoration:underline}.layui-layer-imgtit em{padding-left:10px;font-style:normal} -------------------------------------------------------------------------------- /static/js/mindmup-editabletable.js: -------------------------------------------------------------------------------- 1 | /*global $, window*/ 2 | $.fn.editableTableWidget = function (options) { 3 | 'use strict'; 4 | return $(this).each(function () { 5 | var buildDefaultOptions = function () { 6 | var opts = $.extend({}, $.fn.editableTableWidget.defaultOptions); 7 | opts.editor = opts.editor.clone(); 8 | return opts; 9 | }, 10 | activeOptions = $.extend(buildDefaultOptions(), options), 11 | ARROW_LEFT = 37, ARROW_UP = 38, ARROW_RIGHT = 39, ARROW_DOWN = 40, ENTER = 13, ESC = 27, TAB = 9, 12 | element = $(this), 13 | editor = activeOptions.editor.css('position', 'absolute').hide().appendTo(element.parent()), 14 | active, 15 | showEditor = function (select) { 16 | active = element.find('td:focus'); 17 | if (active.length) { 18 | editor.val(active.text()) 19 | .removeClass('error') 20 | .show() 21 | .offset(active.offset()) 22 | .css(active.css(activeOptions.cloneProperties)) 23 | .width(active.width()) 24 | .height(active.height()) 25 | .focus(); 26 | if (select) { 27 | editor.select(); 28 | } 29 | } 30 | }, 31 | setActiveText = function () { 32 | var text = editor.val(), 33 | evt = $.Event('change'), 34 | originalContent; 35 | if (active.text() === text || editor.hasClass('error')) { 36 | return true; 37 | } 38 | originalContent = active.html(); 39 | active.text(text).trigger(evt, text); 40 | if (evt.result === false) { 41 | active.html(originalContent); 42 | } 43 | }, 44 | movement = function (element, keycode) { 45 | if (keycode === ARROW_RIGHT) { 46 | return element.next('td'); 47 | } else if (keycode === ARROW_LEFT) { 48 | return element.prev('td'); 49 | } else if (keycode === ARROW_UP) { 50 | return element.parent().prev().children().eq(element.index()); 51 | } else if (keycode === ARROW_DOWN) { 52 | return element.parent().next().children().eq(element.index()); 53 | } 54 | return []; 55 | }; 56 | editor.blur(function () { 57 | setActiveText(); 58 | editor.hide(); 59 | }).keydown(function (e) { 60 | if (e.which === ENTER) { 61 | setActiveText(); 62 | editor.hide(); 63 | active.focus(); 64 | e.preventDefault(); 65 | e.stopPropagation(); 66 | } else if (e.which === ESC) { 67 | editor.val(active.text()); 68 | e.preventDefault(); 69 | e.stopPropagation(); 70 | editor.hide(); 71 | active.focus(); 72 | } else if (e.which === TAB) { 73 | active.focus(); 74 | } else if (this.selectionEnd - this.selectionStart === this.value.length) { 75 | var possibleMove = movement(active, e.which); 76 | if (possibleMove.length > 0) { 77 | possibleMove.focus(); 78 | e.preventDefault(); 79 | e.stopPropagation(); 80 | } 81 | } 82 | }) 83 | .on('input paste', function () { 84 | var evt = $.Event('validate'); 85 | active.trigger(evt, editor.val()); 86 | if (evt.result === false) { 87 | editor.addClass('error'); 88 | } else { 89 | editor.removeClass('error'); 90 | } 91 | }); 92 | //element.on('click keypress dblclick', showEditor) 93 | element.find("td:not([data-editable='false'])").on('click keypress dblclick', showEditor) 94 | .css('cursor', 'pointer') 95 | .keydown(function (e) { 96 | var prevent = true, 97 | possibleMove = movement($(e.target), e.which); 98 | if (possibleMove.length > 0) { 99 | possibleMove.focus(); 100 | } else if (e.which === ENTER) { 101 | showEditor(false); 102 | } else if (e.which === 17 || e.which === 91 || e.which === 93) { 103 | showEditor(true); 104 | prevent = false; 105 | } else { 106 | prevent = false; 107 | } 108 | if (prevent) { 109 | e.stopPropagation(); 110 | e.preventDefault(); 111 | } 112 | }); 113 | 114 | //element.find('td').prop('tabindex', 1); 115 | element.find("td:not([data-editable='false'])").prop('tabindex', 1); 116 | 117 | $(window).on('resize', function () { 118 | if (editor.is(':visible')) { 119 | editor.offset(active.offset()) 120 | .width(active.width()) 121 | .height(active.height()); 122 | } 123 | }); 124 | }); 125 | 126 | }; 127 | $.fn.editableTableWidget.defaultOptions = { 128 | cloneProperties: ['padding', 'padding-top', 'padding-bottom', 'padding-left', 'padding-right', 129 | 'text-align', 'font', 'font-size', 'font-family', 'font-weight', 130 | 'border', 'border-top', 'border-bottom', 'border-left', 'border-right'], 131 | editor: $('') 132 | }; 133 | 134 | -------------------------------------------------------------------------------- /static/js/plugins/metisMenu/jquery.metisMenu.js: -------------------------------------------------------------------------------- 1 | /* 2 | * metismenu - v1.1.3 3 | * Easy menu jQuery plugin for Twitter Bootstrap 3 4 | * https://github.com/onokumus/metisMenu 5 | * 6 | * Made by Osman Nuri Okumus 7 | * Under MIT License 8 | */ 9 | ;(function($, window, document, undefined) { 10 | 11 | var pluginName = "metisMenu", 12 | defaults = { 13 | toggle: true, 14 | doubleTapToGo: false 15 | }; 16 | 17 | function Plugin(element, options) { 18 | this.element = $(element); 19 | this.settings = $.extend({}, defaults, options); 20 | this._defaults = defaults; 21 | this._name = pluginName; 22 | this.init(); 23 | } 24 | 25 | Plugin.prototype = { 26 | init: function() { 27 | 28 | var $this = this.element, 29 | $toggle = this.settings.toggle, 30 | obj = this; 31 | 32 | if (this.isIE() <= 9) { 33 | $this.find("li.active").has("ul").children("ul").collapse("show"); 34 | $this.find("li").not(".active").has("ul").children("ul").collapse("hide"); 35 | } else { 36 | $this.find("li.active").has("ul").children("ul").addClass("collapse in"); 37 | $this.find("li").not(".active").has("ul").children("ul").addClass("collapse"); 38 | } 39 | 40 | //add the "doubleTapToGo" class to active items if needed 41 | if (obj.settings.doubleTapToGo) { 42 | $this.find("li.active").has("ul").children("a").addClass("doubleTapToGo"); 43 | } 44 | 45 | $this.find("li").has("ul").children("a").on("click" + "." + pluginName, function(e) { 46 | e.preventDefault(); 47 | 48 | //Do we need to enable the double tap 49 | if (obj.settings.doubleTapToGo) { 50 | 51 | //if we hit a second time on the link and the href is valid, navigate to that url 52 | if (obj.doubleTapToGo($(this)) && $(this).attr("href") !== "#" && $(this).attr("href") !== "") { 53 | e.stopPropagation(); 54 | document.location = $(this).attr("href"); 55 | return; 56 | } 57 | } 58 | 59 | $(this).parent("li").toggleClass("active").children("ul").collapse("toggle"); 60 | 61 | if ($toggle) { 62 | $(this).parent("li").siblings().removeClass("active").children("ul.in").collapse("hide"); 63 | } 64 | 65 | }); 66 | }, 67 | 68 | isIE: function() { //https://gist.github.com/padolsey/527683 69 | var undef, 70 | v = 3, 71 | div = document.createElement("div"), 72 | all = div.getElementsByTagName("i"); 73 | 74 | while ( 75 | div.innerHTML = "", 76 | all[0] 77 | ) { 78 | return v > 4 ? v : undef; 79 | } 80 | }, 81 | 82 | //Enable the link on the second click. 83 | doubleTapToGo: function(elem) { 84 | var $this = this.element; 85 | 86 | //if the class "doubleTapToGo" exists, remove it and return 87 | if (elem.hasClass("doubleTapToGo")) { 88 | elem.removeClass("doubleTapToGo"); 89 | return true; 90 | } 91 | 92 | //does not exists, add a new class and return false 93 | if (elem.parent().children("ul").length) { 94 | //first remove all other class 95 | $this.find(".doubleTapToGo").removeClass("doubleTapToGo"); 96 | //add the class on the current element 97 | elem.addClass("doubleTapToGo"); 98 | return false; 99 | } 100 | }, 101 | 102 | remove: function() { 103 | this.element.off("." + pluginName); 104 | this.element.removeData(pluginName); 105 | } 106 | 107 | }; 108 | 109 | $.fn[pluginName] = function(options) { 110 | this.each(function () { 111 | var el = $(this); 112 | if (el.data(pluginName)) { 113 | el.data(pluginName).remove(); 114 | } 115 | el.data(pluginName, new Plugin(this, options)); 116 | }); 117 | return this; 118 | }; 119 | 120 | })(jQuery, window, document); -------------------------------------------------------------------------------- /static/js/plugins/peity/jquery.peity.min.js: -------------------------------------------------------------------------------- 1 | // Peity jQuery plugin version 2.0.3 2 | // (c) 2014 Ben Pickles 3 | // 4 | // http://benpickles.github.io/peity 5 | // 6 | // Released under MIT license. 7 | (function(e,q,h){var o=function(a,b){var c=q.createElementNS("http://www.w3.org/2000/svg",a);e.each(b,function(a,b){c.setAttribute(a,b)});return c},t="createElementNS"in q&&o("svg",{}).createSVGRect,r=1/(window.devicePixelRatio||1),j=e.fn.peity=function(a,b){t&&this.each(function(){var c=e(this),d=c.data("peity");if(d)a&&(d.type=a),e.extend(d.opts,b);else{var f=j.defaults[a],g={};e.each(c.data(),function(a,b){a in f&&(g[a]=b)});var h=e.extend({},f,g,b),d=new s(c,a,h);c.change(function(){d.draw()}).data("peity", 8 | d)}d.draw()});return this},s=function(a,b,c){this.$el=a;this.type=b;this.opts=c},m=s.prototype;m.draw=function(){j.graphers[this.type].call(this,this.opts)};m.fill=function(){var a=this.opts.fill,b=a;e.isFunction(b)||(b=function(b,d){return a[d%a.length]});return b};m.prepare=function(a,b){var c;this.svg?c=e(this.svg).empty():(this.svg=o("svg",{"class":"peity"}),this.$el.hide().after(this.svg),c=e(this.svg).data("peity",this));this.svg.setAttribute("height",b);this.svg.setAttribute("width",a);return c}; 9 | m.values=function(){return e.map(this.$el.text().split(this.opts.delimiter),function(a){return parseFloat(a)})};j.defaults={};j.graphers={};j.register=function(a,b,c){this.defaults[a]=b;this.graphers[a]=c};j.register("pie",{delimiter:null,diameter:16,fill:["#ff9900","#fff4dd","#ffc66e"]},function(a){if(!a.delimiter){var b=this.$el.text().match(/[^0-9\.]/);a.delimiter=b?b[0]:","}b=this.values();if("/"==a.delimiter)var c=b[0],b=[c,h.max(0,b[1]-c)];for(var d=0,c=b.length,f=0;de?1:0,1,q,r,"Z"].join(" ")});i=l}k.setAttribute("fill",j.call(this,n,d,b));this.svg.appendChild(k)}}});j.register("line",{delimiter:",",fill:"#c6d9fd",height:16,max:null, 11 | min:0,stroke:"#4d89f9",strokeWidth:1,width:32},function(a){var b=this.values();1==b.length&&b.push(b[0]);for(var c=h.max.apply(h,b.concat([a.max])),d=h.min.apply(h,b.concat([a.min])),f=this.prepare(a.width,a.height),g=f.width(),f=f.height()-a.strokeWidth,e=g/(b.length-1),c=c-d,j=0==c?f:f/c,m=f+d*j,c=[0,m],i=0;i=d&&0k&&(l+=k,k=-k);n=o("rect",{fill:m.call(this,n,i,b),x:i*g,y:l,width:g-a,height:k});this.svg.appendChild(n)}})})(jQuery,document,Math); 14 | -------------------------------------------------------------------------------- /static/js/plugins/slimscroll/jquery.slimscroll.min.js: -------------------------------------------------------------------------------- 1 | /*! Copyright (c) 2011 Piotr Rochala (http://rocha.la) 2 | * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 3 | * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. 4 | * 5 | * Version: 1.3.0 6 | * 7 | */ 8 | (function(f){jQuery.fn.extend({slimScroll:function(h){var a=f.extend({width:"auto",height:"250px",size:"7px",color:"#000",position:"right",distance:"1px",start:"top",opacity:0.4,alwaysVisible:!1,disableFadeOut:!1,railVisible:!1,railColor:"#333",railOpacity:0.2,railDraggable:!0,railClass:"slimScrollRail",barClass:"slimScrollBar",wrapperClass:"slimScrollDiv",allowPageScroll:!1,wheelStep:20,touchScrollStep:200,borderRadius:"7px",railBorderRadius:"7px"},h);this.each(function(){function r(d){if(s){d=d|| 9 | window.event;var c=0;d.wheelDelta&&(c=-d.wheelDelta/120);d.detail&&(c=d.detail/3);f(d.target||d.srcTarget||d.srcElement).closest("."+a.wrapperClass).is(b.parent())&&m(c,!0);d.preventDefault&&!k&&d.preventDefault();k||(d.returnValue=!1)}}function m(d,f,h){k=!1;var e=d,g=b.outerHeight()-c.outerHeight();f&&(e=parseInt(c.css("top"))+d*parseInt(a.wheelStep)/100*c.outerHeight(),e=Math.min(Math.max(e,0),g),e=0=b.outerHeight()?k=!0:(c.stop(!0,!0).fadeIn("fast"),a.railVisible&&g.stop(!0,!0).fadeIn("fast"))}function p(){a.alwaysVisible||(A=setTimeout(function(){a.disableFadeOut&&s||(x||y)||(c.fadeOut("slow"),g.fadeOut("slow"))},1E3))}var s,x,y,A,z,u,l,B,D=30,k=!1,b=f(this);if(b.parent().hasClass(a.wrapperClass)){var n=b.scrollTop(), 12 | c=b.parent().find("."+a.barClass),g=b.parent().find("."+a.railClass);w();if(f.isPlainObject(h)){if("height"in h&&"auto"==h.height){b.parent().css("height","auto");b.css("height","auto");var q=b.parent().parent().height();b.parent().css("height",q);b.css("height",q)}if("scrollTo"in h)n=parseInt(a.scrollTo);else if("scrollBy"in h)n+=parseInt(a.scrollBy);else if("destroy"in h){c.remove();g.remove();b.unwrap();return}m(n,!1,!0)}}else{a.height="auto"==a.height?b.parent().height():a.height;n=f("
").addClass(a.wrapperClass).css({position:"relative", 13 | overflow:"hidden",width:a.width,height:a.height});b.css({overflow:"hidden",width:a.width,height:a.height});var g=f("
").addClass(a.railClass).css({width:a.size,height:"100%",position:"absolute",top:0,display:a.alwaysVisible&&a.railVisible?"block":"none","border-radius":a.railBorderRadius,background:a.railColor,opacity:a.railOpacity,zIndex:90}),c=f("
").addClass(a.barClass).css({background:a.color,width:a.size,position:"absolute",top:0,opacity:a.opacity,display:a.alwaysVisible? 14 | "block":"none","border-radius":a.borderRadius,BorderRadius:a.borderRadius,MozBorderRadius:a.borderRadius,WebkitBorderRadius:a.borderRadius,zIndex:99}),q="right"==a.position?{right:a.distance}:{left:a.distance};g.css(q);c.css(q);b.wrap(n);b.parent().append(c);b.parent().append(g);a.railDraggable&&c.bind("mousedown",function(a){var b=f(document);y=!0;t=parseFloat(c.css("top"));pageY=a.pageY;b.bind("mousemove.slimscroll",function(a){currTop=t+a.pageY-pageY;c.css("top",currTop);m(0,c.position().top,!1)}); 15 | b.bind("mouseup.slimscroll",function(a){y=!1;p();b.unbind(".slimscroll")});return!1}).bind("selectstart.slimscroll",function(a){a.stopPropagation();a.preventDefault();return!1});g.hover(function(){v()},function(){p()});c.hover(function(){x=!0},function(){x=!1});b.hover(function(){s=!0;v();p()},function(){s=!1;p()});b.bind("touchstart",function(a,b){a.originalEvent.touches.length&&(z=a.originalEvent.touches[0].pageY)});b.bind("touchmove",function(b){k||b.originalEvent.preventDefault();b.originalEvent.touches.length&& 16 | (m((z-b.originalEvent.touches[0].pageY)/a.touchScrollStep,!0),z=b.originalEvent.touches[0].pageY)});w();"bottom"===a.start?(c.css({top:b.outerHeight()-c.outerHeight()}),m(0,!0)):"top"!==a.start&&(m(f(a.start).position().top,null,!0),a.alwaysVisible||c.hide());C()}});return this}});jQuery.fn.extend({slimscroll:jQuery.fn.slimScroll})})(jQuery); -------------------------------------------------------------------------------- /static/js/validator/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/js/validator/images/loading.gif -------------------------------------------------------------------------------- /static/js/validator/images/validator_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/js/validator/images/validator_default.png -------------------------------------------------------------------------------- /static/js/validator/images/validator_simple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibuler/jumpserver/0aa43c7cabc012cf02f39826fdce80f4b7b7654b/static/js/validator/images/validator_simple.png -------------------------------------------------------------------------------- /static/js/wssh.js: -------------------------------------------------------------------------------- 1 | /* 2 | WSSH Javascript Client 3 | 4 | Usage: 5 | 6 | var client = new WSSHClient(); 7 | 8 | client.connect({ 9 | // Connection and authentication parameters 10 | username: 'root', 11 | hostname: 'localhost', 12 | authentication_method: 'password', // can either be password or private_key 13 | password: 'secretpassword', // do not provide when using private_key 14 | key_passphrase: 'secretpassphrase', // *may* be provided if the private_key is encrypted 15 | 16 | // Callbacks 17 | onError: function(error) { 18 | // Called upon an error 19 | console.error(error); 20 | }, 21 | onConnect: function() { 22 | // Called after a successful connection to the server 23 | console.debug('Connected!'); 24 | 25 | client.send('ls\n'); // You can send data back to the server by using WSSHClient.send() 26 | }, 27 | onClose: function() { 28 | // Called when the remote closes the connection 29 | console.debug('Connection Reset By Peer'); 30 | }, 31 | onData: function(data) { 32 | // Called when data is received from the server 33 | console.debug('Received: ' + data); 34 | } 35 | }); 36 | 37 | */ 38 | 39 | function WSSHClient() { 40 | } 41 | 42 | WSSHClient.prototype._generateEndpoint = function(options) { 43 | console.log(options); 44 | if (window.location.protocol == 'https:') { 45 | var protocol = 'wss://'; 46 | } else { 47 | var protocol = 'ws://'; 48 | } 49 | 50 | var endpoint = protocol + window.location.host + ':8080' + '/terminal'; 51 | return endpoint; 52 | }; 53 | 54 | WSSHClient.prototype.connect = function(options) { 55 | var endpoint = this._generateEndpoint(options); 56 | 57 | if (window.WebSocket) { 58 | this._connection = new WebSocket(endpoint); 59 | } 60 | else if (window.MozWebSocket) { 61 | this._connection = MozWebSocket(endpoint); 62 | } 63 | else { 64 | options.onError('WebSocket Not Supported'); 65 | return ; 66 | } 67 | 68 | this._connection.onopen = function() { 69 | options.onConnect(); 70 | }; 71 | 72 | this._connection.onmessage = function (evt) { 73 | var data = JSON.parse(evt.data.toString()); 74 | if (data.error !== undefined) { 75 | options.onError(data.error); 76 | } 77 | else { 78 | options.onData(data.data); 79 | } 80 | }; 81 | 82 | this._connection.onclose = function(evt) { 83 | options.onClose(); 84 | }; 85 | }; 86 | 87 | WSSHClient.prototype.send = function(data) { 88 | this._connection.send(JSON.stringify({'data': data})); 89 | }; 90 | -------------------------------------------------------------------------------- /templates/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Jumpserver | 404 Error 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 |

404

24 |

Page Not Found

25 |
26 | Sorry, but the page you are looking for has note been found. Try checking the URL for error, then hit the refresh button on your browser or try found something else in our app. 27 |
28 |
29 | 30 |
31 | 32 |
33 |
34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /templates/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Jumpserver | 500 Error 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 |

500

24 |

Internal Server Error

25 | 26 |
27 | The server encountered something unexpected that didn't allow it to complete the request. We apologize.
28 | You can go back to main page:
Dashboard 29 |
30 |
31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Jumpserver | 开源跳板机系统 9 | 10 | 11 | {% include 'link_css.html' %} 12 | {% include 'head_script.html' %} 13 | {% block self_head_css_js %} {% endblock %} 14 | 15 | 16 | 17 | 18 |
19 | {% include 'nav.html' %} 20 |
21 |
22 | {% include 'nav_bar_header.html' %} 23 |
24 | {% block content %}{% endblock %} 25 | {% include 'footer.html' %} 26 |
27 |
28 | 29 | 30 | {% include 'foot_script.html' %} 31 | {% block self_footer_js %} {% endblock %} 32 | 33 | -------------------------------------------------------------------------------- /templates/download.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% load mytags %} 3 | {% block self_head_css_js %} 4 | 5 | 6 | 7 | {% endblock %} 8 | {% block content %} 9 | {% include 'nav_cat_bar.html' %} 10 | 11 |
12 |
13 |
14 |
15 |
16 |
下载文件
17 | 28 |
29 |
30 |
31 | {% if error %} 32 |
{{ error }}
33 | {% endif %} 34 | {% if msg %} 35 |
{{ msg }}
36 | {% endif %} 37 |
38 | 39 |
40 | 41 |
42 |
43 |
44 |
45 | 46 |
47 | 52 |
53 |
54 |
55 |
56 | 57 | 58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | {% endblock %} 67 | 68 | {% block self_footer_js %} 69 | 82 | {% endblock %} -------------------------------------------------------------------------------- /templates/error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Jumpserver | 500 Error 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 |

Error

24 |

{{ message }}

25 |

26 |
27 | The server encountered something unexpected that didn't allow it to complete the request. We apologize.
28 | You can go back to main page:
首页 29 |
30 |
31 | 32 | 33 | 34 | 35 | 36 | 37 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /templates/filter_ajax_api.html: -------------------------------------------------------------------------------- 1 | {% for object in contact_list %} 2 | {% ifequal attr "asset" %} 3 | 4 | {% else %} 5 | 6 | {% endifequal %} 7 | 8 | 9 | {% endfor %} -------------------------------------------------------------------------------- /templates/foot_script.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 42 | -------------------------------------------------------------------------------- /templates/footer.html: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /templates/head_script.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /templates/jasset/asset_add_batch.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% block content %} 3 | {% include 'nav_cat_bar.html' %} 4 | 9 |
10 |
11 |
12 |
13 |
14 |
填写主机基本信息
15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 |
28 |
29 | 30 |
31 |
32 |
33 | 37 |
38 |
39 |
40 | {% if emg %} 41 |
{{ emg }}
42 | {% endif %} 43 | {% if smg %} 44 |
{{ smg }}
45 | {% endif %} 46 |

请下载Excel文件, 按照格式填写主机信息, 上传导入. 点击下载模板

47 |
48 |
49 | 50 | 51 | 52 | 53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | 64 | {% endblock %} -------------------------------------------------------------------------------- /templates/jasset/asset_excel_download.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | Nice! excel文件已生成请点击 下载 5 |
6 |
-------------------------------------------------------------------------------- /templates/jasset/asset_update_status.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | {% load bootstrap %} 16 | {% block content %} 17 | 18 |
19 |
20 |
21 |
22 |

23 |
24 |
25 |
26 |
27 | 28 | 43 | {% endblock content %} 44 | 45 | -------------------------------------------------------------------------------- /templates/jasset/error.html: -------------------------------------------------------------------------------- 1 | {% for field in af_form %} 2 |
{{ field.errors }}
3 | {{ field.label_tag }}: {{ field }} 4 | {% endfor %} 5 | 6 | 7 | {% if af.errors %} 8 |
    9 | {% for error in af.errors %} 10 |
  • {{ error }}
  • 11 | {% endfor %} 12 |
13 | {% endif %} -------------------------------------------------------------------------------- /templates/jasset/idc_add.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% block content %} 3 | {% load bootstrap %} 4 | {% include 'nav_cat_bar.html' %} 5 |
6 |
7 |
8 |
9 |
10 |
填写IDC基本信息
11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | 20 | 21 | 22 | 23 |
24 |
25 | 26 |
27 | {% if emg %} 28 |
{{ emg }}
29 | {% endif %} 30 | {% if smg %} 31 |
{{ smg }}
32 | {% endif %} 33 |
34 | {{ idc_form.name|bootstrap_horizontal }} 35 | 36 |
37 | {{ idc_form.bandwidth|bootstrap_horizontal }} 38 | 39 |
40 | {{ idc_form.operator|bootstrap_horizontal }} 41 | 42 |
43 | {{ idc_form.linkman|bootstrap_horizontal }} 44 | 45 |
46 | {{ idc_form.phone|bootstrap_horizontal }} 47 | 48 |
49 | {{ idc_form.address|bootstrap_horizontal }} 50 | 51 |
52 | {{ idc_form.network|bootstrap_horizontal }} 53 | 54 |
55 | {{ idc_form.comment|bootstrap_horizontal }} 56 | 57 |
58 |
59 |
60 | 61 | 62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | 71 | 94 | 95 | {% endblock %} -------------------------------------------------------------------------------- /templates/jasset/idc_edit.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% block content %} 3 | {% load bootstrap %} 4 | {% include 'nav_cat_bar.html' %} 5 |
6 |
7 |
8 |
9 |
10 |
填写IDC基本信息
11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | 24 | 25 | 26 | 27 |
28 |
29 | 30 |
31 | {% if emg %} 32 |
{{ emg }}
33 | {% endif %} 34 | {% if smg %} 35 |
{{ smg }}
36 | {% endif %} 37 |
38 | {{ idc_form.name|bootstrap_horizontal }} 39 | 40 |
41 | {{ idc_form.bandwidth|bootstrap_horizontal }} 42 | 43 |
44 | {{ idc_form.operator|bootstrap_horizontal }} 45 | 46 |
47 | {{ idc_form.linkman|bootstrap_horizontal }} 48 | 49 |
50 | {{ idc_form.phone|bootstrap_horizontal }} 51 | 52 |
53 | {{ idc_form.address|bootstrap_horizontal }} 54 | 55 |
56 | {{ idc_form.network|bootstrap_horizontal }} 57 | 58 |
59 | {{ idc_form.comment|bootstrap_horizontal }} 60 | 61 |
62 |
63 |
64 | 65 | 66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | 75 | 98 | 99 | {% endblock %} -------------------------------------------------------------------------------- /templates/jasset/show_all_ajax.html: -------------------------------------------------------------------------------- 1 | {% load mytags %} 2 | {% ifequal env 'group' %} 3 | {{ host.bis_group.all|group_dept_all }} 4 | {% endifequal %} 5 | {% ifequal env 'dept' %} 6 | {{ host.dept.all|group_dept_all }} 7 | {% endifequal %} -------------------------------------------------------------------------------- /templates/jasset/test.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /templates/jlog/base.jinja2: -------------------------------------------------------------------------------- 1 | 2 | {% block head %}{% endblock %} 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | 12 | -5x +5x 14 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /templates/jlog/dynamic.jinja2: -------------------------------------------------------------------------------- 1 | {% extends "base.jinja2" %} 2 | {% block head %} 3 | 4 | 5 | 11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /templates/jlog/log_search.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | {% for post in contacts.object_list %} 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | {% endfor %} 27 | 28 |
用户名 所属部门 登录主机 来源IP 命令统计 登录时间 结束时间
{{ post.user }} {{ post.dept_name }} {{ post.host }} {{ post.remote_ip }} 命令统计 {{ post.start_time|date:"Y-m-d H:i:s"}} {{ post.end_time|date:"Y-m-d H:i:s" }}
29 |
30 |
31 | {% include 'paginator.html' %} 32 |
33 |
-------------------------------------------------------------------------------- /templates/jperm/perm_log.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% load mytags %} 3 | {% block content %} 4 | {% include 'nav_cat_bar.html' %} 5 | 6 |
7 |
8 |
9 |
10 |
11 |
查看小组
12 | 23 |
24 | 25 |
26 |
27 | 37 |
38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | {% for log in logs %} 50 | 51 | 52 | 53 | 58 | 59 | 60 | {% endfor %} 61 | 62 |
日期动作成功完成
{{ log.datetime | date:"Y-n-d G:i:s" }} {{ log.action }} 54 | 55 | {{ log.is_success | yesno:"是,否,为止" }} 56 | 57 | {{ log.is_finish | yesno:"是,否,为止" }}
63 |
64 |
65 |
66 | Showing {{ users.start_index }} to {{ users.end_index }} of {{ p.count }} entries 67 |
68 |
69 | {% include 'paginator.html' %} 70 |
71 |
72 |
73 |
74 |
75 |
76 | 77 | {% endblock %} 78 | 79 | {% block self_footer_js %} 80 | 87 | 88 | {% endblock %} -------------------------------------------------------------------------------- /templates/jperm/perm_sudo_add.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% load mytags %} 3 | {% block content %} 4 | {% include 'nav_cat_bar.html' %} 5 |
6 |
7 |
8 |
9 |
10 |
填写基本信息
11 | 22 |
23 |
24 |
25 | {% if error %} 26 |
{{ error }}
27 | {% endif %} 28 | {% if msg %} 29 |
{{ msg }}
30 | {% endif %} 31 |
32 | 33 |
34 | 35 |
36 |
37 |
38 |
39 | 40 |
41 | 42 | sudo命令,逗号分隔, 不支持换行 43 |
44 |
45 |
46 |
47 | 48 |
49 | 50 |
51 |
52 |
53 |
54 |
55 | 56 | 57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | {% endblock %} 66 | {% block self_footer_js %} 67 | 91 | {% endblock %} 92 | 93 | -------------------------------------------------------------------------------- /templates/jperm/role_sudo.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | real_file=/etc/sudoers 5 | tmp_file=$(mktemp /tmp/XXXXXXX) 6 | 7 | # Backup sudoers file 8 | cp ${real_file} ${tmp_file} 9 | 10 | # Add Command Aliases 11 | add_cmd_alias() { 12 | sudo_file=$1 13 | {% for sudo_name, sudo_cmd in sudo_alias.items %} 14 | {% if sudo_name != 'ALL' %} 15 | if $(grep '^Cmnd_Alias \<{{ sudo_name }}\>' ${sudo_file} &> /dev/null); then 16 | sed -i 's@^Cmnd_Alias \<{{ sudo_name }}\>.*@Cmnd_Alias {{ sudo_name }} = {{ sudo_cmd }}@g' ${sudo_file} 17 | else 18 | echo "Cmnd_Alias {{ sudo_name }} = {{ sudo_cmd }}" >> ${sudo_file} 19 | fi 20 | {% endif %} 21 | {% endfor %} 22 | } 23 | 24 | 25 | # Add Command Aliases to role 26 | add_role_chosen() { 27 | sudo_file=$1 28 | {% for user, alias in sudo_user.items %} 29 | if $(grep '^{{ user }}\>' ${sudo_file} &> /dev/null); then 30 | sed -i 's@^{{ user }}\>.*@{{ user }} ALL = (root) NOPASSWD: {{ alias }}@g' ${sudo_file} 31 | else 32 | echo "{{ user }} ALL = (root) NOPASSWD: {{ alias }}" >> ${sudo_file} 33 | fi 34 | {% endfor %} 35 | } 36 | 37 | 38 | check_syntax(){ 39 | visudo -c -f $1 40 | } 41 | 42 | cp $real_file $tmp_file && add_cmd_alias $tmp_file && add_role_chosen $tmp_file || exit 1 43 | check_syntax $tmp_file && add_cmd_alias $real_file && add_role_chosen $real_file && rm -f $tmp_file || exit 2 44 | check_syntax $real_file 45 | 46 | -------------------------------------------------------------------------------- /templates/juser/forget_password.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 忘记密码 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | Jumpserver 20 |
21 |
22 |
23 |
24 | {# image#} 25 | {% if error %} 26 |
{{ error }}
27 | {% endif %} 28 | {% if msg %} 29 |
{{ msg }}
30 | {% endif %} 31 |
32 |

忘记密码

33 |

请输入您原来的信息

34 |
35 |
36 | 37 |
38 |
39 | 40 |
41 |
42 | 43 |
44 | 45 |
46 |
47 |
48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /templates/juser/group_detail.html: -------------------------------------------------------------------------------- 1 | {% load mytags %} 2 | 3 | 4 | {% include 'link_css.html' %} 5 | 6 | 12 | 13 | 14 | 15 |
16 |
17 |

{{ group.name }} 组中成员

18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | {% for user in users %} 30 | 31 | 32 | 33 | 34 | 35 | {% endfor %} 36 | 37 | 38 | 39 |
用户名姓名系统用户
{{ user.username }}{{ user.name }}{{ user.id|get_role }}
40 |
41 |
42 | 43 | -------------------------------------------------------------------------------- /templates/juser/profile.html: -------------------------------------------------------------------------------- 1 | {% load mytags %} 2 | 3 | 4 | {% include 'link_css.html' %} 5 | 6 | 12 | 13 | 14 | 15 |
16 |
17 |

{{ user.name }} 用户详情

18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 53 | 54 |
ID用户名姓名关联用户Email激活
{{ user.id }}{{ user.username }}{{ user.name }}{{ user.id | get_role }}{{ user.email }}{{ user.is_active|bool2str }}
添加日期: {{ user.date_joined }}最后登录: {{ user.last_login }}
用户组: 49 | {% for group in user.group.all %} 50 | {{ group.name }} 51 | {% endfor %} 52 |
55 |
56 |
57 | 58 | -------------------------------------------------------------------------------- /templates/juser/reset_password.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 重置{{ name }} 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | JumpServer 21 |
22 |
23 |
24 |
25 | {% if error %} 26 |
{{ error }}
27 | {% endif %} 28 | {% if msg %} 29 |
{{ msg }}
30 | {% endif %} 31 |
32 |

请输入新密码

33 |
34 |
35 | 36 | 37 |
38 | 39 |
40 |
41 |
42 | 43 | 44 | 45 | 46 | 47 | 72 | 73 | -------------------------------------------------------------------------------- /templates/link_css.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 登录 | JumpServer 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 |

20 |
21 | {% if error %} 22 |
{{ error }}
23 | {% endif %} 24 |

Welcome to JumpServer

25 |
26 |
27 | 28 |
29 |
30 | 31 |
32 | 33 | 34 | Forgot password? 35 |
36 |

Copyright Jumpserver.org Organization © 2014-2015

37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /templates/nav_bar_header.html: -------------------------------------------------------------------------------- 1 | {% load humanize %} 2 | {% load mytags %} 3 | -------------------------------------------------------------------------------- /templates/nav_cat_bar.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

{{ header_title }}

4 | 19 |
20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /templates/nav_li_profile.html: -------------------------------------------------------------------------------- 1 | {% load mytags %} 2 | 36 | 52 | 53 | -------------------------------------------------------------------------------- /templates/paginator.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
    4 | {% if contacts.has_previous %} 5 | 8 | {% else %} 9 | 12 | {% endif %} 13 | {% ifequal show_first 1 %} 14 |
  • 1...
  • 15 | {% endifequal %} 16 | {% for page in page_range %} 17 | {% ifequal current_page page %} 18 |
  • {{ page }}
  • 19 | {% else %} 20 |
  • {{ page }}
  • 21 | {% endifequal %} 22 | {% endfor %} 23 | {% ifequal show_end 1 %} 24 |
  • ...{{ p.num_pages }}
  • 25 | {% endifequal %} 26 | {% if contacts.has_next %} 27 | 30 | {% else %} 31 | 34 | {% endif %} 35 |
36 |
37 |
38 | 67 | -------------------------------------------------------------------------------- /templates/success.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Jumpserver | Success 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 |

成功

24 |

{{ msg }}

25 | 26 |
27 | The server success response the request. Congratulations.
28 | You can go back to main page:
首页 29 |
30 |
31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | --------------------------------------------------------------------------------