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)
|
||||
name = db.Column(db.String(64), index=True)
|
||||
url = db.Column(db.String)
|
||||
api_key = db.Column(db.String(60), index=True)
|
||||
is_active = db.Column(db.Boolean)
|
||||
|
||||
def to_json(self):
|
||||
|
@ -103,6 +104,7 @@ class ExternalTools(db.Model):
|
|||
"id": self.id,
|
||||
"url": self.url,
|
||||
"name": self.name,
|
||||
"api_key": self.api_key,
|
||||
"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_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"]:
|
||||
res = ToolModel.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
|
||||
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"])
|
||||
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 "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_name"', '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:
|
||||
tool.name = request_json["tool_name"]
|
||||
tool.url = request_json["tool_url"]
|
||||
tool.api_key = request_json["tool_api_key"]
|
||||
db.session.commit()
|
||||
return True
|
||||
return False
|
||||
|
@ -34,6 +35,7 @@ def add_tool_core(form_dict):
|
|||
tool = ExternalTools(
|
||||
name=form_dict["name"],
|
||||
url = form_dict["url"],
|
||||
api_key = form_dict["api_key"],
|
||||
is_active=True
|
||||
)
|
||||
db.session.add(tool)
|
||||
|
|
|
@ -9,4 +9,5 @@ from wtforms.validators import InputRequired, Length
|
|||
class ExternalToolForm(FlaskForm):
|
||||
name = StringField('Name', validators=[InputRequired(), Length(1, 64)])
|
||||
url = StringField('Url', validators=[InputRequired()])
|
||||
api_key = StringField('API key', validators=[InputRequired(), Length(1, 60)])
|
||||
submit = SubmitField('Create')
|
|
@ -2,9 +2,11 @@ import ast
|
|||
import json
|
||||
from flask import Blueprint, render_template, request, jsonify, session as sess
|
||||
from flask_login import current_user
|
||||
import requests
|
||||
from . import session_class as SessionModel
|
||||
from . import home_core as HomeModel
|
||||
from .utils.utils import admin_user_active
|
||||
from .external_tools import external_tools_core as ToolModel
|
||||
|
||||
home_blueprint = Blueprint(
|
||||
'home',
|
||||
|
@ -255,3 +257,19 @@ def change_status():
|
|||
return {'message': 'Need to pass "module_id"', 'toast_class': "warning-subtle"}, 400
|
||||
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 requests
|
||||
from .utils.utils import isUUID, query_get_module
|
||||
from . import db
|
||||
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()
|
||||
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%}
|
||||
</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>
|
||||
|
|
|
@ -53,6 +53,11 @@
|
|||
<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>
|
||||
</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-danger" @click="delete_tool()" style="margin-left: 5px;">Delete</button>
|
||||
</div>
|
||||
|
@ -86,6 +91,7 @@
|
|||
current_config.value["tool_name"] = tool.name
|
||||
current_config.value["tool_url"] = tool.url
|
||||
current_config.value["tool_id"] = tool.id
|
||||
current_config.value["tool_api_key"] = tool.api_key
|
||||
}
|
||||
|
||||
function close_panel(){
|
||||
|
@ -95,6 +101,7 @@
|
|||
async function change_config(){
|
||||
$("#error-name-"+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 = {}
|
||||
result_dict["tool_id"] = current_config.value["tool_id"]
|
||||
|
||||
|
@ -108,6 +115,11 @@
|
|||
$("#error-url-"+current_config.value["tool_id"]).text('Cannot be empty')
|
||||
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
|
||||
result_dict["tool_name"] = loc_name
|
||||
|
@ -115,12 +127,16 @@
|
|||
|
||||
result_dict["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
|
||||
for(let i in tools_config.value){
|
||||
if(tools_config.value[i].id == current_config.value["tool_id"] ){
|
||||
tools_config.value[i].name = loc_name
|
||||
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 %}
|
||||
<script type="module">
|
||||
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'
|
||||
createApp({
|
||||
delimiters: ['[[', ']]'],
|
||||
|
@ -460,14 +460,13 @@ Value: [[misp_attr]]
|
|||
to_return = modules_res.value
|
||||
}
|
||||
|
||||
$('#insert_form').append(
|
||||
$('<form>').attr(
|
||||
{"action": external_tools.value[tool_selected].url, "name": "external_tools_form", "method": "post", "style": "display:none"}).append(
|
||||
$("<input>").attr({"type": "text", "name": "results"}).val(JSON.stringify(to_return)
|
||||
)
|
||||
)
|
||||
);
|
||||
document.forms['external_tools_form'].submit();
|
||||
const res = await fetch('/submit_external_tool',{
|
||||
headers: { "X-CSRFToken": $("#csrf_token").val(), "Content-Type": "application/json" },
|
||||
method: "POST",
|
||||
body: JSON.stringify({"results": JSON.stringify(to_return), "external_tool_id": external_tools.value[tool_selected].id})
|
||||
})
|
||||
|
||||
display_toast(res)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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