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