Compare commits

...

6 Commits

Author SHA1 Message Date
Ginger d33684e391 fix: Use a LRU cache for storing pending auth code grants 2026-06-09 14:54:57 -04:00
Ginger 97ad112070 fix: Spacing 2026-06-09 10:57:29 -04:00
Ginger 1e01bcdbeb chore: Clippy fixes 2026-06-09 10:28:35 -04:00
Ginger d4f6dfc3bf fix: Accessibility improvements 2026-06-09 10:05:44 -04:00
Ginger eb4cae8f95 fix: More CSS tweaks 2026-06-08 14:56:08 -04:00
Ginger 376b9555e3 fix: Set correct default for registration terms config section 2026-06-08 14:05:40 -04:00
12 changed files with 81 additions and 32 deletions
+1 -1
View File
@@ -2001,7 +2001,7 @@
# privacy_policy = { name = "Privacy Policy", url = "https://homeserver.example/en/privacy_policy.html" }
# ```
#
#documents = {}
#documents =
#[global.oauth]
+3 -2
View File
@@ -2367,6 +2367,7 @@ pub struct RegistrationTerms {
/// The language code to provide to clients along with the policy documents.
///
/// default: "en"
#[serde(default = "default_terms_language")]
pub language: String,
/// Policy documents, such as terms and conditions or a privacy policy,
/// which users must agree to when registering an account.
@@ -2376,8 +2377,6 @@ pub struct RegistrationTerms {
/// [global.registration_terms.documents]
/// privacy_policy = { name = "Privacy Policy", url = "https://homeserver.example/en/privacy_policy.html" }
/// ```
///
/// default: {}
pub documents: BTreeMap<String, TermsDocument>,
}
@@ -2805,3 +2804,5 @@ fn default_client_response_timeout() -> u64 { 120 }
fn default_client_shutdown_timeout() -> u64 { 15 }
fn default_sender_shutdown_timeout() -> u64 { 5 }
fn default_terms_language() -> String { "en".to_owned() }
+2
View File
@@ -125,6 +125,7 @@ pub struct OAuthError {
}
impl OAuthError {
#[must_use]
pub const fn invalid_request(error_description: &'static str) -> Self {
Self {
error: ErrorCode::InvalidRequest,
@@ -132,6 +133,7 @@ pub const fn invalid_request(error_description: &'static str) -> Self {
}
}
#[must_use]
pub const fn invalid_grant(error_description: &'static str) -> Self {
Self {
error: ErrorCode::InvalidGrant,
+9 -2
View File
@@ -11,6 +11,7 @@
};
use database::{Deserialized, Json, Map};
use itertools::Itertools;
use lru_cache::LruCache;
use ruma::{DeviceId, OwnedDeviceId, OwnedUserId, UserId};
use serde::{Deserialize, Serialize};
use url::Url;
@@ -34,7 +35,7 @@ pub struct Service {
services: Services,
db: Data,
tickets: Mutex<HashMap<String, HashMap<OAuthTicket, SystemTime>>>,
pending_code_grants: tokio::sync::Mutex<HashMap<String, PendingCodeGrant>>,
pending_code_grants: tokio::sync::Mutex<LruCache<String, PendingCodeGrant>>,
}
struct Data {
@@ -118,7 +119,9 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
refreshtoken_refreshtokeninfo: args.db["refreshtoken_refreshtokeninfo"].clone(),
},
tickets: Mutex::default(),
pending_code_grants: tokio::sync::Mutex::default(),
pending_code_grants: tokio::sync::Mutex::new(LruCache::new(
Self::MAX_PENDING_CODE_GRANTS,
)),
}))
}
@@ -127,6 +130,10 @@ fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
impl Service {
const ACCESS_TOKEN_MAX_AGE: Duration = Duration::from_hours(1);
// Maximum number of pending code grants which will be held in memory at once,
// to prevent unbounded memory use if someone decides to repeatedly reload the
// grant page.
const MAX_PENDING_CODE_GRANTS: usize = 100;
const RANDOM_TOKEN_LENGTH: usize = 32;
fn generate_token() -> String { utils::random_string(Self::RANDOM_TOKEN_LENGTH) }
+39 -1
View File
@@ -4,7 +4,7 @@
--background-color: #fff;
--text-color: #000;
--secondary: #666;
--secondary: #555;
--bg: oklch(0.76 0.0854 317.27);
--panel-bg: oklch(0.91 0.042 317.27);
--c1: oklch(0.44 0.177 353.06);
@@ -84,6 +84,10 @@ footer {
width: 100%;
height: 64px;
}
@media (prefers-color-scheme: light) {
--name-lightness: 0.35;
}
}
p {
@@ -305,6 +309,26 @@ ul.bullet-separated {
filter: brightness(1.2);
}
.kitty {
margin-bottom: 0;
overflow: clip;
width: fit-content;
position: relative;
float: right;
cursor: default;
font-size: small;
span {
display: inline-block;
transform: translateX(calc(100% - 1.5em));
transition: transform 0.3s ease-in-out;
&:hover {
transform: translateX(0);
}
}
}
@media (max-width: 425px) {
main {
padding-block-start: 2rem;
@@ -316,6 +340,20 @@ ul.bullet-separated {
width: 100%;
margin-top: 0;
}
ul.bullet-separated {
display: block;
padding-left: inherit;
li {
display: list-item;
list-style-type: disc;
&::before {
content: none !important;
}
}
}
}
@media (max-width: 799px) {
@@ -1,6 +1,6 @@
{% match avatar_type %}
{% when AvatarType::Initial with (initial) %}
<span class="avatar" role="img">{{ initial }}</span>
<span class="avatar" role="img" aria-hidden="true">{{ initial }}</span>
{% when AvatarType::Image with (src) %}
<img class="avatar" src="{{ src }}">
<img class="avatar" src="{{ src }}" aria-hidden="true">
{% endmatch %}
+1 -1
View File
@@ -19,7 +19,7 @@
{%~ block content %}{% endblock ~%}
{%~ block footer ~%}
<footer>
<a href="{{ crate::ROUTE_PREFIX }}/"><img class="logo" src="{{ crate::ROUTE_PREFIX }}/resources/logo.svg"></a>
<a href="{{ crate::ROUTE_PREFIX }}/"><img class="logo" alt="Continuwuity logo" src="{{ crate::ROUTE_PREFIX }}/resources/logo.svg"></a>
<p>Powered by <a href="https://continuwuity.org">Continuwuity</a> {{ env!("CARGO_PKG_VERSION") }} &bullet; <a href="{{ crate::ROUTE_PREFIX }}/about">About</a></p>
</footer>
{%~ endblock ~%}
+11 -10
View File
@@ -5,11 +5,11 @@ About server
{%- endblock -%}
{%- block content -%}
<div class="panel">
<div class="panel middle">
<h1>About {{ server_name }}</h1>
{% if let Some(support_page) = support_page %}
<p>
Support: <a href="{{ support_page }} target="_blank">{{ support_page }}</a>
Visit this server's website: <a href="{{ support_page }} target="_blank">{{ support_page }}</a>
</p>
{% endif %}
{% if !contacts.is_empty() %}
@@ -32,7 +32,7 @@ About server
: <ul class="bullet-separated">
{%- if let Some(matrix_id) = contact.matrix_id -%}
<li><a href="matrix:u/{{ matrix_id.localpart() }}:{{ matrix_id.server_name() }}?action=chat" target="_blank">{{ matrix_id }}</a></li>
{%- endif -%}
{%~ endif -%}
{%- if let Some(email_address) = contact.email_address -%}
<li><a href="mailto:{{ email_address }}" target="_blank">{{ email_address }}</a>
{%- if let Some(pgp_key) = contact.pgp_key -%}
@@ -58,7 +58,7 @@ About server
</ul>
{% endif %}
<p>
Server version {{ env!("CARGO_PKG_VERSION") }}
Server version <b>{{ env!("CARGO_PKG_VERSION") }}</b>
{%~ if let Some(version_info) = conduwuit_build_metadata::version_tag() ~%}
{%~ if let Some(url) = conduwuit_build_metadata::GIT_REMOTE_COMMIT_URL.or(conduwuit_build_metadata::GIT_REMOTE_WEB_URL) ~%}
(<a href="{{ url }}">{{ version_info }}</a>)
@@ -73,12 +73,13 @@ About server
a high-performance and community-driven <a href="https://matrix.org">Matrix</a> homeserver
maintained as an open source project by volunteers from around the world.
</p>
<p>
<ul class="bullet-separated">
<li><a href="https://forgejo.ellis.link/continuwuation/continuwuity">Source code</a></li>
<li><a href="https://matrix.to/#/#continuwuity:continuwuity.org">Official Matrix chatroom</a></li>
<li><span class="project-name">❤</span>&nbsp;<a href="https://opencollective.com/continuwuity">Support the project</a></li>
</ul>
<ul class="bullet-separated">
<li><a href="https://forgejo.ellis.link/continuwuation/continuwuity">Source code</a></li>
<li><a href="https://matrix.to/#/#continuwuity:continuwuity.org">Official Matrix chatroom</a></li>
<li><span class="project-name">❤</span>&nbsp;<a href="https://opencollective.com/continuwuity">Support the project</a></li>
</ul>
<p class="kitty">
<span>🐈 meow :3</span>
</p>
</div>
{% endblock %}
+1 -1
View File
@@ -10,7 +10,7 @@
{%- block content -%}
<div class="error-body">
<pre class="k10y" aria-hidden>
<pre class="k10y" aria-hidden="true">
      />  
      |  _  _|
     ` ミ_x
+1 -1
View File
@@ -15,7 +15,7 @@ Authorize client
<div class="red-avatar">
{{ user_avatar }}
</div>
<div class="separator" aria-hidden>
<div class="separator" aria-hidden="true">
</div>
{{ client_avatar }}
+3 -3
View File
@@ -29,11 +29,11 @@ Log in
<form method="post">
<p>
<label for="identifier">Username or email address</label>
<input type="text" name="identifier" autocomplete="username">
<input type="text" id="identifier" name="identifier" autocomplete="username">
</p>
<p>
<label for="password">Password</label>
<input type="password" name="password" autocomplete="current-password">
<input type="password" id="password" name="password" autocomplete="current-password">
</p>
<button type="submit">Log in</button>
</form>
@@ -51,7 +51,7 @@ Log in
<form method="post">
<p>
<label for="password">Password</label>
<input type="password" name="password" autocomplete="current-password">
<input type="password" id="password" name="password" autocomplete="current-password">
</p>
<button type="submit">Continue</button>
</form>
+8 -8
View File
@@ -55,7 +55,7 @@ Sign up
<label for="username">Username</label>
<span class="username-input">
<span>@</span>
<input type="text" name="username" autocomplete="username" required>
<input type="text" id="username" name="username" autocomplete="username" required>
<span>:{{ server_name }}</span>
</span>
{% if let Some(username_error) = username_error %}
@@ -98,9 +98,9 @@ Sign up
<span class="username-input">
<span>@</span>
{% if let Some(username) = username %}
<input type="text" name="username" value="{{ username }}" autocomplete="username" required>
<input type="text" id="username" name="username" value="{{ username }}" autocomplete="username" required>
{% else %}
<input type="text" name="username" autocomplete="username" required>
<input type="text" id="username" name="username" autocomplete="username" required>
{% endif %}
<span>:{{ server_name }}</span>
</span>
@@ -114,18 +114,18 @@ Sign up
{% endif %}
<p>
<label for="password">Password</label>
<input type="password" name="password" autocomplete="new-password" required>
<input type="password" id="password" name="password" autocomplete="new-password" required>
{{ form::errors(field_errors, std::borrow::Cow::Borrowed("password")) }}
</p>
<p>
<label for="confirm_password">Confirm password</label>
<input type="password" name="confirm_password" autocomplete="new-password" required>
<input type="password" id="confirm_password" name="confirm_password" autocomplete="new-password" required>
{{ form::errors(field_errors, std::borrow::Cow::Borrowed("confirm_password")) }}
</p>
{% if require_email %}
<p>
<label for="email">Email address</label>
<input type="email" name="email" required>
<input type="email" id="email" name="email" required>
{{ form::errors(field_errors, std::borrow::Cow::Borrowed("email")) }}
</p>
{% endif %}
@@ -153,8 +153,8 @@ Sign up
</div>
{% else %}
<p>
<label for="username">Registration token</label>
<input type="text" name="registration_token" autocomplete="none" required>
<label for="registration_token">Registration token</label>
<input type="text" id="registration_token" name="registration_token" autocomplete="none" required>
{% if is_first_run %}
<small>Check the server console to find the registration token.</small>
{% endif %}