Add client comments & fix server side port sorting
This commit is contained in:
parent
464ed3d7ef
commit
008bb93111
@ -285,7 +285,7 @@ class Scanner(Thread):
|
|||||||
results.extend(
|
results.extend(
|
||||||
list(map(lambda x: "%s TCP" % x, self.tcp_results))
|
list(map(lambda x: "%s TCP" % x, self.tcp_results))
|
||||||
) # noqa: E501
|
) # noqa: E501
|
||||||
results.sort()
|
results.sort(key=lambda x: int(x.split(" ")[0]))
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def __scan_tcp(self):
|
def __scan_tcp(self):
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
src/overseer/static/js/app.f1a42415.js
Normal file
2
src/overseer/static/js/app.f1a42415.js
Normal file
File diff suppressed because one or more lines are too long
1
src/overseer/static/js/app.f1a42415.js.map
Normal file
1
src/overseer/static/js/app.f1a42415.js.map
Normal file
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
|||||||
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/static/favicon.ico"><title>Overseer</title><link href="/static/css/app.4fe206b0.css" rel="preload" as="style"><link href="/static/js/app.e5e6eeee.js" rel="preload" as="script"><link href="/static/js/chunk-vendors.1f751c93.js" rel="preload" as="script"><link href="/static/css/app.4fe206b0.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but Overseer doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="/static/js/chunk-vendors.1f751c93.js"></script><script src="/static/js/app.e5e6eeee.js"></script></body></html>
|
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/static/favicon.ico"><title>Overseer</title><link href="/static/css/app.a6dc3078.css" rel="preload" as="style"><link href="/static/js/app.f1a42415.js" rel="preload" as="script"><link href="/static/js/chunk-vendors.1f751c93.js" rel="preload" as="script"><link href="/static/css/app.a6dc3078.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but Overseer doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="/static/js/chunk-vendors.1f751c93.js"></script><script src="/static/js/app.f1a42415.js"></script></body></html>
|
@ -25,6 +25,9 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
/**
|
||||||
|
* Emits a notification to the Notification component.
|
||||||
|
**/
|
||||||
toggleNotifications() {
|
toggleNotifications() {
|
||||||
this.$root.$emit("toggleNotifications");
|
this.$root.$emit("toggleNotifications");
|
||||||
}
|
}
|
||||||
|
@ -32,9 +32,15 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
/**
|
||||||
|
* Routes the user to the provided scan.
|
||||||
|
**/
|
||||||
navigateToScan(scan) {
|
navigateToScan(scan) {
|
||||||
this.$router.push({ path: `/scan/${scan.target}/${scan.id}` })
|
this.$router.push({ path: `/scan/${scan.target}/${scan.id}` })
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Derives notification drawer CSS to open / close.
|
||||||
|
**/
|
||||||
deriveNotificationCSS(showNotifications) {
|
deriveNotificationCSS(showNotifications) {
|
||||||
return {
|
return {
|
||||||
"right": showNotifications ? "0px" : "-320px"
|
"right": showNotifications ? "0px" : "-320px"
|
||||||
@ -42,6 +48,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
// Sets up listener for toggleNotification event
|
||||||
this.$root.$on("toggleNotifications", () => {
|
this.$root.$on("toggleNotifications", () => {
|
||||||
this.showNotifications = !this.showNotifications;
|
this.showNotifications = !this.showNotifications;
|
||||||
});
|
});
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<ul>
|
<ul>
|
||||||
<li v-for="port in ports" :key="port" v-bind:style="getItemWidth()">
|
<li v-for="port in ports" :key="port" v-bind:style="deriveItemWidth()">
|
||||||
<span>{{ port.split(" ")[0] }}</span>
|
<span style="margin: auto;">{{ port.split(" ")[0] }}</span>
|
||||||
<span class="proto" v-bind:style="dynamicProtocolStyle(port.split(' ')[1])" >{{ port.split(" ")[1] }}</span>
|
<span class="proto" v-bind:style="deriveProtocolStyle(port.split(' ')[1])" >{{ port.split(" ")[1] }}</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</template>
|
</template>
|
||||||
@ -12,12 +12,18 @@ export default {
|
|||||||
name: 'PortList',
|
name: 'PortList',
|
||||||
props: ["ports", "itemWidth"],
|
props: ["ports", "itemWidth"],
|
||||||
methods: {
|
methods: {
|
||||||
dynamicProtocolStyle(proto) {
|
/**
|
||||||
|
* Derives TCP / UDP background colors (Default Wireshark colors)
|
||||||
|
**/
|
||||||
|
deriveProtocolStyle(proto) {
|
||||||
return {
|
return {
|
||||||
backgroundColor: proto == "TCP" ? "#E7E6FF" : "#D5EFFF",
|
backgroundColor: proto == "TCP" ? "#E7E6FF" : "#D5EFFF",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getItemWidth() {
|
/**
|
||||||
|
* Derives item width (If provided)
|
||||||
|
**/
|
||||||
|
deriveItemWidth() {
|
||||||
return {
|
return {
|
||||||
width: this.itemWidth || "75px"
|
width: this.itemWidth || "75px"
|
||||||
}
|
}
|
||||||
@ -31,7 +37,7 @@ export default {
|
|||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 0px 2px;
|
padding: 0px 2px;
|
||||||
color: #0A282F;
|
color: #0A282F;
|
||||||
margin-left: 5px;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
li {
|
li {
|
||||||
|
@ -24,6 +24,11 @@ export default {
|
|||||||
PortList,
|
PortList,
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
/**
|
||||||
|
* Returns left outer join between s1 scan, and s2 scan. We use this
|
||||||
|
* to figure out what ports have been add / removed between the two
|
||||||
|
* reference scans.
|
||||||
|
**/
|
||||||
getPortDiff(s1, s2) {
|
getPortDiff(s1, s2) {
|
||||||
return s1.results
|
return s1.results
|
||||||
.filter(p => !s2.results.includes(p));
|
.filter(p => !s2.results.includes(p));
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="scan-progress" >
|
<div class="scan-progress" >
|
||||||
<span style="right: 46.5%;">{{ title }}</span>
|
<span style="right: 46.5%;">{{ title }}</span>
|
||||||
<div v-bind:style="scanProgress(percentage)"></div>
|
<div v-bind:style="deriveScanProgressStyle(percentage)"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -10,8 +10,13 @@ export default {
|
|||||||
name: 'ScanProgress',
|
name: 'ScanProgress',
|
||||||
props: ["percentage", "title"],
|
props: ["percentage", "title"],
|
||||||
methods: {
|
methods: {
|
||||||
scanProgress(perc) {
|
/**
|
||||||
// Calculate color based on percentage - https://gist.github.com/mlocati/7210513
|
* Derives the style to reflect the provided percentage. Also
|
||||||
|
* calculates the appropriate hex color.
|
||||||
|
*
|
||||||
|
* Reference: https://gist.github.com/mlocati/7210513
|
||||||
|
**/
|
||||||
|
deriveScanProgressStyle(perc) {
|
||||||
let r, g, b = 0;
|
let r, g, b = 0;
|
||||||
if (perc < 50) {
|
if (perc < 50) {
|
||||||
r = 255;
|
r = 255;
|
||||||
|
@ -42,6 +42,9 @@ export default {
|
|||||||
ScanProgress,
|
ScanProgress,
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
/**
|
||||||
|
* Converts a dateISO string to a more presentable format.
|
||||||
|
**/
|
||||||
normalizeDate(dateISO) {
|
normalizeDate(dateISO) {
|
||||||
let parsedDate = new Date(dateISO);
|
let parsedDate = new Date(dateISO);
|
||||||
return parsedDate.toDateString() + " " + parsedDate.toLocaleTimeString()
|
return parsedDate.toDateString() + " " + parsedDate.toLocaleTimeString()
|
||||||
@ -59,7 +62,7 @@ export default {
|
|||||||
|
|
||||||
#sub-status {
|
#sub-status {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 200px;
|
width: 190px;
|
||||||
margin: -5px auto 10px auto;
|
margin: -5px auto 10px auto;
|
||||||
border-bottom: 1px solid;
|
border-bottom: 1px solid;
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,9 @@ import router from './router';
|
|||||||
import VueSocketIO from 'vue-socket.io';
|
import VueSocketIO from 'vue-socket.io';
|
||||||
import socketio from 'socket.io-client';
|
import socketio from 'socket.io-client';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initiates the Websocket connection with the API server.
|
||||||
|
**/
|
||||||
Vue.use(new VueSocketIO({
|
Vue.use(new VueSocketIO({
|
||||||
debug: true,
|
debug: true,
|
||||||
connection: socketio({ path: "/api/v1/socket.io" }),
|
connection: socketio({ path: "/api/v1/socket.io" }),
|
||||||
@ -17,6 +20,9 @@ Vue.use(new VueSocketIO({
|
|||||||
|
|
||||||
Vue.config.productionTip = false
|
Vue.config.productionTip = false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the Overseer Vue Application.
|
||||||
|
**/
|
||||||
new Vue({
|
new Vue({
|
||||||
render: h => h(App),
|
render: h => h(App),
|
||||||
router,
|
router,
|
||||||
|
@ -7,6 +7,9 @@ import NotFound from '../views/NotFound.vue'
|
|||||||
|
|
||||||
Vue.use(VueRouter)
|
Vue.use(VueRouter)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define all routes within the Overseer SPA.
|
||||||
|
**/
|
||||||
const routes = [
|
const routes = [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
|
@ -3,18 +3,21 @@ import Vuex from 'vuex'
|
|||||||
|
|
||||||
Vue.use(Vuex)
|
Vue.use(Vuex)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exports a new Vuex store. Responsible for API access and maintaining a cache
|
||||||
|
* of requested and pushed Websocket data.
|
||||||
|
**/
|
||||||
export default new Vuex.Store({
|
export default new Vuex.Store({
|
||||||
state: {
|
state: {
|
||||||
ws_connected: false,
|
ws_connected: false,
|
||||||
notifications: [],
|
notifications: [],
|
||||||
scan_cache: {}
|
scan_cache: {}
|
||||||
},
|
},
|
||||||
getters: {
|
|
||||||
getScansByTarget(state, target){
|
|
||||||
return state.scan_cache[target]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
actions: {
|
actions: {
|
||||||
|
/**
|
||||||
|
* Queries the API for all scans for the given target, then commits the
|
||||||
|
* result to the store.
|
||||||
|
**/
|
||||||
getScansByTarget({ commit }, target){
|
getScansByTarget({ commit }, target){
|
||||||
return fetch('/api/v1/scans/' + target)
|
return fetch('/api/v1/scans/' + target)
|
||||||
.then(resp => resp.json())
|
.then(resp => resp.json())
|
||||||
@ -22,6 +25,10 @@ export default new Vuex.Store({
|
|||||||
commit("SET_TARGET_SCANS", { target, data: json.data });
|
commit("SET_TARGET_SCANS", { target, data: json.data });
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Requests a scan from the API. On response, commits the new scan to
|
||||||
|
* the store.
|
||||||
|
**/
|
||||||
performScan({ commit }, target) {
|
performScan({ commit }, target) {
|
||||||
return fetch('/api/v1/scans', {
|
return fetch('/api/v1/scans', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@ -37,9 +44,15 @@ export default new Vuex.Store({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
|
/**
|
||||||
|
* Sets the state of the scan cache for a given target.
|
||||||
|
**/
|
||||||
"SET_TARGET_SCANS"(state, { target, data }) {
|
"SET_TARGET_SCANS"(state, { target, data }) {
|
||||||
Vue.set(state.scan_cache, target, data)
|
Vue.set(state.scan_cache, target, data)
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Upserts a scan in the scan cache store.
|
||||||
|
**/
|
||||||
"UPDATE_SCAN"(state, { scan }) {
|
"UPDATE_SCAN"(state, { scan }) {
|
||||||
let target = scan.target;
|
let target = scan.target;
|
||||||
if (!state.scan_cache[target]) {
|
if (!state.scan_cache[target]) {
|
||||||
@ -56,6 +69,10 @@ export default new Vuex.Store({
|
|||||||
state.scan_cache[target].unshift(scan);
|
state.scan_cache[target].unshift(scan);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Listens to all 'message' Websocket events for scan progress data
|
||||||
|
* in order to update the scan cache and notification queue.
|
||||||
|
**/
|
||||||
"SOCKET_message"(state, scan) {
|
"SOCKET_message"(state, scan) {
|
||||||
// Update progress queue
|
// Update progress queue
|
||||||
let matchedItem = state.notifications.find(item => item.id == scan.id);
|
let matchedItem = state.notifications.find(item => item.id == scan.id);
|
||||||
@ -69,9 +86,17 @@ export default new Vuex.Store({
|
|||||||
// Update scan cache
|
// Update scan cache
|
||||||
this.commit("UPDATE_SCAN", { scan });
|
this.commit("UPDATE_SCAN", { scan });
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Listens for Websocket connect events. This is used for the green /
|
||||||
|
* red 'O' in the Overseer logo. Green = connected, Red = disconnected.
|
||||||
|
**/
|
||||||
"SOCKET_connect"(state) {
|
"SOCKET_connect"(state) {
|
||||||
state.ws_connected = true
|
state.ws_connected = true
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Listens for Websocket connect events. This is used for the green /
|
||||||
|
* red 'O' in the Overseer logo. Green = connected, Red = disconnected.
|
||||||
|
**/
|
||||||
"SOCKET_disconnect"(state) {
|
"SOCKET_disconnect"(state) {
|
||||||
state.ws_connected = false
|
state.ws_connected = false
|
||||||
},
|
},
|
||||||
|
@ -27,6 +27,10 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
/**
|
||||||
|
* Initiates a new scan for the inputted hostname / IP address.
|
||||||
|
* Routes the user to the history view of the requested target.
|
||||||
|
**/
|
||||||
onSubmit(event){
|
onSubmit(event){
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
this.error = null;
|
this.error = null;
|
||||||
@ -34,7 +38,8 @@ export default {
|
|||||||
.then(scan => {
|
.then(scan => {
|
||||||
if (scan.error)
|
if (scan.error)
|
||||||
throw new Error(scan.error)
|
throw new Error(scan.error)
|
||||||
this.$router.push({ path: `/scan/${event.target.value}/${scan.id}` })
|
this.$router.push({ path: `/scan/${event.target.value}` })
|
||||||
|
// this.$router.push({ path: `/scan/${event.target.value}/${scan.id}` })
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
this.error = err;
|
this.error = err;
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
:scan="scan"
|
:scan="scan"
|
||||||
:error="error"
|
:error="error"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
style="padding: 20px; margin-top: 25px; border-radius: 5px; box-shadow: 0px 0px 10px #e0e3de;"/>
|
style="padding: 20px; margin-top: 25px; border-radius: 5px; box-shadow: 0px 0px 10px black;"/>
|
||||||
|
|
||||||
<div ref="compareContainer"
|
<div ref="compareContainer"
|
||||||
v-if="getRequestedScans.length != index + 1"
|
v-if="getRequestedScans.length != index + 1"
|
||||||
@ -49,6 +49,9 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
/**
|
||||||
|
* Returns requested scans based on filters and URI
|
||||||
|
**/
|
||||||
getRequestedScans() {
|
getRequestedScans() {
|
||||||
let scanCache = this.$store.state.scan_cache;
|
let scanCache = this.$store.state.scan_cache;
|
||||||
let target = this.$route.params.target;
|
let target = this.$route.params.target;
|
||||||
@ -70,6 +73,10 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
/**
|
||||||
|
* Determines whether a comparison is expanded, and returns the
|
||||||
|
* appropriate style.
|
||||||
|
**/
|
||||||
deriveCompareStyle(scan) {
|
deriveCompareStyle(scan) {
|
||||||
if (!this.openCompare.includes(scan))
|
if (!this.openCompare.includes(scan))
|
||||||
return {};
|
return {};
|
||||||
@ -79,6 +86,10 @@ export default {
|
|||||||
"max-height": "10000px",
|
"max-height": "10000px",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Updates component variable to expand or collapse a specified
|
||||||
|
* scan comparison.
|
||||||
|
**/
|
||||||
toggleCompare(scan) {
|
toggleCompare(scan) {
|
||||||
if (this.openCompare.includes(scan))
|
if (this.openCompare.includes(scan))
|
||||||
this.openCompare = this.openCompare
|
this.openCompare = this.openCompare
|
||||||
@ -86,15 +97,20 @@ export default {
|
|||||||
else
|
else
|
||||||
this.openCompare.push(scan);
|
this.openCompare.push(scan);
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Initiates a new scan for the currently displayed target and
|
||||||
|
* navigates to the history view of said target.
|
||||||
|
**/
|
||||||
performScan() {
|
performScan() {
|
||||||
this.error = null;
|
this.error = null;
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
|
||||||
this.$store.dispatch("performScan", this.$route.params.target)
|
this.$store.dispatch("performScan", this.$route.params.target)
|
||||||
.then(scan => {
|
.then(scan => {
|
||||||
if (scan.error)
|
if (scan.error)
|
||||||
throw new Error(scan.error)
|
throw new Error(scan.error)
|
||||||
this.$router.push({ path: `/scan/${this.$route.params.target}` })
|
this.$router.push({ path: `/scan/${this.$route.params.target}` })
|
||||||
|
|
||||||
|
// If you want to navigate to the specific scan
|
||||||
// this.$router.push({ path: `/scan/${this.$route.params.target}/${scan.id}` })
|
// this.$router.push({ path: `/scan/${this.$route.params.target}/${scan.id}` })
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
this.error = err;
|
this.error = err;
|
||||||
@ -104,6 +120,7 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted(){
|
mounted(){
|
||||||
|
// Acquires scans by requested target from the Vuex store.
|
||||||
this.$store.dispatch("getScansByTarget", this.$route.params.target);
|
this.$store.dispatch("getScansByTarget", this.$route.params.target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
6
src/overseer_client/src/views/Targets.vue
Normal file
6
src/overseer_client/src/views/Targets.vue
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<template>
|
||||||
|
<div style="padding-top: 300px;">
|
||||||
|
<h1>Error</h1>
|
||||||
|
<h4>404 Page Not Found</h4>
|
||||||
|
</div>
|
||||||
|
</template>
|
Loading…
Reference in New Issue
Block a user