From c030be4d3f2ace3493fe98819eb85ada2c413c20 Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Fri, 24 Jul 2020 11:10:09 +0200 Subject: [PATCH] Fix dashboard logout button and py3.8 removed hmac.new digestmod (#1156) * Fix dashboard logout button and py3.8 removed hmac.new digestmod * Just use SHA256 No reason to use HMAC here, as authenticity is not an issue * Wrong branch * Clenaup --- esphome/dashboard/dashboard.py | 14 +++++++++----- esphome/dashboard/templates/index.html | 4 +++- esphome/dashboard/util.py | 9 +++++++++ 3 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 esphome/dashboard/util.py diff --git a/esphome/dashboard/dashboard.py b/esphome/dashboard/dashboard.py index 1b150e008d..c53c68b3a3 100644 --- a/esphome/dashboard/dashboard.py +++ b/esphome/dashboard/dashboard.py @@ -30,6 +30,7 @@ from esphome.helpers import mkdir_p, get_bool_env, run_system_command from esphome.storage_json import EsphomeStorageJSON, StorageJSON, \ esphome_storage_path, ext_storage_path, trash_storage_path from esphome.util import shlex_quote, get_serial_ports +from .util import password_hash # pylint: disable=unused-import, wrong-import-order from typing import Optional # noqa @@ -42,7 +43,7 @@ _LOGGER = logging.getLogger(__name__) class DashboardSettings: def __init__(self): self.config_dir = '' - self.password_digest = '' + self.password_hash = '' self.username = '' self.using_password = False self.on_hassio = False @@ -55,7 +56,7 @@ class DashboardSettings: self.username = args.username or os.getenv('USERNAME', '') self.using_password = bool(password) if self.using_password: - self.password_digest = hmac.new(password.encode()).digest() + self.password_hash = password_hash(password) self.config_dir = args.configuration[0] @property @@ -82,8 +83,11 @@ class DashboardSettings: if username != self.username: return False - password = hmac.new(password.encode()).digest() - return username == self.username and hmac.compare_digest(self.password_digest, password) + # Compare password in constant running time (to prevent timing attacks) + return hmac.compare_digest( + self.password_hash, + password_hash(password) + ) def rel_path(self, *args): return os.path.join(self.config_dir, *args) @@ -446,7 +450,7 @@ class MainRequestHandler(BaseHandler): entries = _list_dashboard_entries() self.render("templates/index.html", entries=entries, begin=begin, - **template_args()) + **template_args(), login_enabled=settings.using_auth) def _ping_func(filename, address): diff --git a/esphome/dashboard/templates/index.html b/esphome/dashboard/templates/index.html index 1e546b037f..fa742fd2c6 100644 --- a/esphome/dashboard/templates/index.html +++ b/esphome/dashboard/templates/index.html @@ -52,7 +52,9 @@
  • Update All
  • Secrets Editor
  • -
  • Logout
  • + {% if login_enabled %} +
  • Logout
  • + {% end %} diff --git a/esphome/dashboard/util.py b/esphome/dashboard/util.py new file mode 100644 index 0000000000..3e3864aa17 --- /dev/null +++ b/esphome/dashboard/util.py @@ -0,0 +1,9 @@ +import hashlib + + +def password_hash(password: str) -> bytes: + """Create a hash of a password to transform it to a fixed-length digest. + + Note this is not meant for secure storage, but for securely comparing passwords. + """ + return hashlib.sha256(password.encode()).digest()