2019-11-17 01:16:46 +01:00
|
|
|
/* HTTP Server setup and handler functions */
|
|
|
|
|
2019-11-20 22:42:35 +01:00
|
|
|
#include <SPIFFS.h>
|
2019-11-25 22:45:01 +01:00
|
|
|
#include <mbedtls/sha256.h>
|
2019-11-20 22:42:35 +01:00
|
|
|
|
2019-11-25 22:45:01 +01:00
|
|
|
#include "WebServer.h"
|
|
|
|
|
|
|
|
#include "Crypto_Config.h"
|
2019-11-17 01:16:46 +01:00
|
|
|
|
|
|
|
#include "Fader.h"
|
|
|
|
|
2019-11-25 22:45:01 +01:00
|
|
|
WebServer::WebServer(void)
|
|
|
|
: m_cr(crypto::HTTP_PASSWORD), m_fader(NULL)
|
2019-11-17 01:16:46 +01:00
|
|
|
{
|
|
|
|
m_server = new httpsserver::HTTPServer();
|
|
|
|
}
|
|
|
|
|
2019-11-25 22:45:01 +01:00
|
|
|
void WebServer::serveFile(String filename, httpsserver::HTTPResponse *res)
|
2019-11-17 01:16:46 +01:00
|
|
|
{
|
2019-11-20 22:42:35 +01:00
|
|
|
uint8_t buf[1024];
|
|
|
|
File f = SPIFFS.open(filename.c_str(), "r");
|
|
|
|
|
|
|
|
size_t nread = 1;
|
|
|
|
while(nread > 0) {
|
|
|
|
nread = f.readBytes(reinterpret_cast<char*>(buf), 1024);
|
|
|
|
if(nread <= 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
res->write(buf, nread);
|
|
|
|
}
|
2019-11-17 01:16:46 +01:00
|
|
|
|
2019-11-20 22:42:35 +01:00
|
|
|
f.close();
|
|
|
|
}
|
|
|
|
|
2019-11-25 22:45:01 +01:00
|
|
|
void WebServer::handleRoot(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res)
|
2019-11-20 22:42:35 +01:00
|
|
|
{
|
2019-11-26 21:11:36 +01:00
|
|
|
serveFile("/htdocs/index.html", res);
|
2019-11-20 22:42:35 +01:00
|
|
|
res->setHeader("Content-Type", "text/html");
|
2019-11-17 01:16:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void error400(httpsserver::HTTPResponse *res, const std::string &reason)
|
|
|
|
{
|
|
|
|
res->println("Error 400: Bad Request");
|
|
|
|
res->println(reason.c_str());
|
|
|
|
|
|
|
|
res->setStatusCode(400);
|
|
|
|
}
|
|
|
|
|
2019-11-25 22:45:01 +01:00
|
|
|
void WebServer::handleColor(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res)
|
2019-11-17 01:16:46 +01:00
|
|
|
{
|
|
|
|
res->setHeader("Content-Type", "text/plain");
|
|
|
|
|
|
|
|
httpsserver::ResourceParameters * params = req->getParams();
|
|
|
|
|
|
|
|
if(!params->isRequestParameterSet("color")) {
|
|
|
|
error400(res, "Parameter 'color' not set.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string colorstr = params->getRequestParameter("color");
|
|
|
|
|
|
|
|
if(colorstr.length() != 8) {
|
|
|
|
error400(res, "Wrong length of color string (expected 8 hex digits).");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t color = 0;
|
|
|
|
|
|
|
|
for(size_t i = 0; i < 8; i++) {
|
|
|
|
color <<= 4;
|
|
|
|
|
|
|
|
char c = colorstr[i];
|
|
|
|
if(c >= 'A' && c <= 'F') {
|
|
|
|
color |= c - 'A' + 10;
|
|
|
|
} else if(c >= 'a' && c <= 'f') {
|
|
|
|
color |= c - 'a' + 10;
|
|
|
|
} else if(c >= '0' && c <= '9') {
|
|
|
|
color |= c - '0';
|
|
|
|
} else {
|
|
|
|
error400(res, "Invalid character in color string (allowed: 0-9, a-f, A-F)");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t r = (color & 0xFF000000) >> 24;
|
|
|
|
uint8_t g = (color & 0x00FF0000) >> 16;
|
|
|
|
uint8_t b = (color & 0x0000FF00) >> 8;
|
|
|
|
uint8_t w = (color & 0x000000FF) >> 0;
|
|
|
|
|
|
|
|
res->print("Color changed to r:");
|
|
|
|
res->print(r);
|
|
|
|
res->print(" g:");
|
|
|
|
res->print(g);
|
|
|
|
res->print(" b:");
|
|
|
|
res->print(b);
|
|
|
|
res->print(" w:");
|
|
|
|
res->println(w);
|
|
|
|
|
2019-11-25 22:45:01 +01:00
|
|
|
WebServer::instance().m_fader->fade_color({r,g,b,w});
|
|
|
|
}
|
|
|
|
|
|
|
|
void WebServer::handleUpdate(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res)
|
|
|
|
{
|
|
|
|
res->setHeader("Content-Type", "text/plain");
|
|
|
|
|
|
|
|
httpsserver::ResourceParameters * params = req->getParams();
|
|
|
|
|
|
|
|
if(!params->isRequestParameterSet("content")) {
|
|
|
|
error400(res, "Send update image as 'content'.");
|
|
|
|
}
|
|
|
|
|
|
|
|
res->print("Content length: ");
|
|
|
|
res->println(req->getContentLength());
|
|
|
|
|
|
|
|
res->println("Content:");
|
|
|
|
res->println("--------------------------------------------------------------------------------");
|
|
|
|
|
|
|
|
uint8_t buf[128];
|
|
|
|
while(!req->requestComplete()) {
|
|
|
|
size_t bytes_processed = req->readBytes(buf, 128);
|
|
|
|
res->write(buf, bytes_processed);
|
|
|
|
}
|
|
|
|
res->println("--------------------------------------------------------------------------------");
|
|
|
|
|
|
|
|
std::vector<uint8_t> d;
|
|
|
|
d.push_back(1);
|
|
|
|
d.push_back(2);
|
|
|
|
d.push_back(3);
|
|
|
|
|
|
|
|
uint8_t sha256sum[32];
|
|
|
|
mbedtls_sha256_ret(d.data(), d.size(), sha256sum, 0);
|
|
|
|
|
|
|
|
for(size_t i = 0; i < 32; i++) {
|
|
|
|
static const char *conv = "0123456789abcdef";
|
|
|
|
|
|
|
|
uint8_t b = sha256sum[i];
|
|
|
|
|
|
|
|
res->print(conv[(b >> 4)]);
|
|
|
|
res->print(conv[(b &0x0F)]);
|
|
|
|
}
|
|
|
|
|
|
|
|
res->println();
|
|
|
|
}
|
|
|
|
|
|
|
|
void WebServer::handleChallenge(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res)
|
|
|
|
{
|
|
|
|
res->setHeader("Content-Type", "application/json");
|
|
|
|
|
|
|
|
std::ostringstream responseBuilder;
|
|
|
|
responseBuilder << "{ \"nonce\": " << WebServer::instance().m_cr.nonce() << "}";
|
|
|
|
|
|
|
|
res->println(responseBuilder.str().c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
void WebServer::handleAuthTest(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res)
|
|
|
|
{
|
|
|
|
res->setHeader("Content-Type", "text/plain");
|
|
|
|
|
|
|
|
httpsserver::ResourceParameters * params = req->getParams();
|
|
|
|
|
|
|
|
if(!params->isRequestParameterSet("response")) {
|
|
|
|
error400(res, "Parameter 'response' not set.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string response = params->getRequestParameter("response");
|
|
|
|
bool result = WebServer::instance().m_cr.verify(response);
|
|
|
|
|
|
|
|
if(result) {
|
|
|
|
res->println("Authentication test successful!");
|
|
|
|
} else {
|
|
|
|
res->println("Authentication test failed (invalid response)");
|
|
|
|
}
|
2019-11-17 01:16:46 +01:00
|
|
|
}
|
|
|
|
|
2019-11-25 22:45:01 +01:00
|
|
|
void WebServer::handle404(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res)
|
2019-11-17 01:16:46 +01:00
|
|
|
{
|
|
|
|
req->discardRequestBody();
|
|
|
|
|
|
|
|
res->setStatusCode(404);
|
|
|
|
res->setHeader("Content-Type", "text/plain");
|
|
|
|
|
|
|
|
res->println("Error 404: Not found");
|
|
|
|
}
|
|
|
|
|
2019-11-25 22:45:01 +01:00
|
|
|
void WebServer::serverTask(void *arg)
|
2019-11-17 01:16:46 +01:00
|
|
|
{
|
|
|
|
httpsserver::ResourceNode *nodeRoot = new httpsserver::ResourceNode("/", "GET",
|
2019-11-25 22:45:01 +01:00
|
|
|
WebServer::handleRoot);
|
2019-11-17 01:16:46 +01:00
|
|
|
httpsserver::ResourceNode *nodeColor = new httpsserver::ResourceNode("/color", "GET",
|
2019-11-25 22:45:01 +01:00
|
|
|
WebServer::handleColor);
|
|
|
|
httpsserver::ResourceNode *nodeUpdate = new httpsserver::ResourceNode("/update", "POST",
|
|
|
|
WebServer::handleUpdate);
|
|
|
|
httpsserver::ResourceNode *nodeChallenge = new httpsserver::ResourceNode("/challenge", "GET",
|
|
|
|
WebServer::handleChallenge);
|
|
|
|
httpsserver::ResourceNode *nodeAuthTest = new httpsserver::ResourceNode("/authtest", "GET",
|
|
|
|
WebServer::handleAuthTest);
|
2019-11-17 01:16:46 +01:00
|
|
|
httpsserver::ResourceNode *node404 = new httpsserver::ResourceNode("", "GET",
|
2019-11-25 22:45:01 +01:00
|
|
|
WebServer::handle404);
|
2019-11-17 01:16:46 +01:00
|
|
|
|
2019-11-25 22:45:01 +01:00
|
|
|
WebServer &server = WebServer::instance();
|
2019-11-17 01:16:46 +01:00
|
|
|
|
|
|
|
server.m_server->registerNode(nodeRoot);
|
|
|
|
server.m_server->registerNode(nodeColor);
|
2019-11-25 22:45:01 +01:00
|
|
|
server.m_server->registerNode(nodeUpdate);
|
|
|
|
server.m_server->registerNode(nodeChallenge);
|
|
|
|
server.m_server->registerNode(nodeAuthTest);
|
2019-11-17 01:16:46 +01:00
|
|
|
server.m_server->setDefaultNode(node404);
|
|
|
|
|
|
|
|
Serial.println("[server] Starting HTTP Server...");
|
|
|
|
server.m_server->start();
|
|
|
|
if (server.m_server->isRunning())
|
|
|
|
{
|
|
|
|
Serial.println("[server] Server ready.");
|
|
|
|
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
server.m_server->loop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Serial.println("[server] Server died?! This should never happen.");
|
|
|
|
}
|
|
|
|
|
2019-11-25 22:45:01 +01:00
|
|
|
bool WebServer::start(void)
|
2019-11-17 01:16:46 +01:00
|
|
|
{
|
|
|
|
xTaskCreate(
|
2019-11-25 22:45:01 +01:00
|
|
|
WebServer::serverTask, /* Task function. */
|
2019-11-17 01:16:46 +01:00
|
|
|
"HTTP Server Task", /* name of task. */
|
|
|
|
6144, /* Stack size of task */
|
|
|
|
NULL, /* parameter of the task */
|
|
|
|
1, /* priority of the task */
|
|
|
|
NULL); /* Task handle to keep track of created task */
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|