I'm preparing using an esp32cam as a kind of "Bird-Cam". I used the example "CameraWebServer", but I want to protect the main control page with a password. I thought at a kind of prompt like known from creating an ".htaccess"-file in Apache. I tried different thing, but I can't get it running. Has somebody an idea for me?
i stole this from somewhere online so i take no credit the online down side is you need to completely close out the mobile browser to reach the log in page again so it wont prompt you to log in every time just once for every new browser access until the entire browser is shut down and restarted aka not on a new tab
obviously you'll need to change some stuff but its a good start youll just need to bridge the log in screen to open the webserver after creds have been added
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
// Replace with your network credentials
const char* ssid = "tu_madre";
const char* password = "es_bonita";
const char* http_username = "edgy_hacker_username";
const char* http_password = "name_of_ur_puppy";
const char* PARAM_INPUT_1 = "state";
const int output = 2;
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
<title>ESP Web Server</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
html {font-family: Arial; display: inline-block; text-align: center;}
h2 {font-size: 2.6rem;}
body {max-width: 600px; margin:0px auto; padding-bottom: 10px;}
.switch {position: relative; display: inline-block; width: 120px; height: 68px}
.switch input {display: none}
.slider {position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; border-radius: 34px}
.slider:before {position: absolute; content: ""; height: 52px; width: 52px; left: 8px; bottom: 8px; background-color: #fff; -webkit-transition: .4s; transition: .4s; border-radius: 68px}
input:checked+.slider {background-color: #2196F3}
input:checked+.slider:before {-webkit-transform: translateX(52px); -ms-transform: translateX(52px); transform: translateX(52px)}
</style>
</head>
<body>
<h2>ESP Web Server</h2>
<button onclick="logoutButton()">Logout</button>
<p>Ouput - GPIO 2 - State <span id="state">%STATE%</span></p>
%BUTTONPLACEHOLDER%
<script>function toggleCheckbox(element) {
var xhr = new XMLHttpRequest();
if(element.checked){
xhr.open("GET", "/update?state=1", true);
document.getElementById("state").innerHTML = "OFF";
}
else {
xhr.open("GET", "/update?state=0", true);
document.getElementById("state").innerHTML = "ON";
}
xhr.send();
}
function logoutButton() {
var xhr = new XMLHttpRequest();
xhr.open("GET", "/logout", true);
xhr.send();
setTimeout(function(){ window.open("/logged-out","_self"); }, 1000);
}
</script>
</body>
</html>
)rawliteral";
const char logout_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<p>Logged out or <a href="/">return to homepage</a>.</p>
<p><strong>Note:</strong> close all web browser tabs to complete the logout process.</p>
</body>
</html>
)rawliteral";
// Replaces placeholder with button section in your web page
String processor(const String& var){
//Serial.println(var);
if(var == "BUTTONPLACEHOLDER"){
String buttons ="";
String outputStateValue = outputState();
buttons+= "<p><label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"output\" " + outputStateValue + "><span class=\"slider\"></span></label></p>";
return buttons;
}
if (var == "STATE"){
if(digitalRead(output)){
return "ON";
}
else {
return "OFF";
}
}
return String();
}
String outputState(){
if(digitalRead(output)){
return "checked";
}
else {
return "";
}
return "";
}
void setup(){
// Serial port for debugging purposes
Serial.begin(115200);
pinMode(output, OUTPUT);
digitalWrite(output,HIGH);
// Connect to Wi-Fi
WiFi.softAP(ssid, password);
IPAddress IP = WiFi.softAPIP();
Serial.print("AP IP address: ");
Serial.println(IP);
// Route for root / web page
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
if(!request->authenticate(http_username, http_password))
return request->requestAuthentication();
request->send_P(200, "text/html", index_html, processor);
});
server.on("/logout", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(401);
});
server.on("/logged-out", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", logout_html, processor);
});
// Send a GET request to <ESP_IP>/update?state=<inputMessage>
server.on("/update", HTTP_GET, [] (AsyncWebServerRequest *request) {
if(!request->authenticate(http_username, http_password))
return request->requestAuthentication();
String inputMessage;
String inputParam;
// GET input1 value on <ESP_IP>/update?state=<inputMessage>
if (request->hasParam(PARAM_INPUT_1)) {
inputMessage = request->getParam(PARAM_INPUT_1)->value();
inputParam = PARAM_INPUT_1;
digitalWrite(output, inputMessage.toInt());
}
else {
inputMessage = "No message sent";
inputParam = "none";
}
Serial.println(inputMessage);
request->send(200, "text/plain", "OK");
});
// Start server
server.begin();
}
void loop() {
}
@ZX80 Great code! Thanks for sharing. I incorporated your piece of code into the http server of esp32cam. It wasn't so difficult as expected.
I just have one further question: In line 34 window.open("/serverIndex")
opens the site "serverIndex" from the server. But serverIndex is still not protected when it's called directly like http://www.website.com/serverIndex
Is there a way to create a site which is not callable from outside without password protection?
@do_not_sleep Thanks for the script. Unfortunalety, it's not possible for esp32cam because the esp32 uses a http server and not the "ESPAsyncTCP" / "ESPAsyncWebServer". Nevertheless, thank's for helping!
Someone would have to guess the name of the page. So don 't use index.html
Okay, thats a solution. Thank you!
Only sufficient if you're not really that concerned about someone gaining access to the camera.
I'm not. I don't want to protect the camera data neither, but just the main configuration page. I have some people around me who would have much fun to trick me in which changing the camera config. If somebody want to take a look at the camera pictures or stream, he can do, if he want, because it will just display some birds like a trail-camera.
For everyone who has the same problem, here how to incorporate the code from @ZX80 into app_httpd.cpp of the CameraWebServer Example:
Just insert the piece of code at the beginning of the sketch. You can change the username and password into the code at line 32. The site which will be opened if credentials are correct can be changed in line 34. Then change in the function void startCameraServer() in the structure index_uri the handler into "password_handler" or something like that.
You have to add a new struct like this with a variable .uri-site and "index_handler" as .handler.
You have to do the same with all pages which you want to protect with a password.
Further up, create a new function called "password_handler":
Hi @model_railroader ! I'm trying to add some kind of protection to the site too, but I can't figure things out.
Now, to access my web server, I just have to enter the IP address, without specifying the page name. How did you manage to direct the configuration menu and the stream to that particular page? And, question I should have asked you earlier, how did you manage to create that page with that particular name?
If it were not a problem for you I would ask you the code with which you managed to realize the project.
And you have to insert the piece of code of @ZX80 at the beginning of the sketch.
And, question I should have asked you earlier, how did you manage to create that page with that particular name?
Sorry, I don't understand that. Maybe it's because my night was too long, but which page do you mean?
The code of the app_httpd.cpp is very long. You'll find it in the attachement. In line 625 you can change the page which will be opened after you entered the right credentials. In this case, it is "configpasswordprotected". In line 657 is in the config_uri struct - the structure for the configuration page - the same name. If you have any more questions, feel free to ask me again. It's just able, that you have to wait for a moment, because I'm very busy in these days.
Have fun coding! forum.cpp (23,3 KB)
Hi, I am attempting to implement your solution, but whenever I try to compile it an error occurs in the 'static esp_err_t password handler()' function. The error is
"no return statement in function returning non-void [-Werror=return-type]"
does it need a return statement, and if so how do I add one?
Could you send your complete "app_httpd.cpp"-file? Of course, without your credentials that you want to use.
And it would be great, if you could send your complete error message.