mirror of
https://github.com/LemmyNet/lemmy.git
synced 2025-01-16 23:15:54 +00:00
Nutomic
a00313e680
* Merge /site_inbox into /inbox (fixes #4137) Get rid of different inboxes, only use /inbox Remove shared_inbox_url db columns add code migration move to db migration, fixes machete fix sql drop inbox url unique constraints Dont create auth cookie in backend (#4136) dont change individual inboxes to shared inbox Dont send comment reply to user who has community blocked. Fixes #3684 (#4096) * Dont send comment reply to user who has community blocked. Fixes #3684 * Adding source instance block check. * Adding api test. * Addressing PR comments. * move site inbox rewrite to db * fix test * clippy * clippy 2 * fix test
202 lines
6.5 KiB
Rust
202 lines
6.5 KiB
Rust
use activitypub_federation::{config::Data, http_signatures::generate_actor_keypair};
|
|
use actix_web::{web::Json, HttpRequest};
|
|
use lemmy_api_common::{
|
|
claims::Claims,
|
|
context::LemmyContext,
|
|
person::{LoginResponse, Register},
|
|
utils::{
|
|
generate_inbox_url,
|
|
generate_local_apub_endpoint,
|
|
generate_shared_inbox_url,
|
|
honeypot_check,
|
|
local_site_to_slur_regex,
|
|
password_length_check,
|
|
send_new_applicant_email_to_admins,
|
|
send_verification_email,
|
|
EndpointType,
|
|
},
|
|
};
|
|
use lemmy_db_schema::{
|
|
aggregates::structs::PersonAggregates,
|
|
source::{
|
|
captcha_answer::{CaptchaAnswer, CheckCaptchaAnswer},
|
|
local_user::{LocalUser, LocalUserInsertForm},
|
|
person::{Person, PersonInsertForm},
|
|
registration_application::{RegistrationApplication, RegistrationApplicationInsertForm},
|
|
},
|
|
traits::Crud,
|
|
RegistrationMode,
|
|
};
|
|
use lemmy_db_views::structs::{LocalUserView, SiteView};
|
|
use lemmy_utils::{
|
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
|
|
utils::{
|
|
slurs::{check_slurs, check_slurs_opt},
|
|
validation::is_valid_actor_name,
|
|
},
|
|
};
|
|
|
|
#[tracing::instrument(skip(context))]
|
|
pub async fn register(
|
|
data: Json<Register>,
|
|
req: HttpRequest,
|
|
context: Data<LemmyContext>,
|
|
) -> Result<Json<LoginResponse>, LemmyError> {
|
|
let site_view = SiteView::read_local(&mut context.pool()).await?;
|
|
let local_site = site_view.local_site;
|
|
let require_registration_application =
|
|
local_site.registration_mode == RegistrationMode::RequireApplication;
|
|
|
|
if local_site.registration_mode == RegistrationMode::Closed {
|
|
Err(LemmyErrorType::RegistrationClosed)?
|
|
}
|
|
|
|
password_length_check(&data.password)?;
|
|
honeypot_check(&data.honeypot)?;
|
|
|
|
if local_site.require_email_verification && data.email.is_none() {
|
|
Err(LemmyErrorType::EmailRequired)?
|
|
}
|
|
|
|
if local_site.site_setup && require_registration_application && data.answer.is_none() {
|
|
Err(LemmyErrorType::RegistrationApplicationAnswerRequired)?
|
|
}
|
|
|
|
// Make sure passwords match
|
|
if data.password != data.password_verify {
|
|
Err(LemmyErrorType::PasswordsDoNotMatch)?
|
|
}
|
|
|
|
if local_site.site_setup && local_site.captcha_enabled {
|
|
if let Some(captcha_uuid) = &data.captcha_uuid {
|
|
let uuid = uuid::Uuid::parse_str(captcha_uuid)?;
|
|
let check = CaptchaAnswer::check_captcha(
|
|
&mut context.pool(),
|
|
CheckCaptchaAnswer {
|
|
uuid,
|
|
answer: data.captcha_answer.clone().unwrap_or_default(),
|
|
},
|
|
)
|
|
.await?;
|
|
if !check {
|
|
Err(LemmyErrorType::CaptchaIncorrect)?
|
|
}
|
|
} else {
|
|
Err(LemmyErrorType::CaptchaIncorrect)?
|
|
}
|
|
}
|
|
|
|
let slur_regex = local_site_to_slur_regex(&local_site);
|
|
check_slurs(&data.username, &slur_regex)?;
|
|
check_slurs_opt(&data.answer, &slur_regex)?;
|
|
|
|
let actor_keypair = generate_actor_keypair()?;
|
|
is_valid_actor_name(&data.username, local_site.actor_name_max_length as usize)?;
|
|
let actor_id = generate_local_apub_endpoint(
|
|
EndpointType::Person,
|
|
&data.username,
|
|
&context.settings().get_protocol_and_hostname(),
|
|
)?;
|
|
|
|
if let Some(email) = &data.email {
|
|
if LocalUser::is_email_taken(&mut context.pool(), email).await? {
|
|
Err(LemmyErrorType::EmailAlreadyExists)?
|
|
}
|
|
}
|
|
|
|
// We have to create both a person, and local_user
|
|
|
|
// Register the new person
|
|
let person_form = PersonInsertForm::builder()
|
|
.name(data.username.clone())
|
|
.actor_id(Some(actor_id.clone()))
|
|
.private_key(Some(actor_keypair.private_key))
|
|
.public_key(actor_keypair.public_key)
|
|
.inbox_url(Some(generate_inbox_url(&actor_id)?))
|
|
.shared_inbox_url(Some(generate_shared_inbox_url(context.settings())?))
|
|
.instance_id(site_view.site.instance_id)
|
|
.build();
|
|
|
|
// insert the person
|
|
let inserted_person = Person::create(&mut context.pool(), &person_form)
|
|
.await
|
|
.with_lemmy_type(LemmyErrorType::UserAlreadyExists)?;
|
|
|
|
// Automatically set their application as accepted, if they created this with open registration.
|
|
// Also fixes a bug which allows users to log in when registrations are changed to closed.
|
|
let accepted_application = Some(!require_registration_application);
|
|
|
|
// Create the local user
|
|
let local_user_form = LocalUserInsertForm::builder()
|
|
.person_id(inserted_person.id)
|
|
.email(data.email.as_deref().map(str::to_lowercase))
|
|
.password_encrypted(data.password.to_string())
|
|
.show_nsfw(Some(data.show_nsfw))
|
|
.accepted_application(accepted_application)
|
|
.default_listing_type(Some(local_site.default_post_listing_type))
|
|
// If its the initial site setup, they are an admin
|
|
.admin(Some(!local_site.site_setup))
|
|
.build();
|
|
|
|
let inserted_local_user = LocalUser::create(&mut context.pool(), &local_user_form).await?;
|
|
|
|
if local_site.site_setup && require_registration_application {
|
|
// Create the registration application
|
|
let form = RegistrationApplicationInsertForm {
|
|
local_user_id: inserted_local_user.id,
|
|
// We already made sure answer was not null above
|
|
answer: data.answer.clone().expect("must have an answer"),
|
|
};
|
|
|
|
RegistrationApplication::create(&mut context.pool(), &form).await?;
|
|
}
|
|
|
|
// Email the admins, only if email verification is not required
|
|
if local_site.application_email_admins && !local_site.require_email_verification {
|
|
send_new_applicant_email_to_admins(&data.username, &mut context.pool(), context.settings())
|
|
.await?;
|
|
}
|
|
|
|
let mut login_response = LoginResponse {
|
|
jwt: None,
|
|
registration_created: false,
|
|
verify_email_sent: false,
|
|
};
|
|
|
|
// Log the user in directly if the site is not setup, or email verification and application aren't required
|
|
if !local_site.site_setup
|
|
|| (!require_registration_application && !local_site.require_email_verification)
|
|
{
|
|
let jwt = Claims::generate(inserted_local_user.id, req, &context).await?;
|
|
login_response.jwt = Some(jwt);
|
|
} else {
|
|
if local_site.require_email_verification {
|
|
let local_user_view = LocalUserView {
|
|
local_user: inserted_local_user,
|
|
person: inserted_person,
|
|
counts: PersonAggregates::default(),
|
|
};
|
|
// we check at the beginning of this method that email is set
|
|
let email = local_user_view
|
|
.local_user
|
|
.email
|
|
.clone()
|
|
.expect("email was provided");
|
|
|
|
send_verification_email(
|
|
&local_user_view,
|
|
&email,
|
|
&mut context.pool(),
|
|
context.settings(),
|
|
)
|
|
.await?;
|
|
login_response.verify_email_sent = true;
|
|
}
|
|
|
|
if require_registration_application {
|
|
login_response.registration_created = true;
|
|
}
|
|
}
|
|
|
|
Ok(Json(login_response))
|
|
}
|