mirror of
https://forgejo.ellis.link/continuwuation/continuwuity/
synced 2026-07-16 23:01:54 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba0ec6ba70 |
@@ -32,7 +32,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
if: steps.runner-env.outputs.node_major == '' || steps.runner-env.outputs.node_major < '20'
|
if: steps.runner-env.outputs.node_major == '' || steps.runner-env.outputs.node_major < '20'
|
||||||
uses: https://github.com/actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
|
uses: https://github.com/actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version: 22
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: 📦 Setup Node.js
|
- name: 📦 Setup Node.js
|
||||||
uses: https://github.com/actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
|
uses: https://github.com/actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
|
||||||
with:
|
with:
|
||||||
node-version: "22"
|
node-version: "22"
|
||||||
|
|
||||||
|
|||||||
Generated
+9
-9
@@ -637,7 +637,7 @@ checksum = "aa61aec073ec94791433ddf3df2323ff9d1711557c2a0eefb0f99cb4f8dca520"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"semver",
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
"toml 1.1.3+spec-1.1.0",
|
"toml 1.1.2+spec-1.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -996,7 +996,7 @@ dependencies = [
|
|||||||
"tikv-jemallocator",
|
"tikv-jemallocator",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-metrics",
|
"tokio-metrics",
|
||||||
"toml 1.1.3+spec-1.1.0",
|
"toml 1.1.2+spec-1.1.0",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
@@ -4728,7 +4728,7 @@ dependencies = [
|
|||||||
"ruma-identifiers-validation",
|
"ruma-identifiers-validation",
|
||||||
"serde",
|
"serde",
|
||||||
"syn",
|
"syn",
|
||||||
"toml 1.1.3+spec-1.1.0",
|
"toml 1.1.2+spec-1.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5631,9 +5631,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.119"
|
version = "2.0.118"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
|
checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -5944,9 +5944,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "1.1.3+spec-1.1.0"
|
version = "1.1.2+spec-1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "53c96ecdfa941c8fc4fcaed14f99ada8ebed502eef533015095a07e3301d4c3c"
|
checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.14.0",
|
"indexmap 2.14.0",
|
||||||
"serde_core",
|
"serde_core",
|
||||||
@@ -6018,9 +6018,9 @@ checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_writer"
|
name = "toml_writer"
|
||||||
version = "1.1.2+spec-1.1.0"
|
version = "1.1.1+spec-1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2"
|
checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tonic"
|
name = "tonic"
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
Fixed `create` being returned as a supported prompt value regardless of if registration is enabled or not. Contributed by @ginger
|
|
||||||
@@ -37,17 +37,6 @@ pub(crate) async fn authorization_server_metadata(services: &Services) -> Value
|
|||||||
.join(super::BASE_PATH)
|
.join(super::BASE_PATH)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let prompt_values_supported = if services
|
|
||||||
.uiaa
|
|
||||||
.registration_flow_status()
|
|
||||||
.await
|
|
||||||
.any_available()
|
|
||||||
{
|
|
||||||
json!(["create"])
|
|
||||||
} else {
|
|
||||||
json!([])
|
|
||||||
};
|
|
||||||
|
|
||||||
json!({
|
json!({
|
||||||
"account_management_uri": endpoint_base.join(ACCOUNT_MANAGEMENT_PATH).unwrap(),
|
"account_management_uri": endpoint_base.join(ACCOUNT_MANAGEMENT_PATH).unwrap(),
|
||||||
"account_management_actions_supported": [
|
"account_management_actions_supported": [
|
||||||
@@ -63,7 +52,7 @@ pub(crate) async fn authorization_server_metadata(services: &Services) -> Value
|
|||||||
"grant_types_supported": ["authorization_code", "refresh_token"],
|
"grant_types_supported": ["authorization_code", "refresh_token"],
|
||||||
"issuer": services.config.get_client_domain(),
|
"issuer": services.config.get_client_domain(),
|
||||||
"jwks_uri": endpoint_base.join(JWKS_URI_PATH).unwrap(),
|
"jwks_uri": endpoint_base.join(JWKS_URI_PATH).unwrap(),
|
||||||
"prompt_values_supported": prompt_values_supported,
|
"prompt_values_supported": ["create"],
|
||||||
"registration_endpoint": endpoint_base.join(CLIENT_REGISTER_PATH).unwrap(),
|
"registration_endpoint": endpoint_base.join(CLIENT_REGISTER_PATH).unwrap(),
|
||||||
"response_modes_supported": ["query", "fragment"],
|
"response_modes_supported": ["query", "fragment"],
|
||||||
"response_types_supported": ["code"],
|
"response_types_supported": ["code"],
|
||||||
|
|||||||
+7
-89
@@ -5,7 +5,6 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
use conduwuit::{Err, Error, Result, error, utils};
|
use conduwuit::{Err, Error, Result, error, utils};
|
||||||
use futures::StreamExt;
|
|
||||||
use lettre::Address;
|
use lettre::Address;
|
||||||
use ruma::{
|
use ruma::{
|
||||||
DeviceId, UserId,
|
DeviceId, UserId,
|
||||||
@@ -26,7 +25,7 @@
|
|||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Dep, config, firstrun, globals,
|
Dep, config, globals,
|
||||||
oauth::{self, OAuthTicket},
|
oauth::{self, OAuthTicket},
|
||||||
registration_tokens, threepid, users,
|
registration_tokens, threepid, users,
|
||||||
};
|
};
|
||||||
@@ -37,54 +36,25 @@ pub struct Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct Services {
|
struct Services {
|
||||||
config: Dep<config::Service>,
|
|
||||||
firstrun: Dep<firstrun::Service>,
|
|
||||||
globals: Dep<globals::Service>,
|
globals: Dep<globals::Service>,
|
||||||
oauth: Dep<oauth::Service>,
|
users: Dep<users::Service>,
|
||||||
|
config: Dep<config::Service>,
|
||||||
registration_tokens: Dep<registration_tokens::Service>,
|
registration_tokens: Dep<registration_tokens::Service>,
|
||||||
threepid: Dep<threepid::Service>,
|
threepid: Dep<threepid::Service>,
|
||||||
users: Dep<users::Service>,
|
oauth: Dep<oauth::Service>,
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum TrustedFlowStatus {
|
|
||||||
Unavailable,
|
|
||||||
Available,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum UntrustedFlowStatus {
|
|
||||||
Unavailable,
|
|
||||||
Available {
|
|
||||||
require_email: bool,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FlowStatus {
|
|
||||||
pub trusted: TrustedFlowStatus,
|
|
||||||
pub untrusted: UntrustedFlowStatus,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FlowStatus {
|
|
||||||
#[must_use]
|
|
||||||
pub fn any_available(&self) -> bool {
|
|
||||||
matches!(self.trusted, TrustedFlowStatus::Available)
|
|
||||||
|| matches!(self.untrusted, UntrustedFlowStatus::Available { .. })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::Service for Service {
|
impl crate::Service for Service {
|
||||||
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||||
Ok(Arc::new(Self {
|
Ok(Arc::new(Self {
|
||||||
services: Services {
|
services: Services {
|
||||||
config: args.depend::<config::Service>("config"),
|
|
||||||
firstrun: args.depend::<firstrun::Service>("firstrun"),
|
|
||||||
globals: args.depend::<globals::Service>("globals"),
|
globals: args.depend::<globals::Service>("globals"),
|
||||||
oauth: args.depend::<oauth::Service>("oauth"),
|
users: args.depend::<users::Service>("users"),
|
||||||
|
config: args.depend::<config::Service>("config"),
|
||||||
registration_tokens: args
|
registration_tokens: args
|
||||||
.depend::<registration_tokens::Service>("registration_tokens"),
|
.depend::<registration_tokens::Service>("registration_tokens"),
|
||||||
threepid: args.depend::<threepid::Service>("threepid"),
|
threepid: args.depend::<threepid::Service>("threepid"),
|
||||||
users: args.depend::<users::Service>("users"),
|
oauth: args.depend::<oauth::Service>("oauth"),
|
||||||
},
|
},
|
||||||
uiaa_sessions: Mutex::new(HashMap::new()),
|
uiaa_sessions: Mutex::new(HashMap::new()),
|
||||||
}))
|
}))
|
||||||
@@ -625,56 +595,4 @@ async fn check_stage(
|
|||||||
|
|
||||||
Ok((completed_auth_type, session_metadata))
|
Ok((completed_auth_type, session_metadata))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn registration_flow_status(&self) -> FlowStatus {
|
|
||||||
// Allow registration if it's enabled in the config file or if this is the first
|
|
||||||
// run (so the first user account can be created)
|
|
||||||
let allow_registration =
|
|
||||||
self.services.config.allow_registration || self.services.firstrun.is_first_run();
|
|
||||||
|
|
||||||
// Trusted flow is only available if any registration tokens exist
|
|
||||||
let trusted = {
|
|
||||||
if !allow_registration {
|
|
||||||
TrustedFlowStatus::Unavailable
|
|
||||||
} else if self
|
|
||||||
.services
|
|
||||||
.registration_tokens
|
|
||||||
.iterate_tokens()
|
|
||||||
.next()
|
|
||||||
.await
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
TrustedFlowStatus::Available
|
|
||||||
} else {
|
|
||||||
TrustedFlowStatus::Unavailable
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Untrusted flow is available if email is required for registration,
|
|
||||||
// or reCAPTCHA is configured, or open registration is enabled
|
|
||||||
let untrusted = {
|
|
||||||
let require_email = self
|
|
||||||
.services
|
|
||||||
.config
|
|
||||||
.smtp
|
|
||||||
.as_ref()
|
|
||||||
.is_some_and(|smtp| smtp.require_email_for_registration);
|
|
||||||
|
|
||||||
if !allow_registration || self.services.firstrun.is_first_run() {
|
|
||||||
UntrustedFlowStatus::Unavailable
|
|
||||||
} else if self.services.config.recaptcha_private_site_key.is_some() || require_email {
|
|
||||||
UntrustedFlowStatus::Available { require_email }
|
|
||||||
} else if self
|
|
||||||
.services
|
|
||||||
.config
|
|
||||||
.yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse
|
|
||||||
{
|
|
||||||
UntrustedFlowStatus::Available { require_email: false }
|
|
||||||
} else {
|
|
||||||
UntrustedFlowStatus::Unavailable
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
FlowStatus { trusted, untrusted }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
extract::{Expect, PostForm},
|
extract::{Expect, PostForm},
|
||||||
pages::{
|
pages::{
|
||||||
GET_POST, Result, TemplateContext,
|
GET_POST, Result, TemplateContext,
|
||||||
|
account::register::{TrustedFlowStatus, UntrustedFlowStatus, registration_flow_status},
|
||||||
components::UserCard,
|
components::UserCard,
|
||||||
oidc::{OIDC_SESSION_ID_KEY, OidcSession, OidcSessionState},
|
oidc::{OIDC_SESSION_ID_KEY, OidcSession, OidcSessionState},
|
||||||
},
|
},
|
||||||
@@ -100,13 +101,13 @@ async fn route_login(
|
|||||||
|
|
||||||
LoginType::Oidc { redirect_url }
|
LoginType::Oidc { redirect_url }
|
||||||
} else {
|
} else {
|
||||||
LoginType::Interactive {
|
let (trusted_flow_status, untrusted_flow_status) =
|
||||||
registration_available: services
|
registration_flow_status(&services).await;
|
||||||
.uiaa
|
|
||||||
.registration_flow_status()
|
let registration_available = matches!(trusted_flow_status, TrustedFlowStatus::Available)
|
||||||
.await
|
|| matches!(untrusted_flow_status, UntrustedFlowStatus::Available { .. });
|
||||||
.any_available(),
|
|
||||||
}
|
LoginType::Interactive { registration_available }
|
||||||
};
|
};
|
||||||
|
|
||||||
let body = match &user_id {
|
let body = match &user_id {
|
||||||
|
|||||||
@@ -8,12 +8,9 @@
|
|||||||
};
|
};
|
||||||
use conduwuit_core::{config::TermsDocument, warn};
|
use conduwuit_core::{config::TermsDocument, warn};
|
||||||
use conduwuit_service::{
|
use conduwuit_service::{
|
||||||
mailer::messages,
|
mailer::messages, registration_tokens::ValidToken, users::HashedPassword,
|
||||||
registration_tokens::ValidToken,
|
|
||||||
uiaa::{FlowStatus, TrustedFlowStatus, UntrustedFlowStatus},
|
|
||||||
users::HashedPassword,
|
|
||||||
};
|
};
|
||||||
use futures::FutureExt;
|
use futures::{FutureExt, StreamExt};
|
||||||
use lettre::{Address, message::Mailbox};
|
use lettre::{Address, message::Mailbox};
|
||||||
use ruma::{ClientSecret, OwnedClientSecret, OwnedServerName, OwnedSessionId, OwnedUserId};
|
use ruma::{ClientSecret, OwnedClientSecret, OwnedServerName, OwnedSessionId, OwnedUserId};
|
||||||
use serde::{Deserialize, Serialize, de::IgnoredAny};
|
use serde::{Deserialize, Serialize, de::IgnoredAny};
|
||||||
@@ -64,6 +61,20 @@ enum RegisterBody {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(super) enum TrustedFlowStatus {
|
||||||
|
Unavailable,
|
||||||
|
Available,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(super) enum UntrustedFlowStatus {
|
||||||
|
Unavailable,
|
||||||
|
Available {
|
||||||
|
require_email: bool,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Serialize)]
|
#[derive(Default, Deserialize, Serialize)]
|
||||||
pub(crate) struct RegisterQuery {
|
pub(crate) struct RegisterQuery {
|
||||||
pub username: Option<String>,
|
pub username: Option<String>,
|
||||||
@@ -158,10 +169,7 @@ async fn route_register(
|
|||||||
ValidationErrors::new()
|
ValidationErrors::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
let FlowStatus {
|
let (trusted_flow_status, untrusted_flow_status) = registration_flow_status(&services).await;
|
||||||
trusted: trusted_flow_status,
|
|
||||||
untrusted: untrusted_flow_status,
|
|
||||||
} = services.uiaa.registration_flow_status().await;
|
|
||||||
|
|
||||||
if matches!(trusted_flow_status, TrustedFlowStatus::Unavailable)
|
if matches!(trusted_flow_status, TrustedFlowStatus::Unavailable)
|
||||||
&& matches!(untrusted_flow_status, UntrustedFlowStatus::Unavailable)
|
&& matches!(untrusted_flow_status, UntrustedFlowStatus::Unavailable)
|
||||||
@@ -532,3 +540,54 @@ async fn complete_registration(
|
|||||||
|
|
||||||
Ok(Redirect::to(&next.unwrap_or_default().target_path()))
|
Ok(Redirect::to(&next.unwrap_or_default().target_path()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) async fn registration_flow_status(
|
||||||
|
services: &crate::State,
|
||||||
|
) -> (TrustedFlowStatus, UntrustedFlowStatus) {
|
||||||
|
// Allow registration if it's enabled in the config file or if this is the first
|
||||||
|
// run (so the first user account can be created)
|
||||||
|
let allow_registration =
|
||||||
|
services.config.allow_registration || services.firstrun.is_first_run();
|
||||||
|
|
||||||
|
// Trusted flow is only available if any registration tokens exist
|
||||||
|
let trusted_flow_status = {
|
||||||
|
if !allow_registration {
|
||||||
|
TrustedFlowStatus::Unavailable
|
||||||
|
} else if services
|
||||||
|
.registration_tokens
|
||||||
|
.iterate_tokens()
|
||||||
|
.next()
|
||||||
|
.await
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
TrustedFlowStatus::Available
|
||||||
|
} else {
|
||||||
|
TrustedFlowStatus::Unavailable
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Untrusted flow is available if email is required for registration,
|
||||||
|
// or reCAPTCHA is configured, or open registration is enabled
|
||||||
|
let untrusted_flow_status = {
|
||||||
|
let require_email = services
|
||||||
|
.config
|
||||||
|
.smtp
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|smtp| smtp.require_email_for_registration);
|
||||||
|
|
||||||
|
if !allow_registration || services.firstrun.is_first_run() {
|
||||||
|
UntrustedFlowStatus::Unavailable
|
||||||
|
} else if services.config.recaptcha_private_site_key.is_some() || require_email {
|
||||||
|
UntrustedFlowStatus::Available { require_email }
|
||||||
|
} else if services
|
||||||
|
.config
|
||||||
|
.yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse
|
||||||
|
{
|
||||||
|
UntrustedFlowStatus::Available { require_email: false }
|
||||||
|
} else {
|
||||||
|
UntrustedFlowStatus::Unavailable
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(trusted_flow_status, untrusted_flow_status)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user