mirror of https://github.com/MISP/misp-modules
chg: [external_tools] api_key, remove redirect
parent
feeeaddeb1
commit
230eaf8437
|
@ -96,6 +96,7 @@ class ExternalTools(db.Model):
|
||||||
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
||||||
name = db.Column(db.String(64), index=True)
|
name = db.Column(db.String(64), index=True)
|
||||||
url = db.Column(db.String)
|
url = db.Column(db.String)
|
||||||
|
api_key = db.Column(db.String(60), index=True)
|
||||||
is_active = db.Column(db.Boolean)
|
is_active = db.Column(db.Boolean)
|
||||||
|
|
||||||
def to_json(self):
|
def to_json(self):
|
||||||
|
@ -103,6 +104,7 @@ class ExternalTools(db.Model):
|
||||||
"id": self.id,
|
"id": self.id,
|
||||||
"url": self.url,
|
"url": self.url,
|
||||||
"name": self.name,
|
"name": self.name,
|
||||||
|
"api_key": self.api_key,
|
||||||
"is_active": self.is_active
|
"is_active": self.is_active
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,10 +61,12 @@ def change_config():
|
||||||
if "tool_id" in request.json["result_dict"] and request.json["result_dict"]["tool_id"]:
|
if "tool_id" in request.json["result_dict"] and request.json["result_dict"]["tool_id"]:
|
||||||
if "tool_name" in request.json["result_dict"] and request.json["result_dict"]["tool_name"]:
|
if "tool_name" in request.json["result_dict"] and request.json["result_dict"]["tool_name"]:
|
||||||
if "tool_url" in request.json["result_dict"] and request.json["result_dict"]["tool_url"]:
|
if "tool_url" in request.json["result_dict"] and request.json["result_dict"]["tool_url"]:
|
||||||
|
if "tool_api_key" in request.json["result_dict"] and request.json["result_dict"]["tool_api_key"]:
|
||||||
res = ToolModel.change_config_core(request.json["result_dict"])
|
res = ToolModel.change_config_core(request.json["result_dict"])
|
||||||
if res:
|
if res:
|
||||||
return {'message': 'Config changed', 'toast_class': "success-subtle"}, 200
|
return {'message': 'Config changed', 'toast_class': "success-subtle"}, 200
|
||||||
return {'message': 'Something went wrong', 'toast_class': "danger-subtle"}, 400
|
return {'message': 'Something went wrong', 'toast_class': "danger-subtle"}, 400
|
||||||
|
return {'message': 'Need to pass "tool_api_key"', 'toast_class': "warning-subtle"}, 400
|
||||||
return {'message': 'Need to pass "tool_url"', 'toast_class': "warning-subtle"}, 400
|
return {'message': 'Need to pass "tool_url"', 'toast_class': "warning-subtle"}, 400
|
||||||
return {'message': 'Need to pass "tool_name"', 'toast_class': "warning-subtle"}, 400
|
return {'message': 'Need to pass "tool_name"', 'toast_class': "warning-subtle"}, 400
|
||||||
return {'message': 'Need to pass "tool_id"', 'toast_class': "warning-subtle"}, 400
|
return {'message': 'Need to pass "tool_id"', 'toast_class': "warning-subtle"}, 400
|
||||||
|
|
|
@ -25,6 +25,7 @@ def change_config_core(request_json):
|
||||||
if tool:
|
if tool:
|
||||||
tool.name = request_json["tool_name"]
|
tool.name = request_json["tool_name"]
|
||||||
tool.url = request_json["tool_url"]
|
tool.url = request_json["tool_url"]
|
||||||
|
tool.api_key = request_json["tool_api_key"]
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
@ -34,6 +35,7 @@ def add_tool_core(form_dict):
|
||||||
tool = ExternalTools(
|
tool = ExternalTools(
|
||||||
name=form_dict["name"],
|
name=form_dict["name"],
|
||||||
url = form_dict["url"],
|
url = form_dict["url"],
|
||||||
|
api_key = form_dict["api_key"],
|
||||||
is_active=True
|
is_active=True
|
||||||
)
|
)
|
||||||
db.session.add(tool)
|
db.session.add(tool)
|
||||||
|
|
|
@ -9,4 +9,5 @@ from wtforms.validators import InputRequired, Length
|
||||||
class ExternalToolForm(FlaskForm):
|
class ExternalToolForm(FlaskForm):
|
||||||
name = StringField('Name', validators=[InputRequired(), Length(1, 64)])
|
name = StringField('Name', validators=[InputRequired(), Length(1, 64)])
|
||||||
url = StringField('Url', validators=[InputRequired()])
|
url = StringField('Url', validators=[InputRequired()])
|
||||||
|
api_key = StringField('API key', validators=[InputRequired(), Length(1, 60)])
|
||||||
submit = SubmitField('Create')
|
submit = SubmitField('Create')
|
|
@ -2,9 +2,11 @@ import ast
|
||||||
import json
|
import json
|
||||||
from flask import Blueprint, render_template, request, jsonify, session as sess
|
from flask import Blueprint, render_template, request, jsonify, session as sess
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
import requests
|
||||||
from . import session_class as SessionModel
|
from . import session_class as SessionModel
|
||||||
from . import home_core as HomeModel
|
from . import home_core as HomeModel
|
||||||
from .utils.utils import admin_user_active
|
from .utils.utils import admin_user_active
|
||||||
|
from .external_tools import external_tools_core as ToolModel
|
||||||
|
|
||||||
home_blueprint = Blueprint(
|
home_blueprint = Blueprint(
|
||||||
'home',
|
'home',
|
||||||
|
@ -255,3 +257,19 @@ def change_status():
|
||||||
return {'message': 'Need to pass "module_id"', 'toast_class': "warning-subtle"}, 400
|
return {'message': 'Need to pass "module_id"', 'toast_class': "warning-subtle"}, 400
|
||||||
return {'message': 'Permission denied', 'toast_class': "danger-subtle"}, 403
|
return {'message': 'Permission denied', 'toast_class': "danger-subtle"}, 403
|
||||||
|
|
||||||
|
|
||||||
|
@home_blueprint.route("/submit_external_tool", methods=["GET", "POST"])
|
||||||
|
def submit_external_tool():
|
||||||
|
"""Submit result to an external tool"""
|
||||||
|
sess["admin_user"] = admin_user_active()
|
||||||
|
flag = True
|
||||||
|
if sess.get("admin_user"):
|
||||||
|
if not current_user.is_authenticated:
|
||||||
|
flag = False
|
||||||
|
# if admin is active and user is logon or if admin is not active
|
||||||
|
if flag:
|
||||||
|
ext = ToolModel.get_tool(request.json["external_tool_id"])
|
||||||
|
if HomeModel.submit_external_tool(request.json["results"], ext):
|
||||||
|
return {'message': f'Send to {ext.name} successfully', 'toast_class': "success-subtle"}, 200
|
||||||
|
return {'message': 'Something went wrong', 'toast_class': "danger-subtle"}, 400
|
||||||
|
return {'message': 'Permission denied', 'toast_class': "danger-subtle"}, 403
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
import requests
|
||||||
from .utils.utils import isUUID, query_get_module
|
from .utils.utils import isUUID, query_get_module
|
||||||
from . import db
|
from . import db
|
||||||
from .db_class.db import History, Module, Config, Module_Config, Session_db, History_Tree
|
from .db_class.db import History, Module, Config, Module_Config, Session_db, History_Tree
|
||||||
|
@ -113,6 +115,13 @@ def change_status_core(module_id):
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def submit_external_tool(results, ext_tool):
|
||||||
|
headers = {'Content-Type': 'application/json', "X-API-KEY": ext_tool.api_key, "Origin": "misp-module"}
|
||||||
|
response = requests.post(ext_tool.url, json={"results":results}, headers=headers)
|
||||||
|
if response.status_code == 200:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##############
|
##############
|
||||||
|
|
|
@ -26,6 +26,15 @@
|
||||||
{%endif%}
|
{%endif%}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="mb-3 w-50">
|
||||||
|
{{form.api_key.label(class_="col-form-label")}}:
|
||||||
|
{{form.api_key(class_="form-control")}}
|
||||||
|
{% if form.api_key.errors %}
|
||||||
|
<div style="color: red;">{{form.api_key.errors[0] | safe}}</div>
|
||||||
|
{%endif%}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{{form.submit(class='btn btn-primary')}}
|
{{form.submit(class='btn btn-primary')}}
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -53,6 +53,11 @@
|
||||||
<input type="text" class="form-control" :id="'form-url-'+current_config.tool_id" :value="current_config.tool_url">
|
<input type="text" class="form-control" :id="'form-url-'+current_config.tool_id" :value="current_config.tool_url">
|
||||||
<span style="color: brown" :id="'error-url-'+current_config.tool_id"></span>
|
<span style="color: brown" :id="'error-url-'+current_config.tool_id"></span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label :for="'form-api-key-'+current_config.tool_id" class="form-label">API key: </label>
|
||||||
|
<input type="text" class="form-control" :id="'form-api-key-'+current_config.tool_id" :value="current_config.tool_api_key">
|
||||||
|
<span style="color: brown" :id="'error-api-key-'+current_config.tool_id"></span>
|
||||||
|
</div>
|
||||||
<button class="btn btn-primary" @click="change_config()">Save</button>
|
<button class="btn btn-primary" @click="change_config()">Save</button>
|
||||||
<button class="btn btn-danger" @click="delete_tool()" style="margin-left: 5px;">Delete</button>
|
<button class="btn btn-danger" @click="delete_tool()" style="margin-left: 5px;">Delete</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -86,6 +91,7 @@
|
||||||
current_config.value["tool_name"] = tool.name
|
current_config.value["tool_name"] = tool.name
|
||||||
current_config.value["tool_url"] = tool.url
|
current_config.value["tool_url"] = tool.url
|
||||||
current_config.value["tool_id"] = tool.id
|
current_config.value["tool_id"] = tool.id
|
||||||
|
current_config.value["tool_api_key"] = tool.api_key
|
||||||
}
|
}
|
||||||
|
|
||||||
function close_panel(){
|
function close_panel(){
|
||||||
|
@ -95,6 +101,7 @@
|
||||||
async function change_config(){
|
async function change_config(){
|
||||||
$("#error-name-"+current_config.value["tool_id"]).text("")
|
$("#error-name-"+current_config.value["tool_id"]).text("")
|
||||||
$("#error-url-"+current_config.value["tool_id"]).text("")
|
$("#error-url-"+current_config.value["tool_id"]).text("")
|
||||||
|
$("#error-url-"+current_config.value["tool_api_key"]).text("")
|
||||||
let result_dict = {}
|
let result_dict = {}
|
||||||
result_dict["tool_id"] = current_config.value["tool_id"]
|
result_dict["tool_id"] = current_config.value["tool_id"]
|
||||||
|
|
||||||
|
@ -108,6 +115,11 @@
|
||||||
$("#error-url-"+current_config.value["tool_id"]).text('Cannot be empty')
|
$("#error-url-"+current_config.value["tool_id"]).text('Cannot be empty')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
let loc_api_key = $("#form-api-key-"+current_config.value["tool_id"]).val()
|
||||||
|
if(!loc_api_key){
|
||||||
|
$("#error-api-key-"+current_config.value["tool_id"]).text('Cannot be empty')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Update result_dict and current_config
|
// Update result_dict and current_config
|
||||||
result_dict["tool_name"] = loc_name
|
result_dict["tool_name"] = loc_name
|
||||||
|
@ -116,11 +128,15 @@
|
||||||
result_dict["tool_url"] = loc_url
|
result_dict["tool_url"] = loc_url
|
||||||
current_config.value["tool_url"] = loc_url
|
current_config.value["tool_url"] = loc_url
|
||||||
|
|
||||||
|
result_dict["tool_api_key"] = loc_api_key
|
||||||
|
current_config.value["tool_api_key"] = loc_api_key
|
||||||
|
|
||||||
// Update list of tools with new value for current tool
|
// Update list of tools with new value for current tool
|
||||||
for(let i in tools_config.value){
|
for(let i in tools_config.value){
|
||||||
if(tools_config.value[i].id == current_config.value["tool_id"] ){
|
if(tools_config.value[i].id == current_config.value["tool_id"] ){
|
||||||
tools_config.value[i].name = loc_name
|
tools_config.value[i].name = loc_name
|
||||||
tools_config.value[i].url = loc_url
|
tools_config.value[i].url = loc_url
|
||||||
|
tools_config.value[i].api_key = loc_api_key
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -292,7 +292,7 @@ Value: [[misp_attr]]
|
||||||
{% block script %}
|
{% block script %}
|
||||||
<script type="module">
|
<script type="module">
|
||||||
const { createApp, ref, onMounted, nextTick} = Vue
|
const { createApp, ref, onMounted, nextTick} = Vue
|
||||||
import {message_list} from '/static/js/toaster.js'
|
import {message_list, display_toast} from '/static/js/toaster.js'
|
||||||
import history_view from '/static/js/history/history_tree_query.js'
|
import history_view from '/static/js/history/history_tree_query.js'
|
||||||
createApp({
|
createApp({
|
||||||
delimiters: ['[[', ']]'],
|
delimiters: ['[[', ']]'],
|
||||||
|
@ -460,14 +460,13 @@ Value: [[misp_attr]]
|
||||||
to_return = modules_res.value
|
to_return = modules_res.value
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#insert_form').append(
|
const res = await fetch('/submit_external_tool',{
|
||||||
$('<form>').attr(
|
headers: { "X-CSRFToken": $("#csrf_token").val(), "Content-Type": "application/json" },
|
||||||
{"action": external_tools.value[tool_selected].url, "name": "external_tools_form", "method": "post", "style": "display:none"}).append(
|
method: "POST",
|
||||||
$("<input>").attr({"type": "text", "name": "results"}).val(JSON.stringify(to_return)
|
body: JSON.stringify({"results": JSON.stringify(to_return), "external_tool_id": external_tools.value[tool_selected].id})
|
||||||
)
|
})
|
||||||
)
|
|
||||||
);
|
display_toast(res)
|
||||||
document.forms['external_tools_form'].submit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
source env/bin/activate
|
||||||
|
export FLASKENV=development
|
||||||
|
|
||||||
|
function migrate {
|
||||||
|
flask db migrate
|
||||||
|
}
|
||||||
|
|
||||||
|
function upgrade {
|
||||||
|
flask db upgrade
|
||||||
|
}
|
||||||
|
|
||||||
|
function downgrade {
|
||||||
|
flask db downgrade
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if [ "$1" ]; then
|
||||||
|
case $1 in
|
||||||
|
-m | --migrate ) migrate;
|
||||||
|
;;
|
||||||
|
-u | --upgrade ) upgrade;
|
||||||
|
;;
|
||||||
|
-d | --downgrade ) downgrade;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
else
|
||||||
|
echo "need -m or -u or -d"
|
||||||
|
fi
|
|
@ -0,0 +1,34 @@
|
||||||
|
"""empty message
|
||||||
|
|
||||||
|
Revision ID: 206e0e808b0c
|
||||||
|
Revises: 3a631d400f60
|
||||||
|
Create Date: 2024-08-21 09:36:37.801809
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '206e0e808b0c'
|
||||||
|
down_revision = '3a631d400f60'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('external_tools', schema=None) as batch_op:
|
||||||
|
batch_op.add_column(sa.Column('api_key', sa.String(length=60), nullable=True))
|
||||||
|
batch_op.create_index(batch_op.f('ix_external_tools_api_key'), ['api_key'], unique=False)
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('external_tools', schema=None) as batch_op:
|
||||||
|
batch_op.drop_index(batch_op.f('ix_external_tools_api_key'))
|
||||||
|
batch_op.drop_column('api_key')
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
Loading…
Reference in New Issue