mirror of
https://github.com/esp8266/Arduino.git
synced 2025-04-21 10:26:06 +03:00
Merge pull request #1112 from me-no-dev/www-basic-auth
Add HTTP Basic Auth to WebServer and libb64 (base64) to core
This commit is contained in:
commit
1b49c58cdb
7
cores/esp8266/libb64/AUTHORS
Executable file
7
cores/esp8266/libb64/AUTHORS
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
libb64: Base64 Encoding/Decoding Routines
|
||||||
|
======================================
|
||||||
|
|
||||||
|
Authors:
|
||||||
|
-------
|
||||||
|
|
||||||
|
Chris Venter chris.venter@gmail.com http://rocketpod.blogspot.com
|
29
cores/esp8266/libb64/LICENSE
Executable file
29
cores/esp8266/libb64/LICENSE
Executable file
@ -0,0 +1,29 @@
|
|||||||
|
Copyright-Only Dedication (based on United States law)
|
||||||
|
or Public Domain Certification
|
||||||
|
|
||||||
|
The person or persons who have associated work with this document (the
|
||||||
|
"Dedicator" or "Certifier") hereby either (a) certifies that, to the best of
|
||||||
|
his knowledge, the work of authorship identified is in the public domain of the
|
||||||
|
country from which the work is published, or (b) hereby dedicates whatever
|
||||||
|
copyright the dedicators holds in the work of authorship identified below (the
|
||||||
|
"Work") to the public domain. A certifier, moreover, dedicates any copyright
|
||||||
|
interest he may have in the associated work, and for these purposes, is
|
||||||
|
described as a "dedicator" below.
|
||||||
|
|
||||||
|
A certifier has taken reasonable steps to verify the copyright status of this
|
||||||
|
work. Certifier recognizes that his good faith efforts may not shield him from
|
||||||
|
liability if in fact the work certified is not in the public domain.
|
||||||
|
|
||||||
|
Dedicator makes this dedication for the benefit of the public at large and to
|
||||||
|
the detriment of the Dedicator's heirs and successors. Dedicator intends this
|
||||||
|
dedication to be an overt act of relinquishment in perpetuity of all present
|
||||||
|
and future rights under copyright law, whether vested or contingent, in the
|
||||||
|
Work. Dedicator understands that such relinquishment of all rights includes
|
||||||
|
the relinquishment of all rights to enforce (by lawsuit or otherwise) those
|
||||||
|
copyrights in the Work.
|
||||||
|
|
||||||
|
Dedicator recognizes that, once placed in the public domain, the Work may be
|
||||||
|
freely reproduced, distributed, transmitted, used, modified, built upon, or
|
||||||
|
otherwise exploited by anyone for any purpose, commercial or non-commercial,
|
||||||
|
and in any way, including by methods that have not yet been invented or
|
||||||
|
conceived.
|
86
cores/esp8266/libb64/cdecode.c
Executable file
86
cores/esp8266/libb64/cdecode.c
Executable file
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
cdecoder.c - c source to a base64 decoding algorithm implementation
|
||||||
|
|
||||||
|
This is part of the libb64 project, and has been placed in the public domain.
|
||||||
|
For details, see http://sourceforge.net/projects/libb64
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "cdecode.h"
|
||||||
|
|
||||||
|
int base64_decode_value(char value_in){
|
||||||
|
static const char decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51};
|
||||||
|
static const char decoding_size = sizeof(decoding);
|
||||||
|
value_in -= 43;
|
||||||
|
if (value_in < 0 || value_in > decoding_size) return -1;
|
||||||
|
return decoding[(int)value_in];
|
||||||
|
}
|
||||||
|
|
||||||
|
void base64_init_decodestate(base64_decodestate* state_in){
|
||||||
|
state_in->step = step_a;
|
||||||
|
state_in->plainchar = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in){
|
||||||
|
const char* codechar = code_in;
|
||||||
|
char* plainchar = plaintext_out;
|
||||||
|
char fragment;
|
||||||
|
|
||||||
|
*plainchar = state_in->plainchar;
|
||||||
|
|
||||||
|
switch (state_in->step){
|
||||||
|
while (1){
|
||||||
|
case step_a:
|
||||||
|
do {
|
||||||
|
if (codechar == code_in+length_in){
|
||||||
|
state_in->step = step_a;
|
||||||
|
state_in->plainchar = *plainchar;
|
||||||
|
return plainchar - plaintext_out;
|
||||||
|
}
|
||||||
|
fragment = (char)base64_decode_value(*codechar++);
|
||||||
|
} while (fragment < 0);
|
||||||
|
*plainchar = (fragment & 0x03f) << 2;
|
||||||
|
case step_b:
|
||||||
|
do {
|
||||||
|
if (codechar == code_in+length_in){
|
||||||
|
state_in->step = step_b;
|
||||||
|
state_in->plainchar = *plainchar;
|
||||||
|
return plainchar - plaintext_out;
|
||||||
|
}
|
||||||
|
fragment = (char)base64_decode_value(*codechar++);
|
||||||
|
} while (fragment < 0);
|
||||||
|
*plainchar++ |= (fragment & 0x030) >> 4;
|
||||||
|
*plainchar = (fragment & 0x00f) << 4;
|
||||||
|
case step_c:
|
||||||
|
do {
|
||||||
|
if (codechar == code_in+length_in){
|
||||||
|
state_in->step = step_c;
|
||||||
|
state_in->plainchar = *plainchar;
|
||||||
|
return plainchar - plaintext_out;
|
||||||
|
}
|
||||||
|
fragment = (char)base64_decode_value(*codechar++);
|
||||||
|
} while (fragment < 0);
|
||||||
|
*plainchar++ |= (fragment & 0x03c) >> 2;
|
||||||
|
*plainchar = (fragment & 0x003) << 6;
|
||||||
|
case step_d:
|
||||||
|
do {
|
||||||
|
if (codechar == code_in+length_in){
|
||||||
|
state_in->step = step_d;
|
||||||
|
state_in->plainchar = *plainchar;
|
||||||
|
return plainchar - plaintext_out;
|
||||||
|
}
|
||||||
|
fragment = (char)base64_decode_value(*codechar++);
|
||||||
|
} while (fragment < 0);
|
||||||
|
*plainchar++ |= (fragment & 0x03f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* control should not reach here */
|
||||||
|
return plainchar - plaintext_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
int base64_decode_chars(const char* code_in, const int length_in, char* plaintext_out){
|
||||||
|
base64_decodestate _state;
|
||||||
|
base64_init_decodestate(&_state);
|
||||||
|
int len = base64_decode_block(code_in, length_in, plaintext_out, &_state);
|
||||||
|
if(len > 0) plaintext_out[len] = 0;
|
||||||
|
return len;
|
||||||
|
}
|
38
cores/esp8266/libb64/cdecode.h
Executable file
38
cores/esp8266/libb64/cdecode.h
Executable file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
cdecode.h - c header for a base64 decoding algorithm
|
||||||
|
|
||||||
|
This is part of the libb64 project, and has been placed in the public domain.
|
||||||
|
For details, see http://sourceforge.net/projects/libb64
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BASE64_CDECODE_H
|
||||||
|
#define BASE64_CDECODE_H
|
||||||
|
|
||||||
|
#define base64_decode_expected_len(n) ((n * 3) / 4)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
step_a, step_b, step_c, step_d
|
||||||
|
} base64_decodestep;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
base64_decodestep step;
|
||||||
|
char plainchar;
|
||||||
|
} base64_decodestate;
|
||||||
|
|
||||||
|
void base64_init_decodestate(base64_decodestate* state_in);
|
||||||
|
|
||||||
|
int base64_decode_value(char value_in);
|
||||||
|
|
||||||
|
int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in);
|
||||||
|
|
||||||
|
int base64_decode_chars(const char* code_in, const int length_in, char* plaintext_out);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* BASE64_CDECODE_H */
|
104
cores/esp8266/libb64/cencode.c
Executable file
104
cores/esp8266/libb64/cencode.c
Executable file
@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
cencoder.c - c source to a base64 encoding algorithm implementation
|
||||||
|
|
||||||
|
This is part of the libb64 project, and has been placed in the public domain.
|
||||||
|
For details, see http://sourceforge.net/projects/libb64
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "cencode.h"
|
||||||
|
|
||||||
|
const int CHARS_PER_LINE = 72;
|
||||||
|
|
||||||
|
void base64_init_encodestate(base64_encodestate* state_in){
|
||||||
|
state_in->step = step_A;
|
||||||
|
state_in->result = 0;
|
||||||
|
state_in->stepcount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char base64_encode_value(char value_in){
|
||||||
|
static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
|
if (value_in > 63) return '=';
|
||||||
|
return encoding[(int)value_in];
|
||||||
|
}
|
||||||
|
|
||||||
|
int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in){
|
||||||
|
const char* plainchar = plaintext_in;
|
||||||
|
const char* const plaintextend = plaintext_in + length_in;
|
||||||
|
char* codechar = code_out;
|
||||||
|
char result;
|
||||||
|
char fragment;
|
||||||
|
|
||||||
|
result = state_in->result;
|
||||||
|
|
||||||
|
switch (state_in->step){
|
||||||
|
while (1){
|
||||||
|
case step_A:
|
||||||
|
if (plainchar == plaintextend){
|
||||||
|
state_in->result = result;
|
||||||
|
state_in->step = step_A;
|
||||||
|
return codechar - code_out;
|
||||||
|
}
|
||||||
|
fragment = *plainchar++;
|
||||||
|
result = (fragment & 0x0fc) >> 2;
|
||||||
|
*codechar++ = base64_encode_value(result);
|
||||||
|
result = (fragment & 0x003) << 4;
|
||||||
|
case step_B:
|
||||||
|
if (plainchar == plaintextend){
|
||||||
|
state_in->result = result;
|
||||||
|
state_in->step = step_B;
|
||||||
|
return codechar - code_out;
|
||||||
|
}
|
||||||
|
fragment = *plainchar++;
|
||||||
|
result |= (fragment & 0x0f0) >> 4;
|
||||||
|
*codechar++ = base64_encode_value(result);
|
||||||
|
result = (fragment & 0x00f) << 2;
|
||||||
|
case step_C:
|
||||||
|
if (plainchar == plaintextend){
|
||||||
|
state_in->result = result;
|
||||||
|
state_in->step = step_C;
|
||||||
|
return codechar - code_out;
|
||||||
|
}
|
||||||
|
fragment = *plainchar++;
|
||||||
|
result |= (fragment & 0x0c0) >> 6;
|
||||||
|
*codechar++ = base64_encode_value(result);
|
||||||
|
result = (fragment & 0x03f) >> 0;
|
||||||
|
*codechar++ = base64_encode_value(result);
|
||||||
|
|
||||||
|
++(state_in->stepcount);
|
||||||
|
if (state_in->stepcount == CHARS_PER_LINE/4){
|
||||||
|
*codechar++ = '\n';
|
||||||
|
state_in->stepcount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* control should not reach here */
|
||||||
|
return codechar - code_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
int base64_encode_blockend(char* code_out, base64_encodestate* state_in){
|
||||||
|
char* codechar = code_out;
|
||||||
|
|
||||||
|
switch (state_in->step){
|
||||||
|
case step_B:
|
||||||
|
*codechar++ = base64_encode_value(state_in->result);
|
||||||
|
*codechar++ = '=';
|
||||||
|
*codechar++ = '=';
|
||||||
|
break;
|
||||||
|
case step_C:
|
||||||
|
*codechar++ = base64_encode_value(state_in->result);
|
||||||
|
*codechar++ = '=';
|
||||||
|
break;
|
||||||
|
case step_A:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*codechar = 0x00;
|
||||||
|
|
||||||
|
return codechar - code_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
int base64_encode_chars(const char* plaintext_in, int length_in, char* code_out){
|
||||||
|
base64_encodestate _state;
|
||||||
|
base64_init_encodestate(&_state);
|
||||||
|
int len = base64_encode_block(plaintext_in, length_in, code_out, &_state);
|
||||||
|
return len + base64_encode_blockend((code_out + len), &_state);
|
||||||
|
}
|
41
cores/esp8266/libb64/cencode.h
Executable file
41
cores/esp8266/libb64/cencode.h
Executable file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
cencode.h - c header for a base64 encoding algorithm
|
||||||
|
|
||||||
|
This is part of the libb64 project, and has been placed in the public domain.
|
||||||
|
For details, see http://sourceforge.net/projects/libb64
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BASE64_CENCODE_H
|
||||||
|
#define BASE64_CENCODE_H
|
||||||
|
|
||||||
|
#define base64_encode_expected_len(n) ((((4 * n) / 3) + 3) & ~3)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
step_A, step_B, step_C
|
||||||
|
} base64_encodestep;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
base64_encodestep step;
|
||||||
|
char result;
|
||||||
|
int stepcount;
|
||||||
|
} base64_encodestate;
|
||||||
|
|
||||||
|
void base64_init_encodestate(base64_encodestate* state_in);
|
||||||
|
|
||||||
|
char base64_encode_value(char value_in);
|
||||||
|
|
||||||
|
int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in);
|
||||||
|
|
||||||
|
int base64_encode_blockend(char* code_out, base64_encodestate* state_in);
|
||||||
|
|
||||||
|
int base64_encode_chars(const char* plaintext_in, int length_in, char* code_out);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* BASE64_CENCODE_H */
|
@ -0,0 +1,40 @@
|
|||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESP8266mDNS.h>
|
||||||
|
#include <ArduinoOTA.h>
|
||||||
|
#include <ESP8266WebServer.h>
|
||||||
|
|
||||||
|
const char* ssid = "........";
|
||||||
|
const char* password = "........";
|
||||||
|
|
||||||
|
ESP8266WebServer server(80);
|
||||||
|
|
||||||
|
const char* www_username = "admin";
|
||||||
|
const char* www_password = "esp8266";
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
WiFi.mode(WIFI_STA);
|
||||||
|
WiFi.begin(ssid, password);
|
||||||
|
if(WiFi.waitForConnectResult() != WL_CONNECTED) {
|
||||||
|
Serial.println("WiFi Connect Failed! Rebooting...");
|
||||||
|
delay(1000);
|
||||||
|
ESP.restart();
|
||||||
|
}
|
||||||
|
ArduinoOTA.begin();
|
||||||
|
|
||||||
|
server.on("/", [](){
|
||||||
|
if(!server.authenticate(www_username, www_password))
|
||||||
|
return server.requestAuthentication();
|
||||||
|
server.send(200, "text/plain", "Login OK");
|
||||||
|
});
|
||||||
|
server.begin();
|
||||||
|
|
||||||
|
Serial.print("Open http://");
|
||||||
|
Serial.print(WiFi.localIP());
|
||||||
|
Serial.println("/ in your browser to see it working");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
ArduinoOTA.handle();
|
||||||
|
server.handleClient();
|
||||||
|
}
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#include <libb64/cencode.h>
|
||||||
#include "WiFiServer.h"
|
#include "WiFiServer.h"
|
||||||
#include "WiFiClient.h"
|
#include "WiFiClient.h"
|
||||||
#include "ESP8266WebServer.h"
|
#include "ESP8266WebServer.h"
|
||||||
@ -30,6 +31,7 @@
|
|||||||
// #define DEBUG
|
// #define DEBUG
|
||||||
#define DEBUG_OUTPUT Serial
|
#define DEBUG_OUTPUT Serial
|
||||||
|
|
||||||
|
const char * AUTHORIZATION_HEADER = "Authorization";
|
||||||
|
|
||||||
ESP8266WebServer::ESP8266WebServer(IPAddress addr, int port)
|
ESP8266WebServer::ESP8266WebServer(IPAddress addr, int port)
|
||||||
: _server(addr, port)
|
: _server(addr, port)
|
||||||
@ -73,6 +75,38 @@ ESP8266WebServer::~ESP8266WebServer() {
|
|||||||
|
|
||||||
void ESP8266WebServer::begin() {
|
void ESP8266WebServer::begin() {
|
||||||
_server.begin();
|
_server.begin();
|
||||||
|
if(!_headerKeysCount)
|
||||||
|
collectHeaders(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ESP8266WebServer::authenticate(const char * username, const char * password){
|
||||||
|
if(hasHeader(AUTHORIZATION_HEADER)){
|
||||||
|
String authReq = header(AUTHORIZATION_HEADER);
|
||||||
|
if(authReq.startsWith("Basic")){
|
||||||
|
authReq = authReq.substring(6);
|
||||||
|
authReq.trim();
|
||||||
|
char toencodeLen = strlen(username)+strlen(password)+1;
|
||||||
|
char *toencode = new char[toencodeLen];
|
||||||
|
if(toencode == NULL)
|
||||||
|
return false;
|
||||||
|
char *encoded = new char[base64_encode_expected_len(toencodeLen)+1];
|
||||||
|
if(encoded == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
sprintf(toencode, "%s:%s", username, password);
|
||||||
|
if(base64_encode_chars(toencode, toencodeLen, encoded) > 0 && authReq.equals(encoded)){
|
||||||
|
authReq = String();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
authReq = String();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266WebServer::requestAuthentication(){
|
||||||
|
sendHeader("WWW-Authenticate", "Basic realm=\"Login Required\"");
|
||||||
|
send(401);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESP8266WebServer::on(const char* uri, ESP8266WebServer::THandlerFunction handler) {
|
void ESP8266WebServer::on(const char* uri, ESP8266WebServer::THandlerFunction handler) {
|
||||||
@ -316,12 +350,13 @@ String ESP8266WebServer::header(const char* name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ESP8266WebServer::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) {
|
void ESP8266WebServer::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) {
|
||||||
_headerKeysCount = headerKeysCount;
|
_headerKeysCount = headerKeysCount + 1;
|
||||||
if (_currentHeaders)
|
if (_currentHeaders)
|
||||||
delete[]_currentHeaders;
|
delete[]_currentHeaders;
|
||||||
_currentHeaders = new RequestArgument[_headerKeysCount];
|
_currentHeaders = new RequestArgument[_headerKeysCount];
|
||||||
for (int i = 0; i < _headerKeysCount; i++){
|
_currentHeaders[0].key = AUTHORIZATION_HEADER;
|
||||||
_currentHeaders[i].key = headerKeys[i];
|
for (int i = 1; i < _headerKeysCount; i++){
|
||||||
|
_currentHeaders[i].key = headerKeys[i-1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +65,10 @@ public:
|
|||||||
|
|
||||||
void begin();
|
void begin();
|
||||||
void handleClient();
|
void handleClient();
|
||||||
|
|
||||||
|
bool authenticate(const char * username, const char * password);
|
||||||
|
void requestAuthentication();
|
||||||
|
|
||||||
typedef std::function<void(void)> THandlerFunction;
|
typedef std::function<void(void)> THandlerFunction;
|
||||||
void on(const char* uri, THandlerFunction handler);
|
void on(const char* uri, THandlerFunction handler);
|
||||||
void on(const char* uri, HTTPMethod method, THandlerFunction fn);
|
void on(const char* uri, HTTPMethod method, THandlerFunction fn);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user