diff options
Diffstat (limited to 'crates/sellershut/src')
-rw-r--r-- | crates/sellershut/src/cnfg.rs | 1 | ||||
-rw-r--r-- | crates/sellershut/src/entity/user.rs | 91 | ||||
-rw-r--r-- | crates/sellershut/src/state.rs | 93 |
3 files changed, 100 insertions, 85 deletions
diff --git a/crates/sellershut/src/cnfg.rs b/crates/sellershut/src/cnfg.rs index 82cd34b..6fe9c39 100644 --- a/crates/sellershut/src/cnfg.rs +++ b/crates/sellershut/src/cnfg.rs @@ -6,4 +6,5 @@ pub struct LocalConfig { pub hostname: String, pub instance_name: String, pub auth_endpoint: String, + pub users_endpoint: String, } diff --git a/crates/sellershut/src/entity/user.rs b/crates/sellershut/src/entity/user.rs index 6fb12ae..5c9ac4f 100644 --- a/crates/sellershut/src/entity/user.rs +++ b/crates/sellershut/src/entity/user.rs @@ -7,27 +7,20 @@ use activitypub_federation::{ activity_sending::SendActivityTask, config::Data, fetch::object_id::ObjectId, - http_signatures::generate_actor_keypair, kinds::actor::{ApplicationType, GroupType, OrganizationType, PersonType, ServiceType}, protocol::{context::WithContext, public_key::PublicKey}, traits::{Activity, Actor, Object}, }; use async_trait::async_trait; use serde::{Deserialize, Serialize}; -use stack_up::Environment; use time::OffsetDateTime; use tracing::trace; use url::Url; -use uuid::Uuid; -use crate::{ - error::AppError, - state::{AppHandle, Services}, -}; +use crate::{error::AppError, state::AppHandle}; #[derive(PartialEq, Clone, Debug)] pub struct User { - pub id: String, pub username: String, pub ap_id: ObjectId<User>, pub private_key: Option<String>, @@ -67,6 +60,22 @@ pub enum UserType { Service(ServiceType), } +impl From<sellershut_core::users::UserType> for UserType { + fn from(value: sellershut_core::users::UserType) -> Self { + match value { + sellershut_core::users::UserType::Person => Self::Person(PersonType::default()), + sellershut_core::users::UserType::Application => { + Self::Application(ApplicationType::default()) + } + sellershut_core::users::UserType::Group => Self::Group(GroupType::default()), + sellershut_core::users::UserType::Organization => { + Self::Organization(OrganizationType::default()) + } + sellershut_core::users::UserType::Service => Self::Service(ServiceType::default()), + } + } +} + impl Display for UserType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( @@ -101,7 +110,6 @@ impl TryFrom<DbUser> for User { type Error = AppError; fn try_from(value: DbUser) -> Result<Self, Self::Error> { Ok(Self { - id: value.id, username: value.username, ap_id: Url::parse(&value.ap_id)?.into(), private_key: value.private_key, @@ -119,58 +127,18 @@ impl TryFrom<DbUser> for User { } impl User { - pub async fn new( - username: &str, - hostname: &str, - services: &Services, - environment: Environment, - ) -> Result<Self, AppError> { - trace!(username = ?username, "checking for system user"); - - let user = sqlx::query_as!( - DbUser, - "select * from account where username = $1 and local = $2", - username, - true - ) - .fetch_optional(&services.postgres) - .await?; - - if let Some(user) = user { - trace!(username = ?username, "system user exists"); - return Self::try_from(user); - } else { - trace!(username = ?username, "system user does not exist. creating"); - } - - trace!("creating keypair for new user"); - let keys = generate_actor_keypair()?; - let stub = &format!( - "{}://{hostname}/users/{username}", - match environment { - Environment::Development => "http", - Environment::Production => "https", - } - ); - let id = Uuid::now_v7(); - - let kind = UserType::Service(ServiceType::Service); - - trace!(id = ?id, "creating a new user"); - let user = sqlx::query_as!( - DbUser, - "insert into account (id, username, ap_id, private_key, public_key, inbox, outbox, local, user_type) values ($1, $2, $3, $4, $5, $6, $7, $8, $9) returning *", - id, - username, - stub, - keys.private_key, - keys.public_key, - &format!("{stub}/inbox"), - &format!("{stub}/outbox"), - true, - kind.to_string(), - ).fetch_one(&services.postgres).await?; - Self::try_from(user) + pub fn new(pk: &str, user: sellershut_core::users::User) -> Result<Self, AppError> { + Ok(Self { + username: user.username.clone(), + ap_id: Url::parse(&user.id)?.into(), + private_key: Some(pk.to_owned()), + description: user.description.clone(), + user_type: user.user_type().into(), + public_key: user.public_key, + inbox: Url::parse(&user.inbox)?, + outbox: Some(Url::parse(&user.outbox)?), + avatar_url: None, + }) } pub(crate) async fn send<A>( @@ -317,7 +285,6 @@ impl Object for User { #[doc = " create and update, so an `upsert` operation should be used."] async fn from_json(json: Self::Kind, data: &Data<Self::DataType>) -> Result<Self, Self::Error> { Ok(Self { - id: todo!(), username: todo!(), ap_id: todo!(), private_key: todo!(), diff --git a/crates/sellershut/src/state.rs b/crates/sellershut/src/state.rs index cc58507..539217a 100644 --- a/crates/sellershut/src/state.rs +++ b/crates/sellershut/src/state.rs @@ -1,10 +1,15 @@ use std::{ops::Deref, sync::Arc}; use activitypub_federation::config::FederationConfig; -use sellershut_core::auth::auth_client::AuthClient; +use sellershut_core::{ + auth::{GetPrivateKeyRequest, RegisterUserRequest, auth_client::AuthClient}, + users::{ + CompleteUserRequest, GetUserRequest, UserType, users_service_client::UsersServiceClient, + }, +}; use sqlx::PgPool; use stack_up::{Configuration, Environment}; -use tonic::transport::Endpoint; +use tonic::{IntoRequest, transport::Endpoint}; use tracing::error; use crate::{ @@ -35,6 +40,7 @@ pub struct AppState { pub environment: Environment, pub protocol: Arc<str>, pub auth_client: AuthClient<Intercepted>, + pub users_client: UsersServiceClient<Intercepted>, } impl AppState { @@ -44,30 +50,74 @@ impl AppState { ) -> Result<FederationConfig<AppHandle>, AppError> { let hut_config: LocalConfig = serde_json::from_value(configuration.misc.clone())?; - let user_id = &format!( - "{}://{}/users/{}", - match configuration.application.env { - Environment::Development => "http", - Environment::Production => "https", - }, - hut_config.hostname, - hut_config.instance_name + let protocol = match configuration.application.env { + Environment::Development => "http", + Environment::Production => "https", + }; + + let user_id = format!( + "{protocol}://{}/users/{}", + hut_config.hostname, hut_config.instance_name ); - let user = User::new( - &hut_config.instance_name, - &hut_config.hostname, - &services, - configuration.application.env, - ) - .await?; + let channel = Endpoint::new(hut_config.users_endpoint.to_string())? + .connect() + .await + .inspect_err(|e| error!("could not connect to users service: {e}"))?; + + let mut users_client = UsersServiceClient::with_interceptor(channel, MyInterceptor); let channel = Endpoint::new(hut_config.auth_endpoint.to_string())? .connect() .await .inspect_err(|e| error!("could not connect to auth service: {e}"))?; - let auth_client = AuthClient::with_interceptor(channel, MyInterceptor); + let mut auth_client = AuthClient::with_interceptor(channel, MyInterceptor); + + let user = if let Some(user) = users_client + .get_user( + GetUserRequest { + id: user_id.clone(), + } + .into_request(), + ) + .await? + .into_inner() + .user + { + user + } else { + let rg = auth_client + .register_user(RegisterUserRequest { + email: "email@example.com".into(), + account: None, + }) + .await? + .into_inner(); + + users_client + .complete_user(CompleteUserRequest { + id: rg.profile_id, + username: hut_config.instance_name.to_owned(), + inbox: format!("{user_id}/inbox"), + outbox: format!("{user_id}/outbox"), + local: true, + user_type: UserType::Service.into(), + ..Default::default() + }) + .await? + .into_inner() + }; + + let pk = auth_client + .get_private_key(GetPrivateKeyRequest { + email: user.email().to_owned(), + }) + .await? + .into_inner() + .private_key; + + let user = User::new(&pk, user)?; let config = FederationConfig::builder() .domain(&hut_config.hostname) @@ -75,12 +125,9 @@ impl AppState { .app_data(AppHandle(Arc::new(Self { services, environment: configuration.application.env, - protocol: match configuration.application.env { - Environment::Development => "http", - Environment::Production => "https", - } - .into(), + protocol: protocol.into(), auth_client, + users_client, }))) // .url_verifier(Box::new(MyUrlVerifier())) .debug(configuration.application.env == Environment::Development) |