From 1c59afa216181d2cee2c188c3fdc957db34f7386 Mon Sep 17 00:00:00 2001 From: Diogo Cordeiro Date: Tue, 3 Apr 2018 09:13:42 +0000 Subject: [PATCH] Special MostraUP release: Add Authentication Translated interface to portuguese as this is a portuguese event --- INSTALL | 2 + README.md | 25 ++--- auth/index.html | 70 ++++++++++++ auth/script.js | 152 +++++++++++++++++++++++++ index.html => game/index.html | 10 +- script.js => game/script.js | 23 ++-- server/HTML.cpp | 82 ++++++++++++++ server/HTML.h | 18 +++ server/server.ino | 205 +++++++++++++++++++++++++++++----- 9 files changed, 533 insertions(+), 54 deletions(-) create mode 100644 auth/index.html create mode 100644 auth/script.js rename index.html => game/index.html (87%) rename script.js => game/script.js (97%) create mode 100644 server/HTML.cpp create mode 100644 server/HTML.h diff --git a/INSTALL b/INSTALL index a6d89cc..b45acff 100644 --- a/INSTALL +++ b/INSTALL @@ -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 in the index.html with the result inside the tags + 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 diff --git a/README.md b/README.md index 97e602d..57469f7 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/auth/index.html b/auth/index.html new file mode 100644 index 0000000..2af1ccf --- /dev/null +++ b/auth/index.html @@ -0,0 +1,70 @@ + + + + + + + + Fun with Binary + + + + + + + + + +
+

+ Já está alguém a jogar, espera pela tua vez! :) +

+
+ + +
+

+ Acende as lâmpadas conforme a caixa! :) +

+
+ + +
+
+ +
+ + + + + + + + + diff --git a/auth/script.js b/auth/script.js new file mode 100644 index 0000000..7f1ed2c --- /dev/null +++ b/auth/script.js @@ -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 . + * + * @category UI interaction + * @package Fun with Binary + * @author Diogo Cordeiro + * @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); +} diff --git a/index.html b/game/index.html similarity index 87% rename from index.html rename to game/index.html index 1460f18..6b10936 100644 --- a/index.html +++ b/game/index.html @@ -38,9 +38,9 @@ along with this program. If not, see .

- How do you represent the number + Como representas o número - in binary? + em binário?

@@ -48,7 +48,8 @@ along with this program. If not, see .
  • -

    Labels

    +

    Potências de 2

- diff --git a/script.js b/game/script.js similarity index 97% rename from script.js rename to game/script.js index d57f3a2..ab9416f 100644 --- a/script.js +++ b/game/script.js @@ -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; @@ -95,6 +98,9 @@ correct_answer = empty_answer; // current answer current_answer = empty_answer; +// Generate a token for this session +sessionStorage.token = Math.random().toString(36).substr(2, 15+2); + /** * Create leds */ @@ -214,9 +220,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 +339,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(); } diff --git a/server/HTML.cpp b/server/HTML.cpp new file mode 100644 index 0000000..c8cbb6d --- /dev/null +++ b/server/HTML.cpp @@ -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; +} diff --git a/server/HTML.h b/server/HTML.h new file mode 100644 index 0000000..cdaf9cf --- /dev/null +++ b/server/HTML.h @@ -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 diff --git a/server/server.ino b/server/server.ino index f7f40b1..20c44ac 100644 --- a/server/server.ino +++ b/server/server.ino @@ -28,7 +28,7 @@ #include // Pages -#include "file1.h" +#include "HTML.h" // Define a dns server for Captive Portal const byte DNS_PORT = 53; @@ -54,6 +54,18 @@ int bits[NLEDS] = { D0, D1, D2, D3, D4, D5 }; // 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 +98,33 @@ turn_all_off() void handleRoot() { - - webServer.send(200, "text/html", file1); + webServer.send(200, "text/html", + ""); } /** - * 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 +157,76 @@ 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(); + } + 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 +235,61 @@ handleInputError() void switch_led() { + if (!is_game_running || token != webServer.arg("token").toInt()) + { + webServer.send(200, "text/plain", "unauthorized"); + return; + } + int incomingByte = webServer.arg("led").toInt(); - // 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'); + } + } } /** @@ -208,6 +325,14 @@ reset_game() { current_answer[i] = 0; } + + is_game_running = false; + token = 0; + + generate_password(); + + // print password + print_binary_string(password); } /** @@ -216,18 +341,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"); } /** @@ -269,16 +408,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); } /**