mirror of https://github.com/MISP/misp-modules
Compare commits
21 Commits
9954d510c5
...
d8d0c8a6cc
Author | SHA1 | Date |
---|---|---|
lgtm-com[bot] | d8d0c8a6cc | |
David Cruciani | 664c2f8a90 | |
David Cruciani | 4426a51193 | |
David Cruciani | 7a31404c7b | |
David Cruciani | 3372ee508e | |
David Cruciani | 2b94f73c15 | |
David Cruciani | ee02bb171b | |
David Cruciani | ba25204ffb | |
David Cruciani | e737605c1b | |
David Cruciani | a2721c967b | |
David Cruciani | 50d6e60074 | |
David Cruciani | b5b42e6807 | |
David Cruciani | 7e3ead7b9e | |
David Cruciani | 10cf1e4a32 | |
David Cruciani | 5a27f3d25d | |
David Cruciani | e1ebd89f69 | |
David Cruciani | 769f7454e2 | |
David Cruciani | 01decb1d44 | |
David Cruciani | 03e4f79a76 | |
David Cruciani | 59a0131880 | |
LGTM Migrator | 7b050c956d |
|
@ -0,0 +1,42 @@
|
|||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
schedule:
|
||||
- cron: "54 22 * * 2"
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ python, javascript ]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
queries: +security-and-quality
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
if: ${{ matrix.language == 'python' || matrix.language == 'javascript' }}
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
with:
|
||||
category: "/language:${{ matrix.language }}"
|
|
@ -1,3 +1,48 @@
|
|||
# MISP-module website
|
||||
|
||||
Use all modules with a dedicate website without any MISP
|
||||
|
||||
![home](https://github.com/MISP/misp-modules/blob/main/website/doc/home_misp_module.png?raw=true)
|
||||
|
||||
![query](https://github.com/MISP/misp-modules/blob/main/website/doc/query_misp_module.png?raw=true)
|
||||
|
||||
## Installation
|
||||
|
||||
**It is strongly recommended to use a virtual environment**
|
||||
|
||||
If you want to know more about virtual environments, [python has you covered](https://docs.python.org/3/tutorial/venv.html)
|
||||
|
||||
```bash
|
||||
sudo apt-get install screen -y
|
||||
pip install -r requirements.txt
|
||||
git submodule init && git submodule update ## Initialize misp-objects submodule
|
||||
python3 app.py -i ## Initialize db
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
Edit `config.py`
|
||||
|
||||
- `SECRET_KEY`: Secret key for the app
|
||||
|
||||
- `FLASK_URL` : url for the instance
|
||||
|
||||
- `FLASK_PORT`: port for the instance
|
||||
|
||||
- `MISP_MODULE`: url and port where misp-module is running
|
||||
|
||||
- `ADMIN_USER`: If True, config page will not be accessible
|
||||
|
||||
- `ADMIN_PASSWORD`: Password for Admin user if `ADMIN_USER` is True
|
||||
|
||||
## Launch
|
||||
|
||||
```bash
|
||||
./launch.sh -l
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Admin user
|
||||
|
||||
If admin user is active, type `/login` in url to access a login page and type the password wrote in `config.py` in `ADMIN_PASSOWRD`.
|
||||
|
|
|
@ -4,6 +4,18 @@ from flask import render_template
|
|||
import os
|
||||
from app.utils.init_modules import create_modules_db
|
||||
|
||||
import signal
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
def signal_handler(sig, frame):
|
||||
path = os.path.join(os.getcwd(), "launch.sh")
|
||||
req = [path, "-ks"]
|
||||
subprocess.call(req)
|
||||
sys.exit(0)
|
||||
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("-i", "--init_db", help="Initialise the db if it not exist", action="store_true")
|
||||
|
|
|
@ -3,6 +3,7 @@ from flask_sqlalchemy import SQLAlchemy
|
|||
from flask_wtf import CSRFProtect
|
||||
from flask_migrate import Migrate
|
||||
from flask_session import Session
|
||||
from flask_login import LoginManager
|
||||
|
||||
from config import config as Config
|
||||
import os
|
||||
|
@ -11,7 +12,8 @@ import os
|
|||
db = SQLAlchemy()
|
||||
csrf = CSRFProtect()
|
||||
migrate = Migrate()
|
||||
sess = Session()
|
||||
session = Session()
|
||||
login_manager = LoginManager()
|
||||
|
||||
def create_app():
|
||||
app = Flask(__name__)
|
||||
|
@ -25,12 +27,16 @@ def create_app():
|
|||
csrf.init_app(app)
|
||||
migrate.init_app(app, db, render_as_batch=True)
|
||||
app.config["SESSION_SQLALCHEMY"] = db
|
||||
sess.init_app(app)
|
||||
session.init_app(app)
|
||||
login_manager.login_view = "account.login"
|
||||
login_manager.init_app(app)
|
||||
|
||||
from .home import home_blueprint
|
||||
from .history.history import history_blueprint
|
||||
from .account.account import account_blueprint
|
||||
app.register_blueprint(home_blueprint, url_prefix="/")
|
||||
app.register_blueprint(history_blueprint, url_prefix="/")
|
||||
app.register_blueprint(account_blueprint, url_prefix="/")
|
||||
|
||||
return app
|
||||
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
from ..db_class.db import User
|
||||
from flask import Blueprint, render_template, redirect, url_for, request, flash
|
||||
from .form import LoginForm
|
||||
from flask_login import (
|
||||
login_required,
|
||||
login_user,
|
||||
logout_user,
|
||||
current_user
|
||||
)
|
||||
from ..utils.utils import admin_password
|
||||
from ..db_class.db import User
|
||||
from .. import db
|
||||
|
||||
account_blueprint = Blueprint(
|
||||
'account',
|
||||
__name__,
|
||||
template_folder='templates',
|
||||
static_folder='static'
|
||||
)
|
||||
|
||||
@account_blueprint.route('/login', methods=['GET', 'POST'])
|
||||
def login():
|
||||
"""Log in an existing user."""
|
||||
form = LoginForm()
|
||||
if form.validate_on_submit():
|
||||
if form.password.data == str(admin_password()):
|
||||
user = User(email="admin@admin.admin")
|
||||
db.session.add(user)
|
||||
db.session.commit()
|
||||
login_user(user, form.remember_me.data)
|
||||
flash('You are now logged in. Welcome back!', 'success')
|
||||
return redirect(request.args.get('next') or "/")
|
||||
else:
|
||||
flash('Invalid password.', 'error')
|
||||
return render_template('account/login.html', form=form)
|
||||
|
||||
@account_blueprint.route('/logout')
|
||||
@login_required
|
||||
def logout():
|
||||
User.query.filter_by(id=current_user.id).delete()
|
||||
logout_user()
|
||||
|
||||
flash('You have been logged out.', 'info')
|
||||
return redirect(url_for('home.home'))
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
from flask_wtf import FlaskForm
|
||||
from wtforms.fields import (
|
||||
BooleanField,
|
||||
PasswordField,
|
||||
SubmitField
|
||||
)
|
||||
from wtforms.validators import InputRequired
|
||||
|
||||
|
||||
class LoginForm(FlaskForm):
|
||||
password = PasswordField('Password', validators=[InputRequired()])
|
||||
remember_me = BooleanField('Keep me logged in')
|
||||
submit = SubmitField('Log in')
|
|
@ -1,5 +1,6 @@
|
|||
import json
|
||||
from .. import db
|
||||
from .. import db, login_manager
|
||||
from flask_login import UserMixin, AnonymousUserMixin
|
||||
|
||||
|
||||
class Module(db.Model):
|
||||
|
@ -76,3 +77,30 @@ class Module_Config(db.Model):
|
|||
config_id = db.Column(db.Integer, index=True)
|
||||
value = db.Column(db.String, index=True)
|
||||
|
||||
|
||||
class User(UserMixin, db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
||||
first_name = db.Column(db.String(64), index=True)
|
||||
last_name = db.Column(db.String(64), index=True)
|
||||
email = db.Column(db.String(64), unique=True, index=True)
|
||||
|
||||
def to_json(self):
|
||||
return {
|
||||
"id": self.id,
|
||||
"first_name": self.first_name,
|
||||
"last_name": self.last_name,
|
||||
"email": self.email
|
||||
}
|
||||
|
||||
class AnonymousUser(AnonymousUserMixin):
|
||||
def is_admin(self):
|
||||
return False
|
||||
|
||||
def read_only(self):
|
||||
return True
|
||||
|
||||
login_manager.anonymous_user = AnonymousUser
|
||||
|
||||
@login_manager.user_loader
|
||||
def load_user(user_id):
|
||||
return User.query.get(int(user_id))
|
|
@ -1,6 +1,7 @@
|
|||
import json
|
||||
from flask import Flask, Blueprint, render_template, request, jsonify
|
||||
from flask import Flask, Blueprint, render_template, request, jsonify, session as sess
|
||||
from . import history_core as HistoryModel
|
||||
from ..utils.utils import admin_user_active
|
||||
|
||||
history_blueprint = Blueprint(
|
||||
'history',
|
||||
|
@ -13,6 +14,7 @@ history_blueprint = Blueprint(
|
|||
@history_blueprint.route("/history", methods=["GET"])
|
||||
def history():
|
||||
"""View all history"""
|
||||
sess["admin_user"] = admin_user_active()
|
||||
return render_template("history.html")
|
||||
|
||||
@history_blueprint.route("/get_history", methods=["GET"])
|
||||
|
@ -25,6 +27,7 @@ def get_history():
|
|||
@history_blueprint.route("/history_session", methods=["GET"])
|
||||
def history_session():
|
||||
"""View all history"""
|
||||
sess["admin_user"] = admin_user_active()
|
||||
return render_template("history_session.html", tree_view=False)
|
||||
|
||||
@history_blueprint.route("/get_history_session", methods=["GET"])
|
||||
|
@ -49,6 +52,7 @@ def save_history(sid):
|
|||
@history_blueprint.route("/history_tree", methods=["GET"])
|
||||
def history_tree():
|
||||
"""View all history"""
|
||||
sess["admin_user"] = admin_user_active()
|
||||
return render_template("history_session.html", tree_view=True)
|
||||
|
||||
@history_blueprint.route("/get_history_tree", methods=["GET"])
|
||||
|
|
|
@ -134,13 +134,15 @@ def get_history_tree():
|
|||
|
||||
def get_history_tree_uuid(history_uuid):
|
||||
history_tree = History_Tree.query.filter_by(session_uuid=history_uuid).first()
|
||||
tree = json.loads(history_tree.tree)
|
||||
loc_session = get_session(history_tree.session_uuid)
|
||||
loc_json = loc_session.history_json()
|
||||
loc_json["children"] = list()
|
||||
for child in tree[history_tree.session_uuid]:
|
||||
loc_json["children"].append(util_get_history_tree(child))
|
||||
return loc_json
|
||||
if history_tree:
|
||||
tree = json.loads(history_tree.tree)
|
||||
loc_session = get_session(history_tree.session_uuid)
|
||||
loc_json = loc_session.history_json()
|
||||
loc_json["children"] = list()
|
||||
for child in tree[history_tree.session_uuid]:
|
||||
loc_json["children"].append(util_get_history_tree(child))
|
||||
return loc_json
|
||||
return {}
|
||||
|
||||
|
||||
def util_remove_node_session(node_uuid, parent, parent_path):
|
||||
|
@ -153,14 +155,19 @@ def util_remove_node_session(node_uuid, parent, parent_path):
|
|||
return util_remove_node_session(node_uuid, child, parent_path["children"][i])
|
||||
|
||||
def remove_node_session(node_uuid):
|
||||
for q in sess:
|
||||
if isUUID(q):
|
||||
q_value = sess.get(q)
|
||||
keys_list = list(sess.keys())
|
||||
loc = None
|
||||
for i in range(0, len(keys_list)):
|
||||
if isUUID(keys_list[i]):
|
||||
q_value = sess.get(keys_list[i])
|
||||
if q_value["uuid"] == node_uuid:
|
||||
del sess[q]
|
||||
loc = i
|
||||
break
|
||||
else:
|
||||
if q_value["children"]:
|
||||
return util_remove_node_session(node_uuid, q_value, sess[q])
|
||||
return util_remove_node_session(node_uuid, q_value, sess[keys_list[i]])
|
||||
if loc:
|
||||
del sess[keys_list[i]]
|
||||
|
||||
|
||||
|
||||
|
@ -181,8 +188,7 @@ def remove_node_tree(node_uuid):
|
|||
tree = json.loads(history_tree.tree)
|
||||
for e in tree:
|
||||
if e == node_uuid:
|
||||
del tree[e]
|
||||
history_tree.tree = json.dumps(tree)
|
||||
db.session.delete(history_tree)
|
||||
db.session.commit()
|
||||
return
|
||||
else:
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import json
|
||||
from flask import Flask, Blueprint, render_template, request, jsonify
|
||||
from flask import Blueprint, render_template, request, jsonify, session as sess
|
||||
from flask_login import current_user
|
||||
from . import session_class as SessionModel
|
||||
from . import home_core as HomeModel
|
||||
from . import session as SessionModel
|
||||
from .utils.utils import admin_user_active
|
||||
|
||||
home_blueprint = Blueprint(
|
||||
'home',
|
||||
|
@ -13,10 +15,14 @@ home_blueprint = Blueprint(
|
|||
|
||||
@home_blueprint.route("/")
|
||||
def home():
|
||||
sess["admin_user"] = admin_user_active()
|
||||
if "query" in request.args:
|
||||
return render_template("home.html", query=request.args.get("query"))
|
||||
return render_template("home.html")
|
||||
|
||||
@home_blueprint.route("/home/<sid>", methods=["GET", "POST"])
|
||||
def home_query(sid):
|
||||
sess["admin_user"] = admin_user_active()
|
||||
if "query" in request.args:
|
||||
query = request.args.get("query")
|
||||
return render_template("home.html", query=query, sid=sid)
|
||||
|
@ -24,6 +30,7 @@ def home_query(sid):
|
|||
|
||||
@home_blueprint.route("/query/<sid>")
|
||||
def query(sid):
|
||||
sess["admin_user"] = admin_user_active()
|
||||
session = HomeModel.get_session(sid)
|
||||
flag=False
|
||||
if session:
|
||||
|
@ -46,6 +53,31 @@ def query(sid):
|
|||
|
||||
|
||||
|
||||
@home_blueprint.route("/get_query_info/<sid>")
|
||||
def get_query_info(sid):
|
||||
"""Return info for a query"""
|
||||
session = HomeModel.get_session(sid)
|
||||
flag=False
|
||||
if session:
|
||||
flag = True
|
||||
query_loc = session.query_enter
|
||||
else:
|
||||
for s in SessionModel.sessions:
|
||||
if s.uuid == sid:
|
||||
flag = True
|
||||
query_loc = s.query
|
||||
session=s
|
||||
if flag:
|
||||
loc_dict = {
|
||||
"query": query_loc,
|
||||
"input_query": session.input_query,
|
||||
"modules": json.loads(session.modules_list),
|
||||
"query_date": session.query_date.strftime('%Y-%m-%d %H:%M')
|
||||
}
|
||||
return loc_dict
|
||||
return {"message": "Session not found"}, 404
|
||||
|
||||
|
||||
@home_blueprint.route("/get_modules")
|
||||
def get_modules():
|
||||
"""Return all modules available"""
|
||||
|
@ -68,9 +100,12 @@ def get_list_misp_attributes():
|
|||
def run_modules():
|
||||
"""Run modules"""
|
||||
if "query" in request.json:
|
||||
if "input" in request.json:
|
||||
if "input" in request.json and request.json["input"]:
|
||||
if "modules" in request.json:
|
||||
session = SessionModel.Session_class(request.json)
|
||||
if "query_as_same" in request.json:
|
||||
session = SessionModel.Session_class(request.json, query_as_same=True, parent_id=request.json["parent_id"])
|
||||
else:
|
||||
session = SessionModel.Session_class(request.json)
|
||||
HomeModel.set_flask_session(session, request.json["parent_id"])
|
||||
session.start()
|
||||
SessionModel.sessions.append(session)
|
||||
|
@ -105,40 +140,74 @@ def result(sid):
|
|||
|
||||
|
||||
|
||||
@home_blueprint.route("/download/<sid>")
|
||||
def download(sid):
|
||||
"""Download a module result as json"""
|
||||
sess = HomeModel.get_session(sid)
|
||||
if "module" in request.args:
|
||||
if sess:
|
||||
loc = json.loads(sess.result)
|
||||
module = request.args.get("module")
|
||||
if module in loc:
|
||||
return jsonify(loc[module]), 200, {'Content-Disposition': f'attachment; filename={sess.query_enter.replace(".", "_")}-{module}.json'}
|
||||
return {"message": "Module not in result", "toast_class": "danger-subtle"}, 400
|
||||
else:
|
||||
for s in SessionModel.sessions:
|
||||
if s.uuid == sid:
|
||||
module = request.args.get("module")
|
||||
if module in s.result:
|
||||
return jsonify(s.result[module]), 200, {'Content-Disposition': f'attachment; filename={s.query}-{module}.json'}
|
||||
return {"message": "Module not in result", "toast_class": "danger-subtle"}, 400
|
||||
return {"message": "Session not found", 'toast_class': "danger-subtle"}, 404
|
||||
return {"message": "Need to pass a module", "toast_class": "warning-subtle"}, 400
|
||||
|
||||
|
||||
|
||||
|
||||
@home_blueprint.route("/modules_config")
|
||||
def modules_config():
|
||||
"""List all modules for configuration"""
|
||||
|
||||
return render_template("modules_config.html")
|
||||
sess["admin_user"] = admin_user_active()
|
||||
if sess.get("admin_user"):
|
||||
if current_user.is_authenticated:
|
||||
return render_template("modules_config.html")
|
||||
return render_template("404.html")
|
||||
|
||||
@home_blueprint.route("/modules_config_data")
|
||||
def modules_config_data():
|
||||
"""List all modules for configuration"""
|
||||
|
||||
modules_config = HomeModel.get_modules_config()
|
||||
return modules_config, 200
|
||||
sess["admin_user"] = admin_user_active()
|
||||
if sess.get("admin_user"):
|
||||
if current_user.is_authenticated:
|
||||
modules_config = HomeModel.get_modules_config()
|
||||
return modules_config, 200
|
||||
return {"message": "Permission denied"}, 403
|
||||
|
||||
|
||||
@home_blueprint.route("/change_config", methods=["POST"])
|
||||
def change_config():
|
||||
"""Change configuation for a module"""
|
||||
if "module_name" in request.json["result_dict"]:
|
||||
res = HomeModel.change_config_core(request.json["result_dict"])
|
||||
if res:
|
||||
return {'message': 'Config changed', 'toast_class': "success-subtle"}, 200
|
||||
return {'message': 'Something went wrong', 'toast_class': "danger-subtle"}, 400
|
||||
return {'message': 'Need to pass "module_name"', 'toast_class': "warning-subtle"}, 400
|
||||
sess["admin_user"] = admin_user_active()
|
||||
if sess.get("admin_user"):
|
||||
if current_user.is_authenticated:
|
||||
if "module_name" in request.json["result_dict"]:
|
||||
res = HomeModel.change_config_core(request.json["result_dict"])
|
||||
if res:
|
||||
return {'message': 'Config changed', 'toast_class': "success-subtle"}, 200
|
||||
return {'message': 'Something went wrong', 'toast_class': "danger-subtle"}, 400
|
||||
return {'message': 'Need to pass "module_name"', 'toast_class': "warning-subtle"}, 400
|
||||
return {'message': 'Permission denied', 'toast_class': "danger-subtle"}, 403
|
||||
|
||||
@home_blueprint.route("/change_status", methods=["GET"])
|
||||
def change_status():
|
||||
"""Change the status of a module, active or unactive"""
|
||||
if "module_id" in request.args:
|
||||
res = HomeModel.change_status_core(request.args.get("module_id"))
|
||||
if res:
|
||||
return {'message': 'Module status changed', 'toast_class': "success-subtle"}, 200
|
||||
return {'message': 'Something went wrong', 'toast_class': "danger-subtle"}, 400
|
||||
return {'message': 'Need to pass "module_id"', 'toast_class': "warning-subtle"}, 400
|
||||
|
||||
sess["admin_user"] = admin_user_active()
|
||||
if sess.get("admin_user"):
|
||||
if current_user.is_authenticated:
|
||||
if "module_id" in request.args:
|
||||
res = HomeModel.change_status_core(request.args.get("module_id"))
|
||||
if res:
|
||||
return {'message': 'Module status changed', 'toast_class': "success-subtle"}, 200
|
||||
return {'message': 'Something went wrong', 'toast_class': "danger-subtle"}, 400
|
||||
return {'message': 'Need to pass "module_id"', 'toast_class': "warning-subtle"}, 400
|
||||
return {'message': 'Permission denied', 'toast_class': "danger-subtle"}, 403
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import json
|
||||
from .utils.utils import query_get_module, isUUID
|
||||
from .utils.utils import query_get_module
|
||||
from . import db
|
||||
from .db_class.db import History, Module, Config, Module_Config, Session_db, History_Tree
|
||||
from flask import session as sess
|
||||
|
@ -148,6 +148,29 @@ def get_history():
|
|||
|
||||
|
||||
|
||||
def create_new_session_tree(current_session, parent_id):
|
||||
loc_session = get_session(parent_id)
|
||||
loc_json = {
|
||||
"uuid": loc_session.uuid,
|
||||
"modules": json.loads(loc_session.modules_list),
|
||||
"query": loc_session.query_enter,
|
||||
"input": loc_session.input_query,
|
||||
"query_date": loc_session.query_date.strftime('%Y-%m-%d %H:%M'),
|
||||
"config": json.loads(loc_session.config_module)
|
||||
}
|
||||
loc_json_child = {
|
||||
"uuid": current_session.uuid,
|
||||
"modules": current_session.modules_list,
|
||||
"query": current_session.query,
|
||||
"input": current_session.input_query,
|
||||
"query_date": current_session.query_date.strftime('%Y-%m-%d'),
|
||||
"config": current_session.config_module,
|
||||
"children": []
|
||||
}
|
||||
|
||||
sess["current_query"] = loc_session.uuid
|
||||
sess[sess.get("current_query")] = loc_json
|
||||
sess[sess.get("current_query")]["children"] = [loc_json_child]
|
||||
|
||||
def util_set_flask_session(parent_id, loc_session, current_session):
|
||||
if parent_id == loc_session["uuid"]:
|
||||
|
@ -156,7 +179,8 @@ def util_set_flask_session(parent_id, loc_session, current_session):
|
|||
"modules": current_session.modules_list,
|
||||
"query": current_session.query,
|
||||
"input": current_session.input_query,
|
||||
"query_date": current_session.query_date.strftime('%Y-%m-%d')
|
||||
"query_date": current_session.query_date.strftime('%Y-%m-%d %H:%M'),
|
||||
"config": current_session.config_module
|
||||
}
|
||||
loc_session["children"].append(loc_json)
|
||||
return True
|
||||
|
@ -172,23 +196,14 @@ def deep_explore(session_dict, parent_id, current_session):
|
|||
return False
|
||||
|
||||
def set_flask_session(current_session, parent_id):
|
||||
current_query = sess.get("current_query")
|
||||
if not current_query or current_query not in sess:
|
||||
loc_json = {
|
||||
"uuid": current_session.uuid,
|
||||
"modules": current_session.modules_list,
|
||||
"query": current_session.query,
|
||||
"input": current_session.input_query,
|
||||
"query_date": current_session.query_date.strftime('%Y-%m-%d')
|
||||
}
|
||||
|
||||
sess["current_query"] = current_session.uuid
|
||||
sess[sess.get("current_query")] = loc_json
|
||||
sess[sess.get("current_query")]["children"] = list()
|
||||
else:
|
||||
# sess["uuid"]
|
||||
loc_session = sess.get(sess.get("current_query"))
|
||||
if not "children" in loc_session:
|
||||
loc_session["children"] = list()
|
||||
if not util_set_flask_session(parent_id, loc_session, current_session):
|
||||
sess["current_query"] = current_session.uuid
|
||||
if parent_id:
|
||||
current_query = sess.get("current_query")
|
||||
if not current_query or current_query not in sess:
|
||||
create_new_session_tree(current_session, parent_id)
|
||||
else:
|
||||
# sess["uuid"]
|
||||
loc_session = sess.get(sess.get("current_query"))
|
||||
if not "children" in loc_session:
|
||||
loc_session["children"] = list()
|
||||
if not util_set_flask_session(parent_id, loc_session, current_session):
|
||||
create_new_session_tree(current_session, parent_id)
|
||||
|
|
|
@ -3,16 +3,17 @@ import json
|
|||
from queue import Queue
|
||||
from threading import Thread
|
||||
from uuid import uuid4
|
||||
from .utils.utils import query_post_query, query_get_module
|
||||
from .utils.utils import query_post_query, query_get_module, get_object
|
||||
from . import home_core as HomeModel
|
||||
import uuid
|
||||
from . import db
|
||||
from .db_class.db import History, History_Tree, Session_db
|
||||
from flask import session as sess
|
||||
|
||||
sessions = list()
|
||||
|
||||
class Session_class:
|
||||
def __init__(self, request_json) -> None:
|
||||
def __init__(self, request_json, query_as_same=False, parent_id=None) -> None:
|
||||
self.uuid = str(uuid4())
|
||||
self.thread_count = 4
|
||||
self.jobs = Queue(maxsize=0)
|
||||
|
@ -24,20 +25,41 @@ class Session_class:
|
|||
self.input_query = request_json["input"]
|
||||
self.modules_list = request_json["modules"]
|
||||
self.nb_errors = 0
|
||||
self.config_module = self.config_module_setter(request_json)
|
||||
self.config_module = self.config_module_setter(request_json, query_as_same, parent_id)
|
||||
self.query_date = datetime.datetime.now(tz=datetime.timezone.utc)
|
||||
|
||||
|
||||
def config_module_setter(self, request_json):
|
||||
def util_config_as_same(self, child, parent_id):
|
||||
if child["uuid"] == parent_id:
|
||||
return child["config"]
|
||||
elif "children" in child:
|
||||
for c in child["children"]:
|
||||
return self.util_config_as_same(c, parent_id)
|
||||
|
||||
|
||||
def config_module_setter(self, request_json, query_as_same, parent_id):
|
||||
"""Setter for config for all modules used"""
|
||||
for query in self.modules_list:
|
||||
if not query in request_json["config"]:
|
||||
request_json["config"][query] = {}
|
||||
module = HomeModel.get_module_by_name(query)
|
||||
mcs = HomeModel.get_module_config_module(module.id)
|
||||
for mc in mcs:
|
||||
config_db = HomeModel.get_config(mc.config_id)
|
||||
request_json["config"][query][config_db.name] = mc.value
|
||||
flag = False
|
||||
if query_as_same:
|
||||
current_query_val = sess.get(sess.get("current_query"))
|
||||
if current_query_val:
|
||||
if current_query_val["uuid"] == parent_id:
|
||||
return current_query_val["config"]
|
||||
else:
|
||||
for child in current_query_val["children"]:
|
||||
res = self.util_config_as_same(child, parent_id)
|
||||
if res:
|
||||
flag = True
|
||||
return res
|
||||
if not flag:
|
||||
for query in self.modules_list:
|
||||
if not query in request_json["config"]:
|
||||
request_json["config"][query] = {}
|
||||
module = HomeModel.get_module_by_name(query)
|
||||
mcs = HomeModel.get_module_config_module(module.id)
|
||||
for mc in mcs:
|
||||
config_db = HomeModel.get_config(mc.config_id)
|
||||
request_json["config"][query][config_db.name] = mc.value
|
||||
return request_json["config"]
|
||||
|
||||
def start(self):
|
||||
|
@ -109,6 +131,20 @@ class Session_class:
|
|||
else:
|
||||
send_to = {"module": work[1], self.input_query: self.query, "config": loc_config}
|
||||
res = query_post_query(send_to)
|
||||
|
||||
## Sort attr in object by ui-priority
|
||||
if "results" in res:
|
||||
if "Object" in res["results"]:
|
||||
for obj in res["results"]["Object"]:
|
||||
loc_obj = get_object(obj["name"])
|
||||
if loc_obj:
|
||||
for attr in obj["Attribute"]:
|
||||
attr["ui-priority"] = loc_obj["attributes"][attr["object_relation"]]["ui-priority"]
|
||||
|
||||
# After adding 'ui-priority'
|
||||
obj["Attribute"].sort(key=lambda x: x["ui-priority"], reverse=True)
|
||||
|
||||
|
||||
# print(res)
|
||||
if "error" in res:
|
||||
self.nb_errors += 1
|
|
@ -6,7 +6,10 @@ body {
|
|||
background-color: #fbfbfb;
|
||||
}
|
||||
|
||||
|
||||
main
|
||||
{
|
||||
overflow-x: hidden;
|
||||
}
|
||||
span#goTop{
|
||||
position: fixed;
|
||||
right: 1em;
|
||||
|
|
|
@ -56,7 +56,7 @@ export default {
|
|||
</li>
|
||||
<li class="list-group-item">
|
||||
<h5 style="color: brown"><u>Modules</u></h5>
|
||||
<template v-for="module in history.modules">[[module]],</template>
|
||||
[[history.modules.join(", ")]]
|
||||
</li>
|
||||
</ul>
|
||||
</a>
|
||||
|
@ -77,7 +77,7 @@ export default {
|
|||
<br>
|
||||
<p class="mb-1" style="color: #2000ff;"><u>Modules</u>:</p>
|
||||
<div>
|
||||
<template v-for="module in history.modules">[[module]],</template>
|
||||
[[history.modules.join(", ")]]
|
||||
</div>
|
||||
<div></div>
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
function parseMispObject(misp_object, query_url, functionToCall){
|
||||
|
||||
function generate(misp_object, query_url, functionToCall){
|
||||
let $container = $("<div>")
|
||||
misp_object.Attribute.forEach(function (v, i) {
|
||||
let $query = $("<a>")
|
||||
let $query_same = null
|
||||
|
||||
if(v.type != 'counter' && v.type != 'datetime'){
|
||||
if(query_url){
|
||||
$query=$("<a>").attr("href", query_url+v.value).text("query").css("margin-left", "10px")
|
||||
}
|
||||
// `_${functionToCall.name}('${v.value}')` refer to 'window._query_as_same = query_as_same' in my vue file
|
||||
$query_same = $("<button>").attr({"onclick": `_${functionToCall.name}('${v.value}')`,
|
||||
"title": "Query this value with the same attribute and modules as the main query",
|
||||
"class": "btn btn-link"
|
||||
})
|
||||
.text("query as same")
|
||||
.css({"margin-left": "10px", "padding": "0", "--bs-btn-border-width": "0"})
|
||||
}
|
||||
|
||||
$container.append(
|
||||
$("<div>").css("margin-top", "10px").append(
|
||||
$("<h6>").append($("<u>").text(v.object_relation)),
|
||||
$("<div>").css("display", "flex").append(
|
||||
$("<div>").css({
|
||||
"border-left": "2px solid grey",
|
||||
"border-bottom": "2px solid grey",
|
||||
"width": "15px",
|
||||
"height": "15px",
|
||||
"display": "flex",
|
||||
"margin-left": "0.5em",
|
||||
}),
|
||||
$("<div>").text("Type: "+ v.type)
|
||||
),
|
||||
$("<div>").css("display", "flex").append(
|
||||
$("<div>").css({
|
||||
"border-left": "2px solid grey",
|
||||
"border-bottom": "2px solid grey",
|
||||
"width": "15px",
|
||||
"height": "15px",
|
||||
"display": "flex",
|
||||
"margin-left": "0.5em",
|
||||
}),
|
||||
$("<div>").text("Value: "+ v.value),
|
||||
$query,
|
||||
$query_same
|
||||
)
|
||||
)
|
||||
)
|
||||
});
|
||||
return $container
|
||||
}
|
||||
|
||||
var $mainContainer = $('<div>')
|
||||
let first_elem = $("<div>").css({"display": "flex", "align-items": "baseline"}).append(
|
||||
$("<i>").attr({"class": "fa-solid fa-cube", "title": "MISP Object"}),
|
||||
$('<h4>').css("margin-left", "5px").append(
|
||||
$("<small>").text(misp_object.name)
|
||||
)
|
||||
)
|
||||
$mainContainer.append(first_elem)
|
||||
$mainContainer.append(generate(misp_object, query_url, functionToCall))
|
||||
$mainContainer.append($("<hr>"))
|
||||
return $mainContainer
|
||||
}
|
||||
|
||||
function parseMispAttr(misp_attr, misp_types, key, query_url, query_as_same){
|
||||
let $query = $("<a>")
|
||||
let $query_same = null
|
||||
|
||||
if(!misp_types.includes('counter') && !misp_types.includes('datetime') ){
|
||||
if(query_url){
|
||||
$query=$("<a>").attr("href", query_url+misp_attr).text("query").css("margin-left", "10px")
|
||||
}
|
||||
// `_${functionToCall.name}('${misp_attr}')` refer to 'window._query_as_same = query_as_same' in my vue file
|
||||
$query_same = $("<button>").attr({"onclick": `_${query_as_same.name}('${misp_attr}')`,
|
||||
"title": "Query this value with the same attribute and modules as the main query",
|
||||
"class": "btn btn-link"
|
||||
})
|
||||
.text("query as same")
|
||||
.css({"margin-left": "10px", "padding": "0", "--bs-btn-border-width": "0"})
|
||||
}
|
||||
|
||||
|
||||
var $mainContainer = $('<div>')
|
||||
let cp = key+1
|
||||
$mainContainer.append($("<h6>").append($("<u>").text("#Attr "+cp)))
|
||||
$mainContainer.append($("<div>").css("display", "flex").append(
|
||||
$("<div>").css({
|
||||
"border-left": "2px solid grey",
|
||||
"border-bottom": "2px solid grey",
|
||||
"width": "15px",
|
||||
"height": "15px",
|
||||
"display": "flex",
|
||||
"margin-left": "0.5em",
|
||||
}),
|
||||
$("<div>").text("Type: "+ misp_types.join(", "))
|
||||
)
|
||||
)
|
||||
|
||||
$mainContainer.append($("<div>").css("display", "flex").append(
|
||||
$("<div>").css({
|
||||
"border-left": "2px solid grey",
|
||||
"border-bottom": "2px solid grey",
|
||||
"width": "15px",
|
||||
"height": "15px",
|
||||
"display": "flex",
|
||||
"margin-left": "0.5em",
|
||||
}),
|
||||
$("<div>").text("Value: "+ misp_attr),
|
||||
$query,
|
||||
$query_same
|
||||
)
|
||||
)
|
||||
|
||||
$mainContainer.append($("<hr>"))
|
||||
return $mainContainer
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
<!--
|
||||
Author: David Cruciani
|
||||
-->
|
||||
{% import 'macros/form_macros.html' as f %}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Flowintel-cm</title>
|
||||
<script src="{{ url_for('static',filename='js/popper.min.js') }}"></script>
|
||||
<script src="{{ url_for('static',filename='bootstrap-5.3.0/js/bootstrap.min.js') }}"></script>
|
||||
<script src="{{ url_for('static',filename='js/jquery.min.js') }}"></script>
|
||||
<script src="{{ url_for('static',filename='js/jquery-ui.js') }}"></script>
|
||||
<script src="{{ url_for('static',filename='js/vue.global.js') }}"></script>
|
||||
|
||||
<link rel= "stylesheet" type= "text/css" href= "{{ url_for('static',filename='bootstrap-5.3.0/css/bootstrap.min.css') }}">
|
||||
<link rel= "stylesheet" type= "text/css" href= "{{ url_for('static',filename='fontawesome-6.3.0/css/fontawesome.css') }}">
|
||||
<link rel= "stylesheet" type= "text/css" href= "{{ url_for('static',filename='fontawesome-6.3.0/css/solid.css') }}">
|
||||
<link rel= "stylesheet" type= "text/css" href= "{{ url_for('static',filename='css/jquery-ui.css') }}">
|
||||
|
||||
<style>
|
||||
.bd-placeholder-img {
|
||||
font-size: 1.125rem;
|
||||
text-anchor: middle;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.bd-placeholder-img-lg {
|
||||
font-size: 3.5rem;
|
||||
}
|
||||
}
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-top: 40px;
|
||||
padding-bottom: 40px;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.form-signin {
|
||||
width: 100%;
|
||||
max-width: 330px;
|
||||
padding: 15px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.form-signin .checkbox {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.form-signin .form-floating:focus-within {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.form-signin input[type="email"] {
|
||||
margin-bottom: -1px;
|
||||
border-bottom-right-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
.form-signin input[type="password"] {
|
||||
margin-bottom: 10px;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<main class="form-signin">
|
||||
{% include 'macros/_flashes.html' %}
|
||||
{% set flashes = {
|
||||
'error': get_flashed_messages(category_filter=['form-error']),
|
||||
'warning': get_flashed_messages(category_filter=['form-check-email']),
|
||||
'info': get_flashed_messages(category_filter=['form-info']),
|
||||
'success': get_flashed_messages(category_filter=['form-success'])
|
||||
} %}
|
||||
<form action="" method="post">
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="mb-3">
|
||||
{{form.password.label}}:
|
||||
{{form.password(class_="form-control")}}
|
||||
</div>
|
||||
<div class="checkbox mb-3">
|
||||
{{form.remember_me.label}}:
|
||||
{{form.remember_me}}
|
||||
</div>
|
||||
{{ f.form_message(flashes['error'], header='Something went wrong.', class='error') }}
|
||||
{{ f.form_message(flashes['warning'], header='Check your email.', class='warning') }}
|
||||
{{ f.form_message(flashes['info'], header='Information', class='info') }}
|
||||
{{ f.form_message(flashes['success'], header='Success!', class='success') }}
|
||||
{{form.submit(class='btn btn-primary')}}
|
||||
</form>
|
||||
</main>
|
||||
<!--Main layout-->
|
||||
|
||||
{# Implement CSRF protection for site #}
|
||||
{% if csrf_token()|safe %}
|
||||
<div style="visibility: hidden; display: none">
|
||||
<input type="hidden" id="csrf_token" name="csrf_token" value="{{ csrf_token()|safe }}">
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</body>
|
||||
<script>
|
||||
$('.message').each((i, el) => {
|
||||
const $el = $(el);
|
||||
const $xx = $el.find('.close');
|
||||
const sec = $el.data('autohide');
|
||||
const triggerRemove = () => clearTimeout($el.trigger('remove').T);
|
||||
|
||||
$el.one('remove', () => $el.remove());
|
||||
$xx.one('click', triggerRemove);
|
||||
if (sec) $el.T = setTimeout(triggerRemove, sec * 1000);
|
||||
});
|
||||
</script>
|
||||
</html>
|
|
@ -18,6 +18,7 @@
|
|||
<script src="{{ url_for('static',filename='js/utils.js') }}"></script>
|
||||
|
||||
<script src="{{ url_for('static',filename='js/jsonParser.js') }}"></script>
|
||||
<script src="{{ url_for('static',filename='js/mispParser.js') }}"></script>
|
||||
|
||||
<script src="{{ url_for('static',filename='js/dayjs/dayjs.min.js') }}"></script>
|
||||
<script src="{{ url_for('static',filename='js/dayjs/dayjs-utc.js') }}"></script>
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
<br>
|
||||
<p class="mb-1" style="color: #2000ff;"><u>Modules</u>:</p>
|
||||
<div>
|
||||
<template v-for="module in h.modules">[[module]],</template>
|
||||
[[h.modules.join(", ")]]
|
||||
</div>
|
||||
|
||||
|
||||
|
|
|
@ -32,10 +32,14 @@
|
|||
</li>
|
||||
<li class="list-group-item">
|
||||
<h5 style="color: brown"><u>Modules</u></h5>
|
||||
<template v-for="module in his.modules">[[module]],</template>
|
||||
[[his.modules.join(", ")]]
|
||||
</li>
|
||||
</ul>
|
||||
</a>
|
||||
<div style="display: flex; align-items: center; margin-left: 3px">
|
||||
<button v-if="!tree_view" class="btn btn-danger btn-sm" title="Remove this node" @click="remove_node(his, key)"><i class="fa-solid fa-trash"></i></button>
|
||||
<button v-else class="btn btn-danger btn-sm" title="Remove this node" @click="remove_node_tree(his, key)"><i class="fa-solid fa-trash"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="collapse" :id="'collapse'+his.uuid" style="width: 70%; margin-left:30px">
|
||||
|
@ -49,7 +53,7 @@
|
|||
<br>
|
||||
<p class="mb-1" style="color: #2000ff;"><u>Modules</u>:</p>
|
||||
<div>
|
||||
<template v-for="module in his.modules">[[module]],</template>
|
||||
[[his.modules.join(", ")]]
|
||||
</div>
|
||||
<div></div>
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
|
@ -111,17 +115,35 @@
|
|||
display_toast(res)
|
||||
}
|
||||
|
||||
async function remove_node(history_loc, key){
|
||||
const res = await fetch('/history/remove_node_session/' + history_loc.uuid)
|
||||
display_toast(res)
|
||||
await change_tree(history_loc, key)
|
||||
}
|
||||
async function remove_node_tree(history_loc, key){
|
||||
const res = await fetch('/history/remove_node_tree/' + history_loc.uuid)
|
||||
display_toast(res)
|
||||
await change_tree(history_loc, key)
|
||||
}
|
||||
|
||||
async function change_tree(history_loc, key){
|
||||
if(!tree_view){
|
||||
if(!tree_view.value){
|
||||
const res = await fetch("/get_history_session/"+history_loc.uuid)
|
||||
let loc = await res.json()
|
||||
history.value[key] = loc
|
||||
if(!Object.keys(loc).length){
|
||||
history.value.splice(key, key+1)
|
||||
}else{
|
||||
history.value[key] = loc
|
||||
}
|
||||
}else{
|
||||
const res = await fetch("/get_history_tree/"+history_loc.uuid)
|
||||
let loc = await res.json()
|
||||
history.value[key] = loc
|
||||
}
|
||||
|
||||
if(!Object.keys(loc).length){
|
||||
history.value.splice(key, key+1)
|
||||
}else{
|
||||
history.value[key] = loc
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
@ -142,7 +164,9 @@
|
|||
history,
|
||||
tree_view,
|
||||
save_history,
|
||||
change_tree
|
||||
change_tree,
|
||||
remove_node,
|
||||
remove_node_tree
|
||||
}
|
||||
}
|
||||
}).mount('.container-fluid')
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
<input type="hidden" id="parent_id" value="{{sid}}">
|
||||
<input type="text" value="{{query}}" id="process-query" placeholder="Enter here..." autofocus class="form-control" style="border-radius: 5px;" />
|
||||
</div>
|
||||
<span v-if="status_site" id="status">[[status_site]]</span>
|
||||
<span v-if="status_site" style="color: brown;" id="status">[[status_site]]</span>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
@ -48,7 +48,7 @@
|
|||
<h4>Modules</h4>
|
||||
<select data-placeholder="Modules" class="select2-modules form-control" multiple name="modules_select" id="modules_select">
|
||||
<template v-for="key in modules_list">
|
||||
<option v-if="key.mispattributes.input.includes(attr_selected)" :value="key.name" :title="key.meta.description">[[key.name]]</option>
|
||||
<option v-if="checked_attr(key.mispattributes.input)" :value="key.name" :title="key.meta.description">[[key.name]]</option>
|
||||
</template>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -105,8 +105,18 @@
|
|||
progress.value = 0
|
||||
let error_flag = false
|
||||
|
||||
let result_dict = {"modules": $("#modules_select").val(),
|
||||
"input": $("#input_select").val(),
|
||||
let loc = undefined
|
||||
if($("#input_select").val() != "None"){
|
||||
loc = $("#input_select").val()
|
||||
}
|
||||
|
||||
let loc_modules = undefined
|
||||
if($("#modules_select").val().length){
|
||||
loc_modules = $("#modules_select").val()
|
||||
}
|
||||
|
||||
let result_dict = {"modules": loc_modules,
|
||||
"input": loc,
|
||||
"query": current_query.value,
|
||||
"parent_id": $("#parent_id").val()
|
||||
}
|
||||
|
@ -222,7 +232,14 @@
|
|||
}
|
||||
|
||||
function checked_attr(arr1){
|
||||
return arr1.includes(attr_selected.value)
|
||||
let loc = arr1.includes(attr_selected.value)
|
||||
if(!loc && attr_selected.value == 'ip'){
|
||||
loc = arr1.includes('ip-dst')
|
||||
if(!loc && attr_selected.value == 'ip'){
|
||||
loc = arr1.includes('ip-src')
|
||||
}
|
||||
}
|
||||
return loc
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -41,10 +41,7 @@
|
|||
<h4>[[ current_config['module_name'] ]]</h4>
|
||||
<i>
|
||||
<small>
|
||||
Attributes:
|
||||
<template v-for="attr in current_config['input_attr']">
|
||||
[[ attr ]],
|
||||
</template>
|
||||
Attributes: [[current_config['input_attr'].join(", ")]]
|
||||
</small>
|
||||
</i>
|
||||
<template v-for="conf, key in current_config">
|
||||
|
|
|
@ -11,7 +11,11 @@
|
|||
<h2>{{query}}</h2>
|
||||
</div>
|
||||
|
||||
<a style="float: right;" class="btn btn-primary" href="/">New query</a>
|
||||
<div class="btn-group" style="float: right;" role="group" aria-label="Basic mixed styles example">
|
||||
<a style="float: right;" class="btn btn-primary" href="/" title="Do a new query with no relation with this one">New query</a>
|
||||
<a style="float: right;" class="btn btn-secondary" href="/?query={{query}}" title="New query with same name">Query</a>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card card-body">
|
||||
<div class="row">
|
||||
|
@ -21,7 +25,7 @@
|
|||
</div>
|
||||
<div class="col">
|
||||
<h4>Modules:</h4>
|
||||
{%for module in modules%} {{module}}, {%endfor%}
|
||||
{{", ".join(modules)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
|
@ -39,7 +43,7 @@
|
|||
|
||||
<br/>
|
||||
|
||||
<button class="btn btn-outline-primary" style="position: fixed; right: 0px; top: 50%" title="Session history" data-bs-toggle="offcanvas" data-bs-target="#offcanvasScrolling" aria-controls="offcanvasScrolling">
|
||||
<button class="btn btn-outline-primary" style="position: fixed; right: 0px; margin-top:30px" title="Session history" data-bs-toggle="offcanvas" data-bs-target="#offcanvasScrolling" aria-controls="offcanvasScrolling">
|
||||
<i class="fa-solid fa-bars"></i>
|
||||
</button>
|
||||
|
||||
|
@ -67,22 +71,118 @@
|
|||
<hr>
|
||||
<ul class="nav nav-tabs" style="margin-bottom: 10px;">
|
||||
<li class="nav-item">
|
||||
<button class="nav-link active" id="tab-json" aria-current="page" @click="active_tab('json')">Json</button>
|
||||
<button class="nav-link active" id="tab-visual" @click="active_tab('visual')">Visual</button>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<button class="nav-link" id="tab-parser" @click="active_tab('parser')">Parser</button>
|
||||
<button class="nav-link" id="tab-json" aria-current="page" @click="active_tab('json')">Json</button>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<button class="nav-link" id="tab-markdown" @click="active_tab('markdown')">Markdown</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<template v-if="tab_list == 'json'">
|
||||
<div class="row" v-if="Object.keys(modules_res).length">
|
||||
<div class="col-10">
|
||||
<h3 id="results_part">Results</h3>
|
||||
<div class="accordion">
|
||||
<div class="accordion-item" v-for="result, key in modules_res">
|
||||
<div class="row" style="margin-bottom: 50px;">
|
||||
<div class="col-10">
|
||||
<template v-if="tab_list == 'visual'">
|
||||
<div data-bs-spy="scroll" data-bs-target="#list-result" data-bs-smooth-scroll="true" class="scrollspy-example" tabindex="0">
|
||||
<div class="accordion" v-if="Object.keys(modules_res).length" style="width: 95%">
|
||||
<div class="accordion-item" :id="'list-item-'+key" v-for="result, key in modules_res">
|
||||
<template v-if="!('error' in result)">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button" data-bs-toggle="collapse" :data-bs-target="'#panelsStayOpen-'+key" aria-expanded="true" :aria-controls="'panelsStayOpen-'+key">
|
||||
[[key]]
|
||||
</button>
|
||||
</h2>
|
||||
<div :id="'panelsStayOpen-'+key" class="accordion-collapse collapse show">
|
||||
<div class="accordion-body" >
|
||||
<template v-if="'Object' in result.results">
|
||||
<template v-for="obj in result.results.Object">
|
||||
<div v-html="parseMispObject(obj, '/home/{{sid}}?query=', query_as_same)[0].outerHTML"></div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<!-- <div class="accordion-body" v-html="generateCoreFormatUI(result)[0].outerHTML"></div> -->
|
||||
<template v-for="misp_attrs, key_loop in result.results">
|
||||
<div v-for="misp_attr in misp_attrs.values" class="accordion-body" v-html="parseMispAttr(misp_attr, misp_attrs.types, key_loop, '/home/{{sid}}?query=', query_as_same)[0].outerHTML"></div>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Errors Part -->
|
||||
<hr style="margin-top: 50px; width: 95%">
|
||||
<h3 id="errors_part">Errors</h3>
|
||||
<div data-bs-spy="scroll" data-bs-target="#list-error" data-bs-smooth-scroll="true" class="scrollspy-example" tabindex="0">
|
||||
<div class="accordion" style="width: 95%">
|
||||
<div class="accordion-item" :id="'list-item-'+key" v-for="result, key in modules_res">
|
||||
<template v-if="'error' in result">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" :data-bs-target="'#panelsStayOpen-'+key" aria-expanded="true" :aria-controls="'panelsStayOpen-'+key">
|
||||
[[key]]
|
||||
<span style="margin-left: 5px;" title="Error">❌</span>
|
||||
</button>
|
||||
</h2>
|
||||
<div :id="'panelsStayOpen-'+key" class="accordion-collapse collapse show">
|
||||
<div class="accordion-body" v-html="generateCoreFormatUI(result)[0].outerHTML"></div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-else-if="tab_list == 'json'">
|
||||
<div v-if="Object.keys(modules_res).length">
|
||||
<h3 id="results_part">Results</h3>
|
||||
<div data-bs-spy="scroll" data-bs-target="#list-result" data-bs-smooth-scroll="true" class="scrollspy-example" tabindex="0">
|
||||
<div class="accordion" style="width: 95%">
|
||||
<div class="accordion-item" :id="'list-item-'+key" v-for="result, key in modules_res">
|
||||
<template v-if="!('error' in result)">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button" data-bs-toggle="collapse" :data-bs-target="'#panelsStayOpen-'+key" aria-expanded="true" :aria-controls="'panelsStayOpen-'+key">
|
||||
[[key]]
|
||||
</button>
|
||||
</h2>
|
||||
<div :id="'panelsStayOpen-'+key" class="accordion-collapse collapse show">
|
||||
<a class="btn btn-primary" :href="`/download/${sid}?module=${key}`" title="Download the json" style="padding: 5px; margin-left: 5px; margin-top: 5px;">Download</a>
|
||||
<div class="accordion-body" v-html="generateCoreFormatUI(result)[0].outerHTML"></div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Errors Part -->
|
||||
<hr style="margin-top: 50px; width: 95%">
|
||||
<h3 id="errors_part">Errors</h3>
|
||||
<div data-bs-spy="scroll" data-bs-target="#list-error" data-bs-smooth-scroll="true" class="scrollspy-example" tabindex="0">
|
||||
<div class="accordion" style="width: 95%">
|
||||
<div class="accordion-item" :id="'list-item-'+key" v-for="result, key in modules_res">
|
||||
<template v-if="'error' in result">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" :data-bs-target="'#panelsStayOpen-'+key" aria-expanded="true" :aria-controls="'panelsStayOpen-'+key">
|
||||
[[key]]
|
||||
<span style="margin-left: 5px;" title="Error">❌</span>
|
||||
</button>
|
||||
</h2>
|
||||
<div :id="'panelsStayOpen-'+key" class="accordion-collapse collapse show">
|
||||
<div class="accordion-body" v-html="generateCoreFormatUI(result)[0].outerHTML"></div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-else-if="tab_list == 'markdown'">
|
||||
<div v-if="Object.keys(modules_res).length" class="accordion" style="width: 95%">
|
||||
<div class="accordion-item" :id="'list-item-'+key" v-for="result, key in modules_res">
|
||||
<template v-if="!('error' in result)">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" :data-bs-target="'#panelsStayOpen-'+key" aria-expanded="true" :aria-controls="'panelsStayOpen-'+key">
|
||||
|
@ -90,102 +190,56 @@
|
|||
</button>
|
||||
</h2>
|
||||
<div :id="'panelsStayOpen-'+key" class="accordion-collapse collapse show">
|
||||
<div class="accordion-body" v-html="generateCoreFormatUI(result)[0].outerHTML"></div>
|
||||
<div class="accordion-body row">
|
||||
<template v-if="'Object' in result.results">
|
||||
<template v-for="obj, key_obj in result.results.Object">
|
||||
<pre>
|
||||
#### [[obj.name]]
|
||||
<template v-for="attr, key_attr in obj.Attribute">
|
||||
###### [[attr.object_relation]]
|
||||
Type: [[attr.type]]
|
||||
Value: [[attr.value]]
|
||||
</template>
|
||||
</pre>
|
||||
<hr>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-for="misp_attrs, key_loop in result.results">
|
||||
<template v-for="misp_attr in misp_attrs.values">
|
||||
<pre>
|
||||
#### Attr [[key_loop +1]]
|
||||
Type: [[misp_attrs.types.join(", ")]]
|
||||
Value: [[misp_attr]]
|
||||
</pre>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- Errors Part -->
|
||||
<hr style="margin-top: 50px">
|
||||
<h3 id="errors_part">Errors</h3>
|
||||
<div class="accordion">
|
||||
<div class="accordion-item" v-for="result, key in modules_res">
|
||||
<template v-if="'error' in result">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" :data-bs-target="'#panelsStayOpen-'+key" aria-expanded="true" :aria-controls="'panelsStayOpen-'+key">
|
||||
[[key]]
|
||||
<span style="margin-left: 5px;" title="Error">❌</span>
|
||||
</button>
|
||||
</h2>
|
||||
<div :id="'panelsStayOpen-'+key" class="accordion-collapse collapse show">
|
||||
<div class="accordion-body" v-html="generateCoreFormatUI(result)[0].outerHTML"></div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div id="list-result" class="list-group col-2" style="position: fixed; right: 0px;">
|
||||
<a class="list-group-item list-group-item-action" v-if="tab_list == 'json'" style="background-color: #0d6efd; color:white" href="#results_part">Results</a>
|
||||
|
||||
<template v-for="result, key in modules_res">
|
||||
<a class="list-group-item list-group-item-action" v-if="!('error' in result)" :href="'#list-item-'+key">[[key]]</a>
|
||||
</template>
|
||||
|
||||
<template v-if="tab_list == 'json' || tab_list == 'visual'">
|
||||
<a class="list-group-item list-group-item-action" style="background-color: #0d6efd; color:white" href="#errors_part">Errors</a>
|
||||
<div id="list-error" class="list-group">
|
||||
<template v-for="result, key in modules_res">
|
||||
<a class="list-group-item list-group-item-action" v-if="'error' in result" :href="'#list-item-'+key" style="border-radius: 0;">[[key]]</a>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-1" style="position: fixed; right: 0px; box-shadow: 0 2px 5px 0 rgb(0 0 0 / 5%), 0 2px 10px 0 rgb(0 0 0 / 5%);">
|
||||
<div style="padding: 10px;"><a style="text-decoration: none;" href="#results_part">Results</a></div>
|
||||
<div style="padding: 10px;"><a style="text-decoration: none;" href="#errors_part">Errors</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-else-if="tab_list == 'parser'">
|
||||
<div class="accordion" v-if="Object.keys(modules_res).length" style="width: 95%">
|
||||
<div class="accordion-item" v-for="result, key in modules_res">
|
||||
<template v-if="!('error' in result)">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" :data-bs-target="'#panelsStayOpen-'+key" aria-expanded="true" :aria-controls="'panelsStayOpen-'+key">
|
||||
[[key]]
|
||||
</button>
|
||||
</h2>
|
||||
<div :id="'panelsStayOpen-'+key" class="accordion-collapse collapse show">
|
||||
<div class="accordion-body row">
|
||||
<template v-for="obj, key_obj in result.results.Object">
|
||||
<h4>Object #[[key_obj+1]] - <small>[[obj.name]]</small></h4>
|
||||
<div class="row" style="margin: 5px; padding: 5px;">
|
||||
<div class="col-4 mb-3" style="border: 1px solid #939393; border-radius: 10px;" v-for="attr, key_attr in obj.Attribute">
|
||||
<h6>Attributes #[[key_attr+1]]</h6>
|
||||
<div>
|
||||
Type: [[attr.type]]
|
||||
</div>
|
||||
<div>
|
||||
Value: [[attr.value]]
|
||||
</div>
|
||||
<a v-if="attr.type != 'counter' && attr.type != 'datetime'" :href="'/home/{{sid}}?query='+attr.value">query</a>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-else-if="tab_list == 'markdown'">
|
||||
<div v-if="Object.keys(modules_res).length" class="accordion" style="width: 95%">
|
||||
<div class="accordion-item" v-for="result, key in modules_res">
|
||||
<template v-if="!('error' in result)">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" :data-bs-target="'#panelsStayOpen-'+key" aria-expanded="true" :aria-controls="'panelsStayOpen-'+key">
|
||||
[[key]]
|
||||
</button>
|
||||
</h2>
|
||||
<div :id="'panelsStayOpen-'+key" class="accordion-collapse collapse show">
|
||||
<div class="accordion-body row">
|
||||
<template v-for="obj, key_obj in result.results.Object">
|
||||
<h4>Object #[[key_obj+1]] - <small>[[obj.name]]</small></h4>
|
||||
<div style="margin-bottom: 10px;" v-for="attr, key_attr in obj.Attribute">
|
||||
<h6>Attributes #[[key_attr+1]]</h6>
|
||||
<div>
|
||||
Type: [[attr.type]]
|
||||
</div>
|
||||
<div>
|
||||
Value: [[attr.value]]
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span id="goTop">[<a href="#top">Go Back Top</a>]</span>
|
||||
{% endblock %}
|
||||
|
@ -208,16 +262,23 @@
|
|||
const modules_res = ref({})
|
||||
const progress = ref(0)
|
||||
const status_site = ref()
|
||||
const tab_list = ref("json")
|
||||
const tab_list = ref("visual")
|
||||
const history = ref({})
|
||||
const query_info = ref({})
|
||||
|
||||
|
||||
function actionQuery(){
|
||||
is_searching.value = true
|
||||
sid.value = $("#share").val()
|
||||
pollScan();
|
||||
}
|
||||
|
||||
async function queryInfo(){
|
||||
sid.value = $("#share").val()
|
||||
let res = await fetch("/get_query_info/" + sid.value)
|
||||
let loc = await res.json()
|
||||
query_info.value = loc
|
||||
}
|
||||
|
||||
function pollScan() {
|
||||
// Loop function to update the list of identified domains
|
||||
$.getJSON('/status/' + sid.value, function(data) {
|
||||
|
@ -254,13 +315,13 @@
|
|||
tab_list.value = "json"
|
||||
if ( !document.getElementById("tab-json").classList.contains("active") ){
|
||||
document.getElementById("tab-json").classList.add("active")
|
||||
document.getElementById("tab-parser").classList.remove("active")
|
||||
document.getElementById("tab-visual").classList.remove("active")
|
||||
document.getElementById("tab-markdown").classList.remove("active")
|
||||
}
|
||||
}else if(active_tab == "parser"){
|
||||
tab_list.value = "parser"
|
||||
if ( !document.getElementById("tab-parser").classList.contains("active") ){
|
||||
document.getElementById("tab-parser").classList.add("active")
|
||||
}else if(active_tab == "visual"){
|
||||
tab_list.value = "visual"
|
||||
if ( !document.getElementById("tab-visual").classList.contains("active") ){
|
||||
document.getElementById("tab-visual").classList.add("active")
|
||||
document.getElementById("tab-json").classList.remove("active")
|
||||
document.getElementById("tab-markdown").classList.remove("active")
|
||||
}
|
||||
|
@ -269,7 +330,7 @@
|
|||
if ( !document.getElementById("tab-markdown").classList.contains("active") ){
|
||||
document.getElementById("tab-markdown").classList.add("active")
|
||||
document.getElementById("tab-json").classList.remove("active")
|
||||
document.getElementById("tab-parser").classList.remove("active")
|
||||
document.getElementById("tab-visual").classList.remove("active")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -280,13 +341,37 @@
|
|||
history.value = loc
|
||||
}
|
||||
|
||||
async function query_as_same(value){
|
||||
let result_dict = {"modules": query_info.value["modules"],
|
||||
"input": query_info.value["input_query"],
|
||||
"query": value,
|
||||
"parent_id": sid.value,
|
||||
"query_as_same": true,
|
||||
"config": {}
|
||||
}
|
||||
const res = await fetch('/run_modules',{
|
||||
headers: { "X-CSRFToken": $("#csrf_token").val(), "Content-Type": "application/json" },
|
||||
method: "POST",
|
||||
body: JSON.stringify(result_dict)
|
||||
})
|
||||
if(await res.status == 201){
|
||||
let loc = await res.json()
|
||||
await nextTick()
|
||||
window.location.href="/query/" + loc['id']
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
queryInfo()
|
||||
actionQuery()
|
||||
get_history_session()
|
||||
window._query_as_same = query_as_same
|
||||
})
|
||||
|
||||
return {
|
||||
message_list,
|
||||
sid,
|
||||
query_info,
|
||||
progress,
|
||||
status_site,
|
||||
is_searching,
|
||||
|
@ -294,7 +379,10 @@
|
|||
tab_list,
|
||||
history,
|
||||
generateCoreFormatUI,
|
||||
active_tab
|
||||
parseMispObject,
|
||||
parseMispAttr,
|
||||
active_tab,
|
||||
query_as_same
|
||||
}
|
||||
}
|
||||
}).mount('.container-fluid')
|
||||
|
|
|
@ -11,18 +11,34 @@
|
|||
<a href="/" class="list-group-item list-group-item-action text-nowrap" aria-current="true">
|
||||
<i class="fa-solid fa-house fa-fw me-3"></i><span>Home</span>
|
||||
</a>
|
||||
<a style="margin-top: 30px;" href="/history" class="list-group-item list-group-item-action text-nowrap">
|
||||
<i class="fa-solid fa-clock-rotate-left fa-fw me-3"></i><span>History</span>
|
||||
</a>
|
||||
{% if session.admin_user %}
|
||||
{% if current_user.is_authenticated %}
|
||||
<a style="margin-top: 30px;" href="/history" class="list-group-item list-group-item-action text-nowrap">
|
||||
<i class="fa-solid fa-clock-rotate-left fa-fw me-3"></i><span>History</span>
|
||||
</a>
|
||||
{%endif%}
|
||||
{%else%}
|
||||
<a style="margin-top: 30px;" href="/history" class="list-group-item list-group-item-action text-nowrap">
|
||||
<i class="fa-solid fa-clock-rotate-left fa-fw me-3"></i><span>History</span>
|
||||
</a>
|
||||
{%endif%}
|
||||
<a style="margin-top: 30px;" href="/history_session" class="list-group-item list-group-item-action text-nowrap">
|
||||
<i class="fa-solid fa-clock fa-fw me-3"></i><span>History Session</span>
|
||||
</a>
|
||||
<a style="margin-top: 30px;" href="/history_tree" class="list-group-item list-group-item-action text-nowrap">
|
||||
<i class="fa-solid fa-timeline fa-fw me-3"></i><span>History Tree</span>
|
||||
</a>
|
||||
<a style="margin-top: 30px;" href="/modules_config" class="list-group-item list-group-item-action text-nowrap">
|
||||
<i class="fa-solid fa-gear fa-fw me-3"></i><span>Config</span>
|
||||
</a>
|
||||
{% if session.admin_user %}
|
||||
{% if current_user.is_authenticated %}
|
||||
<a style="margin-top: 30px;" href="/modules_config" class="list-group-item list-group-item-action text-nowrap">
|
||||
<i class="fa-solid fa-gear fa-fw me-3"></i><span>Config</span>
|
||||
</a>
|
||||
{%endif%}
|
||||
{%else%}
|
||||
<a style="margin-top: 30px;" href="/modules_config" class="list-group-item list-group-item-action text-nowrap">
|
||||
<i class="fa-solid fa-gear fa-fw me-3"></i><span>Config</span>
|
||||
</a>
|
||||
{%endif%}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -7,37 +7,39 @@ from .utils import query_get_module
|
|||
|
||||
def create_modules_db():
|
||||
modules = query_get_module()
|
||||
|
||||
for module in modules:
|
||||
m = Module.query.filter_by(name=module["name"]).first()
|
||||
input_attr = ""
|
||||
if "input" in module["mispattributes"]:
|
||||
input_attr = json.dumps(module["mispattributes"]["input"])
|
||||
if not m:
|
||||
m = Module(
|
||||
name=module["name"],
|
||||
description=module["meta"]["description"],
|
||||
is_active=True,
|
||||
request_on_query=False,
|
||||
input_attr=input_attr
|
||||
)
|
||||
db.session.add(m)
|
||||
db.session.commit()
|
||||
if not "message" in modules:
|
||||
for module in modules:
|
||||
m = Module.query.filter_by(name=module["name"]).first()
|
||||
input_attr = ""
|
||||
if "input" in module["mispattributes"]:
|
||||
input_attr = json.dumps(module["mispattributes"]["input"])
|
||||
if not m:
|
||||
m = Module(
|
||||
name=module["name"],
|
||||
description=module["meta"]["description"],
|
||||
is_active=True,
|
||||
request_on_query=False,
|
||||
input_attr=input_attr
|
||||
)
|
||||
db.session.add(m)
|
||||
db.session.commit()
|
||||
|
||||
|
||||
if "config" in module["meta"]:
|
||||
for conf in module["meta"]["config"]:
|
||||
c = Config.query.filter_by(name=conf).first()
|
||||
if not c:
|
||||
c = Config(
|
||||
name = conf
|
||||
if "config" in module["meta"]:
|
||||
for conf in module["meta"]["config"]:
|
||||
c = Config.query.filter_by(name=conf).first()
|
||||
if not c:
|
||||
c = Config(
|
||||
name = conf
|
||||
)
|
||||
db.session.add(c)
|
||||
db.session.commit()
|
||||
|
||||
mc = Module_Config(
|
||||
module_id=m.id,
|
||||
config_id=c.id
|
||||
)
|
||||
db.session.add(c)
|
||||
db.session.add(mc)
|
||||
db.session.commit()
|
||||
|
||||
mc = Module_Config(
|
||||
module_id=m.id,
|
||||
config_id=c.id
|
||||
)
|
||||
db.session.add(mc)
|
||||
db.session.commit()
|
||||
else:
|
||||
print("[-] Error in misp-modules. It might not running.")
|
|
@ -1,9 +1,10 @@
|
|||
# import os
|
||||
import os
|
||||
import uuid
|
||||
import json
|
||||
import requests
|
||||
# import jsonschema
|
||||
from config import Config
|
||||
from pathlib import Path
|
||||
|
||||
MODULES = []
|
||||
|
||||
|
@ -37,83 +38,22 @@ def isUUID(uid):
|
|||
return True
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
def get_object(obj_name):
|
||||
path = Path(os.getcwd())
|
||||
parent_path = path.parent.absolute()
|
||||
loc_path = os.path.join(parent_path, "misp_modules", "lib", "misp-objects", "objects")
|
||||
if os.path.isdir(loc_path):
|
||||
with open(os.path.join(loc_path, obj_name, "definition.json"), "r") as read_json:
|
||||
loc_json = json.load(read_json)
|
||||
return loc_json
|
||||
return False
|
||||
|
||||
|
||||
# def form_to_dict(form):
|
||||
# loc_dict = dict()
|
||||
# for field in form._fields:
|
||||
# if field == "files_upload":
|
||||
# loc_dict[field] = dict()
|
||||
# loc_dict[field]["data"] = form._fields[field].data
|
||||
# loc_dict[field]["name"] = form._fields[field].name
|
||||
# elif not field == "submit" and not field == "csrf_token":
|
||||
# loc_dict[field] = form._fields[field].data
|
||||
# return loc_dict
|
||||
def admin_user_active():
|
||||
return Config.ADMIN_USER
|
||||
|
||||
# def create_specific_dir(specific_dir):
|
||||
# if not os.path.isdir(specific_dir):
|
||||
# os.mkdir(specific_dir)
|
||||
def admin_password():
|
||||
return Config.ADMIN_PASSWORD
|
||||
|
||||
|
||||
# caseSchema = {
|
||||
# "type": "object",
|
||||
# "properties": {
|
||||
# "title": {"type": "string"},
|
||||
# "description": {"type": "string"},
|
||||
# "uuid": {"type": "string"},
|
||||
# "deadline:": {"type": "string"},
|
||||
# "recurring_date:": {"type": "string"},
|
||||
# "recurring_type:": {"type": "string"},
|
||||
# "tasks": {
|
||||
# "type": "array",
|
||||
# "items": {"type": "object"},
|
||||
# },
|
||||
# "tags":{
|
||||
# "type": "array",
|
||||
# "items": {"type": "string"},
|
||||
# },
|
||||
# "clusters":{
|
||||
# "type": "array",
|
||||
# "items": {"type": "string"},
|
||||
# },
|
||||
# },
|
||||
# "required": ['title']
|
||||
# }
|
||||
|
||||
# taskSchema = {
|
||||
# "type": "object",
|
||||
# "properties": {
|
||||
# "title": {"type": "string"},
|
||||
# "description": {"type": "string"},
|
||||
# "uuid": {"type": "string"},
|
||||
# "deadline:": {"type": "string"},
|
||||
# "url:": {"type": "string"},
|
||||
# "notes:": {"type": "string"},
|
||||
# "tags":{
|
||||
# "type": "array",
|
||||
# "items": {"type": "string"}
|
||||
# },
|
||||
# "clusters":{
|
||||
# "type": "array",
|
||||
# "items": {"type": "string"},
|
||||
# },
|
||||
# },
|
||||
# "required": ['title']
|
||||
# }
|
||||
|
||||
# def validateCaseJson(json_data):
|
||||
# try:
|
||||
# jsonschema.validate(instance=json_data, schema=caseSchema)
|
||||
# except jsonschema.exceptions.ValidationError as err:
|
||||
# print(err)
|
||||
# return False
|
||||
# return True
|
||||
|
||||
# def validateTaskJson(json_data):
|
||||
# try:
|
||||
# jsonschema.validate(instance=json_data, schema=taskSchema)
|
||||
# except jsonschema.exceptions.ValidationError as err:
|
||||
# print(err)
|
||||
# return False
|
||||
# return True
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ class Config:
|
|||
FLASK_URL = '127.0.0.1'
|
||||
FLASK_PORT = 7008
|
||||
MISP_MODULE = '127.0.0.1:6666'
|
||||
ADMIN_USER = False
|
||||
ADMIN_PASSWORD = "Password1234"
|
||||
|
||||
class DevelopmentConfig(Config):
|
||||
DEBUG = True
|
||||
|
@ -21,15 +23,9 @@ class TestingConfig(Config):
|
|||
SQLALCHEMY_DATABASE_URI = "sqlite:///misp-module-test.sqlite"
|
||||
WTF_CSRF_ENABLED = False
|
||||
|
||||
@classmethod
|
||||
def init_app(cls, app):
|
||||
print('THIS APP IS IN TESTING MODE. \
|
||||
YOU SHOULD NOT SEE THIS IN PRODUCTION.')
|
||||
|
||||
|
||||
config = {
|
||||
'development': DevelopmentConfig,
|
||||
'testing': TestingConfig,
|
||||
# 'production': ProductionConfig,
|
||||
'default': DevelopmentConfig
|
||||
}
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
Binary file not shown.
After Width: | Height: | Size: 111 KiB |
|
@ -1,12 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install virtualenv -y
|
||||
|
||||
virtualenv env
|
||||
source env/bin/activate
|
||||
|
||||
pip install -r requirements.txt
|
||||
|
||||
python app.py -i
|
||||
deactivate
|
|
@ -1,8 +1,18 @@
|
|||
#!/bin/bash
|
||||
isscripted=`screen -ls | egrep '[0-9]+.misp_mod' | cut -d. -f1`
|
||||
|
||||
function killscript {
|
||||
if [ $isscripted ]; then
|
||||
screen -X -S misp_mod quit
|
||||
fi
|
||||
}
|
||||
|
||||
function launch {
|
||||
export FLASKENV="development"
|
||||
killscript
|
||||
screen -dmS "misp_mod"
|
||||
screen -S "misp_mod" -X screen -t "misp_modules_server" bash -c "../env/bin/misp-modules -l 127.0.0.1; read x"
|
||||
sleep 2
|
||||
python3 app.py -m
|
||||
python3 app.py
|
||||
}
|
||||
|
@ -30,6 +40,8 @@ if [ "$1" ]; then
|
|||
-r | --reload_db ) reload_db;
|
||||
;;
|
||||
-t | --test ) test;
|
||||
;;
|
||||
-ks | --killscript ) killscript;
|
||||
esac
|
||||
shift
|
||||
else
|
||||
|
|
|
@ -4,9 +4,9 @@ flask-session
|
|||
flask-sqlalchemy
|
||||
Flask-WTF
|
||||
Flask-Migrate
|
||||
Flask-Login
|
||||
WTForms
|
||||
Werkzeug==2.3.8
|
||||
Flask-Migrate
|
||||
flask-restx
|
||||
python-dateutil
|
||||
schedule
|
||||
|
|
Loading…
Reference in New Issue