feat: support user deletion
This commit is contained in:
parent
a2af9c3b63
commit
89f2c7003b
5
dev.env
5
dev.env
|
|
@ -68,6 +68,11 @@ GOTRUE_EXTERNAL_DISCORD_ENABLED=false
|
||||||
GOTRUE_EXTERNAL_DISCORD_CLIENT_ID=
|
GOTRUE_EXTERNAL_DISCORD_CLIENT_ID=
|
||||||
GOTRUE_EXTERNAL_DISCORD_SECRET=
|
GOTRUE_EXTERNAL_DISCORD_SECRET=
|
||||||
GOTRUE_EXTERNAL_DISCORD_REDIRECT_URI=http://localhost:9999/callback
|
GOTRUE_EXTERNAL_DISCORD_REDIRECT_URI=http://localhost:9999/callback
|
||||||
|
# Apple OAuth2
|
||||||
|
GOTRUE_EXTERNAL_APPLE_ENABLED=false
|
||||||
|
GOTRUE_EXTERNAL_APPLE_CLIENT_ID=
|
||||||
|
GOTRUE_EXTERNAL_APPLE_SECRET=
|
||||||
|
GOTRUE_EXTERNAL_APPLE_REDIRECT_URI=http://localhost:9999/callback
|
||||||
|
|
||||||
# File Storage
|
# File Storage
|
||||||
APPFLOWY_S3_USE_MINIO=true
|
APPFLOWY_S3_USE_MINIO=true
|
||||||
|
|
|
||||||
|
|
@ -317,6 +317,7 @@ pub enum ErrorCode {
|
||||||
SqlxArgEncodingError = 1035,
|
SqlxArgEncodingError = 1035,
|
||||||
InvalidContentType = 1036,
|
InvalidContentType = 1036,
|
||||||
SingleUploadLimitExceeded = 1037,
|
SingleUploadLimitExceeded = 1037,
|
||||||
|
AppleRevokeTokenError = 1038,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ErrorCode {
|
impl ErrorCode {
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,10 @@ use crate::state::AppState;
|
||||||
use actix_web::web::{Data, Json};
|
use actix_web::web::{Data, Json};
|
||||||
use actix_web::Result;
|
use actix_web::Result;
|
||||||
use actix_web::{web, Scope};
|
use actix_web::{web, Scope};
|
||||||
|
use app_error::ErrorCode;
|
||||||
use authentication::jwt::{Authorization, UserUuid};
|
use authentication::jwt::{Authorization, UserUuid};
|
||||||
use database_entity::dto::{AFUserProfile, AFUserWorkspaceInfo};
|
use database_entity::dto::{AFUserProfile, AFUserWorkspaceInfo};
|
||||||
|
use secrecy::ExposeSecret;
|
||||||
use shared_entity::dto::auth_dto::{SignInTokenResponse, UpdateUserParams};
|
use shared_entity::dto::auth_dto::{SignInTokenResponse, UpdateUserParams};
|
||||||
use shared_entity::response::AppResponseError;
|
use shared_entity::response::AppResponseError;
|
||||||
use shared_entity::response::{AppResponse, JsonAppResponse};
|
use shared_entity::response::{AppResponse, JsonAppResponse};
|
||||||
|
|
@ -69,5 +71,68 @@ async fn delete_user_handler(
|
||||||
state: Data<AppState>,
|
state: Data<AppState>,
|
||||||
) -> Result<JsonAppResponse<()>> {
|
) -> Result<JsonAppResponse<()>> {
|
||||||
delete_user(&state.pg_pool, auth.uuid()?).await?;
|
delete_user(&state.pg_pool, auth.uuid()?).await?;
|
||||||
|
|
||||||
|
if is_apple_user(auth) {
|
||||||
|
if let Err(err) = revoke_apple_token(
|
||||||
|
&state.config.apple_oauth.client_id,
|
||||||
|
state.config.apple_oauth.client_secret.expose_secret(),
|
||||||
|
"TODO: get original apple during oauth",
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
tracing::warn!("revoke apple token failed: {:?}", err);
|
||||||
|
};
|
||||||
|
}
|
||||||
Ok(AppResponse::Ok().into())
|
Ok(AppResponse::Ok().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_apple_user(auth: Authorization) -> bool {
|
||||||
|
if let Some(provider) = auth.claims.app_metadata.get("provider") {
|
||||||
|
if provider == "apple" {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(providers) = auth.claims.app_metadata.get("providers") {
|
||||||
|
if let Some(providers) = providers.as_array() {
|
||||||
|
for provider in providers {
|
||||||
|
if provider == "apple" {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Based on: https://developer.apple.com/documentation/sign_in_with_apple/revoke_tokens
|
||||||
|
async fn revoke_apple_token(
|
||||||
|
apple_client_id: &str,
|
||||||
|
apple_client_secret: &str,
|
||||||
|
apple_user_token: &str,
|
||||||
|
) -> Result<(), AppResponseError> {
|
||||||
|
let resp = reqwest::Client::new()
|
||||||
|
.post("https://appleid.apple.com/auth/revoke")
|
||||||
|
.form(&[
|
||||||
|
("client_id", apple_client_id),
|
||||||
|
("client_secret", apple_client_secret),
|
||||||
|
("token", apple_user_token),
|
||||||
|
])
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let status = resp.status();
|
||||||
|
if status.is_success() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let payload = resp.text().await?;
|
||||||
|
Err(AppResponseError::new(
|
||||||
|
ErrorCode::AppleRevokeTokenError,
|
||||||
|
format!(
|
||||||
|
"calling apple revoke, code: {}, message: {}",
|
||||||
|
status, payload
|
||||||
|
),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ pub struct Config {
|
||||||
pub grpc_history: GrpcHistorySetting,
|
pub grpc_history: GrpcHistorySetting,
|
||||||
pub collab: CollabSetting,
|
pub collab: CollabSetting,
|
||||||
pub mailer: MailerSetting,
|
pub mailer: MailerSetting,
|
||||||
|
pub apple_oauth: AppleOAuthSetting,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(serde::Deserialize, Clone, Debug)]
|
#[derive(serde::Deserialize, Clone, Debug)]
|
||||||
|
|
@ -32,6 +33,12 @@ pub struct MailerSetting {
|
||||||
pub smtp_password: Secret<String>,
|
pub smtp_password: Secret<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize, Clone, Debug)]
|
||||||
|
pub struct AppleOAuthSetting {
|
||||||
|
pub client_id: String,
|
||||||
|
pub client_secret: Secret<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(serde::Deserialize, Clone, Debug)]
|
#[derive(serde::Deserialize, Clone, Debug)]
|
||||||
pub struct CasbinSetting {
|
pub struct CasbinSetting {
|
||||||
pub pool_size: u32,
|
pub pool_size: u32,
|
||||||
|
|
@ -204,6 +211,10 @@ pub fn get_configuration() -> Result<Config, anyhow::Error> {
|
||||||
smtp_username: get_env_var("APPFLOWY_MAILER_SMTP_USERNAME", "sender@example.com"),
|
smtp_username: get_env_var("APPFLOWY_MAILER_SMTP_USERNAME", "sender@example.com"),
|
||||||
smtp_password: get_env_var("APPFLOWY_MAILER_SMTP_PASSWORD", "password").into(),
|
smtp_password: get_env_var("APPFLOWY_MAILER_SMTP_PASSWORD", "password").into(),
|
||||||
},
|
},
|
||||||
|
apple_oauth: AppleOAuthSetting {
|
||||||
|
client_id: get_env_var("APPFLOWY_APPLE_OAUTH_CLIENT_ID", ""),
|
||||||
|
client_secret: get_env_var("APPFLOWY_APPLE_OAUTH_CLIENT_SECRET", "").into(),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue