diff --git a/app/main.py b/app/main.py index fd8bb8e..63f740b 100644 --- a/app/main.py +++ b/app/main.py @@ -71,6 +71,7 @@ from app.templates import is_current_user_admin from app.uploads import UPLOAD_DIR from app.utils import pagination from app.utils.emoji import EMOJIS_BY_NAME +from app.utils.highlight import HIGHLIGHT_CSS_HASH from app.utils.url import check_url from app.webfinger import get_remote_follow_template @@ -133,9 +134,10 @@ class CustomMiddleware: headers["x-xss-protection"] = "1; mode=block" headers["x-frame-options"] = "SAMEORIGIN" # TODO(ts): disallow inline CSS? - headers[ - "content-security-policy" - ] = "default-src 'self'; style-src 'self' 'unsafe-inline';" + headers["content-security-policy"] = ( + f"default-src 'self'; " + f"style-src 'self' 'sha256-{HIGHLIGHT_CSS_HASH}';" + ) if not DEBUG: headers["strict-transport-security"] = "max-age=63072000;" diff --git a/app/scss/main.scss b/app/scss/main.scss index 7894af4..760ed7c 100644 --- a/app/scss/main.scss +++ b/app/scss/main.scss @@ -17,6 +17,36 @@ $code-highlight-background: #f0f0f0; color: $primary-color; } +#admin { + .admin-menu { + margin-bottom: 30px; + padding: 0 20px; + } +} + +.empty-state { + padding: 20px; +} + +.public-top-menu { + margin: 30px 0 0 0; +} + +.width-95 { + width: 95%; +} + +.bold { + font-weight: bold; +} + +.admin-new { + textarea { + font-size: 1.2em; + width: 95%; + } +} + .show-more-wrapper { .p-summary { display: inline-block; @@ -65,13 +95,6 @@ blockquote { color: $muted-color; } -.poll-bar { - width:100%;height:20px; - line { - stroke: $secondary-color; - } -} - .light-background { background: $light-background; } @@ -240,6 +263,9 @@ footer { padding: 0 20px; li { display: block; + span { + padding-right:10px; + } } } @@ -274,6 +300,57 @@ footer { margin: 20px 0; } +.show-hide-sensitive-btn { + display:inline-block; +} + +.no-margin-top { + margin-top: 0; +} + +.float-right { + float: right; +} + +ul.poll-items { + list-style-type: none; + padding: 0; + li { + display: block; + p { + margin: 20px 0 10px 0; + .poll-vote { + padding-left: 20px; + } + } + + .poll-bar { + width:100%;height:20px; + line { + stroke: $secondary-color; + stroke-width: 20px; + } + } + + } +} + +.attachment-wrapper { + .attachment-item { + margin-top: 20px; + } + img.attachment { + margin: 0; + } + a.attachment { + display: inline-block; + margin-bottom: 15px; + } + audio.attachment { + width: 480px; + } +} + nav { form { margin: 15px 0; @@ -334,7 +411,7 @@ nav.flexbox { } } .activity-attachment { - margin: 30px 0; + margin: 30px 0 20px 0; img, audio, video { width: 100%; max-width: 740px; @@ -345,6 +422,20 @@ nav.flexbox { max-width: 740px; } } + +.activity-og-meta { + display: flex; + column-gap: 20px; + margin: 20px 0; + img { + max-width: 200px; + max-height: 100px; + } + small { + display: block; + } +} + .ap-object-expanded { border: 2px dashed $secondary-color; } @@ -367,3 +458,54 @@ nav.flexbox { .emoji, .custom-emoji { max-width: 25px; } + +.indieauth-box { + display: flex; + column-gap: 20px; + + .indieauth-logo { + flex: initial; + width: 100px; + img { + max-width: 100px; + } + } + .indieauth-details { + flex: 1; + div { + padding-left: 20px; + a { + font-size: 1.2em; + font-weight: 600; + } + } + } +} + +.public-interactions { + display: flex; + column-gap: 20px; + flex-wrap: wrap; + margin-top: 20px; + .interactions-block { + flex: 0 1 30%; + max-width: 50%; + .facepile-wrapper { + display: flex; + column-gap: 20px; + row-gap: 20px; + flex-wrap: wrap; + margin-top: 20px; + a { + height: 50px; + img { + max-width: 50px; + } + } + .and-x-more { + display: inline-block; + align-self: center; + } + } + } +} diff --git a/app/templates/admin_new.html b/app/templates/admin_new.html index f86425a..2169a77 100644 --- a/app/templates/admin_new.html +++ b/app/templates/admin_new.html @@ -25,7 +25,7 @@ -
+ {{ utils.embed_csrf_token() }} {{ utils.embed_redirect_url() }}

@@ -38,7 +38,7 @@ {% if request.query_params.type == "Article" %}

- +

{% endif %} @@ -49,7 +49,7 @@ {{ emoji.name }} {% endfor %} - + {% if request.query_params.type == "Question" %}

@@ -69,20 +69,20 @@

{% for i in ["1", "2", "3", "4"] %}

- +

{% endfor %} {% endif %}

- +

- +

diff --git a/app/templates/articles.html b/app/templates/articles.html index 3eeb5ee..e8d5514 100644 --- a/app/templates/articles.html +++ b/app/templates/articles.html @@ -12,7 +12,7 @@ {% for outbox_object in objects %}

  • - {{ outbox_object.ap_published_at.strftime("%b %d, %Y") }} {{ outbox_object.name }} + {{ outbox_object.ap_published_at.strftime("%b %d, %Y") }} {{ outbox_object.name }}
  • {% endfor %} diff --git a/app/templates/header.html b/app/templates/header.html index db236e5..1fe7d98 100644 --- a/app/templates/header.html +++ b/app/templates/header.html @@ -29,7 +29,7 @@ {{ text }} {% endmacro %} -
    +
    {% else %} -
    +

    Nothing to see here yet!

    {% endif %} diff --git a/app/templates/indieauth_flow.html b/app/templates/indieauth_flow.html index 819ee45..7a61562 100644 --- a/app/templates/indieauth_flow.html +++ b/app/templates/indieauth_flow.html @@ -2,15 +2,15 @@ {% extends "layout.html" %} {% block content %}
    -
    +
    {% if client.logo %} -
    - {{ client.name }} logo + {% endif %} -
    -
    - {{ client.name }} +
    +
    + {{ client.name }}

    wants you to login as {{ me }} with the following redirect URI: {{ redirect_uri }}.

    diff --git a/app/templates/layout.html b/app/templates/layout.html index 380e588..c0c45f2 100644 --- a/app/templates/layout.html +++ b/app/templates/layout.html @@ -9,9 +9,7 @@ - + {% block head %}{% endblock %} @@ -23,7 +21,7 @@ {% set url_for = request.app.router.url_path_for(url) %} {{ text }} {% endmacro %} -
    +
    {{ utils.display_object(notif.outbox_object) }} {% elif notif.notification_type.value == "updated_webmention" %} @@ -68,7 +68,7 @@ {% if facepile_item %} {{ facepile_item.actor_name }} {% endif %} - {{ notif.webmention.source }} + {{ notif.webmention.source }}
    {{ utils.display_object(notif.outbox_object) }} {% elif notif.notification_type.value == "deleted_webmention" %} @@ -78,7 +78,7 @@ {% if facepile_item %} {{ facepile_item.actor_name }} {% endif %} - {{ notif.webmention.source }} + {{ notif.webmention.source }}
    {{ utils.display_object(notif.outbox_object) }} {% else %} diff --git a/app/templates/utils.html b/app/templates/utils.html index 085aa22..f017bca 100644 --- a/app/templates/utils.html +++ b/app/templates/utils.html @@ -206,7 +206,7 @@
    {{ actor.display_name }}'s avatar
    - +
    {{ actor.display_name | clean_html(actor) | safe }}
    {{ actor.handle }}
    @@ -292,16 +292,16 @@ {% macro display_og_meta(object) %} {% if object.og_meta %} {% for og_meta in object.og_meta %} -
    +
    {% if og_meta.image %}
    - +
    {% endif %}
    {{ og_meta.title }} {% if og_meta.site_name %} - {{ og_meta.site_name }} + {{ og_meta.site_name }} {% endif %}
    @@ -314,27 +314,27 @@ {% for attachment in object.attachments %} {% if object.sensitive and (attachment.type == "Image" or (attachment | has_media_type("image")) or attachment.type == "Video" or (attachment | has_media_type("video"))) %} -
    - +
    +
    {% else %} -
    +
    {% endif %} {% if attachment.type == "Image" or (attachment | has_media_type("image")) %} {% if attachment.url not in object.inlined_images %} - {{ attachment.name }} + {{ attachment.name }} {% endif %} {% elif attachment.type == "Video" or (attachment | has_media_type("video")) %} {% elif attachment.type == "Audio" or (attachment | has_media_type("audio")) %} - + {% elif attachment.type == "Link" %} - {{ attachment.url }} + {{ attachment.url }} {% else %} {{ attachment.url }} {% endif %} @@ -371,7 +371,7 @@ {% endif %} {% if object.ap_type == "Article" %} -

    {{ object.name }}

    +

    {{ object.name }}

    {% endif %} {% if is_article_mode %} @@ -401,11 +401,11 @@ {% endif %} {% if object.poll_items %} -
      +
        {% for item in object.poll_items %} -
      • +
      • {% set pct = item | poll_item_pct(object.poll_voters_count) %} -

        +

        {% if can_vote %} {% endif %} - {{ pct }}% ({{ item.replies.totalItems }} votes) + {{ pct }}% ({{ item.replies.totalItems }} votes)

        - +
      • {% endfor %} @@ -447,7 +447,7 @@
    {% endif %} -
    +
    {{ display_attachments(object) }}
    @@ -575,17 +575,17 @@ {% if likes or shares or webmentions %} -
    +
    {% if likes %} -
    Likes -
    +
    Likes +
    {% for like in likes %} - - {{ like.actor.handle}} + + {{ like.actor.handle}} {% endfor %} {% if object.likes_count > likes | length %} -
    +
    and {{ object.likes_count - likes | length }} more.
    {% endif %} @@ -594,15 +594,15 @@ {% endif %} {% if shares %} -
    Shares -
    +
    Shares +
    {% for share in shares %} - - {{ share.actor.handle}} + + {{ share.actor.handle}} {% endfor %} {% if object.announces_count > shares | length %} -
    +
    and {{ object.announces_count - shares | length }} more.
    {% endif %} @@ -611,13 +611,13 @@ {% endif %} {% if webmentions %} -
    Webmentions -
    +
    Webmentions +
    {% for webmention in webmentions %} {% set wm = webmention.as_facepile_item %} {% if wm %} - - {{ wm.actor_name }} + + {{ wm.actor_name }} {% endif %} {% endfor %} diff --git a/app/utils/highlight.py b/app/utils/highlight.py index b9a2f34..ff0e079 100644 --- a/app/utils/highlight.py +++ b/app/utils/highlight.py @@ -1,3 +1,5 @@ +import base64 +import hashlib from functools import lru_cache from bs4 import BeautifulSoup # type: ignore @@ -11,6 +13,9 @@ from app.config import CODE_HIGHLIGHTING_THEME _FORMATTER = HtmlFormatter(style=CODE_HIGHLIGHTING_THEME) HIGHLIGHT_CSS = _FORMATTER.get_style_defs() +HIGHLIGHT_CSS_HASH = base64.b64encode( + hashlib.sha256(HIGHLIGHT_CSS.encode()).digest() +).decode() @lru_cache(256)