Fix paths and URLs generated by API, and add note about config for proxying

This commit is contained in:
Paul Bienkowski 2021-11-27 22:40:06 +01:00
parent 9a13631097
commit 8dec4c8262
3 changed files with 68 additions and 10 deletions

View file

@ -8,7 +8,12 @@ from os.path import dirname, join, normpath, abspath, exists, isfile
from datetime import datetime, date
from sanic import Sanic, Blueprint
from sanic.response import text, json as json_response, file as file_response
from sanic.response import (
text,
json as json_response,
file as file_response,
html as html_response,
)
from sanic.exceptions import Unauthorized, NotFound
from sanic_session import Session, InMemorySessionInterface
@ -96,6 +101,43 @@ async def app_disconnect_db(app, loop):
await app.ctx._db_engine_ctx.__aexit__(None, None, None)
def remove_right(l, r):
if l.endswith(r):
return l[: -len(r)]
return l
@app.middleware("request")
async def inject_urls(req):
if req.app.config.FRONTEND_HTTPS:
req.ctx.frontend_scheme = "https"
elif req.app.config.FRONTEND_URL:
req.ctx.frontend_scheme = (
"http" if req.app.config.FRONTEND_URL.startswith("http://") else "https"
)
else:
req.ctx.frontend_scheme = req.scheme
req.ctx.api_scheme = req.ctx.frontend_scheme # just use the same for now
req.ctx.api_base_path = remove_right(req.server_path, req.path)
req.ctx.api_url = f"{req.ctx.frontend_scheme}://{req.host}{req.ctx.api_base_path}"
if req.app.config.FRONTEND_URL:
req.ctx.frontend_base_path = "/" + urlparse(
req.app.config.FRONTEND_URL
).path.strip("/")
req.ctx.frontend_url = req.app.config.FRONTEND_URL.rstrip("/")
elif app.config.FRONTEND_DIR:
req.ctx.frontend_base_path = req.ctx.api_base_path
req.ctx.frontend_url = req.ctx.api_url
else:
req.ctx.frontend_base_path = "/"
req.ctx.frontend_url = (
f"{req.ctx.frontend_scheme}://{req.host}{req.ctx.frontend_base_path}"
)
@app.middleware("request")
async def inject_session(req):
req.ctx._session_ctx = make_session()
@ -156,16 +198,16 @@ if INDEX_HTML and exists(INDEX_HTML):
@app.get("/config.json")
def get_frontend_config(req):
base_path = req.server_path.replace("config.json", "")
scheme = "https" if req.app.config.FRONTEND_HTTPS else req.scheme
result = {
"basename": req.ctx.frontend_base_path,
**req.app.config.FRONTEND_CONFIG,
"apiUrl": f"{scheme}://{req.host}{base_path}api",
"loginUrl": f"{scheme}://{req.host}{base_path}login",
"apiUrl": f"{req.ctx.api_url}/api",
"loginUrl": f"{req.ctx.api_url}/login",
"obsMapSource": {
"type": "vector",
"tiles": [
req.app.url_for("tiles", zoom="000", x="111", y="222.pbf")
req.ctx.api_url
+ req.app.url_for("tiles", zoom="000", x="111", y="222.pbf")
.replace("000", "{z}")
.replace("111", "{x}")
.replace("222", "{y}")
@ -177,14 +219,21 @@ if INDEX_HTML and exists(INDEX_HTML):
return json_response(result)
with open(INDEX_HTML, "rt") as f:
index_file_contents = f.read()
@app.get("/<path:path>")
def get_frontend_static(req, path):
print("++++++++++++++++++++++++++++++++++++++++++++++++", path)
if path.startswith("api/"):
raise NotFound()
file = join(app.config.FRONTEND_DIR, path)
if not exists(file) or not path or not isfile(file):
file = INDEX_HTML
return html_response(
index_file_contents.replace("__BASE_HREF__", req.ctx.frontend_url + "/")
)
return file_response(file)

View file

@ -38,13 +38,12 @@ async def login(req, next: str = None):
session["state"] = rndstr()
session["nonce"] = rndstr()
session["next"] = next
scheme = 'https' if req.app.config.FRONTEND_HTTPS else req.scheme
args = {
"client_id": client.client_id,
"response_type": "code",
"scope": ["openid"],
"nonce": session["nonce"],
"redirect_uri": scheme + "://" + req.host + "/login/redirect",
"redirect_uri": req.ctx.frontend_url + "/login/redirect",
"state": session["state"],
}
@ -81,7 +80,9 @@ async def login_redirect(req):
email = userinfo.get("email")
if email is None:
raise ValueError("user has no email set, please configure keycloak to require emails")
raise ValueError(
"user has no email set, please configure keycloak to require emails"
)
user = (await req.ctx.db.execute(select(User).where(User.sub == sub))).scalar()

View file

@ -78,6 +78,14 @@ Then edit `config/config.py` to your heart's content (and matching the
configuration of the keycloak). Do not forget to generate a secure secret
string.
Also set `PROXIES_COUNT = 1` in your config, even if that option is not
included in the example file. Read the [sanic
docs](https://sanic.readthedocs.io/en/v20.12.3/sanic/config.html) for why this
needs to be done. If your reverse proxy supports it, you can also use a
forwarded secret to secure your proxy target from spoofing. This is not
required if your application server does not listen on a public interface, but
it is recommended anyway, if possible.
### Build container and run them
```bash