diff --git a/rfd-api/src/endpoints/login/oauth/client.rs b/rfd-api/src/endpoints/login/oauth/client.rs new file mode 100644 index 0000000..8a72caa --- /dev/null +++ b/rfd-api/src/endpoints/login/oauth/client.rs @@ -0,0 +1,190 @@ +use dropshot::{endpoint, RequestContext, HttpError, HttpResponseOk, Path, TypedBody}; +use rfd_model::{OAuthClient, OAuthClientSecret}; +use schemars::JsonSchema; +use serde::Deserialize; +use tracing::instrument; +use uuid::Uuid; + +use crate::{context::ApiContext, ApiCaller}; + +/// Create a new OAuth Client +#[endpoint { + method = POST, + path = "/oauth/client" +}] +#[instrument(skip(rqctx), fields(request_id = rqctx.request_id), err(Debug))] +pub async fn create_oauth_client( + rqctx: RequestContext, +) -> Result, HttpError> { + let ctx = rqctx.context(); + let auth = ctx.authn_token(&rqctx).await?; + let caller = ctx.get_caller(&auth).await?; + create_oauth_client_op(ctx, &caller).await +} + +#[instrument(skip(ctx, caller), fields(caller = ?caller.id), err(Debug))] +async fn create_oauth_client_op( + ctx: &ApiContext, + caller: &ApiCaller, +) -> Result, HttpError> { + unimplemented!() +} + +#[derive(Debug, Clone, Deserialize, JsonSchema)] +pub struct DeleteOAuthClientPath { + pub client_id: Uuid, +} + +/// Delete a OAuth Client +#[endpoint { + method = DELETE, + path = "/oauth/client/{client_id}" +}] +#[instrument(skip(rqctx), fields(request_id = rqctx.request_id), err(Debug))] +pub async fn delete_oauth_client( + rqctx: RequestContext, + path: Path +) -> Result, HttpError> { + let ctx = rqctx.context(); + let auth = ctx.authn_token(&rqctx).await?; + let caller = ctx.get_caller(&auth).await?; + delete_oauth_client_op(ctx, &caller, &path.into_inner()).await +} + +#[instrument(skip(ctx, caller), fields(caller = ?caller.id), err(Debug))] +async fn delete_oauth_client_op( + ctx: &ApiContext, + caller: &ApiCaller, + path: &DeleteOAuthClientPath, +) -> Result, HttpError> { + unimplemented!() +} + +#[derive(Debug, Clone, Deserialize, JsonSchema)] +pub struct AddOAuthClientSecretPath { + pub client_id: Uuid, +} + +/// Add an OAuth client secret +#[endpoint { + method = POST, + path = "/oauth/client/{client_id}/secret" +}] +#[instrument(skip(rqctx), fields(request_id = rqctx.request_id), err(Debug))] +pub async fn create_oauth_client_secret( + rqctx: RequestContext, + path: Path +) -> Result, HttpError> { + let ctx = rqctx.context(); + let auth = ctx.authn_token(&rqctx).await?; + let caller = ctx.get_caller(&auth).await?; + create_oauth_client_secret_op(ctx, &caller, &path.into_inner()).await +} + +#[instrument(skip(ctx, caller), fields(caller = ?caller.id), err(Debug))] +async fn create_oauth_client_secret_op( + ctx: &ApiContext, + caller: &ApiCaller, + path: &AddOAuthClientSecretPath, +) -> Result, HttpError> { + unimplemented!() +} + +#[derive(Debug, Clone, Deserialize, JsonSchema)] +pub struct DeleteOAuthClientSecretPath { + pub client_id: Uuid, + pub secret_id: Uuid, +} + +/// Delete an OAuth client secret +#[endpoint { + method = POST, + path = "/oauth/client/{client_id}/secret/{secret_id}" +}] +#[instrument(skip(rqctx), fields(request_id = rqctx.request_id), err(Debug))] +pub async fn delete_oauth_client_secret( + rqctx: RequestContext, + path: Path +) -> Result, HttpError> { + let ctx = rqctx.context(); + let auth = ctx.authn_token(&rqctx).await?; + let caller = ctx.get_caller(&auth).await?; + delete_oauth_client_secret_op(ctx, &caller, &path.into_inner()).await +} + +#[instrument(skip(ctx, caller), fields(caller = ?caller.id), err(Debug))] +async fn delete_oauth_client_secret_op( + ctx: &ApiContext, + caller: &ApiCaller, + path: &DeleteOAuthClientSecretPath, +) -> Result, HttpError> { + unimplemented!() +} + +#[derive(Debug, Clone, Deserialize, JsonSchema)] +pub struct AddOAuthClientRedirectPath { + pub client_id: Uuid, +} + +#[derive(Debug, Clone, Deserialize, JsonSchema)] +pub struct AddOAuthClientRedirectBody { + pub redirect_uri: String, +} + +/// Add an OAuth client redirect uri +#[endpoint { + method = POST, + path = "/oauth/client/{client_id}/redirect_uri" +}] +#[instrument(skip(rqctx), fields(request_id = rqctx.request_id), err(Debug))] +pub async fn create_oauth_client_redirect_uri( + rqctx: RequestContext, + path: Path, + body: TypedBody, +) -> Result, HttpError> { + let ctx = rqctx.context(); + let auth = ctx.authn_token(&rqctx).await?; + let caller = ctx.get_caller(&auth).await?; + create_oauth_client_redirect_uri_op(ctx, &caller, &path.into_inner()).await +} + +#[instrument(skip(ctx, caller), fields(caller = ?caller.id), err(Debug))] +async fn create_oauth_client_redirect_uri_op( + ctx: &ApiContext, + caller: &ApiCaller, + path: &AddOAuthClientRedirectPath, +) -> Result, HttpError> { + unimplemented!() +} + +#[derive(Debug, Clone, Deserialize, JsonSchema)] +pub struct DeleteOAuthClientRediretPath { + pub client_id: Uuid, + pub redirect_uri_id: Uuid, +} + +/// Delete an OAuth client secret +#[endpoint { + method = POST, + path = "/oauth/client/{client_id}/redirect_uri/{redirect_uri_id}" +}] +#[instrument(skip(rqctx), fields(request_id = rqctx.request_id), err(Debug))] +pub async fn delete_oauth_client_redirect_uri( + rqctx: RequestContext, + path: Path +) -> Result, HttpError> { + let ctx = rqctx.context(); + let auth = ctx.authn_token(&rqctx).await?; + let caller = ctx.get_caller(&auth).await?; + delete_oauth_client_redirect_uri_op(ctx, &caller, &path.into_inner()).await +} + +#[instrument(skip(ctx, caller), fields(caller = ?caller.id), err(Debug))] +async fn delete_oauth_client_redirect_uri_op( + ctx: &ApiContext, + caller: &ApiCaller, + path: &DeleteOAuthClientSecretPath, +) -> Result, HttpError> { + unimplemented!() +} + diff --git a/rfd-api/src/endpoints/login/oauth/mod.rs b/rfd-api/src/endpoints/login/oauth/mod.rs index 79981c6..631738c 100644 --- a/rfd-api/src/endpoints/login/oauth/mod.rs +++ b/rfd-api/src/endpoints/login/oauth/mod.rs @@ -12,6 +12,7 @@ use tracing::instrument; use super::{UserInfo, UserInfoError, UserInfoProvider}; pub mod authz_code; +pub mod client; pub mod device_token; pub mod google; diff --git a/rfd-api/src/server.rs b/rfd-api/src/server.rs index a189364..e07ebfb 100644 --- a/rfd-api/src/server.rs +++ b/rfd-api/src/server.rs @@ -15,7 +15,7 @@ use crate::{ }, login::oauth::{ authz_code::{authz_code_exchange, authz_code_redirect, authz_code_return}, - device_token::{exchange_device_token, get_device_provider}, + device_token::{exchange_device_token, get_device_provider}, client::{create_oauth_client, delete_oauth_client_redirect_uri, create_oauth_client_redirect_uri, delete_oauth_client_secret, create_oauth_client_secret, delete_oauth_client}, }, rfd::get_rfd, webhook::github_webhook, @@ -81,6 +81,14 @@ pub fn server( api.register(create_api_user_token).unwrap(); api.register(delete_api_user_token).unwrap(); + // OAuth Client Management + api.register(create_oauth_client).unwrap(); + api.register(delete_oauth_client).unwrap(); + api.register(create_oauth_client_secret).unwrap(); + api.register(delete_oauth_client_secret).unwrap(); + api.register(create_oauth_client_redirect_uri).unwrap(); + api.register(delete_oauth_client_redirect_uri).unwrap(); + // OAuth Authorization Login api.register(authz_code_redirect).unwrap(); api.register(authz_code_return).unwrap();