├── logs ├── .gitkeep └── gunicorn │ └── .gitkeep ├── geye ├── __init__.py ├── system │ ├── __init__.py │ ├── middleware │ │ ├── __init__.py │ │ ├── vue.py │ │ └── cors.py │ ├── apps.py │ └── management │ │ ├── __init__.py │ │ └── commands │ │ ├── __init__.py │ │ └── run.py ├── web │ ├── __init__.py │ ├── apps.py │ ├── controller │ │ ├── __init__.py │ │ ├── rule │ │ │ ├── __init__.py │ │ │ └── monitor.py │ │ ├── leaks │ │ │ ├── __init__.py │ │ │ └── leaks.py │ │ ├── handleCenter │ │ │ ├── __init__.py │ │ │ ├── monitorResults.py │ │ │ └── searchResults.py │ │ ├── user_center │ │ │ ├── __init__.py │ │ │ └── uc.py │ │ ├── system │ │ │ ├── __init__.py │ │ │ └── csrf.py │ │ ├── token │ │ │ ├── __init__.py │ │ │ └── token.py │ │ ├── index.py │ │ ├── cookie.py │ │ └── base.py │ └── urls.py ├── database │ ├── __init__.py │ ├── migrations │ │ ├── __init__.py │ │ ├── 0004_geyecookiemodel.py │ │ ├── 0002_auto_20181223_2137.py │ │ ├── 0003_auto_20211029_2354.py │ │ └── 0001_initial.py │ ├── apps.py │ └── models │ │ ├── rules │ │ ├── __init__.py │ │ ├── search.py │ │ └── filter.py │ │ ├── yuque │ │ ├── __init__.py │ │ ├── leaks.py │ │ └── rules.py │ │ ├── base.py │ │ ├── __init__.py │ │ ├── user.py │ │ ├── cookie.py │ │ ├── monitorResults.py │ │ ├── leaks.py │ │ ├── monitorRules.py │ │ └── token.py ├── core │ ├── __init__.py │ ├── engine │ │ ├── base │ │ │ ├── coroutine.py │ │ │ ├── __init__.py │ │ │ ├── base.py │ │ │ └── thread.py │ │ ├── yuque │ │ │ ├── __init__.py │ │ │ ├── refresh.py │ │ │ └── save.py │ │ ├── filter │ │ │ └── __init__.py │ │ ├── notification.py │ │ ├── monitor │ │ │ ├── __init__.py │ │ │ ├── monitorRefresh.py │ │ │ └── monitorSave.py │ │ ├── __init__.py │ │ ├── refresh.py │ │ └── save.py │ └── data.py ├── utils │ ├── __init__.py │ ├── convert.py │ ├── validator.py │ ├── datatype.py │ └── logger.py ├── tests │ ├── __init__.py │ ├── test_monitor_api.py │ ├── test_lua.py │ ├── test_monitor_engine.py │ ├── test_eval.py │ └── test_process.py ├── wsgi.py ├── settings │ ├── _base.py │ ├── __init__.py │ ├── settings_default.py │ └── settings_example.py ├── constant.py └── urls.py ├── geye-fe ├── .browserslistrc ├── babel.config.js ├── src │ ├── services │ │ ├── index.js │ │ ├── handleCenter │ │ │ ├── monitorCenter.js │ │ │ └── searchCenter.js │ │ ├── monitor.js │ │ ├── filterRule.js │ │ ├── token.js │ │ ├── leaks.js │ │ ├── globalFilterRule.js │ │ └── searchRule.js │ ├── assets │ │ ├── logo.png │ │ └── css │ │ │ ├── color-dark.css │ │ │ └── main.css │ ├── utils │ │ ├── constant.js │ │ └── axios.js │ ├── components │ │ ├── common │ │ │ ├── data.js │ │ │ ├── Sidebar.vue │ │ │ └── Header.vue │ │ ├── 404.vue │ │ ├── utils │ │ │ └── ItemCard.vue │ │ ├── HelloWorld.vue │ │ ├── handleCenter │ │ │ ├── SearchCenter.vue │ │ │ ├── utils │ │ │ │ └── searchResultItem.vue │ │ │ └── MonitorCenter.vue │ │ └── searchRule │ │ │ ├── new.vue │ │ │ └── all.vue │ ├── views │ │ ├── About.vue │ │ └── Home.vue │ ├── config │ │ └── index.js │ ├── App.vue │ ├── main.js │ └── router │ │ └── index.js ├── postcss.config.js ├── public │ ├── favicon.ico │ └── index.html ├── vue.config.js ├── .gitignore ├── .eslintrc.js ├── README.md └── package.json ├── docs └── img │ ├── geye.png │ └── geye-monitor-results.png ├── requirements.txt ├── tools ├── start_web_dev.sh └── start_web.sh ├── manage.py ├── conf ├── geye.nginx.conf └── gunicorn_config.py ├── docker-compose.yml ├── docker_entrypoint.sh ├── Dockerfile ├── README.md └── .gitignore /logs/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /geye/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /geye/system/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /geye/web/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /logs/gunicorn/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /geye/database/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /geye/database/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /geye-fe/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not ie <= 8 4 | -------------------------------------------------------------------------------- /geye-fe/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ["@vue/app"] 3 | }; 4 | -------------------------------------------------------------------------------- /docs/img/geye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightless233/geye/HEAD/docs/img/geye.png -------------------------------------------------------------------------------- /geye-fe/src/services/index.js: -------------------------------------------------------------------------------- 1 | const CSRF_API = "/api/_csrf_token"; 2 | 3 | export default CSRF_API 4 | -------------------------------------------------------------------------------- /geye-fe/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | }; 6 | -------------------------------------------------------------------------------- /geye-fe/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightless233/geye/HEAD/geye-fe/public/favicon.ico -------------------------------------------------------------------------------- /geye-fe/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightless233/geye/HEAD/geye-fe/src/assets/logo.png -------------------------------------------------------------------------------- /geye/system/middleware/__init__.py: -------------------------------------------------------------------------------- 1 | from .cors import CORSMiddleware 2 | from .vue import VueMiddleware 3 | -------------------------------------------------------------------------------- /docs/img/geye-monitor-results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightless233/geye/HEAD/docs/img/geye-monitor-results.png -------------------------------------------------------------------------------- /geye-fe/src/utils/constant.js: -------------------------------------------------------------------------------- 1 | const constant = { 2 | error_500: "后端服务请求失败,请重试!", 3 | }; 4 | 5 | export default constant; -------------------------------------------------------------------------------- /geye/web/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class WebConfig(AppConfig): 5 | name = 'geye.web' 6 | -------------------------------------------------------------------------------- /geye/system/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class SystemConfig(AppConfig): 5 | name = 'geye.system' 6 | -------------------------------------------------------------------------------- /geye-fe/src/components/common/data.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | const globalData = new Vue(); 4 | export default globalData; 5 | -------------------------------------------------------------------------------- /geye-fe/src/views/About.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /geye/database/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class DatabaseConfig(AppConfig): 5 | name = 'geye.database' 6 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | django==3.2.5 2 | # psycopg2==2.9.1 3 | psycopg2-binary 4 | requests 5 | requests[socks] 6 | gunicorn 7 | gunicorn[tornado] 8 | -------------------------------------------------------------------------------- /geye-fe/src/config/index.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | BASE_API: process.env.NODE_ENV === "production" ? "" : "http://192.168.62.129:8080", 3 | }; 4 | 5 | export default config; 6 | -------------------------------------------------------------------------------- /geye-fe/vue.config.js: -------------------------------------------------------------------------------- 1 | // const path = require("path") 2 | 3 | module.exports = { 4 | // publicPath: "/public", 5 | // outputDir: path.join(__dirname, "../templates/"), 6 | lintOnSave: false, 7 | productionSourceMap: false, 8 | }; 9 | -------------------------------------------------------------------------------- /geye-fe/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw* 22 | -------------------------------------------------------------------------------- /geye/core/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | 6 | ~~~~~~~~~~~~~~~~~~ 7 | 8 | 9 | :author: lightless 10 | :homepage: None 11 | :license: GPL-3.0, see LICENSE for more details. 12 | :copyright: Copyright (c) 2017 lightless. All rights reserved 13 | """ 14 | -------------------------------------------------------------------------------- /geye/utils/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | 6 | ~~~~~~~~~~~~~~~~~~ 7 | 8 | 9 | :author: lightless 10 | :homepage: None 11 | :license: GPL-3.0, see LICENSE for more details. 12 | :copyright: Copyright (c) 2017 lightless. All rights reserved 13 | """ 14 | -------------------------------------------------------------------------------- /geye-fe/src/components/404.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | 17 | 20 | -------------------------------------------------------------------------------- /geye/web/controller/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | 6 | ~~~~~~~~~~~~~~~~~~ 7 | 8 | 9 | :author: lightless 10 | :homepage: None 11 | :license: GPL-3.0, see LICENSE for more details. 12 | :copyright: Copyright (c) 2017 lightless. All rights reserved 13 | """ 14 | -------------------------------------------------------------------------------- /geye/core/engine/base/coroutine.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | 6 | ~~~~~~~~~~~~~~~~~~ 7 | 8 | 9 | :author: lightless 10 | :homepage: None 11 | :license: GPL-3.0, see LICENSE for more details. 12 | :copyright: Copyright (c) 2017 lightless. All rights reserved 13 | """ 14 | -------------------------------------------------------------------------------- /geye/system/management/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | 6 | ~~~~~~~~~~~~~~~~~~ 7 | 8 | 9 | :author: lightless 10 | :homepage: None 11 | :license: GPL-3.0, see LICENSE for more details. 12 | :copyright: Copyright (c) 2017 lightless. All rights reserved 13 | """ 14 | -------------------------------------------------------------------------------- /geye/web/controller/rule/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | 6 | ~~~~~~~~~~~~~~~~~~ 7 | 8 | 9 | :author: lightless 10 | :homepage: None 11 | :license: GPL-3.0, see LICENSE for more details. 12 | :copyright: Copyright (c) 2017 lightless. All rights reserved 13 | """ 14 | -------------------------------------------------------------------------------- /geye/system/management/commands/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | 6 | ~~~~~~~~~~~~~~~~~~ 7 | 8 | 9 | :author: lightless 10 | :homepage: None 11 | :license: GPL-3.0, see LICENSE for more details. 12 | :copyright: Copyright (c) 2017 lightless. All rights reserved 13 | """ 14 | -------------------------------------------------------------------------------- /geye/tests/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | -------------------------------------------------------------------------------- /tools/start_web_dev.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | SHELL_DIR=$(cd "$(dirname "$0")";pwd) 4 | echo "Shell directory is ${SHELL_DIR}" 5 | cd ${SHELL_DIR}/../ 6 | WORK_DIR=`pwd` 7 | echo "Current working directory is ${WORK_DIR}" 8 | 9 | PY_ENV_ACTIVATE="${WORK_DIR}/venv/bin/activate" 10 | 11 | source ${PY_ENV_ACTIVATE} 12 | 13 | python manage.py runserver 0.0.0.0:10001 14 | -------------------------------------------------------------------------------- /geye/web/controller/leaks/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | -------------------------------------------------------------------------------- /geye/web/controller/handleCenter/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | -------------------------------------------------------------------------------- /geye/core/engine/yuque/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | __init__.py 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | $END$ 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017-2021 lightless. All rights reserved 14 | """ 15 | -------------------------------------------------------------------------------- /geye-fe/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: false, 3 | env: { 4 | node: true 5 | }, 6 | extends: ["plugin:vue/essential", "@vue/prettier"], 7 | rules: { 8 | "no-console": process.env.NODE_ENV === "production" ? "error" : "off", 9 | "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off" 10 | }, 11 | parserOptions: { 12 | parser: "babel-eslint" 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /geye/core/data.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.core.data 6 | ~~~~~~~~~~~~~~ 7 | 8 | 全局变量 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | 16 | # 全局的app对象 17 | application = None 18 | -------------------------------------------------------------------------------- /geye/web/controller/user_center/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | __init__.py 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | $END$ 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017-2021 lightless. All rights reserved 14 | """ 15 | -------------------------------------------------------------------------------- /geye/core/engine/base/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | 6 | ~~~~~~~~~~~~~~~~~~ 7 | 8 | 9 | :author: lightless 10 | :homepage: None 11 | :license: GPL-3.0, see LICENSE for more details. 12 | :copyright: Copyright (c) 2017 lightless. All rights reserved 13 | """ 14 | 15 | from .thread import SingleThreadEngine, MultiThreadEngine 16 | -------------------------------------------------------------------------------- /geye-fe/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 19 | -------------------------------------------------------------------------------- /geye/web/controller/system/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | 16 | from .csrf import CSRFTokenView 17 | -------------------------------------------------------------------------------- /geye/core/engine/filter/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.core.engine.filter 6 | ~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 9 | :author: lightless 10 | :homepage: None 11 | :license: GPL-3.0, see LICENSE for more details. 12 | :copyright: Copyright (c) 2017 lightless. All rights reserved 13 | """ 14 | 15 | from .filter import FilterEngine 16 | -------------------------------------------------------------------------------- /geye/core/engine/notification.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.core.engine.notification 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 通知engine,负责发送通知 9 | static class or engine??? 10 | 11 | :author: lightless 12 | :homepage: None 13 | :license: GPL-3.0, see LICENSE for more details. 14 | :copyright: Copyright (c) 2017 lightless. All rights reserved 15 | """ 16 | -------------------------------------------------------------------------------- /geye/database/models/rules/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | 6 | ~~~~~~~~~~~~~~~~~~ 7 | 8 | 9 | :author: lightless 10 | :homepage: None 11 | :license: GPL-3.0, see LICENSE for more details. 12 | :copyright: Copyright (c) 2017 lightless. All rights reserved 13 | """ 14 | 15 | from .filter import GeyeFilterRuleModel 16 | from .search import GeyeSearchRuleModel 17 | -------------------------------------------------------------------------------- /geye/database/models/yuque/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | __init__.py 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | $END$ 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017-2021 lightless. All rights reserved 14 | """ 15 | 16 | from .rules import GeyeYuqueSearchRuleModel 17 | -------------------------------------------------------------------------------- /geye/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for geye 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/2.1/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', 'geye.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /geye/web/controller/token/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | 16 | from .token import TokensView, AddTokenView, DeleteTokenView, EditTokenView 17 | -------------------------------------------------------------------------------- /geye-fe/src/services/handleCenter/monitorCenter.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | import config from "@/config/index"; 4 | 5 | const BASE_API = config.BASE_API; 6 | const BASE_PATH = `${BASE_API}/api/v1/results/monitor`; 7 | const API_LIST = { 8 | all: `${BASE_PATH}/all`, 9 | }; 10 | 11 | export default { 12 | getALlMonitorResult(context, val) { 13 | let data = { 14 | page: val, 15 | }; 16 | return context.axios.get(API_LIST.all, {params: data}); 17 | } 18 | } -------------------------------------------------------------------------------- /geye-fe/README.md: -------------------------------------------------------------------------------- 1 | # geye-fe 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Run your tests 19 | ``` 20 | npm run test 21 | ``` 22 | 23 | ### Lints and fixes files 24 | ``` 25 | npm run lint 26 | ``` 27 | 28 | ### Customize configuration 29 | See [Configuration Reference](https://cli.vuejs.org/config/). 30 | -------------------------------------------------------------------------------- /tools/start_web.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | SHELL_DIR=$(cd "$(dirname "$0")";pwd) 4 | echo "Shell directory is ${SHELL_DIR}" 5 | cd ${SHELL_DIR}/../ 6 | WORK_DIR=`pwd` 7 | echo "Current working directory is ${WORK_DIR}" 8 | 9 | PY_ENV_ACTIVATE="${WORK_DIR}/venv/bin/activate" 10 | GUNICORN_CONFIG="${WORK_DIR}/conf/gunicorn_config.py" 11 | 12 | 13 | source "${PY_ENV_ACTIVATE}" 14 | 15 | gunicorn \ 16 | -c ${GUNICORN_CONFIG} \ 17 | --env DJANGO_SETTINGS_MODULE=geye.settings \ 18 | geye.wsgi 19 | -------------------------------------------------------------------------------- /geye/core/engine/monitor/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | 16 | from .monitorFetch import MonitorEngine 17 | from .monitorRefresh import MonitorRefreshEngine 18 | from .monitorSave import MonitorSaveEngine 19 | -------------------------------------------------------------------------------- /geye/settings/_base.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | _base.py 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 基础设置 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017-2021 lightless. All rights reserved 14 | """ 15 | import os 16 | from pathlib import Path 17 | 18 | BASE_DIR = Path(__file__).resolve().parent.parent.parent 19 | print(f"BASE_DIR: {BASE_DIR}") 20 | -------------------------------------------------------------------------------- /geye-fe/src/assets/css/color-dark.css: -------------------------------------------------------------------------------- 1 | .header{ 2 | background-color: #242f42; 3 | } 4 | .login-wrap{ 5 | background: #324157; 6 | } 7 | .plugins-tips{ 8 | background: #eef1f6; 9 | } 10 | .plugins-tips a{ 11 | color: #20a0ff; 12 | } 13 | .el-upload--text em { 14 | color: #20a0ff; 15 | } 16 | .pure-button{ 17 | background: #20a0ff; 18 | } 19 | .tags-li.active { 20 | border: 1px solid #409EFF; 21 | background-color: #409EFF; 22 | } 23 | .message-title{ 24 | color: #20a0ff; 25 | } 26 | .collapse-btn:hover{ 27 | background: rgb(40,52,70); 28 | } 29 | -------------------------------------------------------------------------------- /geye/core/engine/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | 6 | ~~~~~~~~~~~~~~~~~~ 7 | 8 | 9 | :author: lightless 10 | :homepage: None 11 | :license: GPL-3.0, see LICENSE for more details. 12 | :copyright: Copyright (c) 2017 lightless. All rights reserved 13 | """ 14 | 15 | __all__ = ["RefreshEngine", "SearchEngine", "FilterEngine", "SaveEngine"] 16 | 17 | from .refresh import RefreshEngine 18 | from .search import SearchEngine 19 | from .filter import FilterEngine 20 | from .save import SaveEngine 21 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == '__main__': 6 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'geye.settings') 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError as exc: 10 | raise ImportError( 11 | "Couldn't import Django. Are you sure it's installed and " 12 | "available on your PYTHONPATH environment variable? Did you " 13 | "forget to activate a virtual environment?" 14 | ) from exc 15 | execute_from_command_line(sys.argv) 16 | -------------------------------------------------------------------------------- /conf/geye.nginx.conf: -------------------------------------------------------------------------------- 1 | upstream geye { 2 | server 127.0.0.1:8000 fail_timeout=10; 3 | } 4 | 5 | server { 6 | listen 80; 7 | server_name _; 8 | 9 | charset utf-8; 10 | access_log /var/log/nginx/geye.access.log; 11 | root /app/geye-fe/dist/; 12 | index index.html; 13 | 14 | location / { 15 | try_files $uri $uri/ /index.html; 16 | } 17 | 18 | location /api/ { 19 | proxy_set_header X-Forwarded-For $remote_addr; 20 | proxy_set_header Host $http_host; 21 | proxy_redirect off; 22 | proxy_pass http://geye/api/; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /geye/web/controller/index.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | index.py 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 首页,渲染 vue 前端 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017-2021 lightless. All rights reserved 14 | """ 15 | # from django.shortcuts import render 16 | # from django.views import View 17 | # 18 | # 19 | # class IndexView(View): 20 | # 21 | # @staticmethod 22 | # def get(request): 23 | # return render(request, "index.html") 24 | -------------------------------------------------------------------------------- /geye-fe/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | geye-fe 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /geye/web/controller/cookie.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | cookie 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | $END$ 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017-2021 lightless. All rights reserved 14 | """ 15 | 16 | from .base import BaseView 17 | 18 | 19 | class ListCookieView(BaseView): 20 | 21 | @staticmethod 22 | def get(request): 23 | """ 24 | 列出所有的 cookie 25 | :param request: 26 | :return: 27 | """ 28 | pass 29 | -------------------------------------------------------------------------------- /geye/settings/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | __init__.py 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | $END$ 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017-2021 lightless. All rights reserved 14 | """ 15 | import os 16 | 17 | from .settings_default import * 18 | 19 | if os.environ.get("GEYE_ENV") == "prod": 20 | from .settings_prod import * 21 | elif os.environ.get("GEYE_ENV") == "dev": 22 | from .settings_dev import * 23 | else: 24 | from .settings_dev import * 25 | -------------------------------------------------------------------------------- /geye/utils/convert.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.utils.convert 6 | ~~~~~~~~~~~~~~~~~~ 7 | 8 | 一些通用的数据格式转换类 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | import datetime 16 | 17 | 18 | class CommonConvert: 19 | @staticmethod 20 | def datetime_to_str(d: datetime.datetime): 21 | return d.strftime("%Y-%m-%d %H:%M:%S") 22 | 23 | @staticmethod 24 | def ensure_int(arg): 25 | return arg if isinstance(arg, int) else int(arg) 26 | -------------------------------------------------------------------------------- /geye/constant.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | constant 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | $END$ 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017-2021 lightless. All rights reserved 14 | """ 15 | from enum import unique, IntEnum 16 | 17 | 18 | @unique 19 | class ResponseCode(IntEnum): 20 | DEFAULT = -1 21 | OK = 200 22 | GENERIC_ERROR = 400 23 | PARAM_ERROR = 401 24 | RUNTIME_ERROR = 402 25 | 26 | # 兼容老的code 27 | OLD_SUCCESS = 1001 28 | OLD_RUNTIME_ERROR = 1002 29 | OLD_PARAM_ERROR = 1004 30 | -------------------------------------------------------------------------------- /geye-fe/src/services/handleCenter/searchCenter.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | import config from "@/config/index"; 4 | 5 | const BASE_API = config.BASE_API; 6 | const API_LIST = { 7 | getSearchResults: BASE_API + "/api/v1/results/all", 8 | ignoreResult: BASE_API + "/api/v1/results/ignore", 9 | confirmResult: BASE_API + "/api/v1/results/confirm", 10 | }; 11 | 12 | 13 | export default { 14 | getAllSearchResults(ctx, data) { 15 | return ctx.axios.get(API_LIST.getSearchResults, {params: data}) 16 | }, 17 | 18 | ignore(ctx, data) { 19 | return ctx.axios.post(API_LIST.ignoreResult, data); 20 | }, 21 | 22 | confirm(ctx, data) { 23 | return ctx.axios.post(API_LIST.confirmResult, data); 24 | }, 25 | 26 | } 27 | -------------------------------------------------------------------------------- /geye/database/models/base.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.database.models.base 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | Base model 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | 16 | from django.db import models 17 | 18 | 19 | class GeyeBaseModel(models.Model): 20 | 21 | class Meta: 22 | abstract = True 23 | 24 | created_time = models.DateTimeField(auto_now=True) 25 | updated_time = models.DateTimeField(auto_now_add=True) 26 | is_deleted = models.BooleanField(default=False) 27 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | db: 5 | image: postgres:13-buster 6 | restart: always 7 | container_name: geye-db 8 | volumes: 9 | - ./run/db:/var/lib/postgresql/data 10 | # ports: 11 | # - "15432:5432" 12 | environment: 13 | POSTGRES_PASSWORD: 123456 14 | POSTGRES_DB: geye 15 | POSTGRES_USER: geye 16 | webapp: 17 | build: . 18 | ports: 19 | - "9123:80" 20 | container_name: geye-web 21 | volumes: 22 | - ./run/web:/app/logs 23 | depends_on: 24 | - db 25 | environment: 26 | DB_NAME: geye 27 | DB_USER: geye 28 | DB_PASSWORD: 123456 29 | DB_HOST: db 30 | DB_PORT: 5432 31 | # prod: 生产,dev:开发 32 | GEYE_ENV: prod 33 | -------------------------------------------------------------------------------- /docker_entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo "========== Starting geye ==========" 4 | cd /app/ || (echo "/app/ not exist!" && exit) 5 | mkdir -p logs/gunicorn 6 | echo "wait for 10 seconds..." 7 | sleep 10 8 | echo "========== Apply database migrations ==========" 9 | python manage.py migrate 10 | 11 | echo "========== starting nginx ==========" 12 | rm /etc/nginx/sites-enabled/default 13 | nginx 14 | 15 | echo "========== Starting Web Service ==========" 16 | gunicorn -c /app/conf/gunicorn_config.py \ 17 | --env DJANGO_SETTINGS_MODULE=geye.settings \ 18 | geye.wsgi 19 | 20 | echo "========== Starting Agent Service ==========" 21 | python manage.py run --single 22 | 23 | echo "========== Shell sleep ==========" 24 | # just keep this script running 25 | while true; do 26 | sleep 1 27 | done 28 | -------------------------------------------------------------------------------- /geye/database/models/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.database.models 6 | ~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 全部的ORM 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | 16 | from .cookie import GeyeCookieModel 17 | from .leaks import GeyeLeaksModel, LeaksStatusConstant 18 | from .monitorResults import GeyeMonitorResultsModel 19 | from .monitorRules import GeyeMonitorRules 20 | from .rules import GeyeSearchRuleModel, GeyeFilterRuleModel 21 | from .token import GeyeTokenModel 22 | from .user import GeyeUserModel 23 | 24 | # 语雀相关的 models 25 | from .yuque import GeyeYuqueSearchRuleModel 26 | -------------------------------------------------------------------------------- /geye/tests/test_monitor_api.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | test_monitor_api.py 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | $END$ 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017-2019 lightless. All rights reserved 14 | """ 15 | import json 16 | 17 | import requests 18 | 19 | 20 | urls = [ 21 | "https://api.github.com/users/Edward-L/events", 22 | "https://api.github.com/users/lightless233/events", 23 | ] 24 | 25 | 26 | for url in urls: 27 | resp = requests.get(url) 28 | result = json.loads(resp.text) 29 | 30 | for _item in result: 31 | if _item.get("type") == "PushEvent": 32 | print(_item.keys()) 33 | -------------------------------------------------------------------------------- /geye-fe/src/services/monitor.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | import config from "@/config/index"; 4 | 5 | const BASE_API = config.BASE_API; 6 | const BASE_PATH = `${BASE_API}/api/v1/rule/monitor`; 7 | const API_LIST = { 8 | add: `${BASE_PATH}/new`, 9 | update: `${BASE_PATH}/update`, 10 | delete: `${BASE_PATH}/delete`, 11 | all: `${BASE_PATH}/all`, 12 | }; 13 | 14 | export default { 15 | 16 | addMonitorRule(context, data) { 17 | return context.axios.post(API_LIST.add, data); 18 | }, 19 | 20 | updateMonitorRule(context, data) { 21 | return context.axios.post(API_LIST.update, data); 22 | }, 23 | 24 | deleteMonitorRule(context, id) { 25 | return context.axios.post(API_LIST.delete, {id: id}); 26 | }, 27 | 28 | getAllMonitorRule(context) { 29 | return context.axios.get(API_LIST.all); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /geye-fe/src/components/utils/ItemCard.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 27 | 28 | 33 | -------------------------------------------------------------------------------- /geye/system/middleware/vue.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | vue 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | $END$ 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017-2021 lightless. All rights reserved 14 | """ 15 | from django.shortcuts import render 16 | 17 | 18 | class VueMiddleware: 19 | 20 | def __init__(self, get_response): 21 | super(VueMiddleware, self).__init__() 22 | self.get_response = get_response 23 | 24 | def __call__(self, request): 25 | # print(dir(request)) 26 | # print(request.path) 27 | 28 | if request.path.startswith("/api/"): 29 | return self.get_response(request) 30 | else: 31 | return render(request, "index.html") 32 | -------------------------------------------------------------------------------- /geye-fe/src/services/filterRule.js: -------------------------------------------------------------------------------- 1 | import config from "@/config"; 2 | 3 | 4 | const API_LIST = { 5 | addFilterRule: config.BASE_API + "/api/v1/rule/filter/new", 6 | deleteFilterRule: config.BASE_API + "/api/v1/rule/filter/delete", 7 | getDetail: config.BASE_API + "/api/v1/rule/filter/detail", 8 | updateFilterRule: config.BASE_API + "/api/v1/rule/filter/update", 9 | }; 10 | 11 | 12 | const services = { 13 | addFilterRule(ctx, data) { 14 | return ctx.axios.post(API_LIST.addFilterRule, data); 15 | }, 16 | 17 | deleteFilterRule(ctx, data) { 18 | return ctx.axios.post(API_LIST.deleteFilterRule, data); 19 | }, 20 | 21 | getFilterRuleDetail(ctx, data) { 22 | return ctx.axios.get(API_LIST.getDetail, {params: data}) 23 | }, 24 | 25 | updateFilterRule(ctx, data) { 26 | return ctx.axios.post(API_LIST.updateFilterRule, data); 27 | } 28 | 29 | }; 30 | 31 | export default services; 32 | -------------------------------------------------------------------------------- /geye/urls.py: -------------------------------------------------------------------------------- 1 | """geye URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/2.1/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.urls import path, include 17 | 18 | from geye.web.controller.system import csrf 19 | 20 | 21 | urlpatterns = [ 22 | 23 | # CSRF Token 路由 24 | path("api/_csrf_token", csrf.CSRFTokenView.as_view()), 25 | 26 | # API路由 27 | path("api/", include("geye.web.urls")), 28 | ] 29 | -------------------------------------------------------------------------------- /geye-fe/src/App.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 17 | 18 | 19 | 42 | -------------------------------------------------------------------------------- /geye/web/controller/system/csrf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.web.controller.system.csrf 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 用于前端页面获取CSRF Token 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | 16 | 17 | from django.views import View 18 | from django.http import HttpResponse 19 | import django.middleware.csrf 20 | 21 | from geye.utils.log import logger 22 | 23 | 24 | class CSRFTokenView(View): 25 | 26 | @staticmethod 27 | def get(request): 28 | logger.debug("COOKIES: {}".format(request.COOKIES)) 29 | # csrf_token = "22222" 30 | csrf_token = django.middleware.csrf.get_token(request) 31 | response = HttpResponse(csrf_token) 32 | # response.set_cookie("csrftoken", csrf_token, domain="192.168.62.129", samesite=None) 33 | 34 | return response 35 | -------------------------------------------------------------------------------- /geye/tests/test_lua.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | from lupa import LuaRuntime 16 | 17 | lua = LuaRuntime() 18 | lua.eval("1+1") 19 | 20 | 21 | # rule_content = "'password' in {{content}} and 'token' not in {{content}}".replace("\'", "\"") 22 | rule_content = '[x for x in {}.__class__.__bases__[0].__subclasses__() if x.__name__ == "zipimporter"]' 23 | # rule_content = '[].__class__.__mro__[-1].__subclasses__()' 24 | # filter_content = "aaaabbbcccdde\naaacccbdbadjf" 25 | filter_content = "aaaabbbcccdde\naaacccbdbadjf\npassword=123" 26 | 27 | code = rule_content.replace("{{content}}", "filter_content") 28 | code = "python.eval(\'{code}\')".format(code=code) 29 | print("final code: {}".format(code)) 30 | 31 | result = lua.eval(code) 32 | print("result: {}".format(result)) 33 | -------------------------------------------------------------------------------- /geye-fe/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "geye-fe", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "@fortawesome/fontawesome-free": "^5.4.2", 12 | "@fortawesome/fontawesome-svg-core": "^1.2.7", 13 | "@fortawesome/free-regular-svg-icons": "^5.4.2", 14 | "@fortawesome/free-solid-svg-icons": "^5.4.2", 15 | "@fortawesome/vue-fontawesome": "^0.1.2", 16 | "axios": "^0.21.1", 17 | "core-js": "^3.15.2", 18 | "element-ui": "^2.15.3", 19 | "eslint": "^7.31.0", 20 | "normalize.css": "^8.0.1", 21 | "vue": "^2.6.14", 22 | "vue-axios": "^3.2.4", 23 | "vue-router": "^3.5.2" 24 | }, 25 | "devDependencies": { 26 | "@vue/cli-plugin-babel": "^4.5.13", 27 | "@vue/cli-plugin-eslint": "^4.5.13", 28 | "@vue/cli-service": "^4.5.13", 29 | "@vue/eslint-config-prettier": "^6.0.0", 30 | "babel-eslint": "^10.1.0", 31 | "eslint-plugin-vue": "^7.14.0", 32 | "vue-template-compiler": "^2.6.14" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /geye-fe/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import ElementUI from 'element-ui' 3 | import 'element-ui/lib/theme-chalk/index.css' 4 | // import NormailizeCss from 'normalize.css' 5 | 6 | // font awesome 7 | import { library } from '@fortawesome/fontawesome-svg-core' 8 | import { faTachometerAlt, faList, faPaperPlane, faBars, faKey, faMoneyCheckAlt } from '@fortawesome/free-solid-svg-icons' 9 | import {faCircle} from "@fortawesome/free-regular-svg-icons"; 10 | import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' 11 | library.add(faTachometerAlt, faList, faPaperPlane, faCircle, faBars, faKey, faMoneyCheckAlt); 12 | 13 | 14 | // axios 15 | // import axios from "axios" 16 | import axios from "./utils/axios" 17 | import VueAxios from "vue-axios" 18 | 19 | import App from './App' 20 | import router from './router' 21 | 22 | 23 | Vue.component('font-awesome-icon', FontAwesomeIcon); 24 | Vue.config.productionTip = false; 25 | Vue.use(ElementUI); 26 | // Vue.prototype.$axios = axios; 27 | Vue.use(VueAxios, axios); 28 | 29 | /* eslint-disable */ 30 | new Vue({ 31 | router, 32 | render: h => h(App), 33 | }).$mount("#app"); 34 | -------------------------------------------------------------------------------- /geye/database/models/user.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.database.models.user 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | user model 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017-2021 lightless. All rights reserved 14 | """ 15 | 16 | from django.db import models 17 | 18 | from geye.database.models.base import GeyeBaseModel 19 | 20 | 21 | class GeyeUserManager(models.Manager): 22 | pass 23 | 24 | 25 | class GeyeUserModel(GeyeBaseModel): 26 | """ 27 | status - 账户状态,0:等待激活,1:正常,2:封禁 28 | """ 29 | 30 | class Meta: 31 | db_table = "geye_user" 32 | 33 | username = models.CharField(max_length=64, default="", null=False) 34 | password = models.CharField(max_length=512, default="", null=False) 35 | email = models.CharField(max_length=128, default="", null=False) 36 | status = models.PositiveSmallIntegerField(default=0, null=False) 37 | 38 | objects = models.Manager() 39 | instance = GeyeUserManager() 40 | -------------------------------------------------------------------------------- /geye-fe/src/utils/axios.js: -------------------------------------------------------------------------------- 1 | import axios from "axios" 2 | import CSRF_API from "../services" 3 | import config from "@/config" 4 | 5 | axios.defaults.timeout = 5000; 6 | axios.defaults.withCredentials = true; 7 | axios.defaults.xsrfHeaderName = "X-CSRFToken"; 8 | axios.defaults.xsrfCookieName = "csrftoken"; 9 | const BASE_API = config.BASE_API; 10 | 11 | 12 | function getCSRFToken(config) { 13 | return axios.get(BASE_API + CSRF_API) 14 | .then(response => { 15 | // console.log("CSRF Token API response:", response.data); 16 | config.withCredentials = true; 17 | config.headers["X-CSRFToken"] = response.data.trim(); 18 | return config; 19 | }) 20 | } 21 | 22 | // request 拦截器 23 | axios.interceptors.request.use( 24 | config => { 25 | // todo: 这里先简单判断,后面需要优化掉 26 | // console.log(config); 27 | if (config.url.indexOf(CSRF_API) > -1 || config.method !== "post") { 28 | // console.log("no need csrf!"); 29 | return config; 30 | } 31 | 32 | // POST和PUT请求需要先请求CSRF Token 33 | if (config.method === "post" || config.method === "put") { 34 | return getCSRFToken(config); 35 | } 36 | } 37 | ); 38 | 39 | export default axios -------------------------------------------------------------------------------- /geye-fe/src/services/token.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | import config from "@/config/index"; 4 | 5 | 6 | const BASE_API = config.BASE_API; 7 | const API_LIST = { 8 | getAllTokens: BASE_API + "/api/v1/token/all", 9 | addToken: BASE_API + "/api/v1/token/new", 10 | updateToken: BASE_API + "/api/v1/token/update", 11 | deleteToken: BASE_API + "/api/v1/token/delete", 12 | changeTokenStatus: BASE_API + "/api/v1/token/change_status", 13 | getTokenDetail: BASE_API + "/api/v1/token/detail", 14 | }; 15 | 16 | 17 | export default { 18 | 19 | getAllTokens(ctx) { 20 | return ctx.axios.get(API_LIST.getAllTokens); 21 | }, 22 | 23 | addToken(ctx, data) { 24 | return ctx.axios.post(API_LIST.addToken, data); 25 | }, 26 | 27 | updateToken(ctx, data) { 28 | return ctx.axios.post(API_LIST.updateToken, data); 29 | }, 30 | 31 | deleteToken(ctx, data) { 32 | return ctx.axios.post(API_LIST.deleteToken, data); 33 | }, 34 | 35 | changeTokenStatus(ctx, data) { 36 | return ctx.axios.post(API_LIST.changeTokenStatus, data); 37 | }, 38 | 39 | getTokenDetail(ctx, data) { 40 | return ctx.axios.get(API_LIST.getTokenDetail, {params: data}); 41 | }, 42 | 43 | } 44 | 45 | -------------------------------------------------------------------------------- /geye/database/migrations/0004_geyecookiemodel.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.2.5 on 2021-11-06 14:50 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('database', '0003_auto_20211029_2354'), 10 | ] 11 | 12 | operations = [ 13 | migrations.CreateModel( 14 | name='GeyeCookieModel', 15 | fields=[ 16 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 17 | ('created_time', models.DateTimeField(auto_now=True)), 18 | ('updated_time', models.DateTimeField(auto_now_add=True)), 19 | ('is_deleted', models.BooleanField(default=False)), 20 | ('name', models.CharField(default='cookie name', max_length=64)), 21 | ('domain', models.CharField(default='', max_length=2048)), 22 | ('values', models.TextField()), 23 | ('status', models.PositiveSmallIntegerField(default=1)), 24 | ], 25 | options={ 26 | 'db_table': 'geye_cookie', 27 | }, 28 | ), 29 | ] 30 | -------------------------------------------------------------------------------- /geye-fe/src/services/leaks.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | import config from "@/config/index"; 4 | 5 | const BASE_API = config.BASE_API; 6 | const API_LIST = { 7 | getLeaks: BASE_API + "/api/v1/leaks/all", 8 | deleteLeak: BASE_API + "/api/v1/leaks/delete", 9 | changeStatusLeak: BASE_API + "/api/v1/leaks/change_status", 10 | batchChangeStatus: BASE_API + "/api/v1/leaks/batch_change_status", 11 | }; 12 | 13 | export default { 14 | getLeaks(ctx, currentPage, status) { 15 | let data = { 16 | page: currentPage, 17 | status: status, 18 | }; 19 | return ctx.axios.get(API_LIST.getLeaks, {params: data}); 20 | }, 21 | 22 | deleteLeak(ctx, id) { 23 | let data = { 24 | id: id 25 | }; 26 | return ctx.axios.post(API_LIST.deleteLeak, data); 27 | }, 28 | 29 | changeStatusLeak(ctx, action ,id) { 30 | let data = { 31 | id: id, 32 | action: action 33 | }; 34 | return ctx.axios.post(API_LIST.changeStatusLeak, data); 35 | }, 36 | 37 | batchChangeStatusLeak(ctx, action, ids) { 38 | let data = { 39 | action: action, 40 | ids: ids, 41 | }; 42 | return ctx.axios.post(API_LIST.batchChangeStatus, data); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /geye-fe/src/services/globalFilterRule.js: -------------------------------------------------------------------------------- 1 | import config from "@/config"; 2 | 3 | 4 | const API = { 5 | getAllRules: config.BASE_API + "/api/v1/rule/global/all", 6 | addGlobalFilterRule: config.BASE_API + "/api/v1/rule/global/new", 7 | deleteGlobalFilterRule: config.BASE_API + "/api/v1/rule/global/delete", 8 | updateGlobalFilterRule: config.BASE_API + "/api/v1/rule/global/update", 9 | getDetail: config.BASE_API + "/api/v1/rule/global/detail", 10 | changeStatus: config.BASE_API + "/api/v1/rule/global/change_status" 11 | }; 12 | 13 | export default { 14 | 15 | getAllRules(ctx) { 16 | return ctx.axios.get(API.getAllRules); 17 | }, 18 | 19 | addGlobalFilterRule(ctx, data) { 20 | return ctx.axios.post(API.addGlobalFilterRule, data); 21 | }, 22 | 23 | deleteGlobalFilterRule(ctx, data) { 24 | return ctx.axios.post(API.deleteGlobalFilterRule, data); 25 | }, 26 | 27 | updateGlobalFilterRule(ctx, data) { 28 | return ctx.axios.post(API.updateGlobalFilterRule, data); 29 | }, 30 | 31 | getDetail(ctx, data) { 32 | return ctx.axios.get(API.getDetail, {params: data}); 33 | }, 34 | 35 | changeStatus(ctx, data) { 36 | return ctx.axios.post(API.changeStatus, data); 37 | }, 38 | 39 | } 40 | -------------------------------------------------------------------------------- /geye/tests/test_monitor_engine.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | test_monitor_engine 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | $END$ 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017-2018 lightless. All rights reserved 14 | """ 15 | 16 | import sys 17 | import os 18 | 19 | sys.path.append("..") 20 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "geye.settings") 21 | 22 | import django 23 | django.setup() 24 | 25 | from geye.application import GeyeApplication 26 | from geye.database.models.monitorRules import MonitorTaskTypeConstant, MonitorEventTypeConstant 27 | from geye.utils.datatype import PriorityTask 28 | 29 | 30 | if __name__ == '__main__': 31 | app = GeyeApplication("test") 32 | app.start(queues=["monitor_task_queue"], engines=["monitor_refresh_engine", "monitor_engine"]) 33 | 34 | app.MessageQueues.MONITOR_TASK_QUEUE.put(PriorityTask(5, { 35 | "task_type": MonitorTaskTypeConstant.USER, 36 | "event_type": MonitorEventTypeConstant.PUSH_EVENT, 37 | "rule_content": '{"username": "lightless233"}', 38 | })) 39 | 40 | -------------------------------------------------------------------------------- /geye/web/controller/user_center/uc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | uc.py 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | user center api 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017-2021 lightless. All rights reserved 14 | """ 15 | from django.http import JsonResponse 16 | 17 | from geye import constant 18 | from geye.web.controller.base import BaseView, RequestValidator 19 | 20 | 21 | class UserRegisterView(BaseView): 22 | """ 23 | 注册用户 24 | """ 25 | 26 | def post(self, request): 27 | cr = RequestValidator.check_params(request, ("username", "email", "password"), check_empty=True) 28 | if cr.has_error: 29 | err_resp = self.quick_error(constant.ResponseCode.PARAM_ERROR.value, cr.error_message) 30 | return JsonResponse(err_resp.to_dict()) 31 | 32 | request_params = cr.params 33 | username = request_params.get("username", None) 34 | email = request_params.get("email", None) 35 | password = request_params.get("password", None) 36 | 37 | # service.do_register(username, email, password) 38 | -------------------------------------------------------------------------------- /geye/database/models/cookie.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.database.models.cookie 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | cookie 管理表 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017-2021 lightless. All rights reserved 14 | """ 15 | from django.db import models 16 | 17 | from geye.database.models.base import GeyeBaseModel 18 | 19 | 20 | class GeyeCookieManager(models.Manager): 21 | 22 | def get_by_domain(self, domain): 23 | return self.filter(is_deleted=0, domain=domain, status=1).all() 24 | 25 | 26 | class GeyeCookieModel(GeyeBaseModel): 27 | class Meta: 28 | db_table = "geye_cookie" 29 | 30 | # cookie 的名称,用于区分这个 cookie 是干啥用的,并非 cookie 变量的名字 31 | name = models.CharField(max_length=64, default="cookie name") 32 | 33 | # 这个 cookie 应当被附加到哪个域名上 34 | domain = models.CharField(max_length=2048, default="") 35 | 36 | # cookie值,可以直接放到 cookie 头中的格式 37 | # e.g. _yuque_session=123; _csrf_token=345; 38 | values = models.TextField() 39 | 40 | # 状态 41 | # 1:启用,0:关闭 42 | status = models.PositiveSmallIntegerField(default=1) 43 | 44 | objects = models.Manager() 45 | instance = GeyeCookieManager() 46 | -------------------------------------------------------------------------------- /geye/core/engine/base/base.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.core.engine.base.base 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | BaseEngine 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | import threading 16 | from typing import List 17 | 18 | import abc 19 | 20 | 21 | class CommonBaseEngine(object): 22 | 23 | class EngineStatus: 24 | READY = 0x00 25 | RUNNING = 0x01 26 | STOP = 0x02 27 | 28 | def __init__(self): 29 | super(CommonBaseEngine, self).__init__() 30 | self.name = "BaseEngine" 31 | self.status = self.EngineStatus.READY 32 | self.ev: threading.Event = threading.Event() 33 | self.thread: threading.Thread = None 34 | self.thread_pool: List[threading.Thread] = None 35 | 36 | def is_running(self): 37 | return self.status == self.EngineStatus.RUNNING 38 | 39 | @abc.abstractmethod 40 | def start(self): 41 | pass 42 | 43 | @abc.abstractmethod 44 | def stop(self, force=True): 45 | pass 46 | 47 | @abc.abstractmethod 48 | def is_alive(self): 49 | pass 50 | 51 | @abc.abstractmethod 52 | def _worker(self): 53 | pass 54 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3-buster 2 | EXPOSE 80 3 | 4 | # 设置工作目录 5 | WORKDIR /app 6 | 7 | # 声明容器中的 /app 是匿名卷 8 | # VOLUME /app 9 | 10 | # 复制代码到 docker 中 11 | ADD . /app/ 12 | 13 | # 安装 nodejs, nginx 14 | RUN sed -i 's#http://deb.debian.org#https://mirrors.aliyun.com#g' /etc/apt/sources.list && \ 15 | sed -i 's#security.debian.org/debian-security#mirrors.ustc.edu.cn/debian-security#g' /etc/apt/sources.list && \ 16 | # curl -fsSL https://deb.nodesource.com/setup_14.x | bash - && \ 17 | curl -sSL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - && \ 18 | echo "deb https://mirrors.ustc.edu.cn/nodesource/deb/node_14.x stretch main" >> /etc/apt/sources.list && \ 19 | echo "deb-src https://mirrors.ustc.edu.cn/nodesource/deb/node_14.x stretch main" >> /etc/apt/sources.list && \ 20 | apt-get update && \ 21 | apt-get install -y apt-utils nodejs nginx && \ 22 | apt-get autoremove -y 23 | 24 | # 构建前端代码 25 | RUN ls -alh /app/ && \ 26 | cd /app/geye-fe/ && \ 27 | npm i --registry https://registry.npm.taobao.org && \ 28 | npm run build && \ 29 | ls -alh /app/geye-fe/ 30 | 31 | # 安装Python的相关依赖 32 | RUN pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ && \ 33 | pip install "requests[socks]" "gunicorn[tornado]" -i https://mirrors.aliyun.com/pypi/simple/ 34 | 35 | RUN cp /app/conf/geye.nginx.conf /etc/nginx/conf.d/geye.conf 36 | 37 | ENV PYTHONUNBUFFERED=1 38 | CMD cd /app/ && sh docker_entrypoint.sh 39 | -------------------------------------------------------------------------------- /geye/tests/test_eval.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | 16 | import ast 17 | 18 | 19 | # rule_content = "'password' in {{content}} and 'token' not in {{content}}" 20 | rule_content = '[x for x in {}.__class__.__bases__[0].__subclasses__() if x.__name__ == "zipimporter"]' 21 | # rule_content = '[].__class__.__mro__[-1].__subclasses__()' 22 | filter_content = "aaaabbbcccdde\naaacccbdbadjf" 23 | # filter_content = "aaaabbbcccdde\naaacccbdbadjf\npassword=123" 24 | 25 | # print("globals: {}".format(globals())) 26 | # print("locals: {}".format(locals())) 27 | 28 | code = rule_content.replace("{{content}}", "filter_content") 29 | print("final code: {}".format(code)) 30 | 31 | result = eval(code, {"__builtins__": None}, {"filter_content": filter_content}) 32 | print(result) 33 | 34 | 35 | # class ASTNode(ast.NodeVisitor): 36 | # def generic_visit(self, node): 37 | # print("node: {}".format(dir(node.body))) 38 | # print("node: {}".format(node.body.keywords)) 39 | # print("node name: {}".format(type(node))) 40 | # 41 | # 42 | # n = ast.parse(code, '', "eval") 43 | # v = ASTNode() 44 | # v.visit(n) 45 | # 46 | # print("global node: {}".format(n)) 47 | -------------------------------------------------------------------------------- /geye-fe/src/services/searchRule.js: -------------------------------------------------------------------------------- 1 | import config from "@/config/index"; 2 | 3 | const BASE_API = config.BASE_API; 4 | const API_LIST = { 5 | all: BASE_API + "/api/v1/rule/search/all", 6 | addSearchRule: BASE_API + "/api/v1/rule/search/new", 7 | deleteSearchRule: BASE_API + "/api/v1/rule/search/delete", 8 | changeSearchRuleStatus: BASE_API + "/api/v1/rule/search/change_status", 9 | getDetail: BASE_API + "/api/v1/rule/search/get_detail", 10 | updateSearchRule: BASE_API + "/api/v1/rule/search/update" 11 | }; 12 | 13 | 14 | const services = { 15 | 16 | all(context) { 17 | return context.axios.get(API_LIST.all); 18 | }, 19 | 20 | addSearchRule(context, data) { 21 | return context.axios.post(API_LIST.addSearchRule, data, {withCredentials: true}); 22 | }, 23 | 24 | deleteSearchRule(context, data) { 25 | return context.axios.post(API_LIST.deleteSearchRule, data); 26 | }, 27 | 28 | // 修改某个search rule 的状态 29 | changeStatus(context, data) { 30 | return context.axios.post(API_LIST.changeSearchRuleStatus, data); 31 | }, 32 | 33 | // 根据id 或 rule_name获取search rule的详细信息 34 | // 包括search rule的filter rule 35 | // data = { 36 | // "id": 11, "rule_name": "qqq" 37 | // } 38 | // 优先使用id获取信息 39 | getDetail(context, data) { 40 | return context.axios.get(API_LIST.getDetail, {params: data}); 41 | }, 42 | 43 | updateSearchRule(context, data) { 44 | return context.axios.post(API_LIST.updateSearchRule, data); 45 | }, 46 | 47 | }; 48 | 49 | export default services 50 | -------------------------------------------------------------------------------- /conf/gunicorn_config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | gunicorn_config 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | Gunicorn的配置文件 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | 16 | 17 | import multiprocessing 18 | 19 | # 是否开启DEBUG模式 20 | _DEBUG = False 21 | 22 | 23 | # Web后端接口默认开到这个地址 24 | bind = "127.0.0.1:8000" 25 | 26 | # workers 27 | # debug模式下只开启1个worker 28 | workers = multiprocessing.cpu_count() * 2 + 1 if not _DEBUG else 1 29 | 30 | # worker class 31 | # worker进程的类型,你可能需要手动安装:pip install gunicorn[tornado] 32 | # worker_class = "tornado" 暂时不知道为啥不能用这个,先默认设置为 sync 33 | worker_class = "sync" 34 | 35 | # max_requests 36 | # 当worker进程每处理max_requests个请求后,会自动重启,如果为0,则表示永不重启 37 | max_requests = 0 38 | # max_requests_jitter = 0 39 | 40 | # worker重启前处理后事的时间 41 | graceful_timeout = 3 42 | 43 | # 是否后台运行 44 | # debug模式下不启用 45 | daemon = False if _DEBUG else True 46 | 47 | # reload 48 | # 代码变更时是否自动重启,debug模式开启 49 | reload = True if _DEBUG else False 50 | reload_engine = "auto" 51 | 52 | # 进程名字 53 | proc_name = "GeyeWeb" 54 | 55 | # 请求日志,错误日志,日志格式 56 | accesslog = "./logs/gunicorn/access.log" 57 | errorlog = "./logs/gunicorn/error.log" 58 | # remoteIP - 请求时间 请求行 状态码 返回值长度 "referer" "UA" 59 | access_log_format = '%(h)s %(l)s %(t)s %(r)s %(s)s %(b)s "%(f)s" "%(a)s"' 60 | loglevel = "debug" if _DEBUG else "info" 61 | capture_output = True 62 | -------------------------------------------------------------------------------- /geye/tests/test_process.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | 16 | import time 17 | import multiprocessing 18 | 19 | 20 | # def worker(): 21 | # print("start long job!") 22 | # time.sleep(15) 23 | # print("end long job!") 24 | # 25 | # 26 | # p = multiprocessing.Process(target=worker) 27 | # p.start() 28 | # 29 | # # try: 30 | # # print("start join!") 31 | # # p.join(5) 32 | # # print("join done!") 33 | # # except multiprocessing.TimeoutError: 34 | # # print("timeout!") 35 | # # p.terminate() 36 | # 37 | # # 下面这段是正确的杀掉子进程的方法 38 | # # 确认下queue会不会导致内存泄露 39 | # p.join(5) 40 | # if p.is_alive(): 41 | # print("still alive! kill it!") 42 | # p.terminate() 43 | # p.join() 44 | 45 | def child_worker(): 46 | print("child worker start!") 47 | time.sleep(15) 48 | print("child worker stop!") 49 | 50 | 51 | def parent_worker(): 52 | print("parent worker start!") 53 | p = multiprocessing.Process(target=child_worker) 54 | p.start() 55 | p.join(5) 56 | if p.is_alive(): 57 | p.terminate() 58 | p.join() 59 | print("kill confirmed!") 60 | print("parent worker stop!") 61 | 62 | 63 | parent_process = multiprocessing.Process(target=parent_worker) 64 | parent_process.start() 65 | parent_process.join() 66 | 67 | print("main done!") 68 | while True: 69 | time.sleep(1) 70 | -------------------------------------------------------------------------------- /geye/system/middleware/cors.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.system.middleware.cors 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | CORS中间件,暂时把允许的domain写死到代码里,方便开发 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | 16 | from urllib.parse import urlparse 17 | 18 | from django.conf import settings 19 | from django.http import HttpResponseForbidden 20 | 21 | from geye.utils.log import logger 22 | 23 | 24 | class CORSMiddleware: 25 | 26 | def __init__(self, get_response): 27 | super(CORSMiddleware, self).__init__() 28 | self.get_response = get_response 29 | 30 | self.allowed_origins = settings.ALLOWED_CORS 31 | 32 | def __call__(self, request): 33 | response = self.get_response(request) 34 | # logger.debug("COOKIES: {}".format(request.COOKIES)) 35 | # logger.debug("HEADERS: {}".format(request)) 36 | 37 | origin = request.META.get("HTTP_ORIGIN", None) 38 | # print(origin) 39 | if origin: 40 | o = urlparse(origin) 41 | # print(o.hostname) 42 | if o.hostname in self.allowed_origins: 43 | response["Access-Control-Allow-Origin"] = origin 44 | response["Access-Control-Allow-Headers"] = "Content-Type, X-CSRFToken" 45 | response["Access-Control-Allow-Credentials"] = "true" 46 | return response 47 | else: 48 | return HttpResponseForbidden("

Invalid Origin

") 49 | 50 | return response 51 | -------------------------------------------------------------------------------- /geye/database/models/yuque/leaks.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | result.py 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | $END$ 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017-2021 lightless. All rights reserved 14 | """ 15 | from django.db import models 16 | 17 | 18 | class GeyeYuqueLeakManager(models.Manager): 19 | pass 20 | 21 | 22 | class GeyeYuqueLeaksModel(models.Model): 23 | class Meta: 24 | db_table = "geye_yuque_leaks" 25 | 26 | # 语雀文档的标题 27 | title = models.CharField(max_length=512, default="No Title") 28 | 29 | # 文档的URL,是跳转形式,并非直接链接 30 | # 也许可以用来去重 31 | go_url = models.CharField(max_length=512, default="") 32 | 33 | # 直链 URL 34 | url = models.CharField(max_length=2048, default="") 35 | 36 | # 知识库名称? 37 | book_name = models.CharField(max_length=512) 38 | 39 | # 这个知识库所属的 group 40 | group_name = models.CharField(max_length=512) 41 | 42 | # 文章的摘要信息 43 | abstract = models.TextField() 44 | 45 | # 标识是哪条搜索规则触发的 46 | search_rule_id = models.PositiveBigIntegerField(default=0) 47 | 48 | # 这条泄露信息的状态 49 | # 1 - 待处理,2 - 确认是泄露,3-误报 50 | status = models.PositiveSmallIntegerField(default=1) 51 | 52 | # 文章的几个时间值 53 | content_updated_at = models.CharField(max_length=32, default="") 54 | first_published_at = models.CharField(max_length=32, default="") 55 | published_at = models.CharField(max_length=32, default="") 56 | paper_created_at = models.CharField(max_length=32, default="") 57 | paper_updated_at = models.CharField(max_length=32, default="") 58 | 59 | objects = models.Manager() 60 | instance = GeyeYuqueLeakManager() 61 | -------------------------------------------------------------------------------- /geye/database/models/yuque/rules.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | rules 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | $END$ 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017-2021 lightless. All rights reserved 14 | """ 15 | from django.db import models 16 | 17 | from geye.database.models.base import GeyeBaseModel 18 | 19 | 20 | class GeyeYuqueSearchRuleManger(models.Manager): 21 | 22 | def all_enable_rules(self): 23 | """ 24 | 获取所有开启的语雀监控规则 25 | :return: 26 | """ 27 | return self.filter(is_deleted=0, status=1).order_by("-priority").all() 28 | 29 | 30 | class GeyeYuqueSearchRuleModel(GeyeBaseModel): 31 | """ 32 | 语雀监控关键词规则 33 | """ 34 | 35 | class Meta: 36 | db_table = "geye_yuque_search_rule" 37 | 38 | # 规则名称 39 | name = models.CharField(max_length=128, default="", null=False) 40 | 41 | # 规则内容,即要搜索的关键字 42 | rule = models.CharField(max_length=1024, default="", null=False) 43 | 44 | # 规则状态 45 | # 0 - 关闭 46 | # 1 - 启用 47 | status = models.PositiveSmallIntegerField(default=1, null=False) 48 | 49 | # 优先级,默认为5,可选值:1-10 50 | # 越大优先级越高 51 | priority = models.PositiveIntegerField(default=5, null=False) 52 | 53 | # 上一次刷新时间 54 | last_refresh_time = models.DateTimeField(auto_now_add=True, null=False) 55 | 56 | # 刷新间隔,单位:分钟 57 | interval = models.PositiveIntegerField(default=5, null=False) 58 | 59 | # 命中后是否需要发消息通知 60 | # 0 - 不通知 61 | # 1 - 通知 62 | need_notification = models.PositiveSmallIntegerField(default=0, null=False) 63 | 64 | # 命中后是否需要将内容存储下来 65 | need_save = models.BooleanField(default=False, null=False) 66 | 67 | objects = models.Manager() 68 | instance = GeyeYuqueSearchRuleManger() 69 | -------------------------------------------------------------------------------- /geye/settings/settings_default.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | settings_default 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 默认配置文件,最先加载 9 | 不需要用户配置的内容放到这里 10 | 11 | :author: lightless 12 | :homepage: None 13 | :license: GPL-3.0, see LICENSE for more details. 14 | :copyright: Copyright (c) 2017-2021 lightless. All rights reserved 15 | """ 16 | 17 | from ._base import BASE_DIR 18 | 19 | INSTALLED_APPS = [ 20 | 'django.contrib.sessions', 21 | # 'django.contrib.staticfiles', 22 | # geye app 23 | 'geye.system', 24 | 'geye.database', 25 | ] 26 | 27 | MIDDLEWARE = [ 28 | 'django.middleware.security.SecurityMiddleware', 29 | 'django.contrib.sessions.middleware.SessionMiddleware', 30 | 'django.middleware.common.CommonMiddleware', 31 | 'django.middleware.csrf.CsrfViewMiddleware', 32 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 33 | "geye.system.middleware.CORSMiddleware", 34 | # "geye.system.middleware.VueMiddleware", 35 | ] 36 | 37 | ROOT_URLCONF = 'geye.urls' 38 | WSGI_APPLICATION = 'geye.wsgi.application' 39 | 40 | 41 | TEMPLATES = [ 42 | { 43 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 44 | 'DIRS': [BASE_DIR / 'templates'], 45 | 'APP_DIRS': True, 46 | 'OPTIONS': { 47 | 'context_processors': [ 48 | 'django.template.context_processors.debug', 49 | 'django.template.context_processors.request', 50 | ], 51 | }, 52 | }, 53 | ] 54 | 55 | LANGUAGE_CODE = 'en-us' 56 | TIME_ZONE = 'Asia/Shanghai' 57 | USE_I18N = True 58 | USE_L10N = True 59 | USE_TZ = False 60 | 61 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' 62 | 63 | # STATIC_URL = '/public/' 64 | # STATICFILES_DIRS = [ 65 | # BASE_DIR / "templates", 66 | # ] 67 | 68 | CSRF_COOKIE_SAMESITE = None 69 | -------------------------------------------------------------------------------- /geye/utils/validator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.utils.validator 6 | ~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 一些简单的通用验证器 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | 16 | import json 17 | from typing import List 18 | 19 | from django.http import HttpRequest 20 | 21 | 22 | class RequestValidatorResult: 23 | def __init__(self): 24 | self.has_error: bool = True 25 | self.error_message: str = "" 26 | self.params: dict = "" 27 | 28 | 29 | class RequestValidator: 30 | @staticmethod 31 | def check_params( 32 | request: HttpRequest, 33 | check_params: List[str], 34 | method="POST_JSON", 35 | check_empty=False) -> RequestValidatorResult: 36 | # rv = {"has_error": True, "error_message": "", "params": None} 37 | rv = RequestValidatorResult() 38 | 39 | # 获取传递来的参数 40 | if method == "POST_JSON": 41 | request_data = json.loads(request.body) 42 | elif method == "GET_DATA": 43 | request_data = request.GET 44 | elif method == "POST_DATA": 45 | request_data = request.POST 46 | else: 47 | rv.error_message = "method有误,只能为'POST_JSON', 'GET_DATA', 'POST_DATA'中的一种." 48 | return rv 49 | 50 | # 开始检查 51 | request_keys = request_data.keys() 52 | for key_name in check_params: 53 | # 1. 检查这个参数是否发送过来了 54 | if key_name not in request_keys: 55 | rv.error_message = "'{}'参数不存在".format(key_name) 56 | return rv 57 | # 2. 检查这个变量对应的值是否为空 58 | if check_empty: 59 | if request_data.get(key_name, None) is None: 60 | rv.error_message = "'{}'参数的值为空".format(key_name) 61 | return rv 62 | 63 | # 检查完了 64 | rv.has_error = False 65 | rv.params = request_data 66 | return rv 67 | -------------------------------------------------------------------------------- /geye/web/controller/handleCenter/monitorResults.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.web.controller.handleCenter.monitorResults 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 展示监控结果 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | from typing import List 16 | 17 | from django.views import View 18 | from django.http import JsonResponse 19 | 20 | from geye.database.models import GeyeMonitorResultsModel 21 | 22 | 23 | class AllMonitorResults(View): 24 | PAGE_SIZE = 15 25 | 26 | def get(self, request): 27 | page = request.GET.get("page", 1) 28 | page = int(page) 29 | start_id = (page - 1) * self.PAGE_SIZE 30 | end_id = start_id + self.PAGE_SIZE 31 | 32 | sql = GeyeMonitorResultsModel.instance.filter(is_deleted=0) 33 | 34 | # 数据总量 35 | total_count = sql.count() 36 | 37 | # 查询所有的数据 38 | rows: List[GeyeMonitorResultsModel] = sql.order_by("-event_created_time")[start_id:end_id] 39 | return_data = [] 40 | for row in rows: 41 | event_created_time = row.event_created_time.strftime("%Y-%m-%d %H:%M:%S") 42 | return_data.append({ 43 | "monitor_rule_id": row.monitor_rule_id, 44 | "event_id": row.event_id, 45 | "event_type": row.event_type, 46 | "actor_url": row.actor_url, 47 | "actor_login": row.actor_login, 48 | "actor_display_name": row.actor_display_name, 49 | "org_url": row.org_url, 50 | "org_name": row.org_name, 51 | "repo_url": row.repo_url, 52 | "repo_name": row.repo_name, 53 | "content": row.content, 54 | "event_created_time": event_created_time, 55 | "id": row.id, 56 | }) 57 | 58 | return JsonResponse({"code": 1001, "message": "获取成功!", "data": return_data, "total_count": total_count}) 59 | -------------------------------------------------------------------------------- /geye-fe/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | 4 | Vue.use(Router); 5 | 6 | const routerConf = [ 7 | { 8 | path: "/", 9 | redirect: "/dashboard", 10 | }, 11 | { 12 | path: "/hello", 13 | component: resolve => require(["../components/HelloWorld.vue"], resolve), 14 | }, 15 | { 16 | path: "/rule/search/all", 17 | component: resolve => require(["../components/searchRule/all.vue"], resolve), 18 | name: "all-search-rule", 19 | }, 20 | { 21 | path: "/rule/search/new", 22 | component: resolve => require(["../components/searchRule/new.vue"], resolve), 23 | name: "new-search-rule", 24 | }, 25 | { 26 | path: "/rule/search/edit/:srid", 27 | component: resolve => require(["../components/searchRule/edit.vue"], resolve), 28 | name: "edit-search-rule", 29 | }, 30 | 31 | { 32 | path: "/rule/global/filter", 33 | component: resolve => require(["../components/globalFilterRule.vue"], resolve), 34 | name: "global-filter-rule", 35 | }, 36 | 37 | { 38 | path: "/handleCenter/search", 39 | component: resolve => require(["@/components/handleCenter/SearchCenter.vue"], resolve), 40 | name: "handle-center-search", 41 | }, 42 | 43 | { 44 | path: "/token", 45 | component: resolve => require(["@/components/token/token.vue"], resolve), 46 | name: "token", 47 | }, 48 | 49 | { 50 | path: "/leaks", 51 | component: resolve => require(["@/components/leaks.vue"], resolve), 52 | name: "leaks", 53 | }, 54 | 55 | // monitor 部分的路由 56 | { 57 | path: "/monitor/rules", name: "all-monitor-rules", 58 | component: resolve => require(["@/components/monitor/all.vue"], resolve), 59 | }, 60 | 61 | { 62 | path: "/handleCenter/monitor", name: "monitor-results", 63 | component: resolve => require(["@/components/handleCenter/MonitorCenter.vue"], resolve) 64 | }, 65 | 66 | { 67 | path: "/*", 68 | component: resolve => require(["../components/404.vue"], resolve), 69 | } 70 | ]; 71 | 72 | const router = new Router({ 73 | mode: "history", 74 | routes: routerConf, 75 | }); 76 | 77 | export default router; 78 | -------------------------------------------------------------------------------- /geye/database/models/monitorResults.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.database.models.monitorResults 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 存储重点监控的结果 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | 16 | from django.db import models 17 | 18 | from .base import GeyeBaseModel 19 | 20 | 21 | class MonitorResultsManager(models.Manager): 22 | def is_exist_by_event_id(self, event_id): 23 | return self.filter(is_deleted=0, event_id=event_id).first() 24 | 25 | 26 | class GeyeMonitorResultsModel(GeyeBaseModel): 27 | """ 28 | event_id: GitHub事件的唯一ID 29 | event_type: GitHub的类型 30 | 31 | actor_url: 事件的actor,对应用户的个人页面的URL 32 | actor_login: actor的登录名 33 | actor_display_name: actor的实际显示名称 34 | 35 | # org不一定存在的,如果没有,这两个字段全部留空 36 | org_url: 产生事件的org,为对应org的页面URL 37 | org_name: 产生事件的org的名称 38 | 39 | repo_url: 产生事件的repo,为对应repo的页面URL 40 | repo_name: 产生事件的repo名称 41 | 42 | content: 事件的内容,由每个事件的parser生成,格式不固定,但是均为可读字符串 43 | monitor_rule_id: 由哪个监控规则捕捉到的 44 | """ 45 | 46 | class Meta: 47 | db_table = "geye_monitor_results" 48 | 49 | monitor_rule_id = models.BigIntegerField(default=0) 50 | event_id = models.BigIntegerField(default=0) 51 | event_type = models.CharField(default="", max_length=128) 52 | 53 | actor_url = models.CharField(default="", max_length=512) 54 | actor_login = models.CharField(default="", max_length=128) 55 | actor_display_name = models.CharField(default="", max_length=128) 56 | 57 | org_url = models.CharField(default="", max_length=512) 58 | org_name = models.CharField(default="", max_length=128) 59 | 60 | repo_url = models.CharField(default="", max_length=512) 61 | repo_name = models.CharField(default="", max_length=128) 62 | 63 | content = models.TextField() 64 | 65 | event_created_time = models.DateTimeField(auto_now_add=True) 66 | 67 | objects = models.Manager() 68 | instance = MonitorResultsManager() 69 | -------------------------------------------------------------------------------- /geye/system/management/commands/run.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.system.management.commands.run 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 处理程序的启动参数,启动整个Application 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | from django.core.management import BaseCommand, CommandError 16 | 17 | from geye.application import GeyeApplication 18 | from geye.core import data as gdata 19 | 20 | 21 | class Command(BaseCommand): 22 | help = "Start the GEYE application." 23 | available_opts = ["server", "agent", "single"] 24 | 25 | def add_arguments(self, parser): 26 | parser.add_argument("--single", action="store_const", const="single", dest="run_mode", 27 | help="Run GEYE as single app. (Default)") 28 | parser.add_argument("--server", action="store_const", const="server", dest="run_mode", 29 | help="Run GEYE as server.") 30 | parser.add_argument("--agent", action="store_const", const="agent", dest="run_mode", help="Run GEYE as agent.") 31 | 32 | def handle(self, *args, **options): 33 | self.stdout.write(self.style.SUCCESS("Starting GEYE application.")) 34 | 35 | # check run_mode params 36 | run_mode = options.get("run_mode") 37 | if run_mode not in self.available_opts: 38 | raise CommandError("错误的启动参数,只能为: '--single', '--server', '--agent' 其中之一.") 39 | 40 | try: 41 | gdata.application = GeyeApplication(run_mode) 42 | gdata.application.start() 43 | except Exception as e: 44 | self.stdout.write("Error while starting application. {}".format(e)) 45 | import sys 46 | import traceback 47 | 48 | # exc_type, exc_value, exc_tb = sys.exc_info() 49 | # tbe = traceback.TracebackException(exc_type, exc_value, exc_tb) 50 | tbe = traceback.TracebackException(*sys.exc_info()) 51 | full_err = ''.join(tbe.format()) 52 | self.stdout.write("Full error below:\n {}".format(full_err)) 53 | -------------------------------------------------------------------------------- /geye-fe/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 41 | 42 | 43 | 59 | -------------------------------------------------------------------------------- /geye/core/engine/yuque/refresh.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | YuqueRefreshEngine 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | $END$ 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017-2021 lightless. All rights reserved 14 | """ 15 | import datetime 16 | import queue 17 | from typing import Iterable 18 | 19 | from geye.core.engine.base import SingleThreadEngine 20 | from geye.database.models.yuque.rules import GeyeYuqueSearchRuleModel 21 | from geye.utils.datatype import PriorityTask 22 | from geye.utils.logger import LoggerFactory 23 | 24 | 25 | class YuqueRefreshEngine(SingleThreadEngine): 26 | """ 27 | 定时产生语雀的监控任务 28 | """ 29 | 30 | logger = LoggerFactory.get_logger(__name__) 31 | 32 | def __init__(self, app_ctx, name="YuqueRefresh"): 33 | super(YuqueRefreshEngine, self).__init__(app_ctx, name) 34 | 35 | self._task_queue = self.app_ctx.MessageQueues.YUQUE_TASK_QUEUE 36 | 37 | def _worker(self): 38 | self.logger.info(f"{self.name} start!") 39 | 40 | while self.is_running(): 41 | self.logger.debug("start build yuque search task.") 42 | 43 | rows: Iterable[GeyeYuqueSearchRuleModel] = GeyeYuqueSearchRuleModel.instance.all_enable_rules() 44 | for row in rows: 45 | interval = row.interval 46 | last_refresh_time = row.last_refresh_time 47 | 48 | # 判断是否存在需要生成任务的关键字 49 | if last_refresh_time + datetime.timedelta(minutes=interval) > datetime.datetime.now(): 50 | continue 51 | 52 | # 生成搜索任务 53 | task = PriorityTask(row.priority, { 54 | "rule_id": row.id, 55 | "rule_content": row.rule, 56 | }) 57 | 58 | self.logger.debug(f"Create yuque search task: {task}") 59 | 60 | # 添加到任务队列 61 | while self.is_running(): 62 | try: 63 | self._task_queue.put_nowait(task) 64 | break 65 | except queue.Full: 66 | self.ev.wait(3) 67 | continue 68 | 69 | self.ev.wait(30) 70 | 71 | self.logger.info(f"{self.name} stop!") 72 | -------------------------------------------------------------------------------- /geye/core/engine/yuque/save.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | save.py 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | $END$ 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017-2021 lightless. All rights reserved 14 | """ 15 | import queue 16 | 17 | from geye.core.engine.base import SingleThreadEngine 18 | from geye.database.models.yuque.leaks import GeyeYuqueLeaksModel 19 | from geye.utils.log import logger 20 | 21 | 22 | class YuqueSaveEngine(SingleThreadEngine): 23 | 24 | def __init__(self, app_ctx, name): 25 | super(YuqueSaveEngine, self).__init__(app_ctx, name) 26 | 27 | self.save_queue = self.app_ctx.MessageQueues.YUQUE_SAVE_QUEUE 28 | 29 | def _get_task(self): 30 | while self.is_running(): 31 | try: 32 | _task = self.save_queue.get_nowait() 33 | return _task.priority, _task.data 34 | except queue.Empty: 35 | self.ev.wait(1) 36 | continue 37 | 38 | def _worker(self): 39 | logger.debug("{} start.".format(self.name)) 40 | while self.is_running(): 41 | _, task = self._get_task() 42 | if not task: 43 | continue 44 | 45 | rule_id = task.get("rule_id") 46 | result_list = task.get("results") 47 | 48 | for result in result_list: 49 | leak = GeyeYuqueLeaksModel() 50 | leak.title = result.get("title") 51 | leak.go_url = result.get("url") 52 | leak.url = result.get("raw_url") 53 | leak.book_name = result.get("book_name") 54 | leak.group_name = result.get("group_name") 55 | leak.abstract = result.get("abstract") 56 | leak.search_rule_obj = result.get("") 57 | leak.search_rule_id = rule_id 58 | leak.status = 1 59 | leak.content_updated_at = task.get("content_updated_at") 60 | leak.first_published_at = task.get("first_published_at") 61 | leak.paper_created_at = task.get("created_at") 62 | leak.paper_updated_at = task.get("updated_at") 63 | leak.save() 64 | logger.debug("Save yuque leak <<{}>>".format(result.get("title"))) 65 | 66 | logger.debug("{} end.".format(self.name)) 67 | -------------------------------------------------------------------------------- /geye-fe/src/components/handleCenter/SearchCenter.vue: -------------------------------------------------------------------------------- 1 | 14 | 76 | 77 | 80 | -------------------------------------------------------------------------------- /geye/settings/settings_example.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | settings_dev.py 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | $END$ 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017-2021 lightless. All rights reserved 14 | """ 15 | import os 16 | 17 | env = lambda env_name, default_value: \ 18 | os.environ.get(env_name) if os.environ.get(env_name) is not None else default_value 19 | 20 | DEBUG = True 21 | SECRET_KEY = "This_is_bad_key" 22 | 23 | # LOG信息配置,其中LOG_PATH为log存放的位置,基于BASE_DIR(项目当前路径)的相对路径 24 | LOG_TO_FILE = True 25 | LOG_FILENAME = "geye.log" 26 | LOG_PATH = "./logs/" 27 | 28 | # 允许访问的来源HOST 29 | ALLOWED_HOSTS = [ 30 | "127.0.0.1", 31 | "localhost", 32 | ] 33 | ALLOWED_CORS = [ 34 | "localhost", 35 | "127.0.0.1", 36 | ] 37 | 38 | # 数据库的相关信息默认会从环境变量中获取 39 | # 数据库名称:DB_NAME,例如:geye 40 | # 数据库用户名:DB_USER,例如:root 41 | # 数据库密码:DB_PASSWORD,例如:123456 42 | # 数据库主机:DB_HOST,例如 127.0.0.1 43 | # 数据库端口:DB_PORT,例如 5432 44 | DATABASES = { 45 | 'default': { 46 | 'ENGINE': 'django.db.backends.postgresql_psycopg2', 47 | 'NAME': env("DB_NAME", "GEYE"), 48 | 'USER': env("DB_USER", "GEYE"), 49 | 'PASSWORD': env("DB_PASSWORD", "GEYE"), 50 | 'HOST': env("DB_HOST", "localhost"), 51 | 'PORT': env("DB_PORT", "5432"), 52 | } 53 | } 54 | 55 | ########## 56 | # Queue settings 57 | ########## 58 | # Search任务队列大小 59 | SEARCH_TASK_QUEUE_SIZE = 1024 60 | FILTER_TASK_QUEUE_SIZE = 1024 61 | SAVE_TASK_QUEUE_SIZE = 1024 62 | MONITOR_TASK_QUEUE_SIZE = 1024 63 | MONITOR_SAVE_QUEUE_SIZE = 1024 64 | 65 | ########## 66 | # Refresh Engine 67 | ########## 68 | # 每隔多久检查一次search rule是否需要爬取了 69 | # 默认每隔60秒检查一次每个search rule是否需要爬取了 70 | REFRESH_INTERVAL = 60 71 | 72 | ########## 73 | # Search Engine 74 | ########## 75 | # 设置在爬取的时候是否使用代理 76 | # 如果需要代理,就在下面配置,配置多个代理的情况下 77 | # 每次会随机获取一个代理使用 78 | # socks5h 表示在socks服务端进行DNS解析,在国内环境部署时强烈推荐使用 socks5h 协议! 79 | USE_SEARCH_PROXY = False 80 | SEARCH_PROXIES = [ 81 | { 82 | "http": "socks5h://user:pass@host:port", 83 | "https": "socks5h://user:pass@host:port" 84 | } 85 | ] 86 | # 正则引擎的设置,目前支持的为: 87 | # "inner" - python原生正则引擎,效率较低 88 | # "grep" - linux中的grep命令,效率高,但是windows系统要提前安装才可使用 89 | REGEX_ENGINE = "inner" 90 | 91 | ########## 92 | # Github API 相关设置 93 | ########## 94 | GITHUB_API_SEARCH_URL = "https://api.github.com/search/code" 95 | # 搜索多少页 96 | SEARCH_PAGE_SIZE = 5 97 | # 每页的数量 98 | EACH_PAGE_ITEM_SIZE = 100 99 | -------------------------------------------------------------------------------- /geye/core/engine/monitor/monitorRefresh.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.core.engine.monitor.monitorRefresh 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 定时产生刷新任务,监控时间粒度从规则配置中获取 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017-2018 lightless. All rights reserved 14 | """ 15 | import datetime 16 | from typing import List 17 | 18 | import queue 19 | 20 | from geye.core.engine.base import SingleThreadEngine 21 | from geye.utils.datatype import PriorityTask 22 | from geye.utils.log import logger 23 | from geye.database.models import GeyeMonitorRules 24 | 25 | 26 | class MonitorRefreshEngine(SingleThreadEngine): 27 | 28 | def __init__(self, app_ctx, name=None): 29 | super(MonitorRefreshEngine, self).__init__(app_ctx, name) 30 | 31 | self._monitor_task_queue = self.app_ctx.MessageQueues.MONITOR_TASK_QUEUE 32 | 33 | def __running(self): 34 | return self.status == self.EngineStatus.RUNNING 35 | 36 | def _worker(self): 37 | logger.info("{name} start!".format(name=self.name)) 38 | 39 | while self.__running(): 40 | logger.debug("start build monitor task.") 41 | 42 | rows: List[GeyeMonitorRules] = GeyeMonitorRules.instance.get_all() 43 | current_time = datetime.datetime.now() 44 | 45 | for _row in rows: 46 | interval = _row.interval 47 | if _row.last_fetch_time + datetime.timedelta(minutes=interval) < current_time: 48 | task = PriorityTask(_row.priority, { 49 | "task_type": _row.task_type, 50 | "event_type": _row.event_type, 51 | "rule_content": _row.rule_content, 52 | "rule_id": _row.id, 53 | }) 54 | logger.debug("Create monitor task: {task}".format(task=task)) 55 | while self.__running(): 56 | try: 57 | self._monitor_task_queue.put_nowait(task) 58 | break 59 | except queue.Full: 60 | self.ev.wait(3) 61 | continue 62 | 63 | # 更新rule的最后刷新时间 64 | _row.last_fetch_time = current_time 65 | _row.save() 66 | 67 | self.ev.wait(30) 68 | 69 | logger.info("{name} stop!".format(name=self.name)) 70 | -------------------------------------------------------------------------------- /geye/core/engine/refresh.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.core.engine.refresh 6 | ~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 定时产生需要监控的任务 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | import datetime 16 | import queue 17 | import time 18 | 19 | from django.conf import settings 20 | 21 | from .base import SingleThreadEngine 22 | from geye.utils.log import logger 23 | from geye.database.models import GeyeSearchRuleModel 24 | from geye.utils.datatype import PriorityTask 25 | 26 | 27 | class RefreshEngine(SingleThreadEngine): 28 | 29 | def __init__(self, app_ctx, name=None): 30 | super(RefreshEngine, self).__init__(app_ctx, name) 31 | 32 | def _worker(self): 33 | 34 | logger.info("RefreshEngine start!") 35 | 36 | refresh_task_queue = self.app_ctx.MessageQueues.SEARCH_TASK_QUEUE 37 | 38 | while self.status == self.EngineStatus.RUNNING: 39 | logger.debug("start build search task.") 40 | rows = GeyeSearchRuleModel.objects.filter(is_deleted=0, status=1).all() 41 | current_time = datetime.datetime.now() 42 | 43 | for row in rows: 44 | delay = int(row.delay) 45 | if row.last_refresh_time + datetime.timedelta(minutes=delay) < current_time: 46 | # 该刷新了,添加到任务队列中去 47 | # 添加一个字典,如果后续改成分布式,需要改成JSON字符串 48 | # Task格式: 49 | # tuple(priority, _task) 50 | 51 | # build task 52 | _data = { 53 | "search_rule_id": row.id, 54 | "search_rule_name": row.name, 55 | "search_rule_content": row.rule, 56 | } 57 | # task = (row.priority, _data) 58 | task = PriorityTask(row.priority, _data) 59 | logger.debug("task: {}".format(task)) 60 | while True: 61 | try: 62 | refresh_task_queue.put_nowait(task) 63 | break 64 | except queue.Full: 65 | logger.warning("SearchTask队列已满,等待3秒后重试") 66 | self.ev.wait(3) 67 | continue 68 | 69 | # 更新任务的最后刷新时间 70 | row.last_refresh_time = current_time 71 | row.save() 72 | 73 | self.ev.wait(settings.REFRESH_INTERVAL) 74 | 75 | logger.info("RefreshEngine end!") 76 | -------------------------------------------------------------------------------- /geye/database/models/leaks.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.database.models.leaks 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 存储抓取到的泄露内容 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | from django.db import models 16 | 17 | from geye.database.models.base import GeyeBaseModel 18 | 19 | 20 | class LeaksStatusConstant: 21 | TO_BE_CONFIRMED = 1 22 | CONFIRM = 2 23 | IGNORE = 3 24 | 25 | 26 | class LeaksManager(models.Manager): 27 | def is_exist(self, sha): 28 | """ 29 | 根据哈希判断某条记录是否存在 30 | :param sha: 31 | :return: 32 | """ 33 | if self.filter(is_deleted=0, sha=sha).first(): 34 | return True 35 | else: 36 | return False 37 | 38 | def is_exist_by_pk(self, pk): 39 | return True if self.filter(is_deleted=0, pk=pk).first() else False 40 | 41 | def fake_delete(self, pk): 42 | """ 43 | 根据 id 删除一条leak记录 44 | :param pk: 45 | :return: 46 | """ 47 | return self.filter(is_deleted=0, pk=pk).update(is_deleted=1) 48 | 49 | 50 | class GeyeLeaksModel(GeyeBaseModel): 51 | """ 52 | 53 | repo name 54 | 仓库的名称 55 | author 56 | 仓库作者 57 | path 58 | 完整的文件路径,带文件名的 59 | filename 60 | 文件名 61 | sha: 62 | sha256 hash 63 | full_code_url 64 | 完整代码路径 raw.github.com/xx 65 | url: 66 | github上的url地址 67 | code 68 | 命中规则的代码段 69 | search rule id 70 | SRID 命中的search规则ID 71 | filter rule id 72 | FRID 命中的filter规则ID,如果没有命中任何filter rule,则为0 73 | status 74 | 这个信息当前的状态,1-待处理,2-已确认是泄露,3-误报 75 | pushed 76 | 预留字段,是否已经推送到其他系统,1-已推送到其他系统,0-未推送到其他系统 77 | 78 | """ 79 | 80 | class Meta: 81 | db_table = "geye_leaks" 82 | 83 | repo_name = models.CharField(max_length=256, default="", db_index=True) 84 | author = models.CharField(max_length=256, default="") 85 | path = models.CharField(max_length=1024, default="") 86 | filename = models.CharField(max_length=256, default="") 87 | sha = models.CharField(max_length=40, default="", db_index=True) 88 | full_code_url = models.TextField() 89 | url = models.TextField() 90 | code = models.TextField() 91 | srid = models.BigIntegerField(default=0) 92 | frid = models.BigIntegerField(default=0) 93 | status = models.PositiveSmallIntegerField(default=1) 94 | pushed = models.BooleanField(default=False) 95 | 96 | objects = models.Manager() 97 | instance = LeaksManager() 98 | -------------------------------------------------------------------------------- /geye/core/engine/base/thread.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.core.engine.base.thread 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 基于线程的engine基类 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | 16 | # from __future__ import annotations 17 | 18 | import multiprocessing 19 | import threading 20 | import typing 21 | 22 | import abc 23 | 24 | from .base import CommonBaseEngine 25 | 26 | if typing.TYPE_CHECKING: 27 | from geye.application import GeyeApplication 28 | 29 | 30 | class SingleThreadEngine(CommonBaseEngine): 31 | """ 32 | 基于单线程的引擎模块 33 | """ 34 | 35 | def __init__(self, app_ctx: "GeyeApplication", name=None): 36 | super(SingleThreadEngine, self).__init__() 37 | self.name = name if name else "SingleThreadEngine" 38 | self.app_ctx: "GeyeApplication" = app_ctx 39 | 40 | def start(self): 41 | self.status = self.EngineStatus.RUNNING 42 | self.thread: threading.Thread = threading.Thread(target=self._worker, name=self.name) 43 | self.thread.start() 44 | 45 | def stop(self, force=True): 46 | self.status = self.EngineStatus.STOP 47 | self.ev.set() 48 | 49 | def is_alive(self): 50 | return self.thread.is_alive() 51 | 52 | @abc.abstractmethod 53 | def _worker(self): 54 | pass 55 | 56 | 57 | class MultiThreadEngine(CommonBaseEngine): 58 | """ 59 | 基于多线程的基础引擎 60 | """ 61 | 62 | def __init__(self, app_ctx: "GeyeApplication", name=None, pool_size=None): 63 | super(MultiThreadEngine, self).__init__() 64 | self.name = name if name else "MultiThreadEngine" 65 | self.app_ctx: "GeyeApplication" = app_ctx 66 | self.pool_size = pool_size if pool_size else multiprocessing.cpu_count() * 2 + 1 67 | 68 | def start(self): 69 | self.status = self.EngineStatus.RUNNING 70 | self.thread_pool: typing.List[threading.Thread] = \ 71 | [threading.Thread( 72 | target=self._worker, name="{}-{}".format(self.name, idx) 73 | ) for idx in range(self.pool_size)] 74 | _ = [t.start() for t in self.thread_pool] 75 | 76 | def stop(self, force=True): 77 | if not force: 78 | while not self.app_ctx.MessageQueues.SEARCH_TASK_QUEUE.empty(): 79 | self.ev.wait(1) 80 | continue 81 | self.status = self.EngineStatus.STOP 82 | self.ev.set() 83 | 84 | def is_alive(self): 85 | return any([t.is_alive() for t in self.thread_pool]) 86 | 87 | @abc.abstractmethod 88 | def _worker(self): 89 | pass 90 | -------------------------------------------------------------------------------- /geye/core/engine/save.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.core.engine.save 6 | ~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 将任务存储的PostgreSQL中 9 | 如果太慢了,考虑改成线程池 10 | 11 | :author: lightless 12 | :homepage: None 13 | :license: GPL-3.0, see LICENSE for more details. 14 | :copyright: Copyright (c) 2017 lightless. All rights reserved 15 | """ 16 | import queue 17 | 18 | from django.db import Error as DBError 19 | 20 | from geye.database.models import GeyeLeaksModel 21 | from geye.utils.datatype import PriorityTask 22 | from geye.utils.log import logger 23 | from .base import SingleThreadEngine 24 | 25 | 26 | class SaveEngine(SingleThreadEngine): 27 | def __init__(self, app_ctx, name): 28 | super(SaveEngine, self).__init__(app_ctx, name) 29 | 30 | # 获取队列信息 31 | self.save_queue = self.app_ctx.MessageQueues.SAVE_TASK_QUEUE 32 | 33 | def get_task_from_queue(self): 34 | while self.status == self.EngineStatus.RUNNING: 35 | try: 36 | task: PriorityTask = self.save_queue.get_nowait() 37 | return task.priority, task.data 38 | except queue.Empty: 39 | self.ev.wait(1) 40 | continue 41 | else: 42 | return None, None 43 | 44 | def _worker(self): 45 | logger.info("{} start!".format(self.name)) 46 | 47 | while self.status == self.EngineStatus.RUNNING: 48 | task_priority, task = self.get_task_from_queue() 49 | if not task_priority or not task: 50 | continue 51 | 52 | filter_task = task["filter_task"] 53 | 54 | if GeyeLeaksModel.instance.is_exist(filter_task["sha"]): 55 | # 已经有这条记录了,continue 56 | continue 57 | 58 | # 存储数据 59 | try: 60 | GeyeLeaksModel.objects.create( 61 | repo_name=filter_task["repo_name"], 62 | author=filter_task["author"], 63 | path=filter_task["path"], 64 | filename=filter_task["filename"], 65 | sha=filter_task["sha"], 66 | full_code_url=filter_task["full_code_url"], 67 | url=filter_task["url"], 68 | code=task["code"], 69 | srid=filter_task["srid"], 70 | frid=task["frid"], 71 | status=task["status"], 72 | pushed=task["pushed"], 73 | ) 74 | except DBError as e: 75 | logger.error("SaveEngine error: {}".format(e)) 76 | # todo: send error message 77 | continue 78 | 79 | # post-action 80 | # todo: send notification 81 | # todo: clone repo 82 | 83 | logger.info("{} end!".format(self.name)) 84 | -------------------------------------------------------------------------------- /geye/web/controller/base.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | base 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | $END$ 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017-2021 lightless. All rights reserved 14 | """ 15 | import json 16 | from typing import Iterable 17 | 18 | from django.http import HttpRequest 19 | from django.views import View 20 | 21 | from geye.constant import ResponseCode 22 | 23 | 24 | class GeyeResponse(object): 25 | """ 26 | Geye返回的数据结构 27 | """ 28 | 29 | def __init__(self): 30 | self.code = -1 31 | self.message = "" 32 | self.data = None 33 | 34 | def to_dict(self): 35 | return { 36 | "code": self.code, 37 | "message": self.message, 38 | "data": self.data 39 | } 40 | 41 | 42 | class RequestData: 43 | """ 44 | Geye 验证请求数据的结果 45 | """ 46 | 47 | def __init__(self): 48 | self.has_error: bool = True 49 | self.error_message: str = "" 50 | self.params: dict = {} 51 | 52 | 53 | class RequestValidator: 54 | 55 | # noinspection DuplicatedCode 56 | @staticmethod 57 | def check_params(request: HttpRequest, check_params: Iterable[str], method="POST_JSON", 58 | check_empty=False) -> RequestData: 59 | 60 | rv = RequestData() 61 | 62 | # 获取传递来的参数 63 | if method == "POST_JSON": 64 | request_data = json.loads(request.body) 65 | elif method == "GET_DATA": 66 | request_data = request.GET 67 | elif method == "POST_DATA": 68 | request_data = request.POST 69 | else: 70 | rv.error_message = "method有误,只能为'POST_JSON', 'GET_DATA', 'POST_DATA'中的一种." 71 | return rv 72 | 73 | # 开始检查 74 | request_keys = request_data.keys() 75 | for key_name in check_params: 76 | # 1. 检查这个参数是否发送过来了 77 | if key_name not in request_keys: 78 | rv.error_message = "'{}'参数不存在".format(key_name) 79 | return rv 80 | # 2. 检查这个变量对应的值是否为空 81 | if check_empty: 82 | if request_data.get(key_name, None) is None: 83 | rv.error_message = "'{}'参数的值为空".format(key_name) 84 | return rv 85 | 86 | # 检查完了 87 | rv.has_error = False 88 | rv.params = request_data 89 | return rv 90 | 91 | 92 | class BaseView(View): 93 | 94 | @staticmethod 95 | def quick_error(error_type: ResponseCode, message: str): 96 | resp = GeyeResponse() 97 | resp.data = None 98 | resp.code = error_type 99 | resp.message = message 100 | return resp 101 | -------------------------------------------------------------------------------- /geye/database/migrations/0002_auto_20181223_2137.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.2 on 2018-12-23 21:37 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('database', '0001_initial'), 10 | ] 11 | 12 | operations = [ 13 | migrations.CreateModel( 14 | name='GeyeMonitorResultsModel', 15 | fields=[ 16 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 17 | ('created_time', models.DateTimeField(auto_now=True)), 18 | ('updated_time', models.DateTimeField(auto_now_add=True)), 19 | ('is_deleted', models.BooleanField(default=False)), 20 | ('monitor_rule_id', models.BigIntegerField(default=0)), 21 | ('event_id', models.BigIntegerField(default=0)), 22 | ('event_type', models.CharField(default='', max_length=128)), 23 | ('actor_url', models.CharField(default='', max_length=512)), 24 | ('actor_login', models.CharField(default='', max_length=128)), 25 | ('actor_display_name', models.CharField(default='', max_length=128)), 26 | ('org_url', models.CharField(default='', max_length=512)), 27 | ('org_name', models.CharField(default='', max_length=128)), 28 | ('repo_url', models.CharField(default='', max_length=512)), 29 | ('repo_name', models.CharField(default='', max_length=128)), 30 | ('content', models.TextField()), 31 | ('event_created_time', models.DateTimeField(auto_now_add=True)), 32 | ], 33 | options={ 34 | 'db_table': 'geye_monitor_results', 35 | }, 36 | ), 37 | migrations.CreateModel( 38 | name='GeyeMonitorRules', 39 | fields=[ 40 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 41 | ('created_time', models.DateTimeField(auto_now=True)), 42 | ('updated_time', models.DateTimeField(auto_now_add=True)), 43 | ('is_deleted', models.BooleanField(default=False)), 44 | ('task_type', models.CharField(default='', max_length=32)), 45 | ('event_type', models.CharField(default='', max_length=128)), 46 | ('rule_content', models.TextField()), 47 | ('status', models.BooleanField(default=True)), 48 | ('interval', models.IntegerField(default=5)), 49 | ('last_fetch_time', models.DateTimeField(auto_now_add=True)), 50 | ('priority', models.IntegerField(default=5)), 51 | ], 52 | options={ 53 | 'db_table': 'geye_monitor_rules', 54 | }, 55 | ), 56 | migrations.AlterModelManagers( 57 | name='geyeleaksmodel', 58 | managers=[ 59 | ], 60 | ), 61 | ] 62 | -------------------------------------------------------------------------------- /geye-fe/src/assets/css/main.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | html, 7 | body, 8 | #app, 9 | .wrapper { 10 | width: 100%; 11 | height: 100%; 12 | overflow: hidden; 13 | } 14 | 15 | body { 16 | font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif; 17 | } 18 | 19 | a { 20 | text-decoration: none 21 | } 22 | 23 | 24 | .content-box { 25 | position: absolute; 26 | left: 200px; 27 | right: 0; 28 | top: 70px; 29 | bottom: 0; 30 | padding-bottom: 10px; 31 | -webkit-transition: left .3s ease-in-out; 32 | transition: left .3s ease-in-out; 33 | background: #f0f0f0; 34 | } 35 | 36 | .content { 37 | width: auto; 38 | height: 100%; 39 | padding: 10px; 40 | box-sizing: border-box; 41 | overflow-y: auto; 42 | } 43 | 44 | .content-collapse { 45 | left: 65px; 46 | } 47 | 48 | .container { 49 | padding: 30px; 50 | background: #fff; 51 | border: 1px solid #ddd; 52 | border-radius: 5px; 53 | } 54 | 55 | .crumbs { 56 | margin: 10px 0; 57 | } 58 | 59 | .pagination { 60 | margin: 20px 0; 61 | text-align: right; 62 | } 63 | 64 | .plugins-tips { 65 | padding: 20px 10px; 66 | margin-bottom: 20px; 67 | } 68 | 69 | .el-button+.el-tooltip { 70 | margin-left: 10px; 71 | } 72 | 73 | .el-table tr:hover { 74 | background: #f6faff; 75 | } 76 | 77 | .mgb20 { 78 | margin-bottom: 20px; 79 | } 80 | 81 | .move-enter-active, 82 | .move-leave-active { 83 | transition: opacity .5s; 84 | } 85 | 86 | .move-enter, 87 | .move-leave { 88 | opacity: 0; 89 | } 90 | 91 | /*BaseForm*/ 92 | 93 | .form-box { 94 | width: 600px; 95 | } 96 | 97 | .form-box .line { 98 | text-align: center; 99 | } 100 | 101 | .el-time-panel__content::after, 102 | .el-time-panel__content::before { 103 | margin-top: -7px; 104 | } 105 | 106 | .el-time-spinner__wrapper .el-scrollbar__wrap:not(.el-scrollbar__wrap--hidden-default) { 107 | padding-bottom: 0; 108 | } 109 | 110 | /*Upload*/ 111 | 112 | .pure-button { 113 | width: 150px; 114 | height: 40px; 115 | line-height: 40px; 116 | text-align: center; 117 | color: #fff; 118 | border-radius: 3px; 119 | } 120 | 121 | .g-core-image-corp-container .info-aside { 122 | height: 45px; 123 | } 124 | 125 | .el-upload--text { 126 | background-color: #fff; 127 | border: 1px dashed #d9d9d9; 128 | border-radius: 6px; 129 | box-sizing: border-box; 130 | width: 360px; 131 | height: 180px; 132 | text-align: center; 133 | cursor: pointer; 134 | position: relative; 135 | overflow: hidden; 136 | } 137 | 138 | .el-upload--text .el-icon-upload { 139 | font-size: 67px; 140 | color: #97a8be; 141 | margin: 40px 0 16px; 142 | line-height: 50px; 143 | } 144 | 145 | .el-upload--text { 146 | color: #97a8be; 147 | font-size: 14px; 148 | text-align: center; 149 | } 150 | 151 | .el-upload--text em { 152 | font-style: normal; 153 | } 154 | 155 | /*VueEditor*/ 156 | 157 | .ql-container { 158 | min-height: 400px; 159 | } 160 | 161 | .ql-snow .ql-tooltip { 162 | transform: translateX(117.5px) translateY(10px) !important; 163 | } 164 | 165 | .editor-btn { 166 | margin-top: 20px; 167 | } 168 | 169 | /*markdown*/ 170 | 171 | .v-note-wrapper .v-note-panel { 172 | min-height: 500px; 173 | } 174 | -------------------------------------------------------------------------------- /geye/web/urls.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.web.urls 6 | ~~~~~~~~~~~~~ 7 | 8 | 9 | :author: lightless 10 | :homepage: None 11 | :license: GPL-3.0, see LICENSE for more details. 12 | :copyright: Copyright (c) 2017 lightless. All rights reserved 13 | """ 14 | 15 | from django.urls import path 16 | 17 | from geye.web.controller.leaks import leaks 18 | from .controller.rule import search, filter, globalFilter, monitor 19 | from .controller.token import token 20 | from .controller.handleCenter import searchResults, monitorResults 21 | 22 | 23 | # 总的路由 24 | # http://example.com/api/v1/rule/search/v1/all 25 | 26 | # api下的总路由 27 | urlpatterns = [ 28 | # search rule URL 29 | path("v1/rule/search/all", search.ListSearchRuleView.as_view()), 30 | path("v1/rule/search/new", search.AddSearchRuleView.as_view()), 31 | path("v1/rule/search/delete", search.DeleteSearchRuleView.as_view()), 32 | path("v1/rule/search/change_status", search.ChangeStatusSearchRuleView.as_view()), 33 | path("v1/rule/search/get_detail", search.GetDetailView.as_view()), 34 | path("v1/rule/search/update", search.UpdateSearchRuleView.as_view()), 35 | 36 | # filter rule URL 37 | path("v1/rule/filter/new", filter.AddFilterRuleView.as_view()), 38 | path("v1/rule/filter/delete", filter.DeleteFilterRuleView.as_view()), 39 | path("v1/rule/filter/detail", filter.GetFilterRuleDetailView.as_view()), 40 | path("v1/rule/filter/update", filter.UpdateFilterRuleView.as_view()), 41 | 42 | # global filter rule 43 | path("v1/rule/global/all", globalFilter.AllGlobalFilterRulesView.as_view()), 44 | path("v1/rule/global/new", globalFilter.AddGlobalFilterRuleView.as_view()), 45 | path("v1/rule/global/delete", globalFilter.DeleteGlobalFilterRuleView.as_view()), 46 | path("v1/rule/global/detail", globalFilter.GetDetailView.as_view()), 47 | path("v1/rule/global/update", globalFilter.UpdateGlobalFilterRuleView.as_view()), 48 | 49 | # Token 相关的路由 50 | path("v1/token/all", token.TokensView.as_view()), 51 | path("v1/token/new", token.AddTokenView.as_view()), 52 | path("v1/token/update", token.EditTokenView.as_view()), 53 | path("v1/token/delete", token.DeleteTokenView.as_view()), 54 | path("v1/token/change_status", token.UpdateStatus.as_view()), 55 | path("v1/token/detail", token.TokenDetailsView.as_view()), 56 | 57 | # search handle center 相关的路由 58 | path("v1/results/all", searchResults.AllSearchResults.as_view()), 59 | path("v1/results/ignore", searchResults.IgnoreSearchResult.as_view()), 60 | path("v1/results/confirm", searchResults.ConfirmSearchResult.as_view()), 61 | 62 | # leaks 相关的路由 63 | path("v1/leaks/all", leaks.AllLeaksView.as_view()), 64 | path("v1/leaks/delete", leaks.DeleteLeakView.as_view()), 65 | path("v1/leaks/change_status", leaks.ChangeStatusLeakView.as_view()), 66 | path("v1/leaks/batch_change_status", leaks.BatchChangeStatusLeakView.as_view()), 67 | 68 | # monitor rule 相关的路由 69 | path("v1/rule/monitor/new", monitor.AddMonitorRuleView.as_view()), 70 | path("v1/rule/monitor/update", monitor.UpdateMonitorRuleView.as_view()), 71 | path("v1/rule/monitor/delete", monitor.DeleteMonitorRuleView.as_view()), 72 | path("v1/rule/monitor/all", monitor.MonitorRulesView.as_view()), 73 | 74 | # monitor results router 75 | path("v1/results/monitor/all", monitorResults.AllMonitorResults.as_view()), 76 | ] 77 | -------------------------------------------------------------------------------- /geye/web/controller/handleCenter/searchResults.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.web.controller.handlerCenter.searchResults 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | handle center相关的路由 9 | 只有search结果的部分 10 | 11 | :author: lightless 12 | :homepage: None 13 | :license: GPL-3.0, see LICENSE for more details. 14 | :copyright: Copyright (c) 2017 lightless. All rights reserved 15 | """ 16 | import json 17 | 18 | from django.http import JsonResponse 19 | from django.views import View 20 | 21 | from geye.database.models.leaks import GeyeLeaksModel 22 | from geye.database.models.rules import GeyeSearchRuleModel, GeyeFilterRuleModel 23 | 24 | 25 | class AllSearchResults(View): 26 | 27 | PAGE_SIZE = 20 28 | 29 | def get(self, request): 30 | page = request.GET.get("page", 1) 31 | page = int(page) 32 | start_id = (page-1) * self.PAGE_SIZE 33 | end_id = start_id + self.PAGE_SIZE 34 | # 只返回待处理状态的 35 | rows = GeyeLeaksModel.instance.filter(is_deleted=0, status=1).order_by("-created_time")[start_id:end_id] 36 | 37 | data = [] 38 | for row in rows: 39 | search_rule_name = GeyeSearchRuleModel.instance.get_name_by_pk(row.srid) 40 | filter_rule_name = GeyeFilterRuleModel.instance.get_name_by_pk(row.frid) 41 | if not filter_rule_name: 42 | filter_rule_name = "规则已删除" 43 | data.append({ 44 | "id": row.id, 45 | "repoName": row.repo_name, 46 | "author": row.author, 47 | "path": row.path, 48 | "filename": row.filename, 49 | "sha": row.sha, 50 | "full_code_url": row.full_code_url, 51 | "url": row.url, 52 | "code": row.code, 53 | "srid": row.srid, 54 | "frid": row.frid, 55 | "status": row.status, 56 | "pushed": row.pushed, 57 | "searchRuleName": search_rule_name, 58 | "filterRuleName": filter_rule_name, 59 | "created_time": row.created_time.strftime("%Y-%m-%d %H:%M:%S"), 60 | }) 61 | 62 | return JsonResponse({"code": 1001, "message": "获取成功!", "data": data}) 63 | 64 | 65 | class IgnoreSearchResult(View): 66 | @staticmethod 67 | def post(request): 68 | leak_id = json.loads(request.body).get("id", None) 69 | if not leak_id or not GeyeLeaksModel.instance.is_exist_by_pk(leak_id): 70 | return JsonResponse({"code": 1004, "message": "leak id不存在!"}) 71 | 72 | obj = GeyeLeaksModel.instance.filter(pk=leak_id).update(status=3) 73 | if obj: 74 | return JsonResponse({"code": 1001, "message": "已设为误报!"}) 75 | else: 76 | return JsonResponse({"code": 1002, "message": "设为误报失败!"}) 77 | 78 | 79 | class ConfirmSearchResult(View): 80 | @staticmethod 81 | def post(request): 82 | leak_id = json.loads(request.body).get("id", None) 83 | if not leak_id or not GeyeLeaksModel.instance.is_exist_by_pk(leak_id): 84 | return JsonResponse({"code": 1004, "message": "leak id不存在!"}) 85 | 86 | obj = GeyeLeaksModel.instance.filter(pk=leak_id).update(status=2) 87 | if obj: 88 | return JsonResponse({"code": 1001, "message": "已确认为泄露!"}) 89 | else: 90 | return JsonResponse({"code": 1002, "message": "设为泄露失败!"}) 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GEYE 2 | 3 | > GEYE是一款面向企业级以及白帽子的"More Fastest" Github监控工具,目的是为了在短时间内(例如15分钟内)发现Github上泄露的敏感数据。 4 | > 同时GEYE也提供了便捷的Web管理界面,您可以在Web端对监控到的信息进行快速审查,并进行打标处理。 5 | > 开箱即用!🚀🚀🚀 6 | 7 | # 0. 特性 8 | - 设计说明:https://lightless.me/archives/How-To-Designing-A-Faster-Than-Faster-GitHub-Monitoring-System.html 9 | - 开箱即用 10 | - 基于GitHub API进行信息收集,快于大部分产品 11 | - 方便的管理界面,快速打标处理 12 | - 强大的规则系统,满足各种复杂搜索、过滤规则 13 | 14 | ![searchResult](https://raw.githubusercontent.com/redstone-project/geye/master/docs/img/geye.png) 15 | ![monitorResult](https://raw.githubusercontent.com/redstone-project/geye/master/docs/img/geye-monitor-results.png) 16 | 17 | # 1. 快速开始 18 | 19 | ## 1.1 通过 docker 进行安装 20 | 21 | ### 拉取代码 22 | ```shell 23 | git clone https://github.com/lightless233/geye.git geye 24 | cd geye 25 | ``` 26 | 27 | ### 修改配置 28 | 在使用 docker 进行部署前,需要对配置文件进行修改。首先将配置文件复制一份: 29 | ```shell 30 | cp geye/settings/settings_example.py geye/settings/settings_prod.py 31 | ``` 32 | 33 | > 在 `docker-compose.yml` 文件中,有一个环境变量 `GEYE_ENV`,默认为 `prod`,表示生产环境。 34 | > 35 | > 如果此值为 prod,则配置文件需要复制为 settings_prod.py 36 | > 37 | > 如果将此值修改为 dev,则配置文件需要复制为 settings_dev.py 38 | 39 | 其中有几项设置需要进行修改: 40 | - ALLOWED_HOSTS: 41 | - 允许访问的域名或IP,填写部署后实际使用的域名或IP,例如 `geye.lightless.me`,`192.168.62.100`; 42 | - ALLOWED_CORS: 43 | - CORS 配置,通常和 ALLOWED_HOSTS 配置一样; 44 | - USE_SEARCH_PROXY 45 | - 在抓去 Github 上的数据时,是否使用代理,True 使用代理,False 不使用代理; 46 | - SEARCH_PROXIES 47 | - 如果 `USE_SEARCH_PROXY` 为 True,则该配置生效; 48 | - 目前仅支持 socks 代理,例如:`"http": "socks5://127.0.0.1:1080"`; 49 | - REGEX_ENGINE 50 | - 指定使用何种引擎进行正则匹配,默认使用 Python 内置的 `re` 库; 51 | - Linux 环境推荐使用 `grep` 引擎; 52 | 53 | 其余配置项使用默认值即可,如有需要,也可手动进行调整; 54 | 55 | ### 启动 56 | 配置修改完成后,执行以下命令即可启动: 57 | ```shell 58 | docker-compose up 59 | ``` 60 | 61 | ## 1.2 手动安装 62 | 63 | ### 部署需求 64 | - Python 3.6.0 及以上版本 65 | - Nginx 66 | - PostgreSQL (未来会支持更多数据库) 67 | 68 | ### 安装环境 69 | 这里假设您已经有了Python3.6.0及以上版本,这里我们强烈推荐您使用virtualenv或pipenv创建虚拟环境,这样可以避免各种奇怪的问题。 70 | 如果您不想使用虚拟环境管理,也可以直接安装。但是下面的安装方法会基于存在virtualenv的情况下进行说明的。 71 | 72 | ```bash 73 | $ git clone https://github.com/lightless233/geye.git geye 74 | $ cd geye 75 | # 建议使用虚拟环境,不同版本的python可能创建虚拟环境的命令有所不同,请自行调整 76 | $ virtualenv -p python3 venv 77 | $ source ./venv/bin/activate 78 | $ pip install -r requirements.txt 79 | $ pip install "requests[socks]" # 可选,如果在抓取数据时不需要使用 socks5 代理,可以不安装。 80 | $ pip install "gunicorn[tornado]" # 可选,根据 conf/gunicorn_config.py 中的 worker 类型决定。 81 | ``` 82 | 83 | ### 部署Web后端 84 | 在正式部署后端前,需要您手动复制几个内置的配置文件,并填入一些信息。 85 | 86 | ```bash 87 | # 如果用于开发测试环境,请将settings_example.py 复制为 settings_dev.py 88 | # 并同时设置对应的环境变量GEYE_ENV="dev" 89 | (venv) $ cp ./geye/settings/settings_example.py ./geye/settings/settings_prod.py 90 | (venv) $ python manage.py migrate 91 | (venv) $ export GEYE_ENV="prod" # 开发环境为 dev,如果不设置,默认为dev环境启动 92 | (venv) $ chmod +x ./tools/*.sh && ./tools/start_web.sh 93 | ``` 94 | 95 | ### 部署Web前端 96 | 部署前端除了需要修改配置文件外,还需要配置nginx反向代理,这里提供了一份默认的nginx配置文件,只需要稍加修改即可。 97 | 98 | ```bash 99 | $ cd geye-fe && npm run build && cd .. # 构建前端JS文件 100 | $ cp ./conf/geye.nginx.conf /path_to_your_nginx_conf_dir/geye.nginx.conf 101 | $ vim /path_to_your_nginx_conf_dir/geye.nginx.conf # 修改 `root /app/geye-fe/dist/;` 指向刚刚前端 build 生成的 dist 目录 102 | $ nginx -t && nginx -s reload 103 | ``` 104 | 105 | > 如果您更熟悉 caddy 等其他服务器,请自行配置。 106 | 107 | ### 启动引擎 108 | 引擎是监控 GitHub 的核心部分,目前仅支持 --single 模式启动,即`server`和`agent`一同启动,单机模式。 109 | 110 | 未来会支持单独启动 `--server` 和 `--agent` 模式,方便分布式部署,扩展应用。 111 | 112 | ```bash 113 | (venv) $ python manage.py run --single 114 | ``` 115 | -------------------------------------------------------------------------------- /geye/database/models/monitorRules.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.database.models.monitorRules 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 存储重点监控的规则部分 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | 16 | from django.db import models, transaction 17 | 18 | from .base import GeyeBaseModel 19 | 20 | 21 | class CommonConstant: 22 | @classmethod 23 | def lst(cls): 24 | obj = filter(lambda i: i[0].isupper(), cls.__mro__[0].__dict__.items()) 25 | return [x[1] for x in list(obj)] 26 | 27 | 28 | class MonitorTaskTypeConstant(CommonConstant): 29 | REPO = "repo" 30 | ORG = "org" 31 | USER = "user" 32 | 33 | 34 | class MonitorEventTypeConstant(CommonConstant): 35 | PUSH_EVENT = "PushEvent" 36 | RELEASE_EVENT = "ReleaseEvent" 37 | 38 | 39 | class MonitorRulesManager(models.Manager): 40 | def get_all(self): 41 | """ 42 | 获取所有的记录 43 | :return: 44 | """ 45 | return self.filter(is_deleted=False).all() 46 | 47 | def is_pk_exist(self, pk): 48 | """ 49 | 根据主键判断对应的记录是否存在 50 | :param pk: 51 | :return: 52 | """ 53 | return self.filter(is_deleted=False, pk=pk).first() 54 | 55 | def fake_delete_by_pk(self, pk): 56 | """ 57 | 根据主键删除一条规则 58 | :param pk: 主键ID 59 | :return: boolean 60 | """ 61 | with transaction.atomic(): 62 | obj: GeyeMonitorRules = self.select_for_update().filter(is_deleted=False, pk=pk).first() 63 | if not obj: 64 | return False 65 | else: 66 | obj.is_deleted = True 67 | obj.save() 68 | return True 69 | 70 | 71 | class GeyeMonitorRules(GeyeBaseModel): 72 | """ 73 | task_type 74 | 任务类型,监控维度:repo, org, user 75 | event_type 76 | 监控的事件类型 77 | 目前支持:PushEvent,ReleaseEvent 78 | rule_content: 79 | 监控的内容,根据task_type的不同,这里代表的含义也不同 80 | 是个JSON字符串 81 | 1. 组织监控:{"org_name": ""} 82 | 2. 仓库监控:{"owner": "", "repo_name": ""} 83 | 3. 用户监控:{"username": ""} 84 | status: 85 | 规则状态,是否开启 86 | interval: 87 | 每个仓库的监控时间间隔,单位分钟 88 | last_fetch_time: 89 | 上次fetch信息的时间 90 | priority: 91 | 优先级,1-10 92 | """ 93 | 94 | class Meta: 95 | db_table = "geye_monitor_rules" 96 | 97 | task_type = models.CharField(default="", max_length=32, db_index=True) 98 | event_type = models.CharField(default="", max_length=128) 99 | rule_content = models.TextField() 100 | status = models.BooleanField(default=True) 101 | interval = models.IntegerField(default=5) 102 | last_fetch_time = models.DateTimeField(auto_now_add=True) 103 | priority = models.IntegerField(default=5) 104 | 105 | objects = models.Manager() 106 | instance = MonitorRulesManager() 107 | 108 | def convert_to_dict(self): 109 | return { 110 | "id": self.id, 111 | "taskType": self.task_type, 112 | "eventType": self.event_type, 113 | "ruleContent": self.rule_content, 114 | "status": self.status, 115 | "interval": self.interval, 116 | "priority": self.priority, 117 | "lastFetchTime": self.last_fetch_time, 118 | } 119 | -------------------------------------------------------------------------------- /geye/database/models/token.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.database.models.token 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 存储github搜索用的token 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | 16 | from django.db import models, transaction 17 | 18 | from .base import GeyeBaseModel 19 | 20 | 21 | class TokenManager(models.Manager): 22 | def get_all_tokens(self): 23 | """ 24 | 获取所有的token 25 | :return: 26 | """ 27 | return self.filter(is_deleted=0).order_by("id").all() 28 | 29 | def is_exist(self, token_id): 30 | """ 31 | 根据id判断某个token是否存在 32 | :param token_id: 33 | :return: 34 | """ 35 | return self.filter(is_deleted=0, id=token_id).first() 36 | 37 | def fake_delete(self, token_id): 38 | """ 39 | 根据token id删除记录 40 | :param token_id: 41 | :return: 42 | """ 43 | return self.filter(is_deleted=0, id=token_id).update(is_deleted=1) 44 | 45 | def change_status(self, token_id): 46 | """ 47 | 根据id切换token的状态 48 | :param token_id: 49 | :return: 50 | """ 51 | with transaction.atomic(): 52 | obj = self.select_for_update().filter(is_deleted=0, id=token_id).first() 53 | if not obj: 54 | return None 55 | else: 56 | obj.status = not obj.status 57 | obj.save() 58 | return obj 59 | 60 | def update_token(self, params): 61 | """ 62 | 更新某条token 63 | :param params: 64 | :return: 65 | """ 66 | with transaction.atomic(): 67 | obj = self.select_for_update().filter(is_deleted=0, id=params["id"]).first() 68 | if not obj: 69 | return None 70 | else: 71 | obj.token_name = params["tokenName"] 72 | # 如果传递过来的token中有星号,那么不对token字段进行更新 73 | if "*" not in params["tokenContent"]: 74 | obj.token = params["tokenContent"] 75 | # obj.remain_limit = params["remainLimit"] 76 | obj.status = params["status"] 77 | obj.save() 78 | return obj 79 | 80 | def get_details(self, token_id): 81 | """ 82 | 根据id获取某个token的详细信息 83 | :param token_id: 84 | :return: 85 | """ 86 | obj = self.filter(is_deleted=0, id=token_id).first() 87 | if not obj: 88 | return {} 89 | else: 90 | return { 91 | "id": obj.id, 92 | "tokenName": obj.token_name, 93 | "tokenContent": obj.token, 94 | "remainLimit": obj.remain_limit, 95 | "status": obj.status, 96 | } 97 | 98 | 99 | class GeyeTokenModel(GeyeBaseModel): 100 | """ 101 | token: 102 | github access token 103 | remain_limit: 104 | 当前token的剩余可请求次数,从返回头中的X-RateLimit-Remaining获取 105 | 每次搜索的时候,选取这个值最大的,并且更新该值 106 | status: 107 | token 状态,1-启用,0-关闭 108 | """ 109 | 110 | class Meta: 111 | db_table = "geye_token" 112 | 113 | token_name = models.CharField(max_length=32, default="TokenName", null=False) 114 | token = models.CharField(max_length=64, default="", null=False) 115 | remain_limit = models.PositiveIntegerField(default=0, null=False) 116 | status = models.PositiveSmallIntegerField(default=1, null=False) 117 | 118 | objects = models.Manager() 119 | instance = TokenManager() 120 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Python template 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | .hypothesis/ 50 | .pytest_cache/ 51 | 52 | # Translations 53 | *.mo 54 | *.pot 55 | 56 | # Django stuff: 57 | *.log 58 | local_settings.py 59 | db.sqlite3 60 | 61 | # Flask stuff: 62 | instance/ 63 | .webassets-cache 64 | 65 | # Scrapy stuff: 66 | .scrapy 67 | 68 | # Sphinx documentation 69 | docs/_build/ 70 | 71 | # PyBuilder 72 | target/ 73 | 74 | # Jupyter Notebook 75 | .ipynb_checkpoints 76 | 77 | # pyenv 78 | .python-version 79 | 80 | # celery beat schedule file 81 | celerybeat-schedule 82 | 83 | # SageMath parsed files 84 | *.sage.py 85 | 86 | # Environments 87 | .env 88 | .venv 89 | env/ 90 | venv/ 91 | ENV/ 92 | env.bak/ 93 | venv.bak/ 94 | 95 | # Spyder project settings 96 | .spyderproject 97 | .spyproject 98 | 99 | # Rope project settings 100 | .ropeproject 101 | 102 | # mkdocs documentation 103 | /site 104 | 105 | # mypy 106 | .mypy_cache/ 107 | ### JetBrains template 108 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 109 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 110 | 111 | # User-specific stuff 112 | .idea/**/workspace.xml 113 | .idea/**/tasks.xml 114 | .idea/**/usage.statistics.xml 115 | .idea/**/dictionaries 116 | .idea/**/shelf 117 | 118 | # Sensitive or high-churn files 119 | .idea/**/dataSources/ 120 | .idea/**/dataSources.ids 121 | .idea/**/dataSources.local.xml 122 | .idea/**/sqlDataSources.xml 123 | .idea/**/dynamic.xml 124 | .idea/**/uiDesigner.xml 125 | .idea/**/dbnavigator.xml 126 | 127 | # Gradle 128 | .idea/**/gradle.xml 129 | .idea/**/libraries 130 | 131 | # Gradle and Maven with auto-import 132 | # When using Gradle or Maven with auto-import, you should exclude module files, 133 | # since they will be recreated, and may cause churn. Uncomment if using 134 | # auto-import. 135 | # .idea/modules.xml 136 | # .idea/*.iml 137 | # .idea/modules 138 | 139 | # CMake 140 | cmake-build-*/ 141 | 142 | # Mongo Explorer plugin 143 | .idea/**/mongoSettings.xml 144 | 145 | # File-based project format 146 | *.iws 147 | 148 | # IntelliJ 149 | out/ 150 | 151 | # mpeltonen/sbt-idea plugin 152 | .idea_modules/ 153 | 154 | # JIRA plugin 155 | atlassian-ide-plugin.xml 156 | 157 | # Cursive Clojure plugin 158 | .idea/replstate.xml 159 | 160 | # Crashlytics plugin (for Android Studio and IntelliJ) 161 | com_crashlytics_export_strings.xml 162 | crashlytics.properties 163 | crashlytics-build.properties 164 | fabric.properties 165 | 166 | # Editor-based Rest Client 167 | .idea/httpRequests 168 | ### VirtualEnv template 169 | # Virtualenv 170 | # http://iamzed.com/2009/05/07/a-primer-on-virtualenv/ 171 | [Bb]in 172 | [Ii]nclude 173 | [Ll]ib 174 | [Ll]ib64 175 | [Ll]ocal 176 | [Ss]cripts 177 | pyvenv.cfg 178 | pip-selfcheck.json 179 | 180 | ### PROJECT'S FILE 181 | .idea 182 | logs/*.log* 183 | geye/settings/settings_dev.py 184 | geye/settings/settings_prod.py 185 | -------------------------------------------------------------------------------- /geye/database/migrations/0003_auto_20211029_2354.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.2.5 on 2021-10-29 23:54 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('database', '0002_auto_20181223_2137'), 10 | ] 11 | 12 | operations = [ 13 | migrations.CreateModel( 14 | name='GeyeUserModel', 15 | fields=[ 16 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 17 | ('created_time', models.DateTimeField(auto_now=True)), 18 | ('updated_time', models.DateTimeField(auto_now_add=True)), 19 | ('is_deleted', models.BooleanField(default=False)), 20 | ('username', models.CharField(default='', max_length=64)), 21 | ('password', models.CharField(default='', max_length=512)), 22 | ('email', models.CharField(default='', max_length=128)), 23 | ('status', models.PositiveSmallIntegerField(default=0)), 24 | ], 25 | options={ 26 | 'db_table': 'geye_user', 27 | }, 28 | ), 29 | migrations.CreateModel( 30 | name='GeyeYuqueSearchRuleModel', 31 | fields=[ 32 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 33 | ('created_time', models.DateTimeField(auto_now=True)), 34 | ('updated_time', models.DateTimeField(auto_now_add=True)), 35 | ('is_deleted', models.BooleanField(default=False)), 36 | ('name', models.CharField(default='', max_length=128)), 37 | ('rule', models.CharField(default='', max_length=1024)), 38 | ('status', models.PositiveSmallIntegerField(default=1)), 39 | ('priority', models.PositiveIntegerField(default=5)), 40 | ('last_refresh_time', models.DateTimeField(auto_now_add=True)), 41 | ('interval', models.PositiveIntegerField(default=5)), 42 | ('need_notification', models.PositiveSmallIntegerField(default=0)), 43 | ('need_save', models.BooleanField(default=False)), 44 | ], 45 | options={ 46 | 'db_table': 'geye_yuque_search_rule', 47 | }, 48 | ), 49 | migrations.AlterField( 50 | model_name='geyefilterrulemodel', 51 | name='id', 52 | field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), 53 | ), 54 | migrations.AlterField( 55 | model_name='geyeleaksmodel', 56 | name='id', 57 | field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), 58 | ), 59 | migrations.AlterField( 60 | model_name='geyemonitorresultsmodel', 61 | name='id', 62 | field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), 63 | ), 64 | migrations.AlterField( 65 | model_name='geyemonitorrules', 66 | name='id', 67 | field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), 68 | ), 69 | migrations.AlterField( 70 | model_name='geyemonitorrules', 71 | name='task_type', 72 | field=models.CharField(db_index=True, default='', max_length=32), 73 | ), 74 | migrations.AlterField( 75 | model_name='geyesearchrulemodel', 76 | name='id', 77 | field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), 78 | ), 79 | migrations.AlterField( 80 | model_name='geyetokenmodel', 81 | name='id', 82 | field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), 83 | ), 84 | ] 85 | -------------------------------------------------------------------------------- /geye/core/engine/monitor/monitorSave.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.core.engine.monitor.monitorSave 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | 持久化存储monitor的结果 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | import json 16 | import queue 17 | 18 | from geye.core.engine.base import SingleThreadEngine 19 | from geye.database.models import GeyeMonitorResultsModel 20 | from geye.utils.datatype import PriorityTask 21 | from geye.utils.log import logger 22 | 23 | 24 | class MonitorSaveEngine(SingleThreadEngine): 25 | 26 | def __init__(self, app_ctx, name=None): 27 | super(MonitorSaveEngine, self).__init__(app_ctx, name) 28 | 29 | self._save_queue = self.app_ctx.MessageQueues.MONITOR_SAVE_QUEUE 30 | 31 | def __wait(self, timeout: int): 32 | self.ev.wait(timeout) 33 | 34 | def __get_task_from_queue(self): 35 | """ 36 | 从队列中获取一个任务 37 | :return: 38 | """ 39 | while self.is_running(): 40 | try: 41 | task: PriorityTask = self._save_queue.get_nowait() 42 | return task.priority, task.data 43 | except queue.Empty: 44 | self.__wait(1) 45 | continue 46 | 47 | def _worker(self): 48 | logger.info("{name} start!".format(name=self.name)) 49 | 50 | while self.is_running(): 51 | # 从队列中获取任务 52 | task_priority, task = self.__get_task_from_queue() 53 | if not task_priority or not task: 54 | continue 55 | 56 | # 任务格式 57 | # { 58 | # "data": [{}..], 59 | # "monitor_rule_id": int, 60 | # } 61 | # data中的每一项结构如下 62 | # { 63 | # "event_id": event_id, 64 | # "event_type": event_type, 65 | # "actor_url": actor_url, 66 | # "actor_login": actor_login, 67 | # "actor_display_name": actor_display_name, 68 | # "repo_name": repo_name, 69 | # "repo_url": repo_url, 70 | # "org_name": org_name, 71 | # "org_url": org_url, 72 | # "created_time": created_time, 73 | # "payloads": {} 74 | # } 75 | 76 | monitor_rule_id = task.get("monitor_rule_id") 77 | if not monitor_rule_id: 78 | continue 79 | 80 | dataset = task.get("data") 81 | for item in dataset: 82 | 83 | e_id = item.get("event_id") 84 | if not e_id: 85 | continue 86 | 87 | # 检查event_id是否已经存在了 88 | if GeyeMonitorResultsModel.instance.is_exist_by_event_id(event_id=e_id): 89 | continue 90 | 91 | monitor_results = GeyeMonitorResultsModel() 92 | monitor_results.monitor_rule_id = monitor_rule_id 93 | monitor_results.event_id = e_id 94 | monitor_results.event_type = item.get("event_type") 95 | 96 | monitor_results.actor_url = item.get("actor_url") 97 | monitor_results.actor_login = item.get("actor_login") 98 | monitor_results.actor_display_name = item.get("actor_display_name") 99 | 100 | monitor_results.org_name = item.get("org_name") 101 | monitor_results.org_url = item.get("org_url") 102 | 103 | monitor_results.repo_url = item.get("repo_url") 104 | monitor_results.repo_name = item.get("repo_name") 105 | 106 | monitor_results.event_created_time = item.get("created_time") 107 | 108 | monitor_results.content = json.dumps(item.get("payloads") or {}) 109 | 110 | monitor_results.save() 111 | 112 | logger.info("{name} stop!".format(name=self.name)) 113 | 114 | -------------------------------------------------------------------------------- /geye-fe/src/components/common/Sidebar.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 119 | 120 | 148 | -------------------------------------------------------------------------------- /geye-fe/src/components/common/Header.vue: -------------------------------------------------------------------------------- 1 | 41 | 42 | 79 | 80 | 168 | -------------------------------------------------------------------------------- /geye/utils/datatype.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.utils.datatype 6 | ~~~~~~~~~~~~~~~~~~~ 7 | 8 | Thanks to sqlmap's AttribDict 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | 15 | -------------------------------------------------------------- 16 | Copyright (c) 2006-2018 sqlmap developers (http://sqlmap.org/) 17 | See the file 'LICENSE' for copying permission 18 | -------------------------------------------------------------- 19 | """ 20 | 21 | 22 | import copy 23 | import types 24 | 25 | 26 | class AttribDict(dict): 27 | """ 28 | This class defines the sqlmap object, inheriting from Python data 29 | type dictionary. 30 | >>> foo = AttribDict() 31 | >>> foo.bar = 1 32 | >>> foo.bar 33 | 1 34 | """ 35 | 36 | def __init__(self, indict=None, attribute=None): 37 | if indict is None: 38 | indict = {} 39 | 40 | # Set any attributes here - before initialisation 41 | # these remain as normal attributes 42 | self.attribute = attribute 43 | dict.__init__(self, indict) 44 | self.__initialised = True 45 | 46 | # After initialisation, setting attributes 47 | # is the same as setting an item 48 | 49 | def __getattr__(self, item): 50 | """ 51 | Maps values to attributes 52 | Only called if there *is NOT* an attribute with this name 53 | """ 54 | 55 | try: 56 | return self.__getitem__(item) 57 | except KeyError: 58 | raise AttributeError("unable to access item '%s'" % item) 59 | 60 | def __setattr__(self, item, value): 61 | """ 62 | Maps attributes to values 63 | Only if we are initialised 64 | """ 65 | 66 | # This test allows attributes to be set in the __init__ method 67 | if "_AttribDict__initialised" not in self.__dict__: 68 | return dict.__setattr__(self, item, value) 69 | 70 | # Any normal attributes are handled normally 71 | elif item in self.__dict__: 72 | dict.__setattr__(self, item, value) 73 | 74 | else: 75 | self.__setitem__(item, value) 76 | 77 | def __getstate__(self): 78 | return self.__dict__ 79 | 80 | def __setstate__(self, dict): 81 | self.__dict__ = dict 82 | 83 | def __deepcopy__(self, memo): 84 | retVal = self.__class__() 85 | memo[id(self)] = retVal 86 | 87 | for attr in dir(self): 88 | if not attr.startswith('_'): 89 | value = getattr(self, attr) 90 | if not isinstance(value, (types.BuiltinFunctionType, types.FunctionType, types.MethodType)): 91 | setattr(retVal, attr, copy.deepcopy(value, memo)) 92 | 93 | for key, value in self.items(): 94 | retVal.__setitem__(key, copy.deepcopy(value, memo)) 95 | 96 | return retVal 97 | 98 | 99 | class InjectionDict(AttribDict): 100 | def __init__(self): 101 | AttribDict.__init__(self) 102 | 103 | self.place = None 104 | self.parameter = None 105 | self.ptype = None 106 | self.prefix = None 107 | self.suffix = None 108 | self.clause = None 109 | self.notes = [] # Note: https://github.com/sqlmapproject/sqlmap/issues/1888 110 | 111 | # data is a dict with various stype, each which is a dict with 112 | # all the information specific for that stype 113 | self.data = AttribDict() 114 | 115 | # conf is a dict which stores current snapshot of important 116 | # options used during detection 117 | self.conf = AttribDict() 118 | 119 | self.dbms = None 120 | self.dbms_version = None 121 | self.os = None 122 | 123 | 124 | class PriorityTask: 125 | def __init__(self, priority: int, data): 126 | self.data = data 127 | self.priority = int(priority) 128 | 129 | def __lt__(self, other: "PriorityTask"): 130 | return self.priority < other.priority 131 | 132 | def __str__(self): 133 | return "".format(self.priority, self.data) 134 | -------------------------------------------------------------------------------- /geye/database/models/rules/search.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | 6 | ~~~~~~~~~~~~~~~~~~ 7 | 8 | 9 | :author: lightless 10 | :homepage: None 11 | :license: GPL-3.0, see LICENSE for more details. 12 | :copyright: Copyright (c) 2017 lightless. All rights reserved 13 | """ 14 | 15 | from django.db import models 16 | from django.db import transaction 17 | 18 | from geye.utils.log import logger 19 | from ..base import GeyeBaseModel 20 | 21 | 22 | class SearchRuleConvert: 23 | @staticmethod 24 | def convert_status(status: int, html_template="{c}"): 25 | if status == 1: 26 | return html_template.format(t="success", c="开启") if html_template else "开启" 27 | elif status == 0: 28 | return html_template.format(t="danger", c="关闭") if html_template else "关闭" 29 | else: 30 | return html_template.format(t="", c="未知") if html_template else "未知" 31 | 32 | 33 | class SearchRuleManager(models.Manager): 34 | def get_all_search_rules(self): 35 | """ 36 | 获取所有的search rule 37 | """ 38 | return self.filter(is_deleted=0).order_by("id").all() 39 | 40 | def is_exist(self, rule_name): 41 | """ 42 | 判断rule name对应的规则是否存在 43 | :param rule_name: 44 | :return: 45 | """ 46 | # logger.debug("rule name: {}, exist: {}".format(rule_name, self.filter(is_deleted=0, name=rule_name).first())) 47 | return True if self.filter(is_deleted=0, name=rule_name).first() else False 48 | 49 | def is_exist_by_pk(self, pk): 50 | return True if self.filter(is_deleted=0, id=pk).first() else False 51 | 52 | def fake_delete(self, pk=None, rule_name=None): 53 | if pk: 54 | return self.filter(is_deleted=0, id=pk).update(is_deleted=1) 55 | if rule_name: 56 | return self.filter(is_deleted=0, name=rule_name).update(is_deleted=1) 57 | 58 | return None 59 | 60 | def change_status(self, pk=None, rule_name=None): 61 | with transaction.atomic(): 62 | if pk: 63 | obj = self.select_for_update().filter(is_deleted=0, id=pk) 64 | elif rule_name: 65 | obj = self.select_for_update().filter(is_deleted=0, name=rule_name) 66 | else: 67 | return None 68 | 69 | obj = obj.first() 70 | if not obj: 71 | return None 72 | obj.status = not obj.status 73 | obj.save() 74 | 75 | return obj 76 | 77 | def get_detail(self, pk=None, rule_name=None): 78 | if pk: 79 | return self.filter(is_deleted=0, id=pk).first() 80 | elif rule_name: 81 | return self.filter(is_deleted=0, name=rule_name).first() 82 | else: 83 | return None 84 | 85 | def get_name_by_pk(self, pk): 86 | """ 87 | 根据search rule id获取对应的规则名称 88 | :param pk: 89 | :return: 90 | """ 91 | obj = self.filter(is_deleted=0, id=pk).first() 92 | if not obj: 93 | return "" 94 | else: 95 | return obj.name 96 | 97 | 98 | class GeyeSearchRuleModel(GeyeBaseModel): 99 | """ 100 | 用于搜索代码的搜索规则 101 | Search Rule 102 | 103 | name 104 | 规则名称 105 | rule 106 | 搜索关键字 107 | status 108 | 状态,1-启用,0-关闭 109 | priority: 110 | 优先级,默认为5,1-10,越大越优先被搜索 111 | last_refresh_time 112 | 上次刷新时间 113 | delay 114 | 刷新间隔,单位分钟 115 | need_notification 116 | 当该条SRID命中后是否需要发送通知,默认 117 | clone: 118 | 当命中规则后,是否需要clone保存代码 119 | """ 120 | 121 | class Meta: 122 | db_table = "geye_search_rule" 123 | 124 | name = models.CharField(max_length=128, default="", null=False) 125 | rule = models.CharField(max_length=1024, default="", null=False) 126 | status = models.PositiveSmallIntegerField(default=1) 127 | priority = models.PositiveIntegerField(default=5, null=False) 128 | last_refresh_time = models.DateTimeField(auto_now_add=True) 129 | delay = models.PositiveIntegerField(default=5) 130 | need_notification = models.BooleanField(default=False) 131 | clone = models.BooleanField(default=False) 132 | 133 | objects = models.Manager() 134 | instance = SearchRuleManager() 135 | -------------------------------------------------------------------------------- /geye-fe/src/components/handleCenter/utils/searchResultItem.vue: -------------------------------------------------------------------------------- 1 | 42 | 43 | 108 | 109 | 126 | -------------------------------------------------------------------------------- /geye-fe/src/components/handleCenter/MonitorCenter.vue: -------------------------------------------------------------------------------- 1 | 69 | 70 | 140 | 141 | 147 | -------------------------------------------------------------------------------- /geye/database/models/rules/filter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.database.models.rules.filter 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | FilterRule 过滤规则 9 | 用于对搜索到的代码进行精确匹配 10 | 11 | :author: lightless 12 | :homepage: None 13 | :license: GPL-3.0, see LICENSE for more details. 14 | :copyright: Copyright (c) 2017 lightless. All rights reserved 15 | """ 16 | 17 | from django.db import models, transaction 18 | 19 | from ..base import GeyeBaseModel 20 | 21 | 22 | class FilterRuleManager(models.Manager): 23 | def get_filter_rules_by_srid(self, srid, contains_global_rule=True) -> list: 24 | """ 25 | 返回指定SRID对应的全部filter规则 26 | :param srid: 27 | :param contains_global_rule: True-包含全局规则,False-不包含全局规则 28 | :return: list 29 | """ 30 | all_rules = [] 31 | if contains_global_rule: 32 | global_rules = self.filter(is_deleted=0, parent_id=0, status=1).order_by('-priority').all() 33 | for r in global_rules: 34 | all_rules.append(r) 35 | 36 | child_rules = self.filter(is_deleted=0, parent_id=srid, status=1).order_by('-priority').all() 37 | for r in child_rules: 38 | all_rules.append(r) 39 | return all_rules 40 | 41 | def is_exist(self, pk): 42 | return self.filter(is_deleted=0, id=pk).first() 43 | 44 | def is_exist_global(self, pk): 45 | return self.filter(is_deleted=0, parent_id=0, id=pk).first() 46 | 47 | def fake_delete(self, pk): 48 | return self.filter(is_deleted=0, id=pk).update(is_deleted=1) 49 | 50 | def fake_delete_global(self, pk): 51 | return self.filter(is_deleted=0, id=pk, parent_id=0).update(is_deleted=1) 52 | 53 | def get_detail(self, pk): 54 | return self.filter(is_deleted=0, id=pk).first() 55 | 56 | def get_detail_global(self, pk): 57 | return self.filter(is_deleted=0, id=pk, parent_id=0).first() 58 | 59 | def update_filter_rule(self, params: dict) -> "GeyeFilterRuleModel": 60 | with transaction.atomic(): 61 | obj: GeyeFilterRuleModel = self.select_for_update().filter(is_deleted=0, id=params.get("id")).first() 62 | obj.name = params.get("name") 63 | obj.rule = params.get("ruleContent") 64 | obj.rule_type = params.get("ruleType") 65 | obj.rule_engine = params.get("ruleEngine") 66 | obj.status = params.get("status") 67 | obj.action = params.get("action") 68 | obj.position = params.get("position") 69 | obj.priority = params.get("priority") 70 | 71 | obj.save() 72 | return obj 73 | 74 | def all_global_filter_rule(self): 75 | return self.filter(is_deleted=0, parent_id=0).all() 76 | 77 | def get_name_by_pk(self, pk): 78 | obj = self.filter(is_deleted=0, id=pk).first() 79 | if not obj: 80 | return "" 81 | else: 82 | return obj.name 83 | 84 | 85 | class GeyeFilterRuleModel(GeyeBaseModel): 86 | """ 87 | 用于获取详细代码后二次匹配用到的filter规则 88 | Filter Rule 89 | 90 | name 91 | 规则标题,用于区分这个规则是干啥的 92 | rule_type 93 | 规则类型 1-正向匹配,2-反向匹配 94 | rule_engine 95 | 1 - 正则匹配 96 | 2 - 字符串匹配 97 | rule 98 | 规则内容,正则表达式 或 需要匹配的字符串 99 | status 100 | 规则状态,1-启用,0-关闭 101 | parent_id 102 | 父规则(搜索规则)ID,如果这个值为0,那么该规则为全局规则,对所有search rule生效 103 | action 104 | 如果rule_type为1,则这里是命中后的操作 105 | 如果rule_type为2,则这里是未命中后的操作 106 | 1-啥也不做,继续下一条匹配,不保存,可以用于其他规则的前置 107 | 2-设为误报,结束匹配,不保存,可以排除掉一定不是敏感信息泄露的内容 108 | 3-设为误报,结束匹配,保存,可以排除掉一定不是敏感信息泄露的内容 109 | 4-设为确认,结束匹配,保存,确定规则 110 | 5-啥也不做(设为待确认),结束匹配,保存 111 | position 112 | 决定在哪里执行二次过滤 113 | 1-author 114 | 2-repo name 115 | 3-path 116 | 4-code 117 | 5-filename 118 | priority 119 | 规则优先级,决定了规则的匹配顺序 120 | """ 121 | 122 | class Meta: 123 | db_table = "geye_filter_rule" 124 | 125 | name = models.CharField(max_length=128) 126 | rule_type = models.PositiveSmallIntegerField(default=0) 127 | rule_engine = models.PositiveSmallIntegerField(default=0) 128 | rule = models.TextField() 129 | status = models.PositiveSmallIntegerField(default=1) 130 | parent_id = models.BigIntegerField(default=0) 131 | action = models.PositiveSmallIntegerField(default=1) 132 | position = models.PositiveSmallIntegerField(default=1) 133 | priority = models.PositiveIntegerField(default=5) 134 | 135 | objects = models.Manager() 136 | instance = FilterRuleManager() 137 | 138 | def __str__(self): 139 | return "".format(self.id, self.name, self.parent_id) 140 | 141 | def __repr__(self): 142 | return "".format(self.id, self.name, self.parent_id) 143 | -------------------------------------------------------------------------------- /geye/database/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.2 on 2018-10-22 21:38 2 | 3 | from django.db import migrations, models 4 | import django.db.models.manager 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | initial = True 10 | 11 | dependencies = [ 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='GeyeFilterRuleModel', 17 | fields=[ 18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 19 | ('created_time', models.DateTimeField(auto_now=True)), 20 | ('updated_time', models.DateTimeField(auto_now_add=True)), 21 | ('is_deleted', models.BooleanField(default=False)), 22 | ('name', models.CharField(max_length=128)), 23 | ('rule_type', models.PositiveSmallIntegerField(default=0)), 24 | ('rule_engine', models.PositiveSmallIntegerField(default=0)), 25 | ('rule', models.TextField()), 26 | ('status', models.PositiveSmallIntegerField(default=1)), 27 | ('parent_id', models.BigIntegerField(default=0)), 28 | ('action', models.PositiveSmallIntegerField(default=1)), 29 | ('position', models.PositiveSmallIntegerField(default=1)), 30 | ('priority', models.PositiveIntegerField(default=5)), 31 | ], 32 | options={ 33 | 'db_table': 'geye_filter_rule', 34 | }, 35 | ), 36 | migrations.CreateModel( 37 | name='GeyeLeaksModel', 38 | fields=[ 39 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 40 | ('created_time', models.DateTimeField(auto_now=True)), 41 | ('updated_time', models.DateTimeField(auto_now_add=True)), 42 | ('is_deleted', models.BooleanField(default=False)), 43 | ('repo_name', models.CharField(db_index=True, default='', max_length=256)), 44 | ('author', models.CharField(default='', max_length=256)), 45 | ('path', models.CharField(default='', max_length=1024)), 46 | ('filename', models.CharField(default='', max_length=256)), 47 | ('sha', models.CharField(db_index=True, default='', max_length=40)), 48 | ('full_code_url', models.TextField()), 49 | ('url', models.TextField()), 50 | ('code', models.TextField()), 51 | ('srid', models.BigIntegerField(default=0)), 52 | ('frid', models.BigIntegerField(default=0)), 53 | ('status', models.PositiveSmallIntegerField(default=1)), 54 | ('pushed', models.BooleanField(default=False)), 55 | ], 56 | options={ 57 | 'db_table': 'geye_leaks', 58 | }, 59 | managers=[ 60 | ('object', django.db.models.manager.Manager()), 61 | ], 62 | ), 63 | migrations.CreateModel( 64 | name='GeyeSearchRuleModel', 65 | fields=[ 66 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 67 | ('created_time', models.DateTimeField(auto_now=True)), 68 | ('updated_time', models.DateTimeField(auto_now_add=True)), 69 | ('is_deleted', models.BooleanField(default=False)), 70 | ('name', models.CharField(default='', max_length=128)), 71 | ('rule', models.CharField(default='', max_length=1024)), 72 | ('status', models.PositiveSmallIntegerField(default=1)), 73 | ('priority', models.PositiveIntegerField(default=5)), 74 | ('last_refresh_time', models.DateTimeField(auto_now_add=True)), 75 | ('delay', models.PositiveIntegerField(default=5)), 76 | ('need_notification', models.BooleanField(default=False)), 77 | ('clone', models.BooleanField(default=False)), 78 | ], 79 | options={ 80 | 'db_table': 'geye_search_rule', 81 | }, 82 | ), 83 | migrations.CreateModel( 84 | name='GeyeTokenModel', 85 | fields=[ 86 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 87 | ('created_time', models.DateTimeField(auto_now=True)), 88 | ('updated_time', models.DateTimeField(auto_now_add=True)), 89 | ('is_deleted', models.BooleanField(default=False)), 90 | ('token_name', models.CharField(default='TokenName', max_length=32)), 91 | ('token', models.CharField(default='', max_length=64)), 92 | ('remain_limit', models.PositiveIntegerField(default=0)), 93 | ('status', models.PositiveSmallIntegerField(default=1)), 94 | ], 95 | options={ 96 | 'db_table': 'geye_token', 97 | }, 98 | ), 99 | ] 100 | -------------------------------------------------------------------------------- /geye/utils/logger.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | logger 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | $END$ 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017-2021 lightless. All rights reserved 14 | """ 15 | 16 | import logging 17 | import logging.handlers 18 | import os 19 | 20 | from django.conf import settings 21 | 22 | # 用户配置部分 ↓ 23 | LEVEL_COLOR = { 24 | 'DEBUG': 'cyan', 25 | 'INFO': 'green', 26 | 'WARNING': 'yellow', 27 | 'ERROR': 'red', 28 | 'CRITICAL': 'red,bg_white', 29 | } 30 | STDOUT_LOG_FMT = "%(log_color)s[%(asctime)s] [%(levelname)s] [%(threadName)s] [%(filename)s:%(lineno)d] %(message)s" 31 | STDOUT_DATE_FMT = "%Y-%m-%d %H:%M:%S" 32 | FILE_LOG_FMT = "[%(asctime)s] [%(levelname)s] [%(threadName)s] [%(filename)s:%(lineno)d] %(message)s" 33 | FILE_DATE_FMT = "%Y-%m-%d %H:%M:%S" 34 | 35 | # 不同日志级别对用的文件名suffix 36 | LEVEL_SUFFIX = { 37 | "debug": ".DEBUG", 38 | "info": ".INFO", 39 | "warning": ".WARNING", 40 | "error": ".ERROR", 41 | "critical": ".CRITICAL", 42 | "all": ".ALL", 43 | } 44 | 45 | 46 | # 用户配置部分 ↑ 47 | 48 | class ColoredFormatter(logging.Formatter): 49 | COLOR_MAP = { 50 | "black": "30", 51 | "red": "31", 52 | "green": "32", 53 | "yellow": "33", 54 | "blue": "34", 55 | "magenta": "35", 56 | "cyan": "36", 57 | "white": "37", 58 | "bg_black": "40", 59 | "bg_red": "41", 60 | "bg_green": "42", 61 | "bg_yellow": "43", 62 | "bg_blue": "44", 63 | "bg_magenta": "45", 64 | "bg_cyan": "46", 65 | "bg_white": "47", 66 | "light_black": "1;30", 67 | "light_red": "1;31", 68 | "light_green": "1;32", 69 | "light_yellow": "1;33", 70 | "light_blue": "1;34", 71 | "light_magenta": "1;35", 72 | "light_cyan": "1;36", 73 | "light_white": "1;37", 74 | "light_bg_black": "100", 75 | "light_bg_red": "101", 76 | "light_bg_green": "102", 77 | "light_bg_yellow": "103", 78 | "light_bg_blue": "104", 79 | "light_bg_magenta": "105", 80 | "light_bg_cyan": "106", 81 | "light_bg_white": "107", 82 | } 83 | 84 | def __init__(self, fmt, datefmt): 85 | super(ColoredFormatter, self).__init__(fmt, datefmt) 86 | 87 | def parse_color(self, level_name): 88 | color_name = LEVEL_COLOR.get(level_name, "") 89 | if not color_name: 90 | return "" 91 | 92 | color_value = [] 93 | color_name = color_name.split(",") 94 | for _cn in color_name: 95 | color_code = self.COLOR_MAP.get(_cn, "") 96 | if color_code: 97 | color_value.append(color_code) 98 | 99 | return "\033[" + ";".join(color_value) + "m" 100 | 101 | def format(self, record): 102 | record.log_color = self.parse_color(record.levelname) 103 | message = super(ColoredFormatter, self).format(record) + "\033[0m" 104 | 105 | return message 106 | 107 | 108 | class FileLoggerFilter(logging.Filter): 109 | """ 110 | 用来过滤输出到文件中的日志 111 | 只有当当期的日志级别和指定的级别一致时,才输出 112 | """ 113 | 114 | def __init__(self, level: str): 115 | super(FileLoggerFilter, self).__init__() 116 | self.level = level.upper() 117 | 118 | def filter(self, record: logging.LogRecord): 119 | """ 120 | Is the specified record to be logged? Returns zero for no, nonzero for yes. 121 | :param record: 122 | :return: 123 | """ 124 | if self.level == "all": 125 | return True 126 | else: 127 | return record.levelname == self.level 128 | 129 | 130 | class LoggerFactory(object): 131 | """ 132 | from utils.logger import LoggerFactory 133 | logger = LoggerFactory.get_logger(__name__) 134 | """ 135 | 136 | log_to_file = settings.LOG_TO_FILE 137 | log_filename = settings.LOG_FILENAME 138 | log_level = settings.LOG_LEVEL if settings.LOG_LEVEL else "DEBUG" 139 | 140 | @classmethod 141 | def get_logger(cls, name): 142 | _logger = logging.getLogger(name) 143 | 144 | stdout_handler = logging.StreamHandler() 145 | stdout_handler.setFormatter( 146 | ColoredFormatter( 147 | fmt=STDOUT_LOG_FMT, 148 | datefmt=STDOUT_DATE_FMT, 149 | ) 150 | ) 151 | _logger.addHandler(stdout_handler) 152 | 153 | if cls.log_to_file: 154 | # 检查指定的日志目录是否存在,如果不存在就先创建目录 155 | _tmp_path = settings.LOG_PATH 156 | if not os.path.exists(_tmp_path): 157 | os.mkdir(_tmp_path) 158 | _tmp_path = os.path.join(_tmp_path, cls.log_filename) 159 | 160 | # 写文件的handler 161 | file_formatter = logging.Formatter(fmt=FILE_LOG_FMT, datefmt=FILE_DATE_FMT) 162 | file_handler = logging.handlers.TimedRotatingFileHandler(_tmp_path, when="midnight", backupCount=15) 163 | file_handler.setFormatter(file_formatter) 164 | _logger.addHandler(file_handler) 165 | 166 | _logger.setLevel(cls.log_level) 167 | return _logger 168 | -------------------------------------------------------------------------------- /geye-fe/src/components/searchRule/new.vue: -------------------------------------------------------------------------------- 1 | 87 | 88 | 147 | 148 | -------------------------------------------------------------------------------- /geye-fe/src/components/searchRule/all.vue: -------------------------------------------------------------------------------- 1 | 49 | 50 | 130 | 131 | 152 | -------------------------------------------------------------------------------- /geye/web/controller/token/token.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.web.controller.web.token 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | Token 相关的controller 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | import json 16 | 17 | from django.http import JsonResponse 18 | from django.views import View 19 | 20 | from geye.database.models import GeyeTokenModel 21 | from geye.utils.log import logger 22 | from geye.utils.validator import RequestValidator 23 | 24 | 25 | def mask_token(token): 26 | return token[:8] + "*" * 24 27 | 28 | 29 | class TokensView(View): 30 | """ 31 | 获取所有token信息 32 | """ 33 | @staticmethod 34 | def get(request): 35 | rows = GeyeTokenModel.instance.get_all_tokens() 36 | 37 | data = [] 38 | for row in rows: 39 | data.append({ 40 | "id": row.id, 41 | "tokenName": row.token_name, 42 | "tokenContent": mask_token(row.token), 43 | "status": row.status, 44 | "remainLimit": row.remain_limit 45 | }) 46 | return JsonResponse({"code": 1001, "message": "获取成功", "data": data}) 47 | 48 | 49 | class DeleteTokenView(View): 50 | """ 51 | 删除某条token 52 | """ 53 | @staticmethod 54 | def post(request): 55 | token_id = json.loads(request.body).get("id", None) 56 | if not token_id or not GeyeTokenModel.instance.is_exist(token_id): 57 | return JsonResponse({"code": 1004, "message": "token id不存在"}) 58 | 59 | obj = GeyeTokenModel.instance.fake_delete(token_id) 60 | if obj: 61 | return JsonResponse({"code": 1001, "message": "删除成功!"}) 62 | else: 63 | return JsonResponse({"code": 1002, "message": "删除失败!"}) 64 | 65 | 66 | class AddTokenView(View): 67 | """ 68 | 添加一条token 69 | """ 70 | @staticmethod 71 | def post(request): 72 | logger.debug("POST: {}".format(request.body)) 73 | 74 | result = RequestValidator.check_params( 75 | request, check_empty=True, 76 | check_params=["tokenName", "tokenContent", "status"] 77 | ) 78 | if result.has_error: 79 | logger.error("error: {}".format(result.error_message)) 80 | return JsonResponse({"code": 1004, "message": result.error_message}) 81 | 82 | args = result.params 83 | 84 | token_name = args.get("tokenName", None) 85 | token = args.get("tokenContent", None) 86 | status = args.get("status", None) 87 | 88 | obj = GeyeTokenModel.objects.create( 89 | token_name=token_name, token=token, status=status, remain_limit=99999 90 | ) 91 | if obj: 92 | return JsonResponse({"code": 1001, "message": "添加成功!", "data": { 93 | "id": obj.id, 94 | "tokenName": obj.token_name, 95 | "tokenContent": obj.token, 96 | "status": obj.status, 97 | "remainLimit": obj.remain_limit, 98 | }}) 99 | else: 100 | return JsonResponse({"code": 1002, "message": "添加失败!"}) 101 | 102 | 103 | class EditTokenView(View): 104 | """ 105 | 编辑一条token 106 | """ 107 | @staticmethod 108 | def post(request): 109 | logger.debug("POST: {}".format(request.body)) 110 | 111 | result = RequestValidator.check_params( 112 | request, check_empty=True, 113 | check_params=["id", "tokenName", "tokenContent", "status"] 114 | ) 115 | if result.has_error: 116 | logger.error("error: {}".format(result.error_message)) 117 | return JsonResponse({"code": 1004, "message": result.error_message}) 118 | 119 | args = result.params 120 | 121 | token_id = args.get("id", None) 122 | if not token_id or not GeyeTokenModel.instance.is_exist(token_id): 123 | return JsonResponse({"code": 1004, "message": "token id不存在!"}) 124 | 125 | obj = GeyeTokenModel.instance.update_token(args) 126 | if obj: 127 | return JsonResponse({"code": 1001, "message": "更新成功!", "data": { 128 | "id": obj.id, 129 | "tokenName": obj.token_name, 130 | "tokenContent": mask_token(obj.token), 131 | "status": obj.status, 132 | "remainLimit": obj.remain_limit, 133 | }}) 134 | else: 135 | return JsonResponse({"code": 1002, "message": "更新失败!"}) 136 | 137 | 138 | class UpdateStatus(View): 139 | """ 140 | 切换一条token状态 141 | """ 142 | @staticmethod 143 | def post(request): 144 | token_id = json.loads(request.body).get("id", None) 145 | if not token_id or not GeyeTokenModel.instance.is_exist(token_id): 146 | return JsonResponse({"code": 1004, "message": "token id不存在!"}) 147 | 148 | obj = GeyeTokenModel.instance.change_status(token_id) 149 | if obj: 150 | return JsonResponse({"code": 1001, "message": "切换成功!"}) 151 | else: 152 | return JsonResponse({"code": 1002, "message": "切换失败!"}) 153 | 154 | 155 | class TokenDetailsView(View): 156 | """ 157 | 获取某条token的详细信息 158 | """ 159 | @staticmethod 160 | def get(request): 161 | token_id = request.GET.get("id", None) 162 | if not token_id or not GeyeTokenModel.instance.is_exist(token_id): 163 | return JsonResponse({"code": 1004, "message": "token id不存在!"}) 164 | 165 | obj = GeyeTokenModel.instance.get_details(token_id) 166 | if obj: 167 | obj["tokenContent"] = mask_token(obj["tokenContent"]) 168 | return JsonResponse({"code": 1001, "message": "获取成功!", "data": obj}) 169 | else: 170 | return JsonResponse({"code": 1002, "message": "获取失败!"}) 171 | -------------------------------------------------------------------------------- /geye/web/controller/leaks/leaks.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.web.controller.leaks.leaks 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | Leaks相关的controller 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017 lightless. All rights reserved 14 | """ 15 | import json 16 | 17 | from django.http import JsonResponse 18 | from django.views import View 19 | 20 | from geye.database.models import GeyeLeaksModel, GeyeSearchRuleModel, GeyeFilterRuleModel, LeaksStatusConstant 21 | 22 | 23 | class AllLeaksView(View): 24 | PAGE_SIZE = 20 25 | 26 | def get(self, request): 27 | page = request.GET.get("page", 1) 28 | status = request.GET.get("status", None) 29 | if not status: 30 | return JsonResponse({"code": 1005, "message": "参数错误!"}) 31 | 32 | page = int(page) 33 | status = status.split(",") 34 | if not status: 35 | status = [1, 2, 3] 36 | 37 | if not page or not status: 38 | return JsonResponse({"code": 1004, "message": "参数错误!"}) 39 | 40 | start_id = (page - 1) * self.PAGE_SIZE 41 | end_id = start_id + self.PAGE_SIZE 42 | 43 | sql = GeyeLeaksModel.instance.filter( 44 | is_deleted=0, status__in=status 45 | ).order_by("-created_time") 46 | 47 | rows = sql[start_id:end_id] 48 | total_count = sql.count() 49 | 50 | data = [] 51 | for row in rows: 52 | search_rule_name = GeyeSearchRuleModel.instance.get_name_by_pk(row.srid) 53 | filter_rule_name = GeyeFilterRuleModel.instance.get_name_by_pk(row.frid) 54 | if not filter_rule_name: 55 | filter_rule_name = "规则已删除" 56 | data.append({ 57 | "id": row.id, 58 | "repoName": row.repo_name, 59 | "author": row.author, 60 | "path": row.path, 61 | "filename": row.filename, 62 | "sha": row.sha, 63 | "full_code_url": row.full_code_url, 64 | "url": row.url, 65 | "code": row.code, 66 | "srid": row.srid, 67 | "frid": row.frid, 68 | "status": row.status, 69 | "pushed": row.pushed, 70 | "searchRuleName": search_rule_name, 71 | "filterRuleName": filter_rule_name, 72 | "created_time": row.created_time.strftime("%Y-%m-%d %H:%M:%S"), 73 | }) 74 | 75 | return JsonResponse({"code": 1001, "message": "获取成功!", "data": data, "total_count": total_count}) 76 | 77 | 78 | class DeleteLeakView(View): 79 | """ 80 | 删除一条Leaks记录 81 | """ 82 | @staticmethod 83 | def post(request): 84 | leak_id = json.loads(request.body).get("id", None) 85 | 86 | if not leak_id or not GeyeLeaksModel.instance.is_exist_by_pk(leak_id): 87 | return JsonResponse({"code": 1004, "message": "id不存在!"}) 88 | 89 | if GeyeLeaksModel.instance.fake_delete(leak_id): 90 | return JsonResponse({"code": 1001, "message": "删除成功!"}) 91 | else: 92 | return JsonResponse({"code": 1002, "message": "删除失败!"}) 93 | 94 | 95 | class ChangeStatusLeakView(View): 96 | """ 97 | 修改leaks的状态 98 | request params: 99 | - action 100 | - id 101 | """ 102 | ACTIONS = ["ignore", "confirm"] 103 | 104 | def post(self, request): 105 | request_params = json.loads(request.body) 106 | action = request_params.get("action", None) 107 | leak_id = request_params.get("id", None) 108 | if not action or action not in self.ACTIONS: 109 | return JsonResponse({"code": 1004, "message": "action不存在!"}) 110 | if not leak_id or not GeyeLeaksModel.instance.is_exist_by_pk(leak_id): 111 | return JsonResponse({"code": 1004, "message": "id不存在!"}) 112 | 113 | if action == "confirm": 114 | result = GeyeLeaksModel.instance.filter(is_deleted=0, pk=leak_id).update(status=LeaksStatusConstant.CONFIRM) 115 | if result: 116 | return JsonResponse({"code": 1001, "message": "修改成功!"}) 117 | else: 118 | return JsonResponse({"code": 1002, "message": "修改失败!"}) 119 | elif action == "ignore": 120 | result = GeyeLeaksModel.instance.filter(is_deleted=0, pk=leak_id).update(status=LeaksStatusConstant.IGNORE) 121 | if result: 122 | return JsonResponse({"code": 1001, "message": "修改成功!"}) 123 | else: 124 | return JsonResponse({"code": 1002, "message": "修改失败!"}) 125 | 126 | return JsonResponse({"code": 1003, "message": "error action!"}) 127 | 128 | 129 | class BatchChangeStatusLeakView(View): 130 | """ 131 | 批量修改leaks的状态 132 | request params: 133 | :action: 134 | :ids: 135 | """ 136 | ACTIONS = ["ignore", "confirm"] 137 | 138 | def post(self, request): 139 | request_params = json.loads(request.body) 140 | action = request_params.get("action", None) 141 | leak_id = request_params.get("ids", list()) 142 | 143 | if not action or action not in self.ACTIONS: 144 | return JsonResponse({"code": 1004, "message": "action不存在!"}) 145 | if not isinstance(leak_id, list) or not len(leak_id): 146 | return JsonResponse({"code": 1004, "message": "id不存在!"}) 147 | 148 | if action == "confirm": 149 | new_status = LeaksStatusConstant.CONFIRM 150 | elif action == "ignore": 151 | new_status = LeaksStatusConstant.IGNORE 152 | 153 | result = GeyeLeaksModel.instance.filter(is_deleted=0, pk__in=leak_id).update(status=new_status) 154 | if result: 155 | return JsonResponse({"code": 1001, "message": "更新成功!"}) 156 | else: 157 | return JsonResponse({"code": 1002, "message": "更新失败!"}) 158 | -------------------------------------------------------------------------------- /geye/web/controller/rule/monitor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | """ 5 | geye.web.controller.rule.monitor 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 | 8 | Monitor Rule相关的控制器 9 | 10 | :author: lightless 11 | :homepage: None 12 | :license: GPL-3.0, see LICENSE for more details. 13 | :copyright: Copyright (c) 2017-2019 lightless. All rights reserved 14 | """ 15 | import json 16 | from typing import List 17 | 18 | from django.db import transaction 19 | from django.views import View 20 | from django.http import JsonResponse 21 | 22 | from geye.utils.log import logger 23 | from geye.utils.validator import RequestValidator 24 | from geye.database.models.monitorRules import MonitorEventTypeConstant, MonitorTaskTypeConstant, GeyeMonitorRules 25 | 26 | 27 | class MonitorRulesView(View): 28 | """ 29 | 获取所有的monitor rule信息 30 | """ 31 | 32 | @staticmethod 33 | def get(request): 34 | rows: List[GeyeMonitorRules] = GeyeMonitorRules.instance.get_all() 35 | return JsonResponse({ 36 | "code": 1001, "message": "获取成功!", 37 | "data": [ 38 | { 39 | "id": row.id, 40 | "taskType": row.task_type, 41 | "eventType": row.event_type.split(","), 42 | "ruleContent": row.rule_content, 43 | "status": row.status, 44 | "interval": row.interval, 45 | "priority": row.priority, 46 | "lastFetchTime": row.last_fetch_time, 47 | } for row in rows 48 | ]}) 49 | 50 | 51 | class AddMonitorRuleView(View): 52 | """ 53 | 添加一条 monitor rule 54 | eventType: (...) 55 | interval: (...) 56 | priority: (...) 57 | ruleContent: (...) 58 | status: (...) 59 | taskType: (...) 60 | """ 61 | 62 | @staticmethod 63 | def post(request): 64 | 65 | logger.debug(f"POST data: {request.body}") 66 | 67 | # 校验参数 68 | validator = RequestValidator() 69 | result = validator.check_params(request, check_params=[ 70 | "taskType", "eventType", "interval", "priority", "ruleContent", "status" 71 | ], check_empty=True) 72 | if result.has_error: 73 | return JsonResponse({"code": 1004, "message": result.error_message}) 74 | 75 | # 校验参数 76 | params = result.params 77 | # logger.debug(f"params: {params}") 78 | task_type = params.get("taskType") 79 | event_type = params.get("eventType") 80 | logger.debug(f"TaskTypeConstantList: {MonitorTaskTypeConstant.lst()}") 81 | logger.debug(f"EventTypeConstantList: {MonitorEventTypeConstant.lst()}") 82 | if task_type not in MonitorTaskTypeConstant.lst(): 83 | return JsonResponse({"code": 1003, "message": "taskType有误!"}) 84 | for _post_event_type in event_type: 85 | if _post_event_type not in MonitorEventTypeConstant.lst(): 86 | return JsonResponse({"code": 1003, "message": "eventType有误!"}) 87 | 88 | # 插入数据 89 | obj = GeyeMonitorRules.instance.create( 90 | task_type=task_type, event_type=",".join(event_type), rule_content=params.get("ruleContent"), 91 | status=params.get("status"), interval=params.get("interval"), priority=params.get("priority") 92 | ) 93 | if obj: 94 | return JsonResponse({"code": 1001, "message": "添加成功", "data": obj.convert_to_dict()}) 95 | else: 96 | return JsonResponse({"code": 1002, "message": "添加失败"}) 97 | 98 | 99 | class UpdateMonitorRuleView(View): 100 | """ 101 | 更新一条 monitor rule 102 | """ 103 | 104 | @staticmethod 105 | def post(request): 106 | 107 | logger.debug(f"POST data: {request.body}") 108 | 109 | # 校验参数 110 | validator = RequestValidator() 111 | result = validator.check_params(request, check_params=[ 112 | "taskType", "eventType", "interval", "priority", "ruleContent", "status" 113 | ], check_empty=True) 114 | if result.has_error: 115 | return JsonResponse({"code": 1004, "message": result.error_message}) 116 | 117 | # 校验参数 118 | params = result.params 119 | task_type = params.get("taskType") 120 | event_type = params.get("eventType") 121 | if task_type not in MonitorTaskTypeConstant.lst(): 122 | return JsonResponse({"code": 1003, "message": "taskType有误!"}) 123 | for _post_event_type in event_type: 124 | if _post_event_type not in MonitorEventTypeConstant.lst(): 125 | return JsonResponse({"code": 1003, "message": "eventType有误!"}) 126 | 127 | # 更新数据 128 | with transaction.atomic(): 129 | obj: GeyeMonitorRules = GeyeMonitorRules.instance.select_for_update(). \ 130 | filter(is_deleted=False, pk=params.get("id")).first() 131 | if not obj: 132 | return JsonResponse({"code": 1003, "message": "规则不存在!"}) 133 | 134 | obj.task_type = task_type 135 | obj.event_type = ",".join(event_type) 136 | obj.rule_content = params.get("ruleContent") 137 | obj.status = params.get("status") 138 | obj.interval = params.get("interval") 139 | obj.priority = params.get("priority") 140 | obj.save() 141 | 142 | return JsonResponse({"code": 1001, "message": "更新成功!"}) 143 | 144 | 145 | class DeleteMonitorRuleView(View): 146 | """ 147 | 删除一条 monitor rule 148 | """ 149 | 150 | @staticmethod 151 | def post(request): 152 | rule_id = json.loads(request.body).get("id", None) 153 | if not rule_id or not GeyeMonitorRules.instance.is_pk_exist(rule_id): 154 | return JsonResponse({"code": 1004, "message": "规则不存在!"}) 155 | 156 | obj = GeyeMonitorRules.instance.fake_delete_by_pk(rule_id) 157 | if obj: 158 | return JsonResponse({"code": 1001, "message": "删除成功!"}) 159 | else: 160 | return JsonResponse({"code": 1002, "message": "删除失败!"}) 161 | --------------------------------------------------------------------------------