mirror of
https://github.com/aljazceru/addons.git
synced 2025-12-18 21:54:20 +01:00
Upgrade web server for OAuth connection process [add-on: google_assistant] (#1267)
* Update pages styling and better error handling * Fix css * Offload static folder to /usr/share/public * Remove unnecessary os import * Add a changelog and update the version * Update google_assistant/config.json * Update google_assistant/CHANGELOG.md Co-authored-by: Pascal Vizeli <pascal.vizeli@syshack.ch>
This commit is contained in:
@@ -1,5 +1,10 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2.4.0
|
||||||
|
|
||||||
|
- Improve OAuth connection process UI
|
||||||
|
- Fix error 500 after submitting the OAuth token
|
||||||
|
|
||||||
## 2.3.2
|
## 2.3.2
|
||||||
|
|
||||||
- Update Google Assistant SDK back to 0.5.1
|
- Update Google Assistant SDK back to 0.5.1
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "Google Assistant SDK",
|
"name": "Google Assistant SDK",
|
||||||
"version": "2.3.2",
|
"version": "2.4.0",
|
||||||
"slug": "google_assistant",
|
"slug": "google_assistant",
|
||||||
"description": "A virtual personal assistant developed by Google",
|
"description": "A virtual personal assistant developed by Google",
|
||||||
"url": "https://github.com/home-assistant/hassio-addons/tree/master/google_assistant",
|
"url": "https://github.com/home-assistant/hassio-addons/tree/master/google_assistant",
|
||||||
|
|||||||
@@ -15,8 +15,7 @@ if bashio::fs.file_exists "/share/${CLIENT_SECRETS}"; then
|
|||||||
cp -f "/share/${CLIENT_SECRETS}" "${CLIENT_JSON}"
|
cp -f "/share/${CLIENT_SECRETS}" "${CLIENT_JSON}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! bashio::fs.file_exists "${CRED_JSON}" && bashio::fs.file_exists "${CLIENT_JSON}";
|
if ! bashio::fs.file_exists "${CRED_JSON}" && bashio::fs.file_exists "${CLIENT_JSON}"; then
|
||||||
then
|
|
||||||
bashio::log.info "Starting WebUI for handling OAuth2..."
|
bashio::log.info "Starting WebUI for handling OAuth2..."
|
||||||
python3 /usr/bin/hassio_oauth.py "${CLIENT_JSON}" "${CRED_JSON}"
|
python3 /usr/bin/hassio_oauth.py "${CLIENT_JSON}" "${CRED_JSON}"
|
||||||
elif ! bashio::fs.file_exists "${CRED_JSON}"; then
|
elif ! bashio::fs.file_exists "${CRED_JSON}"; then
|
||||||
|
|||||||
@@ -2,11 +2,18 @@
|
|||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
|
||||||
import cherrypy
|
import cherrypy
|
||||||
from requests_oauthlib import OAuth2Session
|
from requests_oauthlib import OAuth2Session
|
||||||
from google.oauth2.credentials import Credentials
|
from google.oauth2.credentials import Credentials
|
||||||
|
|
||||||
|
HEADERS = str("""
|
||||||
|
<link rel="icon" href="/static/favicon.ico?v=1">
|
||||||
|
<link href="/static/css/style.css" rel="stylesheet">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">
|
||||||
|
""")
|
||||||
|
|
||||||
class oauth2Site(object):
|
class oauth2Site(object):
|
||||||
"""Website for handling oauth2."""
|
"""Website for handling oauth2."""
|
||||||
@@ -28,22 +35,36 @@ class oauth2Site(object):
|
|||||||
def index(self):
|
def index(self):
|
||||||
"""Landing page."""
|
"""Landing page."""
|
||||||
return str("""<html>
|
return str("""<html>
|
||||||
<head></head>
|
<head>{headers}</head>
|
||||||
<body>
|
<body>
|
||||||
<p>
|
|
||||||
Get token from google: <a href="{url}" target="_blank">Authentication</a>
|
|
||||||
</p>
|
|
||||||
<form method="get" action="token">
|
<form method="get" action="token">
|
||||||
<input type="text" value="" name="token" />
|
<div class="card">
|
||||||
<button type="submit">Connect</button>
|
<div class="card-content">
|
||||||
|
<img src="/static/logo.png" alt="Google Assistant Logo" />
|
||||||
|
<h1>Google Assistant SDK</h1>
|
||||||
|
<p>Initial setup</p>
|
||||||
|
<ol>
|
||||||
|
<li><a href="{url}" target="_blank">Get a code from Google here</a></li>
|
||||||
|
<li><input type="text" value="" name="token" placeholder="Paste the code here" /></li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
<div class="card-actions">
|
||||||
|
<button type="submit">CONNECT</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</body>
|
</body>
|
||||||
</html>""").format(url=self.auth_url)
|
</html>""").format(url=self.auth_url, headers=HEADERS)
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
def token(self, token):
|
def token(self, token):
|
||||||
"""Read access token and process it."""
|
"""Read access token and process it."""
|
||||||
|
try:
|
||||||
self.oauth2.fetch_token(self.user_data['token_uri'], client_secret=self.user_data['client_secret'], code=token)
|
self.oauth2.fetch_token(self.user_data['token_uri'], client_secret=self.user_data['client_secret'], code=token)
|
||||||
|
except Exception as e:
|
||||||
|
cherrypy.log("Error with the given token: {error}".format(error=str(e)))
|
||||||
|
cherrypy.log("Restarting authentication process.")
|
||||||
|
raise cherrypy.HTTPRedirect('/')
|
||||||
|
|
||||||
# create credentials
|
# create credentials
|
||||||
credentials = Credentials(
|
credentials = Credentials(
|
||||||
@@ -65,8 +86,30 @@ class oauth2Site(object):
|
|||||||
'scopes': credentials.scopes,
|
'scopes': credentials.scopes,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
sys.exit(0)
|
threading.Thread(target=self.exit_app).start()
|
||||||
|
return str("""<html>
|
||||||
|
<head>{headers}</head>
|
||||||
|
<body>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-content">
|
||||||
|
<img src="/static/logo.png" alt="Google Assistant Logo" />
|
||||||
|
<h1>Google Assistant SDK</h1>
|
||||||
|
<p>Setup completed.</p>
|
||||||
|
<p>You can now close this window.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>""").format(url=self.auth_url, headers=HEADERS)
|
||||||
|
|
||||||
|
def exit_app(self):
|
||||||
|
time.sleep(2)
|
||||||
|
cherrypy.engine.exit()
|
||||||
|
|
||||||
|
def hide_access_logs():
|
||||||
|
"""Hide file access logging for cleaner logs"""
|
||||||
|
access_log = cherrypy.log.access_log
|
||||||
|
for handler in tuple(access_log.handlers):
|
||||||
|
access_log.removeHandler(handler)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
oauth_json = Path(sys.argv[1])
|
oauth_json = Path(sys.argv[1])
|
||||||
@@ -75,5 +118,11 @@ if __name__ == '__main__':
|
|||||||
with oauth_json.open('r') as data:
|
with oauth_json.open('r') as data:
|
||||||
user_data = json.load(data)['installed']
|
user_data = json.load(data)['installed']
|
||||||
|
|
||||||
|
hide_access_logs()
|
||||||
cherrypy.config.update({'server.socket_port': 9324, 'server.socket_host': '0.0.0.0'})
|
cherrypy.config.update({'server.socket_port': 9324, 'server.socket_host': '0.0.0.0'})
|
||||||
cherrypy.quickstart(oauth2Site(user_data, cred_json))
|
cherrypy.quickstart(oauth2Site(user_data, cred_json), config={
|
||||||
|
'/static': {
|
||||||
|
'tools.staticdir.on': True,
|
||||||
|
'tools.staticdir.dir': '/usr/share/public'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|||||||
97
google_assistant/rootfs/usr/share/public/css/style.css
Normal file
97
google_assistant/rootfs/usr/share/public/css/style.css
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
body {
|
||||||
|
font-family: 'Roboto', sans-serif;
|
||||||
|
background-color: #fafafa;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
|
||||||
|
background-color: #ffffff;
|
||||||
|
color: #212121;
|
||||||
|
border-radius: 2px;
|
||||||
|
margin: 15px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 400px;
|
||||||
|
max-width: 90vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card .card-content {
|
||||||
|
padding: 15px 25px;
|
||||||
|
border-bottom: 1px solid #bdbdbd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card .card-actions {
|
||||||
|
padding: 15px 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol {
|
||||||
|
margin: 28px 0 0 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol li {
|
||||||
|
counter-increment: step-counter;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol li::before {
|
||||||
|
content: counter(step-counter);
|
||||||
|
margin-right: 5px;
|
||||||
|
padding: 3px 8px;
|
||||||
|
border-radius: 9999px;
|
||||||
|
border: 1px solid #bdbdbd;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
border: none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
border-bottom: 1px solid black;
|
||||||
|
font-size: 14px;
|
||||||
|
flex-grow: 1;
|
||||||
|
height: 30px;
|
||||||
|
width: 100%;
|
||||||
|
background: transparent;
|
||||||
|
outline: none;
|
||||||
|
transition: border-bottom 0.225s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus {
|
||||||
|
border-bottom: 2px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 8px 10px;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
color: #03a9f4;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 4px;
|
||||||
|
outline: none;
|
||||||
|
transition: background-color 0.225s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background-color: #03a8f425;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:active {
|
||||||
|
background-color: #03a8f44f;
|
||||||
|
}
|
||||||
BIN
google_assistant/rootfs/usr/share/public/favicon.ico
Normal file
BIN
google_assistant/rootfs/usr/share/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
BIN
google_assistant/rootfs/usr/share/public/logo.png
Normal file
BIN
google_assistant/rootfs/usr/share/public/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
Reference in New Issue
Block a user