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('SuccessSuccess') } 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}`) })