Login and Token System implemented
This commit is contained in:
parent
8f2444caeb
commit
bb3e4fa27c
BIN
data/admin
BIN
data/admin
Binary file not shown.
2
data/s/bundle.1727d.js
Normal file
2
data/s/bundle.1727d.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
|||||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>doorlock_pwa</title><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-capable" content="yes"><link rel="apple-touch-icon" href="/assets/icons/apple-touch-icon.png"><link rel="manifest" href="/manifest.json"><meta name="theme-color" content="#673ab8"><style>*{box-sizing:border-box}html{font-family:Helvetica,sans-serif;font-size:16px}body,html{height:100%}body{background-color:#fff;margin:0;padding:0;width:100%}</style><link href="/bundle.45d14.css" rel="stylesheet" media="only x" onload="this.media='all'"><noscript><link rel="stylesheet" href="/bundle.45d14.css"></noscript></head><body><script defer="defer" src="/bundle.f9ad8.js"></script><script nomodule="" src="/polyfills.058fb.js"></script></body></html>
|
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>doorlock_pwa</title><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-capable" content="yes"><link rel="apple-touch-icon" href="/assets/icons/apple-touch-icon.png"><link rel="manifest" href="/manifest.json"><meta name="theme-color" content="#673ab8"><style>*{box-sizing:border-box}html{font-family:Helvetica,sans-serif;font-size:16px}body,html{height:100%}body{background-color:#fff;margin:0;padding:0;width:100%}</style><link href="/bundle.45d14.css" rel="stylesheet" media="only x" onload="this.media='all'"><noscript><link rel="stylesheet" href="/bundle.45d14.css"></noscript></head><body><script defer="defer" src="/bundle.1727d.js"></script><script nomodule="" src="/polyfills.058fb.js"></script></body></html>
|
59
src/AdminAuth.cpp
Normal file
59
src/AdminAuth.cpp
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#include "AdminAuth.h"
|
||||||
|
using namespace webconsole;
|
||||||
|
bool AdminAuth::isAuth(const char *token)
|
||||||
|
{
|
||||||
|
return tokenbuffer->exists(token) != -1;
|
||||||
|
}
|
||||||
|
bool AdminAuth::logout(const char *token)
|
||||||
|
{
|
||||||
|
int16_t tid = tokenbuffer->exists(token);
|
||||||
|
tokenbuffer->setnull(tid);
|
||||||
|
return tid != -1;
|
||||||
|
}
|
||||||
|
char *AdminAuth::login(const char *username, const char *password)
|
||||||
|
{
|
||||||
|
char *res = nullptr;
|
||||||
|
File adminfile = LittleFS.open("admin", "r");
|
||||||
|
bool current_field = false;
|
||||||
|
uint16_t current_pos = 0;
|
||||||
|
Serial.print('-');
|
||||||
|
while (adminfile.available())
|
||||||
|
{
|
||||||
|
char current = adminfile.read();
|
||||||
|
Serial.print(current);
|
||||||
|
Serial.print('-');
|
||||||
|
if (current == 0x00)
|
||||||
|
{
|
||||||
|
if (current_field)
|
||||||
|
{
|
||||||
|
if (password[current_pos] == 0x00)
|
||||||
|
res = tokenbuffer->newToken();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (username[current_pos] != 0x00)
|
||||||
|
break;
|
||||||
|
current_pos = 0;
|
||||||
|
current_field = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!current_field)
|
||||||
|
{
|
||||||
|
Serial.print(String(username[current_pos]));
|
||||||
|
if (username[current_pos] == 0x00 || username[current_pos] != current)
|
||||||
|
break;
|
||||||
|
current_pos++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Serial.print(String(password[current_pos]));
|
||||||
|
if (password[current_pos] == 0x00 || password[current_pos] != current)
|
||||||
|
break;
|
||||||
|
current_pos++;
|
||||||
|
}
|
||||||
|
Serial.print(',');
|
||||||
|
}
|
||||||
|
adminfile.close();
|
||||||
|
return res;
|
||||||
|
}
|
77
src/AdminAuth.h
Normal file
77
src/AdminAuth.h
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "LittleFS.h"
|
||||||
|
#define TOKENBUFFERCAPACITY 3
|
||||||
|
#define TOKENLENGHT 10
|
||||||
|
namespace webconsole
|
||||||
|
{
|
||||||
|
|
||||||
|
struct TokenBuffer
|
||||||
|
{
|
||||||
|
|
||||||
|
TokenBuffer()
|
||||||
|
{
|
||||||
|
for (uint16_t j = 0; j < TOKENBUFFERCAPACITY; j++)
|
||||||
|
setnull(j);
|
||||||
|
}
|
||||||
|
char *newToken()
|
||||||
|
{
|
||||||
|
if (next >= TOKENBUFFERCAPACITY)
|
||||||
|
next = 0;
|
||||||
|
for (uint16_t i = 0; i < TOKENLENGHT; i++)
|
||||||
|
token[next][i] = randomChar();
|
||||||
|
token[next][TOKENLENGHT] = 0x00;
|
||||||
|
|
||||||
|
return &token[next++][0];
|
||||||
|
}
|
||||||
|
int16_t exists(const char *cmp)
|
||||||
|
{
|
||||||
|
for (uint16_t j = 0; j < TOKENBUFFERCAPACITY; j++)
|
||||||
|
{
|
||||||
|
bool match = true;
|
||||||
|
for (uint16_t i = 0; match && i < TOKENLENGHT; i++)
|
||||||
|
if (token[j][i] != cmp[i])
|
||||||
|
match = false;
|
||||||
|
if (match)
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
void setnull(uint16_t index)
|
||||||
|
{
|
||||||
|
if (index >= 0 && index < TOKENBUFFERCAPACITY)
|
||||||
|
for (uint16_t i = 0; i < TOKENLENGHT; i++)
|
||||||
|
token[index][i] = 0x00; // initialize with nullbytes
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint16_t next = 0;
|
||||||
|
char token[TOKENBUFFERCAPACITY][TOKENLENGHT + 1];
|
||||||
|
char randomChar()
|
||||||
|
{
|
||||||
|
auto charrype = random(0, 3);
|
||||||
|
switch (charrype)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return random(0x30, 0x3A); // Numbers
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
return random(0x41, 0x5B); // Capital Letters
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
return random(0x61, 0x7B); // Small Letters
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0x21;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
class AdminAuth
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
char *login(const char *username, const char *password);
|
||||||
|
bool isAuth(const char *token);
|
||||||
|
bool logout(const char *token);
|
||||||
|
|
||||||
|
private:
|
||||||
|
TokenBuffer *tokenbuffer = new TokenBuffer();
|
||||||
|
};
|
||||||
|
}
|
@ -46,6 +46,8 @@ namespace userdb
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class UserDb
|
class UserDb
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@ -148,7 +150,8 @@ namespace userdb
|
|||||||
{
|
{
|
||||||
close_file();
|
close_file();
|
||||||
}
|
}
|
||||||
void close_file(){
|
void close_file()
|
||||||
|
{
|
||||||
db_file.close();
|
db_file.close();
|
||||||
}
|
}
|
||||||
bool has_next()
|
bool has_next()
|
||||||
@ -164,7 +167,7 @@ namespace userdb
|
|||||||
if (matchline == line)
|
if (matchline == line)
|
||||||
{
|
{
|
||||||
current = read_csv_line(current, db_file, line, match, filter_attr);
|
current = read_csv_line(current, db_file, line, match, filter_attr);
|
||||||
current.match=true;
|
current.match = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
using namespace webconsole;
|
using namespace webconsole;
|
||||||
|
|
||||||
WebConsole::WebConsole() {}
|
WebConsole::WebConsole()
|
||||||
|
{
|
||||||
|
}
|
||||||
WebConsole::~WebConsole()
|
WebConsole::~WebConsole()
|
||||||
{
|
{
|
||||||
_server->close();
|
_server->close();
|
||||||
@ -12,7 +14,11 @@ bool WebConsole::init(userdb::UserDb *userdb)
|
|||||||
{
|
{
|
||||||
_server = new ESP8266WebServer(80);
|
_server = new ESP8266WebServer(80);
|
||||||
this->userdb = userdb;
|
this->userdb = userdb;
|
||||||
|
const char *headerkeys[] = {"Authentification"};
|
||||||
|
size_t headerkeyssize = sizeof(headerkeys) / sizeof(char *);
|
||||||
|
_server->collectHeaders(headerkeys, headerkeyssize);
|
||||||
_server->begin();
|
_server->begin();
|
||||||
|
_server->on("/api/auth", HTTPMethod::HTTP_POST, std::bind(&WebConsole::_auth, this));
|
||||||
_server->on("/api/userdb", HTTPMethod::HTTP_DELETE, std::bind(&WebConsole::_dropUserDb, this));
|
_server->on("/api/userdb", HTTPMethod::HTTP_DELETE, std::bind(&WebConsole::_dropUserDb, this));
|
||||||
_server->on("/api/userdb", HTTPMethod::HTTP_GET, std::bind(&WebConsole::_getUserDb, this));
|
_server->on("/api/userdb", HTTPMethod::HTTP_GET, std::bind(&WebConsole::_getUserDb, this));
|
||||||
_server->on("/api/rfid", std::bind(&WebConsole::_catchRFID, this));
|
_server->on("/api/rfid", std::bind(&WebConsole::_catchRFID, this));
|
||||||
@ -45,6 +51,48 @@ bool WebConsole::isInterceptingRfid()
|
|||||||
{
|
{
|
||||||
return catch_rfid;
|
return catch_rfid;
|
||||||
}
|
}
|
||||||
|
bool WebConsole::_isAuth()
|
||||||
|
{
|
||||||
|
if (!_server->hasHeader("Authentification"))
|
||||||
|
{
|
||||||
|
_server->send(401, "text/plain", "Error 401: Unauthorized (missing auth token)");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const char *token = _server->header("Authentification").c_str();
|
||||||
|
bool res = auth.isAuth(token);
|
||||||
|
if (!res)
|
||||||
|
_server->send(401, "text/plain", "Error 401: Unauthorized (missing auth token)");
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
void WebConsole::_auth()
|
||||||
|
{
|
||||||
|
_sendCORS();
|
||||||
|
String action = _server->arg("action");
|
||||||
|
if (action.equals("check"))
|
||||||
|
{
|
||||||
|
const char *token = _server->arg("token").c_str();
|
||||||
|
bool res = auth.isAuth(token);
|
||||||
|
_server->send(200, "text/plain", res ? "valid" : "invalid");
|
||||||
|
}
|
||||||
|
else if (action.equals("login"))
|
||||||
|
{
|
||||||
|
const char *username = _server->arg("username").c_str();
|
||||||
|
const char *password = _server->arg("password").c_str();
|
||||||
|
char *token = auth.login(username, password);
|
||||||
|
if (token == nullptr)
|
||||||
|
_server->send(401, "text/plain", "failed!");
|
||||||
|
else
|
||||||
|
_server->send(200, "text/plain", token);
|
||||||
|
}
|
||||||
|
else if (action.equals("logout"))
|
||||||
|
{
|
||||||
|
const char *token = _server->arg("token").c_str();
|
||||||
|
bool res = auth.logout(token);
|
||||||
|
_server->send(200, "text/plain", res ? "success" : "failed");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_server->send(404, "text/plain", "unknown action");
|
||||||
|
}
|
||||||
void WebConsole::_sendCORS()
|
void WebConsole::_sendCORS()
|
||||||
{
|
{
|
||||||
_server->sendHeader("Access-Control-Allow-Origin", "*");
|
_server->sendHeader("Access-Control-Allow-Origin", "*");
|
||||||
@ -54,9 +102,9 @@ void WebConsole::_sendCORS()
|
|||||||
}
|
}
|
||||||
void WebConsole::_handleUnknown()
|
void WebConsole::_handleUnknown()
|
||||||
{
|
{
|
||||||
|
_sendCORS();
|
||||||
if (_server->method() == HTTP_OPTIONS)
|
if (_server->method() == HTTP_OPTIONS)
|
||||||
{
|
{
|
||||||
_sendCORS();
|
|
||||||
_server->send(204);
|
_server->send(204);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -70,6 +118,8 @@ void WebConsole::_handleUnknown()
|
|||||||
void WebConsole::_getUserDb()
|
void WebConsole::_getUserDb()
|
||||||
{
|
{
|
||||||
_sendCORS();
|
_sendCORS();
|
||||||
|
if (!_isAuth())
|
||||||
|
return;
|
||||||
File src = LittleFS.open("userdb.csv", "r");
|
File src = LittleFS.open("userdb.csv", "r");
|
||||||
if (src)
|
if (src)
|
||||||
{
|
{
|
||||||
@ -80,6 +130,8 @@ void WebConsole::_getUserDb()
|
|||||||
void WebConsole::_deleteUser()
|
void WebConsole::_deleteUser()
|
||||||
{
|
{
|
||||||
_sendCORS();
|
_sendCORS();
|
||||||
|
if (!_isAuth())
|
||||||
|
return;
|
||||||
if (userdb == nullptr)
|
if (userdb == nullptr)
|
||||||
{
|
{
|
||||||
_server->send(500, "text/json", "{\"error\":\"UserDb not initialized\"}");
|
_server->send(500, "text/json", "{\"error\":\"UserDb not initialized\"}");
|
||||||
@ -101,6 +153,8 @@ void WebConsole::_deleteUser()
|
|||||||
void WebConsole::_getUser()
|
void WebConsole::_getUser()
|
||||||
{
|
{
|
||||||
_sendCORS();
|
_sendCORS();
|
||||||
|
if (!_isAuth())
|
||||||
|
return;
|
||||||
if (userdb == nullptr)
|
if (userdb == nullptr)
|
||||||
{
|
{
|
||||||
_server->send(500, "text/json", "{\"error\":\"UserDb not initialized\"}");
|
_server->send(500, "text/json", "{\"error\":\"UserDb not initialized\"}");
|
||||||
@ -120,6 +174,8 @@ void WebConsole::_getUser()
|
|||||||
void WebConsole::_updateUser()
|
void WebConsole::_updateUser()
|
||||||
{
|
{
|
||||||
_sendCORS();
|
_sendCORS();
|
||||||
|
if (!_isAuth())
|
||||||
|
return;
|
||||||
userdb::User updated;
|
userdb::User updated;
|
||||||
String body = _server->arg("plain");
|
String body = _server->arg("plain");
|
||||||
const int capacity = 256;
|
const int capacity = 256;
|
||||||
@ -172,6 +228,8 @@ void WebConsole::_updateUser()
|
|||||||
void WebConsole::_createUser()
|
void WebConsole::_createUser()
|
||||||
{
|
{
|
||||||
_sendCORS();
|
_sendCORS();
|
||||||
|
if (!_isAuth())
|
||||||
|
return;
|
||||||
userdb::User created;
|
userdb::User created;
|
||||||
String body = _server->arg("plain");
|
String body = _server->arg("plain");
|
||||||
const int capacity = 1024;
|
const int capacity = 1024;
|
||||||
@ -207,6 +265,8 @@ void WebConsole::_createUser()
|
|||||||
void WebConsole::_dropUserDb()
|
void WebConsole::_dropUserDb()
|
||||||
{
|
{
|
||||||
_sendCORS();
|
_sendCORS();
|
||||||
|
if (!_isAuth())
|
||||||
|
return;
|
||||||
if (userdb->drop())
|
if (userdb->drop())
|
||||||
_server->send(500, "text/json", "{\"ok\":\"UserDb dropped.\"}");
|
_server->send(500, "text/json", "{\"ok\":\"UserDb dropped.\"}");
|
||||||
else
|
else
|
||||||
@ -215,6 +275,8 @@ void WebConsole::_dropUserDb()
|
|||||||
void WebConsole::_catchRFID()
|
void WebConsole::_catchRFID()
|
||||||
{
|
{
|
||||||
_sendCORS();
|
_sendCORS();
|
||||||
|
if (!_isAuth())
|
||||||
|
return;
|
||||||
if (rfid == nullptr)
|
if (rfid == nullptr)
|
||||||
{
|
{
|
||||||
_server->send(500, "text/json", "{\"error\":\"RFID not attached.\"}");
|
_server->send(500, "text/json", "{\"error\":\"RFID not attached.\"}");
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "ArduinoJson.h"
|
#include "ArduinoJson.h"
|
||||||
#include "UserDb.h"
|
#include "UserDb.h"
|
||||||
#include "Rfid.h"
|
#include "Rfid.h"
|
||||||
|
#include "AdminAuth.h"
|
||||||
namespace webconsole
|
namespace webconsole
|
||||||
{
|
{
|
||||||
static const char path_prefix[] PROGMEM = "/s";
|
static const char path_prefix[] PROGMEM = "/s";
|
||||||
@ -24,6 +25,8 @@ namespace webconsole
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void _sendCORS();
|
void _sendCORS();
|
||||||
|
void _auth();
|
||||||
|
bool _isAuth();
|
||||||
void _handleUnknown();
|
void _handleUnknown();
|
||||||
void _getUserDb();
|
void _getUserDb();
|
||||||
void _deleteUser();
|
void _deleteUser();
|
||||||
@ -49,6 +52,7 @@ namespace webconsole
|
|||||||
bool catch_rfid_updated = false;
|
bool catch_rfid_updated = false;
|
||||||
String rfid_buffer;
|
String rfid_buffer;
|
||||||
Rfid *rfid = nullptr;
|
Rfid *rfid = nullptr;
|
||||||
|
AdminAuth auth;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user