summaryrefslogtreecommitdiffstats
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/auth-service/src/server/grpc/auth.rs22
-rw-r--r--crates/auth-service/src/server/routes/authorised.rs12
-rw-r--r--crates/sellershut/Cargo.toml2
-rw-r--r--crates/sellershut/src/cnfg.rs1
-rw-r--r--crates/sellershut/src/entity/user.rs91
-rw-r--r--crates/sellershut/src/state.rs93
-rw-r--r--crates/users-service/src/server/manager.rs30
7 files changed, 158 insertions, 93 deletions
diff --git a/crates/auth-service/src/server/grpc/auth.rs b/crates/auth-service/src/server/grpc/auth.rs
index 87113a5..18e7546 100644
--- a/crates/auth-service/src/server/grpc/auth.rs
+++ b/crates/auth-service/src/server/grpc/auth.rs
@@ -3,8 +3,8 @@ use std::str::FromStr;
use jsonwebtoken::DecodingKey;
use sellershut_core::{
auth::{
- RegisterUserRequest, RegisterUserResponse, ValidationRequest, ValidationResponse,
- auth_server::Auth,
+ GetPrivateKeyRequest, GetPrivateKeyResponse, RegisterUserRequest, RegisterUserResponse,
+ ValidationRequest, ValidationResponse, auth_server::Auth,
},
users::CreateUserRequest,
};
@@ -136,4 +136,22 @@ impl Auth for AppHandle {
auth_id: user.id.to_string(),
}))
}
+
+ async fn get_private_key(
+ &self,
+ request: Request<GetPrivateKeyRequest>,
+ ) -> Result<Response<GetPrivateKeyResponse>, Status> {
+ let email = request.into_inner().email;
+
+ let private_key = sqlx::query_scalar!(
+ "select private_key from auth_user where email = $1
+ ",
+ uuid,
+ )
+ .fetch_one(&self.services.postgres)
+ .await
+ .unwrap();
+
+ Ok(Response::new(GetPrivateKeyResponse { private_key }))
+ }
}
diff --git a/crates/auth-service/src/server/routes/authorised.rs b/crates/auth-service/src/server/routes/authorised.rs
index 552f6c1..63c5a49 100644
--- a/crates/auth-service/src/server/routes/authorised.rs
+++ b/crates/auth-service/src/server/routes/authorised.rs
@@ -9,7 +9,9 @@ use axum::{
use axum_extra::{TypedHeader, headers};
use oauth2::{AuthorizationCode, TokenResponse};
use reqwest::{StatusCode, header::SET_COOKIE};
-use sellershut_core::auth::{RegisterUserRequest, auth_server::Auth, register_user_request::AccountDetails};
+use sellershut_core::auth::{
+ RegisterUserRequest, auth_server::Auth, register_user_request::AccountDetails,
+};
use serde::{Deserialize, Serialize};
use sqlx::types::uuid;
use time::OffsetDateTime;
@@ -123,10 +125,14 @@ pub async fn login_authorised(
account: Some(AccountDetails {
provider_id: provider,
provider_user_id: data.id,
- })
+ }),
};
- let resp = state.register_user(request.into_request()).await.unwrap().into_inner();
+ let resp = state
+ .register_user(request.into_request())
+ .await
+ .unwrap()
+ .into_inner();
Uuid::parse_str(&resp.auth_id).unwrap()
};
diff --git a/crates/sellershut/Cargo.toml b/crates/sellershut/Cargo.toml
index d742086..bc58b8d 100644
--- a/crates/sellershut/Cargo.toml
+++ b/crates/sellershut/Cargo.toml
@@ -19,7 +19,7 @@ enum_delegate = "0.2.0"
futures-util.workspace = true
nanoid.workspace = true
openssl = "0.10.73"
-sellershut-core = { workspace = true, features = ["auth"] }
+sellershut-core = { workspace = true, features = ["auth", "users"] }
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
sha2 = "0.10.9"
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)
diff --git a/crates/users-service/src/server/manager.rs b/crates/users-service/src/server/manager.rs
index 05ee4fe..add385f 100644
--- a/crates/users-service/src/server/manager.rs
+++ b/crates/users-service/src/server/manager.rs
@@ -1,7 +1,7 @@
use prost::Message;
use sellershut_core::users::{
- CompleteUserRequest, CreateUserRequest, CreateUserResponse, User, UserType,
- users_service_server::UsersService,
+ CompleteUserRequest, CreateUserRequest, CreateUserResponse, GetUserRequest, GetUserResponse,
+ User, UserType, users_service_server::UsersService,
};
use stack_up::redis::AsyncCommands;
use time::OffsetDateTime;
@@ -132,4 +132,30 @@ impl UsersService for AppHandle {
Ok(Response::new(user))
}
+
+ async fn get_user(
+ &self,
+ request: Request<GetUserRequest>,
+ ) -> Result<Response<GetUserResponse>, Status> {
+ let inner = request.into_inner().id;
+
+ let mut cache = self.cache().await?;
+ let resp = cache.get::<_, Vec<u8>>(inner).await.unwrap();
+ // TODO: read from cache
+
+ let user = sqlx::query_as!(DbUser, "select * from profile where id = $1", inner)
+ .fetch_optional(&self.services.postgres)
+ .await
+ .map_err(|_e| Status::internal("storage error"))?;
+ // TODO: save to cache
+
+ let resp = GetUserResponse {
+ user: match user {
+ Some(user) => Some(User::try_from(user)?),
+ None => None,
+ },
+ };
+
+ Ok(Response::new(resp))
+ }
}