Frontend password checking is now done in polymer
This commit is contained in:
parent
b9d0316903
commit
3bab3f4be1
6 changed files with 212 additions and 58 deletions
|
@ -4,7 +4,7 @@ cd homeassistant/components/http/www_static/polymer
|
||||||
bower install
|
bower install
|
||||||
cd ..
|
cd ..
|
||||||
cp polymer/bower_components/platform/platform.js polymer_platform.js
|
cp polymer/bower_components/platform/platform.js polymer_platform.js
|
||||||
vulcanize -o frontend.html --inline polymer/home-assistant-main.html
|
vulcanize -o frontend.html --inline polymer/splash-login.html
|
||||||
cd ..
|
cd ..
|
||||||
echo '""" DO NOT MODIFY. Auto-generated by build_polymer script """' > frontend.py
|
echo '""" DO NOT MODIFY. Auto-generated by build_polymer script """' > frontend.py
|
||||||
echo 'VERSION = "'`md5 -q www_static/frontend.html`'"' >> frontend.py
|
echo 'VERSION = "'`md5 -q www_static/frontend.html`'"' >> frontend.py
|
||||||
|
|
|
@ -301,10 +301,12 @@ class RequestHandler(SimpleHTTPRequestHandler):
|
||||||
# Did we find a handler for the incoming request?
|
# Did we find a handler for the incoming request?
|
||||||
if handle_request_method:
|
if handle_request_method:
|
||||||
|
|
||||||
# Do not enforce api password for static files
|
# For API calls we need a valid password
|
||||||
if handle_request_method == self._handle_get_static or \
|
if self.use_json and api_password != self.server.api_password:
|
||||||
self._verify_api_password(api_password):
|
self._message(
|
||||||
|
"API password missing or incorrect.", HTTP_UNAUTHORIZED)
|
||||||
|
|
||||||
|
else:
|
||||||
handle_request_method(path_match, data)
|
handle_request_method(path_match, data)
|
||||||
|
|
||||||
elif path_matched_but_not_method:
|
elif path_matched_but_not_method:
|
||||||
|
@ -333,44 +335,6 @@ class RequestHandler(SimpleHTTPRequestHandler):
|
||||||
""" DELETE request handler. """
|
""" DELETE request handler. """
|
||||||
self._handle_request('DELETE')
|
self._handle_request('DELETE')
|
||||||
|
|
||||||
def _verify_api_password(self, api_password):
|
|
||||||
""" Helper method to verify the API password
|
|
||||||
and take action if incorrect. """
|
|
||||||
if api_password == self.server.api_password:
|
|
||||||
return True
|
|
||||||
|
|
||||||
elif self.use_json:
|
|
||||||
self._message(
|
|
||||||
"API password missing or incorrect.", HTTP_UNAUTHORIZED)
|
|
||||||
|
|
||||||
else:
|
|
||||||
self.send_response(HTTP_OK)
|
|
||||||
self.send_header('Content-type', 'text/html')
|
|
||||||
self.end_headers()
|
|
||||||
|
|
||||||
self.wfile.write((
|
|
||||||
"<html>"
|
|
||||||
"<head><title>Home Assistant</title>"
|
|
||||||
"<link rel='shortcut icon' href='/static/favicon.ico' />"
|
|
||||||
"<link rel='icon' type='image/png' "
|
|
||||||
" href='/static/favicon-192x192.png' sizes='192x192'>"
|
|
||||||
"</head>"
|
|
||||||
"<body>"
|
|
||||||
"<div>"
|
|
||||||
"<form class='form-signin' action='{}' method='POST'>"
|
|
||||||
|
|
||||||
"<input type='text' name='api_password' "
|
|
||||||
" placeholder='API Password for Home Assistant' "
|
|
||||||
" required autofocus>"
|
|
||||||
|
|
||||||
"<button type='submit'>Enter</button>"
|
|
||||||
|
|
||||||
"</form>"
|
|
||||||
"</div>"
|
|
||||||
"</body></html>").format(self.path).encode("UTF-8"))
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
def _handle_get_root(self, path_match, data):
|
def _handle_get_root(self, path_match, data):
|
||||||
""" Renders the debug interface. """
|
""" Renders the debug interface. """
|
||||||
|
@ -382,7 +346,7 @@ class RequestHandler(SimpleHTTPRequestHandler):
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
|
|
||||||
if self.server.development:
|
if self.server.development:
|
||||||
app_url = "polymer/home-assistant-main.html"
|
app_url = "polymer/splash-login.html"
|
||||||
else:
|
else:
|
||||||
app_url = "frontend-{}.html".format(frontend.VERSION)
|
app_url = "frontend-{}.html".format(frontend.VERSION)
|
||||||
|
|
||||||
|
@ -400,8 +364,8 @@ class RequestHandler(SimpleHTTPRequestHandler):
|
||||||
" minimum-scale=1.0, maximum-scale=1.0' />"
|
" minimum-scale=1.0, maximum-scale=1.0' />"
|
||||||
"</head>"
|
"</head>"
|
||||||
"<body fullbleed>"
|
"<body fullbleed>"
|
||||||
"<home-assistant-main auth='{}'></home-assistant-main>"
|
"<splash-login auth='{}'></splash-login>"
|
||||||
"</body></html>").format(app_url, self.server.api_password))
|
"</body></html>").format(app_url, data.get('api_password', '')))
|
||||||
|
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
def _handle_get_api(self, path_match, data):
|
def _handle_get_api(self, path_match, data):
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
""" DO NOT MODIFY. Auto-generated by build_polymer script """
|
""" DO NOT MODIFY. Auto-generated by build_polymer script """
|
||||||
VERSION = "2242f67744e2c8bb92362bbd1489319f"
|
VERSION = "460fa7f075841b858b102678f13fb070"
|
||||||
|
|
|
@ -674,8 +674,8 @@ mode: cover
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</polymer-element>
|
</polymer-element>
|
||||||
</div>
|
|
||||||
<div hidden><!--
|
<!--
|
||||||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||||||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||||||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||||||
|
@ -869,8 +869,8 @@ polyfill-next-selector { content: ':host .indent'; }
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
<script>Polymer('core-toolbar');</script></polymer-element>
|
<script>Polymer('core-toolbar');</script></polymer-element>
|
||||||
</div>
|
|
||||||
<div hidden><!--
|
<!--
|
||||||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||||||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||||||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||||||
|
@ -2076,8 +2076,8 @@ core-icon {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</polymer-element>
|
</polymer-element>
|
||||||
</div>
|
|
||||||
<div hidden><!--
|
<!--
|
||||||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||||||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||||||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||||||
|
@ -3267,9 +3267,9 @@ root if there is one. This implies:
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</polymer-element>
|
</polymer-element>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div hidden>
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||||||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||||||
|
@ -9375,8 +9375,8 @@ core-item {
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</polymer-element>
|
</polymer-element>
|
||||||
</div>
|
|
||||||
<div hidden>
|
|
||||||
<script>//! moment.js
|
<script>//! moment.js
|
||||||
//! version : 2.8.3
|
//! version : 2.8.3
|
||||||
//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
|
//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
|
||||||
|
@ -12762,7 +12762,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</polymer-element>
|
</polymer-element>
|
||||||
</div>
|
|
||||||
|
|
||||||
<polymer-element name="home-assistant-main" attributes="auth" assetpath="polymer/">
|
<polymer-element name="home-assistant-main" attributes="auth" assetpath="polymer/">
|
||||||
<template>
|
<template>
|
||||||
|
@ -12845,3 +12845,98 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</polymer-element>
|
</polymer-element>
|
||||||
|
</div>
|
||||||
|
<div hidden>undefined</div>
|
||||||
|
<div hidden>undefined</div>
|
||||||
|
|
||||||
|
<polymer-element name="splash-login" attributes="auth" assetpath="polymer/">
|
||||||
|
<template>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
:host {
|
||||||
|
font-family: 'RobotoDraft', sans-serif;
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login paper-button {
|
||||||
|
margin-left: 242px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login .interact {
|
||||||
|
height: 110px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<template if="{{state == 'no_auth'}}">
|
||||||
|
<div layout="" horizontal="" center="" fit="" class="login">
|
||||||
|
<div layout="" vertical="" center="" flex="">
|
||||||
|
<img src="/static/favicon-192x192.png">
|
||||||
|
<h1>Home Assistant</h1>
|
||||||
|
|
||||||
|
<div class="interact" layout="" vertical="">
|
||||||
|
<div id="loginform">
|
||||||
|
<paper-input id="passwordInput" label="Password" type="password" value="{{auth}}"></paper-input>
|
||||||
|
<paper-button on-click="{{validatePassword}}">Log In</paper-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="validateMessage" hidden>Validating password...</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template if="{{state == 'valid_auth'}}">
|
||||||
|
<home-assistant-main auth="{{auth}}"></home-assistant-main>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
Polymer('splash-login',{
|
||||||
|
|
||||||
|
// can be no_auth, test_auth, valid_auth
|
||||||
|
state: "no_auth",
|
||||||
|
auth: "",
|
||||||
|
|
||||||
|
ready: function() {
|
||||||
|
},
|
||||||
|
|
||||||
|
domReady: function() {
|
||||||
|
if(this.auth) {
|
||||||
|
this.validatePassword();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
validatePassword: function() {
|
||||||
|
this.$.passwordInput.commit();
|
||||||
|
this.$.loginform.setAttribute('hidden', null)
|
||||||
|
this.$.validateMessage.removeAttribute('hidden')
|
||||||
|
|
||||||
|
var req = new XMLHttpRequest();
|
||||||
|
req.open("GET", "/api/", true);
|
||||||
|
req.setRequestHeader("HA-access", this.auth);
|
||||||
|
|
||||||
|
req.onreadystatechange = function() {
|
||||||
|
if(req.readyState == 4) {
|
||||||
|
if(req.status == 200) {
|
||||||
|
this.state = 'valid_auth'
|
||||||
|
} else {
|
||||||
|
this.auth = "";
|
||||||
|
|
||||||
|
this.$.passwordInput.error = "Invalid Password";
|
||||||
|
this.$.passwordInput.required = 1;
|
||||||
|
|
||||||
|
this.$.loginform.removeAttribute('hidden');
|
||||||
|
this.$.validateMessage.setAttribute('hidden', null);
|
||||||
|
|
||||||
|
this.state = 'no_auth'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.bind(this)
|
||||||
|
|
||||||
|
req.send();
|
||||||
|
},
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</polymer-element>
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
<link rel="import" href="bower_components/font-roboto/roboto.html">
|
|
||||||
<link rel="import" href="bower_components/core-header-panel/core-header-panel.html">
|
<link rel="import" href="bower_components/core-header-panel/core-header-panel.html">
|
||||||
<link rel="import" href="bower_components/core-toolbar/core-toolbar.html">
|
<link rel="import" href="bower_components/core-toolbar/core-toolbar.html">
|
||||||
<link rel="import" href="bower_components/core-icon-button/core-icon-button.html">
|
<link rel="import" href="bower_components/core-icon-button/core-icon-button.html">
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
<link rel="import" href="bower_components/font-roboto/roboto.html">
|
||||||
|
<link rel="import" href="home-assistant-main.html">
|
||||||
|
<link rel="import" href="bower_components/paper-button/paper-button.html">
|
||||||
|
<link rel="import" href="bower_components/paper-input/paper-input.html">
|
||||||
|
|
||||||
|
<polymer-element name="splash-login" attributes="auth">
|
||||||
|
<template>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
:host {
|
||||||
|
font-family: 'RobotoDraft', sans-serif;
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login paper-button {
|
||||||
|
margin-left: 242px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login .interact {
|
||||||
|
height: 110px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<template if="{{state == 'no_auth'}}">
|
||||||
|
<div layout horizontal center fit class='login'>
|
||||||
|
<div layout vertical center flex>
|
||||||
|
<img src="/static/favicon-192x192.png" />
|
||||||
|
<h1>Home Assistant</h1>
|
||||||
|
|
||||||
|
<div class='interact' layout vertical>
|
||||||
|
<div id='loginform'>
|
||||||
|
<paper-input id="passwordInput" label="Password" type="password" value="{{auth}}"></paper-input>
|
||||||
|
<paper-button on-click={{validatePassword}}>Log In</paper-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="validateMessage" hidden>Validating password...</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template if="{{state == 'valid_auth'}}">
|
||||||
|
<home-assistant-main auth="{{auth}}"></home-assistant-main>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
Polymer({
|
||||||
|
|
||||||
|
// can be no_auth, test_auth, valid_auth
|
||||||
|
state: "no_auth",
|
||||||
|
auth: "",
|
||||||
|
|
||||||
|
ready: function() {
|
||||||
|
},
|
||||||
|
|
||||||
|
domReady: function() {
|
||||||
|
if(this.auth) {
|
||||||
|
this.validatePassword();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
validatePassword: function() {
|
||||||
|
this.$.passwordInput.commit();
|
||||||
|
this.$.loginform.setAttribute('hidden', null)
|
||||||
|
this.$.validateMessage.removeAttribute('hidden')
|
||||||
|
|
||||||
|
var req = new XMLHttpRequest();
|
||||||
|
req.open("GET", "/api/", true);
|
||||||
|
req.setRequestHeader("HA-access", this.auth);
|
||||||
|
|
||||||
|
req.onreadystatechange = function() {
|
||||||
|
if(req.readyState == 4) {
|
||||||
|
if(req.status == 200) {
|
||||||
|
this.state = 'valid_auth'
|
||||||
|
} else {
|
||||||
|
this.auth = "";
|
||||||
|
|
||||||
|
this.$.passwordInput.error = "Invalid Password";
|
||||||
|
this.$.passwordInput.required = 1;
|
||||||
|
|
||||||
|
this.$.loginform.removeAttribute('hidden');
|
||||||
|
this.$.validateMessage.setAttribute('hidden', null);
|
||||||
|
|
||||||
|
this.state = 'no_auth'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.bind(this)
|
||||||
|
|
||||||
|
req.send();
|
||||||
|
},
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</polymer-element>
|
Loading…
Add table
Add a link
Reference in a new issue