You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
126 lines
3.1 KiB
126 lines
3.1 KiB
const express = require('express')
|
|
const app = express()
|
|
|
|
const exec = require('child_process').exec
|
|
const requestIp = require('request-ip')
|
|
|
|
require('colors')
|
|
|
|
const ByMac = {}
|
|
const ByIp = {}
|
|
|
|
const CFG = require('./config')
|
|
|
|
app.use(function (req, res, next) {
|
|
res.set('Access-Control-Allow-Origin', '*')
|
|
res.set('Access-Control-Allow-Methods', '*')
|
|
res.set('Access-Control-Allow-Headers', '*')
|
|
|
|
if (req.method === 'OPTIONS') {
|
|
return res.status(200).send()
|
|
}
|
|
|
|
req.clientIp = requestIp.getClientIp(req).split(':').slice(-1).pop()
|
|
// req.clientIp = '192.168.8.226'
|
|
findMacAddress(req.clientIp, function (pErr, pMac) {
|
|
req.clientMac = pMac || null
|
|
req.flagHandler = new FlagHandler(req.clientIp, req.clientMac)
|
|
|
|
try {
|
|
req.isIos = req.headers['user-agent'].indexOf('CaptiveNetworkSupport') !== -1 || req.headers['user-agent'].indexOf('iPhone') !== -1
|
|
} catch (e) {}
|
|
|
|
next()
|
|
})
|
|
})
|
|
|
|
app.use(function (req, res, next) {
|
|
if (CFG.quiet) {
|
|
return next()
|
|
}
|
|
let currentDate = new Date()
|
|
let isFlagged = req.flagHandler.getFlag()
|
|
if (req.hostname === 'detectportal.firefox.com') return next()
|
|
console.log(currentDate.toISOString().grey, '|', req.clientIp, '=>', req.clientMac || 'MacNotFound |', isFlagged ? 'OK'.green : 'ko'.red, '|', req.originalUrl)
|
|
console.log(req.hostname, req.headers['user-agent'])
|
|
next()
|
|
})
|
|
|
|
// API called to validate an MAC address
|
|
app.all('/validate', function (req, res) {
|
|
req.flagHandler.setFlag()
|
|
if (req.isIos) {
|
|
res.status(302).set({ Location: '/ready.html' }).end()
|
|
} else {
|
|
res.status(200).end()
|
|
}
|
|
})
|
|
|
|
// Serve assets
|
|
app.use(express.static(CFG.webapp.portal))
|
|
|
|
// Default callback
|
|
app.use(function (req, res, next) {
|
|
let flag = req.flagHandler.getFlag()
|
|
// If MAC has been flag by one /validate call
|
|
if (flag) {
|
|
// Case iOS
|
|
if (req.isIos) {
|
|
res.status(200).send('<HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>')
|
|
} else {
|
|
res.status(204).end()
|
|
}
|
|
} else {
|
|
res.status(302).set({ Location: CFG.redirectTo }).end()
|
|
}
|
|
})
|
|
|
|
function findMacAddress (pIp, pCallback) {
|
|
exec(CFG.arpCmd, function (pCode, pStdout) {
|
|
console.log(pCode, pStdout)
|
|
let lines = pStdout.split('\n')
|
|
if (!lines.length) {
|
|
return pCallback('NotFound')
|
|
}
|
|
|
|
for (let i = 0; i < lines.length; i++) {
|
|
let line = lines[i]
|
|
if (line.indexOf(pIp) !== -1) {
|
|
// console.log(line)
|
|
let cols = line.split(' ').filter(function (str) { return !!str })
|
|
return pCallback(null, cols[2])
|
|
}
|
|
}
|
|
|
|
pCallback('NotFound')
|
|
})
|
|
}
|
|
|
|
class FlagHandler {
|
|
constructor (pIp, pMac) {
|
|
this.ip = pIp
|
|
this.mac = pMac
|
|
}
|
|
|
|
setFlag () {
|
|
if (!this.mac) {
|
|
ByIp[this.ip] = new Date()
|
|
} else {
|
|
ByMac[this.mac] = new Date()
|
|
}
|
|
}
|
|
|
|
getFlag () {
|
|
let flag = null
|
|
if (!this.mac) {
|
|
flag = ByIp[this.ip]
|
|
} else {
|
|
flag = ByMac[this.mac]
|
|
}
|
|
return flag || null
|
|
}
|
|
}
|
|
|
|
app.listen(CFG.port, function () {
|
|
console.log(`[>] PXPortal service running on: ${CFG.port}`)
|
|
})
|