1
0
mirror of https://git.sr.ht/~tsileo/microblog.pub synced 2025-06-05 21:59:23 +02:00

4 Commits

9 changed files with 230 additions and 174 deletions

View File

@ -109,6 +109,8 @@ class Config(pydantic.BaseModel):
inbox_retention_days: int = 15
custom_content_security_policy: str | None = None
# Config items to make tests easier
sqlalchemy_database: str | None = None
key_path: str | None = None
@ -165,6 +167,7 @@ if CONFIG.privacy_replace:
BLOCKED_SERVERS = {blocked_server.hostname for blocked_server in CONFIG.blocked_servers}
ALSO_KNOWN_AS = CONFIG.also_known_as
CUSTOM_CONTENT_SECURITY_POLICY = CONFIG.custom_content_security_policy
INBOX_RETENTION_DAYS = CONFIG.inbox_retention_days
CUSTOM_FOOTER = (

View File

@ -137,9 +137,15 @@ class CustomMiddleware:
headers["x-frame-options"] = "DENY"
headers["permissions-policy"] = "interest-cohort=()"
headers["content-security-policy"] = (
f"default-src 'self'; "
f"style-src 'self' 'sha256-{HIGHLIGHT_CSS_HASH}'; "
f"frame-ancestors 'none'; base-uri 'self'; form-action 'self';"
(
f"default-src 'self'; "
f"style-src 'self' 'sha256-{HIGHLIGHT_CSS_HASH}'; "
f"frame-ancestors 'none'; base-uri 'self'; form-action 'self';"
)
if not config.CUSTOM_CONTENT_SECURITY_POLICY
else config.CUSTOM_CONTENT_SECURITY_POLICY.format(
HIGHLIGHT_CSS_HASH=HIGHLIGHT_CSS_HASH
)
)
if not DEBUG:
headers["strict-transport-security"] = "max-age=63072000;"

View File

@ -1,9 +1,11 @@
$font-stack: Helvetica, sans-serif;
$font-stack: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, helvetica, Cantarell,
Ubuntu, roboto, noto, arial, sans-serif;
$background: #ddd;
$light-background: #e6e6e6;
$text-color: #111;
$primary-color: #1d781d;
$secondary-color: #781D78;
$secondary-color: #781d78;
$form-background-color: #ccc;
$form-text-color: #333;
$muted-color: #555; // solarized comment text
@ -13,6 +15,46 @@ $code-highlight-background: #f0f0f0;
// Load custom theme
@import "theme.scss";
/* Box sizing rules */
*,
*::before,
*::after {
box-sizing: border-box;
}
/* Set core root defaults */
html:focus-within {
scroll-behavior: smooth;
}
/* Inherit fonts for inputs and buttons */
input,
button,
textarea,
select {
font: inherit;
}
html {
max-width: 90ch;
padding: 3em 1em;
margin: auto;
line-height: 1.75;
font-size: 1.25em;
}
body {
font-family: $font-stack;
background: $background;
color: $text-color;
display: flex;
min-height: 100vh;
flex-direction: column;
}
a {
text-decoration: none;
}
.primary-color {
color: $primary-color;
}
@ -70,7 +112,7 @@ $code-highlight-background: #f0f0f0;
display: none;
}
.sensitive-attachment-state:checked ~ .sensitive-attachment-box div {
display:none;
display: none;
}
.sensitive-attachment-box {
position: relative;
@ -84,7 +126,6 @@ $code-highlight-background: #f0f0f0;
}
}
blockquote {
border-left: 3px solid $secondary-color;
margin-left: 0;
@ -92,28 +133,11 @@ blockquote {
}
.muted {
color: $muted-color;
color: $muted-color;
}
.light-background {
background: $light-background;
}
body {
font-family: $font-stack;
font-size: 20px;
line-height: 32px;
background: $background;
color: $text-color;
margin: 0;
padding: 0;
display: flex;
min-height: 100vh;
flex-direction: column;
}
a {
text-decoration: none;
background: $light-background;
}
dl {
@ -137,53 +161,56 @@ dl {
}
.shared-header {
margin-left: 20px;
margin-top: 30px;
margin-bottom: -20px;
strong {
color: $primary-color;
}
span {
color: $muted-color;
}
margin-left: 20px;
margin-top: 30px;
margin-bottom: -20px;
strong {
color: $primary-color;
}
span {
color: $muted-color;
}
}
div.highlight {
background: $code-highlight-background;
padding: 0 10px;
overflow: auto;
display: block;
margin: 20px 0;
background: $code-highlight-background;
padding: 0 10px;
overflow: auto;
display: block;
margin: 20px 0;
}
.box {
padding: 0 20px;
padding: 0 20px;
}
code, pre {
code,
pre {
color: $secondary-color; // #cb4b16; // #268bd2; // #2aa198;
font-family: monospace;
}
.form {
input, select, textarea {
font-size: 20px;
border: 0;
padding: 5px;
background: $form-background-color;
color: $form-text-color;
&:focus {
outline: 1px solid $secondary-color;
}
}
input[type=submit] {
font-size: 20px;
outline: none;
background: $primary-color;
color: $primary-button-text-color;
padding: 5px 12px;
cursor: pointer;
input,
select,
textarea {
font-size: 20px;
border: 0;
padding: 5px;
background: $form-background-color;
color: $form-text-color;
&:focus {
outline: 1px solid $secondary-color;
}
}
input[type="submit"] {
font-size: 20px;
outline: none;
background: $primary-color;
color: $primary-button-text-color;
padding: 5px 12px;
cursor: pointer;
}
}
header {
@ -212,18 +239,17 @@ a {
}
}
#main {
display: flex;
flex: 1;
display: flex;
flex: 1;
}
main {
width: 100%;
max-width: 1000px;
margin: 30px auto;
width: 100%;
margin: 30px auto;
}
.main-flex {
display: flex;
flex: 1;
display: flex;
flex: 1;
}
.centered {
@ -237,12 +263,12 @@ main {
}
footer {
font-size: 1em;
width: 100%;
max-width: 1000px;
margin: 20px auto;
color: $muted-color;
p {
margin: 0;
margin: 0;
}
}
.tiny-actor-icon {
@ -254,7 +280,7 @@ footer {
.actor-box {
display: flex;
column-gap: 20px;
margin:10px 0;
margin: 10px 0;
.icon-box {
flex: 0 0 50px;
}
@ -268,50 +294,54 @@ footer {
}
}
#articles {
list-style-type: none;
margin: 30px 0;
padding: 0 20px;
li {
display: block;
span {
padding-right:10px;
}
list-style-type: none;
margin: 30px 0;
padding: 0 20px;
li {
display: block;
span {
padding-right: 10px;
}
}
}
#notifications, #followers, #following {
ul {
list-style-type: none;
margin: 0;
padding: 0;
}
li {
display: block;
}
#notifications,
#followers,
#following {
ul {
list-style-type: none;
margin: 0;
padding: 0;
}
li {
display: block;
}
}
@mixin admin-button() {
font-size: 20px;
line-height: 32px;
font-family: $font-stack;
background: $form-background-color;
color: $form-text-color;
border: 1px solid $background;
padding: 8px 10px 5px 10px;
cursor: pointer;
&:hover {
border: 1px solid $form-text-color;
}
font-size: 20px;
line-height: 32px;
font-family: $font-stack;
background: $form-background-color;
color: $form-text-color;
border: 1px solid $background;
padding: 8px 10px 5px 10px;
cursor: pointer;
&:hover {
border: 1px solid $form-text-color;
}
}
.show-sensitive-btn, .show-more-btn, .label-btn {
@include admin-button;
padding: 10px 5px;
margin: 20px 0;
.show-sensitive-btn,
.show-more-btn,
.label-btn {
@include admin-button;
padding: 10px 5px;
margin: 20px 0;
}
.show-hide-sensitive-btn {
display:inline-block;
display: inline-block;
}
.no-margin-top {
@ -335,13 +365,13 @@ ul.poll-items {
}
.poll-bar {
width:100%;height:20px;
line {
stroke: $secondary-color;
stroke-width: 20px;
}
width: 100%;
height: 20px;
line {
stroke: $secondary-color;
stroke-width: 20px;
}
}
}
}
@ -362,44 +392,45 @@ ul.poll-items {
}
nav {
form {
margin: 15px 0;
}
input[type=submit], button {
@include admin-button;
}
form {
margin: 15px 0;
}
input[type="submit"],
button {
@include admin-button;
}
}
nav.flexbox {
ul {
display: flex;
flex-wrap: wrap;
align-items: center;
list-style-type: none;
margin: 0;
padding: 0;
ul {
display: flex;
flex-wrap: wrap;
align-items: center;
list-style-type: none;
margin: 0;
padding: 0;
}
}
ul li {
margin-right: 20px;
ul li {
margin-right: 20px;
&:last-child {
margin-right: 0px;
}
&:last-child {
margin-right: 0px;
}
a:not(.label-btn) {
color: $primary-color;
text-decoration: none;
&:hover, &:active {
color: $secondary-color;
text-decoration: underline;
}
}
a.active:not(.label-btn) {
color: $secondary-color;
font-weight: bold;
}
a:not(.label-btn) {
color: $primary-color;
text-decoration: none;
&:hover,
&:active {
color: $secondary-color;
text-decoration: underline;
}
}
a.active:not(.label-btn) {
color: $secondary-color;
font-weight: bold;
}
}
// after nav.flexbox to override default behavior
@ -412,31 +443,34 @@ a.label-btn {
}
.ap-object {
margin: 15px 0;
padding: 20px;
nav {
color: $muted-color;
margin: 15px 0;
padding: 20px;
nav {
color: $muted-color;
}
.in-reply-to {
display: inline;
color: $muted-color;
}
.e-content,
.activity-og-meta {
a:hover {
text-decoration: underline;
}
.in-reply-to {
display: inline;
color: $muted-color;
}
.e-content, .activity-og-meta {
a:hover {
text-decoration: underline;
}
}
.activity-attachment {
margin: 30px 0 20px 0;
img, audio, video {
width: 100%;
max-width: 740px;
}
}
img.inline-img {
display: block;
max-width: 740px;
}
.activity-attachment {
margin: 30px 0 20px 0;
img,
audio,
video {
width: 100%;
max-width: 740px;
}
}
img.inline-img {
display: block;
max-width: 740px;
}
}
.activity-og-meta {
@ -453,25 +487,26 @@ a.label-btn {
}
.ap-object-expanded {
border: 2px dashed $secondary-color;
border: 2px dashed $secondary-color;
}
.error-box {
color: $secondary-color;
color: $secondary-color;
}
.actor-action {
margin-top:20px;
margin-bottom:-20px;
margin-top: 20px;
margin-bottom: -20px;
padding: 0 20px;
span {
color: $muted-color;
}
}
.actor-metadata {
color: $muted-color;
color: $muted-color;
}
.emoji, .custom-emoji {
.emoji,
.custom-emoji {
max-width: 25px;
}

View File

@ -424,3 +424,4 @@ _templates.env.globals["BASE_URL"] = config.BASE_URL
_templates.env.globals["HIDES_FOLLOWERS"] = config.HIDES_FOLLOWERS
_templates.env.globals["HIDES_FOLLOWING"] = config.HIDES_FOLLOWING
_templates.env.globals["NAVBAR_ITEMS"] = config.NavBarItems
_templates.env.globals["ICON_URL"] = config.CONFIG.icon_url

View File

@ -14,7 +14,7 @@
<meta content="{{ local_actor.display_name }}'s microblog" property="og:site_name" />
<meta content="Homepage" property="og:title" />
<meta content="{{ local_actor.summary | html2text | trim }}" property="og:description" />
<meta content="{{ local_actor.url }}" property="og:image" />
<meta content="{{ ICON_URL }}" property="og:image" />
<meta content="summary" property="twitter:card" />
<meta content="{{ local_actor.handle }}" property="profile:username" />
{% endif %}

View File

@ -26,11 +26,12 @@
{%- macro header_link(url, text) -%}
{% set url_for = BASE_URL + request.app.router.url_path_for(url) %}
<a href="{{ url_for }}" {% if request.url.path == url_for %}class="active"{% endif %}>{{ text }}</a>
<a href="{{ url_for }}" {% if BASE_URL + request.url.path == url_for %}class="active"{% endif %}>{{ text }}</a>
{% endmacro %}
{%- macro navbar_item_link(navbar_item) -%}
<a href="{{ navbar_item[0] }}" {% if request.url.path == navbar_item[0] %}class="active"{% endif %}>{{ navbar_item[1] }}</a>
{% set url_for = BASE_URL + navbar_item[0] %}
<a href="{{ navbar_item[0] }}" {% if BASE_URL + request.url.path == url_for %}class="active"{% endif %}>{{ navbar_item[1] }}</a>
{% endmacro %}
<div class="public-top-menu">

View File

@ -13,7 +13,7 @@
<meta content="{{ local_actor.display_name }}'s microblog" property="og:site_name" />
<meta content="Homepage" property="og:title" />
<meta content="{{ local_actor.summary | html2text | trim }}" property="og:description" />
<meta content="{{ local_actor.url }}" property="og:image" />
<meta content="{{ ICON_URL }}" property="og:image" />
<meta content="summary" property="twitter:card" />
<meta content="{{ local_actor.handle }}" property="profile:username" />
{% endblock %}

View File

@ -19,7 +19,7 @@
<div id="admin">
{% macro admin_link(url, text) %}
{% set url_for = BASE_URL + request.app.router.url_path_for(url) %}
<a href="{{ url_for }}" {% if request.url.path == url_for %}class="active"{% endif %}>{{ text }}</a>
<a href="{{ url_for }}" {% if BASE_URL + request.url.path == url_for %}class="active"{% endif %}>{{ text }}</a>
{% endmacro %}
<div class="admin-menu">
<nav class="flexbox">

View File

@ -131,9 +131,19 @@ See `app/scss/main.scss` to see what variables can be overridden.
If you'd like to customize your instance's theme beyond CSS, you can modify the app's HTML by placing templates in `data/templates` which overwrite the defaults in `app/templates`.
#### Custom Content Security Policy (CSP)
You can override the default Content Security Policy by adding a line in `data/profile.toml`:
```toml
custom_content_security_policy = "default-src 'self'; style-src 'self' 'sha256-{HIGHLIGHT_CSS_HASH}'; frame-ancestors 'none'; base-uri 'self'; form-action 'self';"
```
This example will output the default CSP, note that `{HIGHLIGHT_CSS_HASH}` will be dynamically replaced by the correct value (the hash of the CSS needed for syntax highlighting).
#### Code highlighting theme
You can switch to one of the [styles supported by Pygments](https://pygments.org/styles/) by adding a line in `profile.toml`:
You can switch to one of the [styles supported by Pygments](https://pygments.org/styles/) by adding a line in `data/profile.toml`:
```toml
code_highlighting_theme = "solarized-dark"