mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2026-05-26 20:49:55 +00:00
feat: Add support for registering a new account with an email address
This commit is contained in:
@@ -2068,3 +2068,11 @@
|
|||||||
# - `address@domain.org` to not use a name
|
# - `address@domain.org` to not use a name
|
||||||
#
|
#
|
||||||
#sender =
|
#sender =
|
||||||
|
|
||||||
|
# Whether to require that users provide an email address when they register.
|
||||||
|
#
|
||||||
|
#require_email_for_registration = false
|
||||||
|
|
||||||
|
# Whether to require that users who register with a registration token provide an email address.
|
||||||
|
#
|
||||||
|
#require_email_for_token_registration = false
|
||||||
|
|||||||
@@ -9,17 +9,22 @@ use conduwuit::{
|
|||||||
};
|
};
|
||||||
use conduwuit_service::Services;
|
use conduwuit_service::Services;
|
||||||
use futures::{FutureExt, StreamExt};
|
use futures::{FutureExt, StreamExt};
|
||||||
|
use lettre::{Address, message::Mailbox};
|
||||||
use register::RegistrationKind;
|
use register::RegistrationKind;
|
||||||
use ruma::{
|
use ruma::{
|
||||||
OwnedUserId, UserId,
|
OwnedUserId, UserId,
|
||||||
api::client::{
|
api::client::{
|
||||||
account::register::{self, LoginType},
|
account::{
|
||||||
|
register::{self, LoginType},
|
||||||
|
request_registration_token_via_email,
|
||||||
|
},
|
||||||
uiaa::{AuthFlow, AuthType},
|
uiaa::{AuthFlow, AuthType},
|
||||||
},
|
},
|
||||||
events::{GlobalAccountDataEventType, room::message::RoomMessageEventContent},
|
events::{GlobalAccountDataEventType, room::message::RoomMessageEventContent},
|
||||||
push,
|
push,
|
||||||
};
|
};
|
||||||
use serde_json::value::RawValue;
|
use serde_json::value::RawValue;
|
||||||
|
use service::mailer::messages;
|
||||||
|
|
||||||
use super::{DEVICE_ID_LENGTH, TOKEN_LENGTH, join_room_by_id_helper};
|
use super::{DEVICE_ID_LENGTH, TOKEN_LENGTH, join_room_by_id_helper};
|
||||||
use crate::Ruma;
|
use crate::Ruma;
|
||||||
@@ -391,13 +396,14 @@ pub(crate) async fn register_route(
|
|||||||
async fn create_registration_uiaa_session(
|
async fn create_registration_uiaa_session(
|
||||||
services: &Services,
|
services: &Services,
|
||||||
) -> Result<(Vec<AuthFlow>, Box<RawValue>)> {
|
) -> Result<(Vec<AuthFlow>, Box<RawValue>)> {
|
||||||
let mut flows = vec![];
|
|
||||||
let mut params = HashMap::<String, serde_json::Value>::new();
|
let mut params = HashMap::<String, serde_json::Value>::new();
|
||||||
|
|
||||||
if services.firstrun.is_first_run() {
|
let flows = if services.firstrun.is_first_run() {
|
||||||
// Registration token forced while in first-run mode
|
// Registration token forced while in first-run mode
|
||||||
flows.push(AuthFlow::new(vec![AuthType::RegistrationToken]));
|
vec![AuthFlow::new(vec![AuthType::RegistrationToken])]
|
||||||
} else {
|
} else {
|
||||||
|
let mut flows = vec![];
|
||||||
|
|
||||||
if services
|
if services
|
||||||
.registration_tokens
|
.registration_tokens
|
||||||
.iterate_tokens()
|
.iterate_tokens()
|
||||||
@@ -405,14 +411,25 @@ async fn create_registration_uiaa_session(
|
|||||||
.await
|
.await
|
||||||
.is_some()
|
.is_some()
|
||||||
{
|
{
|
||||||
// Registration token flow is available
|
// Trusted registration flow with a token is available
|
||||||
flows.push(AuthFlow::new(vec![AuthType::RegistrationToken]));
|
let mut token_flow = AuthFlow::new(vec![AuthType::RegistrationToken]);
|
||||||
|
|
||||||
|
if let Some(smtp) = &services.config.smtp
|
||||||
|
&& smtp.require_email_for_token_registration
|
||||||
|
{
|
||||||
|
// Email is required for token registrations
|
||||||
|
token_flow.stages.push(AuthType::EmailIdentity);
|
||||||
|
}
|
||||||
|
|
||||||
|
flows.push(token_flow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut untrusted_flow = AuthFlow::default();
|
||||||
|
|
||||||
if services.config.recaptcha_private_site_key.is_some() {
|
if services.config.recaptcha_private_site_key.is_some() {
|
||||||
if let Some(pubkey) = &services.config.recaptcha_site_key {
|
if let Some(pubkey) = &services.config.recaptcha_site_key {
|
||||||
// ReCaptcha flow is available
|
// ReCaptcha is configured for untrusted registrations
|
||||||
flows.push(AuthFlow::new(vec![AuthType::ReCaptcha]));
|
untrusted_flow.stages.push(AuthType::ReCaptcha);
|
||||||
|
|
||||||
params.insert(
|
params.insert(
|
||||||
AuthType::ReCaptcha.as_str().to_owned(),
|
AuthType::ReCaptcha.as_str().to_owned(),
|
||||||
@@ -422,23 +439,36 @@ async fn create_registration_uiaa_session(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if flows.is_empty() {
|
if let Some(smtp) = &services.config.smtp
|
||||||
// Registration is enabled, but no flows are configured. Bail out by default
|
&& smtp.require_email_for_registration
|
||||||
// unless open registration was explicitly enabled.
|
|
||||||
if !services
|
|
||||||
.config
|
|
||||||
.yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse
|
|
||||||
{
|
{
|
||||||
return Err!(Request(Forbidden(
|
// Email is required for untrusted registrations
|
||||||
"This server is not accepting registrations at this time."
|
untrusted_flow.stages.push(AuthType::EmailIdentity);
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have open registration enabled (😧), provide a dummy flow
|
if !untrusted_flow.stages.is_empty() {
|
||||||
flows.push(AuthFlow { stages: vec![AuthType::Dummy] });
|
flows.push(untrusted_flow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if flows.is_empty() {
|
||||||
|
// No flows are configured. Bail out by default
|
||||||
|
// unless open registration was explicitly enabled.
|
||||||
|
if !services
|
||||||
|
.config
|
||||||
|
.yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse
|
||||||
|
{
|
||||||
|
return Err!(Request(Forbidden(
|
||||||
|
"This server is not accepting registrations at this time."
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have open registration enabled (😧), provide a dummy flow
|
||||||
|
flows.push(AuthFlow::new(vec![AuthType::Dummy]));
|
||||||
|
}
|
||||||
|
|
||||||
|
flows
|
||||||
|
};
|
||||||
|
|
||||||
let params = serde_json::value::to_raw_value(¶ms).expect("params should be valid JSON");
|
let params = serde_json::value::to_raw_value(¶ms).expect("params should be valid JSON");
|
||||||
|
|
||||||
@@ -536,3 +566,39 @@ async fn determine_registration_user_id(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// # `POST /_matrix/client/v3/register/email/requestToken`
|
||||||
|
///
|
||||||
|
/// Requests a validation email for the purpose of registering a new account
|
||||||
|
pub(crate) async fn register_request_token_route(
|
||||||
|
State(services): State<crate::State>,
|
||||||
|
body: Ruma<request_registration_token_via_email::v3::Request>,
|
||||||
|
) -> Result<request_registration_token_via_email::v3::Response> {
|
||||||
|
let Ok(email) = Address::try_from(body.email.clone()) else {
|
||||||
|
return Err!(Request(InvalidParam("Invalid email address")));
|
||||||
|
};
|
||||||
|
|
||||||
|
if services
|
||||||
|
.threepid
|
||||||
|
.get_localpart_for_email(&email)
|
||||||
|
.await
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
return Err!(Request(ThreepidInUse("This email address is already in use")));
|
||||||
|
}
|
||||||
|
|
||||||
|
let session = services
|
||||||
|
.threepid
|
||||||
|
.send_validation_email(
|
||||||
|
Mailbox::new(None, email),
|
||||||
|
|verification_link| messages::NewAccount {
|
||||||
|
server_name: services.config.server_name.as_ref(),
|
||||||
|
verification_link,
|
||||||
|
},
|
||||||
|
&body.client_secret,
|
||||||
|
body.send_attempt.try_into().unwrap(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(request_registration_token_via_email::v3::Response::new(session))
|
||||||
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ pub fn build(router: Router<State>, server: &Server) -> Router<State> {
|
|||||||
.ruma_route(&client::get_supported_versions_route)
|
.ruma_route(&client::get_supported_versions_route)
|
||||||
.ruma_route(&client::get_register_available_route)
|
.ruma_route(&client::get_register_available_route)
|
||||||
.ruma_route(&client::register::register_route)
|
.ruma_route(&client::register::register_route)
|
||||||
|
.ruma_route(&client::register::register_request_token_route)
|
||||||
.ruma_route(&client::get_login_types_route)
|
.ruma_route(&client::get_login_types_route)
|
||||||
.ruma_route(&client::login_route)
|
.ruma_route(&client::login_route)
|
||||||
.ruma_route(&client::login_token_route)
|
.ruma_route(&client::login_token_route)
|
||||||
|
|||||||
@@ -2477,6 +2477,20 @@ pub struct SmtpConfig {
|
|||||||
/// - `Name <address@domain.org>` to specify a sender name
|
/// - `Name <address@domain.org>` to specify a sender name
|
||||||
/// - `address@domain.org` to not use a name
|
/// - `address@domain.org` to not use a name
|
||||||
pub sender: Mailbox,
|
pub sender: Mailbox,
|
||||||
|
|
||||||
|
/// Whether to require that users provide an email address when they
|
||||||
|
/// register.
|
||||||
|
///
|
||||||
|
/// default: false
|
||||||
|
#[serde(default)]
|
||||||
|
pub require_email_for_registration: bool,
|
||||||
|
|
||||||
|
/// Whether to require that users who register with a registration token
|
||||||
|
/// provide an email address.
|
||||||
|
///
|
||||||
|
/// default: false
|
||||||
|
#[serde(default)]
|
||||||
|
pub require_email_for_token_registration: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEPRECATED_KEYS: &[&str] = &[
|
const DEPRECATED_KEYS: &[&str] = &[
|
||||||
|
|||||||
Reference in New Issue
Block a user