add request proxying and basic user auth
This commit is contained in:
		
							parent
							
								
									bfb0a1d1b0
								
							
						
					
					
						commit
						274c527ade
					
				
					 31 changed files with 541 additions and 36 deletions
				
			
		|  | @ -1,3 +1,4 @@ | |||
| use rsa::{RsaPublicKey, RsaPrivateKey}; | ||||
| use sqlx::{Pool, Postgres}; | ||||
| 
 | ||||
| use crate::config::Config; | ||||
|  | @ -5,4 +6,6 @@ use crate::config::Config; | |||
| pub struct AppState { | ||||
|     pub pool: Pool<Postgres>, | ||||
|     pub config: Config, | ||||
|     pub public_key: RsaPublicKey, | ||||
|     pub private_key: RsaPrivateKey, | ||||
| } | ||||
|  |  | |||
							
								
								
									
										40
									
								
								chat/src/http/api/guilds/create_guild.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								chat/src/http/api/guilds/create_guild.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,40 @@ | |||
| use std::sync::Arc; | ||||
| 
 | ||||
| use axum::{Extension, Json}; | ||||
| use foxchat::{ | ||||
|     http::ApiError, | ||||
|     model::{http::guild::CreateGuildParams, Guild, user::PartialUser}, | ||||
|     FoxError, | ||||
| }; | ||||
| use ulid::Ulid; | ||||
| 
 | ||||
| use crate::{app_state::AppState, fed::FoxRequestData, model::user::User}; | ||||
| 
 | ||||
| pub async fn create_guild( | ||||
|     Extension(state): Extension<Arc<AppState>>, | ||||
|     request: FoxRequestData, | ||||
|     Json(params): Json<CreateGuildParams>, | ||||
| ) -> Result<Json<Guild>, ApiError> { | ||||
|     let user_id = request.user_id.ok_or(FoxError::MissingUser)?; | ||||
| 
 | ||||
|     let user = User::get(&state, &request.instance, user_id).await?; | ||||
| 
 | ||||
|     let guild = sqlx::query!( | ||||
|         "insert into guilds (id, owner_id, name) values ($1, $2, $3) returning *", | ||||
|         Ulid::new().to_string(), | ||||
|         user.id, | ||||
|         params.name | ||||
|     ) | ||||
|     .fetch_one(&state.pool) | ||||
|     .await?; | ||||
| 
 | ||||
|     Ok(Json(Guild { | ||||
|         id: guild.id, | ||||
|         name: guild.name, | ||||
|         owner: PartialUser { | ||||
|             id: user.id, | ||||
|             username: user.username, | ||||
|             instance: request.instance.domain, | ||||
|         } | ||||
|     })) | ||||
| } | ||||
							
								
								
									
										8
									
								
								chat/src/http/api/guilds/mod.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								chat/src/http/api/guilds/mod.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | |||
| mod create_guild; | ||||
| 
 | ||||
| use axum::{Router, routing::post}; | ||||
| 
 | ||||
| pub fn router() -> Router { | ||||
|     Router::new() | ||||
|         .route("/_fox/chat/guilds", post(create_guild::create_guild)) | ||||
| } | ||||
							
								
								
									
										7
									
								
								chat/src/http/api/mod.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								chat/src/http/api/mod.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,7 @@ | |||
| use axum::Router; | ||||
| 
 | ||||
| pub mod guilds; | ||||
| 
 | ||||
| pub fn router() -> Router { | ||||
|     Router::new().merge(guilds::router()) | ||||
| } | ||||
|  | @ -16,17 +16,15 @@ use rsa::{ | |||
| use tracing::error; | ||||
| use ulid::Ulid; | ||||
| 
 | ||||
| use crate::{app_state::AppState, fed::FoxSignatureData, model::instance::Instance}; | ||||
| use crate::{app_state::AppState, fed::FoxSignatureData}; | ||||
| 
 | ||||
| pub async fn post_hello( | ||||
|     Extension(state): Extension<Arc<AppState>>, | ||||
|     signature: FoxSignatureData, | ||||
|     Json(data): Json<HelloRequest>, | ||||
| ) -> Result<Json<HelloResponse>, ApiError> { | ||||
|     let instance = Instance::get(&state.pool).await?; | ||||
| 
 | ||||
|     let node = fed::get::<NodeResponse>( | ||||
|         &instance.private_key, | ||||
|         &state.private_key, | ||||
|         &state.config.domain, | ||||
|         &data.host, | ||||
|         "/_fox/ident/node", | ||||
|  | @ -68,7 +66,7 @@ pub async fn post_hello( | |||
|     .await?; | ||||
| 
 | ||||
|     Ok(Json(HelloResponse { | ||||
|         public_key: instance | ||||
|         public_key: state | ||||
|             .public_key | ||||
|             .to_pkcs1_pem(rsa::pkcs8::LineEnding::CR) | ||||
|             .wrap_err("formatting instance public key")?, | ||||
|  |  | |||
|  | @ -1,16 +1,23 @@ | |||
| mod api; | ||||
| mod hello; | ||||
| 
 | ||||
| use crate::{app_state::AppState, config::Config}; | ||||
| use crate::{app_state::AppState, config::Config, model::instance::Instance}; | ||||
| use axum::{routing::post, Extension, Router}; | ||||
| use sqlx::{Pool, Postgres}; | ||||
| use std::sync::Arc; | ||||
| use tower_http::trace::TraceLayer; | ||||
| 
 | ||||
| pub fn new(pool: Pool<Postgres>, config: Config) -> Router { | ||||
|     let app_state = Arc::new(AppState { pool, config }); | ||||
| pub fn new(pool: Pool<Postgres>, config: Config, instance: Instance) -> Router { | ||||
|     let app_state = Arc::new(AppState { | ||||
|         pool, | ||||
|         config, | ||||
|         public_key: instance.public_key, | ||||
|         private_key: instance.private_key, | ||||
|     }); | ||||
| 
 | ||||
|     let app = Router::new() | ||||
|         .route("/_fox/chat/hello", post(hello::post_hello)) | ||||
|         .merge(api::router()) | ||||
|         .layer(TraceLayer::new_for_http()) | ||||
|         .layer(Extension(app_state)); | ||||
| 
 | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ mod fed; | |||
| mod http; | ||||
| mod model; | ||||
| 
 | ||||
| use crate::config::Config; | ||||
| use crate::{config::Config, model::instance::Instance}; | ||||
| use clap::{Parser, Subcommand}; | ||||
| use eyre::Result; | ||||
| use std::net::{Ipv4Addr, SocketAddrV4}; | ||||
|  | @ -64,8 +64,9 @@ async fn main_web(config: Config) -> Result<()> { | |||
|     db::init_instance(&pool).await?; | ||||
|     info!("Initialized instance data!"); | ||||
| 
 | ||||
|     let instance = Instance::get(&pool).await?; | ||||
|     let port = config.port; | ||||
|     let app = http::new(pool, config); | ||||
|     let app = http::new(pool, config, instance); | ||||
| 
 | ||||
|     let listener = TcpListener::bind(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), port)).await?; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,2 +1,3 @@ | |||
| pub mod instance; | ||||
| pub mod identity_instance; | ||||
| pub mod user; | ||||
|  |  | |||
							
								
								
									
										60
									
								
								chat/src/model/user.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								chat/src/model/user.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,60 @@ | |||
| use std::sync::Arc; | ||||
| 
 | ||||
| use eyre::Result; | ||||
| use foxchat::{fed, model::User as HttpUser}; | ||||
| use ulid::Ulid; | ||||
| 
 | ||||
| use crate::app_state::AppState; | ||||
| 
 | ||||
| use super::identity_instance::IdentityInstance; | ||||
| 
 | ||||
| pub struct User { | ||||
|     pub id: String, | ||||
|     pub instance_id: String, | ||||
|     pub remote_user_id: String, | ||||
|     pub username: String, | ||||
|     pub avatar: Option<String>, | ||||
| } | ||||
| 
 | ||||
| impl User { | ||||
|     pub async fn get( | ||||
|         state: &Arc<AppState>, | ||||
|         instance: &IdentityInstance, | ||||
|         remote_id: String, | ||||
|     ) -> Result<User> { | ||||
|         if let Some(user) = sqlx::query_as!( | ||||
|             User, | ||||
|             "select * from users where instance_id = $1 and remote_user_id = $2", | ||||
|             instance.id, | ||||
|             remote_id | ||||
|         ) | ||||
|         .fetch_optional(&state.pool) | ||||
|         .await? | ||||
|         { | ||||
|             return Ok(user); | ||||
|         } | ||||
| 
 | ||||
|         let http_user = fed::get::<HttpUser>( | ||||
|             &state.private_key, | ||||
|             &state.config.domain, | ||||
|             &instance.domain, | ||||
|             &format!("/_fox/ident/users/{}", remote_id), | ||||
|             None, | ||||
|         ) | ||||
|         .await?; | ||||
| 
 | ||||
|         let user = sqlx::query_as!( | ||||
|             User, | ||||
|             "insert into users (id, instance_id, remote_user_id, username, avatar) values ($1, $2, $3, $4, $5) returning *", | ||||
|             Ulid::new().to_string(), | ||||
|             instance.id, | ||||
|             http_user.id, | ||||
|             http_user.username, | ||||
|             http_user.avatar_url | ||||
|         ) | ||||
|         .fetch_one(&state.pool) | ||||
|         .await?; | ||||
| 
 | ||||
|         Ok(user) | ||||
|     } | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue