Merge pull request #274 from AppFlowy-IO/jwt-expiry

Jwt expiry check
This commit is contained in:
Zack 2024-01-28 17:28:06 +08:00 committed by GitHub
commit 3a5a3f3e20
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 432 additions and 354 deletions

3
.gitignore vendored
View File

@ -13,6 +13,7 @@ node_modules
data/ data/
.env .env
.logs .logs
shell.nix flake.nix
flake.lock
.envrc .envrc
.direnv/ .direnv/

View File

@ -1,6 +1,6 @@
{ {
"db_name": "PostgreSQL", "db_name": "PostgreSQL",
"query": "\n SELECT * FROM public.af_workspace WHERE owner_uid = (\n SELECT uid FROM public.af_user WHERE uuid = $1\n )\n ", "query": "\n SELECT * FROM public.af_workspace\n WHERE workspace_id IN (\n SELECT workspace_id FROM public.af_workspace_member\n WHERE af_workspace_member.uid = (SELECT uid FROM public.af_user WHERE uuid = $1)\n );\n ",
"describe": { "describe": {
"columns": [ "columns": [
{ {
@ -54,5 +54,5 @@
true true
] ]
}, },
"hash": "030b315f14742d266f545d6db37cc8cb083f9d52ebecd252311c4faf6fb5ab22" "hash": "03b8ab1c98353b442f9c143c29a905442985f7cfa19faaaa970a410708adc773"
} }

709
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -409,19 +409,23 @@ pub async fn select_user_workspace<'a, E: Executor<'a, Database = Postgres>>(
Ok(workspaces) Ok(workspaces)
} }
/// Returns a list of workspaces that the user is part of.
/// User may owner or non-owner.
#[inline] #[inline]
pub async fn select_all_user_workspaces( pub async fn select_all_user_workspaces(
pool: &PgPool, pool: &PgPool,
owner_uuid: &Uuid, user_uuid: &Uuid,
) -> Result<Vec<AFWorkspaceRow>, AppError> { ) -> Result<Vec<AFWorkspaceRow>, AppError> {
let workspaces = sqlx::query_as!( let workspaces = sqlx::query_as!(
AFWorkspaceRow, AFWorkspaceRow,
r#" r#"
SELECT * FROM public.af_workspace WHERE owner_uid = ( SELECT * FROM public.af_workspace
SELECT uid FROM public.af_user WHERE uuid = $1 WHERE workspace_id IN (
) SELECT workspace_id FROM public.af_workspace_member
WHERE af_workspace_member.uid = (SELECT uid FROM public.af_user WHERE uuid = $1)
);
"#, "#,
owner_uuid user_uuid
) )
.fetch_all(pool) .fetch_all(pool)
.await?; .await?;

View File

@ -12,3 +12,4 @@ anyhow = "1.0.79"
lazy_static = "1.4.0" lazy_static = "1.4.0"
jsonwebtoken = "8.3.0" jsonwebtoken = "8.3.0"
app-error = { workspace = true, features = ["gotrue_error"] } app-error = { workspace = true, features = ["gotrue_error"] }
chrono = "0.4.33"

View File

@ -35,6 +35,16 @@ lazy_static::lazy_static! {
impl GoTrueJWTClaims { impl GoTrueJWTClaims {
pub fn verify(token: &str, secret: &[u8]) -> Result<Self, jsonwebtoken::errors::Error> { pub fn verify(token: &str, secret: &[u8]) -> Result<Self, jsonwebtoken::errors::Error> {
Ok(decode(token, &DecodingKey::from_secret(secret), &VALIDATION)?.claims) let claims = decode::<Self>(token, &DecodingKey::from_secret(secret), &VALIDATION)?.claims;
let ts_expiry = claims.exp.ok_or_else(|| {
jsonwebtoken::errors::ErrorKind::MissingRequiredClaim("expect exp but not found".to_owned())
})?;
let ts_now = chrono::Utc::now().timestamp();
match ts_now > ts_expiry {
true => Err(jsonwebtoken::errors::ErrorKind::ExpiredSignature.into()),
false => Ok(claims),
}
} }
} }

View File

@ -1,4 +1,6 @@
use client_api_test_util::generate_unique_registered_user_client; use client_api_test_util::generate_unique_registered_user_client;
use database_entity::dto::AFRole;
use shared_entity::dto::workspace_dto::CreateWorkspaceMember;
use shared_entity::dto::workspace_dto::CreateWorkspaceParam; use shared_entity::dto::workspace_dto::CreateWorkspaceParam;
#[tokio::test] #[tokio::test]
@ -29,3 +31,44 @@ async fn add_and_delete_workspace_for_user() {
let workspaces = c.get_workspaces().await.unwrap(); let workspaces = c.get_workspaces().await.unwrap();
assert_eq!(workspaces.0.len(), 1); assert_eq!(workspaces.0.len(), 1);
} }
#[tokio::test]
async fn add_and_delete_workspace_for_non_owner_user() {
let (member, member_user) = generate_unique_registered_user_client().await;
// Owner added member to workspace
let (owner, _user) = generate_unique_registered_user_client().await;
let owner_workspace = owner
.create_workspace(CreateWorkspaceParam {
workspace_name: Some("owner_workspace".to_string()),
})
.await
.unwrap();
owner
.add_workspace_members(
owner_workspace.workspace_id.to_string(),
vec![CreateWorkspaceMember {
email: member_user.email.clone(),
role: AFRole::Member,
}],
)
.await
.unwrap();
// Member should have 2 workspaces
let member_workspaces = member.get_workspaces().await.unwrap();
assert_eq!(member_workspaces.0.len(), 2);
owner
.remove_workspace_members(
owner_workspace.workspace_id.to_string(),
vec![member_user.email],
)
.await
.unwrap();
// Member should have 1 workspaces, because owner removed him
let member_workspaces = member.get_workspaces().await.unwrap();
assert_eq!(member_workspaces.0.len(), 1);
}