Frontend password checking is now done in polymer

This commit is contained in:
Paulus Schoutsen 2014-10-28 00:38:25 -07:00
parent b9d0316903
commit 3bab3f4be1
6 changed files with 212 additions and 58 deletions

View file

@ -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

View file

@ -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):

View file

@ -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"

View file

@ -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>

View file

@ -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">

View file

@ -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>