Add mac-check app

This commit is contained in:
Dzejkobik007
2023-01-19 23:38:38 +01:00
parent 271a17cd16
commit 1bcc8212e9
11 changed files with 33577 additions and 0 deletions

10
wap/mac-check/Dockerfile Normal file
View File

@@ -0,0 +1,10 @@
FROM node:12.18.1
ENV NODE_ENV=production
COPY "src" "/app"
WORKDIR /app
RUN npm install --production
CMD [ "node", "app.js" ]

View File

@@ -0,0 +1,11 @@
version: '3'
services:
node:
build:
context: .
dockerfile: Dockerfile
container_name: mac-check
restart: always
ports:
- 80:80

121
wap/mac-check/src/app.js Normal file
View File

@@ -0,0 +1,121 @@
const csv = require('fast-csv');
const sha256 = require('simple-sha256')
const xml = require('object-to-xml');
const fs = require('fs');
const path = require('path');
const { response, json } = require('express');
const express = require('express');
const e = require('express');
const app = express();
const port = 80;
const secret = "123456";
let ready = false;
app.use(express.static('public'));
function loadOrg(filename, options) {
console.log("Loading records....");
let orgdata = {};
fs.createReadStream(path.resolve(__dirname, filename))
.pipe(csv.parse(options))
.on('error', error => console.error(error))
.on('data', row => {orgdata[`${row[0]}`] = row[1]})
.on('end', rowCount => {console.log(`Loaded ${rowCount} records`); ready = true });
return orgdata;
}
function error(ans, req, res) {
if (req.query.format == "xml"){
res.set('Content-Type', 'text/xml');
res.send(xml({ xml: ans}));
} else if (req.query.format == "csv") {
res.send(ans.error);
} else {
res.json(ans);
}
}
app.get('/api/range/:mac', (req, res) => {
// console.log(req);
allowed = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"];
mac = req.params.mac.toUpperCase();
newmac = "";
if(mac.length < 6) {
res.status(400);
ans = { error: 'Mac address too short', code: 400 };
error(ans, req, res);
return;
}
for (var i = 0; i < 6; i++) {
if (allowed.includes(mac.charAt(i))) {
newmac = newmac + mac.charAt(i);
} else {
res.status(400);
ans = { error: 'Invalid mac', code: 400 };
error(ans, req, res);
return;
}
}
while(!ready) {};
if(orgdata[mac] !== undefined) {
result = {"range":mac,"organization":orgdata[mac]};
console.log(JSON.stringify(result));
const resulthash = sha256.sync(result+secret);
if (req.query.format == "xml"){
res.set('Content-Type', 'text/xml');
res.send(xml({xml: {result: result, code:200, hash:resulthash}},));
} else if (req.query.format == "csv") {
res.set('Content-Type', 'text/csv');
res.send(result.mac+","+result.organization);
} else {
res.json({result: result, code:200, hash:resulthash});
}
} else {
res.status(404);
ans = {error:"Range not found", code: 404};
error(ans, req, res);
return;
}
})
app.use(function (req, res, next) {
res.status(404);
console.log(req.query);
ans = { error: 'Not found', code: 404 }
if (req.query.format == "xml"){
res.set('Content-Type', 'text/xml');
res.send(xml({xml: ans}));
} else if (req.query.format == "csv") {
res.send(ans.error);
} else if (req.query.format == "json") {
res.json(ans);
}
// respond with html page
if (req.accepts('html') && !req.url.startsWith("/api")) {
res.send('<h1>Page not found</h1>');
return;
}
// respond with json
if (req.accepts('json')) {
res.json({ error: 'Not found', code: 404 });
return;
}
// default to plain-text. send()
res.send('404');
});
const orgdata = loadOrg("oui-fix.csv");
app.listen(port, () => {
console.log(`App listening on port ${port}`);
})

33192
wap/mac-check/src/oui-fix.csv Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
{
"dependencies": {
"express": "^4.18.2",
"fast-csv": "^4.3.6",
"object-to-xml": "^2.0.0",
"simple-sha256": "^1.1.0"
}
}

View File

@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="24"
height="24"
viewBox="0 0 24 24"
version="1.1"
id="svg14"
sodipodi:docname="bars-scale-light.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs18" />
<sodipodi:namedview
id="namedview16"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="24.833333"
inkscape:cx="12.020134"
inkscape:cy="12"
inkscape:window-width="1920"
inkscape:window-height="1015"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg14" />
<style
id="style2">.spinner_jCIR{animation:spinner_B8Vq .9s linear infinite;animation-delay:-.9s}.spinner_upm8{animation-delay:-.8s}.spinner_2eL5{animation-delay:-.7s}.spinner_Rp9l{animation-delay:-.6s}.spinner_dy3W{animation-delay:-.5s}@keyframes spinner_B8Vq{0%,66.66%{animation-timing-function:cubic-bezier(0.36,.61,.3,.98);y:6px;height:12px}33.33%{animation-timing-function:cubic-bezier(0.36,.61,.3,.98);y:1px;height:22px}}</style>
<rect
class="spinner_jCIR"
x="1"
y="6"
width="2.8"
height="12"
id="rect4"
style="fill:#ffffff" />
<rect
class="spinner_jCIR spinner_upm8"
x="5.8"
y="6"
width="2.8"
height="12"
id="rect6"
style="fill:#ffffff" />
<rect
class="spinner_jCIR spinner_2eL5"
x="10.6"
y="6"
width="2.8"
height="12"
id="rect8"
style="fill:#ffffff" />
<rect
class="spinner_jCIR spinner_Rp9l"
x="15.4"
y="6"
width="2.8"
height="12"
id="rect10"
style="fill:#ffffff" />
<rect
class="spinner_jCIR spinner_dy3W"
x="20.2"
y="6"
width="2.8"
height="12"
id="rect12"
style="fill:#ffffff" />
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,21 @@
html, body {
padding: 0;
margin: 0;
border: none;
background-color: #181a1b;
color: white;
}
.box {
display: block;
width: 300px;
margin-top: 200px;
margin-left: auto;
margin-right: auto;
text-align: center;
}
.box * {
display: block;
margin-left: auto;
margin-right: auto;
}/*# sourceMappingURL=style.css.map */

View File

@@ -0,0 +1 @@
{"version":3,"sources":["style.scss","style.css"],"names":[],"mappings":"AAAA;EACI,UAAA;EACA,SAAA;EACA,YAAA;EACA,yBAAA;EACA,YAAA;ACCJ;;ADEA;EACI,cAAA;EACA,YAAA;EACA,iBAAA;EACA,iBAAA;EACA,kBAAA;EACA,kBAAA;ACCJ;ADAI;EACI,cAAA;EACA,iBAAA;EACA,kBAAA;ACER","file":"style.css"}

View File

@@ -0,0 +1,21 @@
html, body {
padding: 0;
margin: 0;
border: none;
background-color: #181a1b;
color: white;
}
.box {
display: block;
width: 300px;
margin-top: 200px;
margin-left: auto;
margin-right: auto;
text-align: center;
* {
display: block;
margin-left: auto;
margin-right: auto;
}
}

View File

@@ -0,0 +1,77 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="/css/style.css">
<script src="/js/hash.js"></script>
</head>
<body>
<div class="box">
<p class="manufacturer">Please write first half of a mac address</p>
<input type="text" autocomplete="off" maxlength="17" pattern="[a-fA-F0-9-]+" oninput="macformat(this);"
required>
</div>
</body>
<script>
const secret = "1234567";
function macformat(input) {
str = input.value.toUpperCase();
allowed = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", ":"];
newstr = "";
for (var i = 0; i < str.length; i++) {
if (allowed.includes(str.charAt(i))) {
if ((i + 1) % 3) {
newstr = newstr + str.charAt(i).replace(':', '');
} else {
newstr = newstr + ":";
newstr = newstr + str.charAt(i).replace(':', '');
}
}
}
input.value = newstr;
if (newstr.length < 8) {
document.getElementsByClassName("manufacturer")[0].innerHTML = "Please write first half of a mac address";
} else if (newstr.length == 8) {
updateOrg(input, newstr.replaceAll(':', ''));
}
}
function updateOrg(input, macrange) {
man = document.getElementsByClassName("manufacturer")[0];
man.innerHTML = '<img src="bars-scale-light.svg" alt="">';
fetch('/api/range/' + macrange)
.then(
response => response.json()
).then(jsonResponse => {
console.log(jsonResponse);
if (jsonResponse.code == 404) {
man.innerHTML = 'Unknown';
} else if (jsonResponse.code == 200) {
man.innerHTML = jsonResponse.result.organization;
// Hash check not working, idk why
// sha256(jsonResponse.result + secret).then(value => {
// console.log(value);
// if (value == jsonResponse.hash) {
// man.innerHTML = jsonResponse.result.organization;
// }else {
// man.innerHTML = 'Insecure';
// }
// })
} else {
man.innerHTML = 'Error';
}
});
}
</script>
</html>

View File

@@ -0,0 +1,38 @@
module.exports = sha256
module.exports.sync = sha256sync
const crypto = globalThis.crypto || globalThis.msCrypto
const subtle = crypto.subtle || crypto.webkitSubtle
function sha256sync (buf) {
throw new Error('No support for sha256.sync() in the browser, use sha256()')
}
async function sha256 (buf) {
if (typeof buf === 'string') buf = strToBuf(buf)
// Browsers throw if they lack support for an algorithm.
// Promise will be rejected on non-secure origins. (http://goo.gl/lq4gCo)
const hash = subtle.digest({ name: 'sha-256' }, buf)
return hex(new Uint8Array(hash))
}
function strToBuf (str) {
const len = str.length
const buf = new Uint8Array(len)
for (let i = 0; i < len; i++) {
buf[i] = str.charCodeAt(i)
}
return buf
}
function hex (buf) {
const len = buf.length
const chars = []
for (let i = 0; i < len; i++) {
const byte = buf[i]
chars.push((byte >>> 4).toString(16))
chars.push((byte & 0x0f).toString(16))
}
return chars.join('')
}