Fix assumption that is_err always means the local site doesn't exist, which may cause the local site's keypair to be regenerated (#5724)

* Fix assumption that is_err always means the local site doesn't exst, which may cause things like keypairs to be overwritten

* remove use of unstable feature

* fix map_err

* exists query and transaction
This commit is contained in:
dullbananas 2025-06-13 16:12:12 -07:00 committed by GitHub
parent ba0099e7a2
commit 38e87f6dc4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 104 additions and 84 deletions

1
Cargo.lock generated
View file

@ -3794,6 +3794,7 @@ dependencies = [
name = "lemmy_db_views_site" name = "lemmy_db_views_site"
version = "1.0.0-alpha.5" version = "1.0.0-alpha.5"
dependencies = [ dependencies = [
"anyhow",
"chrono", "chrono",
"diesel", "diesel",
"diesel-async", "diesel-async",

View file

@ -25,6 +25,7 @@ full = [
"lemmy_db_views_api_misc/full", "lemmy_db_views_api_misc/full",
"lemmy_db_views_person/full", "lemmy_db_views_person/full",
"lemmy_db_views_readable_federation_state/full", "lemmy_db_views_readable_federation_state/full",
"anyhow",
] ]
ts-rs = ["dep:ts-rs"] ts-rs = ["dep:ts-rs"]
@ -42,3 +43,4 @@ serde = { workspace = true }
serde_with = { workspace = true } serde_with = { workspace = true }
ts-rs = { workspace = true, optional = true } ts-rs = { workspace = true, optional = true }
url = { workspace = true } url = { workspace = true }
anyhow = { workspace = true, optional = true }

View file

@ -40,7 +40,7 @@ impl SiteView {
Ok(local_site) Ok(local_site)
}) })
.await .await
.map_err(|_e: Arc<LemmyError>| LemmyErrorType::LocalSiteNotSetup.into()) .map_err(|e: Arc<LemmyError>| anyhow::anyhow!("err getting local site: {e:?}").into())
} }
} }

View file

@ -1,5 +1,10 @@
use activitypub_federation::http_signatures::generate_actor_keypair; use activitypub_federation::http_signatures::generate_actor_keypair;
use chrono::Utc; use chrono::Utc;
use diesel::{
dsl::{exists, not, select},
query_builder::AsQuery,
};
use diesel_async::{scoped_futures::ScopedFutureExt, RunQueryDsl};
use lemmy_api_utils::utils::generate_inbox_url; use lemmy_api_utils::utils::generate_inbox_url;
use lemmy_db_schema::{ use lemmy_db_schema::{
source::{ source::{
@ -11,8 +16,9 @@ use lemmy_db_schema::{
site::{Site, SiteInsertForm}, site::{Site, SiteInsertForm},
}, },
traits::{ApubActor, Crud}, traits::{ApubActor, Crud},
utils::DbPool, utils::{get_conn, DbPool},
}; };
use lemmy_db_schema_file::schema::local_site;
use lemmy_db_views_site::SiteView; use lemmy_db_views_site::SiteView;
use lemmy_utils::{ use lemmy_utils::{
error::{LemmyErrorExt, LemmyErrorType, LemmyResult}, error::{LemmyErrorExt, LemmyErrorType, LemmyResult},
@ -22,18 +28,23 @@ use tracing::info;
use url::Url; use url::Url;
pub async fn setup_local_site(pool: &mut DbPool<'_>, settings: &Settings) -> LemmyResult<SiteView> { pub async fn setup_local_site(pool: &mut DbPool<'_>, settings: &Settings) -> LemmyResult<SiteView> {
// Check to see if local_site exists let conn = &mut get_conn(pool).await?;
if let Ok(site_view) = SiteView::read_local(pool).await { // Check to see if local_site exists, without the cache wrapper
return Ok(site_view); if select(not(exists(local_site::table.as_query())))
} .get_result(conn)
.await?
{
info!("No Local Site found, creating it."); info!("No Local Site found, creating it.");
let domain = settings let domain = settings
.get_hostname_without_port() .get_hostname_without_port()
.with_lemmy_type(LemmyErrorType::Unknown("must have domain".into()))?; .with_lemmy_type(LemmyErrorType::Unknown("must have domain".into()))?;
conn
.run_transaction(|conn| {
async move {
// Upsert this to the instance table // Upsert this to the instance table
let instance = Instance::read_or_create(pool, domain).await?; let instance = Instance::read_or_create(&mut conn.into(), domain).await?;
if let Some(setup) = &settings.setup { if let Some(setup) = &settings.setup {
let person_keypair = generate_actor_keypair()?; let person_keypair = generate_actor_keypair()?;
@ -50,14 +61,14 @@ pub async fn setup_local_site(pool: &mut DbPool<'_>, settings: &Settings) -> Lem
instance.id, instance.id,
) )
}; };
let person_inserted = Person::create(pool, &person_form).await?; let person_inserted = Person::create(&mut conn.into(), &person_form).await?;
let local_user_form = LocalUserInsertForm { let local_user_form = LocalUserInsertForm {
email: setup.admin_email.clone(), email: setup.admin_email.clone(),
admin: Some(true), admin: Some(true),
..LocalUserInsertForm::new(person_inserted.id, Some(setup.admin_password.clone())) ..LocalUserInsertForm::new(person_inserted.id, Some(setup.admin_password.clone()))
}; };
LocalUser::create(pool, &local_user_form, vec![]).await?; LocalUser::create(&mut conn.into(), &local_user_form, vec![]).await?;
}; };
// Add an entry for the site table // Add an entry for the site table
@ -77,14 +88,14 @@ pub async fn setup_local_site(pool: &mut DbPool<'_>, settings: &Settings) -> Lem
public_key: Some(site_key_pair.public_key), public_key: Some(site_key_pair.public_key),
..SiteInsertForm::new(name, instance.id) ..SiteInsertForm::new(name, instance.id)
}; };
let site = Site::create(pool, &site_form).await?; let site = Site::create(&mut conn.into(), &site_form).await?;
// Finally create the local_site row // Finally create the local_site row
let local_site_form = LocalSiteInsertForm { let local_site_form = LocalSiteInsertForm {
site_setup: Some(settings.setup.is_some()), site_setup: Some(settings.setup.is_some()),
..LocalSiteInsertForm::new(site.id) ..LocalSiteInsertForm::new(site.id)
}; };
let local_site = LocalSite::create(pool, &local_site_form).await?; let local_site = LocalSite::create(&mut conn.into(), &local_site_form).await?;
// Create the rate limit table // Create the rate limit table
let local_site_rate_limit_form = if cfg!(debug_assertions) { let local_site_rate_limit_form = if cfg!(debug_assertions) {
@ -104,7 +115,13 @@ pub async fn setup_local_site(pool: &mut DbPool<'_>, settings: &Settings) -> Lem
// tests to pass, and there's no way to live update the rate limits without restarting the // tests to pass, and there's no way to live update the rate limits without restarting the
// server. // server.
// This can be removed once live rate limits are enabled. // This can be removed once live rate limits are enabled.
LocalSiteRateLimit::create(pool, &local_site_rate_limit_form).await?; LocalSiteRateLimit::create(&mut conn.into(), &local_site_rate_limit_form).await?;
Ok(())
}
.scope_boxed()
})
.await?;
}
SiteView::read_local(pool).await SiteView::read_local(pool).await
} }