Compare commits

...

7 Commits

10 changed files with 252 additions and 116 deletions

17
Dockerfile Normal file
View File

@ -0,0 +1,17 @@
FROM node:16
# Create app directory
WORKDIR /usr/src/app
ENV WEB_IP "$WEB_ADDRESS_INT"
# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./
RUN npm install
# If you are building your code for production
# RUN npm ci --only=production
# Bundle app source
COPY . .
EXPOSE 3100
EXPOSE 8999
CMD [ "npm", "start" ]

View File

@ -2,6 +2,8 @@
Ntopng alerts are displayed in Globe.gl Ntopng alerts are displayed in Globe.gl
![Example Image](https://git.dergeorg.at/dergeorg/NtopngGlobe/raw/branch/master/public/images/example.png)
### Install packages ### Install packages
``` sh ``` sh
npm install npm install
@ -15,6 +17,19 @@ npm install
npm start npm start
``` ```
### Docker
[DockerHub link](https://hub.docker.com/r/dergeorg/ntopngglobe)
#### Run with config file
```sh
docker run -p 3100:3100 -p 8999:8999 --name ntopngglobe -v /PATH/TO/CONF/FOLDER:/usr/src/app/public/conf -d dergeorg/ntopngglobe
```
#### Run without config file (default config)
```sh
docker run -p 3100:3100 -p 8999:8999 --name ntopngglobe -d dergeorg/ntopngglobe
```
### Usage ### Usage
> :notebook: **Open in browser**: ```http://<ADRESS>:3100``` > :notebook: **Open in browser**: ```http://<ADRESS>:3100```
@ -23,7 +38,67 @@ npm start
* Manual refresh on left-click * Manual refresh on left-click
* Click on arc reveals whole "Ntopng Alert" * Click on arc reveals whole "Ntopng Alert"
* Hover on arc reveals src/dest ip/hostname * Hover on arc reveals src/dest ip/hostname
#### Colors #### Colors
* Orange arc is a bidirectional request (sender and receiver are swapped) * Orange arc is a bidirectional request (sender and receiver are swapped)
* Red side of arc is receiving * Red side of arc is receiving
* Green side of arc is sending * Green side of arc is sending
### Settings example
[settings.json](https://git.dergeorg.at/dergeorg/NtopngGlobe/src/branch/master/public/conf/settings.json)
```json
{
"location": {
"home": {
"lat": 48.1, // must be set to lat of home wan ip --> https://www.maxmind.com/en/locate-my-ip-address
"lng": 16.3 // must be set to lng of home wan ip --> https://www.maxmind.com/en/locate-my-ip-address
},
"precision": 0 // how to round the decimal. 0 is no decimal
},
"colors": {
"loc": {
"default": "green",
"dualsender": "orange"
},
"arc": {
"default": [
"green",
"red"
],
"dualsender": [
"orange",
"orange"
]
}
},
"sizes": {
"loc": {
"default": 0.1
},
"arc": {
"default": 1.1
},
"globe": {
"arcDashLength": 0.4,
"arcAltitudeAutoScale": 0.4,
"arcDashGap": 0.1,
"arcDashInitialGap": 0.1,
"arcDashAnimateTime": 7000,
"arcStroke": 0.5,
"labelSize": 0,
"labelDotRadius": 0.4,
"labelResolution": 2
}
},
"timer": {
"del": 30, // deletes alerts older than 30 minutes
"refreshTimer": 1 // 1 --> refresh globe every 1 minute; 0 --> refresh globe on every new Data set
},
"ips": {
"home": "192.168.1.", //Private home adress
"loopback": "127.0.0.1",
"server": "localhost:3100", //Server adress
"serverws": "localhost:8999" //websocket adress
}
}
```

4
app.js
View File

@ -18,7 +18,9 @@ var usersRouter = require('./routes/users');
// view engine setup // view engine setup
app.set('views', path.join(__dirname, 'views')); app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade'); app.set('view engine', 'jade');
app.use(cors()) app.use(cors({
origin: 'globe.dergeorg.at'
}))
app.use(logger('dev')); app.use(logger('dev'));
app.use(express.json()); app.use(express.json());
app.use(express.urlencoded({ extended: false })); app.use(express.urlencoded({ extended: false }));

View File

@ -3,47 +3,7 @@ var data = {
arc: [] arc: []
} }
var settings = { var settings = require('../public/conf/settings.json')
location: {
home: {
lat: 48.1,
lng: 16.3
},
precision: 0
},
colors: {
loc: {
default: "green",
dualsender: "orange"
},
arc: {
default: ["green", "red"],
dualsender: ["orange", "orange"]
}
},
sizes: {
loc: {
default: 0.1
},
arc: {
default: 1.1
},
globe: {
arcDashLength: 0.4,
arcAltitudeAutoScale: 0.4,
arcDashGap: 0.1,
arcDashInitialGap: 0.1,
arcDashAnimateTime: 7000,
arcStroke: 0.5,
labelSize: 0,
labelDotRadius: 0.4,
labelResolution: 2
}
},
timer:{
del: 30
}
}
var geoip = require('fast-geoip'); var geoip = require('fast-geoip');
@ -56,7 +16,7 @@ async function addArc(src, dest, uid, src_name, dest_name){
var endLat = undefined; var endLat = undefined;
var endLng = undefined; var endLng = undefined;
if(!data.arc.some(x => x.src === src && x.dest === dest)) { if(!data.arc.some(x => x.src === src && x.dest === dest)) {
if (src.includes("192.168.1.") || src.includes("127.0.0.1")) { if (src.includes(settings.ips.home) || src.includes("127.0.0.1")) {
startLat = round(settings.location.home.lat, settings.location.precision) startLat = round(settings.location.home.lat, settings.location.precision)
startLng = round(settings.location.home.lng, settings.location.precision) startLng = round(settings.location.home.lng, settings.location.precision)
} else { } else {

29
package-lock.json generated
View File

@ -17,7 +17,8 @@
"jade": "~1.11.0", "jade": "~1.11.0",
"morgan": "~1.9.1", "morgan": "~1.9.1",
"node-cron": "^3.0.0", "node-cron": "^3.0.0",
"uuid": "^8.3.2" "uuid": "^8.3.2",
"ws": "^8.4.2"
} }
}, },
"node_modules/accepts": { "node_modules/accepts": {
@ -1002,6 +1003,26 @@
"node": ">=0.4.0" "node": ">=0.4.0"
} }
}, },
"node_modules/ws": {
"version": "8.4.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.4.2.tgz",
"integrity": "sha512-Kbk4Nxyq7/ZWqr/tarI9yIt/+iNNFOjBXEWgTb4ydaNHBNGgvf2QHbS9fdfsndfjFlFwEd4Al+mw83YkaD10ZA==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/yargs": { "node_modules/yargs": {
"version": "3.10.0", "version": "3.10.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
@ -1774,6 +1795,12 @@
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
"integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8="
}, },
"ws": {
"version": "8.4.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.4.2.tgz",
"integrity": "sha512-Kbk4Nxyq7/ZWqr/tarI9yIt/+iNNFOjBXEWgTb4ydaNHBNGgvf2QHbS9fdfsndfjFlFwEd4Al+mw83YkaD10ZA==",
"requires": {}
},
"yargs": { "yargs": {
"version": "3.10.0", "version": "3.10.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",

View File

@ -15,6 +15,7 @@
"jade": "~1.11.0", "jade": "~1.11.0",
"morgan": "~1.9.1", "morgan": "~1.9.1",
"node-cron": "^3.0.0", "node-cron": "^3.0.0",
"uuid": "^8.3.2" "uuid": "^8.3.2",
"ws": "^8.4.2"
} }
} }

54
public/conf/settings.json Normal file
View File

@ -0,0 +1,54 @@
{
"location": {
"home": {
"lat": 48.1,
"lng": 16.3
},
"precision": 0
},
"colors": {
"loc": {
"default": "green",
"dualsender": "orange"
},
"arc": {
"default": [
"green",
"red"
],
"dualsender": [
"orange",
"orange"
]
}
},
"sizes": {
"loc": {
"default": 0.1
},
"arc": {
"default": 1.1
},
"globe": {
"arcDashLength": 0.4,
"arcAltitudeAutoScale": 0.4,
"arcDashGap": 0.1,
"arcDashInitialGap": 0.1,
"arcDashAnimateTime": 7000,
"arcStroke": 0.5,
"labelSize": 0,
"labelDotRadius": 0.4,
"labelResolution": 2
}
},
"timer": {
"del": 30,
"refreshTimer": 1
},
"ips": {
"home": "192.168.1.",
"loopback": "127.0.0.1",
"server": "localhost:3100",
"serverws": "localhost:8999"
}
}

View File

@ -80,77 +80,72 @@
item.cli_os + " \nis_srv_vic " + item.is_srv_vic item.cli_os + " \nis_srv_vic " + item.is_srv_vic
} }
function componentDidMount() {
var data = {};
if ("WebSocket" in window) {
console.log("WebSocket is supported by your Browser!");
const ws = new WebSocket('ws://localhost:8999');
ws.onopen = function () {
// Web Socket is connected, send data using send()
console.log("Message is sent...");
};
ws.onmessage = function (evt) {
var received_msg = evt.data;
console.log("Message is received...");
componentDidMount()
};
ws.onclose = function () {
// websocket is closed.
console.log("Connection is closed...");
};
}else {
// The browser doesn't support WebSocket
alert("WebSocket NOT supported by your Browser! A left click on the globe will refresh the data");
}
axios.get("http://localhost:3100/display").then(res => { function componentDidMount() {
data = res.data; axios.get('/conf/settings.json').then(res => {
console.log(data) const settings = res.data;
ReactDOM.render( var data = {};
<Globe if ("WebSocket" in window) {
onGlobeClick={() => { console.log("WebSocket is supported by your Browser!");
axios.get("http://localhost:3100/display").then(res => { const ws = new WebSocket('ws://'+settings.ips.server);
data = res.data; ws.onmessage = function (evt) {
componentDidMount() var received_msg = evt.data;
}); componentDidMount()
}} };
globeImageUrl="/images/earth-night.jpg" }else {
backgroundImageUrl="/images/night-sky.png" // The browser doesn't support WebSocket
backgroundColor={"#000011"} alert("WebSocket NOT supported by your Browser! A left click on the globe will refresh the data");
// edges }
arcsData={data.arc}
arcColor={(d) => [d.color[0], d.color[1]]} axios.get("http://"+settings.ips.server+"/display").then(res => {
arcDashLength={data.settings.sizes.globe.arcDashLength} data = res.data;
arcAltitudeAutoScale={data.settings.sizes.globe.arcAltitudeAutoScale} console.log(data)
arcDashGap={data.settings.sizes.globe.arcDashGap} ReactDOM.render(
arcDashInitialGap={data.settings.sizes.globe.arcDashInitialGap} <Globe
arcDashAnimateTime={data.settings.sizes.globe.arcDashAnimateTime} onGlobeClick={() => {
arcStroke={data.settings.sizes.globe.arcStroke} axios.get("http://"+settings.ips.server+"/display").then(res => {
arcLabel={(d) => generateHoverText(d.txrx)} data = res.data;
onArcClick={function (d) { componentDidMount()
axios.get("http://localhost:3100/alert/" + d.uid).then(res => { });
const resdata = res.data; }}
alert(generateClickText(resdata)) globeImageUrl="/images/earth-night.jpg"
}) backgroundImageUrl="/images/night-sky.png"
}} backgroundColor={"#000011"}
//arcCircularResolution={64} // edges
// arcLabel={() => "test"} arcsData={data.arc}
// labels arcColor={(d) => [d.color[0], d.color[1]]}
labelsData={data.loc} arcDashLength={data.settings.sizes.globe.arcDashLength}
labelLat={(d) => d.lat} arcAltitudeAutoScale={data.settings.sizes.globe.arcAltitudeAutoScale}
labelLng={(d) => d.lng} arcDashGap={data.settings.sizes.globe.arcDashGap}
labelText={(d) => d.name} arcDashInitialGap={data.settings.sizes.globe.arcDashInitialGap}
// labelSize={(d) => 0.5 + d.size} arcDashAnimateTime={data.settings.sizes.globe.arcDashAnimateTime}
labelSize={0} arcStroke={data.settings.sizes.globe.arcStroke}
labelDotRadius={0.4} arcLabel={(d) => generateHoverText(d.txrx)}
// labelDotRadius={(d) => 0.5 + d.size} onArcClick={function (d) {
labelColor={(d) => d.color} axios.get("http://"+settings.ips.server+"/alert/" + d.uid).then(res => {
labelResolution={2} const resdata = res.data;
enablePointerInteraction={true} alert(generateClickText(resdata))
/>, })
document.getElementById('globeViz') }}
); //arcCircularResolution={64}
}).catch(err => alert(err)) // arcLabel={() => "test"}
// labels
labelsData={data.loc}
labelLat={(d) => d.lat}
labelLng={(d) => d.lng}
labelText={(d) => d.name}
// labelSize={(d) => 0.5 + d.size}
labelSize={0}
labelDotRadius={0.4}
// labelDotRadius={(d) => 0.5 + d.size}
labelColor={(d) => d.color}
labelResolution={2}
enablePointerInteraction={true}
/>,
document.getElementById('globeViz')
);
}).catch(err => alert(err))
})
} }
componentDidMount() componentDidMount()

BIN
public/images/example.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 814 KiB

View File

@ -53,6 +53,9 @@ router.get('/alerts/dates', function(req, res, next) {
}); });
var task = cron.schedule('* * * * *', () => { var task = cron.schedule('* * * * *', () => {
if(globe.getSettigns().timer.refreshTimer === 1) {
wss.broadcast("new data is da")
}
const TEN_MINUTES = globe.getSettigns().timer.del*60*1000; const TEN_MINUTES = globe.getSettigns().timer.del*60*1000;
const date = new Date(); const date = new Date();
alerts.getAlertDates().forEach(ad => { alerts.getAlertDates().forEach(ad => {
@ -79,7 +82,9 @@ router.post('/ws', async function(req, res, next) {
if (typeof src !== 'undefined' || typeof dest !== 'undefined') if (typeof src !== 'undefined' || typeof dest !== 'undefined')
await globe.addArc(src, dest, uid, item.srv_name, item.cli_name) await globe.addArc(src, dest, uid, item.srv_name, item.cli_name)
} }
wss.broadcast("new data is da") if(globe.getSettigns().timer.refreshTimer === 0) {
wss.broadcast("new data is da")
}
res.sendStatus(200); res.sendStatus(200);
}) })