diff --git a/Cargo.lock b/Cargo.lock index 550b57ba..29d4b41b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,27 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "access-control" +version = "0.1.0" +dependencies = [ + "actix-http", + "anyhow", + "app-error", + "async-trait", + "casbin", + "database", + "database-entity", + "futures-util", + "lazy_static", + "prometheus-client", + "redis 0.25.2", + "sqlx", + "tokio", + "tokio-stream", + "tracing", +] + [[package]] name = "actix" version = "0.13.3" @@ -512,6 +533,7 @@ dependencies = [ name = "appflowy-cloud" version = "0.1.0" dependencies = [ + "access-control", "actix", "actix-http", "actix-identity", @@ -752,16 +774,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "atomic-write-file" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edcdbedc2236483ab103a53415653d6b4442ea6141baf1ffa85df29635e88436" -dependencies = [ - "nix", - "rand 0.8.5", -] - [[package]] name = "atomic_refcell" version = "0.1.13" @@ -1213,9 +1225,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "chrono" -version = "0.4.33" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb" +checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" dependencies = [ "android-tzdata", "iana-time-zone", @@ -3368,17 +3380,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" -[[package]] -name = "nix" -version = "0.27.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" -dependencies = [ - "bitflags 2.4.2", - "cfg-if", - "libc", -] - [[package]] name = "no-std-compat" version = "0.4.1" @@ -5201,9 +5202,9 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dba03c279da73694ef99763320dea58b51095dfe87d001b1d4b5fe78ba8763cf" +checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa" dependencies = [ "sqlx-core", "sqlx-macros", @@ -5214,9 +5215,9 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd" +checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6" dependencies = [ "ahash 0.8.7", "atoi", @@ -5225,7 +5226,6 @@ dependencies = [ "chrono", "crc", "crossbeam-queue", - "dotenvy", "either", "event-listener", "futures-channel", @@ -5260,9 +5260,9 @@ dependencies = [ [[package]] name = "sqlx-macros" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89961c00dc4d7dffb7aee214964b065072bff69e36ddb9e2c107541f75e4f2a5" +checksum = "4ea40e2345eb2faa9e1e5e326db8c34711317d2b5e08d0d5741619048a803127" dependencies = [ "proc-macro2", "quote", @@ -5273,11 +5273,10 @@ dependencies = [ [[package]] name = "sqlx-macros-core" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0bd4519486723648186a08785143599760f7cc81c52334a55d6a83ea1e20841" +checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8" dependencies = [ - "atomic-write-file", "dotenvy", "either", "heck", @@ -5300,9 +5299,9 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4" +checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" dependencies = [ "atoi", "base64 0.21.7", @@ -5345,9 +5344,9 @@ dependencies = [ [[package]] name = "sqlx-postgres" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24" +checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" dependencies = [ "atoi", "base64 0.21.7", @@ -5374,7 +5373,6 @@ dependencies = [ "rust_decimal", "serde", "serde_json", - "sha1", "sha2", "smallvec", "sqlx-core", @@ -5387,9 +5385,9 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "210976b7d948c7ba9fced8ca835b11cbb2d677c59c79de41ac0d397e14547490" +checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa" dependencies = [ "atoi", "chrono", diff --git a/Cargo.toml b/Cargo.toml index c94f49e2..e0210bf7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" [dependencies] actix = "0.13.3" actix-web = { version = "4.4.1", default-features = false, features = ["openssl", "compress-brotli", "compress-gzip"] } -actix-http = { version = "3.5.1", default-features = false, features = ["openssl", "compress-brotli", "compress-gzip"] } +actix-http = { workspace = true, default-features = false, features = ["openssl", "compress-brotli", "compress-gzip"] } actix-rt = "2.9.0" actix-web-actors = { version = "4.2.0" } actix-service = "2.0.2" @@ -28,11 +28,11 @@ tokio = { workspace = true, features = [ "fs", "time", ] } -tokio-stream = "0.1.14" +tokio-stream.workspace = true tokio-util = { version = "0.7.10", features = ["io"] } -futures-util ={ version = "0.3.30" , features = ["std","io"] } +futures-util ={ workspace = true , features = ["std","io"] } once_cell = "1.19.0" -chrono = { version = "0.4.31", features = ["serde", "clock"], default-features = false } +chrono = { version = "0.4.37", features = ["serde", "clock"], default-features = false } derive_more = { version = "0.99" } argon2 = { version = "0.5", features = ["std"] } secrecy = { version = "0.8", features = ["serde"] } @@ -41,7 +41,7 @@ anyhow = "1.0.79" thiserror = "1.0.56" reqwest = { workspace = true, features = ["json", "rustls-tls", "cookies"] } unicode-segmentation = "1.10" -lazy_static = "1.4.0" +lazy_static.workspace = true fancy-regex = "0.11.0" validator = "0.16.1" bytes = "1.5.0" @@ -53,14 +53,14 @@ tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["registry", "env-filter", "ansi", "json"] } tracing-bunyan-formatter = "0.3.9" tracing-log = "0.1.4" -sqlx = { version = "0.7", default-features = false, features = ["runtime-tokio-rustls", "macros", "postgres", "uuid", "chrono", "migrate"] } -async-trait = "0.1.77" -prometheus-client = "0.22.0" +sqlx = { workspace = true, default-features = false, features = ["runtime-tokio-rustls", "macros", "postgres", "uuid", "chrono", "migrate"] } +async-trait.workspace = true +prometheus-client.workspace = true itertools = "0.11" uuid = "1.6.1" tokio-tungstenite = { version = "0.20.1", features = ["native-tls"] } prost = "0.12.3" -casbin = { version = "2.2.0", features = ["cached", "runtime-tokio", "incremental"] } +casbin.workspace = true dotenvy = "0.15.7" url = "2.5.0" brotli = "3.4.0" @@ -77,12 +77,13 @@ collab-entity = { version = "0.1.0" } #Local crate snowflake = { path = "libs/snowflake" } -database = { path = "libs/database" } +database.workspace = true appflowy-ai = { path = "libs/appflowy-ai" } database-entity.workspace = true gotrue = { path = "libs/gotrue" } gotrue-entity = { path = "libs/gotrue-entity" } infra = { path = "libs/infra" } +access-control.workspace = true app-error = { workspace = true, features = ["sqlx_error", "actix_web_error", "tokio_error"] } shared-entity = { path = "libs/shared-entity", features = ["cloud"] } workspace-template = { workspace = true } @@ -133,6 +134,7 @@ members = [ "libs/app-error", "libs/workspace-template", "libs/encrypt", + "libs/access-control", "libs/collab-rt-protocol", "libs/collab-stream", "libs/client-websocket", @@ -148,9 +150,14 @@ members = [ [workspace.dependencies] collab-rt-entity = { path = "libs/collab-rt-entity" } collab-rt-protocol = { path = "libs/collab-rt-protocol" } +database = { path = "libs/database" } database-entity = { path = "libs/database-entity" } shared-entity = { path = "libs/shared-entity" } +access-control = { path = "libs/access-control" } app-error = { path = "libs/app-error" } +async-trait = "0.1.77" +prometheus-client = "0.22.0" +casbin = { version = "2.2.0", features = ["cached", "runtime-tokio", "incremental"] } collab-stream = { path = "libs/collab-stream" } serde_json = "1.0.111" serde = { version = "1.0.195", features = ["derive"] } @@ -158,7 +165,10 @@ bytes = "1.5.0" workspace-template = { path = "libs/workspace-template" } uuid = { version = "1.6.1", features = ["v4"] } anyhow = "1.0.79" +actix-http = { version = "3.5.1", default-features = false } tokio = { version = "1.36.0", features = ["sync"] } +tokio-stream = "0.1.14" +futures-util = "0.3.30" yrs = "0.17.2" bincode = "1.3.3" client-websocket = { path = "libs/client-websocket" } @@ -169,11 +179,13 @@ tracing = { version = "0.1.40"} collab-entity = { version = "0.1.0" } gotrue = { path = "libs/gotrue" } redis = "0.25.2" +sqlx = { version = "0.7.4", default-features = false } dashmap = "5.5.3" futures = "0.3.30" async-stream = "0.3.5" reqwest = "0.11.26" collab-rt = { path = "libs/collab-rt" } +lazy_static = "1.4.0" [profile.release] lto = true diff --git a/libs/access-control/Cargo.toml b/libs/access-control/Cargo.toml new file mode 100644 index 00000000..b0c6a7ba --- /dev/null +++ b/libs/access-control/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "access-control" +version = "0.1.0" +edition = "2021" + +[dependencies] +actix-http.workspace = true +app-error.workspace = true +anyhow.workspace = true +async-trait.workspace = true +casbin.workspace = true +database.workspace = true +database-entity.workspace = true +futures-util.workspace = true +lazy_static.workspace = true +prometheus-client.workspace = true +redis.workspace = true +sqlx = { workspace = true, default-features = false, features = ["postgres"] } +tracing.workspace = true +tokio = { workspace = true, features = [ + "macros", + "rt", + "time", +] } +tokio-stream.workspace = true diff --git a/src/biz/casbin/access_control.rs b/libs/access-control/src/access.rs similarity index 95% rename from src/biz/casbin/access_control.rs rename to libs/access-control/src/access.rs index 3708d0a9..d696ec2d 100644 --- a/src/biz/casbin/access_control.rs +++ b/libs/access-control/src/access.rs @@ -1,15 +1,13 @@ -use crate::biz::casbin::collab_ac::CollabAccessControlImpl; -use crate::biz::casbin::enforcer::{AFEnforcer, NoEnforceGroup}; +use crate::enforcer::{AFEnforcer, NoEnforceGroup}; -use crate::biz::casbin::workspace_ac::WorkspaceAccessControlImpl; use std::cmp::Ordering; use app_error::AppError; use casbin::{CoreApi, DefaultModel, Enforcer, MgmtApi}; use database_entity::dto::{AFAccessLevel, AFRole}; -use crate::biz::casbin::adapter::PgAdapter; -use crate::biz::casbin::metrics::{tick_metric, AccessControlMetrics}; +use crate::adapter::PgAdapter; +use crate::metrics::{tick_metric, AccessControlMetrics}; use actix_http::Method; use anyhow::anyhow; @@ -75,14 +73,6 @@ impl AccessControl { self.change_tx.subscribe() } - pub fn new_collab_access_control(&self) -> CollabAccessControlImpl { - CollabAccessControlImpl::new(self.clone()) - } - - pub fn new_workspace_access_control(&self) -> WorkspaceAccessControlImpl { - WorkspaceAccessControlImpl::new(self.clone()) - } - pub async fn update_policy( &self, uid: &i64, diff --git a/src/biz/casbin/adapter.rs b/libs/access-control/src/adapter.rs similarity index 97% rename from src/biz/casbin/adapter.rs rename to libs/access-control/src/adapter.rs index 2c803388..751952d1 100644 --- a/src/biz/casbin/adapter.rs +++ b/libs/access-control/src/adapter.rs @@ -1,8 +1,8 @@ -use crate::biz::casbin::access_control::{ObjectType, ToACAction}; +use crate::access::{ObjectType, ToACAction}; use async_trait::async_trait; -use crate::biz::casbin::metrics::AccessControlMetrics; +use crate::metrics::AccessControlMetrics; use casbin::Adapter; use casbin::Filter; use casbin::Model; diff --git a/src/biz/casbin/enforcer.rs b/libs/access-control/src/enforcer.rs similarity index 97% rename from src/biz/casbin/enforcer.rs rename to libs/access-control/src/enforcer.rs index c1c1f186..26ff08cf 100644 --- a/src/biz/casbin/enforcer.rs +++ b/libs/access-control/src/enforcer.rs @@ -1,9 +1,9 @@ -use crate::biz::casbin::access_control::{ +use crate::access::{ load_group_policies, ActionVariant, ObjectType, ToACAction, POLICY_FIELD_INDEX_OBJECT, POLICY_FIELD_INDEX_SUBJECT, }; -use crate::biz::casbin::metrics::MetricsCalState; -use crate::biz::casbin::request::{GroupPolicyRequest, PolicyRequest, WorkspacePolicyRequest}; +use crate::metrics::MetricsCalState; +use crate::request::{GroupPolicyRequest, PolicyRequest, WorkspacePolicyRequest}; use anyhow::anyhow; use app_error::AppError; use async_trait::async_trait; @@ -223,8 +223,8 @@ impl EnforcerGroup for NoEnforceGroup { #[cfg(test)] mod tests { - use crate::biz::casbin::access_control::{casbin_model, Action, ActionVariant, ObjectType}; - use crate::biz::casbin::enforcer::{AFEnforcer, EnforcerGroup, NoEnforceGroup}; + use crate::access::{casbin_model, Action, ActionVariant, ObjectType}; + use crate::enforcer::{AFEnforcer, EnforcerGroup, NoEnforceGroup}; use async_trait::async_trait; use casbin::{CoreApi, MemoryAdapter}; use database_entity::dto::{AFAccessLevel, AFRole}; diff --git a/libs/access-control/src/lib.rs b/libs/access-control/src/lib.rs new file mode 100644 index 00000000..f6429413 --- /dev/null +++ b/libs/access-control/src/lib.rs @@ -0,0 +1,5 @@ +pub mod access; +mod adapter; +pub mod enforcer; +pub mod metrics; +mod request; diff --git a/src/biz/casbin/metrics.rs b/libs/access-control/src/metrics.rs similarity index 97% rename from src/biz/casbin/metrics.rs rename to libs/access-control/src/metrics.rs index f50b2526..bdb925a8 100644 --- a/src/biz/casbin/metrics.rs +++ b/libs/access-control/src/metrics.rs @@ -2,7 +2,7 @@ use prometheus_client::metrics::gauge::Gauge; use std::sync::atomic::{AtomicI64, Ordering}; use std::sync::Arc; -use crate::biz::casbin::enforcer::ENFORCER_METRICS_TICK_INTERVAL; +use crate::enforcer::ENFORCER_METRICS_TICK_INTERVAL; use prometheus_client::registry::Registry; use tokio::time::interval; diff --git a/src/biz/casbin/request.rs b/libs/access-control/src/request.rs similarity index 96% rename from src/biz/casbin/request.rs rename to libs/access-control/src/request.rs index 9b6f1fc1..950568ab 100644 --- a/src/biz/casbin/request.rs +++ b/libs/access-control/src/request.rs @@ -1,4 +1,4 @@ -use crate::biz::casbin::access_control::{ActionVariant, ObjectType, ToACAction}; +use crate::access::{ActionVariant, ObjectType, ToACAction}; pub struct GroupPolicyRequest<'a> { pub guid: &'a str, diff --git a/src/application.rs b/src/application.rs index 2b651133..be41d709 100644 --- a/src/application.rs +++ b/src/application.rs @@ -4,9 +4,11 @@ use crate::api::file_storage::file_storage_scope; use crate::api::user::user_scope; use crate::api::workspace::{collab_scope, workspace_scope}; use crate::api::ws::ws_scope; -use crate::biz::casbin::access_control::{enable_access_control, AccessControl}; +use access_control::access::{enable_access_control, AccessControl}; -use crate::biz::casbin::RealtimeCollabAccessControlImpl; +use crate::biz::casbin::{ + CollabAccessControlImpl, RealtimeCollabAccessControlImpl, WorkspaceAccessControlImpl, +}; use crate::biz::collab::access_control::{ CollabMiddlewareAccessControl, CollabStorageAccessControlImpl, }; @@ -213,8 +215,8 @@ pub async fn init_state(config: &Config, rt_cmd_tx: RTCommandSender) -> Result