Skip to content

Instantly share code, notes, and snippets.

@wilberforce
Created April 10, 2018 10:27
Show Gist options
  • Save wilberforce/cc6025a535b8a4c7e2910d4ba7845f11 to your computer and use it in GitHub Desktop.
Save wilberforce/cc6025a535b8a4c7e2910d4ba7845f11 to your computer and use it in GitHub Desktop.
Captive Portal
// Captive Portal - extending:
// https://gist.github.com/MaBecker/ae9dade26b44524e076ca19f5fd72fab
// Added form and post back to join network
var http = require('http');
var wifi = require('Wifi');
var dgram = require('dgram');
var dns_srv = dgram.createSocket('udp4');
var SSID = 'CaptivePortalTest';
var authMode = 'open';
var password = null;
var portHTTP = 80;
var portDNS = 53;
var dnsIPStr = '192.168.4.1';
var dnsIP = dnsIPStr.split('.').map(n => String.fromCharCode(parseInt(n, 10))).join('');
var page = 'building...';
// get Query name out of message
// offset = 12
// end \x00
function dnsQname(msg) {
var i = 12;
var qname = '';
while ( msg[i] !== '\x00' ) {
qname += msg[i];
i++;
}
console.log({qname:qname});
return qname + '\x00';
}
/*
1. line header
2. line query
3. line resource
*/
function dnsResponse(msg,dns_ip){
return msg[0]+msg[1] + '\x81\x80'+'\x00\x01'+'\x00\x01'+'\x00\x00\x00\x00' +
dnsQname(msg) + '\x00\x01' + '\x00\x01' +
'\xc0\x0c'+'\x00\x01'+'\x00\x01'+'\x00\x00\x00\xf9'+'\x00\x04' + dns_ip ;
}
function startDNSServer(port){
dns_srv .on('error', (err) => {
dns_srv.close();
});
dns_srv.on('message', (msg, info) => {
// we only serve ip4
if ( msg[msg.length-3] === '\x01') {
dns_srv .send(dnsResponse(msg,dnsIP),info.port,info.address);
}
});
dns_srv.bind(port);
}
// start http server
function startHttpServer(port){
var server = http.createServer(function (req, res) {
accept = req.headers.Accept || '';
var a = url.parse(req.url, true);
console.log( { accept:accept,a :a } );
if (a.pathname=="/connect") {
res.writeHead(200, {'Content-Type': 'text/plain'});
console.log(a.query);
wifi.connect(a.query.ssid,{password:a.query.pwd},function(){
console.log("Connected to access point, ",wifi.getIP());
//wifi.save();
// If connect fails - this will not happen... need to handle errors
res.end(`connected to ${wifi.getIP().ip}`);
});
res.write("Connecting....\n");
} else
if (accept !== '*\/*' || a.page === '/hotspot-detect.html' ) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(page);
} else { // redirect to the Setup page
res.writeHead(302, {'Location': 'http://192.168.4.1',
'Content-Type': 'text/plain'});
res.end();
}
});
server.listen(port);
}
// start being a access point
function startAccessPoint(ssid,authMode, password){
wifi.startAP(ssid,{"authMode" : authMode,"password" : password});
}
// stop beeing connected to a access point
function disconnectStation(){
wifi.disconnect();
}
var scan=[];
function start(){
disconnectStation();
startAccessPoint('CaptivePortalTest','open',null);
startHttpServer(80);
startDNSServer(53);
}
wifi.scan(function(s){scan=s;
scan.map( ap => console.log( ap.ssid ) );
style=`
<!---->
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/pure/1.0.0/pure-min.css"><style>
input{color:inherit;font:inherit;margin:0;}
input{line-height:normal;}
input::-moz-focus-inner{border:0;padding:0;}
.pure-form input[type=email]{padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;vertical-align:middle;box-sizing:border-box;}
.pure-form input[type=email]:focus{outline:0;border-color:#129FEA;}
.pure-form input:focus:invalid{color:#b94a48;border-color:#e9322d;}
.pure-form-aligned input{display:inline-block;vertical-align:middle;}
@media only screen and (max-width :480px){
.pure-form input[type=email]{margin-bottom:.3em;display:block;}
}
html {font-family: sans-serif; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;}
</style>`;
page=`<!DOCTYPE html>
<title> WiFi</title>
<meta name="viewport" content="initial-scale=1.0">
<body>
<html>
<h1>Captive Hotspot</h1>
<form action="/connect" class="pure-form pure-form-aligned">
<fieldset>
<div class="pure-control-group">
<label for="Sid">Access Point</label>
<select name="ssid">`;
scan.map( ap => page+=`<option>${ap.ssid}</option>`);
page+=`</select>
</div>
<div class="pure-control-group">
<label>Password</label>
<input name="pwd" type="text" value="espruino">
</div>
<div class="pure-controls">
<input type="submit" class="pure-button pure-button-primary" value="Connect">
</div>
</fieldset>
</form>
</html>
</body>
`;
});
setTimeout(start,1000);
@tombueng
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment