-
Notifications
You must be signed in to change notification settings - Fork 2.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix rest api access when using script/develop_and_serve #23144
Fix rest api access when using script/develop_and_serve #23144
Conversation
You create a proxy, but it is never used? All the API calls are still done directly to the external HA instance and not to the proxy. You can test this easily with the config flows, as they use a REST API |
@ bramkragten ok, I have confirmed that to use /config/integrations/integration/hacs you also need to configure cors. I will eventually look into seeing if we can improve this, but for now I just documented that it needs to be done. Can you agree that this is sufficient for this change? (as before this change it was also a requirement) Note that the proxy stuff is still needed, as for example /hassio/backups uses a different way to access the api (through relative url's) and completely ignores the $hassUrl. |
@bramkragten ok, ignore my earlier comment. I thought it would a lot of work to get the login flow to work properly when everything would be proxied through the frontend dev instance. But it appears it was rather easy. There is no longer a requirement to configure cors now. |
I still don't see this addressed, the API calls are still done directly to the external host and not through the proxy. Check config flows (add integration, integration options), automation editor, script editor, scene editor, etc |
@bramkragten the change the fixes it is that we no longer override the HASS_URL when calling script/develop in script/develop_and_serve, all calls now go through the development frontend server. |
const coreProxy = createProxyMiddleware({ | ||
target: coreUrl, | ||
changeOrigin: true, | ||
ws: true, | ||
}); | ||
const app = express(); | ||
app.use("/", express.static(path.join(repoDir, "hass_frontend"))); | ||
app.use("/api/hassio/app", express.static(path.join(repoDir, "hassio/build"))); | ||
app.use("/api", coreProxy); | ||
app.get("/auth/authorize", (req, res) => { | ||
res.sendFile(path.join(repoDir, "hass_frontend/authorize.html")); | ||
}); | ||
app.use("/auth", coreProxy); | ||
app.get("/onboarding", (req, res) => { | ||
res.sendFile(path.join(repoDir, "hass_frontend/onboarding.html")); | ||
}); | ||
app.get("*", (req, res) => { | ||
res.sendFile(path.join(repoDir, "hass_frontend/index.html")); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const coreProxy = createProxyMiddleware({ | |
target: coreUrl, | |
changeOrigin: true, | |
ws: true, | |
}); | |
const app = express(); | |
app.use("/", express.static(path.join(repoDir, "hass_frontend"))); | |
app.use("/api/hassio/app", express.static(path.join(repoDir, "hassio/build"))); | |
app.use("/api", coreProxy); | |
app.get("/auth/authorize", (req, res) => { | |
res.sendFile(path.join(repoDir, "hass_frontend/authorize.html")); | |
}); | |
app.use("/auth", coreProxy); | |
app.get("/onboarding", (req, res) => { | |
res.sendFile(path.join(repoDir, "hass_frontend/onboarding.html")); | |
}); | |
app.get("*", (req, res) => { | |
res.sendFile(path.join(repoDir, "hass_frontend/index.html")); | |
}); | |
const indexHtml = fs.readFileSync(path.join(repoDir, "hass_frontend", "index.html"), "utf8") | |
.replace(/<\/body>/g, `<script> | |
const interval = setInterval(() => { | |
window.hassConnection.then(conn => { | |
conn.auth.data.hassUrl = "${coreUrl}"; | |
clearInterval(interval); | |
}); | |
}, 100); | |
</script> | |
</body>`); | |
const coreProxy = createProxyMiddleware({ | |
target: coreUrl, | |
changeOrigin: true, | |
ws: true, | |
}); | |
const app = express(); | |
app.get("/index.html", (req, res) => { | |
res.send(indexHtml); | |
}); | |
app.use(express.static(path.join(repoDir, "hass_frontend"))); | |
app.use(express.static(path.join(repoDir, "hass_frontend", "frontend_latest"))); | |
app.use("/api/hassio/app", express.static(path.join(repoDir, "hassio/build"))); | |
app.use("/api", coreProxy); | |
app.get("/auth/authorize", (req, res) => { | |
res.sendFile(path.join(repoDir, "hass_frontend/authorize.html")); | |
}); | |
app.use("/auth", coreProxy); | |
app.get("/onboarding", (req, res) => { | |
res.sendFile(path.join(repoDir, "hass_frontend/onboarding.html")); | |
}); | |
app.get("*", (req, res) => { | |
res.send(indexHtml); | |
}); |
This works but is very dirty. The problem is that the API url comes from the hassConnection.auth.data.hassUrl
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we have to change the index, we should do it inside the template with a flag, also, why does it use an interval?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interval was the quickest dirty solution to test & show what needs to happen as hassConnection
is not initialized when this script tag runs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MindFreeze why was this extension needed? it worked just fine with proxying everything?
We have done some more thinking and found a different way easier solution, setting allowed cors origins on the core instance 🙈 https://www.home-assistant.io/integrations/http/#cors_allowed_origins So this PR is no longer needed, we just need to document to set the above for |
@bramkragten I disagree that having a proxy for the connections is not a benefit., it is still required because not all functionality uses the value from the login session to determine which /api/ to contact. For example the System/ Backup functionality (which connects directly to /api/... relative paths. |
Setting CORS just works. A proxy is very complicated and very hacky. It's essentially a man in the middle attack. Also requires new dependancies |
@MindFreeze @bramkragten Does that mean that every part of the code that uses /api/... as a relative path is wrong and should be reworked to use hass.auth.data.hassUrl instead? I thought there was only one, but a quick search on /api in the code base shows quite some places where it's used relative instead. Some non obvious examples, loading custom panels and translations is done from relative path. Meaning that nothing of the hassio functionality works without fixing it. |
Breaking change
Proposed change
The script/develop_and_server only took into account UI components that connected through the websocket.
Now support has also been added for those that use the rest api.
Type of change
Example configuration
Tested through the System / Backup functionality
Additional information
Checklist
If user exposed functionality or configuration variables are added/changed: