diff --git a/code/data/index.html.gz b/code/data/index.html.gz index ecad9c84..d879c641 100644 Binary files a/code/data/index.html.gz and b/code/data/index.html.gz differ diff --git a/code/data/password.html.gz b/code/data/password.html.gz new file mode 100644 index 00000000..2bb3023e Binary files /dev/null and b/code/data/password.html.gz differ diff --git a/code/data/script.js.gz b/code/data/script.js.gz new file mode 100644 index 00000000..df838103 Binary files /dev/null and b/code/data/script.js.gz differ diff --git a/code/data/style.css.gz b/code/data/style.css.gz new file mode 100644 index 00000000..1ed7c596 Binary files /dev/null and b/code/data/style.css.gz differ diff --git a/code/gulpfile.js b/code/gulpfile.js index 58ca9ee9..ce6a8134 100644 --- a/code/gulpfile.js +++ b/code/gulpfile.js @@ -2,7 +2,7 @@ ESP8266 file system builder -Copyright (C) 2016 by Xose Pérez +Copyright (C) 2016 by Xose PĆ©rez This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,11 +24,14 @@ along with this program. If not, see . // ----------------------------------------------------------------------------- const gulp = require('gulp'); +const plumber = require('gulp-plumber'); const htmlmin = require('gulp-htmlmin'); const cleancss = require('gulp-clean-css'); const uglify = require('gulp-uglify'); const gzip = require('gulp-gzip'); const del = require('del'); +const useref = require('gulp-useref'); +const gulpif = require('gulp-if'); const inline = require('gulp-inline'); /* Clean destination folder */ @@ -66,6 +69,24 @@ gulp.task('inline', function() { .pipe(gulp.dest('data')); }) +/* Process HTML, CSS, JS */ +gulp.task('html', function() { + return gulp.src('html/*.html') + .pipe(useref()) + .pipe(plumber()) + .pipe(gulpif('*.css', cleancss())) + .pipe(gulpif('*.js', uglify())) + .pipe(gulpif('*.html', htmlmin({ + collapseWhitespace: true, + removeComments: true, + minifyCSS: true, + minifyJS: true + }))) + .pipe(gzip()) + .pipe(gulp.dest('data')); +}); + /* Build file system */ -gulp.task('buildfs', ['clean', 'files', 'inline']); -gulp.task('default', ['buildfs']); +gulp.task('buildfs_split', ['clean', 'files', 'html']); +gulp.task('buildfs_inline', ['clean', 'files', 'inline']); +gulp.task('default', ['buildfs_inline']); diff --git a/code/html/custom.js b/code/html/custom.js index 5d6ef086..8b80db50 100644 --- a/code/html/custom.js +++ b/code/html/custom.js @@ -1,4 +1,5 @@ var websock; +var password = false; function doUpdate() { var data = $("#formSave").serializeArray(); @@ -87,8 +88,11 @@ function processData(data) { // title if ("app" in data) { - $(".pure-menu-heading").html(data.app); var title = data.app; + if ("version" in data) { + title = title + " " + data.version; + } + $(".pure-menu-heading").html(title); if ("hostname" in data) { title = data.hostname + " - " + title; } @@ -97,6 +101,35 @@ function processData(data) { Object.keys(data).forEach(function(key) { + // Actions + if (key == "action") { + + if (data.action == "reload") { + if (password) { + + // Forget current authentication + $.ajax({ + 'method': 'GET', + 'url': '/', + 'async': false, + 'username': "logmeout", + 'password': "123456", + 'headers': { "Authorization": "Basic xxx" } + }).done(function(data) { + // If we don't get an error, we actually got an error as we expect an 401! + }).fail(function(){ + // We expect to get an 401 Unauthorized error! In this case we are successfully + // logged out and we redirect the user. + window.location = "/"; + }); + + } + } + + return; + + } + // Wifi if (key == "wifi") { var groups = $("#panel-wifi .pure-g"); diff --git a/code/html/index.html b/code/html/index.html index 71524dbf..c4606df0 100644 --- a/code/html/index.html +++ b/code/html/index.html @@ -40,6 +40,10 @@ GENERAL +
  • + SECURITY +
  • +
  • WIFI
  • @@ -196,16 +200,36 @@
    Define how the different relays should be synchronized.
    +
    +
    +
    +
    + + + + + +
    + +
    +

    SECURITY

    +

    Device security settings

    +
    + +
    + +
    +
    - - + +
     
    The administrator password is used to access this web interface (user 'admin'), but also to connect to the device when in AP mode or to flash a new firmware over-the-air (OTA).
    -
    -
    -
    +
    + +
    diff --git a/code/html/password.html b/code/html/password.html new file mode 100644 index 00000000..ebb35459 --- /dev/null +++ b/code/html/password.html @@ -0,0 +1,72 @@ + + + + + ESPurna 0.0.0 + + + + + + + + + + + + + + + + +
    + +
    + +
    + +
    + +
    +

    SECURITY

    +

    Before using this device you have to change the default password for the user 'admin'. This password will be used for the AP mode hotspot, the web interface (where you are now) and the over-the-air updates.

    +
    + +
    + +
    + +
    + + +
    + +
    + + +
    + + + +
    +
    +
    + +
    + +
    + +
    + + + + + + + + + + + diff --git a/code/package.json b/code/package.json index 6ce9b531..2e8bff34 100644 --- a/code/package.json +++ b/code/package.json @@ -11,8 +11,11 @@ "gulp-clean-css": "^2.0.10", "gulp-gzip": "^1.4.0", "gulp-htmlmin": "^2.0.0", + "gulp-if": "^2.0.1", "gulp-inline": "^0.1.1", - "gulp-uglify": "^1.5.3" + "gulp-plumber": "^1.1.0", + "gulp-uglify": "^1.5.3", + "gulp-useref": "^3.1.2" }, "dependencies": {} } diff --git a/code/pio_hooks.py b/code/pio_hooks.py index 9a3f7fec..7abf6075 100644 --- a/code/pio_hooks.py +++ b/code/pio_hooks.py @@ -13,7 +13,7 @@ def is_valid_ip(ip): return False def before_build_spiffs(source, target, env): - env.Execute("gulp buildfs") + env.Execute("gulp buildfs_split") def before_upload(source, target, env): upload_port = env.get('UPLOAD_PORT', False) diff --git a/code/src/web.ino b/code/src/web.ino index 36a88046..43caeced 100644 --- a/code/src/web.ino +++ b/code/src/web.ino @@ -94,6 +94,7 @@ void _wsParse(uint32_t client_id, uint8_t * payload, size_t length) { bool fauxmoEnabled = false; #endif unsigned int network = 0; + String adminPass; for (unsigned int i=0; irequestAuthentication(); - request->send(SPIFFS, "/index.html"); + String password = getSetting("adminPass", ADMIN_PASS); + if (password.equals(ADMIN_PASS)) { + request->send(SPIFFS, "/password.html"); + } else { + request->send(SPIFFS, "/index.html"); + } + } bool _apiAuth(AsyncWebServerRequest *request) {