Skip to content

Instantly share code, notes, and snippets.

@yoursunny
Last active September 10, 2021 14:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yoursunny/8ff84447848cb728b1ae99e256952a6d to your computer and use it in GitHub Desktop.
Save yoursunny/8ff84447848cb728b1ae99e256952a6d to your computer and use it in GitHub Desktop.
"freewifi" via ESP8266 Captive Portal https://yoursunny.com/t/2017/freewifi/
/.vscode
/data
#include <FS.h>
#include <ESP8266WiFi.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <PString.h>
#include <Streaming.h>
const IPAddress apIp(192, 168, 0, 1);
DNSServer dnsServer;
ESP8266WebServer server(80);
struct PrintMac
{
const uint8_t* mac;
};
Print&
operator<<(Print& p, const PrintMac& pmac)
{
const uint8_t* mac = pmac.mac;
for (int i = 0; i < 6; ++i) {
if (i > 0) {
p << ':';
}
p << _WIDTHZ(_HEX(mac[i]), 2);
}
return p;
}
File logfile;
char logbuf[256];
PString logline(logbuf, sizeof(logbuf));
void
appendLog()
{
const char* line = logline;
Serial << millis() << ' ' << line << '\n';
logfile << millis() << ' ' << line << '\n';
logline.begin();
}
void
wifiStaConnect(const WiFiEventSoftAPModeStationConnected& evt)
{
logline << PrintMac{evt.mac} << " assoc";
appendLog();
}
WiFiEventHandler wifiStaConnectHandler;
void
wifiStaDisconnect(const WiFiEventSoftAPModeStationDisconnected& evt)
{
logline << PrintMac{evt.mac} << " deassoc";
appendLog();
}
WiFiEventHandler wifiStaDisconnectHandler;
void
httpDefault()
{
logline << server.client().remoteIP() << " redirect";
appendLog();
server.sendHeader("Location", "http://freewifi.lan/", true);
server.send(302, "text/plain", "");
server.client().stop();
}
void
httpHome()
{
if (server.hostHeader() != String("freewifi.lan")) {
return httpDefault();
}
logline << server.client().remoteIP() << " home";
appendLog();
File file = SPIFFS.open("/index.htm.gz", "r");
server.streamFile(file, "text/html");
file.close();
}
void
httpConnect()
{
logline << server.client().remoteIP() << " connect " << server.arg("email");
appendLog();
File file = SPIFFS.open("/connect.htm.gz", "r");
server.streamFile(file, "text/html");
file.close();
}
void
httpPureCss()
{
File file = SPIFFS.open("/pure.css.gz", "r");
server.streamFile(file, "text/css");
file.close();
}
void
httpLog()
{
logline << server.client().remoteIP() << " log";
appendLog();
logfile.seek(0, SeekSet);
server.streamFile(logfile, "text/plain");
logfile.seek(0, SeekEnd);
}
void
setup()
{
Serial.begin(115200);
Serial.println();
Serial.println();
SPIFFS.begin();
logfile = SPIFFS.open("/log.txt", "a+");
WiFi.persistent(false);
WiFi.disconnect(true);
wifiStaConnectHandler = WiFi.onSoftAPModeStationConnected(wifiStaConnect);
wifiStaDisconnectHandler = WiFi.onSoftAPModeStationDisconnected(wifiStaDisconnect);
WiFi.mode(WIFI_AP);
WiFi.softAPConfig(apIp, apIp, IPAddress(255, 255, 255, 0));
WiFi.softAP("freewifi", nullptr, 1);
dnsServer.setErrorReplyCode(DNSReplyCode::NoError);
dnsServer.start(53, "*", apIp);
server.on("/", httpHome);
server.on("/connect", httpConnect);
server.on("/pure.css", httpPureCss);
server.on("/log.txt", httpLog);
server.onNotFound(httpDefault);
server.begin();
Serial << "ready" << endl;
}
void
loop()
{
dnsServer.processNextRequest();
server.handleClient();
}
<!DOCTYPE html>
<title>Free WiFi</title>
<meta name="viewport" content="initial-scale=1.0">
<link rel="stylesheet" href="pure.css">
<h1>Connected to Free WiFi</h1>
<p>No, you don't get Internet access.
We offer free WiFi, but we didn't offer Internet access through WiFi.</p>
<!DOCTYPE html>
<title>Free WiFi</title>
<meta name="viewport" content="initial-scale=1.0">
<link rel="stylesheet" href="pure.css">
<h1>Welcome to Free WiFi</h1>
<form action="/connect" class="pure-form pure-form-aligned">
<fieldset>
<div class="pure-control-group">
<label for="email">Email</label>
<input name="email" id="email" type="email" required placeholder="someone@example.com">
</div>
<div class="pure-controls">
<label class="pure-checkbox">
<input type="checkbox" required>
I've read the terms and conditions
</label>
<input type="submit" class="pure-button pure-button-primary" value="Connect">
</div>
</fieldset>
</form>
#!/bin/bash
set -eo pipefail
mkdir -p data
for P in index connect; do
gzip < $P.htm > data/$P.htm.gz
done
if ! [[ -f data/pure.css.gz ]]; then
curl -sL http://yui.yahooapis.com/pure/0.6.0/pure-min.css | gzip > data/pure.css.gz
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment