Skip to content

Commit

Permalink
feat: single page sharing permission check (#361)
Browse files Browse the repository at this point in the history
* chore: split workspace impl as module

* fix: useless clone

* chore: update deploy config

* feat: expose error in `retry_with_trx`

* feat: parse page meta

* test: add more test

* chore: improve caching

* chore: remove useless action

* fix: doc type

* chore: use `JwstResult`

* chore: add fixtures

* feat: check shared space

* feat: add public page check in api

* test: adjust public workspace test

* test: add page meta test

* test: add workspace metadata test

* fix: lint report
  • Loading branch information
darkskygit authored Apr 10, 2023
1 parent 35b68c3 commit 775ac3b
Show file tree
Hide file tree
Showing 27 changed files with 767 additions and 518 deletions.
17 changes: 9 additions & 8 deletions .github/deployment/cloud-dev.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,18 @@ job "affine-cloud-dev" {
driver = "docker"

env {

AFFINE_CLOUD_LOG = "debug,mio=off,hyper=off,rustls=off,tantivy=off,sqlx::query=off,jwst_rpc=trace,jwst_rpc::context=info,affine_cloud=trace"
JWT_ACCESS_TOKEN_EXPIRES_IN = "3600"
JWT_REFRESH_TOKEN_EXPIRES_IN = "2592000"
JWST_DEV = "1"
}
template {
data = <<EOH
DOCKER_TAG = "{{ key "service/development/affine-cloud/tag" }}"
DATABASE_URL = "postgresql://affine:{{ key "service/development/affine-cloud/database_password" }}@{{ env "NOMAD_ADDR_postgres" }}/affine"
SIGN_KEY = "{{ key "service/development/affine-cloud/sign_key" }}"
MAIL_ACCOUNT = "{{ key "service/development/affine-cloud/mail_account" }}"
MAIL_PASSWORD = "{{ key "service/development/affine-cloud/mail_password" }}"
JWST_DEV = "1"
AFFINE_CLOUD_LOG = "debug,mio=off,hyper=off,rustls=off,tantivy=off,sqlx::query=off,jwst_rpc=trace,jwst_rpc::context=info,affine_cloud=trace"
DOCKER_TAG = "{{ key "service/development/affine-cloud/tag" }}"
DATABASE_URL = "postgresql://affine:{{ key "service/development/affine-cloud/database_password" }}@{{ env "NOMAD_ADDR_postgres" }}/affine"
SIGN_KEY = "{{ key "service/development/affine-cloud/sign_key" }}"
MAIL_ACCOUNT = "{{ key "service/development/affine-cloud/mail_account" }}"
MAIL_PASSWORD = "{{ key "service/development/affine-cloud/mail_password" }}"
EOH

destination = "secrets/.env"
Expand Down
13 changes: 8 additions & 5 deletions .github/deployment/cloud-prod.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,18 @@ job "affine-cloud-prod" {
driver = "docker"

env {
AFFINE_CLOUD_LOG = "info,mio=off,hyper=off,rustls=off,tantivy=off,sqlx::query=off,jwst_rpc=trace,jwst_rpc::context=info,affine_cloud=trace"
JWT_ACCESS_TOKEN_EXPIRES_IN = "3600"
JWT_REFRESH_TOKEN_EXPIRES_IN = "2592000"

}
template {
data = <<EOH
DOCKER_TAG = "{{ key "service/production/affine-cloud/tag" }}"
DATABASE_URL = "postgresql://affine:{{ key "service/production/affine-cloud/database_password" }}@{{ env "NOMAD_ADDR_postgres" }}/affine"
SIGN_KEY = "{{ key "service/production/affine-cloud/sign_key" }}"
MAIL_ACCOUNT = "{{ key "service/production/affine-cloud/mail_account" }}"
MAIL_PASSWORD = "{{ key "service/production/affine-cloud/mail_password" }}"
DOCKER_TAG = "{{ key "service/production/affine-cloud/tag" }}"
DATABASE_URL = "postgresql://affine:{{ key "service/production/affine-cloud/database_password" }}@{{ env "NOMAD_ADDR_postgres" }}/affine"
SIGN_KEY = "{{ key "service/production/affine-cloud/sign_key" }}"
MAIL_ACCOUNT = "{{ key "service/production/affine-cloud/mail_account" }}"
MAIL_PASSWORD = "{{ key "service/production/affine-cloud/mail_password" }}"
EOH

destination = "secrets/.env"
Expand Down
17 changes: 8 additions & 9 deletions .github/deployment/cloud-stage.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -57,18 +57,17 @@ job "affine-cloud-stage" {
driver = "docker"

env {

AFFINE_CLOUD_LOG = "info,mio=off,hyper=off,rustls=off,tantivy=off,sqlx::query=off,jwst_rpc=trace,jwst_rpc::context=info,affine_cloud=trace"
JWT_ACCESS_TOKEN_EXPIRES_IN = "3600"
JWT_REFRESH_TOKEN_EXPIRES_IN = "2592000"
}
template {
data = <<EOH
DOCKER_TAG = "{{ key "service/stage/affine-cloud/tag" }}"
DATABASE_URL = "postgresql://affine:{{ key "service/stage/affine-cloud/database_password" }}@{{ env "NOMAD_ADDR_postgres" }}/affine"
SIGN_KEY = "{{ key "service/stage/affine-cloud/sign_key" }}"
MAIL_ACCOUNT = "{{ key "service/stage/affine-cloud/mail_account" }}"
MAIL_PASSWORD = "{{ key "service/stage/affine-cloud/mail_password" }}"
AFFINE_CLOUD_LOG = "info,mio=off,hyper=off,rustls=off,tantivy=off,sqlx::query=off,jwst_rpc=trace,jwst_rpc::context=info,affine_cloud=trace"
JWT_ACCESS_TOKEN_EXPIRES_IN = "3600"
JWT_REFRESH_TOKEN_EXPIRES_IN = "2592000"
DOCKER_TAG = "{{ key "service/stage/affine-cloud/tag" }}"
DATABASE_URL = "postgresql://affine:{{ key "service/stage/affine-cloud/database_password" }}@{{ env "NOMAD_ADDR_postgres" }}/affine"
SIGN_KEY = "{{ key "service/stage/affine-cloud/sign_key" }}"
MAIL_ACCOUNT = "{{ key "service/stage/affine-cloud/mail_account" }}"
MAIL_PASSWORD = "{{ key "service/stage/affine-cloud/mail_password" }}"
EOH

destination = "secrets/.env"
Expand Down
64 changes: 18 additions & 46 deletions .github/workflows/jwst.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,20 +59,14 @@ jobs:
toolchain: stable
override: true

- name: Set up cargo cache
- uses: Swatinem/rust-cache@v2
- name: Set up cache
uses: actions/cache@v3
continue-on-error: false
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
./vendor
./.cargo/config
./node_modules/.pnpm-store
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-
path: ./node_modules/.pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: ${{ runner.os }}-pnpm-

- name: Cargo Vendor
run: cargo vendor > .cargo/config
Expand Down Expand Up @@ -141,20 +135,14 @@ jobs:
target: x86_64-unknown-linux-musl
override: true

- uses: Swatinem/rust-cache@v2
- name: Set up cache
uses: actions/cache@v3
continue-on-error: false
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
./vendor
./.cargo/config
./node_modules/.pnpm-store
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-
path: ./node_modules/.pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: ${{ runner.os }}-pnpm-

- name: Build & Check
run: |
Expand Down Expand Up @@ -236,22 +224,12 @@ jobs:
labels: ${{ steps.meta_apiproxy.outputs.labels }}
target: apiproxy

test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- uses: actions-rs/cargo@v1
with:
command: test
args: --no-fail-fast

lint:
runs-on: ubuntu-latest
environment: development
permissions:
contents: read
security-events: write

steps:
- name: Checkout
Expand All @@ -267,20 +245,14 @@ jobs:
components: clippy
override: true

- uses: Swatinem/rust-cache@v2
- name: Set up cache
uses: actions/cache@v3
continue-on-error: false
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
./vendor
./.cargo/config
./node_modules/.pnpm-store
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-
path: ./node_modules/.pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: ${{ runner.os }}-pnpm-

- name: Install required cargo components
uses: taiki-e/install-action@v2
Expand All @@ -301,8 +273,8 @@ jobs:
sarif_file: rust-clippy-results.sarif
wait-for-processing: true

coverage:
name: Collect test coverage
test:
name: test & collect coverage
runs-on: ubuntu-latest
continue-on-error: true
env:
Expand Down
39 changes: 34 additions & 5 deletions apps/cloud/src/api/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use cloud_database::{Claims, UpdateWorkspace, WorkspaceSearchInput};
use futures::{future, StreamExt};
use jwst::{error, BlobStorage};
use jwst_logger::{info, instrument, tracing};
use std::sync::Arc;
use jwst_storage::JwstStorageError;
use std::sync::Arc;

impl Context {
#[instrument(skip(self, stream))]
Expand Down Expand Up @@ -375,12 +375,26 @@ pub async fn get_public_page(
) -> Response {
info!("get_page enter");
match ctx.db.is_public_workspace(workspace_id.clone()).await {
Ok(true) => (),
Ok(false) => return ErrorStatus::Forbidden.into_response(),
// check if page is public
// TODO: improve logic
Ok(false)
if ctx
.storage
.get_workspace(workspace_id.clone())
.await
.ok()
.and_then(|ws| {
ws.try_with_trx(|mut t| t.get_space(page_id.clone()).shared(&t.trx))
})
!= Some(true) =>
{
return ErrorStatus::Forbidden.into_response();
}
Err(e) => {
error!("Failed to get permission: {:?}", e);
return ErrorStatus::InternalServerError.into_response();
}
Ok(true | false) => (),
}

match ctx.storage.get_workspace(workspace_id).await {
Expand All @@ -392,6 +406,7 @@ pub async fn get_public_page(
Some(mine) if mine.starts_with("text/") => {
if let Some(markdown) = workspace
.retry_with_trx(|t| space.to_markdown(&t.trx), 10)
.ok()
.flatten()
{
markdown.into_response()
Expand All @@ -402,6 +417,7 @@ pub async fn get_public_page(
_ => {
if let Some(doc) = workspace
.retry_with_trx(|t| space.to_single_page(&t.trx).ok(), 10)
.ok()
.flatten()
{
doc.into_response()
Expand Down Expand Up @@ -1000,6 +1016,7 @@ mod test {
let context = Context::new_test_client(pool).await;
let ctx = Arc::new(context);
let app = make_rest_route(ctx.clone()).layer(Extension(ctx.clone()));

//create user
let client = TestClient::new(app);
let body_data = json!({
Expand All @@ -1017,6 +1034,7 @@ mod test {
.send()
.await;
assert_eq!(resp.status(), StatusCode::OK);

//login user
let body_data = json!({
"type": "DebugLoginUser",
Expand All @@ -1041,6 +1059,7 @@ mod test {
.map(|byte| Ok::<_, std::io::Error>(Bytes::from(vec![byte]))),
);
let body_stream = Body::wrap_stream(test_data_stream.clone());

//create workspace
let resp = client
.post("/workspace")
Expand All @@ -1053,13 +1072,13 @@ mod test {
let resp_json: serde_json::Value = resp.json().await;
let workspace_id = resp_json["id"].as_str().unwrap().to_string();
let public_url = format!("/public/workspace/{}", workspace_id.clone());

let resp = client
.get(&public_url)
.header("authorization", format!("{}", access_token.clone()))
.send()
.await;
assert_eq!(resp.status(), StatusCode::FORBIDDEN);

//public workspace
let url = format!("/workspace/{}", workspace_id.clone());
let body_data = json!({
Expand All @@ -1077,8 +1096,18 @@ mod test {
let resp_json: serde_json::Value = resp.json().await;
let is_workspace_public = resp_json["public"].as_bool().unwrap();
assert_eq!(is_workspace_public, true);
//get public doc

// check public workspace
let url = format!("/public/workspace/{}", workspace_id);
let resp = client
.get(&url)
.header("Content-Type", "application/json")
.send()
.await;
assert_eq!(resp.status(), StatusCode::OK);
// TODO: check public page

//get not public doc
let resp = client
.get(&public_url)
.header("authorization", format!("{}", access_token.clone()))
Expand Down
2 changes: 1 addition & 1 deletion libs/jwst-logger/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ tracing-log = { version = "0.1.3", features = [
"std",
], default-features = false }
tracing-stackdriver = "0.6.2"
tracing-subscriber = "0.3.16"
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
6 changes: 6 additions & 0 deletions libs/jwst-logger/src/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,9 @@ fn init_logger_with_env_filter(env_filter: EnvFilter) {
.with(env_filter)
.init();
}

#[test]
fn test_init_logger() {
// just test that can be called without panicking
init_logger("jwst");
}
10 changes: 6 additions & 4 deletions libs/jwst-rpc/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ mod test {
assert_eq!(block1.get(&t.trx, "key1").unwrap().to_string(), "val1");
},
10,
);
)?;

ws.retry_with_trx(
|mut t| {
Expand All @@ -223,7 +223,7 @@ mod test {
assert_eq!(block1.get(&t.trx, "key1").unwrap().to_string(), "val1");
},
10,
);
)?;

Ok(())
}
Expand Down Expand Up @@ -311,7 +311,7 @@ mod test {
},
50,
)
.unwrap()
.and_then(|v| v)
.unwrap();

// await the task to make sure the doc1 is broadcasted before check doc2
Expand All @@ -336,7 +336,9 @@ mod test {
Ok::<_, JwstError>(())
},
50,
);
)
.and_then(|v| v)
.unwrap();

collaborator.fetch_sub(1, Ordering::Relaxed);
collaborator_pb.set_position(collaborator.load(Ordering::Relaxed));
Expand Down
Loading

1 comment on commit 775ac3b

@vercel
Copy link

@vercel vercel bot commented on 775ac3b Apr 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.