misp/src/static/assets/index/scripts.js

560 lines
No EOL
13 KiB
JavaScript

class Auth {
constructor() {
this.url = "http://localhost:8000"
this.settings = {
authority: "https://sso.sr2.uk/realms/sr2",
client_id: "chris-dev",
redirect_uri: this.url + "/signin-callback.html",
response_type: "code",
scope: "openid email profile",
response_mode: "fragment",
}
this.user_manager = new oidc.UserManager(this.settings)
this.get_user().then(() => {
window.is_authenticated = Boolean(this.user);
ui.update_auth_button()
})
}
async get_user() {
this.user = await this.user_manager.getUser()
}
async login() {
try {
this.user = await this.user_manager.signinPopup();
window.is_authenticated = Boolean(auth.user);
} catch (error) {
console.error(error);
}
}
async logout() {
try {
this.user = await this.user_manager.signoutPopup();
window.is_authenticated = Boolean(auth.user);
} catch (error) {
console.error(error);
}
}
}
class UI {
constructor() {
this.auth_button = document.getElementById("auth_button");
this.blocked_domains = document.getElementById("blocked_domains")
this.timer_status = document.getElementById("timer_status")
this.overall_status = document.getElementById("overall_status")
this.last_update_complete_time = document.getElementById("last_update_complete_time")
this.last_update_duration = document.getElementById("last_update_duration")
this.manual_update_btn = document.getElementById("manual_update_btn")
this.start_timer_btn = document.getElementById("start_timer_btn")
this.stop_timer_btn = document.getElementById("stop_timer_btn")
this.domain_search_btn = document.getElementById("domain_search_btn")
this.false_positive_actions = document.getElementById("false_positive_actions")
this.false_positive_load_btn = document.getElementById("false_positive_load_btn")
this.event_container = document.getElementById("events_container")
this.create_listeners()
}
create_listeners() {
this.auth_button.addEventListener("click", this.onclick_auth_button)
this.manual_update_btn.addEventListener("click", this.onclick_manual_update_btn)
this.start_timer_btn.addEventListener("click", this.onclick_start_timer_btn)
this.stop_timer_btn.addEventListener("click", this.onclick_stop_timer_btn)
this.domain_search_btn.addEventListener("click", this.onclick_domain_search_btn)
this.false_positive_load_btn.addEventListener("click", this.onclick_false_positive_load_btn)
this.event_container.addEventListener("click", this.onclick_event_button)
document.getElementById("modal_button").addEventListener("click", this.onclick_modal_button)
}
open_modal(title, message) {
document.getElementById("modal_title").innerText = title;
document.getElementById("modal_message").innerText = message;
document.getElementById("modal_backdrop").style.display = "flex";
}
set_loading(button_id, loading) {
const button = document.getElementById(button_id);
button.disabled = loading;
if (loading) {
button.dataset.original_text = button.innerText;
button.innerText = "Loading...";
} else {
button.innerText = button.dataset.original_text;
}
}
sync_timer_buttons() {
this.start_timer_btn.disabled = timer_running;
this.stop_timer_btn.disabled = !timer_running;
}
render_search_results(results) {
const container = document.getElementById("domain_search_results");
container.innerHTML = "";
const result_count = Object.keys(results).length;
if (!result_count) {
container.innerHTML = `<div class="search-result">No results found.</div>`;
return;
}
for (const [key, value] of Object.entries(results)) {
const row = document.createElement("div");
row.className = "search-result";
row.innerHTML = `
<div class="row">
<div class="col-8">
${key}
</div>
<div class="col-4 ${ui.event_status_class(value)}">
${value}
</div>
</div>
`;
container.appendChild(row);
}
}
onclick_auth_button() {
if (is_authenticated) {
auth.logout().then(() => {
ui.update_auth_button()
})
} else {
auth.login().then(() => {
ui.update_auth_button()
})
}
ui.update_auth_button()
}
update_auth_button() {
const button = document.getElementById("auth_button");
if (is_authenticated) {
button.innerText = "Logged In";
button.className = "button default-dm success";
} else {
button.innerText = "Logged Out";
button.className = "button default-dm secondary";
}
}
event_status_class(value) {
switch (value.toUpperCase()) {
case "ALLOWED":
return "status-good";
case "IGNORED":
return "status-warning";
default:
return "status-bad";
}
}
update_metrics(metrics){
this.blocked_domains.innerHTML = metrics.blocked_domain_count;
let date
let pretty_length
if(!metrics.last_update_complete_time){
date = "No update since last restart"
pretty_length = ""
} else {
date = new Date(metrics.last_update_complete_time * 1000).toLocaleString();
pretty_length = `${Math.round(metrics.last_update_length)} seconds`
}
this.last_update_complete_time.innerHTML = date;
this.last_update_duration.innerHTML = pretty_length;
let timer_value = ""
switch (metrics.TIMER_STATE) {
case 0:
timer_value = "RUNNING"
window.timer_running = true;
break;
case 1:
timer_value = "STOPPING"
window.timer_running = true;
break;
case 2:
timer_value = "STOPPED"
window.timer_running = false;
break;
}
this.timer_status.innerHTML = timer_value;
this.timer_status.className = timer_running ? "status-good" : "status-warning";
this.sync_timer_buttons()
let overall_status = ""
switch (metrics.MISP_STATE) {
case 0:
overall_status = "IDLE"
break;
case 1:
overall_status = "FETCHING"
break;
case 2:
overall_status = "UPDATING"
break;
case 3:
overall_status = "RELOADING"
break;
case 4:
overall_status = "ERROR"
break;
}
this.overall_status.innerHTML = overall_status;
}
render_false_positive_controls(domain_data) {
ui.false_positive_actions.style.display = "block";
const always_allow_btn = document.getElementById("always_allow_btn");
always_allow_btn.innerText = domain_data.always_allow ? "Enabled" : "Disabled";
always_allow_btn.className = domain_data.always_allow ? "button default-dm success" : "button default-dm secondary";
always_allow_btn.dataset.domain = domain_data.domain;
always_allow_btn.dataset.always_allow = domain_data.always_allow;
always_allow_btn.addEventListener("click", ui.onclick_always_allow_btn)
ui.event_container.innerHTML = "";
domain_data.events.forEach(event => {
const button = document.createElement("button");
button.className = `button event-btn ${event.ignored ? "default-dm warning" : "default-dm danger" }`;
button.innerText = event.id;
button.dataset.id = event.id;
button.dataset.ignored = event.ignored
button.dataset.domain = domain_data.domain;
ui.event_container.appendChild(button);
});
}
async onclick_manual_update_btn() {
ui.set_loading("manual_update_btn", true);
try {
const data = await api.manual_update()
if(data.state==="Starting"){
ui.open_modal(
"Update Triggered",
"Manual update process successfully started."
);
} else {
throw new Error()
}
} catch (error) {
ui.open_modal(
"Update Failed",
"Failed to trigger update process."
);
} finally {
ui.set_loading("manual_update_btn", false);
}
}
async onclick_start_timer_btn() {
ui.set_loading("start_timer_btn", true);
try {
const data = await api.start_timer()
api.update_metrics()
} catch (error) {
console.error(error);
} finally {
ui.set_loading("start_timer_btn", false);
}
}
async onclick_stop_timer_btn() {
ui.set_loading("stop_timer_btn", true);
try {
const data = await api.stop_timer()
api.update_metrics()
} catch (error) {
console.error(error);
} finally {
ui.set_loading("stop_timer_btn", false);
}
}
async onclick_domain_search_btn(){
ui.set_loading("domain_search_btn", true);
try {
const data = await api.domain_search()
ui.render_search_results(data.domains)
} catch (error) {
console.error(error);
} finally {
ui.set_loading("domain_search_btn", false);
}
}
async load_false_positive_controls(){
ui.set_loading("false_positive_load_btn", true);
ui.false_positive_actions.style.display = "none";
ui.event_container.innerHTML = "";
console.log(".")
try {
const data = await api.load_domain_fp()
if(!data){return;}
const parsed_data= {
domain: data.domain,
always_allow: data.always_allowed,
events: []
}
data.events.forEach(event => {
parsed_data.events.push({"id": event, "ignored": data.ignored_events.includes(event)});
})
ui.render_false_positive_controls(parsed_data)
} catch (error) {
console.error(error);
} finally {
ui.set_loading("false_positive_load_btn", false);
}
}
async onclick_false_positive_load_btn(){
await ui.load_false_positive_controls()
}
async onclick_event_button(event){
if (event.target === event.currentTarget) return;
const event_id = event.target.dataset.id;
const domain = event.target.dataset.domain;
const ignored = event.target.dataset.ignored === "true";
try {
if(ignored){
await api.reinstate_event(domain, event_id)
} else {
await api.ignore_event(domain, event_id)
}
await ui.load_false_positive_controls()
} catch (error) {
console.error(error);
}
}
async onclick_always_allow_btn(event){
const domain = event.target.dataset.domain;
const always_allowed = event.target.dataset.always_allow === "true";
try {
await api.change_always_allow(domain, always_allowed)
await ui.load_false_positive_controls()
} catch (error) {
console.error(error);
}
}
onclick_modal_button() {
document.getElementById("modal_backdrop").style.display = "none";
}
}
class API {
constructor() {
const self = this
this.update_metrics()
this.metrics_timer = setInterval(self.update_metrics, 5000)
}
update_metrics() {
axios.get(`misp/dashboard_metrics`)
.then(response => {
ui.update_metrics(response.data);
})
.catch(error => {
console.log(error)
})
}
async manual_update(published_timestamp = null){
const user = await auth.get_user()
return axios.put(
`misp/manual_update`,
{
"published_timestamp": published_timestamp
},
{
headers: {
"Authorization": `Bearer ${user?.access_token}`
}
}
)
.then(response => {
return response.data
})
.catch(error => {
console.log(error)
})
}
async start_timer(){
const user = await auth.get_user()
return axios.put(
`control/start_timer`,
{},
{
headers: {
"Authorization": `Bearer ${user?.access_token}`
}
}
)
.then(response => {
return response.data
})
.catch(error => {
console.log(error)
})
}
async stop_timer(){
const user = await auth.get_user()
return axios.put(
`control/stop_timer`,
{},
{
headers: {
"Authorization": `Bearer ${user?.access_token}`
}
}
)
.then(response => {
return response.data
})
.catch(error => {
console.log(error)
})
}
async domain_search(){
const user = await auth.get_user()
const search_term = document.getElementById("domain_search_input").value
return axios.get(
`misp/domain/search?domain=${search_term}`,
{},
{
headers: {
"Authorization": `Bearer ${user?.access_token}`
}
}
)
.then(response => {
return response.data
})
.catch(error => {
console.log(error)
})
}
async load_domain_fp(){
const user = await auth.get_user()
const search_term = document.getElementById("false_positive_domain").value
return axios.get(
`/misp/domain/details/${search_term}`,
{},
{
headers: {
"Authorization": `Bearer ${user?.access_token}`
}
}
)
.then(response => {
return response.data
})
.catch(error => {
console.log(error)
})
}
async ignore_event(domain, event_id){
const user = await auth.get_user()
return axios.patch(
`/misp/domain/events/${domain}/ignore?event=${event_id}`,
{},
{
headers: {
"Authorization": `Bearer ${user?.access_token}`
}
}
)
.then(response => {
return response.data
})
.catch(error => {
console.log(error)
})
}
async reinstate_event(domain, event_id){
const user = await auth.get_user()
return axios.patch(
`/misp/domain/events/${domain}/reinstate?event=${event_id}`,
{},
{
headers: {
"Authorization": `Bearer ${user?.access_token}`
}
}
)
.then(response => {
return response.data
})
.catch(error => {
console.log(error)
})
}
async change_always_allow(domain, currently_allowed){
const user = await auth.get_user()
return axios.patch(
`/misp/domain/always_allowed/${domain}?allow=${!currently_allowed}`,
{},
{
headers: {
"Authorization": `Bearer ${user?.access_token}`
}
}
)
.then(response => {
return response.data
})
.catch(error => {
console.log(error)
})
}
}
window.onload = () => {
window.ui = new UI()
window.auth = new Auth()
window.api = new API()
window.timer_running = false;
ui.sync_timer_buttons();
}