├── data
└── .gitkeep
├── pekja
├── __init__.py
├── asgi.py
├── wsgi.py
├── urls.py
├── settings.py
└── utils.py
├── layuimini
├── __init__.py
├── migrations
│ └── __init__.py
├── models.py
├── admin.py
├── tests.py
├── apps.py
└── urls.py
├── command
├── management
│ ├── __init__.py
│ └── commands
│ │ ├── __init__.py
│ │ ├── is_tool_empty.py
│ │ ├── parse.py
│ │ ├── cron_all_task.py
│ │ ├── update_input.py
│ │ ├── record_report.py
│ │ ├── set_record_report_cron.py
│ │ └── init_admin.py
├── __init__.py
├── apps.py
├── report.py
└── cron_task.py
├── entities
├── migrations
│ ├── __init__.py
│ └── 0001_initial.py
├── __init__.py
├── apps.py
├── forms.py
├── validators.py
├── widgets.py
├── admin.py
├── resources.py
└── models.py
├── parse
├── examples
│ ├── sublist3r.txt
│ ├── ctfr.txt
│ ├── lijiejie_sub_domains_brute.txt
│ ├── one_for_all.json
│ ├── nmap_sub_domain_brute.xml
│ └── censys_enumeration.json
├── ctfr.py
├── sublist3r_parser.py
├── nmap_dns_brute.py
├── one_for_all.py
├── lijiejie_subdomains_brute.py
├── censys_enumeration_email.py
├── censys_enumeration_domain.py
├── nmap_syn_scan.py
├── nmap_udp_scan.py
├── nmap_http_scan.py
├── __init__.py
├── parser.py
└── tests.py
├── docker
├── env.example
├── sources.list
├── update.sh
├── start.sh
└── tool.json
├── screenshot
├── pekja-web.png
└── pekja-report.jpg
├── requirements.txt
├── static
└── layuimini
│ ├── images
│ ├── bg.jpg
│ ├── logo.png
│ └── favicon.ico
│ ├── lib
│ ├── layui-v2.5.5
│ │ ├── font
│ │ │ ├── iconfont.eot
│ │ │ ├── iconfont.ttf
│ │ │ ├── iconfont.woff
│ │ │ └── iconfont.woff2
│ │ ├── images
│ │ │ └── face
│ │ │ │ ├── 0.gif
│ │ │ │ ├── 1.gif
│ │ │ │ ├── 2.gif
│ │ │ │ ├── 3.gif
│ │ │ │ ├── 4.gif
│ │ │ │ ├── 5.gif
│ │ │ │ ├── 6.gif
│ │ │ │ ├── 7.gif
│ │ │ │ ├── 8.gif
│ │ │ │ ├── 9.gif
│ │ │ │ ├── 10.gif
│ │ │ │ ├── 11.gif
│ │ │ │ ├── 12.gif
│ │ │ │ ├── 13.gif
│ │ │ │ ├── 14.gif
│ │ │ │ ├── 15.gif
│ │ │ │ ├── 16.gif
│ │ │ │ ├── 17.gif
│ │ │ │ ├── 18.gif
│ │ │ │ ├── 19.gif
│ │ │ │ ├── 20.gif
│ │ │ │ ├── 21.gif
│ │ │ │ ├── 22.gif
│ │ │ │ ├── 23.gif
│ │ │ │ ├── 24.gif
│ │ │ │ ├── 25.gif
│ │ │ │ ├── 26.gif
│ │ │ │ ├── 27.gif
│ │ │ │ ├── 28.gif
│ │ │ │ ├── 29.gif
│ │ │ │ ├── 30.gif
│ │ │ │ ├── 31.gif
│ │ │ │ ├── 32.gif
│ │ │ │ ├── 33.gif
│ │ │ │ ├── 34.gif
│ │ │ │ ├── 35.gif
│ │ │ │ ├── 36.gif
│ │ │ │ ├── 37.gif
│ │ │ │ ├── 38.gif
│ │ │ │ ├── 39.gif
│ │ │ │ ├── 40.gif
│ │ │ │ ├── 41.gif
│ │ │ │ ├── 42.gif
│ │ │ │ ├── 43.gif
│ │ │ │ ├── 44.gif
│ │ │ │ ├── 45.gif
│ │ │ │ ├── 46.gif
│ │ │ │ ├── 47.gif
│ │ │ │ ├── 48.gif
│ │ │ │ ├── 49.gif
│ │ │ │ ├── 50.gif
│ │ │ │ ├── 51.gif
│ │ │ │ ├── 52.gif
│ │ │ │ ├── 53.gif
│ │ │ │ ├── 54.gif
│ │ │ │ ├── 55.gif
│ │ │ │ ├── 56.gif
│ │ │ │ ├── 57.gif
│ │ │ │ ├── 58.gif
│ │ │ │ ├── 59.gif
│ │ │ │ ├── 60.gif
│ │ │ │ ├── 61.gif
│ │ │ │ ├── 62.gif
│ │ │ │ ├── 63.gif
│ │ │ │ ├── 64.gif
│ │ │ │ ├── 65.gif
│ │ │ │ ├── 66.gif
│ │ │ │ ├── 67.gif
│ │ │ │ ├── 68.gif
│ │ │ │ ├── 69.gif
│ │ │ │ ├── 70.gif
│ │ │ │ └── 71.gif
│ │ ├── css
│ │ │ └── modules
│ │ │ │ ├── layer
│ │ │ │ └── default
│ │ │ │ │ ├── icon.png
│ │ │ │ │ ├── icon-ext.png
│ │ │ │ │ ├── loading-0.gif
│ │ │ │ │ ├── loading-1.gif
│ │ │ │ │ └── loading-2.gif
│ │ │ │ └── code.css
│ │ ├── lay
│ │ │ └── modules
│ │ │ │ ├── code.js
│ │ │ │ ├── laytpl.js
│ │ │ │ ├── flow.js
│ │ │ │ ├── rate.js
│ │ │ │ ├── util.js
│ │ │ │ ├── carousel.js
│ │ │ │ ├── laypage.js
│ │ │ │ ├── transfer.js
│ │ │ │ ├── slider.js
│ │ │ │ ├── upload.js
│ │ │ │ └── element.js
│ │ └── layui.js
│ └── font-awesome-4.7.0
│ │ ├── fonts
│ │ ├── FontAwesome.otf
│ │ ├── fontawesome-webfont.eot
│ │ ├── fontawesome-webfont.ttf
│ │ ├── fontawesome-webfont.woff
│ │ └── fontawesome-webfont.woff2
│ │ ├── less
│ │ ├── screen-reader.less
│ │ ├── fixed-width.less
│ │ ├── larger.less
│ │ ├── list.less
│ │ ├── core.less
│ │ ├── stacked.less
│ │ ├── font-awesome.less
│ │ ├── bordered-pulled.less
│ │ ├── rotated-flipped.less
│ │ ├── path.less
│ │ ├── animated.less
│ │ └── mixins.less
│ │ ├── scss
│ │ ├── _fixed-width.scss
│ │ ├── _screen-reader.scss
│ │ ├── _larger.scss
│ │ ├── _list.scss
│ │ ├── _core.scss
│ │ ├── font-awesome.scss
│ │ ├── _stacked.scss
│ │ ├── _bordered-pulled.scss
│ │ ├── _rotated-flipped.scss
│ │ ├── _path.scss
│ │ ├── _animated.scss
│ │ └── _mixins.scss
│ │ └── HELP-US-OUT.txt
│ ├── js
│ ├── lay-config.js
│ └── lay-module
│ │ └── layuimini
│ │ └── miniTongji.js
│ ├── css
│ └── public.css
│ └── config
│ └── init.json
├── manage.py
├── templates
├── email.html
├── page
│ ├── show_code.html
│ ├── killer.html
│ ├── show_file.html
│ ├── email_report_setting.html
│ └── timeline.html
└── login.html
├── Dockerfile
└── .gitignore
/data/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pekja/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/layuimini/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/command/management/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/entities/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/layuimini/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/command/management/commands/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/parse/examples/sublist3r.txt:
--------------------------------------------------------------------------------
1 | blog.werner.wiki
2 | search.werner.wiki
--------------------------------------------------------------------------------
/command/__init__.py:
--------------------------------------------------------------------------------
1 | default_app_config = 'command.apps.CommandConfig'
2 |
--------------------------------------------------------------------------------
/entities/__init__.py:
--------------------------------------------------------------------------------
1 | default_app_config = 'entities.apps.EntitiesConfig'
--------------------------------------------------------------------------------
/docker/env.example:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/docker/env.example
--------------------------------------------------------------------------------
/docker/sources.list:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/docker/sources.list
--------------------------------------------------------------------------------
/layuimini/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | # Create your models here.
4 |
--------------------------------------------------------------------------------
/layuimini/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | # Register your models here.
4 |
--------------------------------------------------------------------------------
/layuimini/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/screenshot/pekja-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/screenshot/pekja-web.png
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | django==4.2.25
2 | django-import-export==2.0.2
3 | python-crontab==2.4.0
4 | psutil==5.7.0
--------------------------------------------------------------------------------
/screenshot/pekja-report.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/screenshot/pekja-report.jpg
--------------------------------------------------------------------------------
/static/layuimini/images/bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/images/bg.jpg
--------------------------------------------------------------------------------
/static/layuimini/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/images/logo.png
--------------------------------------------------------------------------------
/static/layuimini/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/images/favicon.ico
--------------------------------------------------------------------------------
/layuimini/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class LayuiminiConfig(AppConfig):
5 | name = 'layuimini'
6 |
--------------------------------------------------------------------------------
/command/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class CommandConfig(AppConfig):
5 | name = 'command'
6 | verbose_name = '命令'
7 |
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/font/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/font/iconfont.eot
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/font/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/font/iconfont.ttf
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/0.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/0.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/1.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/2.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/3.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/3.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/4.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/4.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/5.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/5.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/6.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/6.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/7.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/7.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/8.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/8.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/9.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/9.gif
--------------------------------------------------------------------------------
/entities/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class EntitiesConfig(AppConfig):
5 | name = 'entities'
6 | verbose_name = 'Pekja'
7 |
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/font/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/font/iconfont.woff
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/font/iconfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/font/iconfont.woff2
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/10.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/10.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/11.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/11.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/12.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/12.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/13.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/13.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/14.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/14.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/15.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/15.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/16.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/16.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/17.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/17.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/18.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/18.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/19.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/19.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/20.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/20.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/21.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/21.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/22.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/22.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/23.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/23.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/24.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/24.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/25.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/25.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/26.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/26.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/27.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/27.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/28.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/28.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/29.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/29.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/30.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/30.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/31.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/31.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/32.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/32.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/33.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/33.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/34.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/34.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/35.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/35.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/36.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/36.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/37.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/37.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/38.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/38.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/39.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/39.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/40.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/40.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/41.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/41.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/42.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/42.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/43.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/43.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/44.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/44.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/45.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/45.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/46.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/46.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/47.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/47.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/48.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/48.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/49.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/49.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/50.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/50.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/51.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/51.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/52.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/52.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/53.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/53.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/54.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/54.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/55.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/55.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/56.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/56.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/57.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/57.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/58.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/58.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/59.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/59.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/60.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/60.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/61.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/61.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/62.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/62.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/63.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/63.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/64.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/64.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/65.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/65.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/66.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/66.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/67.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/67.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/68.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/68.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/69.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/69.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/70.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/70.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/images/face/71.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/images/face/71.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/font-awesome-4.7.0/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/font-awesome-4.7.0/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/parse/examples/ctfr.txt:
--------------------------------------------------------------------------------
1 | bharal.werner.wiki
2 | blog.werner.wiki
3 | ms.werner.wiki
4 | poem.werner.wiki
5 | poetry.werner.wiki
6 | search.werner.wiki
7 | wiki.werner.wiki
8 |
--------------------------------------------------------------------------------
/static/layuimini/lib/font-awesome-4.7.0/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/font-awesome-4.7.0/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/static/layuimini/lib/font-awesome-4.7.0/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/font-awesome-4.7.0/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/css/modules/layer/default/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/css/modules/layer/default/icon.png
--------------------------------------------------------------------------------
/static/layuimini/lib/font-awesome-4.7.0/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/font-awesome-4.7.0/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/static/layuimini/lib/font-awesome-4.7.0/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/font-awesome-4.7.0/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/css/modules/layer/default/icon-ext.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/css/modules/layer/default/icon-ext.png
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/css/modules/layer/default/loading-0.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/css/modules/layer/default/loading-0.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/css/modules/layer/default/loading-1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/css/modules/layer/default/loading-1.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/css/modules/layer/default/loading-2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Werneror/pekja/HEAD/static/layuimini/lib/layui-v2.5.5/css/modules/layer/default/loading-2.gif
--------------------------------------------------------------------------------
/static/layuimini/lib/font-awesome-4.7.0/less/screen-reader.less:
--------------------------------------------------------------------------------
1 | // Screen Readers
2 | // -------------------------
3 |
4 | .sr-only { .sr-only(); }
5 | .sr-only-focusable { .sr-only-focusable(); }
6 |
--------------------------------------------------------------------------------
/static/layuimini/lib/font-awesome-4.7.0/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/layuimini/lib/font-awesome-4.7.0/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/layuimini/lib/font-awesome-4.7.0/scss/_screen-reader.scss:
--------------------------------------------------------------------------------
1 | // Screen Readers
2 | // -------------------------
3 |
4 | .sr-only { @include sr-only(); }
5 | .sr-only-focusable { @include sr-only-focusable(); }
6 |
--------------------------------------------------------------------------------
/docker/update.sh:
--------------------------------------------------------------------------------
1 | git pull
2 | docker build -t pekja .
3 | docker stop pekja
4 | docker rm pekja
5 | docker run -d -p 8000:8000 --env-file docker/env -v /opt/pekja:/opt/pekja/data --restart=always --name pekja pekja:latest
--------------------------------------------------------------------------------
/parse/examples/lijiejie_sub_domains_brute.txt:
--------------------------------------------------------------------------------
1 | mail.werner.wiki 123.58.177.51
2 | search.werner.wiki 119.28.89.38
3 | ycj.werner.wiki 119.28.89.38
4 | www.werner.wiki 119.28.89.38
--------------------------------------------------------------------------------
/parse/ctfr.py:
--------------------------------------------------------------------------------
1 | from .parser import Parser
2 |
3 |
4 | class CTFRParser(Parser):
5 | """python3 ctfr.py -d facebook.com -o /home/shei/subdomains_fb.txt
6 | for ctfr 86a804a"""
7 |
8 | def parse(self):
9 | with open(self.file_path) as f:
10 | for line in f:
11 | domain = line.strip()
12 | self.add_record(domain)
13 |
--------------------------------------------------------------------------------
/static/layuimini/lib/font-awesome-4.7.0/HELP-US-OUT.txt:
--------------------------------------------------------------------------------
1 | I hope you love Font Awesome. If you've found it useful, please do me a favor and check out my latest project,
2 | Fort Awesome (https://fortawesome.com). It makes it easy to put the perfect icons on your website. Choose from our awesome,
3 | comprehensive icon sets or copy and paste your own.
4 |
5 | Please. Check it out.
6 |
7 | -Dave Gandy
8 |
--------------------------------------------------------------------------------
/parse/examples/one_for_all.json:
--------------------------------------------------------------------------------
1 | www.github.com
2 | mail.github.com
3 | ftp.github.com
4 | smtp.github.com
5 | pop.github.com
6 | m.github.com
7 | webmail.github.com
8 | pop3.github.com
9 | imap.github.com
10 | localhost.github.com
11 | autodiscover.github.com
12 | admin.github.com
13 | bbs.github.com
14 | test.github.com
15 | mx.github.com
16 | en.github.com
17 | email.github.com
18 | wap.github.com
--------------------------------------------------------------------------------
/command/management/commands/is_tool_empty.py:
--------------------------------------------------------------------------------
1 | from django.core.management.base import BaseCommand
2 |
3 | from entities.models import Tool
4 |
5 |
6 | class Command(BaseCommand):
7 | help = 'Is the tool table empty'
8 |
9 | def handle(self, *args, **options):
10 | if Tool.objects.count() == 0:
11 | print('Yes')
12 | exit(0)
13 | else:
14 | print('No')
15 | exit(-1)
16 |
--------------------------------------------------------------------------------
/pekja/asgi.py:
--------------------------------------------------------------------------------
1 | """
2 | ASGI config for pekja project.
3 |
4 | It exposes the ASGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.asgi import get_asgi_application
13 |
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'pekja.settings')
15 |
16 | application = get_asgi_application()
17 |
--------------------------------------------------------------------------------
/pekja/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for pekja 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/3.0/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'pekja.settings')
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/static/layuimini/lib/font-awesome-4.7.0/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/layuimini/lib/font-awesome-4.7.0/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 |
--------------------------------------------------------------------------------
/parse/sublist3r_parser.py:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 | from .parser import Parser
3 |
4 |
5 | class Sublist3rParser(Parser):
6 | """/usr/local/bin/python /opt/Sublist3r/sublist3r.py -d {input} -o {output_file}
7 | for https://github.com/aboul3la/Sublist3r 61ebf36"""
8 |
9 | def parse(self):
10 | with open(self.file_path) as f:
11 | for line in f:
12 | domain = line.strip()
13 | if domain:
14 | self.add_record(domain)
15 |
--------------------------------------------------------------------------------
/static/layuimini/lib/font-awesome-4.7.0/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/layuimini/lib/font-awesome-4.7.0/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 |
--------------------------------------------------------------------------------
/command/management/commands/parse.py:
--------------------------------------------------------------------------------
1 | from django.core.management.base import BaseCommand
2 |
3 | from command.cron_task import run_parse
4 | from pekja.utils import get_task_by_id
5 |
6 |
7 | class Command(BaseCommand):
8 | help = 'Parse the output of a task'
9 |
10 | def add_arguments(self, parser):
11 | parser.add_argument('task_id', type=int)
12 |
13 | def handle(self, *args, **options):
14 | task = get_task_by_id(options['task_id'])
15 | if task:
16 | run_parse(task)
17 |
--------------------------------------------------------------------------------
/parse/nmap_dns_brute.py:
--------------------------------------------------------------------------------
1 | try:
2 | import xml.etree.cElementTree as ET
3 | except ImportError:
4 | import xml.etree.ElementTree as ET
5 |
6 | from .parser import Parser
7 |
8 |
9 | class NmapDnsBruteParser(Parser):
10 | """nmap -sn -Pn --script=dns-brute {input} -oX {output_file}
11 | for nmap 7.7.0"""
12 |
13 | def parse(self):
14 | tree = ET.parse(self.file_path)
15 | root = tree.getroot()
16 | for domain in root.findall(".//*[@key='hostname']"):
17 | self.add_record(domain.text)
18 |
--------------------------------------------------------------------------------
/parse/one_for_all.py:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 |
3 | import json
4 |
5 | from .parser import Parser
6 |
7 |
8 | class OneForAllParser(Parser):
9 | """/usr/local/bin/python /opt/oneforall/oneforall/oneforall.py --target {input} --out {output_file} --format json run
10 | for OneForAll.py v0.3.0"""
11 |
12 | def parse(self):
13 | with open(self.file_path, encoding='utf-8') as f:
14 | for line in f:
15 | domain = line.strip()
16 | if domain:
17 | self.add_record(domain)
18 |
--------------------------------------------------------------------------------
/static/layuimini/lib/font-awesome-4.7.0/less/core.less:
--------------------------------------------------------------------------------
1 | // Base Class Definition
2 | // -------------------------
3 |
4 | .@{fa-css-prefix} {
5 | display: inline-block;
6 | font: normal normal normal @fa-font-size-base/@fa-line-height-base 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 |
--------------------------------------------------------------------------------
/parse/lijiejie_subdomains_brute.py:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 | from .parser import Parser
3 |
4 |
5 | class LijiejieSubDomainsBrute(Parser):
6 | """/usr/local/bin/python2 /opt/subDomainsBrute/subDomainsBrute.py --full -o {output_file} {input}
7 | for https://github.com/lijiejie/subDomainsBrute bac5eb3"""
8 |
9 | def parse(self):
10 | with open(self.file_path) as f:
11 | for line in f:
12 | domain = line.split('\t')[0].strip()
13 | if domain:
14 | self.add_record(domain)
15 |
--------------------------------------------------------------------------------
/static/layuimini/lib/font-awesome-4.7.0/scss/_core.scss:
--------------------------------------------------------------------------------
1 | // Base Class Definition
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix} {
5 | display: inline-block;
6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} 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 |
--------------------------------------------------------------------------------
/static/layuimini/lib/font-awesome-4.7.0/scss/font-awesome.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome 4.7.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 "animated";
15 | @import "rotated-flipped";
16 | @import "stacked";
17 | @import "icons";
18 | @import "screen-reader";
19 |
--------------------------------------------------------------------------------
/parse/censys_enumeration_email.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | from .parser import Parser
4 |
5 |
6 | class CensysEnumerationEmail(Parser):
7 | """python censys_enumeration.py --outfile {output_file} {input}
8 | for censys_enumeration.py 10d42fa3"""
9 |
10 | def parse(self):
11 | with open(self.file_path) as f:
12 | output = json.loads(f.read())
13 | for domain in output:
14 | sub_domains = output[domain].get('emails', list())
15 | for sub_domain in sub_domains:
16 | self.add_record(sub_domain)
17 |
--------------------------------------------------------------------------------
/parse/censys_enumeration_domain.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | from .parser import Parser
4 |
5 |
6 | class CensysEnumerationDomain(Parser):
7 | """python censys_enumeration.py --outfile {output_file} {input}
8 | for censys_enumeration.py 10d42fa3"""
9 |
10 | def parse(self):
11 | with open(self.file_path) as f:
12 | output = json.loads(f.read())
13 | for domain in output:
14 | sub_domains = output[domain].get('subdomains', list())
15 | for sub_domain in sub_domains:
16 | self.add_record(sub_domain)
17 |
--------------------------------------------------------------------------------
/command/management/commands/cron_all_task.py:
--------------------------------------------------------------------------------
1 | from django.core.management.base import BaseCommand
2 |
3 | from entities.models import Task
4 | from entities.models import BatchTask
5 | from command.cron_task import set_cron_task
6 | from command.cron_task import set_cron_batch_task
7 |
8 |
9 | class Command(BaseCommand):
10 | help = 'Add all tasks to crontab'
11 |
12 | def handle(self, *args, **options):
13 | for task in Task.objects.all():
14 | set_cron_task(task)
15 | for batch_task in BatchTask.objects.all():
16 | set_cron_batch_task(batch_task)
17 |
--------------------------------------------------------------------------------
/entities/forms.py:
--------------------------------------------------------------------------------
1 | from django import forms
2 | from parse import get_parse_class_list
3 |
4 |
5 | class ToolForm(forms.ModelForm):
6 |
7 | parse_class_name = forms.ChoiceField(choices=(), label='输出解析类')
8 |
9 | # 必须重写__init__方法,这样才能每次实例化表单时重新获取选项
10 | def __init__(self, *args, **kwargs):
11 | super(ToolForm, self).__init__(*args, **kwargs)
12 | self.fields['parse_class_name'].choices = ToolForm.get_parse_class_choices()
13 |
14 | @classmethod
15 | def get_parse_class_choices(cls):
16 | return tuple([(class_name, class_name) for class_name in get_parse_class_list()])
17 |
--------------------------------------------------------------------------------
/static/layuimini/lib/font-awesome-4.7.0/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/layuimini/lib/font-awesome-4.7.0/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 |
--------------------------------------------------------------------------------
/entities/validators.py:
--------------------------------------------------------------------------------
1 | from django.core.exceptions import ValidationError
2 | from crontab import CronSlices
3 |
4 |
5 | def cron_validator(value):
6 | """
7 | 校验是否是有效的Cron表达式
8 | :param value:
9 | :return:
10 | """
11 | if not CronSlices.is_valid(value):
12 | raise ValidationError('不是有效的Crontab表达式')
13 |
14 |
15 | def command_validator(value):
16 | """
17 | 校验命令中是否包含输入文件和输出文件占位符
18 | :param value:
19 | :return:
20 | """
21 | if '{input}' not in value or '{output_file}' not in value:
22 | raise ValidationError('命令中必须包含输入占位符`{input}`和输出文件占位符`{output_file}`')
23 |
--------------------------------------------------------------------------------
/static/layuimini/lib/font-awesome-4.7.0/less/font-awesome.less:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome 4.7.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 "animated.less";
15 | @import "rotated-flipped.less";
16 | @import "stacked.less";
17 | @import "icons.less";
18 | @import "screen-reader.less";
19 |
--------------------------------------------------------------------------------
/command/management/commands/update_input.py:
--------------------------------------------------------------------------------
1 | from django.core.management.base import BaseCommand
2 |
3 | from command.cron_task import update_dynamic_input
4 | from pekja.utils import get_task_by_id
5 |
6 |
7 | class Command(BaseCommand):
8 | help = 'Update task input'
9 |
10 | def add_arguments(self, parser):
11 | parser.add_argument('task_id', type=int)
12 |
13 | def handle(self, *args, **options):
14 | task = get_task_by_id(options['task_id'])
15 | if task:
16 | update_dynamic_input(task)
17 | else:
18 | print('Task with ID {} does not exist'.format(options['task_id']))
19 |
--------------------------------------------------------------------------------
/parse/nmap_syn_scan.py:
--------------------------------------------------------------------------------
1 | try:
2 | import xml.etree.cElementTree as ET
3 | except ImportError:
4 | import xml.etree.ElementTree as ET
5 |
6 | from .parser import Parser
7 |
8 |
9 | class NmapSynScanParser(Parser):
10 | """nmap -sS -p- -iL {input} -oX {output_file} --open
11 | for nmap 7.7.0"""
12 |
13 | def parse(self):
14 | tree = ET.parse(self.file_path)
15 | root = tree.getroot()
16 | for host in root.findall('host'):
17 | ipv4 = host.findall("address[@addrtype='ipv4']")[0].get('addr')
18 | for port in host.findall(".//port"):
19 | record = '{}:{}'.format(ipv4, port.get('portid'))
20 | self.add_record(record)
21 |
--------------------------------------------------------------------------------
/parse/nmap_udp_scan.py:
--------------------------------------------------------------------------------
1 | try:
2 | import xml.etree.cElementTree as ET
3 | except ImportError:
4 | import xml.etree.ElementTree as ET
5 |
6 | from .parser import Parser
7 |
8 |
9 | class NmapUdpScanParser(Parser):
10 | """nmap -sU -p- -iL {input} -oX {output_file} --open
11 | for nmap 7.7.0"""
12 |
13 | def parse(self):
14 | tree = ET.parse(self.file_path)
15 | root = tree.getroot()
16 | for host in root.findall('host'):
17 | ipv4 = host.findall("address[@addrtype='ipv4']")[0].get('addr')
18 | for port in host.findall(".//port"):
19 | record = '{}:{}'.format(ipv4, port.get('portid'))
20 | self.add_record(record)
21 |
--------------------------------------------------------------------------------
/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """Django's command-line utility for administrative tasks."""
3 | import os
4 | import sys
5 |
6 |
7 | def main():
8 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'pekja.settings')
9 | try:
10 | from django.core.management import execute_from_command_line
11 | except ImportError as exc:
12 | raise ImportError(
13 | "Couldn't import Django. Are you sure it's installed and "
14 | "available on your PYTHONPATH environment variable? Did you "
15 | "forget to activate a virtual environment?"
16 | ) from exc
17 | execute_from_command_line(sys.argv)
18 |
19 |
20 | if __name__ == '__main__':
21 | main()
22 |
--------------------------------------------------------------------------------
/static/layuimini/lib/font-awesome-4.7.0/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 | .@{fa-css-prefix}-pull-left { float: left; }
11 | .@{fa-css-prefix}-pull-right { float: right; }
12 |
13 | .@{fa-css-prefix} {
14 | &.@{fa-css-prefix}-pull-left { margin-right: .3em; }
15 | &.@{fa-css-prefix}-pull-right { margin-left: .3em; }
16 | }
17 |
18 | /* Deprecated as of 4.4.0 */
19 | .pull-right { float: right; }
20 | .pull-left { float: left; }
21 |
22 | .@{fa-css-prefix} {
23 | &.pull-left { margin-right: .3em; }
24 | &.pull-right { margin-left: .3em; }
25 | }
26 |
--------------------------------------------------------------------------------
/static/layuimini/lib/font-awesome-4.7.0/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/layuimini/lib/font-awesome-4.7.0/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 | .#{$fa-css-prefix}-pull-left { float: left; }
11 | .#{$fa-css-prefix}-pull-right { float: right; }
12 |
13 | .#{$fa-css-prefix} {
14 | &.#{$fa-css-prefix}-pull-left { margin-right: .3em; }
15 | &.#{$fa-css-prefix}-pull-right { margin-left: .3em; }
16 | }
17 |
18 | /* Deprecated as of 4.4.0 */
19 | .pull-right { float: right; }
20 | .pull-left { float: left; }
21 |
22 | .#{$fa-css-prefix} {
23 | &.pull-left { margin-right: .3em; }
24 | &.pull-right { margin-left: .3em; }
25 | }
26 |
--------------------------------------------------------------------------------
/command/management/commands/record_report.py:
--------------------------------------------------------------------------------
1 | import datetime
2 |
3 | from django.core.management.base import BaseCommand
4 |
5 | from command.report import generate_new_record_report
6 | from command.report import send_report_by_mail
7 |
8 |
9 | class Command(BaseCommand):
10 | help = 'Generate record report and email'
11 |
12 | def add_arguments(self, parser):
13 | parser.add_argument('date', type=str, nargs='?')
14 |
15 | def handle(self, *args, **options):
16 | try:
17 | date = datetime.datetime.strptime('' if options.get('date') is None else options.get('date'), '%Y-%m-%d')
18 | except ValueError:
19 | date = datetime.datetime.now()
20 | report = generate_new_record_report(date)
21 | send_report_by_mail(date, report)
22 |
--------------------------------------------------------------------------------
/static/layuimini/lib/font-awesome-4.7.0/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 |
--------------------------------------------------------------------------------
/templates/email.html:
--------------------------------------------------------------------------------
1 |
Pekja
--------------------------------------------------------------------------------
/static/layuimini/lib/font-awesome-4.7.0/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.woff2?v=@{fa-version}') format('woff2'),
9 | url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'),
10 | url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'),
11 | url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg');
12 | // src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
13 | font-weight: normal;
14 | font-style: normal;
15 | }
16 |
--------------------------------------------------------------------------------
/static/layuimini/lib/font-awesome-4.7.0/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.woff2?v=#{$fa-version}') format('woff2'),
9 | url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'),
10 | url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'),
11 | url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg');
12 | // src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
13 | font-weight: normal;
14 | font-style: normal;
15 | }
16 |
--------------------------------------------------------------------------------
/static/layuimini/lib/font-awesome-4.7.0/less/animated.less:
--------------------------------------------------------------------------------
1 | // Animated 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 | .@{fa-css-prefix}-pulse {
10 | -webkit-animation: fa-spin 1s infinite steps(8);
11 | animation: fa-spin 1s infinite steps(8);
12 | }
13 |
14 | @-webkit-keyframes fa-spin {
15 | 0% {
16 | -webkit-transform: rotate(0deg);
17 | transform: rotate(0deg);
18 | }
19 | 100% {
20 | -webkit-transform: rotate(359deg);
21 | transform: rotate(359deg);
22 | }
23 | }
24 |
25 | @keyframes fa-spin {
26 | 0% {
27 | -webkit-transform: rotate(0deg);
28 | transform: rotate(0deg);
29 | }
30 | 100% {
31 | -webkit-transform: rotate(359deg);
32 | transform: rotate(359deg);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/static/layuimini/lib/font-awesome-4.7.0/scss/_animated.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 | .#{$fa-css-prefix}-pulse {
10 | -webkit-animation: fa-spin 1s infinite steps(8);
11 | animation: fa-spin 1s infinite steps(8);
12 | }
13 |
14 | @-webkit-keyframes fa-spin {
15 | 0% {
16 | -webkit-transform: rotate(0deg);
17 | transform: rotate(0deg);
18 | }
19 | 100% {
20 | -webkit-transform: rotate(359deg);
21 | transform: rotate(359deg);
22 | }
23 | }
24 |
25 | @keyframes fa-spin {
26 | 0% {
27 | -webkit-transform: rotate(0deg);
28 | transform: rotate(0deg);
29 | }
30 | 100% {
31 | -webkit-transform: rotate(359deg);
32 | transform: rotate(359deg);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/parse/nmap_http_scan.py:
--------------------------------------------------------------------------------
1 | try:
2 | import xml.etree.cElementTree as ET
3 | except ImportError:
4 | import xml.etree.ElementTree as ET
5 |
6 | from .parser import Parser
7 |
8 |
9 | class NmapHTTPScanParser(Parser):
10 | """nmap -sV -sC -p 80,443,7000,8080 -iL {input} --open -oX {output_file}
11 | for nmap 7.7.0"""
12 |
13 | def parse(self):
14 | tree = ET.parse(self.file_path)
15 | root = tree.getroot()
16 | for host in root.findall('host'):
17 | hostname = host.find('hostnames').find('hostname[@type="user"]').get('name')
18 | for port in host.find('ports').findall('port'):
19 | port_id = port.get('portid')
20 | server = port.find('service').get('product')
21 | title = port.find('script[@id="http-title"]').get('output')
22 | self.add_record('{}:{}:{}:{}'.format(hostname, port_id, server, title))
23 |
--------------------------------------------------------------------------------
/pekja/urls.py:
--------------------------------------------------------------------------------
1 | """pekja URL Configuration
2 |
3 | The `urlpatterns` list routes URLs to views. For more information please see:
4 | https://docs.djangoproject.com/en/3.0/topics/http/urls/
5 | Examples:
6 | Function views
7 | 1. Add an import: from my_app import views
8 | 2. Add a URL to urlpatterns: path('', views.home, name='home')
9 | Class-based views
10 | 1. Add an import: from other_app.views import Home
11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
12 | Including another URLconf
13 | 1. Import the include() function: from django.urls import include, path
14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
15 | """
16 | from django.contrib import admin
17 | from django.urls import path
18 | from django.urls import include
19 |
20 | import layuimini.urls
21 |
22 |
23 | urlpatterns = [
24 | path('', include(layuimini.urls)),
25 | path('admin/', admin.site.urls),
26 | ]
27 |
--------------------------------------------------------------------------------
/parse/__init__.py:
--------------------------------------------------------------------------------
1 | import os
2 | import inspect
3 | import pkgutil
4 | import importlib
5 |
6 | from .parser import Parser
7 |
8 |
9 | def get_parse_class_list():
10 | pkg_path = os.path.dirname(__file__)
11 | parse_class_list = list()
12 | for _, file, _ in pkgutil.iter_modules([pkg_path]):
13 | module = importlib.import_module('parse.' + file)
14 | parse_class_list += [m[0] for m in inspect.getmembers(module, inspect.isclass)
15 | if issubclass(m[1], Parser) and m[0] != 'Parser']
16 | return list(set(parse_class_list))
17 |
18 |
19 | def get_parse_class(class_name):
20 | pkg_path = os.path.dirname(__file__)
21 | for _, file, _ in pkgutil.iter_modules([pkg_path]):
22 | module = importlib.import_module('parse.' + file)
23 | for m in inspect.getmembers(module, inspect.isclass):
24 | if issubclass(m[1], Parser) and m[0] == class_name:
25 | return m[1]
26 |
--------------------------------------------------------------------------------
/command/management/commands/set_record_report_cron.py:
--------------------------------------------------------------------------------
1 | import os
2 | from crontab import CronSlices
3 | from django.core.management.base import BaseCommand
4 | from command.cron_task import set_cron_mail_report
5 |
6 |
7 | class Command(BaseCommand):
8 | help = 'Set when to send mail reports'
9 |
10 | def add_arguments(self, parser):
11 | parser.add_argument('dispatch_file_path', type=str)
12 |
13 | def handle(self, *args, **options):
14 | file_path = options.get('dispatch_file_path')
15 | if os.path.exists(file_path):
16 | with open(file_path) as f:
17 | dispatch = f.read()
18 | if CronSlices.is_valid(dispatch):
19 | set_cron_mail_report(dispatch)
20 | print('Successfully set the scheduled sending of mail Report.')
21 | else:
22 | print('Not a valid cron expression.')
23 | else:
24 | print('The file does not exist.')
25 |
--------------------------------------------------------------------------------
/command/management/commands/init_admin.py:
--------------------------------------------------------------------------------
1 | from django.core.management.base import BaseCommand
2 | from django.contrib.auth import get_user_model
3 |
4 |
5 | class Command(BaseCommand):
6 | help = 'Create init admin user'
7 |
8 | def add_arguments(self, parser):
9 | parser.add_argument('username', type=str)
10 | parser.add_argument('email', type=str)
11 | parser.add_argument('password', type=str)
12 |
13 | def handle(self, *args, **options):
14 | user_model = get_user_model()
15 | if user_model.objects.count() == 0:
16 | admin = user_model.objects.create_superuser(username=options.get('username'), email=options.get('email'),
17 | password=options.get('password'))
18 | admin.is_active = True
19 | admin.is_admin = True
20 | admin.save()
21 | else:
22 | print('Admin accounts can only be initialized if no users exist')
23 |
--------------------------------------------------------------------------------
/entities/widgets.py:
--------------------------------------------------------------------------------
1 | from import_export.widgets import Widget
2 |
3 |
4 | # Taken from https://github.com/django-import-export/django-import-export/issues/525#issuecomment-303046691
5 | class ChoicesWidget(Widget):
6 | """
7 | Widget that uses choice display values in place of database values
8 | """
9 |
10 | # pylint:disable=unused-argument
11 | def __init__(self, choices, *args, **kwargs):
12 | """
13 | Creates a self.choices dict with a key, display value, and value,
14 | db value, e.g. {'Chocolate': 'CHOC'}
15 | """
16 | self.choices = dict(choices)
17 | self.revert_choices = dict((v, k) for k, v in self.choices.items())
18 |
19 | def clean(self, value, row=None, *args, **kwargs):
20 | """Returns the db value given the display value"""
21 | return self.revert_choices.get(value, value) if value else None
22 |
23 | def render(self, value, obj=None):
24 | """Returns the display value given the db value"""
25 | return self.choices.get(value, '')
26 |
27 |
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/css/modules/code.css:
--------------------------------------------------------------------------------
1 | /** layui-v2.5.5 MIT License By https://www.layui.com */
2 | html #layuicss-skincodecss{display:none;position:absolute;width:1989px}.layui-code-h3,.layui-code-view{position:relative;font-size:12px}.layui-code-view{display:block;margin:10px 0;padding:0;border:1px solid #e2e2e2;border-left-width:6px;background-color:#F2F2F2;color:#333;font-family:Courier New}.layui-code-h3{padding:0 10px;height:32px;line-height:32px;border-bottom:1px solid #e2e2e2}.layui-code-h3 a{position:absolute;right:10px;top:0;color:#999}.layui-code-view .layui-code-ol{position:relative;overflow:auto}.layui-code-view .layui-code-ol li{position:relative;margin-left:45px;line-height:20px;padding:0 5px;border-left:1px solid #e2e2e2;list-style-type:decimal-leading-zero;*list-style-type:decimal;background-color:#fff}.layui-code-view pre{margin:0}.layui-code-notepad{border:1px solid #0C0C0C;border-left-color:#3F3F3F;background-color:#0C0C0C;color:#C2BE9E}.layui-code-notepad .layui-code-h3{border-bottom:none}.layui-code-notepad .layui-code-ol li{background-color:#3F3F3F;border-left:none}
--------------------------------------------------------------------------------
/static/layuimini/js/lay-config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * date:2019/08/16
3 | * author:Mr.Chung
4 | * description:此处放layui自定义扩展
5 | */
6 |
7 | window.rootPath = (function (src) {
8 | src = document.scripts[document.scripts.length - 1].src;
9 | return src.substring(0, src.lastIndexOf("/") + 1);
10 | })();
11 |
12 | layui.config({
13 | base: rootPath + "lay-module/",
14 | version: true
15 | }).extend({
16 | miniAdmin: "layuimini/miniAdmin", // layuimini后台扩展
17 | miniMenu: "layuimini/miniMenu", // layuimini菜单扩展
18 | miniTab: "layuimini/miniTab", // layuimini tab扩展
19 | miniTheme: "layuimini/miniTheme", // layuimini 主题扩展
20 | miniTongji: "layuimini/miniTongji", // layuimini 统计扩展
21 | step: 'step-lay/step', // 分步表单扩展
22 | treetable: 'treetable-lay/treetable', //table树形扩展
23 | tableSelect: 'tableSelect/tableSelect', // table选择扩展
24 | iconPickerFa: 'iconPicker/iconPickerFa', // fa图标选择扩展
25 | echarts: 'echarts/echarts', // echarts图表扩展
26 | echartsTheme: 'echarts/echartsTheme', // echarts图表主题扩展
27 | wangEditor: 'wangEditor/wangEditor', // wangEditor富文本扩展
28 | layarea: 'layarea/layarea', // 省市县区三级联动下拉选择器
29 | });
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/lay/modules/code.js:
--------------------------------------------------------------------------------
1 | /** layui-v2.5.5 MIT License By https://www.layui.com */
2 | ;layui.define("jquery",function(e){"use strict";var a=layui.$,l="http://www.layui.com/doc/modules/code.html";e("code",function(e){var t=[];e=e||{},e.elem=a(e.elem||".layui-code"),e.about=!("about"in e)||e.about,e.elem.each(function(){t.push(this)}),layui.each(t.reverse(),function(t,i){var c=a(i),o=c.html();(c.attr("lay-encode")||e.encode)&&(o=o.replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,""")),c.html('- '+o.replace(/[\r\t\n]+/g,"
- ")+"
"),c.find(">.layui-code-h3")[0]||c.prepend(''+(c.attr("lay-title")||e.title||"code")+(e.about?'layui.code':"")+"
");var d=c.find(">.layui-code-ol");c.addClass("layui-box layui-code-view"),(c.attr("lay-skin")||e.skin)&&c.addClass("layui-code-"+(c.attr("lay-skin")||e.skin)),(d.find("li").length/100|0)>0&&d.css("margin-left",(d.find("li").length/100|0)+"px"),(c.attr("lay-height")||e.height)&&d.css("max-height",c.attr("lay-height")||e.height)})})}).addcss("modules/code.css","skincodecss");
--------------------------------------------------------------------------------
/layuimini/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 |
3 | from . import views
4 |
5 | urlpatterns = [
6 | path('', views.index, name='index'),
7 | path('login/', views.user_login, name='user_login'),
8 | path('logout/', views.user_logout, name='user_logout'),
9 | path('api/clear/', views.api_clear, name='api_clear'),
10 | path('api/graph/', views.api_graph, name='api_graph'),
11 | path('api/input_file/', views.api_input_file, name='api_input_file'),
12 | path('api/output_file/', views.api_output_file, name='api_output_file'),
13 | path('download/', views.download, name='daownload'),
14 | path('page/dashboard/', views.dashboard, name='dashboard'),
15 | path('page/timeline/', views.timeline, name='timeline'),
16 | path('page/crontab/', views.crontab, name='crontab'),
17 | path('page/email_report/', views.email_report, name='email_report'),
18 | path('page/input/', views.input_file, name='input_file'),
19 | path('page/output/', views.output_file, name='output_file'),
20 | path('page/mail/', views.var_mail, name='var_mail'),
21 | path('page/process/', views.process, name='process'),
22 | path('page/killer/', views.killer, name='killer'),
23 | ]
24 |
--------------------------------------------------------------------------------
/static/layuimini/js/lay-module/layuimini/miniTongji.js:
--------------------------------------------------------------------------------
1 | /**
2 | * date:2020/03/01
3 | * author:Mr.Chung
4 | * version:2.0
5 | * description:layuimini 统计框架扩展
6 | */
7 | layui.define(["jquery"], function (exports) {
8 | var $ = layui.$;
9 |
10 | var miniTongji = {
11 |
12 | /**
13 | * 初始化
14 | * @param options
15 | */
16 | render: function (options) {
17 | options.specific = options.specific || false;
18 | options.domains = options.domains || [];
19 | var domain = window.location.hostname;
20 | if (options.specific === false || (options.specific === true && options.domains.indexOf(domain) >=0)) {
21 | miniTongji.listen();
22 | }
23 | },
24 |
25 | /**
26 | * 监听统计代码
27 | */
28 | listen: function () {
29 | var _hmt = _hmt || [];
30 | (function () {
31 | var hm = document.createElement("script");
32 | hm.src = "https://hm.baidu.com/hm.js?d97abf6d61c21d773f97835defbdef4e";
33 | var s = document.getElementsByTagName("script")[0];
34 | s.parentNode.insertBefore(hm, s);
35 | })();
36 | }
37 | };
38 |
39 | exports("miniTongji", miniTongji);
40 | });
--------------------------------------------------------------------------------
/command/report.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | from entities.models import Record
3 | from pekja.utils import send_mail_to_users
4 | from pekja.utils import rowspan_html_table
5 |
6 |
7 | def generate_new_record_report(date):
8 | """
9 | 生成某天的新增记录报告
10 | :param date:
11 | :return:
12 | """
13 | records = Record.objects.filter(add_time__year=date.year, add_time__month=date.month, add_time__day=date.day)
14 |
15 | data = dict()
16 | for record in records:
17 | if record.project.name not in data:
18 | data[record.project.name] = dict()
19 | if record.type not in data[record.project.name]:
20 | data[record.project.name][record.type] = 0
21 | data[record.project.name][record.type] += 1
22 |
23 | table_data = list()
24 | for project in data:
25 | for record_type in data[project]:
26 | table_data.append([project, record_type, data[project][record_type]])
27 |
28 | return rowspan_html_table(['项目', '类型', '数量'], data)
29 |
30 |
31 | def send_report_by_mail(date, report):
32 | """
33 | 通过邮件发送报告
34 | :param date:
35 | :param report: HTML
36 | :return:
37 | """
38 | send_mail_to_users('【pekja】{}新增记录报告'.format(date.strftime('%Y-%m-%d')),
39 | '{}新增记录见下表。'.format(date.strftime('%Y-%m-%d')), report)
40 |
--------------------------------------------------------------------------------
/parse/parser.py:
--------------------------------------------------------------------------------
1 | import os
2 | import time
3 | from pekja.utils import get_output_file_path
4 | from entities.models import Record
5 |
6 |
7 | class Parser:
8 |
9 | def __init__(self, task, file_path=None):
10 | self.task = task
11 | if file_path is not None:
12 | self.file_path = file_path
13 | else:
14 | self.file_path = get_output_file_path(task)
15 |
16 | def parse(self):
17 | pass
18 |
19 | def rename_file(self):
20 | now = time.strftime('%Y-%m-%d %H-%M-%S', time.localtime(time.time()))
21 | os.rename(self.file_path,
22 | self.file_path.replace('-{}.txt'.format(self.task.id), '-{}-{}.txt'.format(self.task.id, now)))
23 |
24 | def add_record(self, record, record_type=None):
25 | """
26 | 添加一条记录
27 | :param record: 记录内容
28 | :param record_type: 记录类型
29 | :return: 是否成功,错误消息
30 | """
31 | if record_type is None:
32 | record_type = self.task.tool.type
33 | try:
34 | record = Record.objects.get(record=record, project=self.task.project, type=record_type)
35 | except Record.DoesNotExist:
36 | Record(record=record, project=self.task.project, type=record_type, source=self.task.tool.name).save()
37 | return True
38 | except Record.MultipleObjectsReturned:
39 | return False
40 | else:
41 | if self.task.tool.name not in record.source:
42 | record.source += ',' + self.task.tool.name
43 | record.save() # 保存一次是为了更新最后修改时间
44 | return True
45 |
--------------------------------------------------------------------------------
/static/layuimini/css/public.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 15px 15px 15px 15px;
3 | background: #f2f2f2;
4 | }
5 |
6 | .layuimini-container {
7 | border: 1px solid #f2f2f2;
8 | border-radius: 5px;
9 | background-color: #ffffff
10 | }
11 |
12 | .layuimini-main {
13 | margin: 10px 10px 10px 10px;
14 | }
15 |
16 | /**必填红点 */
17 | .layuimini-form > .layui-form-item > .required:after {
18 | content: '*';
19 | color: red;
20 | position: absolute;
21 | margin-left: 4px;
22 | font-weight: bold;
23 | line-height: 1.8em;
24 | top: 6px;
25 | right: 5px;
26 | }
27 |
28 | .layuimini-form > .layui-form-item > .layui-form-label {
29 | width: 120px !important;
30 | }
31 |
32 | .layuimini-form > .layui-form-item > .layui-input-block {
33 | margin-left: 150px !important;
34 | }
35 |
36 | .layuimini-form > .layui-form-item > .layui-input-block > tip {
37 | display: inline-block;
38 | margin-top: 10px;
39 | line-height: 10px;
40 | font-size: 10px;
41 | color: #a29c9c;
42 | }
43 |
44 | /**搜索框*/
45 | .layuimini-container .table-search-fieldset {
46 | margin: 0;
47 | border: 1px solid #e6e6e6;
48 | padding: 10px 20px 5px 20px;
49 | color: #6b6b6b;
50 | }
51 |
52 | /**自定义滚动条样式 */
53 | ::-webkit-scrollbar {
54 | width: 6px;
55 | height: 6px
56 | }
57 |
58 | ::-webkit-scrollbar-track {
59 | background-color: transparent;
60 | -webkit-border-radius: 2em;
61 | -moz-border-radius: 2em;
62 | border-radius: 2em;
63 | }
64 |
65 | ::-webkit-scrollbar-thumb {
66 | background-color: #9c9da0;
67 | -webkit-border-radius: 2em;
68 | -moz-border-radius: 2em;
69 | border-radius: 2em
70 | }
71 |
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/lay/modules/laytpl.js:
--------------------------------------------------------------------------------
1 | /** layui-v2.5.5 MIT License By https://www.layui.com */
2 | ;layui.define(function(e){"use strict";var r={open:"{{",close:"}}"},c={exp:function(e){return new RegExp(e,"g")},query:function(e,c,t){var o=["#([\\s\\S])+?","([^{#}])*?"][e||0];return n((c||"")+r.open+o+r.close+(t||""))},escape:function(e){return String(e||"").replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,""")},error:function(e,r){var c="Laytpl Error:";return"object"==typeof console&&console.error(c+e+"\n"+(r||"")),c+e}},n=c.exp,t=function(e){this.tpl=e};t.pt=t.prototype,window.errors=0,t.pt.parse=function(e,t){var o=this,p=e,a=n("^"+r.open+"#",""),l=n(r.close+"$","");e=e.replace(/\s+|\r|\t|\n/g," ").replace(n(r.open+"#"),r.open+"# ").replace(n(r.close+"}"),"} "+r.close).replace(/\\/g,"\\\\").replace(n(r.open+"!(.+?)!"+r.close),function(e){return e=e.replace(n("^"+r.open+"!"),"").replace(n("!"+r.close),"").replace(n(r.open+"|"+r.close),function(e){return e.replace(/(.)/g,"\\$1")})}).replace(/(?="|')/g,"\\").replace(c.query(),function(e){return e=e.replace(a,"").replace(l,""),'";'+e.replace(/\\/g,"")+';view+="'}).replace(c.query(1),function(e){var c='"+(';return e.replace(/\s/g,"")===r.open+r.close?"":(e=e.replace(n(r.open+"|"+r.close),""),/^=/.test(e)&&(e=e.replace(/^=/,""),c='"+_escape_('),c+e.replace(/\\/g,"")+')+"')}),e='"use strict";var view = "'+e+'";return view;';try{return o.cache=e=new Function("d, _escape_",e),e(t,c.escape)}catch(u){return delete o.cache,c.error(u,p)}},t.pt.render=function(e,r){var n,t=this;return e?(n=t.cache?t.cache(e,c.escape):t.parse(t.tpl,e),r?void r(n):n):c.error("no data")};var o=function(e){return"string"!=typeof e?c.error("Template not found"):new t(e)};o.config=function(e){e=e||{};for(var c in e)r[c]=e[c]},o.v="1.2.0",e("laytpl",o)});
--------------------------------------------------------------------------------
/static/layuimini/lib/font-awesome-4.7.0/less/mixins.less:
--------------------------------------------------------------------------------
1 | // Mixins
2 | // --------------------------
3 |
4 | .fa-icon() {
5 | display: inline-block;
6 | font: normal normal normal @fa-font-size-base/@fa-line-height-base 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 |
14 | .fa-icon-rotate(@degrees, @rotation) {
15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})";
16 | -webkit-transform: rotate(@degrees);
17 | -ms-transform: rotate(@degrees);
18 | transform: rotate(@degrees);
19 | }
20 |
21 | .fa-icon-flip(@horiz, @vert, @rotation) {
22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)";
23 | -webkit-transform: scale(@horiz, @vert);
24 | -ms-transform: scale(@horiz, @vert);
25 | transform: scale(@horiz, @vert);
26 | }
27 |
28 |
29 | // Only display content to screen readers. A la Bootstrap 4.
30 | //
31 | // See: http://a11yproject.com/posts/how-to-hide-content/
32 |
33 | .sr-only() {
34 | position: absolute;
35 | width: 1px;
36 | height: 1px;
37 | padding: 0;
38 | margin: -1px;
39 | overflow: hidden;
40 | clip: rect(0,0,0,0);
41 | border: 0;
42 | }
43 |
44 | // Use in conjunction with .sr-only to only display content when it's focused.
45 | //
46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
47 | //
48 | // Credit: HTML5 Boilerplate
49 |
50 | .sr-only-focusable() {
51 | &:active,
52 | &:focus {
53 | position: static;
54 | width: auto;
55 | height: auto;
56 | margin: 0;
57 | overflow: visible;
58 | clip: auto;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/static/layuimini/lib/font-awesome-4.7.0/scss/_mixins.scss:
--------------------------------------------------------------------------------
1 | // Mixins
2 | // --------------------------
3 |
4 | @mixin fa-icon() {
5 | display: inline-block;
6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} 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 |
14 | @mixin fa-icon-rotate($degrees, $rotation) {
15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation})";
16 | -webkit-transform: rotate($degrees);
17 | -ms-transform: rotate($degrees);
18 | transform: rotate($degrees);
19 | }
20 |
21 | @mixin fa-icon-flip($horiz, $vert, $rotation) {
22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)";
23 | -webkit-transform: scale($horiz, $vert);
24 | -ms-transform: scale($horiz, $vert);
25 | transform: scale($horiz, $vert);
26 | }
27 |
28 |
29 | // Only display content to screen readers. A la Bootstrap 4.
30 | //
31 | // See: http://a11yproject.com/posts/how-to-hide-content/
32 |
33 | @mixin sr-only {
34 | position: absolute;
35 | width: 1px;
36 | height: 1px;
37 | padding: 0;
38 | margin: -1px;
39 | overflow: hidden;
40 | clip: rect(0,0,0,0);
41 | border: 0;
42 | }
43 |
44 | // Use in conjunction with .sr-only to only display content when it's focused.
45 | //
46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
47 | //
48 | // Credit: HTML5 Boilerplate
49 |
50 | @mixin sr-only-focusable {
51 | &:active,
52 | &:focus {
53 | position: static;
54 | width: auto;
55 | height: auto;
56 | margin: 0;
57 | overflow: visible;
58 | clip: auto;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/lay/modules/flow.js:
--------------------------------------------------------------------------------
1 | /** layui-v2.5.5 MIT License By https://www.layui.com */
2 | ;layui.define("jquery",function(e){"use strict";var l=layui.$,o=function(e){},t='';o.prototype.load=function(e){var o,i,n,r,a=this,c=0;e=e||{};var f=l(e.elem);if(f[0]){var m=l(e.scrollElem||document),u=e.mb||50,s=!("isAuto"in e)||e.isAuto,v=e.end||"没有更多了",y=e.scrollElem&&e.scrollElem!==document,d="加载更多",h=l('");f.find(".layui-flow-more")[0]||f.append(h);var p=function(e,t){e=l(e),h.before(e),t=0==t||null,t?h.html(v):h.find("a").html(d),i=t,o=null,n&&n()},g=function(){o=!0,h.find("a").html(t),"function"==typeof e.done&&e.done(++c,p)};if(g(),h.find("a").on("click",function(){l(this);i||o||g()}),e.isLazyimg)var n=a.lazyimg({elem:e.elem+" img",scrollElem:e.scrollElem});return s?(m.on("scroll",function(){var e=l(this),t=e.scrollTop();r&&clearTimeout(r),i||(r=setTimeout(function(){var i=y?e.height():l(window).height(),n=y?e.prop("scrollHeight"):document.documentElement.scrollHeight;n-t-i<=u&&(o||g())},100))}),a):a}},o.prototype.lazyimg=function(e){var o,t=this,i=0;e=e||{};var n=l(e.scrollElem||document),r=e.elem||"img",a=e.scrollElem&&e.scrollElem!==document,c=function(e,l){var o=n.scrollTop(),r=o+l,c=a?function(){return e.offset().top-n.offset().top+o}():e.offset().top;if(c>=o&&c<=r&&!e.attr("src")){var m=e.attr("lay-src");layui.img(m,function(){var l=t.lazyimg.elem.eq(i);e.attr("src",m).removeAttr("lay-src"),l[0]&&f(l),i++})}},f=function(e,o){var f=a?(o||n).height():l(window).height(),m=n.scrollTop(),u=m+f;if(t.lazyimg.elem=l(r),e)c(e,f);else for(var s=0;su)break}};if(f(),!o){var m;n.on("scroll",function(){var e=l(this);m&&clearTimeout(m),m=setTimeout(function(){f(null,e)},50)}),o=!0}return f},e("flow",new o)});
--------------------------------------------------------------------------------
/parse/examples/nmap_sub_domain_brute.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/static/layuimini/config/init.json:
--------------------------------------------------------------------------------
1 | {
2 | "homeInfo": {
3 | "title": "首页",
4 | "href": "page/dashboard/"
5 | },
6 | "logoInfo": {
7 | "title": "pekja",
8 | "image": "/static/layuimini/images/logo.png",
9 | "href": ""
10 | },
11 | "menuInfo": [
12 | {
13 | "title": "数据展示",
14 | "icon": "fa fa-home",
15 | "href": "",
16 | "target": "_self",
17 | "child": [
18 | {
19 | "title": "数据面板",
20 | "icon": "fa fa-tachometer",
21 | "href": "page/dashboard/",
22 | "target": "_self"
23 | },
24 | {
25 | "title": "时间线",
26 | "icon": "fa fa-heartbeat",
27 | "href": "page/timeline/",
28 | "target": "_self"
29 | }
30 | ]
31 | },
32 | {
33 | "title": "系统设置",
34 | "icon": "fa fa-gears",
35 | "href": "",
36 | "target": "_self",
37 | "child": [
38 | {
39 | "title": "邮件报告",
40 | "icon": "fa fa-envelope",
41 | "href": "page/email_report/",
42 | "target": "_self"
43 | }
44 | ]
45 | },
46 | {
47 | "title": "高级调试",
48 | "icon": "fa fa-bug",
49 | "href": "",
50 | "target": "_self",
51 | "child": [
52 | {
53 | "title": "Crontab",
54 | "icon": "fa fa-calendar",
55 | "href": "page/crontab/",
56 | "target": "_self"
57 | },
58 | {
59 | "title": "Input",
60 | "icon": "fa fa-hourglass-start",
61 | "href": "page/input/",
62 | "target": "_self"
63 | },
64 | {
65 | "title": "Output",
66 | "icon": "fa fa-hourglass-end",
67 | "href": "page/output/",
68 | "target": "_self"
69 | },
70 | {
71 | "title": "Mail",
72 | "icon": "fa fa-envelope-o",
73 | "href": "page/mail/",
74 | "target": "_self"
75 | },
76 | {
77 | "title": "Process",
78 | "icon": "fa fa-list",
79 | "href": "page/process/",
80 | "target": "_self"
81 | },
82 | {
83 | "title": "Killer",
84 | "icon": "fa fa-cutlery",
85 | "href": "page/killer/",
86 | "target": "_self"
87 | }
88 | ]
89 | }
90 | ]
91 | }
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.8
2 |
3 | # Set up for localization in China. If you are not in China, please delete this part
4 | COPY docker/sources.list /etc/apt/sources.list
5 | RUN pip install -U pip setuptools -i https://pypi.tuna.tsinghua.edu.cn/simple
6 | RUN pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
7 | RUN ln -fs /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
8 | RUN dpkg-reconfigure -f noninteractive tzdata
9 |
10 | # Update
11 | RUN apt-get update && apt-get upgrade -y
12 |
13 | # Install crontab
14 | RUN apt-get install -y cron
15 | RUN service cron start
16 | RUN update-rc.d cron defaults
17 |
18 | # Clear /opt
19 | RUN rm -rf /opt
20 |
21 | # Install tool: nmap
22 | RUN apt-get install -y nmap
23 |
24 | # Install censys-enumeration
25 | RUN mkdir -p /opt/censys_enumeration
26 | RUN git clone https://github.com/0xbharath/censys-enumeration.git /opt/censys_enumeration
27 | RUN pip install -r /opt/censys_enumeration/requirements.txt
28 |
29 | # Install CTFR
30 | RUN mkdir -p /opt/ctfr
31 | RUN git clone https://github.com/UnaPibaGeek/ctfr.git /opt/ctfr
32 | RUN pip install -r /opt/ctfr/requirements.txt
33 |
34 | # Install OneForAll
35 | RUN mkdir -p /opt/oneforall
36 | RUN wget https://github.com/shmilylty/OneForAll/archive/v0.3.0.tar.gz -O /opt/oneforall/v0.3.0.tar.gz
37 | RUN tar xzf /opt/oneforall/v0.3.0.tar.gz -C /opt/oneforall/
38 | RUN mv /opt/oneforall/OneForAll-0.3.0/* /opt/oneforall
39 | RUN rm -rf /opt/oneforall/OneForAll-0.3.0 /opt/oneforall/v0.3.0.tar.gz
40 | RUN apt install -y python3-testresources
41 | RUN pip install -r /opt/oneforall/requirements.txt
42 |
43 | # Install lijiejie/subDomainsBrute
44 | RUN mkdir -p /opt/subDomainsBrute
45 | RUN git clone https://github.com/lijiejie/subDomainsBrute.git /opt/subDomainsBrute
46 | RUN apt install -y python-pip
47 | RUN python2 -m pip install dnspython gevent
48 |
49 | # Install Sublist3r
50 | RUN mkdir -p /opt/Sublist3r
51 | RUN git clone https://github.com/aboul3la/Sublist3r.git /opt/Sublist3r
52 | RUN pip install -r /opt/Sublist3r/requirements.txt
53 |
54 | # Install pekja
55 | RUN mkdir -p /opt/pekja
56 | COPY requirements.txt /opt/pekja/requirements.txt
57 | RUN pip install -r /opt/pekja/requirements.txt
58 | COPY . /opt/pekja
59 | RUN chmod +x /opt/pekja/docker/start.sh
60 |
61 | # Run pekja
62 | WORKDIR /opt/pekja
63 | EXPOSE 8000
64 | ENTRYPOINT ["/opt/pekja/docker/start.sh"]
65 |
--------------------------------------------------------------------------------
/templates/page/show_code.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Show Code
6 |
7 |
8 | {% load static %}
9 |
10 |
11 |
12 |
13 |
23 |
24 |
25 |
38 |
39 |
40 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib64/
18 | parts/
19 | sdist/
20 | var/
21 | wheels/
22 | pip-wheel-metadata/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 |
53 | # Translations
54 | *.mo
55 | *.pot
56 |
57 | # Django stuff:
58 | *.log
59 | local_settings.py
60 | data/db.sqlite3
61 | db.sqlite3-journal
62 |
63 | # Flask stuff:
64 | instance/
65 | .webassets-cache
66 |
67 | # Scrapy stuff:
68 | .scrapy
69 |
70 | # Sphinx documentation
71 | docs/_build/
72 |
73 | # PyBuilder
74 | target/
75 |
76 | # Jupyter Notebook
77 | .ipynb_checkpoints
78 |
79 | # IPython
80 | profile_default/
81 | ipython_config.py
82 |
83 | # pyenv
84 | .python-version
85 |
86 | # pipenv
87 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
88 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
89 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
90 | # install all needed dependencies.
91 | #Pipfile.lock
92 |
93 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
94 | __pypackages__/
95 |
96 | # Celery stuff
97 | celerybeat-schedule
98 | celerybeat.pid
99 |
100 | # SageMath parsed files
101 | *.sage.py
102 |
103 | # Environments
104 | .env
105 | .venv
106 | docker/env.example/
107 | venv/
108 | docker/env.example/
109 | env.bak/
110 | venv.bak/
111 |
112 | # Spyder project settings
113 | .spyderproject
114 | .spyproject
115 |
116 | # Rope project settings
117 | .ropeproject
118 |
119 | # mkdocs documentation
120 | /site
121 |
122 | # mypy
123 | .mypy_cache/
124 | .dmypy.json
125 | dmypy.json
126 |
127 | # Pyre type checker
128 | .pyre/
129 |
130 | # Custom
131 | venv/
132 | .idea/
133 | *.log
134 | data/*.txt
135 |
--------------------------------------------------------------------------------
/docker/start.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Set timezone and restart crontab
4 | echo TZ=$(cat /etc/timezone) >> /etc/crontab
5 | echo CRON_TZ=$(cat /etc/timezone) >> /etc/crontab
6 | service cron restart
7 |
8 | # Set OneForAll's API
9 | echo "censys_api_id = '$CENSYS_API_ID'" >> /opt/oneforall/api.py
10 | echo "censys_api_secret = '$CENSYS_API_SECRET'" >> /opt/oneforall/api.py
11 | echo "binaryedge_api = '$BINARYEDGE_API'" >> /opt/oneforall/api.py
12 | echo "chinaz_api = '$CHINAZ_API'" >> /opt/oneforall/api.py
13 | echo "bing_api_id = '$BING_API_ID'" >> /opt/oneforall/api.py
14 | echo "bing_api_key = '$BING_API_KEY'" >> /opt/oneforall/api.py
15 | echo "securitytrails_api = '$SECURITYTRAILS_API'" >> /opt/oneforall/api.py
16 | echo "fofa_api_email = '$FOFA_API_EMAIL'" >> /opt/oneforall/api.py
17 | echo "fofa_api_key = '$FOFA_API_KEY'" >> /opt/oneforall/api.py
18 | echo "google_api_key = '$GOOGLE_API_KEY'" >> /opt/oneforall/api.py
19 | echo "google_api_cx = '$GOOGLE_API_CX'" >> /opt/oneforall/api.py
20 | echo "riskiq_api_username = '$RISKIQ_API_USERNAME'" >> /opt/oneforall/api.py
21 | echo "riskiq_api_key = '$RISKIQ_API_KEY'" >> /opt/oneforall/api.py
22 | echo "shodan_api_key = '$SHODAN_API_KEY'" >> /opt/oneforall/api.py
23 | echo "threatbook_api_key = '$THREATBOOK_API_KEY'" >> /opt/oneforall/api.py
24 | echo "virustotal_api_key = '$VIRUSTOTAL_API_KEY'" >> /opt/oneforall/api.py
25 | echo "zoomeye_api_usermail = '$ZOOMEYE_API_USERMAIL'" >> /opt/oneforall/api.py
26 | echo "zoomeye_api_password = '$ZOOMEYE_API_PASSWORD'" >> /opt/oneforall/api.py
27 | echo "spyse_api_token = '$SPYSE_API_TOKEN'" >> /opt/oneforall/api.py
28 | echo "circl_api_username = '$CIRCL_API_USERNAME'" >> /opt/oneforall/api.py
29 | echo "circl_api_password = '$CIRCL_API_PASSWORD'" >> /opt/oneforall/api.py
30 | echo "dnsdb_api_key = '$DNSDB_API_KEY'" >> /opt/oneforall/api.py
31 | echo "ipv4info_api_key = '$IPV4INFO_API_KEY'" >> /opt/oneforall/api.py
32 | echo "passivedns_api_addr = '$PASSIVEDNS_API_ADDR'" >> /opt/oneforall/api.py
33 | echo "passivedns_api_token = '$PASSIVEDNS_API_TOKEN'" >> /opt/oneforall/api.py
34 | echo "github_api_user = '$GITHUB_API_USER'" >> /opt/oneforall/api.py
35 | echo "github_api_token = '$GITHUB_API_TOKEN'" >> /opt/oneforall/api.py
36 | echo "github_email = '$GITHUB_EMAIL'" >> /opt/oneforall/api.py
37 | echo "github_password = '$GITHUB_PASSWORD'" >> /opt/oneforall/api.py
38 |
39 | # Start pekja
40 | python manage.py migrate --noinput
41 | python manage.py init_admin $INIT_ADMIN_USER $INIT_ADMIN_EMAIL $INIT_ADMIN_PASSWORD
42 | python manage.py loaddata docker/tool.json
43 | python manage.py cron_all_task
44 | python manage.py set_record_report_cron data/mail_report_dispatch.txt
45 | python manage.py runserver 0.0.0.0:8000
46 |
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/lay/modules/rate.js:
--------------------------------------------------------------------------------
1 | /** layui-v2.5.5 MIT License By https://www.layui.com */
2 | ;layui.define("jquery",function(e){"use strict";var a=layui.jquery,i={config:{},index:layui.rate?layui.rate.index+1e4:0,set:function(e){var i=this;return i.config=a.extend({},i.config,e),i},on:function(e,a){return layui.onevent.call(this,n,e,a)}},l=function(){var e=this,a=e.config;return{setvalue:function(a){e.setvalue.call(e,a)},config:a}},n="rate",t="layui-rate",o="layui-icon-rate",s="layui-icon-rate-solid",u="layui-icon-rate-half",r="layui-icon-rate-solid layui-icon-rate-half",c="layui-icon-rate-solid layui-icon-rate",f="layui-icon-rate layui-icon-rate-half",v=function(e){var l=this;l.index=++i.index,l.config=a.extend({},l.config,i.config,e),l.render()};v.prototype.config={length:5,text:!1,readonly:!1,half:!1,value:0,theme:""},v.prototype.render=function(){var e=this,i=e.config,l=i.theme?'style="color: '+i.theme+';"':"";i.elem=a(i.elem),parseInt(i.value)!==i.value&&(i.half||(i.value=Math.ceil(i.value)-i.value<.5?Math.ceil(i.value):Math.floor(i.value)));for(var n='",u=1;u<=i.length;u++){var r=' ";i.half&&parseInt(i.value)!==i.value&&u==Math.ceil(i.value)?n=n+' ":n+=r}n+="
"+(i.text?''+i.value+"星":"")+"";var c=i.elem,f=c.next("."+t);f[0]&&f.remove(),e.elemTemp=a(n),i.span=e.elemTemp.next("span"),i.setText&&i.setText(i.value),c.html(e.elemTemp),c.addClass("layui-inline"),i.readonly||e.action()},v.prototype.setvalue=function(e){var a=this,i=a.config;i.value=e,a.render()},v.prototype.action=function(){var e=this,i=e.config,l=e.elemTemp,n=l.find("i").width();l.children("li").each(function(e){var t=e+1,v=a(this);v.on("click",function(e){if(i.value=t,i.half){var o=e.pageX-a(this).offset().left;o<=n/2&&(i.value=i.value-.5)}i.text&&l.next("span").text(i.value+"星"),i.choose&&i.choose(i.value),i.setText&&i.setText(i.value)}),v.on("mousemove",function(e){if(l.find("i").each(function(){a(this).addClass(o).removeClass(r)}),l.find("i:lt("+t+")").each(function(){a(this).addClass(s).removeClass(f)}),i.half){var c=e.pageX-a(this).offset().left;c<=n/2&&v.children("i").addClass(u).removeClass(s)}}),v.on("mouseleave",function(){l.find("i").each(function(){a(this).addClass(o).removeClass(r)}),l.find("i:lt("+Math.floor(i.value)+")").each(function(){a(this).addClass(s).removeClass(f)}),i.half&&parseInt(i.value)!==i.value&&l.children("li:eq("+Math.floor(i.value)+")").children("i").addClass(u).removeClass(c)})})},v.prototype.events=function(){var e=this;e.config},i.render=function(e){var a=new v(e);return l.call(a)},e(n,i)});
--------------------------------------------------------------------------------
/templates/page/killer.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 结束进程
6 |
7 |
8 | {% load static %}
9 |
10 |
11 |
12 |
13 |
23 |
24 |
25 |
52 | {% if error_msg %}
53 |
54 |
55 |
61 | {% endif %}
62 |
63 |
64 |
--------------------------------------------------------------------------------
/docker/tool.json:
--------------------------------------------------------------------------------
1 | [{"model": "entities.tool", "pk": 1, "fields": {"name": "Nmap\u5b50\u57df\u540d\u7206\u7834", "link": "https://nmap.org/", "type": "\u57df\u540d", "parse_class_name": "NmapDnsBruteParser", "command": "nmap -sn -Pn --script=dns-brute {input} -oX {output_file}", "input_type": "parameter", "version": "7.7.0", "comment": ""}}, {"model": "entities.tool", "pk": 2, "fields": {"name": "Nmap SYN\u626b\u63cf", "link": "https://nmap.org/", "type": "TCP\u7aef\u53e3", "parse_class_name": "NmapSynScanParser", "command": "nmap -sS -p- -iL {input} -oX {output_file} --open", "input_type": "file", "version": "7.7.0", "comment": ""}}, {"model": "entities.tool", "pk": 3, "fields": {"name": "Nmap UDP\u7aef\u53e3\u626b\u63cf", "link": "https://nmap.org/", "type": "UDP\u7aef\u53e3", "parse_class_name": "NmapUdpScanParser", "command": "nmap -sU -p- -iL {input} -oX {output_file} --open", "input_type": "file", "version": "7.7.0", "comment": ""}}, {"model": "entities.tool", "pk": 4, "fields": {"name": "Censys\u5b50\u57df\u540d\u91c7\u96c6", "link": "https://github.com/0xbharath/censys-enumeration/", "type": "\u57df\u540d", "parse_class_name": "CensysEnumerationDomain", "command": "/usr/local/bin/python /opt/censys_enumeration/censys_enumeration.py --outfile {output_file} {input}", "input_type": "file", "version": "10d42fa3", "comment": ""}}, {"model": "entities.tool", "pk": 5, "fields": {"name": "Censys\u90ae\u7bb1\u91c7\u96c6", "link": "https://github.com/0xbharath/censys-enumeration/", "type": "\u90ae\u7bb1", "parse_class_name": "CensysEnumerationEmail", "command": "/usr/local/bin/python /opt/censys_enumeration/censys_enumeration.py --outfile {output_file} {input}", "input_type": "file", "version": "10d42fa3", "comment": ""}}, {"model": "entities.tool", "pk": 6, "fields": {"name": "CTFR", "link": "https://github.com/UnaPibaGeek/ctfr", "type": "\u57df\u540d", "parse_class_name": "CTFRParser", "command": "/usr/local/bin/python /opt/ctfr/ctfr.py -d {input} -o {output_file}", "input_type": "parameter", "version": "86a804a", "comment": ""}}, {"model": "entities.tool", "pk": 7, "fields": {"name": "OneForAll\u5b50\u57df\u540d\u6536\u96c6", "link": "https://github.com/shmilylty/OneForAll", "type": "\u57df\u540d", "parse_class_name": "OneForAllParser", "command": "/usr/local/bin/python /opt/oneforall/oneforall.py --target {input} --path {output_file} --format json run", "input_type": "file", "version": "0.3.0", "comment": "\u5b58\u5728\u8fd0\u884c\u5b8c\u540e\u65e0\u6cd5\u9000\u51fa\u7684BUG"}}, {"model": "entities.tool", "pk": 8, "fields": {"name": "lijiejie/subDomainsBrute", "link": "https://github.com/lijiejie/subDomainsBrute", "type": "\u57df\u540d", "parse_class_name": "LijiejieSubDomainsBrute", "command": "cd /opt/subDomainsBrute;/usr/bin/python2 subDomainsBrute.py --full -o {output_file} {input}", "input_type": "parameter", "version": "bac5eb3", "comment": ""}}, {"model": "entities.tool", "pk": 9, "fields": {"name": "Sublist3r", "link": "https://github.com/aboul3la/Sublist3r", "type": "\u57df\u540d", "parse_class_name": "Sublist3rParser", "command": "/usr/local/bin/python /opt/Sublist3r/sublist3r.py -d {input} -e Baidu,Yahoo,Bing,Ask,Netcraft,DNSdumpster,Virustotal,ThreatCrowd,SSL,PassiveDNS -b -o {output_file}", "input_type": "parameter", "version": "61ebf36", "comment": ""}}, {"model": "entities.tool", "pk": 11, "fields": {"name": "Nmap HTTP\u626b\u63cf", "link": "https://nmap.org/", "type": "\u7f51\u7ad9", "parse_class_name": "NmapHTTPScanParser", "command": "nmap -sV -sC -p 80,443,7000,8080 -iL {input} --open -oX {output_file}", "input_type": "file", "version": "7.7.0", "comment": ""}}]
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/lay/modules/util.js:
--------------------------------------------------------------------------------
1 | /** layui-v2.5.5 MIT License By https://www.layui.com */
2 | ;layui.define("jquery",function(t){"use strict";var e=layui.$,i={fixbar:function(t){var i,n,a="layui-fixbar",o="layui-fixbar-top",r=e(document),l=e("body");t=e.extend({showHeight:200},t),t.bar1=t.bar1===!0?"":t.bar1,t.bar2=t.bar2===!0?"":t.bar2,t.bgcolor=t.bgcolor?"background-color:"+t.bgcolor:"";var c=[t.bar1,t.bar2,""],g=e(['',t.bar1?'- '+c[0]+"
":"",t.bar2?'- '+c[1]+"
":"",'- '+c[2]+"
","
"].join("")),s=g.find("."+o),u=function(){var e=r.scrollTop();e>=t.showHeight?i||(s.show(),i=1):i&&(s.hide(),i=0)};e("."+a)[0]||("object"==typeof t.css&&g.css(t.css),l.append(g),u(),g.find("li").on("click",function(){var i=e(this),n=i.attr("lay-type");"top"===n&&e("html,body").animate({scrollTop:0},200),t.click&&t.click.call(this,n)}),r.on("scroll",function(){clearTimeout(n),n=setTimeout(function(){u()},100)}))},countdown:function(t,e,i){var n=this,a="function"==typeof e,o=new Date(t).getTime(),r=new Date(!e||a?(new Date).getTime():e).getTime(),l=o-r,c=[Math.floor(l/864e5),Math.floor(l/36e5)%24,Math.floor(l/6e4)%60,Math.floor(l/1e3)%60];a&&(i=e);var g=setTimeout(function(){n.countdown(t,r+1e3,i)},1e3);return i&&i(l>0?c:[0,0,0,0],e,g),l<=0&&clearTimeout(g),g},timeAgo:function(t,e){var i=this,n=[[],[]],a=(new Date).getTime()-new Date(t).getTime();return a>6912e5?(a=new Date(t),n[0][0]=i.digit(a.getFullYear(),4),n[0][1]=i.digit(a.getMonth()+1),n[0][2]=i.digit(a.getDate()),e||(n[1][0]=i.digit(a.getHours()),n[1][1]=i.digit(a.getMinutes()),n[1][2]=i.digit(a.getSeconds())),n[0].join("-")+" "+n[1].join(":")):a>=864e5?(a/1e3/60/60/24|0)+"天前":a>=36e5?(a/1e3/60/60|0)+"小时前":a>=12e4?(a/1e3/60|0)+"分钟前":a<0?"未来":"刚刚"},digit:function(t,e){var i="";t=String(t),e=e||2;for(var n=t.length;n/g,">").replace(/'/g,"'").replace(/"/g,""")},event:function(t,n,a){n=i.event[t]=e.extend(!0,i.event[t],n)||{},e("body").on(a||"click","*["+t+"]",function(){var i=e(this),a=i.attr(t);n[a]&&n[a].call(this,i)})}};!function(t,e,i){"$:nomunge";function n(){a=e[l](function(){o.each(function(){var e=t(this),i=e.width(),n=e.height(),a=t.data(this,g);(i!==a.w||n!==a.h)&&e.trigger(c,[a.w=i,a.h=n])}),n()},r[s])}var a,o=t([]),r=t.resize=t.extend(t.resize,{}),l="setTimeout",c="resize",g=c+"-special-event",s="delay",u="throttleWindow";r[s]=250,r[u]=!0,t.event.special[c]={setup:function(){if(!r[u]&&this[l])return!1;var e=t(this);o=o.add(e),t.data(this,g,{w:e.width(),h:e.height()}),1===o.length&&n()},teardown:function(){if(!r[u]&&this[l])return!1;var e=t(this);o=o.not(e),e.removeData(g),o.length||clearTimeout(a)},add:function(e){function n(e,n,o){var r=t(this),l=t.data(this,g)||{};l.w=n!==i?n:r.width(),l.h=o!==i?o:r.height(),a.apply(this,arguments)}if(!r[u]&&this[l])return!1;var a;return t.isFunction(e)?(a=e,n):(a=e.handler,void(e.handler=n))}}}(e,window),t("util",i)});
--------------------------------------------------------------------------------
/entities/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from django.utils.html import format_html
3 | from django.utils.html import escape
4 |
5 | from import_export.admin import ImportExportActionModelAdmin
6 |
7 | from command.cron_task import set_cron_task
8 | from command.cron_task import set_cron_batch_task
9 | from .forms import ToolForm
10 | from .resources import *
11 |
12 |
13 | @admin.register(Project)
14 | class ProjectAdmin(ImportExportActionModelAdmin):
15 | list_display = ['name', 'src_link_url']
16 | search_fields = ['name', 'comment']
17 | resource_class = ProjectResource
18 |
19 | def src_link_url(self, obj):
20 | if obj.src_link:
21 | url = obj.src_link.replace('"', r'%22')
22 | return format_html('{}'.format(url, escape(obj.src_link)))
23 | else:
24 | return obj.src_link
25 |
26 | src_link_url.short_description = 'SRC链接'
27 |
28 |
29 | @admin.register(Record)
30 | class RecordAdmin(ImportExportActionModelAdmin):
31 | list_display = ['record', 'project', 'add_time', 'last_modify_time', 'type', 'source']
32 | search_fields = ['record', 'source']
33 | list_filter = ('project', 'type', 'source')
34 | resource_class = RecordResource
35 |
36 |
37 | @admin.register(Tool)
38 | class ToolAdmin(ImportExportActionModelAdmin):
39 | list_display = ['name', 'link_url', 'version', 'type', 'parse_class_name', 'command', 'input_type', 'comment']
40 | search_fields = ['name', 'command', 'comment']
41 | list_filter = ('type', 'input_type')
42 | resource_class = ToolResource
43 | form = ToolForm
44 |
45 | def save_model(self, request, obj, form, change):
46 | obj.save()
47 | for task in obj.task_set.all():
48 | set_cron_task(task)
49 | for i in range(1, BatchTask.MAX_TASK_AMOUNT + 1):
50 | for batch_task in getattr(task, 'task{}'.format(i)).all():
51 | set_cron_batch_task(batch_task)
52 |
53 | def link_url(self, obj):
54 | if obj.link:
55 | url = obj.link.replace('"', r'%22')
56 | return format_html('{}'.format(url, escape(obj.link)))
57 | else:
58 | return obj.link
59 |
60 | link_url.short_description = '项目链接'
61 |
62 |
63 | @admin.register(Task)
64 | class TaskAdmin(ImportExportActionModelAdmin):
65 | list_display = ['id', 'name', 'project', 'tool', 'input_overview', 'dispatch', 'active']
66 | search_fields = ['name', 'input']
67 | list_filter = ('project', 'tool', 'active')
68 | resource_class = TaskResource
69 |
70 | def save_model(self, request, obj, form, change):
71 | obj.save()
72 | set_cron_task(obj)
73 | for i in range(1, BatchTask.MAX_TASK_AMOUNT+1):
74 | for batch_task in getattr(obj, 'task{}'.format(i)).all():
75 | set_cron_batch_task(batch_task)
76 |
77 | def input_overview(self, obj):
78 | if len(obj.input) > 20:
79 | return obj.input[:20] + '...'
80 | else:
81 | return obj.input
82 | input_overview.short_description = '输入'
83 |
84 |
85 | @admin.register(BatchTask)
86 | class BatchTaskAdmin(ImportExportActionModelAdmin):
87 | list_display = ['id', 'name', 'task1', 'task2', 'task3', 'task4', 'task5', 'task6', 'task7', 'task8', 'task9',
88 | 'task10', 'dispatch', 'active']
89 | search_fields = ['name']
90 | list_filter = ('active', )
91 | resource_class = BatchTaskResource
92 |
93 | def save_model(self, request, obj, form, change):
94 | obj.save()
95 | set_cron_batch_task(obj)
96 |
97 |
98 | admin.site.site_header = 'Pekja'
99 |
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/lay/modules/carousel.js:
--------------------------------------------------------------------------------
1 | /** layui-v2.5.5 MIT License By https://www.layui.com */
2 | ;layui.define("jquery",function(e){"use strict";var i=layui.$,n=(layui.hint(),layui.device(),{config:{},set:function(e){var n=this;return n.config=i.extend({},n.config,e),n},on:function(e,i){return layui.onevent.call(this,t,e,i)}}),t="carousel",a="layui-this",l=">*[carousel-item]>*",o="layui-carousel-left",r="layui-carousel-right",d="layui-carousel-prev",s="layui-carousel-next",u="layui-carousel-arrow",c="layui-carousel-ind",m=function(e){var t=this;t.config=i.extend({},t.config,n.config,e),t.render()};m.prototype.config={width:"600px",height:"280px",full:!1,arrow:"hover",indicator:"inside",autoplay:!0,interval:3e3,anim:"",trigger:"click",index:0},m.prototype.render=function(){var e=this,n=e.config;n.elem=i(n.elem),n.elem[0]&&(e.elemItem=n.elem.find(l),n.index<0&&(n.index=0),n.index>=e.elemItem.length&&(n.index=e.elemItem.length-1),n.interval<800&&(n.interval=800),n.full?n.elem.css({position:"fixed",width:"100%",height:"100%",zIndex:9999}):n.elem.css({width:n.width,height:n.height}),n.elem.attr("lay-anim",n.anim),e.elemItem.eq(n.index).addClass(a),e.elemItem.length<=1||(e.indicator(),e.arrow(),e.autoplay(),e.events()))},m.prototype.reload=function(e){var n=this;clearInterval(n.timer),n.config=i.extend({},n.config,e),n.render()},m.prototype.prevIndex=function(){var e=this,i=e.config,n=i.index-1;return n<0&&(n=e.elemItem.length-1),n},m.prototype.nextIndex=function(){var e=this,i=e.config,n=i.index+1;return n>=e.elemItem.length&&(n=0),n},m.prototype.addIndex=function(e){var i=this,n=i.config;e=e||1,n.index=n.index+e,n.index>=i.elemItem.length&&(n.index=0)},m.prototype.subIndex=function(e){var i=this,n=i.config;e=e||1,n.index=n.index-e,n.index<0&&(n.index=i.elemItem.length-1)},m.prototype.autoplay=function(){var e=this,i=e.config;i.autoplay&&(clearInterval(e.timer),e.timer=setInterval(function(){e.slide()},i.interval))},m.prototype.arrow=function(){var e=this,n=e.config,t=i(['",'"].join(""));n.elem.attr("lay-arrow",n.arrow),n.elem.find("."+u)[0]&&n.elem.find("."+u).remove(),n.elem.append(t),t.on("click",function(){var n=i(this),t=n.attr("lay-type");e.slide(t)})},m.prototype.indicator=function(){var e=this,n=e.config,t=e.elemInd=i(['',function(){var i=[];return layui.each(e.elemItem,function(e){i.push("")}),i.join("")}(),"
"].join(""));n.elem.attr("lay-indicator",n.indicator),n.elem.find("."+c)[0]&&n.elem.find("."+c).remove(),n.elem.append(t),"updown"===n.anim&&t.css("margin-top",-(t.height()/2)),t.find("li").on("hover"===n.trigger?"mouseover":n.trigger,function(){var t=i(this),a=t.index();a>n.index?e.slide("add",a-n.index):a
2 |
3 |
4 |
5 | 文件查看
6 |
7 |
8 | {% load static %}
9 |
10 |
11 |
12 |
13 |
23 |
24 |
25 |
49 |
50 |
51 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/pekja/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for pekja project.
3 |
4 | Generated by 'django-admin startproject' using Django 3.0.4.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/3.0/topics/settings/
8 |
9 | For the full list of settings and their values, see
10 | https://docs.djangoproject.com/en/3.0/ref/settings/
11 | """
12 |
13 | import os
14 |
15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
17 |
18 |
19 | # Quick-start development settings - unsuitable for production
20 | # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
21 |
22 | # SECURITY WARNING: keep the secret key used in production secret!
23 | SECRET_KEY = '!2v^7t9b+%1xqeecwni&b3&y=%kj+80#l1lyd1&f)d3-ukcv3&'
24 |
25 | # SECURITY WARNING: don't run with debug turned on in production!
26 | DEBUG = True
27 |
28 | ALLOWED_HOSTS = ['*']
29 |
30 |
31 | # Application definition
32 |
33 | INSTALLED_APPS = [
34 | 'django.contrib.admin',
35 | 'django.contrib.auth',
36 | 'django.contrib.contenttypes',
37 | 'django.contrib.sessions',
38 | 'django.contrib.messages',
39 | 'django.contrib.staticfiles',
40 | 'import_export',
41 | 'layuimini',
42 | 'entities',
43 | 'command',
44 | ]
45 |
46 | MIDDLEWARE = [
47 | 'django.middleware.security.SecurityMiddleware',
48 | 'django.contrib.sessions.middleware.SessionMiddleware',
49 | 'django.middleware.common.CommonMiddleware',
50 | 'django.middleware.csrf.CsrfViewMiddleware',
51 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
52 | 'django.contrib.messages.middleware.MessageMiddleware',
53 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
54 | ]
55 |
56 | ROOT_URLCONF = 'pekja.urls'
57 |
58 | TEMPLATES = [
59 | {
60 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
61 | 'DIRS': [os.path.join(BASE_DIR, 'templates')],
62 | 'APP_DIRS': True,
63 | 'OPTIONS': {
64 | 'context_processors': [
65 | 'django.template.context_processors.debug',
66 | 'django.template.context_processors.request',
67 | 'django.contrib.auth.context_processors.auth',
68 | 'django.contrib.messages.context_processors.messages',
69 | ],
70 | },
71 | },
72 | ]
73 |
74 | WSGI_APPLICATION = 'pekja.wsgi.application'
75 |
76 |
77 | # Database
78 | # https://docs.djangoproject.com/en/3.0/ref/settings/#databases
79 |
80 | DATABASES = {
81 | 'default': {
82 | 'ENGINE': 'django.db.backends.sqlite3',
83 | 'NAME': os.path.join(BASE_DIR, 'data', 'db.sqlite3'),
84 | }
85 | }
86 |
87 |
88 | # Password validation
89 | # https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
90 |
91 | AUTH_PASSWORD_VALIDATORS = [
92 | {
93 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
94 | },
95 | {
96 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
97 | },
98 | {
99 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
100 | },
101 | {
102 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
103 | },
104 | ]
105 |
106 |
107 | # Internationalization
108 | # https://docs.djangoproject.com/en/3.0/topics/i18n/
109 |
110 | LANGUAGE_CODE = 'zh-Hans'
111 |
112 | TIME_ZONE = 'Asia/Shanghai'
113 |
114 | USE_I18N = True
115 |
116 | USE_L10N = True
117 |
118 | USE_TZ = True
119 |
120 |
121 | # Static files (CSS, JavaScript, Images)
122 | # https://docs.djangoproject.com/en/3.0/howto/static-files/
123 |
124 | STATIC_URL = '/static/'
125 | STATICFILES_DIRS = [
126 | os.path.join(BASE_DIR, "static"),
127 | ]
128 |
129 | DATA_DIRS = os.path.join(BASE_DIR, "data")
130 | CRON_USER = True # 为True表示当前用户,也可以写具体的用户名
131 |
132 | EMAIL_USE_SSL = True if os.environ.get('EMAIL_USE_SSL') else False
133 | EMAIL_HOST = os.environ.get('EMAIL_HOST')
134 | EMAIL_PORT = os.environ.get('EMAIL_PORT')
135 | EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER')
136 | EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD')
137 | DEFAULT_FROM_EMAIL = 'Pekja <{}>'.format(EMAIL_HOST_USER)
138 |
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/lay/modules/laypage.js:
--------------------------------------------------------------------------------
1 | /** layui-v2.5.5 MIT License By https://www.layui.com */
2 | ;layui.define(function(e){"use strict";var a=document,t="getElementById",n="getElementsByTagName",i="laypage",r="layui-disabled",u=function(e){var a=this;a.config=e||{},a.config.index=++s.index,a.render(!0)};u.prototype.type=function(){var e=this.config;if("object"==typeof e.elem)return void 0===e.elem.length?2:3},u.prototype.view=function(){var e=this,a=e.config,t=a.groups="groups"in a?0|a.groups:5;a.layout="object"==typeof a.layout?a.layout:["prev","page","next"],a.count=0|a.count,a.curr=0|a.curr||1,a.limits="object"==typeof a.limits?a.limits:[10,20,30,40,50],a.limit=0|a.limit||10,a.pages=Math.ceil(a.count/a.limit)||1,a.curr>a.pages&&(a.curr=a.pages),t<0?t=1:t>a.pages&&(t=a.pages),a.prev="prev"in a?a.prev:"上一页",a.next="next"in a?a.next:"下一页";var n=a.pages>t?Math.ceil((a.curr+(t>1?1:0))/(t>0?t:1)):1,i={prev:function(){return a.prev?''+a.prev+"":""}(),page:function(){var e=[];if(a.count<1)return"";n>1&&a.first!==!1&&0!==t&&e.push(''+(a.first||1)+"");var i=Math.floor((t-1)/2),r=n>1?a.curr-i:1,u=n>1?function(){var e=a.curr+(t-i-1);return e>a.pages?a.pages:e}():t;for(u-r2&&e.push('…');r<=u;r++)r===a.curr?e.push('"+r+""):e.push(''+r+"");return a.pages>t&&a.pages>u&&a.last!==!1&&(u+1…'),0!==t&&e.push(''+(a.last||a.pages)+"")),e.join("")}(),next:function(){return a.next?''+a.next+"":""}(),count:'共 '+a.count+" 条",limit:function(){var e=['"}(),refresh:['','',""].join(""),skip:function(){return['到第','','页',""].join("")}()};return['',function(){var e=[];return layui.each(a.layout,function(a,t){i[t]&&e.push(i[t])}),e.join("")}(),"
"].join("")},u.prototype.jump=function(e,a){if(e){var t=this,i=t.config,r=e.children,u=e[n]("button")[0],l=e[n]("input")[0],p=e[n]("select")[0],c=function(){var e=0|l.value.replace(/\s|\D/g,"");e&&(i.curr=e,t.render())};if(a)return c();for(var o=0,y=r.length;oi.pages||(i.curr=e,t.render())});p&&s.on(p,"change",function(){var e=this.value;i.curr*e>i.count&&(i.curr=Math.ceil(i.count/e)),i.limit=e,t.render()}),u&&s.on(u,"click",function(){c()})}},u.prototype.skip=function(e){if(e){var a=this,t=e[n]("input")[0];t&&s.on(t,"keyup",function(t){var n=this.value,i=t.keyCode;/^(37|38|39|40)$/.test(i)||(/\D/.test(n)&&(this.value=n.replace(/\D/,"")),13===i&&a.jump(e,!0))})}},u.prototype.render=function(e){var n=this,i=n.config,r=n.type(),u=n.view();2===r?i.elem&&(i.elem.innerHTML=u):3===r?i.elem.html(u):a[t](i.elem)&&(a[t](i.elem).innerHTML=u),i.jump&&i.jump(i,e);var s=a[t]("layui-laypage-"+i.index);n.jump(s),i.hash&&!e&&(location.hash="!"+i.hash+"="+i.curr),n.skip(s)};var s={render:function(e){var a=new u(e);return a.index},index:layui.laypage?layui.laypage.index+1e4:0,on:function(e,a,t){return e.attachEvent?e.attachEvent("on"+a,function(a){a.target=a.srcElement,t.call(e,a)}):e.addEventListener(a,t,!1),this}};e(i,s)});
--------------------------------------------------------------------------------
/templates/login.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | pekja管理-登录
6 |
7 |
8 |
9 |
10 |
11 | {% load static %}
12 |
13 |
17 |
36 |
37 |
38 |
58 |
59 |
86 |
87 |
--------------------------------------------------------------------------------
/pekja/utils.py:
--------------------------------------------------------------------------------
1 | import os
2 | from html import escape
3 | from platform import system
4 |
5 | from crontab import CronTab
6 |
7 | from django.core.mail import EmailMessage
8 | from django.template.loader import render_to_string
9 | from django.contrib.auth import get_user_model
10 |
11 | from pekja.settings import DEFAULT_FROM_EMAIL
12 | from pekja.settings import DATA_DIRS
13 | from pekja.settings import CRON_USER
14 | from entities.models import Task
15 |
16 |
17 | def get_input_file_path(obj):
18 | return os.path.join(DATA_DIRS, 'input-{}.txt'.format(obj.id))
19 |
20 |
21 | def get_output_file_path(obj):
22 | return os.path.join(DATA_DIRS, 'output-{}.txt'.format(obj.id))
23 |
24 |
25 | def get_mail_report_dispatch_file_path():
26 | return os.path.join(DATA_DIRS, 'mail_report_dispatch.txt')
27 |
28 |
29 | def get_task_cron_comment(obj):
30 | return 'task-{}-pekja'.format(obj.id)
31 |
32 |
33 | def get_batch_task_cron_comment(obj):
34 | return 'batch-task-{}-pekja'.format(obj.id)
35 |
36 |
37 | def get_mail_report_cron_comment():
38 | return '#send-mail-report-pekja'
39 |
40 |
41 | def get_windows_cron_file_path():
42 | cron_file_path = os.path.join(DATA_DIRS, 'windows_crontab.txt')
43 | if not os.path.exists(cron_file_path):
44 | with open(cron_file_path, 'w') as f:
45 | pass
46 | return cron_file_path
47 |
48 |
49 | def get_task_by_id(task_id):
50 | """
51 | 根据ID返回Task
52 | :param task_id:
53 | :return:
54 | """
55 | try:
56 | task = Task.objects.get(id=task_id)
57 | except Task.DoesNotExist:
58 | return None
59 | else:
60 | return task
61 |
62 |
63 | def get_user_emails():
64 | """
65 | 获取所有用户的邮箱地址
66 | :return:
67 | """
68 | user = get_user_model()
69 | emails = [email for email in user.objects.values_list('email', flat=True) if email != '']
70 | return emails
71 |
72 |
73 | def send_mail_to_users(subject, title, message):
74 | """
75 | 给所有用户发送邮件
76 | :param subject:
77 | :param title:
78 | :param message:
79 | :return:
80 | """
81 | emails = get_user_emails()
82 | if len(emails) > 0:
83 | msg_html = render_to_string('email.html', {'title': title, 'content': message})
84 | msg = EmailMessage(subject=subject, body=msg_html, from_email=DEFAULT_FROM_EMAIL, to=emails)
85 | msg.content_subtype = 'html'
86 | return msg.send()
87 |
88 |
89 | def rowspan_html_table(headers, input_dict):
90 | """
91 | 将输入的字典转换为HTML表格
92 | :param headers:
93 | :param input_dict:
94 | :return:
95 | """
96 | table = ''
97 | for header in headers:
98 | table += '| ' + escape(header) + ' | '
99 | table += '
'
100 | for key in input_dict:
101 | for index, sub_key in enumerate(input_dict[key]):
102 | row = ''
103 | if index == 0:
104 | row += '| '.format(len(input_dict[key])) + key + ' | '
105 | row += '' + escape(sub_key) + ' | '
106 | row += '' + escape(str(input_dict[key][sub_key])) + ' | '
107 | row += '
'
108 | table += row
109 | table += '
'
110 | return table
111 |
112 |
113 | def open_crontab():
114 | """
115 | 打开crontab
116 | :return:
117 | """
118 | if system() == 'Windows':
119 | cron = CronTab(tabfile=get_windows_cron_file_path()) # 仅用于调试
120 | else:
121 | cron = CronTab(user=CRON_USER)
122 | return cron
123 |
124 |
125 | def human_size(size):
126 | def str_of_size(integer, remainder, level):
127 | if integer >= 1024:
128 | remainder = integer % 1024
129 | integer //= 1024
130 | level += 1
131 | return str_of_size(integer, remainder, level)
132 | else:
133 | return integer, remainder, level
134 |
135 | units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
136 | integer, remainder, level = str_of_size(size, 0, 0)
137 | if level + 1 > len(units):
138 | level = -1
139 | return '{}.{:>02d} {}'.format(integer, remainder, units[level])
140 |
--------------------------------------------------------------------------------
/entities/resources.py:
--------------------------------------------------------------------------------
1 | from import_export import fields
2 | from import_export import resources
3 | from import_export.widgets import DateTimeWidget
4 | from import_export.widgets import BooleanWidget
5 | from import_export.widgets import ForeignKeyWidget
6 |
7 | from .widgets import ChoicesWidget
8 | from .models import *
9 |
10 |
11 | class ProjectResource(resources.ModelResource):
12 |
13 | id = fields.Field(column_name='ID', attribute='id')
14 | name = fields.Field(column_name='项目名', attribute='name')
15 | src_link = fields.Field(column_name='SRC链接', attribute='src_link')
16 | comment = fields.Field(column_name='备注', attribute='comment')
17 |
18 | class Meta:
19 | model = Project
20 |
21 |
22 | class RecordResource(resources.ModelResource):
23 |
24 | id = fields.Field(column_name='ID', attribute='id')
25 | record = fields.Field(column_name='记录', attribute='record')
26 | project = fields.Field(column_name='项目', attribute='project', widget=ForeignKeyWidget(Project, 'name'))
27 | add_time = fields.Field(column_name='创建时间',
28 | attribute='add_time',
29 | widget=DateTimeWidget('%Y-%m-%d %H:%M:%S'))
30 | last_modify_time = fields.Field(column_name='最后修改时间',
31 | attribute='last_modify_time',
32 | widget=DateTimeWidget('%Y-%m-%d %H:%M:%S'))
33 | type = fields.Field(column_name='类型', attribute='type')
34 | source = fields.Field(column_name='来源', attribute='source')
35 |
36 | class Meta:
37 | model = Record
38 |
39 |
40 | class ToolResource(resources.ModelResource):
41 |
42 | id = fields.Field(column_name='ID', attribute='id')
43 | name = fields.Field(column_name='工具名', attribute='name')
44 | link = fields.Field(column_name='项目地址', attribute='link')
45 | type = fields.Field(column_name='记录类型', attribute='type')
46 | parse_class_name = fields.Field(column_name='解析类名', attribute='parse_class_name')
47 | command = fields.Field(column_name='调用命令', attribute='command')
48 | input_type = fields.Field(column_name='输入参数类型', attribute='input_type',
49 | widget=ChoicesWidget(Tool.input_type_choices))
50 | version = fields.Field(column_name='版本', attribute='version')
51 | comment = fields.Field(column_name='备注', attribute='comment')
52 |
53 | class Meta:
54 | model = Tool
55 |
56 |
57 | class TaskResource(resources.ModelResource):
58 |
59 | id = fields.Field(column_name='ID', attribute='id')
60 | name = fields.Field(column_name='任务名', attribute='name')
61 | project = fields.Field(column_name='项目', attribute='project', widget=ForeignKeyWidget(Project, 'name'))
62 | tool = fields.Field(column_name='工具', attribute='tool', widget=ForeignKeyWidget(Tool, 'name'))
63 | input = fields.Field(column_name='输入', attribute='input')
64 | dispatch = fields.Field(column_name='调度', attribute='dispatch')
65 | active = fields.Field(column_name='是否生效', attribute='active', widget=BooleanWidget())
66 |
67 | class Meta:
68 | model = Task
69 |
70 |
71 | class BatchTaskResource(resources.ModelResource):
72 |
73 | id = fields.Field(column_name='ID', attribute='id')
74 | name = fields.Field(column_name='任务名', attribute='name')
75 | task1 = fields.Field(column_name='任务1', attribute='task1', widget=ForeignKeyWidget(Task, 'name'))
76 | task2 = fields.Field(column_name='任务2', attribute='task2', widget=ForeignKeyWidget(Task, 'name'))
77 | task3 = fields.Field(column_name='任务3', attribute='task3', widget=ForeignKeyWidget(Task, 'name'))
78 | task4 = fields.Field(column_name='任务4', attribute='task4', widget=ForeignKeyWidget(Task, 'name'))
79 | task5 = fields.Field(column_name='任务5', attribute='task5', widget=ForeignKeyWidget(Task, 'name'))
80 | task6 = fields.Field(column_name='任务6', attribute='task6', widget=ForeignKeyWidget(Task, 'name'))
81 | task7 = fields.Field(column_name='任务7', attribute='task7', widget=ForeignKeyWidget(Task, 'name'))
82 | task8 = fields.Field(column_name='任务8', attribute='task8', widget=ForeignKeyWidget(Task, 'name'))
83 | task9 = fields.Field(column_name='任务9', attribute='task9', widget=ForeignKeyWidget(Task, 'name'))
84 | task10 = fields.Field(column_name='任务10', attribute='task10', widget=ForeignKeyWidget(Task, 'name'))
85 | dispatch = fields.Field(column_name='调度', attribute='dispatch')
86 | active = fields.Field(column_name='是否生效', attribute='active', widget=BooleanWidget())
87 |
88 | class Meta:
89 | model = BatchTask
90 |
--------------------------------------------------------------------------------
/templates/page/email_report_setting.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 邮件报告设置
6 |
7 |
8 | {% load static %}
9 |
10 |
11 |
12 |
13 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | 当前邮件报告接收者为: {% for email in emails %}{{ email }}{% if not forloop.last %}、{% endif %}{% endfor %},
36 | 可前往
「认证和授权 › 用户」进行修改。
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | {% if crontab %}
46 |
{{ crontab }}
47 | {% else %}
48 |
暂无发送邮件报告的定时任务
49 | {% endif %}
50 |
51 |
52 |
53 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/command/cron_task.py:
--------------------------------------------------------------------------------
1 | import os
2 | from sys import executable
3 |
4 | from pekja.utils import get_input_file_path
5 | from pekja.utils import get_output_file_path
6 | from pekja.utils import get_mail_report_dispatch_file_path
7 | from pekja.utils import get_task_cron_comment
8 | from pekja.utils import get_batch_task_cron_comment
9 | from pekja.utils import get_mail_report_cron_comment
10 | from pekja.utils import open_crontab
11 | from pekja.settings import BASE_DIR
12 | from entities.models import Tool
13 | from entities.models import Task
14 | from entities.models import Record
15 | from parse import get_parse_class
16 |
17 |
18 | def set_cron_task(obj):
19 | """
20 | 设置任务的定时任务
21 | :param obj: Task 模型对象
22 | :return:
23 | """
24 | command, comment = get_task_command(obj)
25 | set_crontab(obj.dispatch, command, comment, obj.active)
26 |
27 |
28 | def set_cron_batch_task(obj):
29 | """
30 | 设置批量任务的定时任务
31 | :param obj:
32 | :return:
33 | """
34 | commands = list()
35 | for task in obj.get_tasks():
36 | command, _ = get_task_command(task)
37 | commands.append(command)
38 | comment = get_batch_task_cron_comment(obj)
39 | if len(commands) > 0:
40 | set_crontab(obj.dispatch, ' && '.join(commands), comment, obj.active)
41 |
42 |
43 | def get_task_command(task):
44 | """
45 | 获取任务的命令
46 | :param task:
47 | :return: command, comment
48 | """
49 | output_file_path = get_output_file_path(task)
50 | task_cron_comment = get_task_cron_comment(task)
51 |
52 | if task.tool.input_type == Tool.INPUT_TYPE_FILE:
53 | if task.input_file_type == Task.INPUT_FILE_TYPE_STATIC:
54 | _input = update_static_input(task)
55 | else:
56 | _input = update_dynamic_input(task)
57 | else:
58 | _input = task.input
59 |
60 | pre_command = '{} {} update_input {}'.format(executable, os.path.join(BASE_DIR, 'manage.py'), task.id)
61 | tool_command = task.tool.command.replace('{input}', _input).replace('{output_file}', output_file_path)
62 | parse_command = '{} {} parse {}'.format(executable, os.path.join(BASE_DIR, 'manage.py'), task.id)
63 | if task.input_file_type == Task.INPUT_FILE_TYPE_DYNAMIC:
64 | command = ' && '.join([pre_command, tool_command, parse_command])
65 | else:
66 | command = ' && '.join([tool_command, parse_command])
67 |
68 | return command, task_cron_comment
69 |
70 |
71 | def run_parse(task):
72 | """
73 | 运行解析类解析任务输出结果
74 | :param task:
75 | :return:
76 | """
77 | parse_class = get_parse_class(task.tool.parse_class_name)
78 | if parse_class is None:
79 | print('Parse class {} does not exist'.format(task.tool.parse_class_name))
80 | else:
81 | p = parse_class(task)
82 | p.parse()
83 | p.rename_file()
84 |
85 |
86 | def update_dynamic_input(task):
87 | """
88 | 更新任务的动态输入
89 | :param task:
90 | :return:
91 | """
92 | if task.input_file_type == Task.INPUT_FILE_TYPE_DYNAMIC:
93 | input_file_path = get_input_file_path(task)
94 | with open(input_file_path, 'w') as f:
95 | for record in Record.objects.filter(project=task.project, type=task.input):
96 | f.write(record.record)
97 | f.write('\n')
98 | return input_file_path
99 |
100 |
101 | def update_static_input(task):
102 | """
103 | 更新任务的静态输入
104 | :param task:
105 | :return:
106 | """
107 | if task.input_file_type == Task.INPUT_FILE_TYPE_STATIC:
108 | input_file_path = get_input_file_path(task)
109 | with open(input_file_path, 'w', newline='') as f:
110 | f.write(task.input)
111 | return input_file_path
112 |
113 |
114 | def set_crontab(dispatch, command, comment, active):
115 | """
116 | 设置定时任务
117 | :param dispatch: 调度
118 | :param command: 命令
119 | :param comment: 备注,用于查找和更新命令
120 | :param active: 是否生效
121 | :return:
122 | """
123 | # 打开定时任务文件
124 | cron = open_crontab()
125 | # 删除该任务已存在的定时任务
126 | for job in cron.find_comment(comment):
127 | cron.remove(job)
128 | # 新建定时任务
129 | job = cron.new(command=command, comment=comment)
130 | job.setall(dispatch)
131 | if active:
132 | job.enable()
133 | else:
134 | job.enable(False)
135 | # 设置环境变量
136 | set_crontab_env(cron)
137 | # 保存定时任务
138 | cron.write()
139 |
140 |
141 | def set_crontab_env(cron):
142 | """
143 | 设置定时任务的环境变量
144 | :param cron
145 | :return:
146 | """
147 | for key in os.environ:
148 | cron.env[key] = os.environ[key]
149 |
150 |
151 | def set_cron_mail_report(dispatch):
152 | """
153 | 设置发送邮件报告的定时任务
154 | :param dispatch:
155 | :return:
156 | """
157 | comment = get_mail_report_cron_comment()
158 | command = '{} {} record_report'.format(executable, os.path.join(BASE_DIR, 'manage.py'))
159 | set_crontab(dispatch, command, comment, True)
160 | with open(get_mail_report_dispatch_file_path(), 'w') as f:
161 | f.write(dispatch)
162 |
--------------------------------------------------------------------------------
/parse/tests.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from django.test import TestCase
4 | from entities.models import Task
5 | from entities.models import Tool
6 | from entities.models import Record
7 | from entities.models import Project
8 |
9 | from parse.sublist3r_parser import Sublist3rParser
10 | from parse.one_for_all import OneForAllParser
11 | from parse.lijiejie_subdomains_brute import LijiejieSubDomainsBrute
12 | from parse.censys_enumeration_email import CensysEnumerationEmail
13 | from parse.censys_enumeration_domain import CensysEnumerationDomain
14 | from parse.ctfr import CTFRParser
15 | from parse.nmap_dns_brute import NmapDnsBruteParser
16 | from parse.nmap_syn_scan import NmapSynScanParser
17 | from parse.nmap_udp_scan import NmapUdpScanParser
18 |
19 |
20 | class ParserTest(TestCase):
21 |
22 | def setUp(self):
23 | self.project = Project.objects.create(name='test_project')
24 |
25 | def test_sublist3r_parser(self):
26 | tool = Tool.objects.create(name='sublist3r_tool', type='sublist3r_type')
27 | task = Task.objects.create(name='sublist3r_task', project=self.project, tool=tool)
28 | parser = Sublist3rParser(task, os.path.join('parse', 'examples', 'sublist3r.txt'))
29 | parser.parse()
30 | self.assertEqual(Record.objects.filter(type='sublist3r_type').count(), 2)
31 |
32 | def test_censys_enumeration_domain(self):
33 | tool = Tool.objects.create(name='censys_enumeration_domain_tool', type='censys_enumeration_domain_type')
34 | task = Task.objects.create(name='censys_enumeration_domain_task', project=self.project, tool=tool)
35 | parser = CensysEnumerationDomain(task, os.path.join('parse', 'examples', 'censys_enumeration.json'))
36 | parser.parse()
37 | self.assertEqual(Record.objects.filter(type='censys_enumeration_domain_type').count(), 127)
38 |
39 | def test_censys_enumeration_email(self):
40 | tool = Tool.objects.create(name='censys_enumeration_email_tool', type='censys_enumeration_email_type')
41 | task = Task.objects.create(name='censys_enumeration_email_task', project=self.project, tool=tool)
42 | parser = CensysEnumerationEmail(task, os.path.join('parse', 'examples', 'censys_enumeration.json'))
43 | parser.parse()
44 | self.assertEqual(Record.objects.filter(type='censys_enumeration_email_type').count(), 5)
45 |
46 | def test_one_for_all(self):
47 | tool = Tool.objects.create(name='one_for_all_tool', type='one_for_all_type')
48 | task = Task.objects.create(name='one_for_all_task', project=self.project, tool=tool)
49 | parser = OneForAllParser(task, os.path.join('parse', 'examples', 'one_for_all.json'))
50 | parser.parse()
51 | self.assertEqual(Record.objects.filter(type='one_for_all_type').count(), 6)
52 |
53 | def test_lijiejie_sub_domains_brute(self):
54 | tool = Tool.objects.create(name='lijiejie_sub_domains_brute_tool', type='lijiejie_sub_domains_brute_type')
55 | task = Task.objects.create(name='lijiejie_sub_domains_brute_task', project=self.project, tool=tool)
56 | parser = LijiejieSubDomainsBrute(task, os.path.join('parse', 'examples', 'lijiejie_sub_domains_brute.txt'))
57 | parser.parse()
58 | self.assertEqual(Record.objects.filter(type='lijiejie_sub_domains_brute_type').count(), 4)
59 |
60 | def test_ctfr(self):
61 | tool = Tool.objects.create(name='ctfr_tool', type='ctfr_type')
62 | task = Task.objects.create(name='ctfr_task', project=self.project, tool=tool)
63 | parser = CTFRParser(task, os.path.join('parse', 'examples', 'ctfr.txt'))
64 | parser.parse()
65 | self.assertEqual(Record.objects.filter(type='ctfr_type').count(), 7)
66 |
67 | def test_nmap_sub_domain_brute(self):
68 | tool = Tool.objects.create(name='nmap_sub_domain_brute_tool', type='nmap_sub_domain_brute_type')
69 | task = Task.objects.create(name='nmap_sub_domain_brute_task', project=self.project, tool=tool)
70 | parser = NmapDnsBruteParser(task, os.path.join('parse', 'examples', 'nmap_sub_domain_brute.xml'))
71 | parser.parse()
72 | self.assertEqual(Record.objects.filter(type='nmap_sub_domain_brute_type').count(), 4)
73 |
74 | def test_nmap_syn_scan(self):
75 | tool = Tool.objects.create(name='nmap_syn_scan_tool', type='nmap_syn_scan_type')
76 | task = Task.objects.create(name='nmap_syn_scan_task', project=self.project, tool=tool)
77 | parser = NmapSynScanParser(task, os.path.join('parse', 'examples', 'nmap_syn_scan.xml'))
78 | parser.parse()
79 | self.assertEqual(Record.objects.filter(type='nmap_syn_scan_type').count(), 6)
80 |
81 | def test_nmap_udp_scan(self):
82 | tool = Tool.objects.create(name='nmap_udp_scan_tool', type='nmap_udp_scan_type')
83 | task = Task.objects.create(name='nmap_udp_scan_task', project=self.project, tool=tool)
84 | parser = NmapUdpScanParser(task, os.path.join('parse', 'examples', 'nmap_udp_scan.xml'))
85 | parser.parse()
86 | self.assertEqual(Record.objects.filter(type='nmap_udp_scan_type').count(), 2)
87 |
88 | def test_nmap_http_scan(self):
89 | tool = Tool.objects.create(name='nmap_http_scan_tool', type='nmap_http_scan_type')
90 | task = Task.objects.create(name='nmap_http_scan_task', project=self.project, tool=tool)
91 | parser = NmapUdpScanParser(task, os.path.join('parse', 'examples', 'nmap_http_scan.xml'))
92 | parser.parse()
93 | self.assertEqual(Record.objects.filter(type='nmap_http_scan_type').count(), 5)
94 |
--------------------------------------------------------------------------------
/templates/page/timeline.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 时间线
6 |
7 |
8 | {% load static %}
9 |
10 |
11 |
12 |
13 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
35 |
36 | {% for record in records %}
37 | -
38 |
39 |
40 |
{{ record.date }}
41 | {% for content in record.contents %}
42 |
43 | {{ content.record }}
44 | {{content.project}}
45 | {% if content.type %}
46 | {{content.type}}
47 | {% endif %}
48 | {% if content.source %}
49 | {{content.source}}
50 | {% endif %}
51 |
52 | {% endfor %}
53 |
54 |
55 | {% endfor %}
56 | -
57 |
58 |
61 |
62 |
63 |
72 |
73 |
74 |
75 |
78 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
--------------------------------------------------------------------------------
/entities/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from .validators import command_validator
3 | from .validators import cron_validator
4 |
5 |
6 | class Project(models.Model):
7 |
8 | name = models.CharField(verbose_name='项目名', max_length=100, unique=True)
9 | src_link = models.URLField(verbose_name='SRC链接', null=True, blank=True)
10 | comment = models.TextField(verbose_name='备注', null=True, blank=True)
11 |
12 | def __str__(self):
13 | return self.name
14 |
15 | class Meta:
16 | verbose_name = '项目'
17 | verbose_name_plural = verbose_name
18 |
19 |
20 | class Record(models.Model):
21 |
22 | record = models.CharField(verbose_name='记录', max_length=200)
23 | project = models.ForeignKey(verbose_name='项目', to=Project, on_delete=models.CASCADE)
24 | add_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
25 | last_modify_time = models.DateTimeField(verbose_name='最后修改时间', auto_now=True)
26 | type = models.CharField(verbose_name='类型', max_length=50, null=True, blank=True)
27 | source = models.CharField(verbose_name='来源', max_length=50, null=True, blank=True)
28 |
29 | def __str__(self):
30 | return self.record
31 |
32 | class Meta:
33 | verbose_name = '记录'
34 | verbose_name_plural = verbose_name
35 |
36 |
37 | class Tool(models.Model):
38 |
39 | INPUT_TYPE_FILE = 'file'
40 | INPUT_TYPE_PARAMETER = 'parameter'
41 | input_type_choices = ((INPUT_TYPE_FILE, '文件'),
42 | (INPUT_TYPE_PARAMETER, '参数'))
43 |
44 | name = models.CharField(verbose_name='工具名', max_length=100, unique=True)
45 | link = models.URLField(verbose_name='项目地址', null=True, blank=True)
46 | type = models.CharField(verbose_name='记录类型', max_length=50)
47 | parse_class_name = models.CharField(verbose_name='输出解析类', max_length=50)
48 | command = models.CharField(verbose_name='调用命令', max_length=500, validators=[command_validator])
49 | input_type = models.CharField(verbose_name='输入参数类型', max_length=50,
50 | choices=input_type_choices, default=INPUT_TYPE_FILE)
51 | version = models.CharField(verbose_name='版本', max_length=50, null=True, blank=True)
52 | comment = models.CharField(verbose_name='备注', null=True, blank=True, max_length=100)
53 |
54 | def __str__(self):
55 | return self.name
56 |
57 | class Meta:
58 | verbose_name = '工具'
59 | verbose_name_plural = verbose_name
60 |
61 |
62 | class Task(models.Model):
63 |
64 | INPUT_FILE_TYPE_STATIC = 'static_file'
65 | INPUT_FILE_TYPE_DYNAMIC = 'dynamic_file'
66 | input_file_type_choices = ((INPUT_FILE_TYPE_STATIC, '静态'),
67 | (INPUT_FILE_TYPE_DYNAMIC, '动态'))
68 | name = models.CharField(verbose_name='任务名', max_length=100, unique=True)
69 | project = models.ForeignKey(verbose_name='所属项目', to=Project, on_delete=models.CASCADE)
70 | tool = models.ForeignKey(verbose_name='工具', to=Tool, on_delete=models.CASCADE)
71 | input = models.TextField(verbose_name='输入')
72 | input_file_type = models.CharField(verbose_name='输入文件类型', max_length=50,
73 | choices=input_file_type_choices, default=INPUT_FILE_TYPE_STATIC)
74 | dispatch = models.CharField(verbose_name='调度', max_length=100, validators=[cron_validator])
75 | active = models.BooleanField(verbose_name='是否生效', default=True)
76 |
77 | def __str__(self):
78 | return '{}-{}'.format(self.project.name, self.name)
79 |
80 | class Meta:
81 | verbose_name = '任务'
82 | verbose_name_plural = verbose_name
83 |
84 |
85 | class BatchTask(models.Model):
86 |
87 | name = models.CharField(verbose_name='批量任务名', max_length=100, unique=True)
88 | task1 = models.ForeignKey(verbose_name='任务1', to=Task, on_delete=models.SET_NULL, null=True, blank=True, related_name='task1')
89 | task2 = models.ForeignKey(verbose_name='任务2', to=Task, on_delete=models.SET_NULL, null=True, blank=True, related_name='task2')
90 | task3 = models.ForeignKey(verbose_name='任务3', to=Task, on_delete=models.SET_NULL, null=True, blank=True, related_name='task3')
91 | task4 = models.ForeignKey(verbose_name='任务4', to=Task, on_delete=models.SET_NULL, null=True, blank=True, related_name='task4')
92 | task5 = models.ForeignKey(verbose_name='任务5', to=Task, on_delete=models.SET_NULL, null=True, blank=True, related_name='task5')
93 | task6 = models.ForeignKey(verbose_name='任务6', to=Task, on_delete=models.SET_NULL, null=True, blank=True, related_name='task6')
94 | task7 = models.ForeignKey(verbose_name='任务7', to=Task, on_delete=models.SET_NULL, null=True, blank=True, related_name='task7')
95 | task8 = models.ForeignKey(verbose_name='任务8', to=Task, on_delete=models.SET_NULL, null=True, blank=True, related_name='task8')
96 | task9 = models.ForeignKey(verbose_name='任务9', to=Task, on_delete=models.SET_NULL, null=True, blank=True, related_name='task9')
97 | task10 = models.ForeignKey(verbose_name='任务10', to=Task, on_delete=models.SET_NULL, null=True, blank=True, related_name='task10')
98 | dispatch = models.CharField(verbose_name='调度', max_length=100, validators=[cron_validator])
99 | active = models.BooleanField(verbose_name='是否生效', default=True)
100 |
101 | MAX_TASK_AMOUNT = 10
102 |
103 | def get_tasks(self):
104 | tasks = list()
105 | for i in range(1, self.MAX_TASK_AMOUNT+1):
106 | if getattr(self, 'task{}'.format(i)) is not None:
107 | tasks.append(getattr(self, 'task{}'.format(i)))
108 | return tasks
109 |
110 | def __str__(self):
111 | return self.name
112 |
113 | class Meta:
114 | verbose_name = '批量任务'
115 | verbose_name_plural = verbose_name
116 |
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/lay/modules/transfer.js:
--------------------------------------------------------------------------------
1 | /** layui-v2.5.5 MIT License By https://www.layui.com */
2 | ;layui.define(["laytpl","form"],function(e){"use strict";var a=layui.$,t=layui.laytpl,n=layui.form,i="transfer",l={config:{},index:layui[i]?layui[i].index+1e4:0,set:function(e){var t=this;return t.config=a.extend({},t.config,e),t},on:function(e,a){return layui.onevent.call(this,i,e,a)}},r=function(){var e=this,a=e.config,t=a.id||e.index;return r.that[t]=e,r.config[t]=a,{config:a,reload:function(a){e.reload.call(e,a)},getData:function(){return e.getData.call(e)}}},c="layui-hide",o="layui-btn-disabled",d="layui-none",s="layui-transfer-box",u="layui-transfer-header",h="layui-transfer-search",f="layui-transfer-active",y="layui-transfer-data",p=function(e){return e=e||{},['','","{{# if(d.data.showSearch){ }}",'
','','',"
","{{# } }}",'
',"
"].join("")},v=['"].join(""),x=function(e){var t=this;t.index=++l.index,t.config=a.extend({},t.config,l.config,e),t.render()};x.prototype.config={title:["列表一","列表二"],width:200,height:360,data:[],value:[],showSearch:!1,id:"",text:{none:"无数据",searchNone:"无匹配数据"}},x.prototype.reload=function(e){var t=this;layui.each(e,function(e,a){a.constructor===Array&&delete t.config[e]}),t.config=a.extend(!0,{},t.config,e),t.render()},x.prototype.render=function(){var e=this,n=e.config,i=e.elem=a(t(v).render({data:n,index:e.index})),l=n.elem=a(n.elem);l[0]&&(n.data=n.data||[],n.value=n.value||[],e.key=n.id||e.index,l.html(e.elem),e.layBox=e.elem.find("."+s),e.layHeader=e.elem.find("."+u),e.laySearch=e.elem.find("."+h),e.layData=i.find("."+y),e.layBtn=i.find("."+f+" .layui-btn"),e.layBox.css({width:n.width,height:n.height}),e.layData.css({height:function(){return n.height-e.layHeader.outerHeight()-e.laySearch.outerHeight()-2}()}),e.renderData(),e.events())},x.prototype.renderData=function(){var e=this,a=(e.config,[{checkName:"layTransferLeftCheck",views:[]},{checkName:"layTransferRightCheck",views:[]}]);e.parseData(function(e){var t=e.selected?1:0,n=["",'',""].join("");a[t].views.push(n),delete e.selected}),e.layData.eq(0).html(a[0].views.join("")),e.layData.eq(1).html(a[1].views.join("")),e.renderCheckBtn()},x.prototype.renderForm=function(e){n.render(e,"LAY-transfer-"+this.index)},x.prototype.renderCheckBtn=function(e){var t=this,n=t.config;e=e||{},t.layBox.each(function(i){var l=a(this),r=l.find("."+y),d=l.find("."+u).find('input[type="checkbox"]'),s=r.find('input[type="checkbox"]'),h=0,f=!1;if(s.each(function(){var e=a(this).data("hide");(this.checked||this.disabled||e)&&h++,this.checked&&!e&&(f=!0)}),d.prop("checked",f&&h===s.length),t.layBtn.eq(i)[f?"removeClass":"addClass"](o),!e.stopNone){var p=r.children("li:not(."+c+")").length;t.noneView(r,p?"":n.text.none)}}),t.renderForm("checkbox")},x.prototype.noneView=function(e,t){var n=a(''+(t||"")+"
");e.find("."+d)[0]&&e.find("."+d).remove(),t.replace(/\s/g,"")&&e.append(n)},x.prototype.setValue=function(){var e=this,t=e.config,n=[];return e.layBox.eq(1).find("."+y+' input[type="checkbox"]').each(function(){var e=a(this).data("hide");e||n.push(this.value)}),t.value=n,e},x.prototype.parseData=function(e){var t=this,n=t.config,i=[];return layui.each(n.data,function(t,l){l=("function"==typeof n.parseData?n.parseData(l):l)||l,i.push(l=a.extend({},l)),layui.each(n.value,function(e,a){a==l.value&&(l.selected=!0)}),e&&e(l)}),n.data=i,t},x.prototype.getData=function(e){var a=this,t=a.config,n=[];return a.setValue(),layui.each(e||t.value,function(e,a){layui.each(t.data,function(e,t){delete t.selected,a==t.value&&n.push(t)})}),n},x.prototype.events=function(){var e=this,t=e.config;e.elem.on("click",'input[lay-filter="layTransferCheckbox"]+',function(){var t=a(this).prev(),n=t[0].checked,i=t.parents("."+s).eq(0).find("."+y);t[0].disabled||("all"===t.attr("lay-type")&&i.find('input[type="checkbox"]').each(function(){this.disabled||(this.checked=n)}),e.renderCheckBtn({stopNone:!0}))}),e.layBtn.on("click",function(){var n=a(this),i=n.data("index"),l=e.layBox.eq(i),r=[];if(!n.hasClass(o)){e.layBox.eq(i).each(function(t){var n=a(this),i=n.find("."+y);i.children("li").each(function(){var t=a(this),n=t.find('input[type="checkbox"]'),i=n.data("hide");n[0].checked&&!i&&(n[0].checked=!1,l.siblings("."+s).find("."+y).append(t.clone()),t.remove(),r.push(n[0].value)),e.setValue()})}),e.renderCheckBtn();var c=l.siblings("."+s).find("."+h+" input");""===c.val()||c.trigger("keyup"),t.onchange&&t.onchange(e.getData(r),i)}}),e.laySearch.find("input").on("keyup",function(){var n=this.value,i=a(this).parents("."+h).eq(0).siblings("."+y),l=i.children("li");l.each(function(){var e=a(this),t=e.find('input[type="checkbox"]'),i=t[0].title.indexOf(n)!==-1;e[i?"removeClass":"addClass"](c),t.data("hide",!i)}),e.renderCheckBtn();var r=l.length===i.children("li."+c).length;e.noneView(i,r?t.text.searchNone:"")})},r.that={},r.config={},l.reload=function(e,a){var t=r.that[e];return t.reload(a),r.call(t)},l.getData=function(e){var a=r.that[e];return a.getData()},l.render=function(e){var a=new x(e);return r.call(a)},e(i,l)});
--------------------------------------------------------------------------------
/parse/examples/censys_enumeration.json:
--------------------------------------------------------------------------------
1 | {
2 | "ietf.org": {
3 | "domain": "ietf.org",
4 | "emails": [
5 | "randy@psg.com",
6 | "noc@meeting.ietf.org",
7 | "webmaster@machshav.com",
8 | "root@dechaunac.tools.ietf.org"
9 | ],
10 | "subdomains": [
11 | "www.rtg.ietf.org",
12 | "netdot.noc.ietf.org",
13 | "services-1.meeting.ietf.org",
14 | "permatrac.noc.ietf.org",
15 | "nms.sql1.ietf.org",
16 | "sql1.ietf.org",
17 | "etherpad.noc.ietf.org",
18 | "permatrac.sql1.ietf.org",
19 | "tools.ietf.org",
20 | "observium.meeting.ietf.org",
21 | "Switch.meeting.ietf.org",
22 | "sec.ietf.org",
23 | "ops.ietf.org",
24 | "dechaunac.tools.ietf.org",
25 | "vm1.noc.ietf.org",
26 | "codestand.ietf.org",
27 | "git.noc.ietf.org",
28 | "tickets.meeting.ietf.org",
29 | "noc.meeting.ietf.org",
30 | "vm0.noc.ietf.org",
31 | "noc.ietf.org",
32 | "etherpad.sql1.ietf.org",
33 | "meeting.ietf.org",
34 | "management.meeting.ietf.org",
35 | "rtg.ietf.org",
36 | "netdot.sql1.ietf.org",
37 | "ietf.org",
38 | "nms.noc.ietf.org",
39 | "services-2.meeting.ietf.org",
40 | "ztp.meeting.ietf.org",
41 | "deadperson.meeting.ietf.org",
42 | "vnam.meeting.ietf.org",
43 | "dhcp-8599.meeting.ietf.org",
44 | "vm2.noc.ietf.org",
45 | "dav.noc.ietf.org"
46 | ]
47 | },
48 | "censys.io": {
49 | "domain": "censys.io",
50 | "emails": [
51 | "hostmaster@censys.io"
52 | ],
53 | "subdomains": [
54 | "kibana2.censys.io",
55 | "www.censys.io",
56 | "es-frontend-1.censys.io",
57 | "elasticsearch2.censys.io",
58 | "kafka-1.censys.io",
59 | "alertmanager.censys.io",
60 | "kafka2.censys.io",
61 | "kafka1.censys.io",
62 | "elasticsearch1.censys.io",
63 | "kibana1.censys.io",
64 | "git.wiki.censys.io",
65 | "censys.io",
66 | "logs.censys.io",
67 | "prometheus.censys.io",
68 | "wiki.censys.io",
69 | "kibana.es-frontend-1.censys.io",
70 | "kafka3.censys.io",
71 | "grafana.censys.io",
72 | "support.censys.io",
73 | "ichnaea.censys.io",
74 | "kibana.es-frontend-2.censys.io",
75 | "es-frontend-2.censys.io"
76 | ]
77 | },
78 | "wikimedia.org": {
79 | "domain": "wikimedia.org",
80 | "emails": [
81 |
82 | ],
83 | "subdomains": [
84 | "apt.wikimedia.org",
85 | "etherpad.wikimedia.org",
86 | "status.wikimedia.org",
87 | "blog.wikimedia.org",
88 | "bug-attachment.wikimedia.org",
89 | "mirrors.wikimedia.org",
90 | "mail.wikimedia.org",
91 | "ticket.wikimedia.org",
92 | "vpn.corp.wikimedia.org",
93 | "ganglia.wikimedia.org",
94 | "wikitech.wikimedia.org",
95 | "netbox.wikimedia.org",
96 | "mx1001.wikimedia.org",
97 | "icinga-admin.wikimedia.org",
98 | "frdev.wikimedia.org",
99 | "archiva.wikimedia.org",
100 | "civicrm.wikimedia.org",
101 | "frdata.wikimedia.org",
102 | "noc.wikimedia.org",
103 | "gerrit-slave.wikimedia.org",
104 | "ishmael.wikimedia.org",
105 | "git.wikimedia.org",
106 | "rt.wikimedia.org",
107 | "dumps.wikimedia.org",
108 | "tendril.wikimedia.org",
109 | "svn.wikimedia.org",
110 | "corp.wikimedia.org",
111 | "stats.wikimedia.org",
112 | "virt0.wikimedia.org",
113 | "metrics.wikimedia.org",
114 | "fundraising.wikimedia.org",
115 | "wikitech-static-iad.wikimedia.org",
116 | "policy.wikimedia.org",
117 | "download.wikimedia.org",
118 | "ubuntu.wikimedia.org",
119 | "wikitech-static.wikimedia.org",
120 | "wikitech-static-ord.wikimedia.org",
121 | "directory.corp.wikimedia.org",
122 | "racktables.wikimedia.org",
123 | "mx2002.wikimedia.org",
124 | "mx1002.wikimedia.org",
125 | "shop.wikimedia.org",
126 | "payments.wikimedia.org",
127 | "benefactorevents.wikimedia.org",
128 | "techblog.wikimedia.org",
129 | "mingle.corp.wikimedia.org",
130 | "lists.wikimedia.org",
131 | "sugar.corp.wikimedia.org",
132 | "gerrit-new.wikimedia.org",
133 | "bugzilla.wikimedia.org",
134 | "eventdonations.wikimedia.org",
135 | "planet.wikimedia.org",
136 | "stream.wikimedia.org",
137 | "www.ticket.wikimedia.org",
138 | "store.wikimedia.org",
139 | "www.policy.wikimedia.org",
140 | "librenms.wikimedia.org",
141 | "payments-listener.wikimedia.org",
142 | "icinga.wikimedia.org",
143 | "labtestwikitech.wikimedia.org",
144 | "gerrit.wikimedia.org",
145 | "mx2001.wikimedia.org",
146 | "m.wikimedia.org",
147 | "wikimedia.org"
148 | ]
149 | },
150 | "iana.org": {
151 | "domain": "iana.org",
152 | "emails": [
153 |
154 | ],
155 | "subdomains": [
156 | "www.itar.iana.org",
157 | "data.iana.org",
158 | "iana.org",
159 | "www.ns.iana.org",
160 | "ns.iana.org",
161 | "itar.iana.org"
162 | ]
163 | }
164 | }
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/layui.js:
--------------------------------------------------------------------------------
1 | /** layui-v2.5.5 MIT License By https://www.layui.com */
2 | ;!function(e){"use strict";var t=document,o={modules:{},status:{},timeout:10,event:{}},n=function(){this.v="2.5.5"},r=function(){var e=t.currentScript?t.currentScript.src:function(){for(var e,o=t.scripts,n=o.length-1,r=n;r>0;r--)if("interactive"===o[r].readyState){e=o[r].src;break}return e||o[n].src}();return e.substring(0,e.lastIndexOf("/")+1)}(),i=function(t){e.console&&console.error&&console.error("Layui hint: "+t)},a="undefined"!=typeof opera&&"[object Opera]"===opera.toString(),u={layer:"modules/layer",laydate:"modules/laydate",laypage:"modules/laypage",laytpl:"modules/laytpl",layim:"modules/layim",layedit:"modules/layedit",form:"modules/form",upload:"modules/upload",transfer:"modules/transfer",tree:"modules/tree",table:"modules/table",element:"modules/element",rate:"modules/rate",colorpicker:"modules/colorpicker",slider:"modules/slider",carousel:"modules/carousel",flow:"modules/flow",util:"modules/util",code:"modules/code",jquery:"modules/jquery",mobile:"modules/mobile","layui.all":"../layui.all"};n.prototype.cache=o,n.prototype.define=function(e,t){var n=this,r="function"==typeof e,i=function(){var e=function(e,t){layui[e]=t,o.status[e]=!0};return"function"==typeof t&&t(function(n,r){e(n,r),o.callback[n]=function(){t(e)}}),this};return r&&(t=e,e=[]),!layui["layui.all"]&&layui["layui.mobile"]?i.call(n):(n.use(e,i),n)},n.prototype.use=function(e,n,l){function s(e,t){var n="PLaySTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/;("load"===e.type||n.test((e.currentTarget||e.srcElement).readyState))&&(o.modules[f]=t,d.removeChild(v),function r(){return++m>1e3*o.timeout/4?i(f+" is not a valid module"):void(o.status[f]?c():setTimeout(r,4))}())}function c(){l.push(layui[f]),e.length>1?y.use(e.slice(1),n,l):"function"==typeof n&&n.apply(layui,l)}var y=this,p=o.dir=o.dir?o.dir:r,d=t.getElementsByTagName("head")[0];e="string"==typeof e?[e]:e,window.jQuery&&jQuery.fn.on&&(y.each(e,function(t,o){"jquery"===o&&e.splice(t,1)}),layui.jquery=layui.$=jQuery);var f=e[0],m=0;if(l=l||[],o.host=o.host||(p.match(/\/\/([\s\S]+?)\//)||["//"+location.host+"/"])[0],0===e.length||layui["layui.all"]&&u[f]||!layui["layui.all"]&&layui["layui.mobile"]&&u[f])return c(),y;if(o.modules[f])!function g(){return++m>1e3*o.timeout/4?i(f+" is not a valid module"):void("string"==typeof o.modules[f]&&o.status[f]?c():setTimeout(g,4))}();else{var v=t.createElement("script"),h=(u[f]?p+"lay/":/^\{\/\}/.test(y.modules[f])?"":o.base||"")+(y.modules[f]||f)+".js";h=h.replace(/^\{\/\}/,""),v.async=!0,v.charset="utf-8",v.src=h+function(){var e=o.version===!0?o.v||(new Date).getTime():o.version||"";return e?"?v="+e:""}(),d.appendChild(v),!v.attachEvent||v.attachEvent.toString&&v.attachEvent.toString().indexOf("[native code")<0||a?v.addEventListener("load",function(e){s(e,h)},!1):v.attachEvent("onreadystatechange",function(e){s(e,h)}),o.modules[f]=h}return y},n.prototype.getStyle=function(t,o){var n=t.currentStyle?t.currentStyle:e.getComputedStyle(t,null);return n[n.getPropertyValue?"getPropertyValue":"getAttribute"](o)},n.prototype.link=function(e,n,r){var a=this,u=t.createElement("link"),l=t.getElementsByTagName("head")[0];"string"==typeof n&&(r=n);var s=(r||e).replace(/\.|\//g,""),c=u.id="layuicss-"+s,y=0;return u.rel="stylesheet",u.href=e+(o.debug?"?v="+(new Date).getTime():""),u.media="all",t.getElementById(c)||l.appendChild(u),"function"!=typeof n?a:(function p(){return++y>1e3*o.timeout/100?i(e+" timeout"):void(1989===parseInt(a.getStyle(t.getElementById(c),"width"))?function(){n()}():setTimeout(p,100))}(),a)},o.callback={},n.prototype.factory=function(e){if(layui[e])return"function"==typeof o.callback[e]?o.callback[e]:null},n.prototype.addcss=function(e,t,n){return layui.link(o.dir+"css/"+e,t,n)},n.prototype.img=function(e,t,o){var n=new Image;return n.src=e,n.complete?t(n):(n.onload=function(){n.onload=null,"function"==typeof t&&t(n)},void(n.onerror=function(e){n.onerror=null,"function"==typeof o&&o(e)}))},n.prototype.config=function(e){e=e||{};for(var t in e)o[t]=e[t];return this},n.prototype.modules=function(){var e={};for(var t in u)e[t]=u[t];return e}(),n.prototype.extend=function(e){var t=this;e=e||{};for(var o in e)t[o]||t.modules[o]?i("模块名 "+o+" 已被占用"):t.modules[o]=e[o];return t},n.prototype.router=function(e){var t=this,e=e||location.hash,o={path:[],search:{},hash:(e.match(/[^#](#.*$)/)||[])[1]||""};return/^#\//.test(e)?(e=e.replace(/^#\//,""),o.href="/"+e,e=e.replace(/([^#])(#.*$)/,"$1").split("/")||[],t.each(e,function(e,t){/^\w+=/.test(t)?function(){t=t.split("="),o.search[t[0]]=t[1]}():o.path.push(t)}),o):o},n.prototype.data=function(t,o,n){if(t=t||"layui",n=n||localStorage,e.JSON&&e.JSON.parse){if(null===o)return delete n[t];o="object"==typeof o?o:{key:o};try{var r=JSON.parse(n[t])}catch(i){var r={}}return"value"in o&&(r[o.key]=o.value),o.remove&&delete r[o.key],n[t]=JSON.stringify(r),o.key?r[o.key]:r}},n.prototype.sessionData=function(e,t){return this.data(e,t,sessionStorage)},n.prototype.device=function(t){var o=navigator.userAgent.toLowerCase(),n=function(e){var t=new RegExp(e+"/([^\\s\\_\\-]+)");return e=(o.match(t)||[])[1],e||!1},r={os:function(){return/windows/.test(o)?"windows":/linux/.test(o)?"linux":/iphone|ipod|ipad|ios/.test(o)?"ios":/mac/.test(o)?"mac":void 0}(),ie:function(){return!!(e.ActiveXObject||"ActiveXObject"in e)&&((o.match(/msie\s(\d+)/)||[])[1]||"11")}(),weixin:n("micromessenger")};return t&&!r[t]&&(r[t]=n(t)),r.android=/android/.test(o),r.ios="ios"===r.os,r},n.prototype.hint=function(){return{error:i}},n.prototype.each=function(e,t){var o,n=this;if("function"!=typeof t)return n;if(e=e||[],e.constructor===Object){for(o in e)if(t.call(e[o],o,e[o]))break}else for(o=0;oi?1:rt.min?a:t.min,t.value[1]=n>t.min?n:t.min,t.value[0]=t.value[0]>t.max?t.max:t.value[0],t.value[1]=t.value[1]>t.max?t.max:t.value[1];var r=Math.floor((t.value[0]-t.min)/(t.max-t.min)*100),v=Math.floor((t.value[1]-t.min)/(t.max-t.min)*100),m=v-r+"%";r+="%",v+="%"}else{"object"==typeof t.value&&(t.value=Math.min.apply(null,t.value)),t.valuet.max&&(t.value=t.max);var m=Math.floor((t.value-t.min)/(t.max-t.min)*100)+"%"}var p=t.disabled?"#c2c2c2":t.theme,f=''+(t.tips?'
':"")+'
'+(t.range?'
':"")+"
",h=i(t.elem),y=h.next("."+s);if(y[0]&&y.remove(),e.elemTemp=i(f),t.range?(e.elemTemp.find("."+o).eq(0).data("value",t.value[0]),e.elemTemp.find("."+o).eq(1).data("value",t.value[1])):e.elemTemp.find("."+o).data("value",t.value),h.html(e.elemTemp),"vertical"===t.type&&e.elemTemp.height(t.height+"px"),t.showstep){for(var g=(t.max-t.min)/t.step,b="",x=1;x')}e.elemTemp.append(b)}if(t.input&&!t.range){var w=i('');h.css("position","relative"),h.append(w),h.find("."+c).children("input").val(t.value),"vertical"===t.type?w.css({left:0,top:-48}):e.elemTemp.css("margin-right",w.outerWidth()+15)}t.disabled?(e.elemTemp.addClass(l),e.elemTemp.find("."+u).addClass(l)):e.slide(),e.elemTemp.find("."+u).on("mouseover",function(){var a="vertical"===t.type?t.height:e.elemTemp[0].offsetWidth,n=e.elemTemp.find("."+o),l="vertical"===t.type?a-i(this).parent()[0].offsetTop-n.height():i(this).parent()[0].offsetLeft,s=l/a*100,r=i(this).parent().data("value"),u=t.setTips?t.setTips(r):r;e.elemTemp.find("."+d).html(u),"vertical"===t.type?e.elemTemp.find("."+d).css({bottom:s+"%","margin-bottom":"20px",display:"inline-block"}):e.elemTemp.find("."+d).css({left:s+"%",display:"inline-block"})}).on("mouseout",function(){e.elemTemp.find("."+d).css("display","none")})},f.prototype.slide=function(e,t,a){var n=this,l=n.config,s=n.elemTemp,f=function(){return"vertical"===l.type?l.height:s[0].offsetWidth},h=s.find("."+o),y=s.next("."+v),g=y.children("."+c).children("input").val(),b=100/((l.max-l.min)/Math.ceil(l.step)),x=function(e,i){e=Math.ceil(e)*b>100?Math.ceil(e)*b:Math.round(e)*b,e=e>100?100:e,h.eq(i).css("vertical"===l.type?"bottom":"left",e+"%");var t=T(h[0].offsetLeft),a=l.range?T(h[1].offsetLeft):0;"vertical"===l.type?(s.find("."+d).css({bottom:e+"%","margin-bottom":"20px"}),t=T(f()-h[0].offsetTop-h.height()),a=l.range?T(f()-h[1].offsetTop-h.height()):0):s.find("."+d).css("left",e+"%"),t=t>100?100:t,a=a>100?100:a;var n=Math.min(t,a),o=Math.abs(t-a);"vertical"===l.type?s.find("."+r).css({height:o+"%",bottom:n+"%"}):s.find("."+r).css({width:o+"%",left:n+"%"});var u=l.min+Math.round((l.max-l.min)*e/100);if(g=u,y.children("."+c).children("input").val(g),h.eq(i).data("value",u),u=l.setTips?l.setTips(u):u,s.find("."+d).html(u),l.range){var v=[h.eq(0).data("value"),h.eq(1).data("value")];v[0]>v[1]&&v.reverse()}l.change&&l.change(l.range?v:u)},T=function(e){var i=e/f()*100/b,t=Math.round(i)*b;return e==f()&&(t=Math.ceil(i)*b),t},w=i(['f()&&(r=f());var o=r/f()*100/b;x(o,e),t.addClass(p),s.find("."+d).show(),i.preventDefault()},o=function(){t.removeClass(p),s.find("."+d).hide()};M(r,o)})}),s.on("click",function(e){var t=i("."+u);if(!t.is(event.target)&&0===t.has(event.target).length&&t.length){var a,n="vertical"===l.type?f()-e.clientY+i(this).offset().top:e.clientX-i(this).offset().left;n<0&&(n=0),n>f()&&(n=f());var s=n/f()*100/b;a=l.range?"vertical"===l.type?Math.abs(n-parseInt(i(h[0]).css("bottom")))>Math.abs(n-parseInt(i(h[1]).css("bottom")))?1:0:Math.abs(n-h[0].offsetLeft)>Math.abs(n-h[1].offsetLeft)?1:0:0,x(s,a),e.preventDefault()}}),y.hover(function(){var e=i(this);e.children("."+m).fadeIn("fast")},function(){var e=i(this);e.children("."+m).fadeOut("fast")}),y.children("."+m).children("i").each(function(e){i(this).on("click",function(){g=1==e?g-l.stepl.max?l.max:Number(g)+l.step;var i=(g-l.min)/(l.max-l.min)*100/b;x(i,0)})});var q=function(){var e=this.value;e=isNaN(e)?0:e,e=el.max?l.max:e,this.value=e;var i=(e-l.min)/(l.max-l.min)*100/b;x(i,0)};y.children("."+c).children("input").on("keydown",function(e){13===e.keyCode&&(e.preventDefault(),q.call(this))}).on("change",q)},f.prototype.events=function(){var e=this;e.config},t.render=function(e){var i=new f(e);return a.call(i)},e(n,t)});
--------------------------------------------------------------------------------
/entities/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.0.4 on 2020-04-06 02:08
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 | import entities.validators
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | initial = True
11 |
12 | dependencies = [
13 | ]
14 |
15 | operations = [
16 | migrations.CreateModel(
17 | name='Project',
18 | fields=[
19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
20 | ('name', models.CharField(max_length=100, unique=True, verbose_name='项目名')),
21 | ('src_link', models.URLField(blank=True, null=True, verbose_name='SRC链接')),
22 | ('comment', models.TextField(blank=True, null=True, verbose_name='备注')),
23 | ],
24 | options={
25 | 'verbose_name': '项目',
26 | 'verbose_name_plural': '项目',
27 | },
28 | ),
29 | migrations.CreateModel(
30 | name='Tool',
31 | fields=[
32 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
33 | ('name', models.CharField(max_length=100, unique=True, verbose_name='工具名')),
34 | ('link', models.URLField(blank=True, null=True, verbose_name='项目地址')),
35 | ('type', models.CharField(max_length=50, verbose_name='记录类型')),
36 | ('parse_class_name', models.CharField(max_length=50, verbose_name='输出解析类')),
37 | ('command', models.CharField(max_length=500, validators=[entities.validators.command_validator], verbose_name='调用命令')),
38 | ('input_type', models.CharField(choices=[('file', '文件'), ('parameter', '参数')], default='file', max_length=50, verbose_name='输入参数类型')),
39 | ('version', models.CharField(blank=True, max_length=50, null=True, verbose_name='版本')),
40 | ('comment', models.CharField(blank=True, max_length=100, null=True, verbose_name='备注')),
41 | ],
42 | options={
43 | 'verbose_name': '工具表',
44 | 'verbose_name_plural': '工具表',
45 | },
46 | ),
47 | migrations.CreateModel(
48 | name='Task',
49 | fields=[
50 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
51 | ('name', models.CharField(max_length=100, unique=True, verbose_name='任务名')),
52 | ('input', models.TextField(verbose_name='输入')),
53 | ('input_file_type', models.CharField(choices=[('static_file', '静态'), ('dynamic_file', '动态')], default='static_file', max_length=50, verbose_name='输入文件类型')),
54 | ('dispatch', models.CharField(max_length=100, validators=[entities.validators.cron_validator], verbose_name='调度')),
55 | ('active', models.BooleanField(default=True, verbose_name='是否生效')),
56 | ('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='entities.Project', verbose_name='所属项目')),
57 | ('tool', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='entities.Tool', verbose_name='工具')),
58 | ],
59 | options={
60 | 'verbose_name': '任务表',
61 | 'verbose_name_plural': '任务表',
62 | },
63 | ),
64 | migrations.CreateModel(
65 | name='Record',
66 | fields=[
67 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
68 | ('record', models.CharField(max_length=200, verbose_name='记录')),
69 | ('add_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
70 | ('last_modify_time', models.DateTimeField(auto_now=True, verbose_name='最后修改时间')),
71 | ('type', models.CharField(blank=True, max_length=50, null=True, verbose_name='类型')),
72 | ('source', models.CharField(blank=True, max_length=50, null=True, verbose_name='来源')),
73 | ('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='entities.Project', verbose_name='项目')),
74 | ],
75 | options={
76 | 'verbose_name': '记录',
77 | 'verbose_name_plural': '记录',
78 | },
79 | ),
80 | migrations.CreateModel(
81 | name='BatchTask',
82 | fields=[
83 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
84 | ('name', models.CharField(max_length=100, unique=True, verbose_name='批量任务名')),
85 | ('dispatch', models.CharField(max_length=100, validators=[entities.validators.cron_validator], verbose_name='调度')),
86 | ('active', models.BooleanField(default=True, verbose_name='是否生效')),
87 | ('task1', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='task1', to='entities.Task', verbose_name='任务1')),
88 | ('task10', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='task10', to='entities.Task', verbose_name='任务10')),
89 | ('task2', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='task2', to='entities.Task', verbose_name='任务2')),
90 | ('task3', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='task3', to='entities.Task', verbose_name='任务3')),
91 | ('task4', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='task4', to='entities.Task', verbose_name='任务4')),
92 | ('task5', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='task5', to='entities.Task', verbose_name='任务5')),
93 | ('task6', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='task6', to='entities.Task', verbose_name='任务6')),
94 | ('task7', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='task7', to='entities.Task', verbose_name='任务7')),
95 | ('task8', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='task8', to='entities.Task', verbose_name='任务8')),
96 | ('task9', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='task9', to='entities.Task', verbose_name='任务9')),
97 | ],
98 | options={
99 | 'verbose_name': '批量任务表',
100 | 'verbose_name_plural': '批量任务表',
101 | },
102 | ),
103 | ]
104 |
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/lay/modules/upload.js:
--------------------------------------------------------------------------------
1 | /** layui-v2.5.5 MIT License By https://www.layui.com */
2 | ;layui.define("layer",function(e){"use strict";var t=layui.$,i=layui.layer,n=layui.hint(),o=layui.device(),a={config:{},set:function(e){var i=this;return i.config=t.extend({},i.config,e),i},on:function(e,t){return layui.onevent.call(this,r,e,t)}},l=function(){var e=this;return{upload:function(t){e.upload.call(e,t)},reload:function(t){e.reload.call(e,t)},config:e.config}},r="upload",u="layui-upload-file",c="layui-upload-form",f="layui-upload-iframe",s="layui-upload-choose",p=function(e){var i=this;i.config=t.extend({},i.config,a.config,e),i.render()};p.prototype.config={accept:"images",exts:"",auto:!0,bindAction:"",url:"",field:"file",acceptMime:"",method:"post",data:{},drag:!0,size:0,number:0,multiple:!1},p.prototype.render=function(e){var i=this,e=i.config;e.elem=t(e.elem),e.bindAction=t(e.bindAction),i.file(),i.events()},p.prototype.file=function(){var e=this,i=e.config,n=e.elemFile=t(['"].join("")),a=i.elem.next();(a.hasClass(u)||a.hasClass(c))&&a.remove(),o.ie&&o.ie<10&&i.elem.wrap(''),e.isFile()?(e.elemFile=i.elem,i.field=i.elem[0].name):i.elem.after(n),o.ie&&o.ie<10&&e.initIE()},p.prototype.initIE=function(){var e=this,i=e.config,n=t(''),o=t(['"].join(""));t("#"+f)[0]||t("body").append(n),i.elem.next().hasClass(c)||(e.elemFile.wrap(o),i.elem.next("."+c).append(function(){var e=[];return layui.each(i.data,function(t,i){i="function"==typeof i?i():i,e.push('')}),e.join("")}()))},p.prototype.msg=function(e){return i.msg(e,{icon:2,shift:6})},p.prototype.isFile=function(){var e=this.config.elem[0];if(e)return"input"===e.tagName.toLocaleLowerCase()&&"file"===e.type},p.prototype.preview=function(e){var t=this;window.FileReader&&layui.each(t.chooseFiles,function(t,i){var n=new FileReader;n.readAsDataURL(i),n.onload=function(){e&&e(t,i,this.result)}})},p.prototype.upload=function(e,i){var n,a=this,l=a.config,r=a.elemFile[0],u=function(){var i=0,n=0,o=e||a.files||a.chooseFiles||r.files,u=function(){l.multiple&&i+n===a.fileLength&&"function"==typeof l.allDone&&l.allDone({total:a.fileLength,successful:i,aborted:n})};layui.each(o,function(e,o){var r=new FormData;r.append(l.field,o),layui.each(l.data,function(e,t){t="function"==typeof t?t():t,r.append(e,t)}),t.ajax({url:l.url,type:"post",data:r,contentType:!1,processData:!1,dataType:"json",headers:l.headers||{},success:function(t){i++,d(e,t),u()},error:function(){n++,a.msg("请求上传接口出现异常"),m(e),u()},xhr:function(){var e=new XMLHttpRequest;return e.upload.addEventListener("progress",function(e){if(e.lengthComputable){var t=Math.floor(e.loaded/e.total*100);"function"==typeof l.progress&&l.progress(t,e)}}),e}})})},c=function(){var e=t("#"+f);a.elemFile.parent().submit(),clearInterval(p.timer),p.timer=setInterval(function(){var t,i=e.contents().find("body");try{t=i.text()}catch(n){a.msg("获取上传后的响应信息出现异常"),clearInterval(p.timer),m()}t&&(clearInterval(p.timer),i.html(""),d(0,t))},30)},d=function(e,t){if(a.elemFile.next("."+s).remove(),r.value="","object"!=typeof t)try{t=JSON.parse(t)}catch(i){return t={},a.msg("请对上传接口返回有效JSON")}"function"==typeof l.done&&l.done(t,e||0,function(e){a.upload(e)})},m=function(e){l.auto&&(r.value=""),"function"==typeof l.error&&l.error(e||0,function(e){a.upload(e)})},h=l.exts,v=function(){var t=[];return layui.each(e||a.chooseFiles,function(e,i){t.push(i.name)}),t}(),g={preview:function(e){a.preview(e)},upload:function(e,t){var i={};i[e]=t,a.upload(i)},pushFile:function(){return a.files=a.files||{},layui.each(a.chooseFiles,function(e,t){a.files[e]=t}),a.files},resetFile:function(e,t,i){var n=new File([t],i);a.files=a.files||{},a.files[e]=n}},y=function(){if("choose"!==i&&!l.auto||(l.choose&&l.choose(g),"choose"!==i))return l.before&&l.before(g),o.ie?o.ie>9?u():c():void u()};if(v=0===v.length?r.value.match(/[^\/\\]+\..+/g)||[]||"":v,0!==v.length){switch(l.accept){case"file":if(h&&!RegExp("\\w\\.("+h+")$","i").test(escape(v)))return a.msg("选择的文件中包含不支持的格式"),r.value="";break;case"video":if(!RegExp("\\w\\.("+(h||"avi|mp4|wma|rmvb|rm|flash|3gp|flv")+")$","i").test(escape(v)))return a.msg("选择的视频中包含不支持的格式"),r.value="";break;case"audio":if(!RegExp("\\w\\.("+(h||"mp3|wav|mid")+")$","i").test(escape(v)))return a.msg("选择的音频中包含不支持的格式"),r.value="";break;default:if(layui.each(v,function(e,t){RegExp("\\w\\.("+(h||"jpg|png|gif|bmp|jpeg$")+")","i").test(escape(t))||(n=!0)}),n)return a.msg("选择的图片中包含不支持的格式"),r.value=""}if(a.fileLength=function(){var t=0,i=e||a.files||a.chooseFiles||r.files;return layui.each(i,function(){t++}),t}(),l.number&&a.fileLength>l.number)return a.msg("同时最多只能上传的数量为:"+l.number);if(l.size>0&&!(o.ie&&o.ie<10)){var F;if(layui.each(a.chooseFiles,function(e,t){if(t.size>1024*l.size){var i=l.size/1024;i=i>=1?i.toFixed(2)+"MB":l.size+"KB",r.value="",F=i}}),F)return a.msg("文件不能超过"+F)}y()}},p.prototype.reload=function(e){e=e||{},delete e.elem,delete e.bindAction;var i=this,e=i.config=t.extend({},i.config,a.config,e),n=e.elem.next();n.attr({name:e.name,accept:e.acceptMime,multiple:e.multiple})},p.prototype.events=function(){var e=this,i=e.config,a=function(t){e.chooseFiles={},layui.each(t,function(t,i){var n=(new Date).getTime();e.chooseFiles[n+"-"+t]=i})},l=function(t,n){var o=e.elemFile,a=t.length>1?t.length+"个文件":(t[0]||{}).name||o[0].value.match(/[^\/\\]+\..+/g)||[]||"";o.next().hasClass(s)&&o.next().remove(),e.upload(null,"choose"),e.isFile()||i.choose||o.after(''+a+"")};i.elem.off("upload.start").on("upload.start",function(){var o=t(this),a=o.attr("lay-data");if(a)try{a=new Function("return "+a)(),e.config=t.extend({},i,a)}catch(l){n.error("Upload element property lay-data configuration item has a syntax error: "+a)}e.config.item=o,e.elemFile[0].click()}),o.ie&&o.ie<10||i.elem.off("upload.over").on("upload.over",function(){var e=t(this);e.attr("lay-over","")}).off("upload.leave").on("upload.leave",function(){var e=t(this);e.removeAttr("lay-over")}).off("upload.drop").on("upload.drop",function(n,o){var r=t(this),u=o.originalEvent.dataTransfer.files||[];r.removeAttr("lay-over"),a(u),i.auto?e.upload(u):l(u)}),e.elemFile.off("upload.change").on("upload.change",function(){var t=this.files||[];a(t),i.auto?e.upload():l(t)}),i.bindAction.off("upload.action").on("upload.action",function(){e.upload()}),i.elem.data("haveEvents")||(e.elemFile.on("change",function(){t(this).trigger("upload.change")}),i.elem.on("click",function(){e.isFile()||t(this).trigger("upload.start")}),i.drag&&i.elem.on("dragover",function(e){e.preventDefault(),t(this).trigger("upload.over")}).on("dragleave",function(e){t(this).trigger("upload.leave")}).on("drop",function(e){e.preventDefault(),t(this).trigger("upload.drop",e)}),i.bindAction.on("click",function(){t(this).trigger("upload.action")}),i.elem.data("haveEvents",!0))},a.render=function(e){var t=new p(e);return l.call(t)},e(r,a)});
--------------------------------------------------------------------------------
/static/layuimini/lib/layui-v2.5.5/lay/modules/element.js:
--------------------------------------------------------------------------------
1 | /** layui-v2.5.5 MIT License By https://www.layui.com */
2 | ;layui.define("jquery",function(t){"use strict";var a=layui.$,i=(layui.hint(),layui.device()),e="element",l="layui-this",n="layui-show",s=function(){this.config={}};s.prototype.set=function(t){var i=this;return a.extend(!0,i.config,t),i},s.prototype.on=function(t,a){return layui.onevent.call(this,e,t,a)},s.prototype.tabAdd=function(t,i){var e=".layui-tab-title",l=a(".layui-tab[lay-filter="+t+"]"),n=l.children(e),s=n.children(".layui-tab-bar"),o=l.children(".layui-tab-content"),r='"+(i.title||"unnaming")+"";return s[0]?s.before(r):n.append(r),o.append(''+(i.content||"")+"
"),f.hideTabMore(!0),f.tabAuto(),this},s.prototype.tabDelete=function(t,i){var e=".layui-tab-title",l=a(".layui-tab[lay-filter="+t+"]"),n=l.children(e),s=n.find('>li[lay-id="'+i+'"]');return f.tabDelete(null,s),this},s.prototype.tabChange=function(t,i){var e=".layui-tab-title",l=a(".layui-tab[lay-filter="+t+"]"),n=l.children(e),s=n.find('>li[lay-id="'+i+'"]');return f.tabClick.call(s[0],null,null,s),this},s.prototype.tab=function(t){t=t||{},b.on("click",t.headerElem,function(i){var e=a(this).index();f.tabClick.call(this,i,e,null,t)})},s.prototype.progress=function(t,i){var e="layui-progress",l=a("."+e+"[lay-filter="+t+"]"),n=l.find("."+e+"-bar"),s=n.find("."+e+"-text");return n.css("width",i),s.text(i),this};var o=".layui-nav",r="layui-nav-item",c="layui-nav-bar",u="layui-nav-tree",d="layui-nav-child",y="layui-nav-more",h="layui-anim layui-anim-upbit",f={tabClick:function(t,i,s,o){o=o||{};var r=s||a(this),i=i||r.parent().children("li").index(r),c=o.headerElem?r.parent():r.parents(".layui-tab").eq(0),u=o.bodyElem?a(o.bodyElem):c.children(".layui-tab-content").children(".layui-tab-item"),d=r.find("a"),y=c.attr("lay-filter");"javascript:;"!==d.attr("href")&&"_blank"===d.attr("target")||(r.addClass(l).siblings().removeClass(l),u.eq(i).addClass(n).siblings().removeClass(n)),layui.event.call(this,e,"tab("+y+")",{elem:c,index:i})},tabDelete:function(t,i){var n=i||a(this).parent(),s=n.index(),o=n.parents(".layui-tab").eq(0),r=o.children(".layui-tab-content").children(".layui-tab-item"),c=o.attr("lay-filter");n.hasClass(l)&&(n.next()[0]?f.tabClick.call(n.next()[0],null,s+1):n.prev()[0]&&f.tabClick.call(n.prev()[0],null,s-1)),n.remove(),r.eq(s).remove(),setTimeout(function(){f.tabAuto()},50),layui.event.call(this,e,"tabDelete("+c+")",{elem:o,index:s})},tabAuto:function(){var t="layui-tab-more",e="layui-tab-bar",l="layui-tab-close",n=this;a(".layui-tab").each(function(){var s=a(this),o=s.children(".layui-tab-title"),r=(s.children(".layui-tab-content").children(".layui-tab-item"),'lay-stope="tabmore"'),c=a('');if(n===window&&8!=i.ie&&f.hideTabMore(!0),s.attr("lay-allowClose")&&o.find("li").each(function(){var t=a(this);if(!t.find("."+l)[0]){var i=a('ဆ');i.on("click",f.tabDelete),t.append(i)}}),"string"!=typeof s.attr("lay-unauto"))if(o.prop("scrollWidth")>o.outerWidth()+1){if(o.find("."+e)[0])return;o.append(c),s.attr("overflow",""),c.on("click",function(a){o[this.title?"removeClass":"addClass"](t),this.title=this.title?"":"收缩"})}else o.find("."+e).remove(),s.removeAttr("overflow")})},hideTabMore:function(t){var i=a(".layui-tab-title");t!==!0&&"tabmore"===a(t.target).attr("lay-stope")||(i.removeClass("layui-tab-more"),i.find(".layui-tab-bar").attr("title",""))},clickThis:function(){var t=a(this),i=t.parents(o),n=i.attr("lay-filter"),s=t.parent(),c=t.siblings("."+d),y="string"==typeof s.attr("lay-unselect");"javascript:;"!==t.attr("href")&&"_blank"===t.attr("target")||y||c[0]||(i.find("."+l).removeClass(l),s.addClass(l)),i.hasClass(u)&&(c.removeClass(h),c[0]&&(s["none"===c.css("display")?"addClass":"removeClass"](r+"ed"),"all"===i.attr("lay-shrink")&&s.siblings().removeClass(r+"ed"))),layui.event.call(this,e,"nav("+n+")",t)},collapse:function(){var t=a(this),i=t.find(".layui-colla-icon"),l=t.siblings(".layui-colla-content"),s=t.parents(".layui-collapse").eq(0),o=s.attr("lay-filter"),r="none"===l.css("display");if("string"==typeof s.attr("lay-accordion")){var c=s.children(".layui-colla-item").children("."+n);c.siblings(".layui-colla-title").children(".layui-colla-icon").html(""),c.removeClass(n)}l[r?"addClass":"removeClass"](n),i.html(r?"":""),layui.event.call(this,e,"collapse("+o+")",{title:t,content:l,show:r})}};s.prototype.init=function(t,e){var l=function(){return e?'[lay-filter="'+e+'"]':""}(),s={tab:function(){f.tabAuto.call({})},nav:function(){var t=200,e={},s={},p={},b=function(l,o,r){var c=a(this),f=c.find("."+d);o.hasClass(u)?l.css({top:c.position().top,height:c.children("a").outerHeight(),opacity:1}):(f.addClass(h),l.css({left:c.position().left+parseFloat(c.css("marginLeft")),top:c.position().top+c.height()-l.height()}),e[r]=setTimeout(function(){l.css({width:c.width(),opacity:1})},i.ie&&i.ie<10?0:t),clearTimeout(p[r]),"block"===f.css("display")&&clearTimeout(s[r]),s[r]=setTimeout(function(){f.addClass(n),c.find("."+y).addClass(y+"d")},300))};a(o+l).each(function(i){var l=a(this),o=a(''),h=l.find("."+r);l.find("."+c)[0]||(l.append(o),h.on("mouseenter",function(){b.call(this,o,l,i)}).on("mouseleave",function(){l.hasClass(u)||(clearTimeout(s[i]),s[i]=setTimeout(function(){l.find("."+d).removeClass(n),l.find("."+y).removeClass(y+"d")},300))}),l.on("mouseleave",function(){clearTimeout(e[i]),p[i]=setTimeout(function(){l.hasClass(u)?o.css({height:0,top:o.position().top+o.height()/2,opacity:0}):o.css({width:0,left:o.position().left+o.width()/2,opacity:0})},t)})),h.find("a").each(function(){var t=a(this),i=(t.parent(),t.siblings("."+d));i[0]&&!t.children("."+y)[0]&&t.append(''),t.off("click",f.clickThis).on("click",f.clickThis)})})},breadcrumb:function(){var t=".layui-breadcrumb";a(t+l).each(function(){var t=a(this),i="lay-separator",e=t.attr(i)||"/",l=t.find("a");l.next("span["+i+"]")[0]||(l.each(function(t){t!==l.length-1&&a(this).after(""+e+"")}),t.css("visibility","visible"))})},progress:function(){var t="layui-progress";a("."+t+l).each(function(){var i=a(this),e=i.find(".layui-progress-bar"),l=e.attr("lay-percent");e.css("width",function(){return/^.+\/.+$/.test(l)?100*new Function("return "+l)()+"%":l}()),i.attr("lay-showPercent")&&setTimeout(function(){e.html(''+l+"")},350)})},collapse:function(){var t="layui-collapse";a("."+t+l).each(function(){var t=a(this).find(".layui-colla-item");t.each(function(){var t=a(this),i=t.find(".layui-colla-title"),e=t.find(".layui-colla-content"),l="none"===e.css("display");i.find(".layui-colla-icon").remove(),i.append(''+(l?"":"")+""),i.off("click",f.collapse).on("click",f.collapse)})})}};return s[t]?s[t]():layui.each(s,function(t,a){a()})},s.prototype.render=s.prototype.init;var p=new s,b=a(document);p.render();var v=".layui-tab-title li";b.on("click",v,f.tabClick),b.on("click",f.hideTabMore),a(window).on("resize",f.tabAuto),t(e,p)});
--------------------------------------------------------------------------------