diff options
Diffstat (limited to 'crates/auth-service/src/server')
-rw-r--r-- | crates/auth-service/src/server/grpc/auth.rs | 95 | ||||
-rw-r--r-- | crates/auth-service/src/server/keys.rs | 3 | ||||
-rw-r--r-- | crates/auth-service/src/server/routes/authorised.rs | 103 |
3 files changed, 118 insertions, 83 deletions
diff --git a/crates/auth-service/src/server/grpc/auth.rs b/crates/auth-service/src/server/grpc/auth.rs index fb00291..87113a5 100644 --- a/crates/auth-service/src/server/grpc/auth.rs +++ b/crates/auth-service/src/server/grpc/auth.rs @@ -1,12 +1,30 @@ use std::str::FromStr; use jsonwebtoken::DecodingKey; -use sellershut_core::auth::{ValidationRequest, ValidationResponse, auth_server::Auth}; +use sellershut_core::{ + auth::{ + RegisterUserRequest, RegisterUserResponse, ValidationRequest, ValidationResponse, + auth_server::Auth, + }, + users::CreateUserRequest, +}; +use serde::{Deserialize, Serialize}; +use time::OffsetDateTime; use tonic::{Request, Response, Status, async_trait}; use tower_sessions::{SessionStore, session::Id}; -use tracing::warn; +use tracing::{error, warn}; +use uuid::Uuid; -use crate::{auth::Claims, state::AppHandle}; +use crate::{auth::Claims, server::keys::generate_actor_keypair, state::AppHandle}; + +#[derive(Debug, Deserialize, Serialize)] +pub struct DbUser { + pub id: Uuid, + pub email: String, + pub private_key: String, + pub created_at: OffsetDateTime, + pub updated_at: OffsetDateTime, +} #[async_trait] impl Auth for AppHandle { @@ -47,4 +65,75 @@ impl Auth for AppHandle { } } } + + async fn register_user( + &self, + request: Request<RegisterUserRequest>, + ) -> Result<Response<RegisterUserResponse>, Status> { + let keys = generate_actor_keypair() + .map_err(|_e| Status::internal("keys could not be generated"))?; + let uuid = Uuid::now_v7(); + let mut transaction = self + .services + .postgres + .begin() + .await + .inspect_err(|e| error!("{e}")) + .map_err(|_| Status::internal("db error"))?; + let user_data = request.into_inner(); + + let user = sqlx::query_as!( + DbUser, + "insert into auth_user (id, email, private_key) values ($1, $2, $3) + on conflict (email) do update + set email = excluded.email + returning *; + ", + uuid, + user_data.email, + keys.private_key, + ) + .fetch_one(&mut *transaction) + .await + .unwrap(); + + if let Some(ref account) = user_data.account { + sqlx::query_as!( + DbUser, + "with upsert as ( + insert into oauth_account (provider_id, provider_user_id, user_id) values ($1, $2, $3) + on conflict (provider_id, provider_user_id) do update + set provider_id = excluded.provider_id -- no-op + returning user_id + ) + select u.* + from upsert + join auth_user u on u.id = upsert.user_id; + ", + account.provider_id, + account.provider_user_id, + user.id + ) + .fetch_one(&mut *transaction) + .await + .unwrap(); + } + + let user_request = CreateUserRequest { + email: user_data.email.to_owned(), + public_key: keys.public_key, + avatar: None, + }; + + let mut profile_client = self.users_client.clone(); + let resp = profile_client.create_user(user_request).await?.into_inner(); + transaction.commit().await.unwrap(); + + let user_id = resp.temp_id; + + Ok(Response::new(RegisterUserResponse { + profile_id: user_id, + auth_id: user.id.to_string(), + })) + } } diff --git a/crates/auth-service/src/server/keys.rs b/crates/auth-service/src/server/keys.rs index 5c9ee43..d11463e 100644 --- a/crates/auth-service/src/server/keys.rs +++ b/crates/auth-service/src/server/keys.rs @@ -1,7 +1,6 @@ use rsa::{ + RsaPrivateKey, RsaPublicKey, pkcs8::{EncodePrivateKey, EncodePublicKey, LineEnding}, - RsaPrivateKey, - RsaPublicKey, }; use crate::error::AppError; diff --git a/crates/auth-service/src/server/routes/authorised.rs b/crates/auth-service/src/server/routes/authorised.rs index b4c2e00..9b97cd2 100644 --- a/crates/auth-service/src/server/routes/authorised.rs +++ b/crates/auth-service/src/server/routes/authorised.rs @@ -9,10 +9,14 @@ use axum::{ use axum_extra::{TypedHeader, headers}; use oauth2::{AuthorizationCode, TokenResponse}; use reqwest::{StatusCode, header::SET_COOKIE}; -use sellershut_core::users::CreateUserRequest; +use sellershut_core::{ + auth::{RegisterUserRequest, auth_server::Auth, register_user_request::AccountDetails}, + users::CreateUserRequest, +}; use serde::{Deserialize, Serialize}; use sqlx::types::uuid; use time::OffsetDateTime; +use tonic::IntoRequest; use tower_sessions::{ SessionStore, session::{Id, Record}, @@ -23,7 +27,8 @@ use crate::{ auth::Claims, error::AppError, server::{ - csrf_token_validation::csrf_token_validation_workflow, keys::generate_actor_keypair, routes::Provider, OAUTH_CSRF_COOKIE + OAUTH_CSRF_COOKIE, csrf_token_validation::csrf_token_validation_workflow, + grpc::auth::DbUser, keys::generate_actor_keypair, routes::Provider, }, state::AppHandle, }; @@ -35,7 +40,7 @@ pub struct AuthRequest { pub state: String, } -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, Clone)] struct User { id: String, avatar: Option<String>, @@ -45,15 +50,6 @@ struct User { email: String, } -#[derive(Debug, Deserialize, Serialize)] -struct DbUser { - id: Uuid, - email: String, - private_key: String, - created_at: OffsetDateTime, - updated_at: OffsetDateTime, -} - /// The cookie to store the session id for user information. const SESSION_COOKIE: &str = "info"; const SESSION_DATA_KEY: &str = "data"; @@ -102,8 +98,6 @@ pub async fn login_authorised( // Create a new session filled with user data let session_id = Id(i128::from_le_bytes(uuid::Uuid::new_v4().to_bytes_le())); - let mut transaction = state.services.postgres.begin().await?; - let user = sqlx::query_as!( DbUser, " @@ -120,53 +114,29 @@ pub async fn login_authorised( provider, user_data.id ) - .fetch_optional(&mut *transaction) + .fetch_optional(&state.services.postgres) .await?; - let keys = generate_actor_keypair()?; - let user = if let Some(user) = user { - user + user.id } else { - let uuid = uuid::Uuid::now_v7(); - let user = sqlx::query_as!( - DbUser, - "insert into auth_user (id, email, private_key) values ($1, $2, $3) - on conflict (email) do update - set email = excluded.email - returning *; - ", - uuid, - user_data.email, - keys.private_key, - ) - .fetch_one(&mut *transaction) - .await?; - - sqlx::query_as!( - DbUser, - "with upsert as ( - insert into oauth_account (provider_id, provider_user_id, user_id) values ($1, $2, $3) - on conflict (provider_id, provider_user_id) do update - set provider_id = excluded.provider_id -- no-op - returning user_id - ) - select u.* - from upsert - join auth_user u on u.id = upsert.user_id; - ", - provider, - user_data.id, - user.id - ) - .fetch_one(&mut *transaction) - .await? + let data = user_data.clone(); + let request = RegisterUserRequest { + email: data.email, + account: Some(AccountDetails { + provider_id: provider, + provider_user_id: data.id, + }) + }; + + let resp = state.register_user(request.into_request()).await.unwrap().into_inner(); + Uuid::parse_str(&resp.auth_id).unwrap() }; let exp = OffsetDateTime::now_utc() + Duration::from_secs(15 * 60); let claims = Claims { - sub: user.id, + sub: user, exp: exp.unix_timestamp(), iss: "sellershut".to_owned(), sid: session_id.to_string(), @@ -182,18 +152,6 @@ pub async fn login_authorised( ), )?; - - let user_request = CreateUserRequest { - email: user_data.email.to_owned(), - avatar: user_data.avatar.as_ref().map(|value| { - format!( - "https://cdn.discordapp.com/avatars/{}/{value}", - user_data.id - ) - }), - public_key: keys.public_key, - }; - store .create(&mut Record { id: session_id, @@ -210,31 +168,20 @@ pub async fn login_authorised( sqlx::query!( "insert into token (user_id, token, session_id) values ($1, $2, $3)", - user.id, + user, token, session_id.to_string() ) - .execute(&mut *transaction) + .execute(&state.services.postgres) .await?; let cookie = format!("{SESSION_COOKIE}={session_id}; SameSite=Lax; HttpOnly; Secure; Path=/"); - let mut profile_client = state.users_client.clone(); - let resp = profile_client.create_user(user_request).await?.into_inner(); - - let user_id = resp.temp_id; - let mut headers = HeaderMap::new(); headers.insert( SET_COOKIE, cookie.parse().context("failed to parse cookie")?, ); - transaction.commit().await?; - - Ok(( - headers, - Redirect::to(&format!("/?user={user_id}&token={token}")), - ) - .into_response()) + Ok((headers, Redirect::to(&format!("/?token={token}"))).into_response()) } |