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 = `
No results found.
`; return; } for (const [key, value] of Object.entries(results)) { const row = document.createElement("div"); row.className = "search-result"; row.innerHTML = `
${key}
${value}
`; 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(); }