Compare commits

...
This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.

4 Commits

Author SHA1 Message Date
Diogo Cordeiro 2f2b6af671 brilliant hack to make everything work... 2019-04-05 10:53:46 +01:00
Diogo Cordeiro dff282567d Fix weird instruction on token system and add some more debugging outputs to production release 2019-04-03 21:20:14 +01:00
Diogo Cordeiro 59215f4d38 Add production binary 2019-03-22 17:38:56 +00:00
Diogo Cordeiro 1c59afa216 Special MostraUP release: Add Authentication
Translated interface to portuguese as this is a portuguese event
2019-03-22 16:35:03 +00:00
10 changed files with 546 additions and 58 deletions

View File

@ -63,6 +63,8 @@ Installing the basic Fun with Binary in offline mode is relatively easy.
4. Minify the script.js with http://lisperator.net/uglifyjs/ and replace the
line after <!-- JS --> in the index.html with the result inside the tags
<script>*result*</script>
Note: If you have problems minifying try replacing `let` by `var`, then
minify, and then reverting the replace in the minified version.
5. Make the resulting HTM usable with the following tool:
https://github.com/CytronTechnologies/ESP8266-WiFi-Module/raw/master/convertHtml/convertHtml.jar

View File

@ -25,7 +25,15 @@ There are no special prerequisites for the offline mode.
At least: Arduino Uno with ESP8266-01, 6 leds (and 6 resistors), wires, breadboard.
Some instruction of how to build it can be found on my blog post about this project: [https://blog.diogo.site/posts/fun-with-binary](https://blog.diogo.site/posts/fun-with-binary)
You have instructions of how to build your own FwB in my blog: [https://blog.diogo.site/posts/fun-with-binary](https://blog.diogo.site/posts/fun-with-binary)
## MostraUP edition
This is a special edition that adds a password mechanism to force single player
in online mode.
Every output messages were translated to Portuguese due to
University of Porto's Exhibition (MostraUP) being a portuguese event.
For regular usage (during a lecture) you will probably find standard release 2.0
a better option: https://www.diogo.site/projects/fun_with_binary#releases
## Versioning
@ -63,18 +71,3 @@ Additional library software has been made available. All of it is Free Software
and can be distributed under liberal terms, but those terms may differ in detail
from the AGPL's particulars. See each package's license file in their official
repository for additional terms.
## New this version
This is version 2.0 of Fun with Binary and includes the following (key) changes
from the previous one:
- Client <-> Server <-> Arduino was replaced by a Client <-> Arduino structure
- ESP8266 is now required for Access Point purposes
- Both modes have become PHP independent (mostly relevant in the offline one)
The last release, 2.0, gave us these improvements:
- Significant visual improvement
- 2 Powers Label switch functionality
- Offline mode is now lighter and more portable (no computer with webserver required anymore)

70
auth/index.html Normal file
View File

@ -0,0 +1,70 @@
<!--
Fun with Binary - a fun way of introducing binary
Copyright (C) 2018, Diogo Cordeiro.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=800" />
<title>Fun with Binary</title>
<meta name="description" content="A fun way of introducing binary">
<meta name="author" content="Diogo Cordeiro">
<!-- CSS -->
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body class="container">
<!-- auth_html_message_Busy -->
<div id="statement">
<p class="text" id="statement_text">
Já está alguém a jogar, espera pela tua vez! :)
</p>
</div>
<!-- auth_html_message_readyToPLay -->
<div id="statement">
<p class="text" id="statement_text">
Acende as lâmpadas conforme a caixa! :)
</p>
</div>
<!-- auth_html_login_dialog -->
<div class="images" id="leds">
</div>
<br>
<ul id="settings">
<li>
<div class="button">
<input type="button" onclick="submit_auth_form()" value="Vamos Jogar!" id="play_button">
</div>
</li>
</ul>
<!-- Credits -->
<p class="text" id="footer">Feito com <span style="color:
#e25555;">&#9829;</span> por
<a href="https://www.diogo.site/">Diogo Cordeiro</a></p>
<!-- JS -->
<script src="script.js"></script>
</body>
</html>

152
auth/script.js Normal file
View File

@ -0,0 +1,152 @@
/*
* Fun with Binary - a fun way of introducing binary
* Copyright (C) 2018, Diogo Cordeiro.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category UI interaction
* @package Fun with Binary
* @author Diogo Cordeiro <up201705417@fc.up.pt>
* @copyright 2018 Diogo Cordeiro.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.diogo.site/projects/fun_with_binary/
*/
/***********************************
* EXTEND JAVASCRIPT FUNCTIONALITY *
***********************************/
/**
* Returns a random integer between min (inclusive) and max (inclusive)
* Using Math.round() would give a non-uniform distribution!
*/
function getRandomInt (min, max)
{
return Math.floor(Math.random() * (max - min + 1)) + min;
}
/**
* Replace char at given position
*/
String.prototype.replaceAt=function(index, replacement)
{
return this.substr(0, index) + replacement+ this.substr(index +
replacement.length);
}
/**
* Checks if session storage is available
*/
function is_session_storage_available ()
{
return window.sessionStorage != null;
}
//***********************************
/***********************************
* GAME SETTINGS *
***********************************/
// Box IP
let URL = "http://42.42.42.42/";
// Number of leds
let NLEDS = 6;
// ON and OFF leds srcs
let LED_OFF = "data:image/png;base64,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";
let LED_ON = "data:image/png;base64,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";
//***********************************
/**********************************
* ACTUAL GAME *
**********************************/
/**
* Global variables
*/
// Empty Answer
empty_answer = '';
while (empty_answer.length < NLEDS)
{
empty_answer += '0';
}
// current answer
current_answer = empty_answer;
/**
* Create leds
*/
for (let i = 0; i < NLEDS; ++i)
{
// Led holder
let figure = document.createElement ("figure");
figure.setAttribute ("class", "box");
// Led
let img = document.createElement ("img");
img.src = LED_OFF;
img.setAttribute ("value", "OFF");
img.id = "led" + i;
img.setAttribute ("class", "led");
img.setAttribute ("onclick", "switch_led("+i+")");
figure.appendChild (img);
document.getElementById("leds").appendChild(figure);
}
/**
* Turn current answer bits accordingly
*/
function switch_led (led_id)
{
let image = document.getElementById("led"+led_id);
if (image.getAttribute("value") == "ON")
{
image.setAttribute ("value", "OFF");
image.src = LED_OFF;
current_answer = current_answer.replaceAt(led_id, "0");
}
else
{
image.setAttribute ("value", "ON");
image.src = LED_ON;
current_answer = current_answer.replaceAt(led_id, "1");
}
}
function submit_auth_form ()
{
let xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
if (this.responseText == "ok")
window.location.replace (URL+"game");
else
alert (this.responseText);
}
};
xhttp.open("POST", URL+"auth", true);
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
sessionStorage.token=getRandomInt (42, 31337)
xhttp.send("password="+current_answer+"&token="+sessionStorage.token);
}

Binary file not shown.

View File

@ -38,9 +38,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<!-- Statement -->
<div id="statement">
<p class="text" id="statement_text">
How do you represent the number
Como representas o número
<span id="statement_value"></span>
in binary?
em binário?
</p>
</div>
@ -48,7 +48,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<ul id="settings">
<li>
<div class="button" id="label_switch_button">
<p class="text" id="settings_label_label">Labels</p>
<p class="text"
id="settings_label_label">Potências de 2</p>
<label class="switch">
<input id="label_switch"
class="toggle"
@ -63,7 +64,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</ul>
<!-- Credits -->
<p class="text" id="footer">Made with <span style="color: #e25555;">&#9829;</span> by
<p class="text" id="footer">Feito com <span style="color:
#e25555;">&#9829;</span> por
<a href="https://www.diogo.site/">Diogo Cordeiro</a></p>
<!-- JS -->
<script src="script.js"></script>

View File

@ -56,12 +56,11 @@ function is_session_storage_available()
/***********************************
* GAME SETTINGS *
***********************************/
// Online Mode (only used in Online Mode)
ONLINEMODE = false;
ONLINEMODE = true;
// Box IP (only used in Online Mode)
ONLINEURL = "http://42.42.42.42/";
// Box IP
ONLINEURL = "http://42.42.42.42/game/";
// Number of leds
NLEDS = 6;
@ -87,7 +86,11 @@ LED_ON = "data:image/png;base64,R0lGODlhZAC0ANX/AMDAwP//zP//mf//Zv//M///AP/M///
* Global variables
*/
// Empty Answer
for (empty_answer = ''; empty_answer.length < NLEDS; empty_answer += '0');
empty_answer = '';
while (empty_answer.length < NLEDS)
{
empty_answer += '0';
}
// correct answer
correct_answer = empty_answer;
@ -214,9 +217,9 @@ function switch_led(led_id)
if (ONLINEMODE)
{
let xhttp = new XMLHttpRequest();
xhttp.open("GET", ONLINEURL+"switch_state?led=" + led_id, true);
xhttp.open("GET", ONLINEURL+"switch_state?led=" + led_id +
"&token=" + sessionStorage.token, true);
xhttp.send();
}
// If right answer, finish game, restart a new one
@ -333,7 +336,8 @@ function end_game()
if (ONLINEMODE)
{
let xhttp = new XMLHttpRequest();
xhttp.open("GET", ONLINEURL+"won", true);
xhttp.open("GET", ONLINEURL+"won" +
"?token=" + sessionStorage.token, true);
xhttp.send();
}

82
server/HTML.cpp Normal file
View File

@ -0,0 +1,82 @@
#include "HTML.h"
String cssHTML ()
{
const String cssHTML =
"";
return cssHTML;
}
String gameHTML1 ()
{
const String gameHTML1=
"\r\n"
"\r\n"
"\r\n";
return gameHTML1;
}
String gameHTML2 ()
{
const String gameHTML2=
"\r\n"
"\r\n"
"\r\n";
return gameHTML2;
}
String gameHTML3 ()
{
const String gameHTML3=
"\r\n"
"\r\n"
"\r\n";
return gameHTML3;
}
String gameHTML4 ()
{
const String gameHTML4=
"\r\n"
"\r\n"
"\r\n";
return gameHTML4;
}
String authHTML1 ()
{
const String authHTML1=
"\r\n"
"\r\n"
"\r\n";
return authHTML1;
}
String authHTML2 ()
{
const String authHTML2=
"\r\n"
"\r\n"
"\r\n";
return authHTML2;
}
String authHTML3 ()
{
const String authHTML3=
"\r\n"
"\r\n"
"\r\n";
return authHTML3;
}
String authHTML4 ()
{
const String authHTML4=
"\r\n"
"\r\n"
"\r\n";
return authHTML4;
}

18
server/HTML.h Normal file
View File

@ -0,0 +1,18 @@
// Due to https://github.com/esp8266/Arduino/issues/3205#issuecomment-299763849
#ifndef html_h
#define html_h
#include "Arduino.h"
String cssHTML ();
String gameHTML1 ();
String gameHTML2 ();
String gameHTML3 ();
String gameHTML4 ();
String authHTML1 ();
String authHTML2 ();
String authHTML3 ();
String authHTML4 ();
#endif

View File

@ -28,7 +28,7 @@
#include <ESP8266WebServer.h>
// Pages
#include "file1.h"
#include "HTML.h"
// Define a dns server for Captive Portal
const byte DNS_PORT = 53;
@ -40,7 +40,7 @@ IPAddress netMsk(255, 255, 255, 0);
// These are the WiFi access point settings. Update them to your liking
const char *ssid = "Fun with Binary";
//const char *password = "";
//const char *wifi_password = "";
// Define a web server at port 80 for HTTP
ESP8266WebServer webServer(80);
@ -49,11 +49,25 @@ ESP8266WebServer webServer(80);
#define NLEDS 6
// LEDs board outputs
int bits[NLEDS] = { D0, D1, D2, D3, D4, D5 };
// Orange, Yellow, Green, Blue, Purple, Gray
// D0 D1 D2 D5 D6 D7
int bits[NLEDS] = { D2, D3, D4, D5, D6, D7 };
// Memorizes bits state
int current_answer[NLEDS] = { 0 };
// Current state of the game
bool is_game_running = false;
// Current system password
String password = "000000";
// Current system token
int token = 0;
// This is an emergency endpoint in case some of students decides to leave
// in the middle of a game, you should rename it in production as a security
// measure
const String FORCERESTARENDPOINT = "force_restart";
/**
* Turns all leds on
* **Doesn't update current_answer**
@ -86,32 +100,33 @@ turn_all_off()
void
handleRoot()
{
webServer.send(200, "text/html", file1);
webServer.send(200, "text/html",
"<meta http-equiv=\"refresh\" content=\"0; url=http://42.42.42.42/auth\" />");
}
/**
* 404 - Page Not Found endpoint
* Game endpoint
*/
void
handleNotFound()
handleGame()
{
String message = "File Not Found\n\n";
message += "URI: ";
message += webServer.uri();
message += "\nMethod: ";
message +=(webServer.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += webServer.args();
message += "\n";
webServer.setContentLength(gameHTML1().length() +
gameHTML2().length() +
gameHTML3().length() +
gameHTML4().length());
webServer.send(200, "text/html", gameHTML1());
webServer.sendContent(gameHTML2());
webServer.sendContent(gameHTML3());
webServer.sendContent(gameHTML4());
}
for (uint8_t i = 0; i < webServer.args(); ++i) {
message +=
" " + webServer.argName(i) + ": " + webServer.arg(i) +
"\n";
}
webServer.send(404, "text/plain", message);
/**
* CSS endpoint
*/
void
return_css()
{
webServer.send(200, "text/css", cssHTML());
}
/**
@ -144,6 +159,78 @@ handleInputError()
webServer.send(500, "text/plain", message);
}
/**
* Auth endpoint
*/
void
handleAuth()
{
if (webServer.method() == HTTP_GET)
{
webServer.setContentLength(authHTML1().length() +
authHTML2().length() +
authHTML3().length() +
authHTML4().length());
webServer.send(200, "text/html", authHTML1());
webServer.sendContent(authHTML2());
webServer.sendContent(authHTML3());
webServer.sendContent(authHTML4());
}
else if (webServer.method() == HTTP_POST)
{
if (!is_game_running)
{
if (password == webServer.arg("password"))
{
is_game_running = true;
token = webServer.arg("token").toInt();
webServer.send(200, "text/html", "ok");
turn_all_off();
Serial.print("Current valid token is: ");
Serial.println(token);
}
else
{
webServer.send(200, "text/html",
"Esta palavra-passe está errada.");
}
}
else
{
webServer.send(200, "text/html",
"Já está alguém a jogar, espera pela tua vez! :)");
}
}
else
{
// Invalid HTTP request method
handleInputError();
}
}
/**
* 404 - Page Not Found endpoint
*/
void
handleNotFound()
{
String message = "File Not Found\n\n";
message += "URI: ";
message += webServer.uri();
message += "\nMethod: ";
message +=(webServer.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += webServer.args();
message += "\n";
for (uint8_t i = 0; i < webServer.args(); ++i)
message +=
" " + webServer.argName(i) + ": " + webServer.arg(i) +
"\n";
webServer.send(404, "text/plain", message);
}
/**
* Switches a led state (a.k.a. bit of current answer)
*
@ -152,27 +239,67 @@ handleInputError()
void
switch_led()
{
int incomingByte = webServer.arg("led").toInt();
if (!is_game_running || token != webServer.arg("token").toInt())
{
webServer.send(200, "text/plain", "unauthorized");
Serial.print("Invalid token tried to play: ");
Serial.println(webServer.arg("token").toInt());
return;
}
int incomingByte = webServer.arg("led").toInt();
Serial.print("Mandaram-me alterar o estado da lampada: ");
Serial.println(incomingByte);
// Validate input
if (incomingByte >= NLEDS || incomingByte < 0)
{
handleInputError();
return;
}
String message = "Led ";
if (current_answer[incomingByte] == 1)
{ // Turn LED off
message += incomingByte;
message += " off!";
digitalWrite(bits[incomingByte], LOW);
current_answer[incomingByte] = 0;
}
else
{ // Turn LED on
message += incomingByte;
message += " on!";
digitalWrite(bits[incomingByte], HIGH);
current_answer[incomingByte] = 1;
}
webServer.send(200, "text/plain", message);
}
webServer.send(200, "text/plain", "ok");
/**
* Generates a binary string password with NLEDS length
* Result is stored in global password variable
*/
void
generate_password()
{
unsigned int dec_password = random(1, pow(2, NLEDS)-1);
char tmp_password[] = "000000";
for (int i = NLEDS-1; i > 0; --i)
{
tmp_password[i] =(dec_password & 1) + '0';
dec_password >>= 1;
}
for (int i = 0; i < NLEDS; ++i)
{
if (tmp_password[i] == '1')
{
password.setCharAt(i, '1');
}
}
Serial.print("Password is: ");
Serial.println(password);
}
/**
@ -183,6 +310,8 @@ switch_led()
void
print_binary_string(String which)
{
Serial.print("Eu estou a imprimir esta string: ");
Serial.println(which);
for (int i = 0; i < NLEDS; ++i)
{
if (which.charAt(i) == '1')
@ -208,6 +337,14 @@ reset_game()
{
current_answer[i] = 0;
}
is_game_running = false;
token = 0;
generate_password();
// print password
print_binary_string(password);
}
/**
@ -216,18 +353,32 @@ reset_game()
void
won_game()
{
if (!is_game_running || token != webServer.arg("token").toInt())
{
webServer.send(200, "text/plain", "unauthorized");
return;
}
for (int i = 0; i < 3; ++i)
{
turn_all_off();
delay(500);
print_binary_string(current_answer);
for (int i = 0; i < NLEDS; ++i)
{
if (current_answer[i] == 1)
{
digitalWrite(bits[i], HIGH);
}
}
delay(500);
}
reset_game();
webServer.send(200, "text/plain", "ok");
}
/**
@ -252,7 +403,7 @@ setup()
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); // subnet FF FF FF 00
// You can remove/add the password parameter if you want the AP to be open/closed.
WiFi.softAP(ssid); //, password);
WiFi.softAP(ssid); //, wifi_password);
// if DNSServer is started with "*" for domain name, it will reply with
// provided IP to all DNS request
@ -269,16 +420,30 @@ setup()
webServer.on("/fwlink", handleRoot); // Microsoft captive portal.
webServer.on("/", handleRoot);
webServer.on("/auth", handleAuth);
webServer.on("/"+FORCERESTARENDPOINT,[]()
{
reset_game();
webServer.send(200, "text/plain",
"A caixa foi reiniciada com sucesso!");});
webServer.on("/game", handleGame);
webServer.on("/style.css", return_css);
webServer.on("/switch_state", switch_led);
webServer.on("/game/switch_state", switch_led);
webServer.on("/won", won_game);
webServer.on("/game/won", won_game);
webServer.onNotFound(handleNotFound);
//webServer.onNotFound(handleNotFound);
webServer.onNotFound(handleRoot);
// Start WebServer
webServer.begin();
Serial.println("HTTP server started");
/*** Start game ***/
generate_password();
// print password
print_binary_string(password);
}
/**