mirror of https://github.com/MISP/misp-modules
chg: [website] query page
parent
8276650165
commit
30f84f6512
|
@ -1,3 +1,4 @@
|
|||
import json
|
||||
from flask import Flask, Blueprint, render_template, request, jsonify
|
||||
from . import home_core as HomeModel
|
||||
from . import session as SessionModel
|
||||
|
@ -14,6 +15,25 @@ home_blueprint = Blueprint(
|
|||
def home():
|
||||
return render_template("home.html")
|
||||
|
||||
@home_blueprint.route("/query/<sid>")
|
||||
def query(sid):
|
||||
session = HomeModel.get_session(sid)
|
||||
flag=False
|
||||
if session:
|
||||
flag = True
|
||||
query_loc = session.query_enter
|
||||
else:
|
||||
for s in SessionModel.sessions:
|
||||
if s.id == sid:
|
||||
flag = True
|
||||
query_loc = s.query
|
||||
session=s
|
||||
if flag:
|
||||
return render_template("query.html", query=query_loc, sid=sid, input_query=session.input_query, modules=json.loads(session.glob_query))
|
||||
return render_template("404.html")
|
||||
|
||||
|
||||
|
||||
@home_blueprint.route("/get_modules")
|
||||
def get_modules():
|
||||
"""Return all modules available"""
|
||||
|
|
|
@ -154,7 +154,7 @@ class Session_class:
|
|||
|
||||
histories = History.query.all()
|
||||
|
||||
while len(histories) > 3:
|
||||
while len(histories) > 10:
|
||||
history = History.query.order_by(History.id).all()
|
||||
Session_db.query.filter_by(id=history[0].session_id).delete()
|
||||
History.query.filter_by(id=history[0].id).delete()
|
||||
|
|
|
@ -37,7 +37,6 @@ div#searchbox {
|
|||
border: 1px solid #ccc;
|
||||
border-radius: 5px 0 0 5px;
|
||||
padding-left: .75em;
|
||||
width: 80%;
|
||||
outline: none;
|
||||
}
|
||||
button#query {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div id="top"> <h1>History</h1> </div>
|
||||
<h1 id="top">History</h1>
|
||||
|
||||
<hr>
|
||||
<br>
|
||||
|
@ -13,13 +13,12 @@
|
|||
<div v-if="history">
|
||||
<template v-for="h, key in history">
|
||||
<div class="list-group" style="margin-bottom: 20px;">
|
||||
<!-- <a :href="'/query/'+h.uuid" class="list-group-item list-group-item-action"> -->
|
||||
<a href="#" class="list-group-item list-group-item-action">
|
||||
<a :href="'/query/'+h.uuid" class="list-group-item list-group-item-action">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">[[key+1]]- [[h.query]]</h5>
|
||||
<small><i>[[h.uuid]]</i></small>
|
||||
</div>
|
||||
<p class="mb-1" style="color: green;"><u>Input</u>:</p>
|
||||
<p class="mb-1" style="color: green;"><u>Input Attribute</u>:</p>
|
||||
<div>[[h.input]]</div>
|
||||
<br>
|
||||
<p class="mb-1" style="color: #2000ff;"><u>Modules</u>:</p>
|
||||
|
|
|
@ -13,16 +13,10 @@
|
|||
|
||||
<hr>
|
||||
<br>
|
||||
<div>
|
||||
<div id="searchbox">
|
||||
<input type="hidden" id="share" value="{{share}}">
|
||||
<input type="text" id="process-query" placeholder="Enter here..." autofocus>
|
||||
<!-- <button id="query" @click="actionQuery()">[[query]]</button> -->
|
||||
<div style="width:50%; transform: translate(50%, 0);">
|
||||
<div>
|
||||
<input type="text" id="process-query" placeholder="Enter here..." autofocus class="form-control" style="border-radius: 5px;" />
|
||||
</div>
|
||||
<div v-if="is_searching" class="progress">
|
||||
<div class="progress-bar progress-bar-striped active" id="progress" role="progressbar" aria-valuemin="0" aria-valuemax="100" :style="'width:'+progress + '%;'">
|
||||
</div>
|
||||
</div>
|
||||
<span v-if="status_site" id="status">[[status_site]]</span>
|
||||
</div>
|
||||
|
||||
|
@ -48,7 +42,7 @@
|
|||
<div class="row" style="margin-top: 2px;">
|
||||
<div>
|
||||
<div>
|
||||
<h4>Input</h4>
|
||||
<h4>Input Attributes</h4>
|
||||
</div>
|
||||
<div>
|
||||
<select data-placeholder="Input" class="select2-input form-control" name="input_select" id="input_select">
|
||||
|
@ -63,31 +57,33 @@
|
|||
</div>
|
||||
|
||||
<!-- Results modules selection -->
|
||||
<div v-if="Object.keys(modules_list).length">
|
||||
<div class="row" v-if="attr_selected.length">
|
||||
<div class="col-5" v-if="modules_list.expansion.length">
|
||||
<div class="col-5">
|
||||
<h4>Expansion</h4>
|
||||
</div>
|
||||
<template v-if="modules_list">
|
||||
<div v-if="Object.keys(modules_list).length">
|
||||
<div class="row" v-if="attr_selected.length">
|
||||
<div class="col-5" v-if="modules_list.expansion.length">
|
||||
<div class="col-5">
|
||||
<h4>Expansions Modules</h4>
|
||||
</div>
|
||||
|
||||
<select data-placeholder="Expansion" class="select2-expansion form-control" multiple name="expansion_select" id="expansion_select">
|
||||
<template v-for="key in modules_list.expansion">
|
||||
<option v-if="key.mispattributes.input.includes(attr_selected)" :value="key.name" :title="key.meta.description">[[key.name]]</option>
|
||||
</template>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-5" v-if="modules_list.hover.length">
|
||||
<div class="col-5">
|
||||
<h4>Hover</h4>
|
||||
<select data-placeholder="Expansion" class="select2-expansion form-control" multiple name="expansion_select" id="expansion_select">
|
||||
<template v-for="key in modules_list.expansion">
|
||||
<option v-if="key.mispattributes.input.includes(attr_selected)" :value="key.name" :title="key.meta.description">[[key.name]]</option>
|
||||
</template>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-5" v-if="modules_list.hover.length">
|
||||
<div class="col-5">
|
||||
<h4>Hover Modules</h4>
|
||||
</div>
|
||||
<select data-placeholder="Hover" class="select2-hover form-control" multiple name="hover_select" id="hover_select">
|
||||
<template v-for="key in modules_list.hover">
|
||||
<option v-if="key.mispattributes.input.includes(attr_selected)" :value="key.name" :title="key.meta.description">[[key.name]]</option>
|
||||
</template>
|
||||
</select>
|
||||
</div>
|
||||
<select data-placeholder="Hover" class="select2-hover form-control" multiple name="hover_select" id="hover_select">
|
||||
<template v-for="key in modules_list.hover">
|
||||
<option v-if="key.mispattributes.input.includes(attr_selected)" :value="key.name" :title="key.meta.description">[[key.name]]</option>
|
||||
</template>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Display in case a module as reauest_on_query activate -->
|
||||
<div v-if="config_query.length" style="margin-top: 10px;" class="row">
|
||||
|
@ -106,50 +102,6 @@
|
|||
|
||||
<button class="btn btn-primary" @click="actionQuery()">Query</button>
|
||||
|
||||
<!-- Results Part -->
|
||||
<hr>
|
||||
<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">
|
||||
<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" v-html="generateCoreFormatUI(result)[0].outerHTML"></div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</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>
|
||||
</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>
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
|
@ -160,14 +112,10 @@
|
|||
delimiters: ['[[', ']]'],
|
||||
setup() {
|
||||
const query = ref("Query")
|
||||
const is_searching = ref(false)
|
||||
const modules_list = ref({})
|
||||
const misp_attributes_list = ref({})
|
||||
const attr_selected = ref([])
|
||||
|
||||
const sid = ref(null)
|
||||
let last_registered = 0
|
||||
const modules_res = ref({})
|
||||
const progress = ref(0)
|
||||
|
||||
let expansion_bool = false
|
||||
|
@ -189,8 +137,6 @@
|
|||
}
|
||||
|
||||
if (query.value == 'Query') {
|
||||
last_registered = 0;
|
||||
is_searching.value = true
|
||||
progress.value = 0
|
||||
let error_flag = false
|
||||
|
||||
|
@ -221,10 +167,10 @@
|
|||
})
|
||||
if(await res.status == 201){
|
||||
let loc = await res.json()
|
||||
is_searching.value = true
|
||||
sid.value = loc['id']
|
||||
query.value = 'Stop'
|
||||
pollScan();
|
||||
console.log(loc['id']);
|
||||
await nextTick()
|
||||
window.location.href="/query/" + loc['id']
|
||||
}else{
|
||||
let loc = await res.json()
|
||||
query.value = 'Query'
|
||||
|
@ -238,41 +184,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
function pollScan() {
|
||||
// Loop function to update the list of identified domains
|
||||
$.getJSON('/status/' + sid.value, function(data) {
|
||||
progress.value = Math.round((data['complete']/data['total'])*100)
|
||||
status_site.value = 'Processed ' + data['complete'] + ' of ' + data['total']
|
||||
if (data['remaining'] > 0) {
|
||||
setTimeout(pollScan, 3000);
|
||||
} else {
|
||||
// Button Stop pressed
|
||||
if (data['stopped'])
|
||||
status_site.value = 'Stopped ! ' + data['complete'] - data["nb_errors"] + ' Success. ' + data["nb_errors"] + ' Errors. ' + data['complete'] + ' Total.'
|
||||
// Display result of the search
|
||||
else
|
||||
status_site.value = data['complete'] - data["nb_errors"] + ' Success. ' + data["nb_errors"] + ' Errors. ' + data['complete'] + ' Total.'
|
||||
query.value = 'Query'
|
||||
}
|
||||
if (last_registered < data['registered']) {
|
||||
last_registered = data['registered']
|
||||
fetchResult();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function fetchResult(){
|
||||
modules_res.value = {}
|
||||
const res = await fetch("/result/"+sid.value)
|
||||
let loc = await res.json()
|
||||
modules_res.value = loc
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -381,12 +292,10 @@
|
|||
message_list,
|
||||
query,
|
||||
progress,
|
||||
is_searching,
|
||||
modules_list,
|
||||
misp_attributes_list,
|
||||
attr_selected,
|
||||
status_site,
|
||||
modules_res,
|
||||
config_query,
|
||||
actionQuery,
|
||||
expansion_module,
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
<!--
|
||||
Author: David Cruciani
|
||||
-->
|
||||
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<h1 id="top">MISP Modules</h1>
|
||||
|
||||
<hr>
|
||||
<br>
|
||||
<div style="width:50%; transform: translate(50%, 0);">
|
||||
<div>
|
||||
<input type="hidden" id="share" value="{{sid}}">
|
||||
<input type="text" id="process-query" value="{{query}}" class="form-control" style="border-radius: 5px;" />
|
||||
</div>
|
||||
<div v-if="is_searching" class="progress" >
|
||||
<div class="progress-bar progress-bar-striped active" id="progress" role="progressbar" aria-valuemin="0" aria-valuemax="100" :style="'width:'+progress + '%;'">
|
||||
</div>
|
||||
</div>
|
||||
<span v-if="status_site" id="status">[[status_site]]</span>
|
||||
</div>
|
||||
|
||||
|
||||
<button style="margin-top: 10px;" class="btn btn-primary" type="button" data-bs-toggle="collapse" data-bs-target="#collapseInfo" aria-expanded="false" aria-controls="collapseInfo">
|
||||
More Info
|
||||
</button>
|
||||
<div class="collapse" id="collapseInfo">
|
||||
<div class="card card-body">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h4>Input Attribute:</h4>
|
||||
{{input_query}}
|
||||
</div>
|
||||
<div class="col">
|
||||
<h4>Modules:</h4>
|
||||
{%for module in modules%} {{module}}, {%endfor%}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 10px;"><a href="/">New query</a></div>
|
||||
|
||||
<br/>
|
||||
|
||||
<!-- Results Part -->
|
||||
<hr>
|
||||
<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">
|
||||
<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" v-html="generateCoreFormatUI(result)[0].outerHTML"></div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</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>
|
||||
</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>
|
||||
<span id="goTop">[<a href="#top">Go Back Top</a>]</span>
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
<script type="module">
|
||||
const { createApp, ref, onMounted, nextTick, defineComponent} = Vue
|
||||
import {message_list} from '/static/js/toaster.js'
|
||||
createApp({
|
||||
delimiters: ['[[', ']]'],
|
||||
setup() {
|
||||
const is_searching = ref(false)
|
||||
|
||||
const sid = ref(null)
|
||||
let last_registered = 0
|
||||
const modules_res = ref({})
|
||||
const progress = ref(0)
|
||||
const status_site = ref()
|
||||
|
||||
|
||||
function actionQuery(){
|
||||
is_searching.value = true
|
||||
sid.value = $("#share").val()
|
||||
pollScan();
|
||||
}
|
||||
|
||||
function pollScan() {
|
||||
// Loop function to update the list of identified domains
|
||||
$.getJSON('/status/' + sid.value, function(data) {
|
||||
progress.value = Math.round((data['complete']/data['total'])*100)
|
||||
status_site.value = 'Processed ' + data['complete'] + ' of ' + data['total']
|
||||
if (data['remaining'] > 0) {
|
||||
setTimeout(pollScan, 3000);
|
||||
} else {
|
||||
// Button Stop pressed
|
||||
if (data['stopped'])
|
||||
status_site.value = 'Stopped ! ' + data['complete'] - data["nb_errors"] + ' Success. ' + data["nb_errors"] + ' Errors. ' + data['complete'] + ' Total.'
|
||||
// Display result of the search
|
||||
else
|
||||
status_site.value = data['complete'] - data["nb_errors"] + ' Success. ' + data["nb_errors"] + ' Errors. ' + data['complete'] + ' Total.'
|
||||
}
|
||||
if (last_registered < data['registered']) {
|
||||
last_registered = data['registered']
|
||||
fetchResult();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function fetchResult(){
|
||||
modules_res.value = {}
|
||||
const res = await fetch("/result/"+sid.value)
|
||||
let loc = await res.json()
|
||||
modules_res.value = loc
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
actionQuery()
|
||||
})
|
||||
|
||||
|
||||
return {
|
||||
message_list,
|
||||
progress,
|
||||
status_site,
|
||||
is_searching,
|
||||
modules_res,
|
||||
generateCoreFormatUI
|
||||
}
|
||||
}
|
||||
}).mount('.container')
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -1,14 +1,14 @@
|
|||
<!--Main Navigation-->
|
||||
<header>
|
||||
<!-- Sidebar -->
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<nav id="sidebarMenu" class="d-lg-block sidebar bg-white">
|
||||
<nav id="sidebarMenu" class="collapse d-lg-block sidebar collapse bg-white">
|
||||
|
||||
<a class="navbar-brand" style="margin-left: 20px;" href="/">
|
||||
<img src="{{ url_for('static',filename='image/misp.png') }}" height="55" alt="Misp Logo" loading="lazy" />
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="position-sticky">
|
||||
<div class="list-group list-group-flush mx-3 mt-4">
|
||||
|
|
Loading…
Reference in New Issue