diff --git a/relay/application.py b/relay/application.py index cd8f89a..aba9bc7 100644 --- a/relay/application.py +++ b/relay/application.py @@ -44,7 +44,8 @@ def get_csp(request: web.Request) -> str: "connect-src 'self'", "img-src 'self'", "object-src 'none'", - "frame-ancestors 'none'" + "frame-ancestors 'none'", + f"manifest-src 'self' https://{request.app.config.domain}" ] return '; '.join(data) + ';' diff --git a/relay/frontend/base.haml b/relay/frontend/base.haml index d58c98b..7b366ab 100644 --- a/relay/frontend/base.haml +++ b/relay/frontend/base.haml @@ -13,6 +13,7 @@ %meta(name="viewport" content="width=device-width, initial-scale=1") %link(rel="stylesheet" type="text/css" href="/theme/{{config.theme}}.css" nonce="{{view.request['hash']}}" class="theme") %link(rel="stylesheet" type="text/css" href="/static/style.css" nonce="{{view.request['hash']}}") + %link(rel="manifest" href="/manifest.json") %script(type="application/javascript" src="/static/api.js" nonce="{{view.request['hash']}}", defer) -block head diff --git a/relay/misc.py b/relay/misc.py index 5af6e60..ae18b2d 100644 --- a/relay/misc.py +++ b/relay/misc.py @@ -38,7 +38,8 @@ MIMETYPES = { 'css': 'text/css', 'html': 'text/html', 'json': 'application/json', - 'text': 'text/plain' + 'text': 'text/plain', + 'webmanifest': 'application/manifest+json' } NODEINFO_NS = { diff --git a/relay/views/frontend.py b/relay/views/frontend.py index ae1043a..4aed045 100644 --- a/relay/views/frontend.py +++ b/relay/views/frontend.py @@ -210,11 +210,27 @@ class AdminConfig(View): return Response.new(data, ctype = 'html') -@register_route('/style.css') -class StyleCss(View): +@register_route('/manifest.json') +class ManifestJson(View): async def get(self, request: Request) -> Response: - data = self.template.render('style.css', self) - return Response.new(data, ctype = 'css') + with self.database.session(False) as conn: + config = conn.get_config_all() + theme = THEMES[config.theme] + + data = { + 'background_color': theme['background'], + 'categories': ['activitypub'], + 'description': 'Message relay for the ActivityPub network', + 'display': 'standalone', + 'name': config['name'], + 'orientation': 'portrait', + 'scope': f"https://{self.config.domain}/", + 'short_name': 'ActivityRelay', + 'start_url': f"https://{self.config.domain}/", + 'theme_color': theme['primary'] + } + + return Response.new(data, ctype = 'webmanifest') @register_route('/theme/{theme}.css')