bettercap/graphpage.html
2021-04-09 16:17:26 +02:00

195 lines
6.3 KiB
HTML

<head>
<style> body {
margin: 0;
} </style>
<script src="//unpkg.com/jquery"></script>
<script src="//unpkg.com/3d-force-graph"></script>
<script src="//unpkg.com/three"></script>
<script src="//unpkg.com/three/examples/js/renderers/CSS2DRenderer.js"></script>
<script src="//unpkg.com/three-spritetext"></script>
<style>
.node-div {
font-size: 1rem;
padding: 1px 4px;
border-radius: 4px;
background-color: rgba(0, 0, 0, 0.5);
user-select: none;
}
.node-data-div {
background-color: rgba(0, 0, 0, 0.9);
}
</style>
</head>
<body>
<div id="3d-graph"></div>
<script id="vars">
const typeNodeColors = {
'ble_server': '#0066ff',
'ssid': 'transparent',
'station': '#ffcc33',
'access_point': '#ff9900',
'endpoint': '#33cc33',
'gateway': '#006600'
};
const typeColors = {
'ble_server': '#0066ff',
'ssid': '#ffff99',
'station': '#ffcc33',
'access_point': '#ff9900',
'endpoint': '#33cc33',
'gateway': '#006600'
};
var targetNode = null;
</script>
<script id="functions">
function renderNodeHTML(node) {
const nodeDiv = document.createElement('div');
switch (node.type) {
case 'ssid':
nodeDiv.innerHTML = `<small>${node.entity}</small>`
break;
case 'access_point':
var ap = node.entity;
nodeDiv.innerHTML = `
<center>
<b>${ap.hostname}</b> (${ap.encryption})
<br/>
${ap.mac}
${ap.vendor? '<br/>(' + ap.vendor + ')' : ''}
${ap.wps.length? '<br/>' + JSON.stringify(ap.wps) : ''}
</center>`;
break;
case 'station':
var sta = node.entity;
nodeDiv.innerHTML = `
<center>
${sta.mac}
${sta.vendor? '<br/>(' + sta.vendor + ')' : ''}
</center>`;
break;
case 'ble_server':
var dev = node.entity;
nodeDiv.innerHTML = `
<center>
${dev.mac}
${dev.vendor? '<br/>(' + dev.vendor + ')' : ''}
</center>`;
break;
case 'endpoint':
var ip = node.entity;
nodeDiv.innerHTML = `
<center>
${ip.hostname? '<b>' + ip.hostname + '</b><br/>' : ''}
${ip.ipv4? ip.ipv4 + '<br/>' : ''}
${ip.ipv6? ip.ipv6 + '<br/>' : ''}
<br/>
${ip.mac}
${ip.vendor? '<br/>(' + ip.vendor + ')' : ''}
${ip.meta.values.length? '<br/>' + JSON.stringify(ip.meta.values) : ''}
</center>`;
break;
case 'gateway':
var ip = node.entity;
nodeDiv.innerHTML = `
<center>
${ip.hostname? '<b>' + ip.hostname + '</b><br/>' : ''}
${ip.ipv4? ip.ipv4 + '<br/>' : ''}
${ip.ipv6? ip.ipv6 + '<br/>' : ''}
<br/>
${ip.mac}
${ip.vendor? '<br/>(' + ip.vendor + ')' : ''}
${ip.meta.values.length? '<br/>' + JSON.stringify(ip.meta.values) : ''}
</center>`;
break;
default:
nodeDiv.innerHTML = `<b>${node.id}</b>`
}
nodeDiv.style.color = typeColors[node.type];
nodeDiv.className = 'node-div';
const dataDiv = document.createElement('div');
dataDiv.id = 'datadiv_' + node.id;
dataDiv.className = 'node-data-div';
dataDiv.style.visibility = 'hidden';
dataDiv.style.display = 'none';
dataDiv.innerHTML = '<br/><pre>' + node.type + ' ' + JSON.stringify(node.entity, null, 2) + '</pre>';
nodeDiv.appendChild(dataDiv);
return new THREE.CSS2DObject(nodeDiv);
}
</script>
<script id="graph">
const Graph = ForceGraph3D({
extraRenderers: [new THREE.CSS2DRenderer()],
controlType: 'orbit'
})
(document.getElementById('3d-graph'))
.jsonUrl('bettergraph.json')
.nodeLabel('id')
.nodeColor(node => typeNodeColors[node.type])
.linkDirectionalArrowLength(3.5)
.linkDirectionalArrowRelPos(1)
/*
.linkThreeObjectExtend(true)
.linkThreeObject(link => {
const sprite = new SpriteText(link.edge.type);
sprite.color = 'lightgrey';
sprite.textHeight = 1.5;
return sprite;
})
.linkPositionUpdate((sprite, {start, end}) => {
const middlePos = Object.assign(...['x', 'y', 'z'].map(c => ({
[c]: start[c] + (end[c] - start[c]) / 2 // calc middle point
})));
Object.assign(sprite.position, middlePos);
})
*/
.nodeThreeObject(renderNodeHTML)
.nodeThreeObjectExtend(true)
.onNodeClick(node => {
if( targetNode != null ) {
const prev = document.getElementById('datadiv_' + targetNode.id);
prev.style.visibility = 'hidden';
prev.style.display = 'none';
}
targetNode = node;
const curr = document.getElementById('datadiv_' + targetNode.id);
curr.style.visibility = 'visible';
curr.style.display = 'block';
// Aim at node from outside it
const distance = 40;
const distRatio = 1 + distance/Math.hypot(node.x, node.y, node.z);
Graph.cameraPosition(
{ x: node.x * distRatio, y: node.y * distRatio, z: node.z * distRatio }, // new position
node, // lookAt ({ x, y, z })
3000 // ms transition duration
);
});
</script>
</body>