From 58336dca49121d732cc2c2d8c1c17877444d5dfa Mon Sep 17 00:00:00 2001 From: vsilent Date: Thu, 23 Nov 2023 21:36:17 +0200 Subject: [PATCH 001/284] stack form field fix --- src/forms/stack.rs | 57 +++++++++++++++++++++++++++--- src/routes/stack/add.rs | 11 ++++-- src/routes/stack/compose.rs | 4 +-- src/routes/stack/deploy.rs | 2 +- src/startup.rs | 3 +- tests/custom-stack-payload-11.json | 2 ++ 6 files changed, 67 insertions(+), 12 deletions(-) create mode 100644 tests/custom-stack-payload-11.json diff --git a/src/forms/stack.rs b/src/forms/stack.rs index 78a0847..c3f108a 100644 --- a/src/forms/stack.rs +++ b/src/forms/stack.rs @@ -36,8 +36,14 @@ pub struct Ports { #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct DockerImage { + #[validate(min_length=3)] + #[validate(max_length=50)] pub dockerhub_user: Option, + #[validate(min_length=3)] + #[validate(max_length=50)] pub dockerhub_name: Option, + #[validate(min_length=3)] + #[validate(max_length=100)] pub dockerhub_image: Option, } @@ -64,24 +70,46 @@ impl AsRef for App { #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct StackForm { + #[validate(min_length=2)] + #[validate(max_length=255)] #[serde(rename= "commonDomain")] pub common_domain: Option, pub domain_list: Option, + #[validate(min_length=2)] + #[validate(max_length=255)] pub stack_code: Option, + #[validate(min_length=2)] + #[validate(max_length=50)] pub region: String, + #[validate(min_length=2)] + #[validate(max_length=50)] pub zone: Option, + #[validate(min_length=2)] + #[validate(max_length=50)] pub server: String, + #[validate(min_length=2)] + #[validate(max_length=50)] pub os: String, + #[validate(min_length=3)] + #[validate(max_length=50)] pub ssl: String, pub vars: Option>, pub integrated_features: Option>, pub extended_features: Option>, pub subscriptions: Option>, pub form_app: Option>, + #[validate(min_length=3)] + #[validate(max_length=50)] pub disk_type: Option, pub save_token: bool, + #[validate(min_length=10)] + #[validate(max_length=255)] pub cloud_token: String, + #[validate(min_length=2)] + #[validate(max_length=50)] pub provider: String, + #[validate(min_length=3)] + #[validate(max_length=50)] pub selected_plan: String, pub custom: Custom, } @@ -142,10 +170,16 @@ pub struct Custom { pub feature: Option>, pub service: Option>, #[serde(rename = "servers_count")] + #[validate(minimum = 0)] + #[validate(maximum = 10)] pub servers_count: u32, + #[validate(min_length=3)] + #[validate(max_length=50)] #[serde(rename = "custom_stack_code")] pub custom_stack_code: String, #[serde(rename = "project_git_url")] + #[validate(min_length=3)] + #[validate(max_length=255)] pub project_git_url: Option, #[serde(rename = "custom_stack_category")] pub custom_stack_category: Option>, @@ -154,6 +188,8 @@ pub struct Custom { #[serde(rename = "custom_stack_description")] pub custom_stack_description: Option, #[serde(rename = "project_name")] + #[validate(min_length=3)] + #[validate(max_length=255)] pub project_name: String, #[serde(rename = "project_overview")] pub project_overview: Option, @@ -164,6 +200,8 @@ pub struct Custom { #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct App { #[serde(rename = "_etag")] + #[validate(min_length=3)] + #[validate(max_length=255)] pub etag: Option, #[serde(rename = "_id")] pub id: u32, @@ -171,8 +209,14 @@ pub struct App { pub created: Option, #[serde(rename = "_updated")] pub updated: Option, + #[validate(min_length=3)] + #[validate(max_length=50)] pub name: String, + #[validate(min_length=3)] + #[validate(max_length=50)] pub code: String, + #[validate(min_length=3)] + #[validate(max_length=50)] #[serde(rename = "type")] pub type_field: String, #[serde(flatten)] @@ -185,6 +229,7 @@ pub struct App { pub docker_image: DockerImage, #[serde(flatten)] pub requirements: Requirements, + #[validate(minimum=1)] pub popularity: Option, pub commercial: Option, pub subscription: Option, @@ -195,7 +240,6 @@ pub struct App { pub price: Option, pub icon: Option, pub domain: Option, - pub main: bool, pub category_id: Option, pub parent_app_id: Option, pub descr: Option, @@ -213,6 +257,7 @@ pub struct Web { #[serde(flatten)] pub app: App, pub custom: Option, + pub main: bool, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] @@ -248,8 +293,7 @@ pub struct IconLight { pub struct IconDark { } -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Version { #[serde(rename = "_etag")] pub etag: Option, @@ -259,12 +303,15 @@ pub struct Version { pub created: Option, #[serde(rename = "_updated")] pub updated: Option, - #[serde(rename = "app_id")] - pub app_id: u32, + pub app_id: Option, pub name: String, + #[validate(min_length=3)] + #[validate(max_length=20)] pub version: String, #[serde(rename = "update_status")] pub update_status: Option, + #[validate(min_length=3)] + #[validate(max_length=20)] pub tag: String, } diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index 27260e0..4f08fe5 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -11,9 +11,10 @@ use chrono::Utc; use serde_json::Value; use sqlx::PgPool; use std::str; +use serde_valid::json::FromJsonValue; +use serde_valid::Validate; use tracing::Instrument; use uuid::Uuid; -use crate::models; #[tracing::instrument(name = "Add stack.")] @@ -32,7 +33,7 @@ pub async fn add( } Err(_err) => { let msg = format!("Invalid data. {:?}", _err); - return JsonResponse::::build().err("Invalid data".to_owned()); + return JsonResponse::::build().err(msg); } }; @@ -57,6 +58,10 @@ pub async fn add( let query_span = tracing::info_span!("Saving new stack details into the database"); let stack_name = form.custom.custom_stack_code.clone(); + + + let errors = form.validate().is_ok(); + println!("{:?}",errors); let body: Value = match serde_json::to_value::(form) { Ok(body) => body, Err(err) => { @@ -65,7 +70,7 @@ pub async fn add( } }; - return match sqlx::query!( + match sqlx::query!( r#" INSERT INTO user_stack (stack_id, user_id, name, body, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6) diff --git a/src/routes/stack/compose.rs b/src/routes/stack/compose.rs index 4d19a3f..4de94f8 100644 --- a/src/routes/stack/compose.rs +++ b/src/routes/stack/compose.rs @@ -51,7 +51,7 @@ pub async fn add( match stack { Some(stack) => { let id = stack.id.clone(); - let mut dc = DcBuilder::new(stack); + let dc = DcBuilder::new(stack); let fc = dc.build(); tracing::debug!("Docker compose file content {:?}", fc); @@ -104,7 +104,7 @@ pub async fn admin( match stack { Some(stack) => { let id = stack.id.clone(); - let mut dc = DcBuilder::new(stack); + let dc = DcBuilder::new(stack); let fc = dc.build(); // tracing::debug!("Docker compose file content {:?}", fc); return JsonResponse::build() diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs index 45c1b38..645a14a 100644 --- a/src/routes/stack/deploy.rs +++ b/src/routes/stack/deploy.rs @@ -57,7 +57,7 @@ pub async fn add( return match stack { Some(stack) => { let id = stack.id.clone(); - let mut dc = DcBuilder::new(stack); + let dc = DcBuilder::new(stack); dc.build(); let addr = sets.amqp.connection_string(); diff --git a/src/startup.rs b/src/startup.rs index 3306fcd..3d38420 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -27,7 +27,8 @@ pub async fn run( let server = HttpServer::new(move || { App::new() .wrap(TracingLogger::default()) - .service(web::scope("/health_check").service(crate::routes::health_check)) + .service(web::scope("/health_check") + .service(crate::routes::health_check)) .service( web::scope("/client") .wrap(HttpAuthentication::bearer( diff --git a/tests/custom-stack-payload-11.json b/tests/custom-stack-payload-11.json new file mode 100644 index 0000000..7113b57 --- /dev/null +++ b/tests/custom-stack-payload-11.json @@ -0,0 +1,2 @@ + +{"commonDomain":"","domainList":{},"region":"fsn1","zone":null,"server":"cx21","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":["statuspanel","fail2ban","nginx_feature","nginx_proxy_manager"],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":true,"disk_type":"pd-standart","cloud_token":"D3dkDL4Qy1NpFezTl60V5RYfB5p0BSwLLoKVHhEqmJQ3jObSG77irP86e9YtCYVi","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"web":[{"_etag":null,"_id":233,"_created":"2023-07-19T06:38:57.608807","_updated":"2023-11-17T11:38:12.904673","name":"FastAPI","code":"fastapi","role":["fastapi"],"type":"web","default":true,"popularity":null,"descr":null,"ports":{"public":["5050","8000","8080"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":2500,"height":2500,"image":"8d1ba06d-04e2-4523-879e-2846c86a10d8.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":null,"plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":0.1,"ram_size":"0.2Gb","disk_size":"0.2Gb","dockerhub_image":"fastapi","form":null,"versions":[{"_etag":null,"_id":587,"_created":null,"_updated":"2023-07-20T12:51:20.321999","app_id":233,"name":"0.0.1","version":"0.0.1","update_status":"ready_for_testing","tag":"0.0.1"},{"_etag":null,"_id":590,"_created":null,"_updated":"2023-07-20T08:36:49.651219","app_id":233,"name":"0.0.1","version":"0.0.1","update_status":"ready_for_testing","tag":"latest"},{"_etag":null,"_id":589,"_created":null,"_updated":"2023-07-20T08:36:55.200575","app_id":233,"name":"0.0.1","version":"0.0.1","update_status":"ready_for_testing","tag":"unstable"},{"_etag":"591","_id":591,"_created":null,"_updated":"2023-08-15T08:17:40.226186","app_id":233,"name":"Fastapi","version":"0.100.0","update_status":"published","tag":"stable"}],"domain":"fastapi6.test","sharedPorts":["8080"],"main":true,"version":{"_etag":"591","_id":591,"_created":null,"_updated":"2023-08-15T08:17:40.226186","app_id":233,"name":"Fastapi","version":"0.100.0","update_status":"published","tag":"stable"}},{"name":"MyCustomApp6","code":"mycustomapp6","domain":"mycustomapp.fastapi6.test","sharedPorts":["3000"],"versions":[],"custom":true,"type":"web","main":false,"_id":0,"dockerhub_user":"vsilent","dockerhub_name":"smarty-bot","disk_size":"0.8Gb","ram_size":"1.6Gb","cpu":0.6}],"feature":[{"_etag":null,"_id":235,"_created":"2023-08-11T07:07:12.123355","_updated":"2023-09-07T14:19:30.709139","name":"Nginx Proxy Manager","code":"nginx_proxy_manager","role":["nginx_proxy_manager"],"type":"feature","default":null,"popularity":null,"descr":null,"ports":{"public":["80","81","443"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":192,"height":192,"image":"205128e6-0303-4b62-b946-9810b61f3d04.png"},"dark":{}},"category_id":2,"parent_app_id":null,"full_description":null,"description":"

Nginx Proxy Manager is a user-friendly software application designed to effortlessly route traffic to your websites, whether they're hosted at home or elsewhere. It comes equipped with free SSL capabilities, eliminating the need for extensive Nginx or Letsencrypt knowledge. This tool proves especially handy for simplifying SSL generation and seamlessly proxying your docker containers.

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"1","ram_size":"1Gb","disk_size":"0.3Gb","dockerhub_image":"nginx-proxy-manager","form":null,"category":[{"name":"integrated_features"}],"group":[],"versions":[{"_id":601,"name":"Nginx proxy manager","version":"2.10.4","update_status":"published","tag":"stable"}],"links":[],"version":{"_id":601,"name":"Nginx proxy manager","version":"2.10.4","update_status":"published","tag":"stable"}},{"_etag":null,"_id":198,"_created":"2022-04-27T14:10:27.280327","_updated":"2023-08-03T08:24:18.958721","name":"Portainer CE Feature","code":"portainer_ce_feature","role":["portainer-ce-feature"],"type":"feature","default":null,"popularity":null,"descr":null,"ports":{"public":["9000","8000"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":1138,"height":1138,"image":"08589075-44e6-430e-98a5-f9dcf711e054.svg"},"dark":{}},"category_id":2,"parent_app_id":null,"full_description":null,"description":"

Portainer is a lightweight management UI which allows you to easily manage your different Docker environments (Docker hosts or Swarm clusters)

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":0.6,"ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"portainer-ce-feature","form":null,"versions":[{"_etag":null,"_id":456,"_created":"2022-04-25T12:44:30.964547","_updated":"2023-09-07T07:28:51.18965","app_id":198,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"}],"domain":"","sharedPorts":["9000"],"main":false,"version":{"_etag":null,"_id":456,"_created":"2022-04-25T12:44:30.964547","_updated":"2023-09-07T07:28:51.18965","app_id":198,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"}}],"service":[{"_etag":null,"_id":1,"_created":"2020-06-19T13:07:22.483252","_updated":"2023-08-08T10:38:12.307594","name":"MySQL","code":"mysql","role":[],"type":"service","default":null,"popularity":null,"descr":null,"ports":null,"commercial":null,"subscription":null,"autodeploy":false,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":256,"height":133,"image":"d83c4e8a-a3e9-4f06-8058-2392c846df31.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":"

MySQL Server, the world's most popular open-source database, and MySQL Cluster, a real-time, open-source transactional database.

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":0,"ram_size":null,"disk_size":null,"dockerhub_image":"mysql","form":null,"category":[null],"group":[{"_etag":null,"_id":12,"_created":null,"_updated":null,"name":"Database","code":"database"}],"versions":[{"_id":473,"name":"8.0.34","version":"8.0.34","update_status":"published","tag":"8.0.34"},{"_id":472,"name":"5.7.43","version":"5.7.43","update_status":"published","tag":"5.7.43"}],"links":[{"url":"https://dev.mysql.com","title":"MySQL","type":"vendor","follow":null},{"repo_owner":"mysql","repo_name":"mysql-server","type":"github","follow":null}],"domain":"","sharedPorts":[],"main":false,"version":{"_id":473,"name":"8.0.34","version":"8.0.34","update_status":"published","tag":"8.0.34"}}],"servers_count":3,"project_name":"FastAPI6","custom_stack_code":"fastapi6","project_git_url":"https://github.com/trydirect/fastapi.git"}} From a5268ffc8be137cbf6e0fe5a6b6a4ab80a661de1 Mon Sep 17 00:00:00 2001 From: vsilent Date: Thu, 23 Nov 2023 22:26:15 +0200 Subject: [PATCH 002/284] project/stack existence check --- src/routes/stack/add.rs | 29 +++++++++++++++++++++++++---- tests/custom-stack-payload-11.json | 2 -- 2 files changed, 25 insertions(+), 6 deletions(-) delete mode 100644 tests/custom-stack-payload-11.json diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index 4f08fe5..1d64815 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -11,10 +11,10 @@ use chrono::Utc; use serde_json::Value; use sqlx::PgPool; use std::str; -use serde_valid::json::FromJsonValue; use serde_valid::Validate; use tracing::Instrument; use uuid::Uuid; +use crate::models; #[tracing::instrument(name = "Add stack.")] @@ -37,6 +37,30 @@ pub async fn add( } }; + let stack_name = form.custom.custom_stack_code.clone(); + + let query_span = tracing::info_span!("Check project/stack existence by custom_stack_code."); + match sqlx::query_as!( + models::Stack, + r"SELECT * FROM user_stack WHERE name = $1", + stack_name + ) + .fetch_one(pool.get_ref()) + .instrument(query_span) + .await + { + Ok(record) => { + tracing::info!("record exists: id: {}, name: {}", record.id, record.name); + return JsonResponse::build().conflict("Stack with that name already exists" + .to_owned()); + } + Err(sqlx::Error::RowNotFound) => {} + Err(e) => { + tracing::error!("Failed to fetch stack info, error: {:?}", e); + return JsonResponse::build().err(format!("Internal Server Error")); + } + }; + let user_id = user.id.clone(); let request_id = Uuid::new_v4(); let request_span = tracing::info_span!( @@ -57,9 +81,6 @@ pub async fn add( let query_span = tracing::info_span!("Saving new stack details into the database"); - let stack_name = form.custom.custom_stack_code.clone(); - - let errors = form.validate().is_ok(); println!("{:?}",errors); let body: Value = match serde_json::to_value::(form) { diff --git a/tests/custom-stack-payload-11.json b/tests/custom-stack-payload-11.json deleted file mode 100644 index 7113b57..0000000 --- a/tests/custom-stack-payload-11.json +++ /dev/null @@ -1,2 +0,0 @@ - -{"commonDomain":"","domainList":{},"region":"fsn1","zone":null,"server":"cx21","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":["statuspanel","fail2ban","nginx_feature","nginx_proxy_manager"],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":true,"disk_type":"pd-standart","cloud_token":"D3dkDL4Qy1NpFezTl60V5RYfB5p0BSwLLoKVHhEqmJQ3jObSG77irP86e9YtCYVi","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"web":[{"_etag":null,"_id":233,"_created":"2023-07-19T06:38:57.608807","_updated":"2023-11-17T11:38:12.904673","name":"FastAPI","code":"fastapi","role":["fastapi"],"type":"web","default":true,"popularity":null,"descr":null,"ports":{"public":["5050","8000","8080"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":2500,"height":2500,"image":"8d1ba06d-04e2-4523-879e-2846c86a10d8.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":null,"plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":0.1,"ram_size":"0.2Gb","disk_size":"0.2Gb","dockerhub_image":"fastapi","form":null,"versions":[{"_etag":null,"_id":587,"_created":null,"_updated":"2023-07-20T12:51:20.321999","app_id":233,"name":"0.0.1","version":"0.0.1","update_status":"ready_for_testing","tag":"0.0.1"},{"_etag":null,"_id":590,"_created":null,"_updated":"2023-07-20T08:36:49.651219","app_id":233,"name":"0.0.1","version":"0.0.1","update_status":"ready_for_testing","tag":"latest"},{"_etag":null,"_id":589,"_created":null,"_updated":"2023-07-20T08:36:55.200575","app_id":233,"name":"0.0.1","version":"0.0.1","update_status":"ready_for_testing","tag":"unstable"},{"_etag":"591","_id":591,"_created":null,"_updated":"2023-08-15T08:17:40.226186","app_id":233,"name":"Fastapi","version":"0.100.0","update_status":"published","tag":"stable"}],"domain":"fastapi6.test","sharedPorts":["8080"],"main":true,"version":{"_etag":"591","_id":591,"_created":null,"_updated":"2023-08-15T08:17:40.226186","app_id":233,"name":"Fastapi","version":"0.100.0","update_status":"published","tag":"stable"}},{"name":"MyCustomApp6","code":"mycustomapp6","domain":"mycustomapp.fastapi6.test","sharedPorts":["3000"],"versions":[],"custom":true,"type":"web","main":false,"_id":0,"dockerhub_user":"vsilent","dockerhub_name":"smarty-bot","disk_size":"0.8Gb","ram_size":"1.6Gb","cpu":0.6}],"feature":[{"_etag":null,"_id":235,"_created":"2023-08-11T07:07:12.123355","_updated":"2023-09-07T14:19:30.709139","name":"Nginx Proxy Manager","code":"nginx_proxy_manager","role":["nginx_proxy_manager"],"type":"feature","default":null,"popularity":null,"descr":null,"ports":{"public":["80","81","443"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":192,"height":192,"image":"205128e6-0303-4b62-b946-9810b61f3d04.png"},"dark":{}},"category_id":2,"parent_app_id":null,"full_description":null,"description":"

Nginx Proxy Manager is a user-friendly software application designed to effortlessly route traffic to your websites, whether they're hosted at home or elsewhere. It comes equipped with free SSL capabilities, eliminating the need for extensive Nginx or Letsencrypt knowledge. This tool proves especially handy for simplifying SSL generation and seamlessly proxying your docker containers.

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"1","ram_size":"1Gb","disk_size":"0.3Gb","dockerhub_image":"nginx-proxy-manager","form":null,"category":[{"name":"integrated_features"}],"group":[],"versions":[{"_id":601,"name":"Nginx proxy manager","version":"2.10.4","update_status":"published","tag":"stable"}],"links":[],"version":{"_id":601,"name":"Nginx proxy manager","version":"2.10.4","update_status":"published","tag":"stable"}},{"_etag":null,"_id":198,"_created":"2022-04-27T14:10:27.280327","_updated":"2023-08-03T08:24:18.958721","name":"Portainer CE Feature","code":"portainer_ce_feature","role":["portainer-ce-feature"],"type":"feature","default":null,"popularity":null,"descr":null,"ports":{"public":["9000","8000"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":1138,"height":1138,"image":"08589075-44e6-430e-98a5-f9dcf711e054.svg"},"dark":{}},"category_id":2,"parent_app_id":null,"full_description":null,"description":"

Portainer is a lightweight management UI which allows you to easily manage your different Docker environments (Docker hosts or Swarm clusters)

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":0.6,"ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"portainer-ce-feature","form":null,"versions":[{"_etag":null,"_id":456,"_created":"2022-04-25T12:44:30.964547","_updated":"2023-09-07T07:28:51.18965","app_id":198,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"}],"domain":"","sharedPorts":["9000"],"main":false,"version":{"_etag":null,"_id":456,"_created":"2022-04-25T12:44:30.964547","_updated":"2023-09-07T07:28:51.18965","app_id":198,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"}}],"service":[{"_etag":null,"_id":1,"_created":"2020-06-19T13:07:22.483252","_updated":"2023-08-08T10:38:12.307594","name":"MySQL","code":"mysql","role":[],"type":"service","default":null,"popularity":null,"descr":null,"ports":null,"commercial":null,"subscription":null,"autodeploy":false,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":256,"height":133,"image":"d83c4e8a-a3e9-4f06-8058-2392c846df31.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":"

MySQL Server, the world's most popular open-source database, and MySQL Cluster, a real-time, open-source transactional database.

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":0,"ram_size":null,"disk_size":null,"dockerhub_image":"mysql","form":null,"category":[null],"group":[{"_etag":null,"_id":12,"_created":null,"_updated":null,"name":"Database","code":"database"}],"versions":[{"_id":473,"name":"8.0.34","version":"8.0.34","update_status":"published","tag":"8.0.34"},{"_id":472,"name":"5.7.43","version":"5.7.43","update_status":"published","tag":"5.7.43"}],"links":[{"url":"https://dev.mysql.com","title":"MySQL","type":"vendor","follow":null},{"repo_owner":"mysql","repo_name":"mysql-server","type":"github","follow":null}],"domain":"","sharedPorts":[],"main":false,"version":{"_id":473,"name":"8.0.34","version":"8.0.34","update_status":"published","tag":"8.0.34"}}],"servers_count":3,"project_name":"FastAPI6","custom_stack_code":"fastapi6","project_git_url":"https://github.com/trydirect/fastapi.git"}} From c9780b96b5ea7da04809cb4f92cce66916816390 Mon Sep 17 00:00:00 2001 From: Petru Date: Fri, 24 Nov 2023 17:50:03 +0200 Subject: [PATCH 003/284] issue-auth debug for client secret --- src/models/client.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/models/client.rs b/src/models/client.rs index afef0c1..d881597 100644 --- a/src/models/client.rs +++ b/src/models/client.rs @@ -9,10 +9,15 @@ pub struct Client { impl std::fmt::Debug for Client { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let secret: String = match self.secret.as_ref() { + Some(val) => val.chars().take(4).collect::() + "****", + None => "".to_string(), + }; + write!( f, - "Client {{id: {:?}, user_id: {:?}}}", - self.id, self.user_id + "Client {{id: {:?}, user_id: {:?}, secret: {}}}", + self.id, self.user_id, secret ) } } From a4e10679d5dd4faa1aad5e92bb2e7a2be004dd1c Mon Sep 17 00:00:00 2001 From: Petru Date: Fri, 24 Nov 2023 18:47:58 +0200 Subject: [PATCH 004/284] issue-auth refactor --- src/helpers/json.rs | 139 ++++++----------------------------- src/middleware/client.rs | 1 + src/routes/client/add.rs | 9 +-- src/routes/client/disable.rs | 2 +- src/routes/client/enable.rs | 2 +- src/routes/client/update.rs | 2 +- src/routes/rating/add.rs | 20 ++--- src/routes/rating/get.rs | 16 ++-- src/routes/stack/add.rs | 23 +++--- src/routes/stack/compose.rs | 23 +++--- src/routes/stack/deploy.rs | 50 ++++++------- src/routes/stack/get.rs | 32 ++++---- 12 files changed, 99 insertions(+), 220 deletions(-) diff --git a/src/helpers/json.rs b/src/helpers/json.rs index 87e7327..efdfb0e 100644 --- a/src/helpers/json.rs +++ b/src/helpers/json.rs @@ -1,15 +1,15 @@ -use actix_web::error::{ErrorBadRequest, ErrorConflict, ErrorNotFound, ErrorInternalServerError}; -use serde_derive::Serialize; +use actix_web::error::{ErrorBadRequest, ErrorConflict, ErrorInternalServerError, ErrorNotFound}; use actix_web::web::Json; use actix_web::Error; use actix_web::Result; +use serde_derive::Serialize; #[derive(Serialize)] pub(crate) struct JsonResponse { pub(crate) message: String, pub(crate) id: Option, pub(crate) item: Option, - pub(crate) list: Option> + pub(crate) list: Option>, } #[derive(Serialize, Default)] @@ -41,9 +41,9 @@ where self } - fn to_json_response(self, msg: String) -> JsonResponse { + fn to_json_response>(self, msg: I) -> JsonResponse { JsonResponse { - message: msg, + message: msg.into(), id: self.id, item: self.item, list: self.list, @@ -51,63 +51,43 @@ where } pub(crate) fn ok>(self, msg: I) -> Result>, Error> { - Ok(Json(self.to_json_response(msg.into()))) + Ok(Json(self.to_json_response(msg))) } - pub(crate) fn err>(self, msg: I) -> Result>, Error> { - let json_response = self.to_json_response(msg.into()); + pub(crate) fn bad_request>( + self, + msg: I, + ) -> Result>, Error> { + let json_response = self.to_json_response(msg); Err(ErrorBadRequest( serde_json::to_string(&json_response).unwrap(), )) } - pub(crate) fn not_found(self, msg: String) -> Result>, Error> { - - let json_response = JsonResponse { - message: msg, - id: self.id, - item: self.item, - list: self.list - }; + pub(crate) fn not_found>(self, msg: I) -> Result>, Error> { + let json_response = self.to_json_response(msg); Err(ErrorNotFound( - serde_json::to_string(&json_response).unwrap())) + serde_json::to_string(&json_response).unwrap(), + )) } - pub(crate) fn internal_error(self, msg: String) -> Result>, Error> { - - let json_response = JsonResponse { - message: msg, - id: self.id, - item: self.item, - list: self.list - }; + pub(crate) fn internal_server_error>( + self, + msg: I, + ) -> Result>, Error> { + let json_response = self.to_json_response(msg); Err(ErrorInternalServerError( - serde_json::to_string(&json_response).unwrap())) + serde_json::to_string(&json_response).unwrap(), + )) } - pub(crate) fn conflict(self, msg: String) -> Result>, Error> { - - let json_response = JsonResponse { - message: msg, - id: self.id, - item: self.item, - list: self.list - }; + pub(crate) fn conflict>(self, msg: I) -> Result>, Error> { + let json_response = self.to_json_response(msg); Err(ErrorConflict( - serde_json::to_string(&json_response).unwrap())) - } - - pub(crate) fn err_internal_server_error>( - self, - msg: I, - ) -> Result>, Error> { - let json_response = self.to_json_response(msg.into()); - - Err(ErrorInternalServerError( serde_json::to_string(&json_response).unwrap(), )) } @@ -120,75 +100,4 @@ where pub fn build() -> JsonResponseBuilder { JsonResponseBuilder::default() } - - pub(crate) fn new(message: String, - id: Option, - item:Option, - list: Option>) -> Self { - tracing::debug!("Executed.."); - JsonResponse { - message, - id, - item, - list, - } - } - - // pub(crate) fn ok(id: i32, message: &str) -> JsonResponse { - // - // let msg = if !message.trim().is_empty() { - // message.to_string() - // } - // else{ - // String::from("Success") - // }; - // - // JsonResponse { - // message: msg, - // id: Some(id), - // item: None, - // list: None, - // } - // } - - // pub(crate) fn not_found() -> Self { - // JsonResponse { - // id: None, - // item: None, - // message: format!("Object not found"), - // list: None, - // } - // } - // - // pub(crate) fn internal_error(message: &str) -> Self { - // - // let msg = if !message.trim().is_empty() { - // message.to_string() - // } - // else{ - // String::from("Internal error") - // }; - // JsonResponse { - // id: None, - // item: None, - // message: msg, - // list: None, - // } - // } - // - // pub(crate) fn not_valid(message: &str) -> Self { - // - // let msg = if !message.trim().is_empty() { - // message.to_string() - // } - // else{ - // String::from("Validation error") - // }; - // JsonResponse { - // id: None, - // item: None, - // message: msg, - // list: None, - // } - // } } diff --git a/src/middleware/client.rs b/src/middleware/client.rs index dc76c44..65f4002 100644 --- a/src/middleware/client.rs +++ b/src/middleware/client.rs @@ -1,3 +1,4 @@ +use crate::helpers::JsonResponse; use crate::models::Client; use actix_http::header::CONTENT_LENGTH; use actix_web::error::{ErrorForbidden, ErrorInternalServerError, ErrorNotFound, PayloadError}; diff --git a/src/routes/client/add.rs b/src/routes/client/add.rs index eee2ce0..1b9b709 100644 --- a/src/routes/client/add.rs +++ b/src/routes/client/add.rs @@ -9,7 +9,6 @@ use sqlx::PgPool; use std::sync::Arc; use tracing::Instrument; - #[tracing::instrument(name = "Add client.")] #[post("")] pub async fn add_handler( @@ -41,12 +40,12 @@ pub async fn add_handler( client_count ); - return JsonResponse::build().err("Too many clients created".to_owned()); + return JsonResponse::build().bad_request("Too many clients created"); } } Err(e) => { tracing::error!("Failed to execute query: {:?}", e); - return JsonResponse::build().internal_error("Internal Server Error".to_owned()); + return JsonResponse::build().internal_server_error("Internal Server Error"); } }; @@ -79,12 +78,12 @@ pub async fn add_handler( return JsonResponse::build() .set_id(client.id) .set_item(Some(client)) - .ok("OK".to_owned()); + .ok("OK"); } Err(e) => { tracing::error!("Failed to execute query: {:?}", e); let err = format!("Failed to insert. {}", e); - return JsonResponse::build().err(err); + return JsonResponse::build().bad_request(err); } } } diff --git a/src/routes/client/disable.rs b/src/routes/client/disable.rs index 383130b..3ec7154 100644 --- a/src/routes/client/disable.rs +++ b/src/routes/client/disable.rs @@ -62,7 +62,7 @@ pub async fn disable_handler( } Err(e) => { tracing::error!("Failed to execute query: {:?}", e); - JsonResponse::build().err("") + JsonResponse::build().bad_request("") } } } diff --git a/src/routes/client/enable.rs b/src/routes/client/enable.rs index a870c65..f10bf09 100644 --- a/src/routes/client/enable.rs +++ b/src/routes/client/enable.rs @@ -69,7 +69,7 @@ pub async fn enable_handler( } Err(e) => { tracing::error!("Failed to execute query: {:?}", e); - JsonResponse::build().err_internal_server_error("") + JsonResponse::build().internal_server_error("") } } } diff --git a/src/routes/client/update.rs b/src/routes/client/update.rs index f50b4ed..c833508 100644 --- a/src/routes/client/update.rs +++ b/src/routes/client/update.rs @@ -68,7 +68,7 @@ pub async fn update_handler( } Err(e) => { tracing::error!("Failed to execute query: {:?}", e); - JsonResponse::build().err_internal_server_error("") + JsonResponse::build().internal_server_error("") } } } diff --git a/src/routes/rating/add.rs b/src/routes/rating/add.rs index dd13eee..b099cfe 100644 --- a/src/routes/rating/add.rs +++ b/src/routes/rating/add.rs @@ -3,20 +3,15 @@ use crate::helpers::JsonResponse; use crate::models; use crate::models::user::User; use crate::models::RateCategory; +use actix_web::{post, web, Responder, Result}; use sqlx::PgPool; use tracing::Instrument; -use actix_web::{ - web, - post, - Responder, Result, -}; // workflow // add, update, list, get(user_id), ACL, // ACL - access to func for a user // ACL - access to objects for a user - #[tracing::instrument(name = "Add rating.")] #[post("")] pub async fn add_handler( @@ -39,8 +34,7 @@ pub async fn add_handler( } Err(e) => { tracing::error!("Failed to fetch product: {:?}, error: {:?}", form.obj_id, e); - return JsonResponse::::build() - .err(format!("Object not found {}", form.obj_id)); + return JsonResponse::::build().bad_request("Object not found"); } }; @@ -63,12 +57,12 @@ pub async fn add_handler( form.obj_id, form.category ); - return JsonResponse::build().conflict("Already rated".to_owned()); + return JsonResponse::build().conflict("Already rated"); } Err(sqlx::Error::RowNotFound) => {} Err(e) => { tracing::error!("Failed to fetch rating, error: {:?}", e); - return JsonResponse::build().err(format!("Internal Server Error")); + return JsonResponse::build().internal_server_error("Internal Server Error"); } } @@ -96,13 +90,11 @@ pub async fn add_handler( Ok(result) => { tracing::info!("New rating {} have been saved to database", result.id); - JsonResponse::build() - .set_id(result.id) - .ok("Saved".to_owned()) + JsonResponse::build().set_id(result.id).ok("Saved") } Err(e) => { tracing::error!("Failed to execute query: {:?}", e); - JsonResponse::build().internal_error("Failed to insert".to_owned()) + JsonResponse::build().internal_server_error("Failed to insert") } } } diff --git a/src/routes/rating/get.rs b/src/routes/rating/get.rs index 75281c0..e781d9a 100644 --- a/src/routes/rating/get.rs +++ b/src/routes/rating/get.rs @@ -32,23 +32,19 @@ pub async fn get_handler( return JsonResponse::build().set_item(Some(rating)).ok("OK"); } Err(sqlx::Error::RowNotFound) => { - return JsonResponse::build().err("Not Found"); + return JsonResponse::build().not_found(""); } Err(e) => { tracing::error!("Failed to fetch rating, error: {:?}", e); - return JsonResponse::build().err("Internal Server Error"); + return JsonResponse::build().internal_server_error(""); } } } #[tracing::instrument(name = "Get all ratings.")] #[get("")] -pub async fn list_handler( - path: web::Path<()>, - pool: web::Data, -) -> Result { +pub async fn list_handler(path: web::Path<()>, pool: web::Data) -> Result { /// Get ratings of all users - let query_span = tracing::info_span!("Get all rates."); // let category = path.0; match sqlx::query_as!(models::Rating, r"SELECT * FROM rating") @@ -58,14 +54,14 @@ pub async fn list_handler( { Ok(rating) => { tracing::info!("Ratings found: {:?}", rating.len()); - return JsonResponse::build().set_list(rating).ok("OK".to_owned()); + return JsonResponse::build().set_list(rating).ok("OK"); } Err(sqlx::Error::RowNotFound) => { - return JsonResponse::build().not_found("Not Found".to_owned()); + return JsonResponse::build().not_found(""); } Err(e) => { tracing::error!("Failed to fetch rating, error: {:?}", e); - return JsonResponse::build().internal_error("Internal Server Error".to_owned()); + return JsonResponse::build().internal_server_error(""); } } } diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index 27260e0..8176cfa 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -1,20 +1,19 @@ +use crate::forms::stack::StackForm; +use crate::helpers::JsonResponse; +use crate::models; +use crate::models::user::User; +use actix_web::post; use actix_web::{ web, web::{Bytes, Data}, Responder, Result, }; -use crate::forms::stack::StackForm; -use crate::helpers::JsonResponse; -use crate::models::user::User; -use actix_web::post; use chrono::Utc; use serde_json::Value; use sqlx::PgPool; use std::str; use tracing::Instrument; use uuid::Uuid; -use crate::models; - #[tracing::instrument(name = "Add stack.")] #[post("")] @@ -23,16 +22,13 @@ pub async fn add( user: web::ReqData, pool: Data, ) -> Result { - let body_bytes = actix_web::body::to_bytes(body).await.unwrap(); let body_str = str::from_utf8(&body_bytes).unwrap(); let form = match serde_json::from_str::(body_str) { - Ok(f) => { - f - } + Ok(f) => f, Err(_err) => { let msg = format!("Invalid data. {:?}", _err); - return JsonResponse::::build().err("Invalid data".to_owned()); + return JsonResponse::::build().bad_request("Invalid data"); } }; @@ -87,12 +83,11 @@ pub async fn add( "req_id: {} New stack details have been saved to database", request_id ); - return JsonResponse::build().set_id(record.id).ok("OK".to_owned()); + return JsonResponse::build().set_id(record.id).ok("OK"); } Err(e) => { tracing::error!("req_id: {} Failed to execute query: {:?}", request_id, e); - return JsonResponse::build().err("Internal Server Error".to_owned()); + return JsonResponse::build().bad_request("Internal Server Error"); } }; } - diff --git a/src/routes/stack/compose.rs b/src/routes/stack/compose.rs index 4d19a3f..7b2f8a4 100644 --- a/src/routes/stack/compose.rs +++ b/src/routes/stack/compose.rs @@ -4,6 +4,7 @@ use actix_web::{ Responder, Result, }; +use crate::helpers::stack::builder::DcBuilder; use crate::helpers::JsonResponse; use crate::models::user::User; use crate::models::Stack; @@ -12,7 +13,6 @@ use sqlx::PgPool; use std::str; use tracing::Instrument; use uuid::Uuid; -use crate::helpers::stack::builder::DcBuilder; #[tracing::instrument(name = "User's generate docker-compose.")] #[post("/{id}")] @@ -29,10 +29,11 @@ pub async fn add( r#" SELECT * FROM user_stack WHERE id=$1 AND user_id=$2 LIMIT 1 "#, - id, user.id + id, + user.id ) - .fetch_one(pool.get_ref()) - .await + .fetch_one(pool.get_ref()) + .await { Ok(stack) => { tracing::info!("stack found: {:?}", stack.id,); @@ -58,10 +59,10 @@ pub async fn add( return JsonResponse::build() .set_id(id) .set_item(fc.unwrap()) - .ok("Success".to_owned()); + .ok("Success"); } None => { - return JsonResponse::build().err("Could not generate compose file".to_owned()); + return JsonResponse::build().bad_request("Could not generate compose file"); } } } @@ -84,8 +85,8 @@ pub async fn admin( "#, id, ) - .fetch_one(pool.get_ref()) - .await + .fetch_one(pool.get_ref()) + .await { Ok(stack) => { tracing::info!("stack found: {:?}", stack.id,); @@ -109,11 +110,11 @@ pub async fn admin( // tracing::debug!("Docker compose file content {:?}", fc); return JsonResponse::build() .set_id(id) - .set_item(fc.unwrap()).ok("Success".to_owned()); - + .set_item(fc.unwrap()) + .ok("Success"); } None => { - return JsonResponse::build().err("Could not generate compose file".to_owned()); + return JsonResponse::build().bad_request("Could not generate compose file"); } } } diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs index 45c1b38..b76b63c 100644 --- a/src/routes/stack/deploy.rs +++ b/src/routes/stack/deploy.rs @@ -1,23 +1,16 @@ -use std::sync::Arc; -use actix_web::{ - web, - post, - web::Data, - Responder, Result, -}; -use crate::models::user::User; -use crate::models::stack::Stack; -use sqlx::PgPool; -use lapin::{ - options::*, publisher_confirm::Confirmation, BasicProperties, Connection, - ConnectionProperties -}; use crate::configuration::Settings; -use crate::helpers::JsonResponse; +use crate::forms::StackPayload; use crate::helpers::stack::builder::DcBuilder; +use crate::helpers::JsonResponse; +use crate::models::stack::Stack; +use crate::models::user::User; +use actix_web::{post, web, web::Data, Responder, Result}; use futures_lite::stream::StreamExt; -use crate::forms::StackPayload; - +use lapin::{ + options::*, publisher_confirm::Confirmation, BasicProperties, Connection, ConnectionProperties, +}; +use sqlx::PgPool; +use std::sync::Arc; #[tracing::instrument(name = "Deploy for every user. Admin endpoint")] #[post("/{id}/deploy")] @@ -37,8 +30,8 @@ pub async fn add( "#, id ) - .fetch_one(pool.get_ref()) - .await + .fetch_one(pool.get_ref()) + .await { Ok(stack) => { tracing::info!("Stack found: {:?}", stack.id,); @@ -71,9 +64,8 @@ pub async fn add( tracing::info!("RABBITMQ CONNECTED"); let channel = conn.create_channel().await.unwrap(); - let mut stack_data = serde_json::from_value::( - dc.stack.body.clone() - ).unwrap(); + let mut stack_data = + serde_json::from_value::(dc.stack.body.clone()).unwrap(); stack_data.id = Some(id); stack_data.user_token = Some(user.id.clone()); @@ -91,15 +83,15 @@ pub async fn add( _payload, BasicProperties::default(), ) - .await.unwrap() - .await.unwrap(); + .await + .unwrap() + .await + .unwrap(); assert_eq!(confirm, Confirmation::NotRequested); tracing::debug!("Message sent to rabbitmq"); - return JsonResponse::::build().set_id(id).ok("Success".to_owned()); + return JsonResponse::::build().set_id(id).ok("Success"); } - None => { - JsonResponse::build().internal_error("Deployment failed".to_owned()) - } - } + None => JsonResponse::build().internal_server_error("Deployment failed"), + }; } diff --git a/src/routes/stack/get.rs b/src/routes/stack/get.rs index 271d2dc..2264a14 100644 --- a/src/routes/stack/get.rs +++ b/src/routes/stack/get.rs @@ -1,12 +1,11 @@ -use actix_web::{web, get, Responder, Result}; -use sqlx::PgPool; use crate::helpers::{JsonResponse, JsonResponseBuilder}; use crate::models; use crate::models::user::User; +use actix_web::{get, web, Responder, Result}; +use sqlx::PgPool; use std::convert::From; use tracing::Instrument; - #[tracing::instrument(name = "Get logged user stack.")] #[get("/{id}")] pub async fn item( @@ -15,7 +14,6 @@ pub async fn item( pool: web::Data, ) -> Result { /// Get stack apps of logged user only - let (id,) = path.into_inner(); tracing::info!("User {:?} gets stack by id {:?}", user.id, id); @@ -24,21 +22,20 @@ pub async fn item( r#" SELECT * FROM user_stack WHERE id=$1 AND user_id=$2 LIMIT 1 "#, - id, user.id + id, + user.id ) .fetch_one(pool.get_ref()) .await { Ok(stack) => { tracing::info!("Stack found: {:?}", stack.id,); - return JsonResponse::build().set_item(Some(stack)).ok("OK".to_owned()); - } - Err(sqlx::Error::RowNotFound) => { - JsonResponse::build().not_found("Record not found".to_owned()) + return JsonResponse::build().set_item(Some(stack)).ok("OK"); } + Err(sqlx::Error::RowNotFound) => JsonResponse::build().not_found("Record not found"), Err(e) => { tracing::error!("Failed to fetch stack, error: {:?}", e); - return JsonResponse::build().internal_error("Could not fetch data".to_owned()); + return JsonResponse::build().internal_server_error("Could not fetch data"); } } } @@ -50,11 +47,9 @@ pub async fn list( path: web::Path<(String,)>, pool: web::Data, ) -> Result { - /// This is admin endpoint, used by a m2m app, client app is confidential /// it should return stacks by user id /// in order to pass validation at external deployment service - let (id,) = path.into_inner(); tracing::info!("Logged user: {:?}", user.id); tracing::info!("Get stack list for user {:?}", id); @@ -68,21 +63,20 @@ pub async fn list( "#, id ) - .fetch_all(pool.get_ref()) - .instrument(query_span) - .await + .fetch_all(pool.get_ref()) + .instrument(query_span) + .await { Ok(list) => { - return JsonResponse::build().set_list(list).ok("OK".to_string()); + return JsonResponse::build().set_list(list).ok("OK"); } Err(sqlx::Error::RowNotFound) => { tracing::error!("No stacks found for user: {:?}", &user.id); - return JsonResponse::build().not_found("No stacks found for user".to_string()) + return JsonResponse::build().not_found("No stacks found for user"); } Err(e) => { tracing::error!("Failed to fetch stack, error: {:?}", e); - return JsonResponse::build().internal_error("Could not fetch".to_string()); + return JsonResponse::build().internal_server_error("Could not fetch"); } } } - From a49e5c7f84548b7391a67e7c26a341afcd04c235 Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 25 Nov 2023 05:09:23 +0200 Subject: [PATCH 005/284] issue-auth skip_serializing_if --- src/helpers/json.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/helpers/json.rs b/src/helpers/json.rs index efdfb0e..cd86a44 100644 --- a/src/helpers/json.rs +++ b/src/helpers/json.rs @@ -7,8 +7,11 @@ use serde_derive::Serialize; #[derive(Serialize)] pub(crate) struct JsonResponse { pub(crate) message: String, + #[serde(skip_serializing_if = "Option::is_none")] pub(crate) id: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub(crate) item: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub(crate) list: Option>, } From 8c510f792c04e5ed528902632dddc8443875a4a4 Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 25 Nov 2023 05:56:31 +0200 Subject: [PATCH 006/284] issue-auth to_string --- src/helpers/json.rs | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/src/helpers/json.rs b/src/helpers/json.rs index cd86a44..f7ec87f 100644 --- a/src/helpers/json.rs +++ b/src/helpers/json.rs @@ -53,6 +53,11 @@ where } } + fn to_string>(self, msg: I) -> String { + let json_response = self.to_json_response(msg); + serde_json::to_string(&json_response).unwrap() + } + pub(crate) fn ok>(self, msg: I) -> Result>, Error> { Ok(Json(self.to_json_response(msg))) } @@ -61,38 +66,22 @@ where self, msg: I, ) -> Result>, Error> { - let json_response = self.to_json_response(msg); - - Err(ErrorBadRequest( - serde_json::to_string(&json_response).unwrap(), - )) + Err(ErrorBadRequest(self.to_string(msg))) } pub(crate) fn not_found>(self, msg: I) -> Result>, Error> { - let json_response = self.to_json_response(msg); - - Err(ErrorNotFound( - serde_json::to_string(&json_response).unwrap(), - )) + Err(ErrorNotFound(self.to_string(msg))) } pub(crate) fn internal_server_error>( self, msg: I, ) -> Result>, Error> { - let json_response = self.to_json_response(msg); - - Err(ErrorInternalServerError( - serde_json::to_string(&json_response).unwrap(), - )) + Err(ErrorInternalServerError(self.to_string(msg))) } pub(crate) fn conflict>(self, msg: I) -> Result>, Error> { - let json_response = self.to_json_response(msg); - - Err(ErrorConflict( - serde_json::to_string(&json_response).unwrap(), - )) + Err(ErrorConflict(self.to_string(msg))) } } From 02fe07d6ccc0d16aa53eb8ac6c70d4c9714a2dba Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 25 Nov 2023 05:59:05 +0200 Subject: [PATCH 007/284] issue-auth removed set_id in client add --- src/routes/client/add.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/routes/client/add.rs b/src/routes/client/add.rs index 1b9b709..21aba10 100644 --- a/src/routes/client/add.rs +++ b/src/routes/client/add.rs @@ -75,10 +75,7 @@ pub async fn add_handler( tracing::info!("New client {} have been saved to database", result.id); client.id = result.id; - return JsonResponse::build() - .set_id(client.id) - .set_item(Some(client)) - .ok("OK"); + return JsonResponse::build().set_item(Some(client)).ok("OK"); } Err(e) => { tracing::error!("Failed to execute query: {:?}", e); From a2c7bf6216f08761fb2281d97de0a2836e8d9d1a Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 25 Nov 2023 06:07:17 +0200 Subject: [PATCH 008/284] issue-auth client middleware + JsonResponse --- src/helpers/json.rs | 2 +- src/middleware/client.rs | 30 ++++++++++++++++++++++-------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/helpers/json.rs b/src/helpers/json.rs index f7ec87f..419ad5d 100644 --- a/src/helpers/json.rs +++ b/src/helpers/json.rs @@ -53,7 +53,7 @@ where } } - fn to_string>(self, msg: I) -> String { + pub(crate) fn to_string>(self, msg: I) -> String { let json_response = self.to_json_response(msg); serde_json::to_string(&json_response).unwrap() } diff --git a/src/middleware/client.rs b/src/middleware/client.rs index 65f4002..99df23f 100644 --- a/src/middleware/client.rs +++ b/src/middleware/client.rs @@ -74,8 +74,10 @@ where fn call(&self, mut req: ServiceRequest) -> Self::Future { let service = self.service.clone(); async move { - let client_id: i32 = get_header(&req, "stacker-id").map_err(|m| ErrorBadRequest(m))?; - let hash: String = get_header(&req, "stacker-hash").map_err(|m| ErrorBadRequest(m))?; + let client_id: i32 = get_header(&req, "stacker-id") + .map_err(|m| ErrorBadRequest(JsonResponse::::build().to_string(m)))?; + let hash: String = get_header(&req, "stacker-hash") + .map_err(|m| ErrorBadRequest(JsonResponse::::build().to_string(m)))?; let query_span = tracing::info_span!("Fetching the client by ID"); let db_pool = req.app_data::>>().unwrap(); @@ -96,15 +98,21 @@ where { Ok(client) if client.secret.is_some() => client, Ok(_client) => { - return Err(ErrorForbidden("client is not active")); + return Err(ErrorForbidden( + JsonResponse::::build().to_string("client is not active"), + )); } Err(sqlx::Error::RowNotFound) => { - return Err(ErrorNotFound("the client is not found")); + return Err(ErrorNotFound( + JsonResponse::::build().to_string("the client is not found"), + )); } Err(e) => { tracing::error!("Failed to execute fetch query: {:?}", e); - return Err(ErrorInternalServerError("")); + return Err(ErrorInternalServerError( + JsonResponse::::build().to_string(""), + )); } }; @@ -129,14 +137,18 @@ where Err(err) => { tracing::error!("error generating hmac {err:?}"); - return Err(ErrorInternalServerError("")); + return Err(ErrorInternalServerError( + JsonResponse::::build().to_string(""), + )); } }; mac.update(body.as_ref()); let computed_hash = format!("{:x}", mac.finalize().into_bytes()); if hash != computed_hash { - return Err(ErrorBadRequest("hash is wrong")); + return Err(ErrorBadRequest( + JsonResponse::::build().to_string("hash is wrong"), + )); } let (_, mut payload) = actix_http::h1::Payload::create(true); @@ -146,7 +158,9 @@ where match req.extensions_mut().insert(Arc::new(client)) { Some(_) => { tracing::error!("client middleware already called once"); - return Err(ErrorInternalServerError("")); + return Err(ErrorInternalServerError( + JsonResponse::::build().to_string(""), + )); } None => {} } From 53e96690c3531d471f902eeec1a187dd44844a41 Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 25 Nov 2023 06:27:29 +0200 Subject: [PATCH 009/284] issue-auth set_msg --- src/helpers/json.rs | 24 +++++++++++++++--------- src/middleware/client.rs | 28 ++++++++++++++++++---------- src/routes/client/add.rs | 4 +++- src/routes/client/disable.rs | 4 +++- src/routes/client/enable.rs | 2 +- src/routes/client/update.rs | 4 ++-- 6 files changed, 42 insertions(+), 24 deletions(-) diff --git a/src/helpers/json.rs b/src/helpers/json.rs index 419ad5d..8990788 100644 --- a/src/helpers/json.rs +++ b/src/helpers/json.rs @@ -20,6 +20,7 @@ pub struct JsonResponseBuilder where T: serde::Serialize + Default, { + message: String, id: Option, item: Option, list: Option>, @@ -29,6 +30,11 @@ impl JsonResponseBuilder where T: serde::Serialize + Default, { + pub(crate) fn set_msg>(mut self, msg: I) -> Self { + self.message = msg.into(); + self + } + pub(crate) fn set_item(mut self, item: T) -> Self { self.item = Some(item); self @@ -44,44 +50,44 @@ where self } - fn to_json_response>(self, msg: I) -> JsonResponse { + fn to_json_response(self) -> JsonResponse { JsonResponse { - message: msg.into(), + message: self.message, id: self.id, item: self.item, list: self.list, } } - pub(crate) fn to_string>(self, msg: I) -> String { - let json_response = self.to_json_response(msg); + pub(crate) fn to_string(self) -> String { + let json_response = self.to_json_response(); serde_json::to_string(&json_response).unwrap() } pub(crate) fn ok>(self, msg: I) -> Result>, Error> { - Ok(Json(self.to_json_response(msg))) + Ok(Json(self.set_msg(msg).to_json_response())) } pub(crate) fn bad_request>( self, msg: I, ) -> Result>, Error> { - Err(ErrorBadRequest(self.to_string(msg))) + Err(ErrorBadRequest(self.set_msg(msg).to_string())) } pub(crate) fn not_found>(self, msg: I) -> Result>, Error> { - Err(ErrorNotFound(self.to_string(msg))) + Err(ErrorNotFound(self.set_msg(msg).to_string())) } pub(crate) fn internal_server_error>( self, msg: I, ) -> Result>, Error> { - Err(ErrorInternalServerError(self.to_string(msg))) + Err(ErrorInternalServerError(self.set_msg(msg).to_string())) } pub(crate) fn conflict>(self, msg: I) -> Result>, Error> { - Err(ErrorConflict(self.to_string(msg))) + Err(ErrorConflict(self.set_msg(msg).to_string())) } } diff --git a/src/middleware/client.rs b/src/middleware/client.rs index 99df23f..29931d6 100644 --- a/src/middleware/client.rs +++ b/src/middleware/client.rs @@ -74,10 +74,12 @@ where fn call(&self, mut req: ServiceRequest) -> Self::Future { let service = self.service.clone(); async move { - let client_id: i32 = get_header(&req, "stacker-id") - .map_err(|m| ErrorBadRequest(JsonResponse::::build().to_string(m)))?; - let hash: String = get_header(&req, "stacker-hash") - .map_err(|m| ErrorBadRequest(JsonResponse::::build().to_string(m)))?; + let client_id: i32 = get_header(&req, "stacker-id").map_err(|m| { + ErrorBadRequest(JsonResponse::::build().set_msg(m).to_string()) + })?; + let hash: String = get_header(&req, "stacker-hash").map_err(|m| { + ErrorBadRequest(JsonResponse::::build().set_msg(m).to_string()) + })?; let query_span = tracing::info_span!("Fetching the client by ID"); let db_pool = req.app_data::>>().unwrap(); @@ -99,19 +101,23 @@ where Ok(client) if client.secret.is_some() => client, Ok(_client) => { return Err(ErrorForbidden( - JsonResponse::::build().to_string("client is not active"), + JsonResponse::::build() + .set_msg("client is not active") + .to_string(), )); } Err(sqlx::Error::RowNotFound) => { return Err(ErrorNotFound( - JsonResponse::::build().to_string("the client is not found"), + JsonResponse::::build() + .set_msg("the client is not found") + .to_string(), )); } Err(e) => { tracing::error!("Failed to execute fetch query: {:?}", e); return Err(ErrorInternalServerError( - JsonResponse::::build().to_string(""), + JsonResponse::::build().to_string(), )); } }; @@ -138,7 +144,7 @@ where tracing::error!("error generating hmac {err:?}"); return Err(ErrorInternalServerError( - JsonResponse::::build().to_string(""), + JsonResponse::::build().to_string(), )); } }; @@ -147,7 +153,9 @@ where let computed_hash = format!("{:x}", mac.finalize().into_bytes()); if hash != computed_hash { return Err(ErrorBadRequest( - JsonResponse::::build().to_string("hash is wrong"), + JsonResponse::::build() + .set_msg("hash is wrong") + .to_string(), )); } @@ -159,7 +167,7 @@ where Some(_) => { tracing::error!("client middleware already called once"); return Err(ErrorInternalServerError( - JsonResponse::::build().to_string(""), + JsonResponse::::build().to_string(), )); } None => {} diff --git a/src/routes/client/add.rs b/src/routes/client/add.rs index 21aba10..9e722e3 100644 --- a/src/routes/client/add.rs +++ b/src/routes/client/add.rs @@ -55,7 +55,9 @@ pub async fn add_handler( client.secret = client::generate_secret(pool.get_ref(), 255) .await .map(|s| Some(s)) - .map_err(|s| ErrorInternalServerError(s))?; //todo move to helpers::JsonResponse + .map_err(|s| { + ErrorInternalServerError(JsonResponse::::build().set_msg(s).to_string()) + })?; let query_span = tracing::info_span!("Saving new client into the database"); match sqlx::query!( diff --git a/src/routes/client/disable.rs b/src/routes/client/disable.rs index 3ec7154..f9a4a50 100644 --- a/src/routes/client/disable.rs +++ b/src/routes/client/disable.rs @@ -39,7 +39,9 @@ pub async fn disable_handler( Err("") } } - .map_err(|s| ErrorInternalServerError(s))?; //todo + .map_err(|s| { + ErrorInternalServerError(JsonResponse::::build().set_msg(s).to_string()) + })?; client.secret = None; let query_span = tracing::info_span!("Updating client into the database"); diff --git a/src/routes/client/enable.rs b/src/routes/client/enable.rs index f10bf09..a7b024d 100644 --- a/src/routes/client/enable.rs +++ b/src/routes/client/enable.rs @@ -41,7 +41,7 @@ pub async fn enable_handler( Err("") } } - .map_err(|s| ErrorBadRequest(s))?; //todo + .map_err(|s| ErrorBadRequest(JsonResponse::::build().set_msg(s).to_string()))?; client.secret = client::generate_secret(pool.get_ref(), 255) .await diff --git a/src/routes/client/update.rs b/src/routes/client/update.rs index c833508..34d7bfc 100644 --- a/src/routes/client/update.rs +++ b/src/routes/client/update.rs @@ -40,12 +40,12 @@ pub async fn update_handler( Err("") } } - .map_err(|s| ErrorBadRequest(s))?; //todo + .map_err(|s| ErrorBadRequest(JsonResponse::::build().set_msg(s).to_string()))?; client.secret = client::generate_secret(pool.get_ref(), 255) .await .map(|s| Some(s)) - .map_err(|s| ErrorBadRequest(s))?; //todo + .map_err(|s| ErrorBadRequest(JsonResponse::::build().set_msg(s).to_string()))?; let query_span = tracing::info_span!("Updating client into the database"); match sqlx::query!( From 53c8505c69f095273e9ffa732ef146dc71debdd7 Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 25 Nov 2023 06:29:33 +0200 Subject: [PATCH 010/284] issue-auth removed todo --- src/routes/test/deploy.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/routes/test/deploy.rs b/src/routes/test/deploy.rs index 945e293..7a8eddf 100644 --- a/src/routes/test/deploy.rs +++ b/src/routes/test/deploy.rs @@ -9,7 +9,6 @@ struct DeployResponse { client: Arc, } -//todo inject client through enpoint's inputs #[tracing::instrument(name = "Test deploy.")] #[post("/deploy")] pub async fn handler(client: web::ReqData>) -> Result { From c8a5ca2bfaf401b93cfae3b251f1be069d8fa0d0 Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 25 Nov 2023 17:22:30 +0200 Subject: [PATCH 011/284] issue-auth PayloadError --- src/middleware/client.rs | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/middleware/client.rs b/src/middleware/client.rs index 29931d6..021f068 100644 --- a/src/middleware/client.rs +++ b/src/middleware/client.rs @@ -122,20 +122,14 @@ where } }; - let content_length: usize = - get_header(&req, CONTENT_LENGTH.as_str()).map_err(|m| ErrorBadRequest(m))?; - let body = req - .take_payload() - .fold( - BytesMut::with_capacity(content_length), - |mut body, chunk| { - let chunk = chunk.unwrap(); //todo process the potential error of unwrap - body.extend_from_slice(&chunk); //todo - - ready(body) - }, - ) - .await; + let content_length: usize = get_header(&req, CONTENT_LENGTH.as_str()).map_err(|m| { + ErrorBadRequest(JsonResponse::::build().set_msg(m).to_string()) + })?; + let mut bytes = BytesMut::with_capacity(content_length); + let mut payload = req.take_payload(); + while let Some(chunk) = payload.next().await { + bytes.extend_from_slice(&chunk?); + } let mut mac = match Hmac::::new_from_slice(client.secret.as_ref().unwrap().as_bytes()) { @@ -149,7 +143,7 @@ where } }; - mac.update(body.as_ref()); + mac.update(bytes.as_ref()); let computed_hash = format!("{:x}", mac.finalize().into_bytes()); if hash != computed_hash { return Err(ErrorBadRequest( @@ -160,7 +154,7 @@ where } let (_, mut payload) = actix_http::h1::Payload::create(true); - payload.unread_data(body.into()); + payload.unread_data(bytes.into()); req.set_payload(payload.into()); match req.extensions_mut().insert(Arc::new(client)) { From c562ddc8ea07dfa6bd7cd0e21478003bfeabfae0 Mon Sep 17 00:00:00 2001 From: Petru Date: Sun, 26 Nov 2023 08:20:54 +0200 Subject: [PATCH 012/284] issue-auth console.rs --- Cargo.toml | 6 +++++- src/console.rs | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 src/console.rs diff --git a/Cargo.toml b/Cargo.toml index 0301748..c046b34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,11 @@ path="src/lib.rs" [[bin]] path = "src/main.rs" -name = "stacker" +name = "server" + +[[bin]] +path = "src/console.rs" +name = "console" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/console.rs b/src/console.rs new file mode 100644 index 0000000..47ad8c6 --- /dev/null +++ b/src/console.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello World!"); +} From e3c8dc8f4286b50f49f564cb889c837580df726e Mon Sep 17 00:00:00 2001 From: Petru Date: Sun, 26 Nov 2023 08:33:38 +0200 Subject: [PATCH 013/284] issue-auth default-run --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index c046b34..66340ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ name = "stacker" version = "0.1.0" edition = "2021" +default-run= "server" [lib] path="src/lib.rs" From 9643121f17bbe0a745e01f2637326413fd498dac Mon Sep 17 00:00:00 2001 From: Petru Date: Sun, 26 Nov 2023 09:11:11 +0200 Subject: [PATCH 014/284] command --- Cargo.lock | 101 +++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/console.rs | 39 ++++++++++++++++++- 3 files changed, 140 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 2ac8449..d4cbf7c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -342,6 +342,54 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" + +[[package]] +name = "anstyle-parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" +dependencies = [ + "anstyle", + "windows-sys", +] + [[package]] name = "async-channel" version = "1.9.0" @@ -644,6 +692,52 @@ dependencies = [ "inout", ] +[[package]] +name = "clap" +version = "4.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "clap_lex" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + [[package]] name = "concurrent-queue" version = "2.3.0" @@ -2750,6 +2844,7 @@ dependencies = [ "actix-web", "actix-web-httpauth", "chrono", + "clap", "config", "derive_builder", "futures", @@ -3219,6 +3314,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "uuid" version = "1.5.0" diff --git a/Cargo.toml b/Cargo.toml index 66340ac..4c38d6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,6 +51,7 @@ indexmap = { version = "2.0.0", features = ["serde"], optional = true } serde_yaml = "0.9" lapin = { version = "2.3.1", features = ["serde_json"] } futures-lite = "1.13.0" +clap = { version = "4.4.8", features = ["derive"] } [dependencies.sqlx] version = "0.6.3" diff --git a/src/console.rs b/src/console.rs index 47ad8c6..8eed757 100644 --- a/src/console.rs +++ b/src/console.rs @@ -1,3 +1,40 @@ +use clap::{Parser, Subcommand}; + +#[derive(Parser, Debug)] +struct Cli { + #[command(subcommand)] + command: Commands, +} + +#[derive(Debug, Subcommand)] +enum Commands { + AppClient { + #[command(subcommand)] + command: AppClientCommands, + }, +} + +#[derive(Debug, Subcommand)] +enum AppClientCommands { + New { + #[arg(long)] + user_id: i32, + }, +} + fn main() { - println!("Hello World!"); + let cli = Cli::parse(); + + match cli.command { + Commands::AppClient { command } => { + process_app_client_command(command); + } + _ => { + println!("other variant"); + } + }; +} + +fn process_app_client_command(command: AppClientCommands) { + println!("{command:?}"); } From 003e16c1f63b6b044d11740e389fe12d2aac815d Mon Sep 17 00:00:00 2001 From: Petru Date: Sun, 26 Nov 2023 16:31:39 +0200 Subject: [PATCH 015/284] issue-auth removed client.id = 1 --- src/routes/client/add.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/routes/client/add.rs b/src/routes/client/add.rs index 9e722e3..8b136c1 100644 --- a/src/routes/client/add.rs +++ b/src/routes/client/add.rs @@ -50,7 +50,6 @@ pub async fn add_handler( }; let mut client = Client::default(); - client.id = 1; client.user_id = user.id.clone(); client.secret = client::generate_secret(pool.get_ref(), 255) .await From 5009fa36cb9a885b4a75ef6d5b1d1353fb872517 Mon Sep 17 00:00:00 2001 From: Petru Date: Sun, 26 Nov 2023 17:59:18 +0200 Subject: [PATCH 016/284] issue-auth add_handler_internal --- src/routes/client/add.rs | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/routes/client/add.rs b/src/routes/client/add.rs index 8b136c1..830095e 100644 --- a/src/routes/client/add.rs +++ b/src/routes/client/add.rs @@ -1,9 +1,8 @@ use crate::configuration::Settings; use crate::helpers::client; use crate::helpers::JsonResponse; +use crate::models; use crate::models::user::User; -use crate::models::Client; -use actix_web::error::ErrorInternalServerError; use actix_web::{post, web, Responder, Result}; use sqlx::PgPool; use std::sync::Arc; @@ -16,6 +15,17 @@ pub async fn add_handler( settings: web::Data>, pool: web::Data, ) -> Result { + match add_handler_inner(user, settings, pool).await { + Ok(client) => JsonResponse::build().set_item(client).ok("Ok"), + Err(msg) => JsonResponse::build().bad_request(msg), + } +} + +pub async fn add_handler_inner( + user: web::ReqData, + settings: web::Data>, + pool: web::Data, +) -> Result { let query_span = tracing::info_span!("Counting the user's clients"); match sqlx::query!( @@ -40,23 +50,20 @@ pub async fn add_handler( client_count ); - return JsonResponse::build().bad_request("Too many clients created"); + return Err("Too many clients created".to_string()); } } Err(e) => { tracing::error!("Failed to execute query: {:?}", e); - return JsonResponse::build().internal_server_error("Internal Server Error"); + return Err("Internal Server Error".to_string()); } }; - let mut client = Client::default(); + let mut client = models::Client::default(); client.user_id = user.id.clone(); client.secret = client::generate_secret(pool.get_ref(), 255) .await - .map(|s| Some(s)) - .map_err(|s| { - ErrorInternalServerError(JsonResponse::::build().set_msg(s).to_string()) - })?; + .map(|s| Some(s))?; let query_span = tracing::info_span!("Saving new client into the database"); match sqlx::query!( @@ -76,12 +83,11 @@ pub async fn add_handler( tracing::info!("New client {} have been saved to database", result.id); client.id = result.id; - return JsonResponse::build().set_item(Some(client)).ok("OK"); + return Ok(client); } Err(e) => { tracing::error!("Failed to execute query: {:?}", e); - let err = format!("Failed to insert. {}", e); - return JsonResponse::build().bad_request(err); + return Err("Failed to insert".to_string()); } } } From e8fed13412f8f1307785494be889c764faa29959 Mon Sep 17 00:00:00 2001 From: Petru Date: Sun, 26 Nov 2023 18:31:22 +0200 Subject: [PATCH 017/284] issue-auth --- src/routes/client/add.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/client/add.rs b/src/routes/client/add.rs index 830095e..eeb00a1 100644 --- a/src/routes/client/add.rs +++ b/src/routes/client/add.rs @@ -15,14 +15,14 @@ pub async fn add_handler( settings: web::Data>, pool: web::Data, ) -> Result { - match add_handler_inner(user, settings, pool).await { + match add_handler_inner(user.into_inner(), settings, pool).await { Ok(client) => JsonResponse::build().set_item(client).ok("Ok"), Err(msg) => JsonResponse::build().bad_request(msg), } } pub async fn add_handler_inner( - user: web::ReqData, + user: User, settings: web::Data>, pool: web::Data, ) -> Result { From fa7f675ff8173fe2db3e469747ff16df4298484f Mon Sep 17 00:00:00 2001 From: Petru Date: Sun, 26 Nov 2023 18:59:30 +0200 Subject: [PATCH 018/284] issue-auth console --- src/console.rs | 48 +++++++++++++++++++++++++++++++++++++++++++---- src/routes/mod.rs | 2 +- src/startup.rs | 2 +- 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/src/console.rs b/src/console.rs index 8eed757..1ca6442 100644 --- a/src/console.rs +++ b/src/console.rs @@ -1,4 +1,9 @@ +use actix_web::web; use clap::{Parser, Subcommand}; +use sqlx::PgPool; +use stacker::configuration::get_configuration; +use std::sync::Arc; +use tokio::runtime::Runtime; #[derive(Parser, Debug)] struct Cli { @@ -22,19 +27,54 @@ enum AppClientCommands { }, } -fn main() { +fn main() -> Result<(), Box> { + /* + let db_pool = PgPool::connect(&settings.database.connection_string()) + .await + .expect("Failed to connect to database."); + */ let cli = Cli::parse(); match cli.command { Commands::AppClient { command } => { - process_app_client_command(command); + process_app_client_command(command)?; } _ => { println!("other variant"); } }; + + Ok(()) } -fn process_app_client_command(command: AppClientCommands) { - println!("{command:?}"); +fn process_app_client_command( + command: AppClientCommands, +) -> Result<(), Box> { + let rt = Runtime::new()?; + + rt.block_on(async { + let settings = get_configuration().expect("Failed to read configuration."); + let db_pool = PgPool::connect(&settings.database.connection_string()) + .await + .expect("Failed to connect to database."); + + let settings = web::Data::new(Arc::new(settings)); //todo web::Data is already an Arc + let db_pool = web::Data::new(db_pool); + + //todo get user from trydirect + let user = stacker::models::user::User { + id: "first_name".to_string(), + first_name: "first_name".to_string(), + last_name: "last_name".to_string(), + email: "email".to_string(), + email_confirmed: true, + }; + stacker::routes::client::add_handler_inner(user, settings, db_pool) + .await + .expect("todo error"); //todo process the error + Ok(()) + }) + + //rt.block_on(async {}) + //Ok(()) } diff --git a/src/routes/mod.rs b/src/routes/mod.rs index cab3e46..0d6e99e 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -1,4 +1,4 @@ -pub(crate) mod client; +pub mod client; pub mod health_checks; pub(crate) mod rating; pub(crate) mod test; diff --git a/src/startup.rs b/src/startup.rs index 3306fcd..4b330b5 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -16,7 +16,7 @@ pub async fn run( db_pool: Pool, settings: Settings, ) -> Result { - let settings = web::Data::new(Arc::new(settings)); + let settings = web::Data::new(Arc::new(settings)); //todo web::Data is already an Arc let db_pool = web::Data::new(db_pool); // let address = format!("{}:{}", settings.app_host, settings.app_port); From 613e905f13302005b5826724b797b44a955e3fbc Mon Sep 17 00:00:00 2001 From: Petru Date: Mon, 27 Nov 2023 17:11:51 +0200 Subject: [PATCH 019/284] issue-auth remove redundant Arc --- src/console.rs | 5 +---- src/middleware/trydirect.rs | 3 +-- src/routes/client/add.rs | 5 ++--- src/routes/client/disable.rs | 3 +-- src/routes/client/enable.rs | 3 +-- src/routes/client/update.rs | 2 +- src/routes/stack/deploy.rs | 2 +- src/startup.rs | 8 +------- 8 files changed, 9 insertions(+), 22 deletions(-) diff --git a/src/console.rs b/src/console.rs index 1ca6442..221154a 100644 --- a/src/console.rs +++ b/src/console.rs @@ -58,7 +58,7 @@ fn process_app_client_command( .await .expect("Failed to connect to database."); - let settings = web::Data::new(Arc::new(settings)); //todo web::Data is already an Arc + let settings = web::Data::new(settings); //todo web::Data is already an Arc let db_pool = web::Data::new(db_pool); //todo get user from trydirect @@ -74,7 +74,4 @@ fn process_app_client_command( .expect("todo error"); //todo process the error Ok(()) }) - - //rt.block_on(async {}) - //Ok(()) } diff --git a/src/middleware/trydirect.rs b/src/middleware/trydirect.rs index 1d01c50..755baba 100644 --- a/src/middleware/trydirect.rs +++ b/src/middleware/trydirect.rs @@ -7,7 +7,6 @@ use actix_web::Error; use actix_web::HttpMessage; use actix_web_httpauth::extractors::bearer::BearerAuth; use reqwest::header::{ACCEPT, CONTENT_TYPE}; -use std::sync::Arc; use crate::models::user::User; @@ -16,7 +15,7 @@ pub async fn bearer_guard( req: ServiceRequest, credentials: BearerAuth, ) -> Result { - let settings = req.app_data::>>().unwrap(); + let settings = req.app_data::>().unwrap(); let client = reqwest::Client::new(); let resp = client .get(&settings.auth_url) diff --git a/src/routes/client/add.rs b/src/routes/client/add.rs index eeb00a1..db98705 100644 --- a/src/routes/client/add.rs +++ b/src/routes/client/add.rs @@ -5,14 +5,13 @@ use crate::models; use crate::models::user::User; use actix_web::{post, web, Responder, Result}; use sqlx::PgPool; -use std::sync::Arc; use tracing::Instrument; #[tracing::instrument(name = "Add client.")] #[post("")] pub async fn add_handler( user: web::ReqData, - settings: web::Data>, + settings: web::Data, pool: web::Data, ) -> Result { match add_handler_inner(user.into_inner(), settings, pool).await { @@ -23,7 +22,7 @@ pub async fn add_handler( pub async fn add_handler_inner( user: User, - settings: web::Data>, + settings: web::Data, pool: web::Data, ) -> Result { let query_span = tracing::info_span!("Counting the user's clients"); diff --git a/src/routes/client/disable.rs b/src/routes/client/disable.rs index f9a4a50..b0d2cde 100644 --- a/src/routes/client/disable.rs +++ b/src/routes/client/disable.rs @@ -4,14 +4,13 @@ use crate::models::user::User; use crate::models::Client; use actix_web::{error::ErrorInternalServerError, put, web, Responder, Result}; use sqlx::PgPool; -use std::sync::Arc; use tracing::Instrument; #[tracing::instrument(name = "Disable client.")] #[put("/{id}/disable")] pub async fn disable_handler( user: web::ReqData, - settings: web::Data>, + settings: web::Data, pool: web::Data, path: web::Path<(i32,)>, ) -> Result { diff --git a/src/routes/client/enable.rs b/src/routes/client/enable.rs index a7b024d..ef0548d 100644 --- a/src/routes/client/enable.rs +++ b/src/routes/client/enable.rs @@ -5,14 +5,13 @@ use crate::models::user::User; use crate::models::Client; use actix_web::{error::ErrorBadRequest, put, web, Responder, Result}; use sqlx::PgPool; -use std::sync::Arc; use tracing::Instrument; #[tracing::instrument(name = "Enable client.")] #[put("/{id}/enable")] pub async fn enable_handler( user: web::ReqData, - settings: web::Data>, + settings: web::Data, pool: web::Data, path: web::Path<(i32,)>, ) -> Result { diff --git a/src/routes/client/update.rs b/src/routes/client/update.rs index 34d7bfc..64604d3 100644 --- a/src/routes/client/update.rs +++ b/src/routes/client/update.rs @@ -11,7 +11,7 @@ use tracing::Instrument; #[put("/{id}")] pub async fn update_handler( user: web::ReqData, - settings: web::Data>, + settings: web::Data, pool: web::Data, path: web::Path<(i32,)>, ) -> Result { diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs index b76b63c..5c9fa66 100644 --- a/src/routes/stack/deploy.rs +++ b/src/routes/stack/deploy.rs @@ -18,7 +18,7 @@ pub async fn add( user: web::ReqData, path: web::Path<(i32,)>, pool: Data, - sets: Data>, + sets: Data, ) -> Result { let id = path.0; tracing::debug!("Received id: {}", id); diff --git a/src/startup.rs b/src/startup.rs index 4b330b5..7022c9c 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -8,7 +8,6 @@ use actix_web::{ use actix_web_httpauth::middleware::HttpAuthentication; use sqlx::{Pool, Postgres}; use std::net::TcpListener; -use std::sync::Arc; use tracing_actix_web::TracingLogger; pub async fn run( @@ -16,14 +15,9 @@ pub async fn run( db_pool: Pool, settings: Settings, ) -> Result { - let settings = web::Data::new(Arc::new(settings)); //todo web::Data is already an Arc + let settings = web::Data::new(settings); let db_pool = web::Data::new(db_pool); - // let address = format!("{}:{}", settings.app_host, settings.app_port); - // tracing::info!("Start server at {:?}", &address); - // let listener = std::net::TcpListener::bind(address) - // .expect(&format!("failed to bind to {}", settings.app_port)); - let server = HttpServer::new(move || { App::new() .wrap(TracingLogger::default()) From 2ccb733165ad623f62fa6822aa2e100fede7927c Mon Sep 17 00:00:00 2001 From: Petru Date: Mon, 27 Nov 2023 18:07:44 +0200 Subject: [PATCH 020/284] issue-auth console --- src/console.rs | 62 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 8 deletions(-) diff --git a/src/console.rs b/src/console.rs index 221154a..d6a540e 100644 --- a/src/console.rs +++ b/src/console.rs @@ -2,7 +2,6 @@ use actix_web::web; use clap::{Parser, Subcommand}; use sqlx::PgPool; use stacker::configuration::get_configuration; -use std::sync::Arc; use tokio::runtime::Runtime; #[derive(Parser, Debug)] @@ -25,6 +24,46 @@ enum AppClientCommands { #[arg(long)] user_id: i32, }, + New1 { + #[arg(long)] + user_id: i32, + }, +} + +trait StackerCommand { + fn call(&self) -> Result<(), Box>; +} + +struct AppClientNew { + user_id: i32, +} + +struct AppClientNew1 { + user_id: i32, +} + +impl AppClientNew1 { + fn new(user_id: i32) -> Self { + Self { user_id } + } +} + +impl StackerCommand for AppClientNew1 { + fn call(&self) -> Result<(), Box> { + Ok(()) + } +} + +impl AppClientNew { + fn new(user_id: i32) -> Self { + Self { user_id } + } +} + +impl StackerCommand for AppClientNew { + fn call(&self) -> Result<(), Box> { + Ok(()) + } } fn main() -> Result<(), Box> { @@ -34,17 +73,24 @@ fn main() -> Result<(), Box> { .expect("Failed to connect to database."); */ let cli = Cli::parse(); + println!("{cli:?}"); + + get_command(cli)?.call(); + Ok(()) +} + +fn get_command(cli: Cli) -> Result, String> { match cli.command { Commands::AppClient { command } => { - process_app_client_command(command)?; + //process_app_client_command(command)?; + match command { + AppClientCommands::New { user_id } => Ok(Box::new(AppClientNew::new(user_id))), + AppClientCommands::New1 { user_id } => Ok(Box::new(AppClientNew1::new(user_id))), + } } - _ => { - println!("other variant"); - } - }; - - Ok(()) + _ => Err("command does not match".to_string()), + } } fn process_app_client_command( From 279e29a9fa3e22b7a61a0c692662a8d4a3a4b057 Mon Sep 17 00:00:00 2001 From: Petru Date: Tue, 28 Nov 2023 09:18:42 +0200 Subject: [PATCH 021/284] issue-auth call thing --- src/console.rs | 64 ++++++++++++++++++++------------------------------ 1 file changed, 25 insertions(+), 39 deletions(-) diff --git a/src/console.rs b/src/console.rs index d6a540e..8ace4e6 100644 --- a/src/console.rs +++ b/src/console.rs @@ -62,22 +62,37 @@ impl AppClientNew { impl StackerCommand for AppClientNew { fn call(&self) -> Result<(), Box> { - Ok(()) + let rt = Runtime::new()?; + + rt.block_on(async { + let settings = get_configuration().expect("Failed to read configuration."); + let db_pool = PgPool::connect(&settings.database.connection_string()) + .await + .expect("Failed to connect to database."); + + let settings = web::Data::new(settings); //todo web::Data is already an Arc + let db_pool = web::Data::new(db_pool); + + //todo get user from trydirect + let user = stacker::models::user::User { + id: "first_name".to_string(), + first_name: "first_name".to_string(), + last_name: "last_name".to_string(), + email: "email".to_string(), + email_confirmed: true, + }; + stacker::routes::client::add_handler_inner(user, settings, db_pool) + .await + .expect("todo error"); //todo process the error + Ok(()) + }) } } fn main() -> Result<(), Box> { - /* - let db_pool = PgPool::connect(&settings.database.connection_string()) - .await - .expect("Failed to connect to database."); - */ let cli = Cli::parse(); - println!("{cli:?}"); - - get_command(cli)?.call(); - Ok(()) + get_command(cli)?.call() } fn get_command(cli: Cli) -> Result, String> { @@ -92,32 +107,3 @@ fn get_command(cli: Cli) -> Result, String> { _ => Err("command does not match".to_string()), } } - -fn process_app_client_command( - command: AppClientCommands, -) -> Result<(), Box> { - let rt = Runtime::new()?; - - rt.block_on(async { - let settings = get_configuration().expect("Failed to read configuration."); - let db_pool = PgPool::connect(&settings.database.connection_string()) - .await - .expect("Failed to connect to database."); - - let settings = web::Data::new(settings); //todo web::Data is already an Arc - let db_pool = web::Data::new(db_pool); - - //todo get user from trydirect - let user = stacker::models::user::User { - id: "first_name".to_string(), - first_name: "first_name".to_string(), - last_name: "last_name".to_string(), - email: "email".to_string(), - email_confirmed: true, - }; - stacker::routes::client::add_handler_inner(user, settings, db_pool) - .await - .expect("todo error"); //todo process the error - Ok(()) - }) -} From cd26401ab685543d27eb40266db5676e64114132 Mon Sep 17 00:00:00 2001 From: Petru Date: Tue, 28 Nov 2023 09:25:17 +0200 Subject: [PATCH 022/284] issue-auth rename console.rs --- Cargo.toml | 2 +- src/{console.rs => console/main.rs} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/{console.rs => console/main.rs} (100%) diff --git a/Cargo.toml b/Cargo.toml index 4c38d6e..f3d2357 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ path = "src/main.rs" name = "server" [[bin]] -path = "src/console.rs" +path = "src/console/main.rs" name = "console" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/console.rs b/src/console/main.rs similarity index 100% rename from src/console.rs rename to src/console/main.rs From 90d41aa43063fefe71e237bc9537e5ca86000084 Mon Sep 17 00:00:00 2001 From: Petru Date: Tue, 28 Nov 2023 09:56:51 +0200 Subject: [PATCH 023/284] issue-auth console command --- src/console/commands/appclient/mod.rs | 3 + src/console/commands/appclient/new.rs | 43 ++++++++++++++ src/console/commands/callable.rs | 3 + src/console/commands/mod.rs | 4 ++ src/console/main.rs | 82 +++------------------------ src/console/mod.rs | 1 + src/lib.rs | 1 + 7 files changed, 63 insertions(+), 74 deletions(-) create mode 100644 src/console/commands/appclient/mod.rs create mode 100644 src/console/commands/appclient/new.rs create mode 100644 src/console/commands/callable.rs create mode 100644 src/console/commands/mod.rs create mode 100644 src/console/mod.rs diff --git a/src/console/commands/appclient/mod.rs b/src/console/commands/appclient/mod.rs new file mode 100644 index 0000000..b6a00cd --- /dev/null +++ b/src/console/commands/appclient/mod.rs @@ -0,0 +1,3 @@ +mod new; + +pub use new::*; diff --git a/src/console/commands/appclient/new.rs b/src/console/commands/appclient/new.rs new file mode 100644 index 0000000..3f9763a --- /dev/null +++ b/src/console/commands/appclient/new.rs @@ -0,0 +1,43 @@ +use crate::configuration::get_configuration; +use actix_web::web; +use sqlx::PgPool; +use tokio::runtime::Runtime; //todo actix_web runtime + +pub struct New { + user_id: i32, +} + +impl New { + pub fn new(user_id: i32) -> Self { + Self { user_id } + } +} + +impl crate::console::commands::CallableTrait for New { + fn call(&self) -> Result<(), Box> { + let rt = Runtime::new()?; + + rt.block_on(async { + let settings = get_configuration().expect("Failed to read configuration."); + let db_pool = PgPool::connect(&settings.database.connection_string()) + .await + .expect("Failed to connect to database."); + + let settings = web::Data::new(settings); //todo web::Data is already an Arc + let db_pool = web::Data::new(db_pool); + + //todo get user from trydirect + let user = crate::models::user::User { + id: "first_name".to_string(), + first_name: "first_name".to_string(), + last_name: "last_name".to_string(), + email: "email".to_string(), + email_confirmed: true, + }; + crate::routes::client::add_handler_inner(user, settings, db_pool) + .await + .expect("todo error"); //todo process the error + Ok(()) + }) + } +} diff --git a/src/console/commands/callable.rs b/src/console/commands/callable.rs new file mode 100644 index 0000000..45e7124 --- /dev/null +++ b/src/console/commands/callable.rs @@ -0,0 +1,3 @@ +pub trait CallableTrait { + fn call(&self) -> Result<(), Box>; +} diff --git a/src/console/commands/mod.rs b/src/console/commands/mod.rs new file mode 100644 index 0000000..2cf75be --- /dev/null +++ b/src/console/commands/mod.rs @@ -0,0 +1,4 @@ +pub mod appclient; +mod callable; + +pub use callable::*; diff --git a/src/console/main.rs b/src/console/main.rs index 8ace4e6..145d096 100644 --- a/src/console/main.rs +++ b/src/console/main.rs @@ -1,8 +1,4 @@ -use actix_web::web; use clap::{Parser, Subcommand}; -use sqlx::PgPool; -use stacker::configuration::get_configuration; -use tokio::runtime::Runtime; #[derive(Parser, Debug)] struct Cli { @@ -24,70 +20,10 @@ enum AppClientCommands { #[arg(long)] user_id: i32, }, - New1 { - #[arg(long)] - user_id: i32, - }, -} - -trait StackerCommand { - fn call(&self) -> Result<(), Box>; -} - -struct AppClientNew { - user_id: i32, -} - -struct AppClientNew1 { - user_id: i32, -} - -impl AppClientNew1 { - fn new(user_id: i32) -> Self { - Self { user_id } - } } -impl StackerCommand for AppClientNew1 { - fn call(&self) -> Result<(), Box> { - Ok(()) - } -} - -impl AppClientNew { - fn new(user_id: i32) -> Self { - Self { user_id } - } -} - -impl StackerCommand for AppClientNew { - fn call(&self) -> Result<(), Box> { - let rt = Runtime::new()?; - - rt.block_on(async { - let settings = get_configuration().expect("Failed to read configuration."); - let db_pool = PgPool::connect(&settings.database.connection_string()) - .await - .expect("Failed to connect to database."); - - let settings = web::Data::new(settings); //todo web::Data is already an Arc - let db_pool = web::Data::new(db_pool); - - //todo get user from trydirect - let user = stacker::models::user::User { - id: "first_name".to_string(), - first_name: "first_name".to_string(), - last_name: "last_name".to_string(), - email: "email".to_string(), - email_confirmed: true, - }; - stacker::routes::client::add_handler_inner(user, settings, db_pool) - .await - .expect("todo error"); //todo process the error - Ok(()) - }) - } -} +//todo add documentation about how to add a new command +//todo the helper from console should have a nicer display fn main() -> Result<(), Box> { let cli = Cli::parse(); @@ -95,15 +31,13 @@ fn main() -> Result<(), Box> { get_command(cli)?.call() } -fn get_command(cli: Cli) -> Result, String> { +fn get_command(cli: Cli) -> Result, String> { match cli.command { - Commands::AppClient { command } => { - //process_app_client_command(command)?; - match command { - AppClientCommands::New { user_id } => Ok(Box::new(AppClientNew::new(user_id))), - AppClientCommands::New1 { user_id } => Ok(Box::new(AppClientNew1::new(user_id))), - } - } + Commands::AppClient { command } => match command { + AppClientCommands::New { user_id } => Ok(Box::new( + stacker::console::commands::appclient::New::new(user_id), + )), + }, _ => Err("command does not match".to_string()), } } diff --git a/src/console/mod.rs b/src/console/mod.rs new file mode 100644 index 0000000..82b6da3 --- /dev/null +++ b/src/console/mod.rs @@ -0,0 +1 @@ +pub mod commands; diff --git a/src/lib.rs b/src/lib.rs index 56bd1f0..37e4fae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ pub mod configuration; +pub mod console; pub mod forms; pub mod helpers; mod middleware; From f5f6a07a648a8424ea2425fb725789222315649b Mon Sep 17 00:00:00 2001 From: Petru Date: Tue, 28 Nov 2023 18:12:47 +0200 Subject: [PATCH 024/284] issue-auth actix runtime --- src/console/commands/appclient/new.rs | 19 ++++++++----------- src/console/main.rs | 2 +- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/console/commands/appclient/new.rs b/src/console/commands/appclient/new.rs index 3f9763a..138f11f 100644 --- a/src/console/commands/appclient/new.rs +++ b/src/console/commands/appclient/new.rs @@ -1,29 +1,27 @@ use crate::configuration::get_configuration; +use actix_web::rt; use actix_web::web; use sqlx::PgPool; -use tokio::runtime::Runtime; //todo actix_web runtime -pub struct New { +pub struct NewCommand { user_id: i32, } -impl New { +impl NewCommand { pub fn new(user_id: i32) -> Self { Self { user_id } } } -impl crate::console::commands::CallableTrait for New { +impl crate::console::commands::CallableTrait for NewCommand { fn call(&self) -> Result<(), Box> { - let rt = Runtime::new()?; - - rt.block_on(async { + rt::System::new().block_on(async { let settings = get_configuration().expect("Failed to read configuration."); let db_pool = PgPool::connect(&settings.database.connection_string()) .await .expect("Failed to connect to database."); - let settings = web::Data::new(settings); //todo web::Data is already an Arc + let settings = web::Data::new(settings); let db_pool = web::Data::new(db_pool); //todo get user from trydirect @@ -34,9 +32,8 @@ impl crate::console::commands::CallableTrait for New { email: "email".to_string(), email_confirmed: true, }; - crate::routes::client::add_handler_inner(user, settings, db_pool) - .await - .expect("todo error"); //todo process the error + crate::routes::client::add_handler_inner(user, settings, db_pool).await?; + Ok(()) }) } diff --git a/src/console/main.rs b/src/console/main.rs index 145d096..0921128 100644 --- a/src/console/main.rs +++ b/src/console/main.rs @@ -35,7 +35,7 @@ fn get_command(cli: Cli) -> Result match command { AppClientCommands::New { user_id } => Ok(Box::new( - stacker::console::commands::appclient::New::new(user_id), + stacker::console::commands::appclient::NewCommand::new(user_id), )), }, _ => Err("command does not match".to_string()), From cda917bbd82399812c7c8ef25e8071159f17518a Mon Sep 17 00:00:00 2001 From: Petru Date: Tue, 28 Nov 2023 18:38:39 +0200 Subject: [PATCH 025/284] issue-auth --- src/middleware/trydirect.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/middleware/trydirect.rs b/src/middleware/trydirect.rs index 755baba..e19b57a 100644 --- a/src/middleware/trydirect.rs +++ b/src/middleware/trydirect.rs @@ -60,6 +60,7 @@ pub async fn bearer_guard( tracing::error!("already logged {existent_user:?}"); return Err((ErrorInternalServerError(""), req)); } + //todo move request outside Ok(req) } From f2ac4b1194fc213a815574210e2d6d0016ec58b8 Mon Sep 17 00:00:00 2001 From: Petru Date: Wed, 29 Nov 2023 21:18:57 +0200 Subject: [PATCH 026/284] issue-auth --- src/middleware/trydirect.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/middleware/trydirect.rs b/src/middleware/trydirect.rs index e19b57a..755baba 100644 --- a/src/middleware/trydirect.rs +++ b/src/middleware/trydirect.rs @@ -60,7 +60,6 @@ pub async fn bearer_guard( tracing::error!("already logged {existent_user:?}"); return Err((ErrorInternalServerError(""), req)); } - //todo move request outside Ok(req) } From 507dc5695969379d7990056ea653d13e016796bc Mon Sep 17 00:00:00 2001 From: Petru Date: Fri, 1 Dec 2023 17:26:21 +0200 Subject: [PATCH 027/284] issue-auth middleware/client optimisation --- src/middleware/client.rs | 68 ++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 44 deletions(-) diff --git a/src/middleware/client.rs b/src/middleware/client.rs index 021f068..4309ac5 100644 --- a/src/middleware/client.rs +++ b/src/middleware/client.rs @@ -74,12 +74,8 @@ where fn call(&self, mut req: ServiceRequest) -> Self::Future { let service = self.service.clone(); async move { - let client_id: i32 = get_header(&req, "stacker-id").map_err(|m| { - ErrorBadRequest(JsonResponse::::build().set_msg(m).to_string()) - })?; - let hash: String = get_header(&req, "stacker-hash").map_err(|m| { - ErrorBadRequest(JsonResponse::::build().set_msg(m).to_string()) - })?; + let client_id: i32 = get_header(&req, "stacker-id")?; + let hash: String = get_header(&req, "stacker-hash")?; let query_span = tracing::info_span!("Fetching the client by ID"); let db_pool = req.app_data::>>().unwrap(); @@ -98,37 +94,20 @@ where .instrument(query_span) .await { - Ok(client) if client.secret.is_some() => client, - Ok(_client) => { - return Err(ErrorForbidden( - JsonResponse::::build() - .set_msg("client is not active") - .to_string(), - )); - } - Err(sqlx::Error::RowNotFound) => { - return Err(ErrorNotFound( - JsonResponse::::build() - .set_msg("the client is not found") - .to_string(), - )); - } + Ok(client) if client.secret.is_some() => Ok(client), + Ok(_client) => Err("client is not active".to_string()), + Err(sqlx::Error::RowNotFound) => Err("the client is not found".to_string()), Err(e) => { tracing::error!("Failed to execute fetch query: {:?}", e); - - return Err(ErrorInternalServerError( - JsonResponse::::build().to_string(), - )); + Err("".to_string()) } - }; + }?; - let content_length: usize = get_header(&req, CONTENT_LENGTH.as_str()).map_err(|m| { - ErrorBadRequest(JsonResponse::::build().set_msg(m).to_string()) - })?; + let content_length: usize = get_header(&req, CONTENT_LENGTH.as_str())?; let mut bytes = BytesMut::with_capacity(content_length); let mut payload = req.take_payload(); while let Some(chunk) = payload.next().await { - bytes.extend_from_slice(&chunk?); + bytes.extend_from_slice(&chunk.expect("can't unwrap the chunk")); } let mut mac = @@ -136,21 +115,14 @@ where Ok(mac) => mac, Err(err) => { tracing::error!("error generating hmac {err:?}"); - - return Err(ErrorInternalServerError( - JsonResponse::::build().to_string(), - )); + return Err("".to_string()); } }; mac.update(bytes.as_ref()); let computed_hash = format!("{:x}", mac.finalize().into_bytes()); if hash != computed_hash { - return Err(ErrorBadRequest( - JsonResponse::::build() - .set_msg("hash is wrong") - .to_string(), - )); + return Err("hash is wrong".to_string()); } let (_, mut payload) = actix_http::h1::Payload::create(true); @@ -160,16 +132,24 @@ where match req.extensions_mut().insert(Arc::new(client)) { Some(_) => { tracing::error!("client middleware already called once"); - return Err(ErrorInternalServerError( - JsonResponse::::build().to_string(), - )); + return Err("".to_string()); } None => {} } - let service = service.lock().await; - service.call(req).await + Ok(req) } + .then(|req| async move { + match req { + Ok(req) => { + let service = service.lock().await; + service.call(req).await + } + Err(msg) => Err(ErrorBadRequest( + JsonResponse::::build().set_msg(msg).to_string(), + )), + } + }) .boxed_local() } } From caee9a4253e3fe1a79b02cd8dcb308a92a1b368f Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 2 Dec 2023 17:59:07 +0200 Subject: [PATCH 028/284] issue-auth tests/common.rs --- tests/common.rs | 83 ++++++++++++++++++++++++++ tests/health_check.rs | 133 +----------------------------------------- 2 files changed, 85 insertions(+), 131 deletions(-) create mode 100644 tests/common.rs diff --git a/tests/common.rs b/tests/common.rs new file mode 100644 index 0000000..afc4134 --- /dev/null +++ b/tests/common.rs @@ -0,0 +1,83 @@ +use actix_web::{get, web, App, HttpServer, Responder}; +use sqlx::{Connection, Executor, PgConnection, PgPool}; +use stacker::configuration::{get_configuration, DatabaseSettings}; +use stacker::forms; +use std::net::TcpListener; + +pub async fn spawn_app() -> TestApp { + let mut configuration = get_configuration().expect("Failed to get configuration"); + + let listener = std::net::TcpListener::bind("127.0.0.1:0") + .expect("Failed to bind port for testing auth server"); + + configuration.auth_url = format!( + "http://127.0.0.1:{}/me", + listener.local_addr().unwrap().port() + ); + println!("Auth Server is running on: {}", configuration.auth_url); + + let handle = tokio::spawn(mock_auth_server(listener)); + handle.await.expect("Auth Server can not be started"); + + let listener = std::net::TcpListener::bind("127.0.0.1:0").expect("Failed to bind random port"); + + let port = listener.local_addr().unwrap().port(); + let address = format!("http://127.0.0.1:{}", port); + configuration.database.database_name = uuid::Uuid::new_v4().to_string(); + + let connection_pool = configure_database(&configuration.database).await; + + let server = stacker::startup::run(listener, connection_pool.clone(), configuration) + .await + .expect("Failed to bind address."); + + let _ = tokio::spawn(server); + println!("Used Port: {}", port); + + TestApp { + address, + db_pool: connection_pool, + } +} + +pub async fn configure_database(config: &DatabaseSettings) -> PgPool { + let mut connection = PgConnection::connect(&config.connection_string_without_db()) + .await + .expect("Failed to connect to postgres"); + + connection + .execute(format!(r#"CREATE DATABASE "{}""#, config.database_name).as_str()) + .await + .expect("Failed to create database"); + + let connection_pool = PgPool::connect(&config.connection_string()) + .await + .expect("Failed to connect to database pool"); + + sqlx::migrate!("./migrations") + .run(&connection_pool) + .await + .expect("Failed to migrate database"); + + connection_pool +} + +pub struct TestApp { + pub address: String, + pub db_pool: PgPool, +} + +#[get("")] +async fn mock_auth() -> actix_web::Result { + println!("Starting auth server in test mode ..."); + // 1. set user id + // 2. add token to header / hardcoded + Ok(web::Json(forms::user::UserForm::default())) +} + +async fn mock_auth_server(listener: TcpListener) -> actix_web::dev::Server { + HttpServer::new(|| App::new().service(web::scope("/me").service(mock_auth))) + .listen(listener) + .unwrap() + .run() +} diff --git a/tests/health_check.rs b/tests/health_check.rs index 0b858bf..1496735 100644 --- a/tests/health_check.rs +++ b/tests/health_check.rs @@ -1,31 +1,4 @@ -//#[actix_rt::test] - -use std::net::TcpListener; -use actix_web::{App, HttpServer, web, Responder, get}; -use sqlx::{Connection, Executor, PgConnection, PgPool}; -use stacker::configuration::{get_configuration, DatabaseSettings}; -use stacker::forms; - - -#[get("")] -async fn mock_auth() -> actix_web::Result { - println!("Starting auth server in test mode ..."); - // 1. set user id - // 2. add token to header / hardcoded - Ok(web::Json(forms::user::UserForm::default())) -} - -async fn mock_auth_server(listener:TcpListener) -> actix_web::dev::Server { - - HttpServer::new(|| { - App::new() - .service(web::scope("/me") - .service(mock_auth)) - }) - .listen(listener) - .unwrap() - .run() -} +mod common; #[tokio::test] async fn health_check_works() { @@ -34,7 +7,7 @@ async fn health_check_works() { // 3. Assert println!("Before spawn_app"); - let app = spawn_app().await; // server + let app = common::spawn_app().await; // server println!("After spawn_app"); let client = reqwest::Client::new(); // client @@ -46,106 +19,4 @@ async fn health_check_works() { assert!(response.status().is_success()); assert_eq!(Some(0), response.content_length()); - // let app = App::new().service(web::resource("/health_check").route(web::get().to(health_check))); - // let mut app = test::init_service(app).await; - // let req = test::TestRequest::get().uri("/health_check").to_request(); - // let resp = test::call_service(&mut app, req).await; - // assert_eq!(resp.status(), StatusCode::OK); -} - -// test that locks main thread -// async fn spawn_app() -> std::io::Result<()> { -// stacker::run().await -// } - -pub struct TestApp { - pub address: String, - pub db_pool: PgPool, -} - -pub async fn configure_database(config: &DatabaseSettings) -> PgPool { - let mut connection = PgConnection::connect(&config.connection_string_without_db()) - .await - .expect("Failed to connect to postgres"); - - connection - .execute(format!(r#"CREATE DATABASE "{}""#, config.database_name).as_str()) - .await - .expect("Failed to create database"); - - let connection_pool = PgPool::connect(&config.connection_string()) - .await - .expect("Failed to connect to database pool"); - - sqlx::migrate!("./migrations") - .run(&connection_pool) - .await - .expect("Failed to migrate database"); - - connection_pool -} - - -// we have to run server in another thread -async fn spawn_app() -> TestApp { - // Future - - // let mut rt = tokio::runtime::Runtime::new().unwrap(); - // rt.spawn(mock_auth_server(listener)).expect("Could not spawn auth server"); - let mut configuration = get_configuration().expect("Failed to get configuration"); - - let listener = std::net::TcpListener::bind("127.0.0.1:0") - .expect("Failed to bind port for testing auth server"); - - configuration.auth_url = format!("http://127.0.0.1:{}/me", listener.local_addr().unwrap().port()); - println!("Auth Server is running on: {}", configuration.auth_url); - - let handle = tokio::spawn(mock_auth_server(listener)); - handle.await.expect("Auth Server can not be started"); - - let listener = std::net::TcpListener::bind("127.0.0.1:0") - .expect("Failed to bind random port"); - - let port = listener.local_addr().unwrap().port(); - let address = format!("http://127.0.0.1:{}", port); - configuration.database.database_name = uuid::Uuid::new_v4().to_string(); - - let connection_pool = configure_database(&configuration.database).await; - - let server = stacker::startup::run(listener, connection_pool.clone(), configuration) - .await.expect("Failed to bind address."); - - let _ = tokio::spawn(server); - println!("Used Port: {}", port); - - TestApp { - address, - db_pool: connection_pool, - } } - -#[tokio::test] -async fn add_rating_returns_a_200_for_valid_form_data() { - // Arrange - let app = spawn_app().await; - let client = reqwest::Client::new(); - - // let body = "name=le%20guin&email=ursula_le_guin%40gmail.com"; // %20 - space, %40 - @ - // let response = client - // .post(&format!("{}/subscriptions", &app.address)) - // .header("Content-Type", "application/x-www-form-urlencoded") - // .body(body) - // .send() - // .await - // .expect("Failed to execute request."); - // - // assert_eq!(200, response.status().as_u16()); - // - // let saved = sqlx::query!("SELECT email, name FROM subscriptions",) - // .fetch_one(&app.db_pool) - // .await - // .expect("Failed to fetch saved subscription."); - // - // assert_eq!(saved.email, "ursula_le_guin@gmail.com"); - // assert_eq!(saved.name, "le guin"); -} \ No newline at end of file From f62296cb40ed7116fdb7e54fc5c948469a2157e0 Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 2 Dec 2023 18:10:32 +0200 Subject: [PATCH 029/284] issue-auth no common test target --- tests/common.rs | 83 ------------------------------------------------- 1 file changed, 83 deletions(-) delete mode 100644 tests/common.rs diff --git a/tests/common.rs b/tests/common.rs deleted file mode 100644 index afc4134..0000000 --- a/tests/common.rs +++ /dev/null @@ -1,83 +0,0 @@ -use actix_web::{get, web, App, HttpServer, Responder}; -use sqlx::{Connection, Executor, PgConnection, PgPool}; -use stacker::configuration::{get_configuration, DatabaseSettings}; -use stacker::forms; -use std::net::TcpListener; - -pub async fn spawn_app() -> TestApp { - let mut configuration = get_configuration().expect("Failed to get configuration"); - - let listener = std::net::TcpListener::bind("127.0.0.1:0") - .expect("Failed to bind port for testing auth server"); - - configuration.auth_url = format!( - "http://127.0.0.1:{}/me", - listener.local_addr().unwrap().port() - ); - println!("Auth Server is running on: {}", configuration.auth_url); - - let handle = tokio::spawn(mock_auth_server(listener)); - handle.await.expect("Auth Server can not be started"); - - let listener = std::net::TcpListener::bind("127.0.0.1:0").expect("Failed to bind random port"); - - let port = listener.local_addr().unwrap().port(); - let address = format!("http://127.0.0.1:{}", port); - configuration.database.database_name = uuid::Uuid::new_v4().to_string(); - - let connection_pool = configure_database(&configuration.database).await; - - let server = stacker::startup::run(listener, connection_pool.clone(), configuration) - .await - .expect("Failed to bind address."); - - let _ = tokio::spawn(server); - println!("Used Port: {}", port); - - TestApp { - address, - db_pool: connection_pool, - } -} - -pub async fn configure_database(config: &DatabaseSettings) -> PgPool { - let mut connection = PgConnection::connect(&config.connection_string_without_db()) - .await - .expect("Failed to connect to postgres"); - - connection - .execute(format!(r#"CREATE DATABASE "{}""#, config.database_name).as_str()) - .await - .expect("Failed to create database"); - - let connection_pool = PgPool::connect(&config.connection_string()) - .await - .expect("Failed to connect to database pool"); - - sqlx::migrate!("./migrations") - .run(&connection_pool) - .await - .expect("Failed to migrate database"); - - connection_pool -} - -pub struct TestApp { - pub address: String, - pub db_pool: PgPool, -} - -#[get("")] -async fn mock_auth() -> actix_web::Result { - println!("Starting auth server in test mode ..."); - // 1. set user id - // 2. add token to header / hardcoded - Ok(web::Json(forms::user::UserForm::default())) -} - -async fn mock_auth_server(listener: TcpListener) -> actix_web::dev::Server { - HttpServer::new(|| App::new().service(web::scope("/me").service(mock_auth))) - .listen(listener) - .unwrap() - .run() -} From 38da8d42a760db39195bab33c909d8cef1d732fd Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 2 Dec 2023 18:11:05 +0200 Subject: [PATCH 030/284] issue-auth no common test target --- tests/common/mod.rs | 83 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 tests/common/mod.rs diff --git a/tests/common/mod.rs b/tests/common/mod.rs new file mode 100644 index 0000000..afc4134 --- /dev/null +++ b/tests/common/mod.rs @@ -0,0 +1,83 @@ +use actix_web::{get, web, App, HttpServer, Responder}; +use sqlx::{Connection, Executor, PgConnection, PgPool}; +use stacker::configuration::{get_configuration, DatabaseSettings}; +use stacker::forms; +use std::net::TcpListener; + +pub async fn spawn_app() -> TestApp { + let mut configuration = get_configuration().expect("Failed to get configuration"); + + let listener = std::net::TcpListener::bind("127.0.0.1:0") + .expect("Failed to bind port for testing auth server"); + + configuration.auth_url = format!( + "http://127.0.0.1:{}/me", + listener.local_addr().unwrap().port() + ); + println!("Auth Server is running on: {}", configuration.auth_url); + + let handle = tokio::spawn(mock_auth_server(listener)); + handle.await.expect("Auth Server can not be started"); + + let listener = std::net::TcpListener::bind("127.0.0.1:0").expect("Failed to bind random port"); + + let port = listener.local_addr().unwrap().port(); + let address = format!("http://127.0.0.1:{}", port); + configuration.database.database_name = uuid::Uuid::new_v4().to_string(); + + let connection_pool = configure_database(&configuration.database).await; + + let server = stacker::startup::run(listener, connection_pool.clone(), configuration) + .await + .expect("Failed to bind address."); + + let _ = tokio::spawn(server); + println!("Used Port: {}", port); + + TestApp { + address, + db_pool: connection_pool, + } +} + +pub async fn configure_database(config: &DatabaseSettings) -> PgPool { + let mut connection = PgConnection::connect(&config.connection_string_without_db()) + .await + .expect("Failed to connect to postgres"); + + connection + .execute(format!(r#"CREATE DATABASE "{}""#, config.database_name).as_str()) + .await + .expect("Failed to create database"); + + let connection_pool = PgPool::connect(&config.connection_string()) + .await + .expect("Failed to connect to database pool"); + + sqlx::migrate!("./migrations") + .run(&connection_pool) + .await + .expect("Failed to migrate database"); + + connection_pool +} + +pub struct TestApp { + pub address: String, + pub db_pool: PgPool, +} + +#[get("")] +async fn mock_auth() -> actix_web::Result { + println!("Starting auth server in test mode ..."); + // 1. set user id + // 2. add token to header / hardcoded + Ok(web::Json(forms::user::UserForm::default())) +} + +async fn mock_auth_server(listener: TcpListener) -> actix_web::dev::Server { + HttpServer::new(|| App::new().service(web::scope("/me").service(mock_auth))) + .listen(listener) + .unwrap() + .run() +} From 14a8a367c89578d4a111e5af17938cb6e081424e Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 2 Dec 2023 18:15:58 +0200 Subject: [PATCH 031/284] issue-auth test middleware_client sketch --- tests/middleware_client.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/middleware_client.rs diff --git a/tests/middleware_client.rs b/tests/middleware_client.rs new file mode 100644 index 0000000..31c5565 --- /dev/null +++ b/tests/middleware_client.rs @@ -0,0 +1,22 @@ +mod common; + +#[tokio::test] +async fn middleware_client_works() { + // 1. Arrange + // 2. Act + // 3. Assert + + println!("Before spawn_app"); + let app = common::spawn_app().await; // server + println!("After spawn_app"); + let client = reqwest::Client::new(); // client + + let response = client + .get(&format!("{}/health_check", &app.address)) + .send() + .await + .expect("Failed to execute request."); + + assert!(response.status().is_success()); + assert_eq!(Some(0), response.content_length()); +} From a565c4ebf242bb0a3e5416546fd9c2836897e6ae Mon Sep 17 00:00:00 2001 From: vsilent Date: Sun, 3 Dec 2023 15:46:02 +0200 Subject: [PATCH 032/284] ports deserialize fix --- Cargo.lock | 665 +++++++++++++++++++++++------------ src/forms/mod.rs | 2 +- src/forms/stack.rs | 83 +++-- src/helpers/json.rs | 58 --- src/helpers/stack/builder.rs | 274 +++++++++------ src/middleware/trydirect.rs | 2 +- src/routes/stack/add.rs | 9 +- src/routes/stack/compose.rs | 19 +- tests/app.json | 99 ++++++ tests/model_user_stack.rs | 62 ++++ tests/web-item.json | 99 ++++++ 11 files changed, 931 insertions(+), 441 deletions(-) create mode 100644 tests/app.json create mode 100644 tests/model_user_stack.rs create mode 100644 tests/web-item.json diff --git a/Cargo.lock b/Cargo.lock index 2ac8449..abfde51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,8 +44,8 @@ dependencies = [ "actix-rt", "actix-service", "actix-utils", - "ahash 0.8.3", - "base64 0.21.4", + "ahash 0.8.6", + "base64 0.21.5", "bitflags 2.4.1", "brotli", "bytes", @@ -80,7 +80,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -118,7 +118,7 @@ dependencies = [ "futures-core", "futures-util", "mio", - "socket2 0.5.4", + "socket2 0.5.5", "tokio", "tracing", ] @@ -159,7 +159,7 @@ dependencies = [ "actix-service", "actix-utils", "actix-web-codegen", - "ahash 0.8.3", + "ahash 0.8.6", "bytes", "bytestring", "cfg-if", @@ -179,7 +179,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "smallvec", - "socket2 0.5.4", + "socket2 0.5.5", "time 0.3.30", "url", ] @@ -193,7 +193,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -204,7 +204,7 @@ checksum = "1d613edf08a42ccc6864c941d30fe14e1b676a77d16f1dbadc1174d065a0a775" dependencies = [ "actix-utils", "actix-web", - "base64 0.21.4", + "base64 0.21.5", "futures-core", "futures-util", "log", @@ -228,9 +228,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" dependencies = [ "getrandom", "once_cell", @@ -239,14 +239,15 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.3" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" dependencies = [ "cfg-if", "getrandom", "once_cell", "version_check", + "zerocopy", ] [[package]] @@ -344,41 +345,43 @@ dependencies = [ [[package]] name = "async-channel" -version = "1.9.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +checksum = "1ca33f4bc4ed1babef42cad36cc1f51fa88be00420404e5b1e80ab1b18f7678c" dependencies = [ "concurrent-queue", - "event-listener", + "event-listener 4.0.0", + "event-listener-strategy", "futures-core", + "pin-project-lite", ] [[package]] name = "async-executor" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0c4a4f319e45986f347ee47fef8bf5e81c9abc3f6f58dc2391439f30df65f0" +checksum = "17ae5ebefcc48e7452b4987947920dac9450be1110cadf34d1b8c116bdbaf97c" dependencies = [ - "async-lock", + "async-lock 3.1.2", "async-task", "concurrent-queue", "fastrand 2.0.1", - "futures-lite", + "futures-lite 2.0.1", "slab", ] [[package]] name = "async-global-executor" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" +checksum = "9b4353121d5644cdf2beb5726ab752e79a8db1ebb52031770ec47db31d245526" dependencies = [ "async-channel", "async-executor", - "async-io", - "async-lock", + "async-io 2.2.1", + "async-lock 3.1.2", "blocking", - "futures-lite", + "futures-lite 2.0.1", "once_cell", ] @@ -399,27 +402,57 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" dependencies = [ - "async-lock", + "async-lock 2.8.0", "autocfg", "cfg-if", "concurrent-queue", - "futures-lite", + "futures-lite 1.13.0", "log", "parking", - "polling", + "polling 2.8.0", "rustix 0.37.27", "slab", - "socket2 0.4.9", + "socket2 0.4.10", "waker-fn", ] +[[package]] +name = "async-io" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6d3b15875ba253d1110c740755e246537483f152fa334f91abd7fe84c88b3ff" +dependencies = [ + "async-lock 3.1.2", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite 2.0.1", + "parking", + "polling 3.3.1", + "rustix 0.38.25", + "slab", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "async-lock" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" dependencies = [ - "event-listener", + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea8b3453dd7cc96711834b75400d671b73e3656975fa68d9f277163b7f7e316" +dependencies = [ + "event-listener 4.0.0", + "event-listener-strategy", + "pin-project-lite", ] [[package]] @@ -428,7 +461,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a6012d170ad00de56c9ee354aef2e358359deb1ec504254e0e5a3774771de0e" dependencies = [ - "async-io", + "async-io 1.13.0", "async-trait", "futures-core", "reactor-trait", @@ -448,7 +481,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -495,9 +528,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.4" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "bitflags" @@ -531,16 +564,16 @@ dependencies = [ [[package]] name = "blocking" -version = "1.4.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c36a4d0d48574b3dd360b4b7d95cc651d2b6557b6402848a27d4b228a473e2a" +checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118" dependencies = [ "async-channel", - "async-lock", + "async-lock 3.1.2", "async-task", "fastrand 2.0.1", "futures-io", - "futures-lite", + "futures-lite 2.0.1", "piper", "tracing", ] @@ -558,9 +591,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "2.5.0" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da74e2b81409b1b743f8f0c62cc6254afefb8b8e50bbfe3735550f7aeefa3448" +checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -586,9 +619,9 @@ checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "bytestring" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "238e4886760d98c4f899360c834fa93e62cf7f721ac3c2da375cbdf4b8679aae" +checksum = "74d80203ea6b29df88012294f62733de21cfeab47f17b41af3a38bc30a03ee72" dependencies = [ "bytes", ] @@ -631,7 +664,7 @@ dependencies = [ "serde", "time 0.1.45", "wasm-bindgen", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -655,9 +688,9 @@ dependencies = [ [[package]] name = "config" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d379af7f68bfc21714c6c7dea883544201741d2ce8274bb12fa54f89507f52a7" +checksum = "23738e11972c7643e4ec947840fc463b6a571afcd3e735bdfce7d03c7a784aca" dependencies = [ "async-trait", "json5", @@ -713,9 +746,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" dependencies = [ "libc", ] @@ -731,9 +764,9 @@ dependencies = [ [[package]] name = "crc-catalog" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc32fast" @@ -945,12 +978,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" +checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -959,6 +992,27 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +[[package]] +name = "event-listener" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "770d968249b5d99410d61f5bf89057f3199a077a04d087092f58e7d10692baae" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" +dependencies = [ + "event-listener 4.0.0", + "pin-project-lite", +] + [[package]] name = "executor-trait" version = "2.1.0" @@ -1011,6 +1065,15 @@ dependencies = [ "spin 0.9.8", ] +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "spin 0.9.8", +] + [[package]] name = "fnv" version = "1.0.7" @@ -1034,9 +1097,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -1115,6 +1178,20 @@ dependencies = [ "waker-fn", ] +[[package]] +name = "futures-lite" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3831c2651acb5177cbd83943f3d9c8912c5ad03c76afcc0e9511ba568ec5ebb" +dependencies = [ + "fastrand 2.0.1", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", +] + [[package]] name = "futures-macro" version = "0.3.29" @@ -1123,7 +1200,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1178,9 +1255,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", "libc", @@ -1189,9 +1266,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "glob" @@ -1201,9 +1278,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "h2" -version = "0.3.21" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" dependencies = [ "bytes", "fnv", @@ -1211,7 +1288,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", @@ -1224,16 +1301,16 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.6", + "ahash 0.7.7", ] [[package]] name = "hashbrown" -version = "0.14.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.6", "allocator-api2", ] @@ -1243,7 +1320,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.14.1", + "hashbrown 0.14.2", ] [[package]] @@ -1287,9 +1364,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -1336,7 +1413,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.9", + "socket2 0.4.10", "tokio", "tower-service", "tracing", @@ -1387,9 +1464,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1413,7 +1490,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown 0.14.1", + "hashbrown 0.14.2", "serde", ] @@ -1444,14 +1521,14 @@ checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ "hermit-abi", "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "ipnet" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "itertools" @@ -1488,9 +1565,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" dependencies = [ "wasm-bindgen", ] @@ -1523,7 +1600,7 @@ dependencies = [ "async-reactor-trait", "async-trait", "executor-trait", - "flume", + "flume 0.10.14", "futures-core", "futures-io", "parking_lot 0.12.1", @@ -1543,9 +1620,20 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.149" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" + +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall 0.4.1", +] [[package]] name = "linked-hash-map" @@ -1561,15 +1649,15 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" +checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" [[package]] name = "local-channel" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a493488de5f18c8ffcba89eebb8532ffc562dc400490eb65b84893fae0b178" +checksum = "b6cbc85e69b8df4b8bb8b89ec634e7189099cea8927a276b7384ce5488e53ec8" dependencies = [ "futures-core", "futures-sink", @@ -1578,9 +1666,9 @@ dependencies = [ [[package]] name = "local-waker" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e34f76eb3611940e0e7d53a9aaa4e6a3151f69541a282fd0dad5571420c53ff1" +checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" [[package]] name = "lock_api" @@ -1646,16 +1734,22 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.48.0", ] +[[package]] +name = "mutually_exclusive_features" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d02c0b00610773bb7fc61d85e13d86c7858cbdf00e1a120bfc41bc055dbaa0e" + [[package]] name = "native-tls" version = "0.2.11" @@ -1730,9 +1824,9 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "openssl" -version = "0.10.57" +version = "0.10.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" +checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800" dependencies = [ "bitflags 2.4.1", "cfg-if", @@ -1751,7 +1845,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1762,9 +1856,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.93" +version = "0.9.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" +checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f" dependencies = [ "cc", "libc", @@ -1856,7 +1950,7 @@ dependencies = [ "libc", "redox_syscall 0.4.1", "smallvec", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -1873,15 +1967,15 @@ checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c022f1e7b65d6a24c0dbbd5fb344c66881bc01f3e5ae74a1c8100f2f985d98a4" +checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5" dependencies = [ "memchr", "thiserror", @@ -1890,9 +1984,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35513f630d46400a977c4cb58f78e1bfbe01434316e60c37d27b9ad6139c66d8" +checksum = "81d78524685f5ef2a3b3bd1cafbc9fcabb036253d9b1463e726a91cd16e2dfc2" dependencies = [ "pest", "pest_generator", @@ -1900,22 +1994,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc9fc1b9e7057baba189b5c626e2d6f40681ae5b6eb064dc7c7834101ec8123a" +checksum = "68bd1206e71118b5356dae5ddc61c8b11e28b09ef6a31acbd15ea48a28e0c227" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "pest_meta" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df74e9e7ec4053ceb980e7c0c8bd3594e977fde1af91daba9c928e8e8c6708d" +checksum = "7c747191d4ad9e4a4ab9c8798f1e82a39affe7ef9648390b7e5548d18e099de6" dependencies = [ "once_cell", "pest", @@ -1939,7 +2033,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1956,12 +2050,12 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pinky-swear" -version = "6.1.0" +version = "6.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d894b67aa7a4bf295db5e85349078c604edaa6fa5c8721e8eca3c7729a27f2ac" +checksum = "6cfae3ead413ca051a681152bd266438d3bfa301c9bdf836939a14c721bb2a21" dependencies = [ "doc-comment", - "flume", + "flume 0.11.0", "parking_lot 0.12.1", "tracing", ] @@ -1996,7 +2090,21 @@ dependencies = [ "libc", "log", "pin-project-lite", - "windows-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "polling" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf63fa624ab313c11656b4cda960bfc46c410187ad493c41f6ba2d8c1e991c9e" +dependencies = [ + "cfg-if", + "concurrent-queue", + "pin-project-lite", + "rustix 0.38.25", + "tracing", + "windows-sys 0.52.0", ] [[package]] @@ -2037,9 +2145,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" dependencies = [ "unicode-ident", ] @@ -2112,15 +2220,6 @@ dependencies = [ "bitflags 1.3.2", ] -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -2132,12 +2231,12 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ "getrandom", - "redox_syscall 0.2.16", + "libredox", "thiserror", ] @@ -2191,7 +2290,7 @@ version = "0.11.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", "bytes", "encoding_rs", "futures-core", @@ -2240,16 +2339,16 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.4" +version = "0.17.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fce3045ffa7c981a6ee93f640b538952e155f1ae3a1a02b84547fc7a56b7059a" +checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" dependencies = [ "cc", "getrandom", "libc", "spin 0.9.8", "untrusted 0.9.0", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2299,20 +2398,20 @@ dependencies = [ "io-lifetimes", "libc", "linux-raw-sys 0.3.8", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "rustix" -version = "0.38.19" +version = "0.38.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "745ecfa778e66b2b63c88a61cb36e0eea109e803b0b86bf9879fbc77c70e86ed" +checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" dependencies = [ "bitflags 2.4.1", "errno", "libc", - "linux-raw-sys 0.4.10", - "windows-sys", + "linux-raw-sys 0.4.11", + "windows-sys 0.48.0", ] [[package]] @@ -2329,24 +2428,24 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.8" +version = "0.21.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446e14c5cda4f3f30fe71863c34ec70f5ac79d6087097ad0bb433e1be5edf04c" +checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9" dependencies = [ "log", - "ring 0.17.4", + "ring 0.17.5", "rustls-webpki", "sct", ] [[package]] name = "rustls-connector" -version = "0.18.3" +version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "060bcc1795b840d0e56d78f3293be5f652aa1611d249b0e63ffe19f4a8c9ae23" +checksum = "25da151615461c7347114b1ad1a7458b4cdebc69cb220cd140cd5cb324b1dd37" dependencies = [ "log", - "rustls 0.21.8", + "rustls 0.21.9", "rustls-native-certs", "rustls-webpki", ] @@ -2365,11 +2464,11 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", ] [[package]] @@ -2378,7 +2477,7 @@ version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.17.4", + "ring 0.17.5", "untrusted 0.9.0", ] @@ -2394,7 +2493,7 @@ version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2405,12 +2504,12 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sct" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.16.20", - "untrusted 0.7.1", + "ring 0.17.5", + "untrusted 0.9.0", ] [[package]] @@ -2444,29 +2543,29 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "serde" -version = "1.0.189" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.189" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "serde_json" -version = "1.0.107" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", @@ -2531,9 +2630,9 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.25" +version = "0.9.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574" +checksum = "3cc7a1570e38322cfe4154732e5110f887ea57e22b76f4bfd32b5bdd3368666c" dependencies = [ "indexmap 2.1.0", "itoa", @@ -2593,15 +2692,15 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.1" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "socket2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi", @@ -2609,12 +2708,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2659,7 +2758,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa8241483a83a3f33aa5fff7e7d9def398ff9990b2752b6c6112b83c6d246029" dependencies = [ - "ahash 0.7.6", + "ahash 0.7.7", "atoi", "base64 0.13.1", "bitflags 1.3.2", @@ -2671,7 +2770,7 @@ dependencies = [ "dirs", "dotenvy", "either", - "event-listener", + "event-listener 2.5.3", "futures-channel", "futures-core", "futures-intrusive", @@ -2753,7 +2852,7 @@ dependencies = [ "config", "derive_builder", "futures", - "futures-lite", + "futures-lite 1.13.0", "futures-util", "glob", "hmac", @@ -2775,7 +2874,7 @@ dependencies = [ "tracing", "tracing-actix-web", "tracing-bunyan-formatter", - "tracing-log", + "tracing-log 0.1.4", "tracing-subscriber", "uuid", ] @@ -2816,9 +2915,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.38" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -2860,35 +2959,35 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.8.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", "fastrand 2.0.1", - "redox_syscall 0.3.5", - "rustix 0.38.19", - "windows-sys", + "redox_syscall 0.4.1", + "rustix 0.38.25", + "windows-sys 0.48.0", ] [[package]] name = "thiserror" -version = "1.0.49" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.49" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2958,9 +3057,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.33.0" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ "backtrace", "bytes", @@ -2970,20 +3069,20 @@ dependencies = [ "parking_lot 0.12.1", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.4", + "socket2 0.5.5", "tokio-macros", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -3020,9 +3119,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -3049,9 +3148,9 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.39" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2ef2af84856a50c1d430afce2fdded0a4ec7eda868db86409b4543df0797f9" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "log", "pin-project-lite", @@ -3061,11 +3160,12 @@ dependencies = [ [[package]] name = "tracing-actix-web" -version = "0.7.7" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94982c2ad939d5d0bfd71c2f9b7ed273c72348485c72bb87bb4db6bd69df10cb" +checksum = "1fe0d5feac3f4ca21ba33496bcb1ccab58cca6412b1405ae80f0581541e0ca78" dependencies = [ "actix-web", + "mutually_exclusive_features", "pin-project", "tracing", "uuid", @@ -3079,7 +3179,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -3088,7 +3188,7 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5c266b9ac83dedf0e0385ad78514949e6d89491269e7065bee51d2bb8ec7373" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.6", "gethostname", "log", "serde", @@ -3096,7 +3196,7 @@ dependencies = [ "time 0.3.30", "tracing", "tracing-core", - "tracing-log", + "tracing-log 0.1.4", "tracing-subscriber", ] @@ -3112,20 +3212,31 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" dependencies = [ - "lazy_static", "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", "tracing-core", ] [[package]] name = "tracing-subscriber" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", "nu-ansi-term", @@ -3136,7 +3247,7 @@ dependencies = [ "thread_local", "tracing", "tracing-core", - "tracing-log", + "tracing-log 0.2.0", ] [[package]] @@ -3210,9 +3321,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", @@ -3221,9 +3332,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.5.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" +checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" dependencies = [ "getrandom", "serde", @@ -3276,9 +3387,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3286,24 +3397,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" dependencies = [ "cfg-if", "js-sys", @@ -3313,9 +3424,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3323,28 +3434,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" dependencies = [ "js-sys", "wasm-bindgen", @@ -3356,7 +3467,7 @@ version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" dependencies = [ - "ring 0.17.4", + "ring 0.17.5", "untrusted 0.9.0", ] @@ -3407,7 +3518,7 @@ version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -3416,7 +3527,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", ] [[package]] @@ -3425,13 +3545,28 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] @@ -3440,42 +3575,84 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + [[package]] name = "winreg" version = "0.50.0" @@ -3483,7 +3660,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ "cfg-if", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -3501,6 +3678,26 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +[[package]] +name = "zerocopy" +version = "0.7.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e97e415490559a91254a2979b4829267a57d2fcd741a98eee8b722fb57289aa0" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "zstd" version = "0.12.4" diff --git a/src/forms/mod.rs b/src/forms/mod.rs index 957c91d..ae65e1c 100644 --- a/src/forms/mod.rs +++ b/src/forms/mod.rs @@ -1,6 +1,6 @@ mod rating; -pub(crate) mod stack; +pub mod stack; pub mod user; pub use rating::*; diff --git a/src/forms/stack.rs b/src/forms/stack.rs index c3f108a..91b34cb 100644 --- a/src/forms/stack.rs +++ b/src/forms/stack.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use serde::{Deserialize, Serialize}; use serde_json::Value; use serde_valid::Validate; @@ -11,8 +12,10 @@ pub struct Role { #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Requirements { - #[validate(minimum=0.1)] - pub cpu: Option, + #[validate(min_length=1)] + #[validate(max_length=10)] + #[validate(pattern = r"^\d+\.?[0-9]+$")] + pub cpu: Option, #[validate(min_length=1)] #[validate(max_length=10)] #[validate(pattern = r"^\d+G$")] @@ -25,12 +28,18 @@ pub struct Requirements { pub ram_size: Option, } -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Port { + pub host_port: Option, + pub container_port: Option +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Ports { #[serde(rename(deserialize = "sharedPorts"))] #[serde(rename(serialize = "shared_ports"))] - #[serde(alias = "shared_ports")] - pub shared_ports: Option>, + // #[serde(alias = "shared_ports")] + pub shared_ports: Option>, pub ports: Option>, } @@ -159,42 +168,32 @@ pub struct Var { } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] pub struct Price { pub value: f64 } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -#[serde(rename_all = "camelCase")] pub struct Custom { pub web: Vec, pub feature: Option>, pub service: Option>, - #[serde(rename = "servers_count")] #[validate(minimum = 0)] #[validate(maximum = 10)] pub servers_count: u32, #[validate(min_length=3)] #[validate(max_length=50)] - #[serde(rename = "custom_stack_code")] pub custom_stack_code: String, - #[serde(rename = "project_git_url")] #[validate(min_length=3)] #[validate(max_length=255)] pub project_git_url: Option, - #[serde(rename = "custom_stack_category")] pub custom_stack_category: Option>, - #[serde(rename = "custom_stack_short_description")] pub custom_stack_short_description: Option, - #[serde(rename = "custom_stack_description")] pub custom_stack_description: Option, - #[serde(rename = "project_name")] #[validate(min_length=3)] #[validate(max_length=255)] pub project_name: String, - #[serde(rename = "project_overview")] pub project_overview: Option, - #[serde(rename = "project_description")] pub project_description: Option, + pub networks: Option>, // all networks } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] @@ -222,8 +221,6 @@ pub struct App { #[serde(flatten)] pub role: Role, pub default: Option, - #[serde(flatten)] - pub ports: Option, pub versions: Option>, #[serde(flatten)] pub docker_image: DockerImage, @@ -242,6 +239,7 @@ pub struct App { pub domain: Option, pub category_id: Option, pub parent_app_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub descr: Option, pub full_description: Option, pub description: Option, @@ -250,9 +248,42 @@ pub struct App { pub repo_dir: Option, pub url_app: Option, pub url_git: Option, + pub restart: Option, + pub volumes: Option>, + #[serde(flatten)] + pub environment: Environment, + #[serde(flatten)] + pub network: Networks, + // #[serde(flatten)] + // pub ports: Ports, + #[serde(rename(deserialize = "sharedPorts"))] + #[serde(rename(serialize = "shared_ports"))] + // #[serde(alias = "shared_ports")] + pub ports: Option>, } -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Environment { + environment: Option>> +} +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Volume { + host_path: Option, + container_path: Option +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Volumes { + volumes: Vec +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Networks { + //network: Option> + network: Option +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Web { #[serde(flatten)] pub app: App, @@ -260,28 +291,33 @@ pub struct Web { pub main: bool, } -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Feature { + // #[serde(rename(deserialize = "sharedPorts"))] + // #[serde(rename(serialize = "shared_ports"))] + // #[serde(alias = "shared_ports")] + // pub shared_ports: Option>, #[serde(flatten)] pub app: App, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -#[serde(rename_all = "camelCase")] pub struct Service { + // #[serde(rename(deserialize = "sharedPorts"))] + // #[serde(rename(serialize = "shared_ports"))] + // #[serde(alias = "shared_ports")] + // pub shared_ports: Option>, #[serde(flatten)] pub(crate) app: App, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] pub struct Icon { pub light: IconLight, pub dark: IconDark, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] pub struct IconLight { pub width: i64, pub height: i64, @@ -289,7 +325,6 @@ pub struct IconLight { } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] pub struct IconDark { } diff --git a/src/helpers/json.rs b/src/helpers/json.rs index 87e7327..6a08405 100644 --- a/src/helpers/json.rs +++ b/src/helpers/json.rs @@ -133,62 +133,4 @@ where list, } } - - // pub(crate) fn ok(id: i32, message: &str) -> JsonResponse { - // - // let msg = if !message.trim().is_empty() { - // message.to_string() - // } - // else{ - // String::from("Success") - // }; - // - // JsonResponse { - // message: msg, - // id: Some(id), - // item: None, - // list: None, - // } - // } - - // pub(crate) fn not_found() -> Self { - // JsonResponse { - // id: None, - // item: None, - // message: format!("Object not found"), - // list: None, - // } - // } - // - // pub(crate) fn internal_error(message: &str) -> Self { - // - // let msg = if !message.trim().is_empty() { - // message.to_string() - // } - // else{ - // String::from("Internal error") - // }; - // JsonResponse { - // id: None, - // item: None, - // message: msg, - // list: None, - // } - // } - // - // pub(crate) fn not_valid(message: &str) -> Self { - // - // let msg = if !message.trim().is_empty() { - // message.to_string() - // } - // else{ - // String::from("Validation error") - // }; - // JsonResponse { - // id: None, - // item: None, - // message: msg, - // list: None, - // } - // } } diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index c319d8a..316a03f 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -18,6 +18,18 @@ impl Default for Config { } } +impl Default for Port{ + fn default() -> Self { + Port { + target: 80, + host_ip: None, + published: None, + protocol: None, + mode: None, + } + } +} + /// A builder for constructing docker compose. #[derive(Clone, Debug)] pub struct DcBuilder { @@ -25,26 +37,55 @@ pub struct DcBuilder { pub(crate) stack: Stack } +// impl TryInto> for stack::Ports { +// type Error = String; +// fn try_into(self) -> Result, Self::Error> { +// convert_shared_ports(self.shared_ports.clone()) +// } +// } + + impl TryInto> for stack::Ports { type Error = String; fn try_into(self) -> Result, Self::Error> { - convert_shared_ports(self.shared_ports.clone().unwrap()) + convert_shared_ports(self.shared_ports.clone()) } } -fn convert_shared_ports(ports: Vec) -> Result, String> { +fn convert_shared_ports(ports: Option>) -> Result, String> { + tracing::debug!("convert shared ports {:?}", &ports); let mut _ports: Vec = vec![]; - for p in ports { - let port = p.parse::().map_err(|e| e.to_string())?; - _ports.push(Port { - target: port, - host_ip: None, - published: Some(PublishedPort::Single(port)), - protocol: None, - mode: None, - }); + match ports { + Some(ports) => { + tracing::debug!("Ports >>>> {:?}", ports); + for port in ports { + let cp = port.container_port + .unwrap_or("".to_string()) + .parse::().map_err(|err| "Could not parse port".to_string() )?; + let hp = port.host_port + .unwrap_or("".to_string()) + .parse::().map_err(|err| "Could not parse port".to_string() )?; + + tracing::debug!("Port conversion result: cp: {:?} hp: {:?}", cp, hp); + _ports.push( + Port { + target: cp, + host_ip: None, + published: Some(PublishedPort::Single(hp)), + protocol: None, + mode: None, + } + ); + } + } + None => { + tracing::debug!("No ports defined by user"); + return Ok(_ports); + } } + + tracing::debug!("ports {:?}", _ports); Ok(_ports) } @@ -59,109 +100,112 @@ impl DcBuilder { pub fn build(&self) -> Option { - - tracing::debug!("Start build docker compose from {:?}", &self.stack.body); - let _stack = serde_json::from_value::(self.stack.body.clone()); - let mut services = indexmap::IndexMap::new(); - match _stack { - Ok(apps) => { - println!("stack item {:?}", apps.custom.web); - - for app_type in apps.custom.web { - let code = app_type.app.code.clone().to_owned(); - let mut service = Service { - image: Some(app_type.app.docker_image.to_string()), - ..Default::default() - }; - - if let Some(ports) = &app_type.app.ports { - if !ports.shared_ports.clone()?.is_empty() { - service.ports = Ports::Long(app_type.app.ports?.try_into().unwrap()) - } - } - - service.restart = Some("always".to_owned()); - services.insert( - code, - Some(service), - ); - } - - if let Some(srvs) = apps.custom.service { - - if !srvs.is_empty() { - - for app_type in srvs { - let code = app_type.app.code.to_owned(); - let mut service = Service { - image: Some(app_type.app.docker_image.to_string()), - ..Default::default() - }; - - if let Some(ports) = &app_type.app.ports { - if !ports.shared_ports.clone()?.is_empty() { - service.ports = Ports::Long(app_type.app.ports?.try_into().unwrap()) - } - } - service.restart = Some("always".to_owned()); - services.insert( - code, - Some(service), - ); - } - } - } - if let Some(features) = apps.custom.feature { - - if !features.is_empty() { - - for app_type in features { - let code = app_type.app.code.to_owned(); - let mut service = Service { - // image: Some(app.dockerhub_image.as_ref().unwrap().to_owned()), - image: Some(app_type.app.docker_image.to_string()), - ..Default::default() - }; - - if let Some(ports) = &app_type.app.ports { - if !ports.shared_ports.clone()?.is_empty() { - service.ports = Ports::Long(app_type.app.ports?.try_into().unwrap()) - } - } - service.restart = Some("always".to_owned()); - services.insert( - code, - Some(service), - ); - } - } - } - } - Err(e) => { - tracing::debug!("Unpack stack form {:?}", e); - () - } - } - - let compose_content = Compose { - version: Some("3.8".to_string()), - services: { - Services(services) - }, - ..Default::default() - }; - - let fname= format!("./files/{}.yml", self.stack.stack_id); - tracing::debug!("Save docker compose to file {:?}", fname); - let target_file = std::path::Path::new(fname.as_str()); - // serialize to string - let serialized = match serde_yaml::to_string(&compose_content) { - Ok(s) => s, - Err(e) => panic!("Failed to serialize docker-compose file: {}", e), - }; - // serialize to file - std::fs::write(target_file, serialized.clone()).unwrap(); - - Some(serialized) + // + // tracing::debug!("Start build docker compose from {:?}", &self.stack.body); + // let _stack = serde_json::from_value::(self.stack.body.clone()); + // let mut services = indexmap::IndexMap::new(); + // match _stack { + // Ok(apps) => { + // // tracing::debug!("stack item {:?}", apps.custom.web); + // + // for app_type in apps.custom.web { + // let code = app_type.app.code.clone().to_owned(); + // let mut service = Service { + // image: Some(app_type.app.docker_image.to_string()), + // ..Default::default() + // }; + // + // service.ports = Ports::Long(app_type.app.ports.unwrap().try_into().unwrap()); + // service.restart = Some("always".to_owned()); + // tracing::debug!("service 1 {:?}", &service); + // services.insert( + // code, + // Some(service), + // ); + // } + // + // + // if let Some(srvs) = apps.custom.service { + // + // if !srvs.is_empty() { + // + // for app_type in srvs { + // let code = app_type.app.code.to_owned(); + // let mut service = Service { + // image: Some(app_type.app.docker_image.to_string()), + // ..Default::default() + // }; + // + // // if let Some(ports) = &app_type.app._ports { + // // tracing::debug!("service2 ports {:?}", ports); + // // service.ports = Ports::Long(ports.try_into().unwrap()) + // // } + // + // service.ports = Ports::Long(app_type.app.ports.unwrap().try_into().unwrap()); + // service.restart = Some("always".to_owned()); + // services.insert( + // code, + // Some(service), + // ); + // } + // // tracing::debug!("services {:?}", services); + // } + // } + // + // if let Some(features) = apps.custom.feature { + // + // if !features.is_empty() { + // + // for app_type in features { + // let code = app_type.app.code.to_owned(); + // let mut service = Service { + // // image: Some(app.dockerhub_image.as_ref().unwrap().to_owned()), + // image: Some(app_type.app.docker_image.to_string()), + // ..Default::default() + // }; + // + // service.ports = Ports::Long(app_type.app.ports.unwrap().try_into().unwrap()); + // // if let Some(ports) = &app_type.app._ports { + // // tracing::debug!("service3 ports {:?}", ports); + // // service.ports = Ports::Long(ports.try_into().unwrap()) + // // } + // service.restart = Some("always".to_owned()); + // services.insert( + // code, + // Some(service), + // ); + // } + // // tracing::debug!("services### {:?}", &service); + // } + // } + // tracing::debug!("services {:?}", &services); + // } + // Err(e) => { + // tracing::debug!("Unpack stack form error {:?}", e); + // () + // } + // } + // + // let compose_content = Compose { + // version: Some("3.8".to_string()), + // services: { + // Services(services) + // }, + // ..Default::default() + // }; + // + // let fname= format!("./files/{}.yml", self.stack.stack_id); + // tracing::debug!("Saving docker compose to file {:?}", fname); + // let target_file = std::path::Path::new(fname.as_str()); + // // serialize to string + // let serialized = match serde_yaml::to_string(&compose_content) { + // Ok(s) => s, + // Err(e) => panic!("Failed to serialize docker-compose file: {}", e), + // }; + // // serialize to file + // std::fs::write(target_file, serialized.clone()).unwrap(); + // + // Some(serialized) + None } } diff --git a/src/middleware/trydirect.rs b/src/middleware/trydirect.rs index 1d01c50..066c678 100644 --- a/src/middleware/trydirect.rs +++ b/src/middleware/trydirect.rs @@ -11,7 +11,7 @@ use std::sync::Arc; use crate::models::user::User; -#[tracing::instrument(name = "Trydirect bearer guard.")] +#[tracing::instrument(name = "TryDirect bearer guard.")] pub async fn bearer_guard( req: ServiceRequest, credentials: BearerAuth, diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index 1d64815..7c45ef5 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -38,6 +38,7 @@ pub async fn add( }; let stack_name = form.custom.custom_stack_code.clone(); + tracing::debug!("form before convert {:?}", form); let query_span = tracing::info_span!("Check project/stack existence by custom_stack_code."); match sqlx::query_as!( @@ -81,12 +82,14 @@ pub async fn add( let query_span = tracing::info_span!("Saving new stack details into the database"); - let errors = form.validate().is_ok(); - println!("{:?}",errors); + let errors = form.validate().unwrap_err(); + tracing::debug!("{:?}",errors); + + let body: Value = match serde_json::to_value::(form) { Ok(body) => body, Err(err) => { - tracing::error!("request_id {} unwrap body {:?}", request_id, err); + tracing::error!("Request_id {} error unwrap body {:?}", request_id, err); serde_json::to_value::(StackForm::default()).unwrap() } }; diff --git a/src/routes/stack/compose.rs b/src/routes/stack/compose.rs index 4de94f8..58f82f7 100644 --- a/src/routes/stack/compose.rs +++ b/src/routes/stack/compose.rs @@ -11,7 +11,7 @@ use actix_web::{get, post}; use sqlx::PgPool; use std::str; use tracing::Instrument; -use uuid::Uuid; +// use uuid::Uuid; use crate::helpers::stack::builder::DcBuilder; #[tracing::instrument(name = "User's generate docker-compose.")] @@ -35,7 +35,7 @@ pub async fn add( .await { Ok(stack) => { - tracing::info!("stack found: {:?}", stack.id,); + tracing::info!("stack found: {:?}", stack.id); Some(stack) } Err(sqlx::Error::RowNotFound) => { @@ -88,7 +88,7 @@ pub async fn admin( .await { Ok(stack) => { - tracing::info!("stack found: {:?}", stack.id,); + tracing::info!("stack found: {:?}", stack.id); Some(stack) } Err(sqlx::Error::RowNotFound) => { @@ -105,11 +105,20 @@ pub async fn admin( Some(stack) => { let id = stack.id.clone(); let dc = DcBuilder::new(stack); - let fc = dc.build(); + let fc = match dc.build() { + Some(fc) => { + fc + } + None => { + tracing::error!("Error. Compose builder returned an empty string"); + "".to_string() + } + + }; // tracing::debug!("Docker compose file content {:?}", fc); return JsonResponse::build() .set_id(id) - .set_item(fc.unwrap()).ok("Success".to_owned()); + .set_item(fc).ok("Success".to_owned()); } None => { diff --git a/tests/app.json b/tests/app.json new file mode 100644 index 0000000..cb4efb1 --- /dev/null +++ b/tests/app.json @@ -0,0 +1,99 @@ +{ + "_etag": null, + "_id": 180, + "_created": "2021-12-17T08:11:40.875486", + "_updated": "2023-11-21T17:37:24.594545", + "name": "Airflow", + "code": "airflow", + "role": [ + "airflow" + ], + "type": "web", + "default": true, + "popularity": null, + "descr": null, + "ports": { + "private": [ + "31" + ] + }, + "commercial": null, + "subscription": null, + "autodeploy": null, + "suggested": null, + "dependency": null, + "avoid_render": null, + "price": null, + "icon": { + "light": { + "width": 150, + "height": 150, + "image": "7f41d873-2de5-4c6e-a037-42eeff572db6.svg" + }, + "dark": { + } + }, + "category_id": null, + "parent_app_id": null, + "full_description": null, + "description": "

Airflow description

", + "plan_type": null, + "ansible_var": null, + "repo_dir": null, + "cpu": "0.0", + "ram_size": null, + "disk_size": null, + "dockerhub_image": "airflow", + "form": null, + "category": [ + null + ], + "group": [ + ], + "versions": [ + { + "_id": 425, + "name": "Airflow", + "version": "2.7.3", + "update_status": "published", + "tag": "latest" + }, + { + "_id": 426, + "name": "Airflow", + "version": "2.7.1-unstable", + "update_status": "published", + "tag": "stable" + } + ], + "links": [ + ], + "domain": "latestports.com", + "sharedPorts": [ + { + "host_port": "5000", + "container_port": "5000" + } + ], + "main": true, + "version": { + "_id": 426, + "name": "Airflow", + "version": "2.7.1-unstable", + "update_status": "published", + "tag": "stable" + }, + "environment": [ + { + "ENV_VAR1": "ENV_VAR1_VALUE" + } + ], + "network": "testnetwork", + "restart": "always", + "volumes": [ + { + "host_path": "/airflow/host/path/", + "container_path": "/airflow/container/path" + } + ] +} \ No newline at end of file diff --git a/tests/model_user_stack.rs b/tests/model_user_stack.rs new file mode 100644 index 0000000..be93cec --- /dev/null +++ b/tests/model_user_stack.rs @@ -0,0 +1,62 @@ +use stacker::forms::stack::StackForm; +use stacker::forms::stack::App; +use std::fs; +use std::collections::HashMap; + +// Unit Test + +#[test] +fn test_deserialize_user_stack_web() { + + let body_str = fs::read_to_string("./tests/web-item.json").unwrap(); + // let form:serde_json::Value = serde_json::from_str(&body_str).unwrap(); + let form:App = serde_json::from_str(&body_str).unwrap(); + println!("{:?}", form); + // { + // Ok(f) => { + // f + // } + // Err(_err) => { + // let msg = format!("Invalid data. {:?}", _err); + // return JsonResponse::::build().err(msg); + // } + // }; + // + // assert_eq!(result, 12); +} +#[test] +fn test_deserialize_user_stack() { + + let body_str = fs::read_to_string("./tests/custom-stack-payload-11.json").unwrap(); + let form = serde_json::from_str::(&body_str).unwrap(); + println!("{:?}", form); + // @todo assert required data + + // { + // Ok(f) => { + // f + // } + // Err(_err) => { + // let msg = format!("Invalid data. {:?}", _err); + // return JsonResponse::::build().err(msg); + // } + // }; + // + // assert_eq!(result, 12); + + // let form:Environment = serde_json::from_str(&body_str).unwrap(); + + // let body_str = r#" + // [ + // { + // "ENV_VAR1": "ENV_VAR1_VALUE" + // }, + // { + // "ENV_VAR2": "ENV_VAR2_VALUE", + // "ENV_VAR3": "ENV_VAR3_VALUE" + // } + // ] + // "#; + // let form:Vec> = serde_json::from_str(&body_str).unwrap(); + // println!("{:?}", form); +} diff --git a/tests/web-item.json b/tests/web-item.json new file mode 100644 index 0000000..cb4efb1 --- /dev/null +++ b/tests/web-item.json @@ -0,0 +1,99 @@ +{ + "_etag": null, + "_id": 180, + "_created": "2021-12-17T08:11:40.875486", + "_updated": "2023-11-21T17:37:24.594545", + "name": "Airflow", + "code": "airflow", + "role": [ + "airflow" + ], + "type": "web", + "default": true, + "popularity": null, + "descr": null, + "ports": { + "private": [ + "31" + ] + }, + "commercial": null, + "subscription": null, + "autodeploy": null, + "suggested": null, + "dependency": null, + "avoid_render": null, + "price": null, + "icon": { + "light": { + "width": 150, + "height": 150, + "image": "7f41d873-2de5-4c6e-a037-42eeff572db6.svg" + }, + "dark": { + } + }, + "category_id": null, + "parent_app_id": null, + "full_description": null, + "description": "

Airflow description

", + "plan_type": null, + "ansible_var": null, + "repo_dir": null, + "cpu": "0.0", + "ram_size": null, + "disk_size": null, + "dockerhub_image": "airflow", + "form": null, + "category": [ + null + ], + "group": [ + ], + "versions": [ + { + "_id": 425, + "name": "Airflow", + "version": "2.7.3", + "update_status": "published", + "tag": "latest" + }, + { + "_id": 426, + "name": "Airflow", + "version": "2.7.1-unstable", + "update_status": "published", + "tag": "stable" + } + ], + "links": [ + ], + "domain": "latestports.com", + "sharedPorts": [ + { + "host_port": "5000", + "container_port": "5000" + } + ], + "main": true, + "version": { + "_id": 426, + "name": "Airflow", + "version": "2.7.1-unstable", + "update_status": "published", + "tag": "stable" + }, + "environment": [ + { + "ENV_VAR1": "ENV_VAR1_VALUE" + } + ], + "network": "testnetwork", + "restart": "always", + "volumes": [ + { + "host_path": "/airflow/host/path/", + "container_path": "/airflow/container/path" + } + ] +} \ No newline at end of file From 28938e65891433fcab9dfc00284b76039bdba6f0 Mon Sep 17 00:00:00 2001 From: vsilent Date: Mon, 4 Dec 2023 10:40:11 +0200 Subject: [PATCH 033/284] ports deserialize fix, small optimizations --- src/forms/stack.rs | 18 +- src/helpers/stack/builder.rs | 264 ++++++++++++++--------------- tests/custom-stack-payload-11.json | 1 + 3 files changed, 140 insertions(+), 143 deletions(-) create mode 100644 tests/custom-stack-payload-11.json diff --git a/src/forms/stack.rs b/src/forms/stack.rs index 91b34cb..1887931 100644 --- a/src/forms/stack.rs +++ b/src/forms/stack.rs @@ -34,14 +34,14 @@ pub struct Port { pub container_port: Option } -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Ports { - #[serde(rename(deserialize = "sharedPorts"))] - #[serde(rename(serialize = "shared_ports"))] - // #[serde(alias = "shared_ports")] - pub shared_ports: Option>, - pub ports: Option>, -} +// #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +// pub struct Ports { +// #[serde(rename(deserialize = "sharedPorts"))] +// #[serde(rename(serialize = "shared_ports"))] +// // #[serde(alias = "shared_ports")] +// pub shared_ports: Option>, +// pub ports: Option>, +// } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct DockerImage { @@ -258,7 +258,7 @@ pub struct App { // pub ports: Ports, #[serde(rename(deserialize = "sharedPorts"))] #[serde(rename(serialize = "shared_ports"))] - // #[serde(alias = "shared_ports")] + #[serde(alias = "shared_ports")] pub ports: Option>, } diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 316a03f..0026257 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -37,18 +37,25 @@ pub struct DcBuilder { pub(crate) stack: Stack } -// impl TryInto> for stack::Ports { -// type Error = String; -// fn try_into(self) -> Result, Self::Error> { -// convert_shared_ports(self.shared_ports.clone()) -// } -// } - -impl TryInto> for stack::Ports { +impl TryInto for &stack::Port { type Error = String; - fn try_into(self) -> Result, Self::Error> { - convert_shared_ports(self.shared_ports.clone()) + fn try_into(self) -> Result { + let cp = self.container_port.clone() + .unwrap_or("".to_string()) + .parse::().map_err(|err| "Could not parse port".to_string() )?; + let hp = self.host_port.clone() + .unwrap_or("".to_string()) + .parse::().map_err(|err| "Could not parse port".to_string() )?; + + tracing::debug!("Port conversion result: cp: {:?} hp: {:?}", cp, hp); + Ok(Port { + target: cp, + host_ip: None, + published: Some(PublishedPort::Single(hp)), + protocol: None, + mode: None, + }) } } @@ -60,23 +67,6 @@ fn convert_shared_ports(ports: Option>) -> Result, St Some(ports) => { tracing::debug!("Ports >>>> {:?}", ports); for port in ports { - let cp = port.container_port - .unwrap_or("".to_string()) - .parse::().map_err(|err| "Could not parse port".to_string() )?; - let hp = port.host_port - .unwrap_or("".to_string()) - .parse::().map_err(|err| "Could not parse port".to_string() )?; - - tracing::debug!("Port conversion result: cp: {:?} hp: {:?}", cp, hp); - _ports.push( - Port { - target: cp, - host_ip: None, - published: Some(PublishedPort::Single(hp)), - protocol: None, - mode: None, - } - ); } } None => { @@ -100,112 +90,118 @@ impl DcBuilder { pub fn build(&self) -> Option { - // - // tracing::debug!("Start build docker compose from {:?}", &self.stack.body); - // let _stack = serde_json::from_value::(self.stack.body.clone()); - // let mut services = indexmap::IndexMap::new(); - // match _stack { - // Ok(apps) => { - // // tracing::debug!("stack item {:?}", apps.custom.web); - // - // for app_type in apps.custom.web { - // let code = app_type.app.code.clone().to_owned(); - // let mut service = Service { - // image: Some(app_type.app.docker_image.to_string()), - // ..Default::default() - // }; - // - // service.ports = Ports::Long(app_type.app.ports.unwrap().try_into().unwrap()); - // service.restart = Some("always".to_owned()); - // tracing::debug!("service 1 {:?}", &service); - // services.insert( - // code, - // Some(service), - // ); - // } - // - // - // if let Some(srvs) = apps.custom.service { - // - // if !srvs.is_empty() { - // - // for app_type in srvs { - // let code = app_type.app.code.to_owned(); - // let mut service = Service { - // image: Some(app_type.app.docker_image.to_string()), - // ..Default::default() - // }; - // - // // if let Some(ports) = &app_type.app._ports { - // // tracing::debug!("service2 ports {:?}", ports); - // // service.ports = Ports::Long(ports.try_into().unwrap()) - // // } - // - // service.ports = Ports::Long(app_type.app.ports.unwrap().try_into().unwrap()); - // service.restart = Some("always".to_owned()); - // services.insert( - // code, - // Some(service), - // ); - // } - // // tracing::debug!("services {:?}", services); - // } - // } - // - // if let Some(features) = apps.custom.feature { - // - // if !features.is_empty() { - // - // for app_type in features { - // let code = app_type.app.code.to_owned(); - // let mut service = Service { - // // image: Some(app.dockerhub_image.as_ref().unwrap().to_owned()), - // image: Some(app_type.app.docker_image.to_string()), - // ..Default::default() - // }; - // - // service.ports = Ports::Long(app_type.app.ports.unwrap().try_into().unwrap()); - // // if let Some(ports) = &app_type.app._ports { - // // tracing::debug!("service3 ports {:?}", ports); - // // service.ports = Ports::Long(ports.try_into().unwrap()) - // // } - // service.restart = Some("always".to_owned()); - // services.insert( - // code, - // Some(service), - // ); - // } - // // tracing::debug!("services### {:?}", &service); - // } - // } - // tracing::debug!("services {:?}", &services); - // } - // Err(e) => { - // tracing::debug!("Unpack stack form error {:?}", e); - // () - // } - // } - // - // let compose_content = Compose { - // version: Some("3.8".to_string()), - // services: { - // Services(services) - // }, - // ..Default::default() - // }; - // - // let fname= format!("./files/{}.yml", self.stack.stack_id); - // tracing::debug!("Saving docker compose to file {:?}", fname); - // let target_file = std::path::Path::new(fname.as_str()); - // // serialize to string - // let serialized = match serde_yaml::to_string(&compose_content) { - // Ok(s) => s, - // Err(e) => panic!("Failed to serialize docker-compose file: {}", e), - // }; - // // serialize to file - // std::fs::write(target_file, serialized.clone()).unwrap(); - // - // Some(serialized) - None + + tracing::debug!("Start build docker compose from {:?}", &self.stack.body); + let _stack = serde_json::from_value::(self.stack.body.clone()); + let mut services = indexmap::IndexMap::new(); + match _stack { + Ok(apps) => { + // tracing::debug!("stack item {:?}", apps.custom.web); + + for app_type in apps.custom.web { + let code = app_type.app.code.clone().to_owned(); + let mut service = Service { + image: Some(app_type.app.docker_image.to_string()), + ..Default::default() + }; + + let ports: Vec = app_type.app.ports + .unwrap() + .iter() + .map(|x| x.try_into().unwrap()) + .collect(); + service.ports = Ports::Long(ports); + service.restart = Some("always".to_owned()); + tracing::debug!("service 1 {:?}", &service); + services.insert( + code, + Some(service), + ); + } + + + if let Some(srvs) = apps.custom.service { + + if !srvs.is_empty() { + + for app_type in srvs { + let code = app_type.app.code.to_owned(); + let mut service = Service { + image: Some(app_type.app.docker_image.to_string()), + ..Default::default() + }; + + let ports: Vec = app_type.app.ports + .unwrap() + .iter() + .map(|x| x.try_into().unwrap()) + .collect(); + + service.ports = Ports::Long(ports); + service.restart = Some("always".to_owned()); + services.insert( + code, + Some(service), + ); + } + // tracing::debug!("services {:?}", services); + } + } + + if let Some(features) = apps.custom.feature { + + if !features.is_empty() { + + for app_type in features { + let code = app_type.app.code.to_owned(); + let mut service = Service { + // image: Some(app.dockerhub_image.as_ref().unwrap().to_owned()), + image: Some(app_type.app.docker_image.to_string()), + ..Default::default() + }; + + let ports: Vec = app_type.app.ports + .unwrap() + .iter() + .map(|x| x.try_into().unwrap()) + .collect(); + service.ports = Ports::Long(ports); + service.restart = Some("always".to_owned()); + services.insert( + code, + Some(service), + ); + } + // tracing::debug!("services### {:?}", &service); + } + } + tracing::debug!("services {:?}", &services); + } + Err(e) => { + tracing::debug!("Unpack stack form error {:?}", e); + () + } + } + + let compose_content = Compose { + version: Some("3.8".to_string()), + services: { + Services(services) + }, + ..Default::default() + }; + + let fname= format!("./files/{}.yml", self.stack.stack_id); + tracing::debug!("Saving docker compose to file {:?}", fname); + let target_file = std::path::Path::new(fname.as_str()); + // serialize to string + let serialized = match serde_yaml::to_string(&compose_content) { + Ok(s) => s, + Err(e) => panic!("Failed to serialize docker-compose file: {}", e), + }; + // serialize to file + std::fs::write(target_file, serialized.clone()).unwrap(); + + Some(serialized) } } diff --git a/tests/custom-stack-payload-11.json b/tests/custom-stack-payload-11.json new file mode 100644 index 0000000..ee27be4 --- /dev/null +++ b/tests/custom-stack-payload-11.json @@ -0,0 +1 @@ +{"commonDomain":"","domainList":{},"region":"fsn1","zone":null,"server":"cx21","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":["portainer_ce_feature"],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":true,"disk_type":"pd-standart","cloud_token":"****","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"web":[{"_etag":null,"_id":180,"_created":"2021-12-17T08:11:40.875486","_updated":"2023-11-21T17:37:24.594545","name":"Airflow","code":"airflow","role":["airflow"],"type":"web","default":true,"popularity":null,"descr":null,"ports":{"private":["31"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":150,"height":150,"image":"7f41d873-2de5-4c6e-a037-42eeff572db6.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":"

Airflow description

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"airflow","form":null,"category":[null],"group":[],"versions":[{"_id":425,"name":"Airflow","version":"2.7.3","update_status":"published","tag":"latest"},{"_id":426,"name":"Airflow","version":"2.7.1-unstable","update_status":"published","tag":"stable"}],"links":[],"domain":"latestports.com","sharedPorts":[{"host_port":"5000","container_port":"5000"}],"main":true,"version":{"_id":426,"name":"Airflow","version":"2.7.1-unstable","update_status":"published","tag":"stable"},"environment":[{"ENV_VAR1":"ENV_VAR1_VALUE"}],"network":"testnetwork","restart":"always","volumes":[{"host_path":"/airflow/host/path/","container_path":"/airflow/container/path"}]},{"category":[{"name":"integrated_features"}],"name":"CustomNginx","code":"customnginx","domain":"customnginx.latestports.com","sharedPorts":[{"host_port":"80","container_port":"8080"},{"host_port":"443","container_port":"8443"}],"versions":[],"custom":true,"type":"web","main":false,"_id":0,"dockerhub_user":"trydirect","dockerhub_name":"nginx","disk_size":"0.9Gb","ram_size":"1.3Gb","cpu":"0.3","volumes":[{"host_path":"asdfasdf","container_path":"asdfasdf"}],"environment":[{"CUSTOM_NGINX_ENV_VAR1":"CUSTOM_NGINX_ENV_VAR1_VALUE"},{"/customnginx/host/path":"/customnginx/container/path"}],"network":"testnetwork","restart":"always"}],"feature":[{"_etag":null,"_id":198,"_created":"2022-04-27T14:10:27.280327","_updated":"2023-08-03T08:24:18.958721","name":"Portainer CE Feature","code":"portainer_ce_feature","role":["portainer-ce-feature"],"type":"feature","default":null,"popularity":null,"descr":null,"ports":{"public":["9000","8000"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":1138,"height":1138,"image":"08589075-44e6-430e-98a5-f9dcf711e054.svg"},"dark":{}},"category_id":2,"parent_app_id":null,"full_description":null,"description":"

Portainer is a lightweight management UI which allows you to easily manage your different Docker environments (Docker hosts or Swarm clusters)

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.6","ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"portainer-ce-feature","form":null,"category":[{"name":"integrated_features"}],"group":[],"versions":[{"_id":456,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"}],"links":[],"version":{"_id":456,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"},"sharedPorts":[{"host_port":"9000","container_port":"9000"}],"environment":[{"PORTAINER_ENV_VAR1":"PORTAINER_ENV_VAR1_VALUE"}],"volumes":[{"host_path":"/portainer/test/path","container_path":"/portainer/test/path"}],"network":"testnetwork","restart":"always"}],"service":[{"_etag":null,"_id":24,"_created":"2020-06-19T13:07:24.228389","_updated":"2023-11-23T10:18:28.095813","name":"PostgreSQL","code":"postgres","role":["postgres"],"type":"service","default":null,"popularity":null,"descr":null,"ports":{"private":["5432"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":576,"height":594,"image":"fd23f54c-e250-4228-8d56-7e5d93ffb925.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":null,"plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"postgres","form":null,"category":[null],"group":[{"_etag":null,"_id":12,"_created":null,"_updated":null,"name":"Database","code":"database"}],"versions":[{"_id":458,"name":"15","version":"15","update_status":"published","tag":"15"},{"_id":288,"name":"10.22","version":"10.22","update_status":"published","tag":"10.22"},{"_id":303,"name":"13.8","version":"13.8","update_status":"published","tag":"13.8"},{"_id":266,"name":"11","version":"11","update_status":"published","tag":"11"},{"_id":267,"name":"12.12","version":"12.12","update_status":"published","tag":"12.12"},{"_id":38,"name":"14.5","version":"14.5","update_status":"published","tag":"14.5"},{"_id":596,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"}],"links":[],"domain":"","sharedPorts":[{"host_port":"5432","container_port":"5432"}],"main":false,"version":{"_id":596,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"},"environment":[{"POSTGRES_ENV_VAR1":"POSTGRES_ENV_VAR1_VALUE"},{"POSTGRES_ENV_VAR2":"POSTGRES_ENV_VAR2_VALUE"}],"network":"testnetwork","restart":"always","volumes":[{"host_path":"./pg.conf","container_path":"/etc/postgres/pg.conf"}]}],"servers_count":3,"project_name":"LatestPorts","custom_stack_code":"latestports","project_git_url":"https://github.com/latestports","custom_stack_category":[],"networks":["testnetwork","testnetwork2"]}} \ No newline at end of file From be7917146170296c3923e9f0cd6a82be0d14b493 Mon Sep 17 00:00:00 2001 From: vsilent Date: Mon, 4 Dec 2023 16:53:59 +0200 Subject: [PATCH 034/284] stack crud, update impl. --- .gitignore | 2 +- src/forms/stack.rs | 4 +- src/helpers/json.rs | 3 +- src/routes/stack/add.rs | 10 ++- src/routes/stack/compose.rs | 2 +- src/routes/stack/update.rs | 117 ++++++++++++++++++++++++++++- src/startup.rs | 3 +- tests/custom-stack-payload-11.json | 2 +- 8 files changed, 130 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index 3acd8af..32da6d8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ target -.idea +.idea/ files diff --git a/src/forms/stack.rs b/src/forms/stack.rs index 1887931..544dc3d 100644 --- a/src/forms/stack.rs +++ b/src/forms/stack.rs @@ -79,8 +79,8 @@ impl AsRef for App { #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct StackForm { - #[validate(min_length=2)] - #[validate(max_length=255)] + // #[validate(min_length=2)] + // #[validate(max_length=255)] #[serde(rename= "commonDomain")] pub common_domain: Option, pub domain_list: Option, diff --git a/src/helpers/json.rs b/src/helpers/json.rs index 6a08405..a310ab3 100644 --- a/src/helpers/json.rs +++ b/src/helpers/json.rs @@ -9,7 +9,8 @@ pub(crate) struct JsonResponse { pub(crate) message: String, pub(crate) id: Option, pub(crate) item: Option, - pub(crate) list: Option> + pub(crate) list: Option>, + // pub(crate) form: Option } #[derive(Serialize, Default)] diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index 7c45ef5..b793925 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -25,6 +25,7 @@ pub async fn add( pool: Data, ) -> Result { + // @todo ACL let body_bytes = actix_web::body::to_bytes(body).await.unwrap(); let body_str = str::from_utf8(&body_bytes).unwrap(); let form = match serde_json::from_str::(body_str) { @@ -82,9 +83,12 @@ pub async fn add( let query_span = tracing::info_span!("Saving new stack details into the database"); - let errors = form.validate().unwrap_err(); - tracing::debug!("{:?}",errors); - + if !form.validate().is_ok() { + let errors = form.validate().unwrap_err(); + let err_msg = format!("Invalid data received {:?}", &errors.to_string()); + tracing::debug!(err_msg); + return JsonResponse::build().err(errors.to_string());// tmp solution + } let body: Value = match serde_json::to_value::(form) { Ok(body) => body, diff --git a/src/routes/stack/compose.rs b/src/routes/stack/compose.rs index 58f82f7..4dc3c7f 100644 --- a/src/routes/stack/compose.rs +++ b/src/routes/stack/compose.rs @@ -15,7 +15,7 @@ use tracing::Instrument; use crate::helpers::stack::builder::DcBuilder; #[tracing::instrument(name = "User's generate docker-compose.")] -#[post("/{id}")] +#[get("/{id}")] pub async fn add( user: web::ReqData, path: web::Path<(i32,)>, diff --git a/src/routes/stack/update.rs b/src/routes/stack/update.rs index 5a4fa0c..56514eb 100644 --- a/src/routes/stack/update.rs +++ b/src/routes/stack/update.rs @@ -1,4 +1,115 @@ -use actix_web::HttpResponse; -pub async fn update() -> HttpResponse { - unimplemented!() +use chrono::Utc; +use actix_web::{ + web, + web::{Data}, + Responder, Result, +}; +use crate::forms::stack::StackForm; +use crate::helpers::JsonResponse; +use crate::models::user::User; +use actix_web::post; +use serde_json::Value; +use sqlx::PgPool; +use serde_valid::Validate; +use tracing::Instrument; +use uuid::Uuid; +use crate::models; + + +#[tracing::instrument(name = "Update stack.")] +#[post("/{id}")] +pub async fn update( + path: web::Path<(i32,)>, + form: web::Json, + user: web::ReqData, + pool: Data, +) -> Result { + // @todo ACL + + let (id,) = path.into_inner(); + let query_span = tracing::info_span!("Check existence by id."); + match sqlx::query_as!( + models::Stack, + r"SELECT * FROM user_stack WHERE id = $1", + id + ) + .fetch_one(pool.get_ref()) + .instrument(query_span) + .await + { + Ok(stack) => { + tracing::info!("Found record: {:?}", stack.id); + } + Err(e) => { + tracing::error!("Failed to fetch record: {:?}, error: {:?}", id, e); + return JsonResponse::::build() + .err(format!("Object not found {}", id)); + } + }; + + let stack_name = form.custom.custom_stack_code.clone(); + tracing::debug!("form data: {:?}", form); + let user_id = user.id.clone(); + let request_id = Uuid::new_v4(); + let request_span = tracing::info_span!( + "Validating a stack", %request_id, + commonDomain=?&form.custom.project_name, + region=?&form.region, + domainList=?&form.domain_list + ); + let _request_span_guard = request_span.enter(); // ->exit + + tracing::info!("request_id {} Updating '{}' '{}'", + request_id, + form.custom.project_name, + form.region + ); + + let query_span = tracing::info_span!("Update stack details in db."); + + if !form.validate().is_ok() { + let errors = form.validate().unwrap_err(); + let err_msg = format!("Invalid data received {:?}", &errors.to_string()); + tracing::debug!(err_msg); + return JsonResponse::build().err(errors.to_string()); + } + + let body: Value = match serde_json::to_value::(form.into_inner()) { + Ok(body) => body, + Err(err) => { + tracing::error!("Request_id {} error unwrap body {:?}", request_id, err); + serde_json::to_value::(StackForm::default()).unwrap() + } + }; + + match sqlx::query!( + r#" + UPDATE user_stack + SET stack_id=$2, user_id=$3, name=$4, body=$5, created_at=$6, updated_at=$7 + WHERE id=$1 + "#, + id, + Uuid::new_v4(), + user_id, + stack_name, + body, + Utc::now(), + Utc::now(), + ) + .execute(pool.get_ref()) + .instrument(query_span) + .await + { + Ok(record) => { + tracing::info!( + "req_id: {} stack details have been saved to database", + request_id + ); + return JsonResponse::build().set_id(id).ok("OK".to_owned()); + } + Err(e) => { + tracing::error!("req_id: {} Failed to execute query: {:?}", request_id, e); + return JsonResponse::build().err("Internal Server Error".to_owned()); + } + }; } diff --git a/src/startup.rs b/src/startup.rs index 3d38420..816255f 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -67,7 +67,8 @@ pub async fn run( .service(crate::routes::stack::compose::admin) .service(crate::routes::stack::get::item) .service(crate::routes::stack::get::list) - .service(crate::routes::stack::add::add), + .service(crate::routes::stack::add::add) + .service(crate::routes::stack::update::update), ) .app_data(db_pool.clone()) .app_data(settings.clone()) diff --git a/tests/custom-stack-payload-11.json b/tests/custom-stack-payload-11.json index ee27be4..d87ce41 100644 --- a/tests/custom-stack-payload-11.json +++ b/tests/custom-stack-payload-11.json @@ -1 +1 @@ -{"commonDomain":"","domainList":{},"region":"fsn1","zone":null,"server":"cx21","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":["portainer_ce_feature"],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":true,"disk_type":"pd-standart","cloud_token":"****","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"web":[{"_etag":null,"_id":180,"_created":"2021-12-17T08:11:40.875486","_updated":"2023-11-21T17:37:24.594545","name":"Airflow","code":"airflow","role":["airflow"],"type":"web","default":true,"popularity":null,"descr":null,"ports":{"private":["31"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":150,"height":150,"image":"7f41d873-2de5-4c6e-a037-42eeff572db6.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":"

Airflow description

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"airflow","form":null,"category":[null],"group":[],"versions":[{"_id":425,"name":"Airflow","version":"2.7.3","update_status":"published","tag":"latest"},{"_id":426,"name":"Airflow","version":"2.7.1-unstable","update_status":"published","tag":"stable"}],"links":[],"domain":"latestports.com","sharedPorts":[{"host_port":"5000","container_port":"5000"}],"main":true,"version":{"_id":426,"name":"Airflow","version":"2.7.1-unstable","update_status":"published","tag":"stable"},"environment":[{"ENV_VAR1":"ENV_VAR1_VALUE"}],"network":"testnetwork","restart":"always","volumes":[{"host_path":"/airflow/host/path/","container_path":"/airflow/container/path"}]},{"category":[{"name":"integrated_features"}],"name":"CustomNginx","code":"customnginx","domain":"customnginx.latestports.com","sharedPorts":[{"host_port":"80","container_port":"8080"},{"host_port":"443","container_port":"8443"}],"versions":[],"custom":true,"type":"web","main":false,"_id":0,"dockerhub_user":"trydirect","dockerhub_name":"nginx","disk_size":"0.9Gb","ram_size":"1.3Gb","cpu":"0.3","volumes":[{"host_path":"asdfasdf","container_path":"asdfasdf"}],"environment":[{"CUSTOM_NGINX_ENV_VAR1":"CUSTOM_NGINX_ENV_VAR1_VALUE"},{"/customnginx/host/path":"/customnginx/container/path"}],"network":"testnetwork","restart":"always"}],"feature":[{"_etag":null,"_id":198,"_created":"2022-04-27T14:10:27.280327","_updated":"2023-08-03T08:24:18.958721","name":"Portainer CE Feature","code":"portainer_ce_feature","role":["portainer-ce-feature"],"type":"feature","default":null,"popularity":null,"descr":null,"ports":{"public":["9000","8000"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":1138,"height":1138,"image":"08589075-44e6-430e-98a5-f9dcf711e054.svg"},"dark":{}},"category_id":2,"parent_app_id":null,"full_description":null,"description":"

Portainer is a lightweight management UI which allows you to easily manage your different Docker environments (Docker hosts or Swarm clusters)

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.6","ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"portainer-ce-feature","form":null,"category":[{"name":"integrated_features"}],"group":[],"versions":[{"_id":456,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"}],"links":[],"version":{"_id":456,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"},"sharedPorts":[{"host_port":"9000","container_port":"9000"}],"environment":[{"PORTAINER_ENV_VAR1":"PORTAINER_ENV_VAR1_VALUE"}],"volumes":[{"host_path":"/portainer/test/path","container_path":"/portainer/test/path"}],"network":"testnetwork","restart":"always"}],"service":[{"_etag":null,"_id":24,"_created":"2020-06-19T13:07:24.228389","_updated":"2023-11-23T10:18:28.095813","name":"PostgreSQL","code":"postgres","role":["postgres"],"type":"service","default":null,"popularity":null,"descr":null,"ports":{"private":["5432"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":576,"height":594,"image":"fd23f54c-e250-4228-8d56-7e5d93ffb925.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":null,"plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"postgres","form":null,"category":[null],"group":[{"_etag":null,"_id":12,"_created":null,"_updated":null,"name":"Database","code":"database"}],"versions":[{"_id":458,"name":"15","version":"15","update_status":"published","tag":"15"},{"_id":288,"name":"10.22","version":"10.22","update_status":"published","tag":"10.22"},{"_id":303,"name":"13.8","version":"13.8","update_status":"published","tag":"13.8"},{"_id":266,"name":"11","version":"11","update_status":"published","tag":"11"},{"_id":267,"name":"12.12","version":"12.12","update_status":"published","tag":"12.12"},{"_id":38,"name":"14.5","version":"14.5","update_status":"published","tag":"14.5"},{"_id":596,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"}],"links":[],"domain":"","sharedPorts":[{"host_port":"5432","container_port":"5432"}],"main":false,"version":{"_id":596,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"},"environment":[{"POSTGRES_ENV_VAR1":"POSTGRES_ENV_VAR1_VALUE"},{"POSTGRES_ENV_VAR2":"POSTGRES_ENV_VAR2_VALUE"}],"network":"testnetwork","restart":"always","volumes":[{"host_path":"./pg.conf","container_path":"/etc/postgres/pg.conf"}]}],"servers_count":3,"project_name":"LatestPorts","custom_stack_code":"latestports","project_git_url":"https://github.com/latestports","custom_stack_category":[],"networks":["testnetwork","testnetwork2"]}} \ No newline at end of file +{"commonDomain":"justates222t.com","domainList":{},"region":"fsn1","zone":null,"server":"cx21","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":["portainer_ce_feature"],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":true,"disk_type":"pd-standart","cloud_token":"**********","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"web":[{"_etag":null,"_id":180,"_created":"2021-12-17T08:11:40.875486","_updated":"2023-11-21T17:37:24.594545","name":"Airflow","code":"airflow","role":["airflow"],"type":"web","default":true,"popularity":null,"descr":null,"ports":{"private":["31"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":150,"height":150,"image":"7f41d873-2de5-4c6e-a037-42eeff572db6.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":"

Airflow description

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"airflow","form":null,"category":[null],"group":[],"versions":[{"_id":425,"name":"Airflow","version":"2.7.3","update_status":"published","tag":"latest"},{"_id":426,"name":"Airflow","version":"2.7.1-unstable","update_status":"published","tag":"stable"}],"links":[],"domain":"latestports.com","sharedPorts":[{"host_port":"5000","container_port":"5000"}],"main":true,"version":{"_id":426,"name":"Airflow","version":"2.7.1-unstable","update_status":"published","tag":"stable"},"environment":[{"ENV_VAR1":"ENV_VAR1_VALUE"}],"network":"testnetwork","restart":"always","volumes":[{"host_path":"/airflow/host/path/","container_path":"/airflow/container/path"}]},{"category":[{"name":"integrated_features"}],"name":"CustomNginx","code":"customnginx","domain":"customnginx.latestports.com","sharedPorts":[{"host_port":"80","container_port":"8080"},{"host_port":"443","container_port":"8443"}],"versions":[],"custom":true,"type":"web","main":false,"_id":0,"dockerhub_user":"trydirect","dockerhub_name":"nginx","disk_size":"0.9Gb","ram_size":"1.3Gb","cpu":"0.3","volumes":[{"host_path":"asdfasdf","container_path":"asdfasdf"}],"environment":[{"CUSTOM_NGINX_ENV_VAR1":"CUSTOM_NGINX_ENV_VAR1_VALUE"},{"/customnginx/host/path":"/customnginx/container/path"}],"network":"testnetwork","restart":"always"}],"feature":[{"_etag":null,"_id":198,"_created":"2022-04-27T14:10:27.280327","_updated":"2023-08-03T08:24:18.958721","name":"Portainer CE Feature","code":"portainer_ce_feature","role":["portainer-ce-feature"],"type":"feature","default":null,"popularity":null,"descr":null,"ports":{"public":["9000","8000"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":1138,"height":1138,"image":"08589075-44e6-430e-98a5-f9dcf711e054.svg"},"dark":{}},"category_id":2,"parent_app_id":null,"full_description":null,"description":"

Portainer is a lightweight management UI which allows you to easily manage your different Docker environments (Docker hosts or Swarm clusters)

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.6","ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"portainer-ce-feature","form":null,"category":[{"name":"integrated_features"}],"group":[],"versions":[{"_id":456,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"}],"links":[],"version":{"_id":456,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"},"sharedPorts":[{"host_port":"9000","container_port":"9000"}],"environment":[{"PORTAINER_ENV_VAR1":"PORTAINER_ENV_VAR1_VALUE"}],"volumes":[{"host_path":"/portainer/test/path","container_path":"/portainer/test/path"}],"network":"testnetwork","restart":"always"}],"service":[{"_etag":null,"_id":24,"_created":"2020-06-19T13:07:24.228389","_updated":"2023-11-23T10:18:28.095813","name":"PostgreSQL","code":"postgres","role":["postgres"],"type":"service","default":null,"popularity":null,"descr":null,"ports":{"private":["5432"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":576,"height":594,"image":"fd23f54c-e250-4228-8d56-7e5d93ffb925.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":null,"plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"postgres","form":null,"category":[null],"group":[{"_etag":null,"_id":12,"_created":null,"_updated":null,"name":"Database","code":"database"}],"versions":[{"_id":458,"name":"15","version":"15","update_status":"published","tag":"15"},{"_id":288,"name":"10.22","version":"10.22","update_status":"published","tag":"10.22"},{"_id":303,"name":"13.8","version":"13.8","update_status":"published","tag":"13.8"},{"_id":266,"name":"11","version":"11","update_status":"published","tag":"11"},{"_id":267,"name":"12.12","version":"12.12","update_status":"published","tag":"12.12"},{"_id":38,"name":"14.5","version":"14.5","update_status":"published","tag":"14.5"},{"_id":596,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"}],"links":[],"domain":"","sharedPorts":[{"host_port":"5432","container_port":"5432"}],"main":false,"version":{"_id":596,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"},"environment":[{"POSTGRES_ENV_VAR1":"POSTGRES_ENV_VAR1_VALUE"},{"POSTGRES_ENV_VAR2":"POSTGRES_ENV_VAR2_VALUE"}],"network":"testnetwork","restart":"always","volumes":[{"host_path":"./pg.conf","container_path":"/etc/postgres/pg.conf"}]}],"servers_count":3,"project_name":"LatestPorts","custom_stack_code":"latestports","project_git_url":"https://github.com/latestports","custom_stack_category":[],"networks":["testnetwork","testnetwork2"]}} \ No newline at end of file From d71533b4c4f84aa71825ceda7148d8fec3c539a5 Mon Sep 17 00:00:00 2001 From: petru Date: Mon, 4 Dec 2023 17:03:12 +0200 Subject: [PATCH 035/284] issue-auth test/deploy JsonResponse --- src/routes/test/deploy.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/routes/test/deploy.rs b/src/routes/test/deploy.rs index 7a8eddf..51cc201 100644 --- a/src/routes/test/deploy.rs +++ b/src/routes/test/deploy.rs @@ -2,6 +2,7 @@ use crate::models::Client; use actix_web::{post, web, Responder, Result}; use serde::Serialize; use std::sync::Arc; +use crate::helpers::JsonResponse; #[derive(Serialize)] struct DeployResponse { @@ -12,8 +13,5 @@ struct DeployResponse { #[tracing::instrument(name = "Test deploy.")] #[post("/deploy")] pub async fn handler(client: web::ReqData>) -> Result { - Ok(web::Json(DeployResponse { - status: "success".to_string(), - client: client.into_inner(), - })) + JsonResponse::build().set_item(client.into_inner()).ok("success") } From a0d72391c24bd8c9d36d8534e475c95b330a7977 Mon Sep 17 00:00:00 2001 From: petru Date: Mon, 4 Dec 2023 17:42:13 +0200 Subject: [PATCH 036/284] issue-auth optimising middleware client --- src/middleware/trydirect.rs | 99 ++++++++++++++++++++----------------- tests/middleware_client.rs | 4 ++ 2 files changed, 59 insertions(+), 44 deletions(-) diff --git a/src/middleware/trydirect.rs b/src/middleware/trydirect.rs index 755baba..cf5079b 100644 --- a/src/middleware/trydirect.rs +++ b/src/middleware/trydirect.rs @@ -1,4 +1,5 @@ use crate::configuration::Settings; +use futures::future::{FutureExt}; use crate::forms::user::UserForm; use actix_web::dev::ServiceRequest; use actix_web::error::{ErrorInternalServerError, ErrorUnauthorized}; @@ -7,59 +8,69 @@ use actix_web::Error; use actix_web::HttpMessage; use actix_web_httpauth::extractors::bearer::BearerAuth; use reqwest::header::{ACCEPT, CONTENT_TYPE}; +use crate::helpers::JsonResponse; -use crate::models::user::User; +use crate::models::user::User; //todo #[tracing::instrument(name = "Trydirect bearer guard.")] pub async fn bearer_guard( req: ServiceRequest, credentials: BearerAuth, -) -> Result { - let settings = req.app_data::>().unwrap(); - let client = reqwest::Client::new(); - let resp = client - .get(&settings.auth_url) - .bearer_auth(credentials.token()) - .header(CONTENT_TYPE, "application/json") - .header(ACCEPT, "application/json") - .send() - .await; + ) -> Result { + async { + let settings = req.app_data::>().unwrap(); + let client = reqwest::Client::new(); + let resp = client + .get(&settings.auth_url) + .bearer_auth(credentials.token()) + .header(CONTENT_TYPE, "application/json") + .header(ACCEPT, "application/json") + .send() + .await; - let resp = match resp { - Ok(resp) if resp.status().is_success() => resp, - Ok(resp) => { - tracing::error!("Authentication service returned no success {:?}", resp); - return Err((ErrorUnauthorized("401 Unauthorized"), req)); - } - Err(err) => { - tracing::error!("error from reqwest {:?}", err); - return Err((ErrorInternalServerError(err.to_string()), req)); - } - }; + let resp = match resp { + Ok(resp) if resp.status().is_success() => resp, + Ok(resp) => { + tracing::error!("Authentication service returned no success {:?}", resp); + return Err(("401 Unauthorized".to_string(), req)); + } + Err(err) => { + tracing::error!("error from reqwest {:?}", err); + return Err((err.to_string(), req)); + } + }; - let user_form: UserForm = match resp.json().await { - Ok(user) => { - tracing::info!("unpacked user {user:?}"); - user - } - Err(err) => { - tracing::error!("can't parse the response body {:?}", err); - return Err((ErrorUnauthorized(""), req)); - } - }; + let user_form: UserForm = match resp.json().await { + Ok(user) => { + tracing::info!("unpacked user {user:?}"); + user + } + Err(err) => { + tracing::error!("can't parse the response body {:?}", err); + return Err(("can't parse the response body".to_string(), req)); + } + }; - let user: User = match user_form.try_into() { - Ok(user) => user, - Err(err) => { - tracing::error!("Could not create User from form data: {:?}", err); - return Err((ErrorUnauthorized("Unauthorized"), req)); + let user: User = match user_form.try_into() { + Ok(user) => user, + Err(err) => { + tracing::error!("Could not create User from form data: {:?}", err); + return Err(("Could not create User from form data".to_string(), req)); + } + }; + let existent_user = req.extensions_mut().insert(user); + if existent_user.is_some() { + tracing::error!("already logged {existent_user:?}"); + return Err(("user already logged".to_string(), req)); } - }; - let existent_user = req.extensions_mut().insert(user); - if existent_user.is_some() { - tracing::error!("already logged {existent_user:?}"); - return Err((ErrorInternalServerError(""), req)); - } - Ok(req) + Ok(req) + }.await + .map_err(|(err, req)| { + tracing::error!("Authentication service returned no success {:?}", err); + (ErrorUnauthorized(JsonResponse::::build().set_msg(err).to_string()), req) //todo + //default + //type for + //JsonResponse + }) } diff --git a/tests/middleware_client.rs b/tests/middleware_client.rs index 31c5565..8f2a9f5 100644 --- a/tests/middleware_client.rs +++ b/tests/middleware_client.rs @@ -19,4 +19,8 @@ async fn middleware_client_works() { assert!(response.status().is_success()); assert_eq!(Some(0), response.content_length()); + + + //todo header stacker-id not found + // } From 4c76fc3de978b40aa0308dd3e0991ea5f0392778 Mon Sep 17 00:00:00 2001 From: vsilent Date: Mon, 4 Dec 2023 17:44:11 +0200 Subject: [PATCH 037/284] response shortened --- .idea/dataSources.xml | 12 ----- configuration.yaml | 17 ------- src/helpers/json.rs | 96 +++++++++++------------------------- src/routes/client/add.rs | 8 +-- src/routes/client/disable.rs | 2 +- src/routes/client/enable.rs | 2 +- src/routes/client/update.rs | 2 +- src/routes/rating/add.rs | 8 +-- src/routes/rating/get.rs | 10 ++-- src/routes/stack/add.rs | 10 ++-- src/routes/stack/compose.rs | 8 +-- src/routes/stack/deploy.rs | 4 +- src/routes/stack/get.rs | 8 +-- src/routes/stack/update.rs | 8 +-- tests/model_user_stack.rs | 4 +- 15 files changed, 67 insertions(+), 132 deletions(-) delete mode 100644 .idea/dataSources.xml delete mode 100644 configuration.yaml diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml deleted file mode 100644 index a9f6743..0000000 --- a/.idea/dataSources.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - postgresql - true - org.postgresql.Driver - jdbc:postgresql://localhost:5432/stacker - $ProjectFileDir$ - - - \ No newline at end of file diff --git a/configuration.yaml b/configuration.yaml deleted file mode 100644 index 030dd49..0000000 --- a/configuration.yaml +++ /dev/null @@ -1,17 +0,0 @@ -#auth_url: http://127.0.0.1:8080/me -app_host: 127.0.0.1 -app_port: 8000 -auth_url: https://dev.try.direct/server/user/oauth_server/api/me -max_clients_number: 2 -database: - host: 127.0.0.1 - port: 5432 - username: postgres - password: postgres - database_name: stacker - -amqp: - host: 127.0.0.1 - port: 5672 - username: guest - password: guest diff --git a/src/helpers/json.rs b/src/helpers/json.rs index a310ab3..8990788 100644 --- a/src/helpers/json.rs +++ b/src/helpers/json.rs @@ -1,16 +1,18 @@ -use actix_web::error::{ErrorBadRequest, ErrorConflict, ErrorNotFound, ErrorInternalServerError}; -use serde_derive::Serialize; +use actix_web::error::{ErrorBadRequest, ErrorConflict, ErrorInternalServerError, ErrorNotFound}; use actix_web::web::Json; use actix_web::Error; use actix_web::Result; +use serde_derive::Serialize; #[derive(Serialize)] pub(crate) struct JsonResponse { pub(crate) message: String, + #[serde(skip_serializing_if = "Option::is_none")] pub(crate) id: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub(crate) item: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub(crate) list: Option>, - // pub(crate) form: Option } #[derive(Serialize, Default)] @@ -18,6 +20,7 @@ pub struct JsonResponseBuilder where T: serde::Serialize + Default, { + message: String, id: Option, item: Option, list: Option>, @@ -27,6 +30,11 @@ impl JsonResponseBuilder where T: serde::Serialize + Default, { + pub(crate) fn set_msg>(mut self, msg: I) -> Self { + self.message = msg.into(); + self + } + pub(crate) fn set_item(mut self, item: T) -> Self { self.item = Some(item); self @@ -42,75 +50,44 @@ where self } - fn to_json_response(self, msg: String) -> JsonResponse { + fn to_json_response(self) -> JsonResponse { JsonResponse { - message: msg, + message: self.message, id: self.id, item: self.item, list: self.list, } } - pub(crate) fn ok>(self, msg: I) -> Result>, Error> { - Ok(Json(self.to_json_response(msg.into()))) + pub(crate) fn to_string(self) -> String { + let json_response = self.to_json_response(); + serde_json::to_string(&json_response).unwrap() } - pub(crate) fn err>(self, msg: I) -> Result>, Error> { - let json_response = self.to_json_response(msg.into()); - - Err(ErrorBadRequest( - serde_json::to_string(&json_response).unwrap(), - )) - } - - pub(crate) fn not_found(self, msg: String) -> Result>, Error> { - - let json_response = JsonResponse { - message: msg, - id: self.id, - item: self.item, - list: self.list - }; - - Err(ErrorNotFound( - serde_json::to_string(&json_response).unwrap())) + pub(crate) fn ok>(self, msg: I) -> Result>, Error> { + Ok(Json(self.set_msg(msg).to_json_response())) } - pub(crate) fn internal_error(self, msg: String) -> Result>, Error> { - - let json_response = JsonResponse { - message: msg, - id: self.id, - item: self.item, - list: self.list - }; - - Err(ErrorInternalServerError( - serde_json::to_string(&json_response).unwrap())) + pub(crate) fn bad_request>( + self, + msg: I, + ) -> Result>, Error> { + Err(ErrorBadRequest(self.set_msg(msg).to_string())) } - pub(crate) fn conflict(self, msg: String) -> Result>, Error> { - - let json_response = JsonResponse { - message: msg, - id: self.id, - item: self.item, - list: self.list - }; - - Err(ErrorConflict( - serde_json::to_string(&json_response).unwrap())) + pub(crate) fn not_found>(self, msg: I) -> Result>, Error> { + Err(ErrorNotFound(self.set_msg(msg).to_string())) } - pub(crate) fn err_internal_server_error>( + pub(crate) fn internal_server_error>( self, msg: I, ) -> Result>, Error> { - let json_response = self.to_json_response(msg.into()); + Err(ErrorInternalServerError(self.set_msg(msg).to_string())) + } - Err(ErrorInternalServerError( - serde_json::to_string(&json_response).unwrap(), - )) + pub(crate) fn conflict>(self, msg: I) -> Result>, Error> { + Err(ErrorConflict(self.set_msg(msg).to_string())) } } @@ -121,17 +98,4 @@ where pub fn build() -> JsonResponseBuilder { JsonResponseBuilder::default() } - - pub(crate) fn new(message: String, - id: Option, - item:Option, - list: Option>) -> Self { - tracing::debug!("Executed.."); - JsonResponse { - message, - id, - item, - list, - } - } } diff --git a/src/routes/client/add.rs b/src/routes/client/add.rs index eee2ce0..292fc31 100644 --- a/src/routes/client/add.rs +++ b/src/routes/client/add.rs @@ -41,12 +41,12 @@ pub async fn add_handler( client_count ); - return JsonResponse::build().err("Too many clients created".to_owned()); + return JsonResponse::build().bad_request("Too many clients created"); } } Err(e) => { tracing::error!("Failed to execute query: {:?}", e); - return JsonResponse::build().internal_error("Internal Server Error".to_owned()); + return JsonResponse::build().internal_server_error("Internal Server Error"); } }; @@ -79,12 +79,12 @@ pub async fn add_handler( return JsonResponse::build() .set_id(client.id) .set_item(Some(client)) - .ok("OK".to_owned()); + .ok("OK"); } Err(e) => { tracing::error!("Failed to execute query: {:?}", e); let err = format!("Failed to insert. {}", e); - return JsonResponse::build().err(err); + return JsonResponse::build().bad_request(err); } } } diff --git a/src/routes/client/disable.rs b/src/routes/client/disable.rs index 383130b..3ec7154 100644 --- a/src/routes/client/disable.rs +++ b/src/routes/client/disable.rs @@ -62,7 +62,7 @@ pub async fn disable_handler( } Err(e) => { tracing::error!("Failed to execute query: {:?}", e); - JsonResponse::build().err("") + JsonResponse::build().bad_request("") } } } diff --git a/src/routes/client/enable.rs b/src/routes/client/enable.rs index a870c65..c6c53c7 100644 --- a/src/routes/client/enable.rs +++ b/src/routes/client/enable.rs @@ -69,7 +69,7 @@ pub async fn enable_handler( } Err(e) => { tracing::error!("Failed to execute query: {:?}", e); - JsonResponse::build().err_internal_server_error("") + JsonResponse::build().internal_server_error("Internal error") } } } diff --git a/src/routes/client/update.rs b/src/routes/client/update.rs index f50b4ed..c833508 100644 --- a/src/routes/client/update.rs +++ b/src/routes/client/update.rs @@ -68,7 +68,7 @@ pub async fn update_handler( } Err(e) => { tracing::error!("Failed to execute query: {:?}", e); - JsonResponse::build().err_internal_server_error("") + JsonResponse::build().internal_server_error("") } } } diff --git a/src/routes/rating/add.rs b/src/routes/rating/add.rs index dd13eee..773fcee 100644 --- a/src/routes/rating/add.rs +++ b/src/routes/rating/add.rs @@ -40,7 +40,7 @@ pub async fn add_handler( Err(e) => { tracing::error!("Failed to fetch product: {:?}, error: {:?}", form.obj_id, e); return JsonResponse::::build() - .err(format!("Object not found {}", form.obj_id)); + .not_found(format!("Object not found {}", form.obj_id).as_str()); } }; @@ -63,12 +63,12 @@ pub async fn add_handler( form.obj_id, form.category ); - return JsonResponse::build().conflict("Already rated".to_owned()); + return JsonResponse::build().conflict("Already rated"); } Err(sqlx::Error::RowNotFound) => {} Err(e) => { tracing::error!("Failed to fetch rating, error: {:?}", e); - return JsonResponse::build().err(format!("Internal Server Error")); + return JsonResponse::build().bad_request("Internal Server Error"); } } @@ -102,7 +102,7 @@ pub async fn add_handler( } Err(e) => { tracing::error!("Failed to execute query: {:?}", e); - JsonResponse::build().internal_error("Failed to insert".to_owned()) + JsonResponse::build().internal_server_error("Failed to insert") } } } diff --git a/src/routes/rating/get.rs b/src/routes/rating/get.rs index 75281c0..fcde66c 100644 --- a/src/routes/rating/get.rs +++ b/src/routes/rating/get.rs @@ -32,11 +32,11 @@ pub async fn get_handler( return JsonResponse::build().set_item(Some(rating)).ok("OK"); } Err(sqlx::Error::RowNotFound) => { - return JsonResponse::build().err("Not Found"); + return JsonResponse::build().bad_request("Not Found"); } Err(e) => { tracing::error!("Failed to fetch rating, error: {:?}", e); - return JsonResponse::build().err("Internal Server Error"); + return JsonResponse::build().bad_request("Internal Server Error"); } } } @@ -58,14 +58,14 @@ pub async fn list_handler( { Ok(rating) => { tracing::info!("Ratings found: {:?}", rating.len()); - return JsonResponse::build().set_list(rating).ok("OK".to_owned()); + return JsonResponse::build().set_list(rating).ok("OK"); } Err(sqlx::Error::RowNotFound) => { - return JsonResponse::build().not_found("Not Found".to_owned()); + return JsonResponse::build().not_found("Not Found"); } Err(e) => { tracing::error!("Failed to fetch rating, error: {:?}", e); - return JsonResponse::build().internal_error("Internal Server Error".to_owned()); + return JsonResponse::build().internal_server_error("Internal Server Error"); } } } diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index b793925..837eded 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -34,7 +34,7 @@ pub async fn add( } Err(_err) => { let msg = format!("Invalid data. {:?}", _err); - return JsonResponse::::build().err(msg); + return JsonResponse::::build().bad_request(msg); } }; @@ -59,7 +59,7 @@ pub async fn add( Err(sqlx::Error::RowNotFound) => {} Err(e) => { tracing::error!("Failed to fetch stack info, error: {:?}", e); - return JsonResponse::build().err(format!("Internal Server Error")); + return JsonResponse::build().bad_request(format!("Internal Server Error")); } }; @@ -87,7 +87,7 @@ pub async fn add( let errors = form.validate().unwrap_err(); let err_msg = format!("Invalid data received {:?}", &errors.to_string()); tracing::debug!(err_msg); - return JsonResponse::build().err(errors.to_string());// tmp solution + return JsonResponse::build().bad_request(errors.to_string());// tmp solution } let body: Value = match serde_json::to_value::(form) { @@ -120,11 +120,11 @@ pub async fn add( "req_id: {} New stack details have been saved to database", request_id ); - return JsonResponse::build().set_id(record.id).ok("OK".to_owned()); + return JsonResponse::build().set_id(record.id).ok("OK"); } Err(e) => { tracing::error!("req_id: {} Failed to execute query: {:?}", request_id, e); - return JsonResponse::build().err("Internal Server Error".to_owned()); + return JsonResponse::build().internal_server_error("Internal Server Error"); } }; } diff --git a/src/routes/stack/compose.rs b/src/routes/stack/compose.rs index 4dc3c7f..321f88b 100644 --- a/src/routes/stack/compose.rs +++ b/src/routes/stack/compose.rs @@ -58,10 +58,10 @@ pub async fn add( return JsonResponse::build() .set_id(id) .set_item(fc.unwrap()) - .ok("Success".to_owned()); + .ok("Success"); } None => { - return JsonResponse::build().err("Could not generate compose file".to_owned()); + return JsonResponse::build().bad_request("Could not generate compose file"); } } } @@ -118,11 +118,11 @@ pub async fn admin( // tracing::debug!("Docker compose file content {:?}", fc); return JsonResponse::build() .set_id(id) - .set_item(fc).ok("Success".to_owned()); + .set_item(fc).ok("Success"); } None => { - return JsonResponse::build().err("Could not generate compose file".to_owned()); + return JsonResponse::build().bad_request("Could not generate compose file"); } } } diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs index 645a14a..b0f512c 100644 --- a/src/routes/stack/deploy.rs +++ b/src/routes/stack/deploy.rs @@ -96,10 +96,10 @@ pub async fn add( assert_eq!(confirm, Confirmation::NotRequested); tracing::debug!("Message sent to rabbitmq"); - return JsonResponse::::build().set_id(id).ok("Success".to_owned()); + return JsonResponse::::build().set_id(id).ok("Success"); } None => { - JsonResponse::build().internal_error("Deployment failed".to_owned()) + JsonResponse::build().internal_server_error("Deployment failed") } } } diff --git a/src/routes/stack/get.rs b/src/routes/stack/get.rs index 271d2dc..61aa215 100644 --- a/src/routes/stack/get.rs +++ b/src/routes/stack/get.rs @@ -31,14 +31,14 @@ pub async fn item( { Ok(stack) => { tracing::info!("Stack found: {:?}", stack.id,); - return JsonResponse::build().set_item(Some(stack)).ok("OK".to_owned()); + return JsonResponse::build().set_item(Some(stack)).ok("OK"); } Err(sqlx::Error::RowNotFound) => { - JsonResponse::build().not_found("Record not found".to_owned()) + JsonResponse::build().not_found("Record not found") } Err(e) => { tracing::error!("Failed to fetch stack, error: {:?}", e); - return JsonResponse::build().internal_error("Could not fetch data".to_owned()); + return JsonResponse::build().internal_server_error("Could not fetch data"); } } } @@ -81,7 +81,7 @@ pub async fn list( } Err(e) => { tracing::error!("Failed to fetch stack, error: {:?}", e); - return JsonResponse::build().internal_error("Could not fetch".to_string()); + return JsonResponse::build().internal_server_error("Could not fetch".to_string()); } } } diff --git a/src/routes/stack/update.rs b/src/routes/stack/update.rs index 56514eb..9828017 100644 --- a/src/routes/stack/update.rs +++ b/src/routes/stack/update.rs @@ -43,7 +43,7 @@ pub async fn update( Err(e) => { tracing::error!("Failed to fetch record: {:?}, error: {:?}", id, e); return JsonResponse::::build() - .err(format!("Object not found {}", id)); + .not_found(format!("Object not found {}", id)); } }; @@ -71,7 +71,7 @@ pub async fn update( let errors = form.validate().unwrap_err(); let err_msg = format!("Invalid data received {:?}", &errors.to_string()); tracing::debug!(err_msg); - return JsonResponse::build().err(errors.to_string()); + return JsonResponse::build().bad_request(errors.to_string()); } let body: Value = match serde_json::to_value::(form.into_inner()) { @@ -105,11 +105,11 @@ pub async fn update( "req_id: {} stack details have been saved to database", request_id ); - return JsonResponse::build().set_id(id).ok("OK".to_owned()); + return JsonResponse::build().set_id(id).ok("OK"); } Err(e) => { tracing::error!("req_id: {} Failed to execute query: {:?}", request_id, e); - return JsonResponse::build().err("Internal Server Error".to_owned()); + return JsonResponse::build().bad_request("Internal Server Error"); } }; } diff --git a/tests/model_user_stack.rs b/tests/model_user_stack.rs index be93cec..e8ee9b6 100644 --- a/tests/model_user_stack.rs +++ b/tests/model_user_stack.rs @@ -18,7 +18,7 @@ fn test_deserialize_user_stack_web() { // } // Err(_err) => { // let msg = format!("Invalid data. {:?}", _err); - // return JsonResponse::::build().err(msg); + // return JsonResponse::::build().bad_request(msg); // } // }; // @@ -38,7 +38,7 @@ fn test_deserialize_user_stack() { // } // Err(_err) => { // let msg = format!("Invalid data. {:?}", _err); - // return JsonResponse::::build().err(msg); + // return JsonResponse::::build().bad_request(msg); // } // }; // From c11fec45f31fbe83509c44686a4871e7d1d00c5e Mon Sep 17 00:00:00 2001 From: petru Date: Tue, 5 Dec 2023 18:00:58 +0200 Subject: [PATCH 038/284] issue-auth working on optimisations --- src/middleware/trydirect.rs | 68 +++++++++++++------------------------ 1 file changed, 23 insertions(+), 45 deletions(-) diff --git a/src/middleware/trydirect.rs b/src/middleware/trydirect.rs index cf5079b..c270fba 100644 --- a/src/middleware/trydirect.rs +++ b/src/middleware/trydirect.rs @@ -13,12 +13,9 @@ use crate::helpers::JsonResponse; use crate::models::user::User; //todo #[tracing::instrument(name = "Trydirect bearer guard.")] -pub async fn bearer_guard( - req: ServiceRequest, - credentials: BearerAuth, - ) -> Result { - async { - let settings = req.app_data::>().unwrap(); +pub async fn bearer_guard( req: ServiceRequest, credentials: BearerAuth) -> Result { + let settings = req.app_data::>().unwrap(); + async move { let client = reqwest::Client::new(); let resp = client .get(&settings.auth_url) @@ -26,51 +23,32 @@ pub async fn bearer_guard( .header(CONTENT_TYPE, "application/json") .header(ACCEPT, "application/json") .send() - .await; + .await + .map_err(|err| "no resp from auth server".to_string())?; - let resp = match resp { - Ok(resp) if resp.status().is_success() => resp, - Ok(resp) => { - tracing::error!("Authentication service returned no success {:?}", resp); - return Err(("401 Unauthorized".to_string(), req)); - } - Err(err) => { - tracing::error!("error from reqwest {:?}", err); - return Err((err.to_string(), req)); - } - }; + if !resp.status().is_success() { + return Err(("401 Unauthorized".to_string(), req)); + } - let user_form: UserForm = match resp.json().await { + resp + .json() + .await + .map_err(|err| "can't parse the response body".to_string())? + .try_into() //User"Could not create User from form data" + }.await + .map(move |result| { + match result { Ok(user) => { - tracing::info!("unpacked user {user:?}"); - user - } - Err(err) => { - tracing::error!("can't parse the response body {:?}", err); - return Err(("can't parse the response body".to_string(), req)); - } - }; + let existent_user = req.extensions_mut().insert(user); + if existent_user.is_some() { + return Err((ErrorUnauthorized(JsonResponse::::build().set_msg("user already logged").to_string()), req)); + } - let user: User = match user_form.try_into() { - Ok(user) => user, + return Ok(req); + } Err(err) => { - tracing::error!("Could not create User from form data: {:?}", err); - return Err(("Could not create User from form data".to_string(), req)); + return Err((ErrorUnauthorized(JsonResponse::::build().set_msg(err).to_string()), req)); } - }; - let existent_user = req.extensions_mut().insert(user); - if existent_user.is_some() { - tracing::error!("already logged {existent_user:?}"); - return Err(("user already logged".to_string(), req)); } - - Ok(req) - }.await - .map_err(|(err, req)| { - tracing::error!("Authentication service returned no success {:?}", err); - (ErrorUnauthorized(JsonResponse::::build().set_msg(err).to_string()), req) //todo - //default - //type for - //JsonResponse }) } From 29f009515f3094cc2812ed28beab36dc55c36564 Mon Sep 17 00:00:00 2001 From: petru Date: Tue, 5 Dec 2023 18:04:10 +0200 Subject: [PATCH 039/284] issue-auth userform --- src/middleware/trydirect.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/middleware/trydirect.rs b/src/middleware/trydirect.rs index c270fba..05c1aca 100644 --- a/src/middleware/trydirect.rs +++ b/src/middleware/trydirect.rs @@ -27,11 +27,11 @@ pub async fn bearer_guard( req: ServiceRequest, credentials: BearerAuth) -> Resu .map_err(|err| "no resp from auth server".to_string())?; if !resp.status().is_success() { - return Err(("401 Unauthorized".to_string(), req)); + return Err("401 Unauthorized".to_string()); } resp - .json() + .json::() .await .map_err(|err| "can't parse the response body".to_string())? .try_into() //User"Could not create User from form data" From 61e6dd0b9dcfaf93900e89eef55996f2a137075f Mon Sep 17 00:00:00 2001 From: petru Date: Wed, 6 Dec 2023 08:32:44 +0200 Subject: [PATCH 040/284] issue-auth trydirect middleware --- src/middleware/trydirect.rs | 64 ++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/src/middleware/trydirect.rs b/src/middleware/trydirect.rs index 05c1aca..bc8fa06 100644 --- a/src/middleware/trydirect.rs +++ b/src/middleware/trydirect.rs @@ -15,40 +15,38 @@ use crate::models::user::User; //todo #[tracing::instrument(name = "Trydirect bearer guard.")] pub async fn bearer_guard( req: ServiceRequest, credentials: BearerAuth) -> Result { let settings = req.app_data::>().unwrap(); - async move { - let client = reqwest::Client::new(); - let resp = client - .get(&settings.auth_url) - .bearer_auth(credentials.token()) - .header(CONTENT_TYPE, "application/json") - .header(ACCEPT, "application/json") - .send() - .await - .map_err(|err| "no resp from auth server".to_string())?; + let token = credentials.token(); + let user = fetch_user(settings.auth_url.as_str(), token).await; + if let Err(err) = user { + return Err((ErrorUnauthorized(JsonResponse::::build().set_msg(err).to_string()), req)); + } - if !resp.status().is_success() { - return Err("401 Unauthorized".to_string()); - } + let user = user.unwrap(); + if req.extensions_mut().insert(user).is_some() { + return Err((ErrorUnauthorized(JsonResponse::::build().set_msg("user already logged").to_string()), req)); + } - resp - .json::() - .await - .map_err(|err| "can't parse the response body".to_string())? - .try_into() //User"Could not create User from form data" - }.await - .map(move |result| { - match result { - Ok(user) => { - let existent_user = req.extensions_mut().insert(user); - if existent_user.is_some() { - return Err((ErrorUnauthorized(JsonResponse::::build().set_msg("user already logged").to_string()), req)); - } + Ok(req) +} + +async fn fetch_user(auth_url: &str, token: &str) -> Result { + let client = reqwest::Client::new(); + let resp = client + .get(auth_url) + .bearer_auth(token) + .header(CONTENT_TYPE, "application/json") + .header(ACCEPT, "application/json") + .send() + .await + .map_err(|err| "no resp from auth server".to_string())?; + + if !resp.status().is_success() { + return Err("401 Unauthorized".to_string()); + } - return Ok(req); - } - Err(err) => { - return Err((ErrorUnauthorized(JsonResponse::::build().set_msg(err).to_string()), req)); - } - } - }) + resp + .json::() + .await + .map_err(|err| "can't parse the response body".to_string())? + .try_into() } From 7ea0f30bff0d773243aa3c64a76e405a18251d5e Mon Sep 17 00:00:00 2001 From: petru Date: Thu, 7 Dec 2023 07:05:02 +0200 Subject: [PATCH 041/284] issue-auth optimized use block in trydirect.rs --- src/middleware/trydirect.rs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/middleware/trydirect.rs b/src/middleware/trydirect.rs index bc8fa06..3e1db80 100644 --- a/src/middleware/trydirect.rs +++ b/src/middleware/trydirect.rs @@ -1,16 +1,8 @@ -use crate::configuration::Settings; -use futures::future::{FutureExt}; -use crate::forms::user::UserForm; -use actix_web::dev::ServiceRequest; -use actix_web::error::{ErrorInternalServerError, ErrorUnauthorized}; -use actix_web::web::{self}; -use actix_web::Error; -use actix_web::HttpMessage; +use crate::{models::user::User, configuration::Settings, forms::user::UserForm, helpers::JsonResponse}; +use actix_web::{web, dev::ServiceRequest, Error, HttpMessage, error::{ErrorInternalServerError, ErrorUnauthorized}}; use actix_web_httpauth::extractors::bearer::BearerAuth; +use futures::future::{FutureExt}; use reqwest::header::{ACCEPT, CONTENT_TYPE}; -use crate::helpers::JsonResponse; - -use crate::models::user::User; //todo #[tracing::instrument(name = "Trydirect bearer guard.")] pub async fn bearer_guard( req: ServiceRequest, credentials: BearerAuth) -> Result { From e3b9efd7a62259b35c581e07a97dfc92be0bafde Mon Sep 17 00:00:00 2001 From: petru Date: Thu, 7 Dec 2023 07:08:53 +0200 Subject: [PATCH 042/284] issue-auth wiremock --dev --- Cargo.lock | 193 +++++++++++++++++++++++++++++++++++++++++++++++++---- Cargo.toml | 1 + 2 files changed, 181 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d4cbf7c..cdd9ce8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,7 +64,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rand", + "rand 0.8.5", "sha1", "smallvec", "tokio", @@ -232,7 +232,7 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom", + "getrandom 0.2.10", "once_cell", "version_check", ] @@ -244,7 +244,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" dependencies = [ "cfg-if", - "getrandom", + "getrandom 0.2.10", "once_cell", "version_check", ] @@ -390,6 +390,22 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "assert-json-diff" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "async-channel" version = "1.9.0" @@ -902,6 +918,25 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "deadpool" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "421fe0f90f2ab22016f32a9881be5134fdd71c65298917084b0c7477cbc3856e" +dependencies = [ + "async-trait", + "deadpool-runtime", + "num_cpus", + "retain_mut", + "tokio", +] + +[[package]] +name = "deadpool-runtime" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63dfa964fe2a66f3fde91fc70b267fe193d822c7e603e2a675a49a7f46ad3f49" + [[package]] name = "deranged" version = "0.3.9" @@ -1232,6 +1267,12 @@ version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" +[[package]] +name = "futures-timer" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" + [[package]] name = "futures-util" version = "0.3.29" @@ -1270,6 +1311,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + [[package]] name = "getrandom" version = "0.2.10" @@ -1401,6 +1453,27 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "http-types" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e9b187a72d63adbfba487f48095306ac823049cb504ee195541e91c7775f5ad" +dependencies = [ + "anyhow", + "async-channel", + "base64 0.13.1", + "futures-lite", + "http", + "infer", + "pin-project-lite", + "rand 0.7.3", + "serde", + "serde_json", + "serde_qs", + "serde_urlencoded", + "url", +] + [[package]] name = "httparse" version = "1.8.0" @@ -1511,6 +1584,12 @@ dependencies = [ "serde", ] +[[package]] +name = "infer" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac" + [[package]] name = "inout" version = "0.1.3" @@ -1891,7 +1970,7 @@ dependencies = [ "cbc", "cipher", "des", - "getrandom", + "getrandom 0.2.10", "hmac", "lazy_static", "rc2", @@ -2147,6 +2226,19 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + [[package]] name = "rand" version = "0.8.5" @@ -2154,8 +2246,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", ] [[package]] @@ -2165,7 +2267,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", ] [[package]] @@ -2174,7 +2285,16 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.10", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", ] [[package]] @@ -2230,7 +2350,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom", + "getrandom 0.2.10", "redox_syscall 0.2.16", "thiserror", ] @@ -2317,6 +2437,12 @@ dependencies = [ "winreg", ] +[[package]] +name = "retain_mut" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4389f1d5789befaf6029ebd9f7dac4af7f7e3d61b69d4f30e2ac02b57e7712b0" + [[package]] name = "ring" version = "0.16.20" @@ -2339,7 +2465,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fce3045ffa7c981a6ee93f640b538952e155f1ae3a1a02b84547fc7a56b7059a" dependencies = [ "cc", - "getrandom", + "getrandom 0.2.10", "libc", "spin 0.9.8", "untrusted 0.9.0", @@ -2567,6 +2693,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_qs" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6" +dependencies = [ + "percent-encoding", + "serde", + "thiserror", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -2783,7 +2920,7 @@ dependencies = [ "once_cell", "paste", "percent-encoding", - "rand", + "rand 0.8.5", "rustls 0.20.9", "rustls-pemfile", "serde", @@ -2854,7 +2991,7 @@ dependencies = [ "hmac", "indexmap 2.1.0", "lapin", - "rand", + "rand 0.8.5", "regex", "reqwest", "serde", @@ -2873,6 +3010,7 @@ dependencies = [ "tracing-log", "tracing-subscriber", "uuid", + "wiremock", ] [[package]] @@ -3312,6 +3450,7 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -3326,7 +3465,7 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" dependencies = [ - "getrandom", + "getrandom 0.2.10", "serde", ] @@ -3363,6 +3502,12 @@ dependencies = [ "try-lock", ] +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + [[package]] name = "wasi" version = "0.10.0+wasi-snapshot-preview1" @@ -3587,6 +3732,28 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "wiremock" +version = "0.5.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13a3a53eaf34f390dd30d7b1b078287dd05df2aa2e21a589ccb80f5c7253c2e9" +dependencies = [ + "assert-json-diff", + "async-trait", + "base64 0.21.4", + "deadpool", + "futures", + "futures-timer", + "http-types", + "hyper", + "log", + "once_cell", + "regex", + "serde", + "serde_json", + "tokio", +] + [[package]] name = "yaml-rust" version = "0.4.5" diff --git a/Cargo.toml b/Cargo.toml index f3d2357..b23bf3b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,3 +71,4 @@ indexmap = ["dep:indexmap"] [dev-dependencies] glob = "0.3" +wiremock = "0.5.22" From 7b4df7114f25743392bf526ab31499827fbd1f62 Mon Sep 17 00:00:00 2001 From: petru Date: Thu, 7 Dec 2023 07:34:09 +0200 Subject: [PATCH 043/284] issue-auth tests/middleware_trydirect.rs --- tests/common/mod.rs | 36 +++++++++++++++++++---------------- tests/middleware_trydirect.rs | 29 ++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 16 deletions(-) create mode 100644 tests/middleware_trydirect.rs diff --git a/tests/common/mod.rs b/tests/common/mod.rs index afc4134..e5804ab 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,24 +1,10 @@ use actix_web::{get, web, App, HttpServer, Responder}; use sqlx::{Connection, Executor, PgConnection, PgPool}; -use stacker::configuration::{get_configuration, DatabaseSettings}; +use stacker::configuration::{get_configuration, DatabaseSettings, Settings}; use stacker::forms; use std::net::TcpListener; -pub async fn spawn_app() -> TestApp { - let mut configuration = get_configuration().expect("Failed to get configuration"); - - let listener = std::net::TcpListener::bind("127.0.0.1:0") - .expect("Failed to bind port for testing auth server"); - - configuration.auth_url = format!( - "http://127.0.0.1:{}/me", - listener.local_addr().unwrap().port() - ); - println!("Auth Server is running on: {}", configuration.auth_url); - - let handle = tokio::spawn(mock_auth_server(listener)); - handle.await.expect("Auth Server can not be started"); - +pub async fn spawn_app_with_configuration(mut configuration: Settings) -> TestApp { let listener = std::net::TcpListener::bind("127.0.0.1:0").expect("Failed to bind random port"); let port = listener.local_addr().unwrap().port(); @@ -40,6 +26,24 @@ pub async fn spawn_app() -> TestApp { } } +pub async fn spawn_app() -> TestApp { + let mut configuration = get_configuration().expect("Failed to get configuration"); + + let listener = std::net::TcpListener::bind("127.0.0.1:0") + .expect("Failed to bind port for testing auth server"); + + configuration.auth_url = format!( + "http://127.0.0.1:{}/me", + listener.local_addr().unwrap().port() + ); + println!("Auth Server is running on: {}", configuration.auth_url); + + let handle = tokio::spawn(mock_auth_server(listener)); + handle.await.expect("Auth Server can not be started"); + + spawn_app_with_configuration(configuration).await +} + pub async fn configure_database(config: &DatabaseSettings) -> PgPool { let mut connection = PgConnection::connect(&config.connection_string_without_db()) .await diff --git a/tests/middleware_trydirect.rs b/tests/middleware_trydirect.rs new file mode 100644 index 0000000..0590618 --- /dev/null +++ b/tests/middleware_trydirect.rs @@ -0,0 +1,29 @@ +mod common; +use wiremock::MockServer; + +#[tokio::test] +async fn middleware_trydirect_works() { + // 1. Arrange + let trydirect_auth_server = MockServer::start().await; + + // 2. Act + // 3. Assert + + println!("Before spawn_app"); + let app = common::spawn_app().await; // server + println!("After spawn_app"); + let client = reqwest::Client::new(); // client + + let response = client + .get(&format!("{}/health_check", &app.address)) + .send() + .await + .expect("Failed to execute request."); + + assert!(response.status().is_success()); + assert_eq!(Some(0), response.content_length()); + + + //todo header stacker-id not found + // +} From d86e37ff53dbede0902d22b84eda6775ebae26ea Mon Sep 17 00:00:00 2001 From: petru Date: Fri, 8 Dec 2023 16:54:42 +0200 Subject: [PATCH 044/284] issue-auth - db_fetch_client --- src/middleware/client.rs | 56 +++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/src/middleware/client.rs b/src/middleware/client.rs index 4309ac5..a047b13 100644 --- a/src/middleware/client.rs +++ b/src/middleware/client.rs @@ -77,31 +77,11 @@ where let client_id: i32 = get_header(&req, "stacker-id")?; let hash: String = get_header(&req, "stacker-hash")?; - let query_span = tracing::info_span!("Fetching the client by ID"); - let db_pool = req.app_data::>>().unwrap(); - - let mut client: Client = match sqlx::query_as!( - Client, - r#" - SELECT - id, user_id, secret - FROM client c - WHERE c.id = $1 - "#, - client_id, - ) - .fetch_one(db_pool.get_ref()) - .instrument(query_span) - .await - { - Ok(client) if client.secret.is_some() => Ok(client), - Ok(_client) => Err("client is not active".to_string()), - Err(sqlx::Error::RowNotFound) => Err("the client is not found".to_string()), - Err(e) => { - tracing::error!("Failed to execute fetch query: {:?}", e); - Err("".to_string()) - } - }?; + let db_pool = req.app_data::>>().unwrap().get_ref(); + let mut client: Client = db_fetch_client(db_pool, client_id).await?; + if client.secret.is_none() { + return Err("client is not active".to_string()); + } let content_length: usize = get_header(&req, CONTENT_LENGTH.as_str())?; let mut bytes = BytesMut::with_capacity(content_length); @@ -165,9 +145,31 @@ where let header_value: &str = header_value .to_str() - .map_err(|_| format!("header {header_name} can't be converted to string"))?; //map_err - // + .map_err(|_| format!("header {header_name} can't be converted to string"))?; + header_value .parse::() .map_err(|_| format!("header {header_name} has wrong type")) } + +async fn db_fetch_client(db_pool: &Pool, client_id: i32) -> Result { + let query_span = tracing::info_span!("Fetching the client by ID"); + + sqlx::query_as!( + Client, + r#"SELECT id, user_id, secret FROM client c WHERE c.id = $1"#, + client_id, + ) + .fetch_one(db_pool) + .instrument(query_span) + .await + .map_err(|err| { + match err { + sqlx::Error::RowNotFound => "the client is not found".to_string(), + e => { + tracing::error!("Failed to execute fetch query: {:?}", e); + String::new() + } + } + }) +} From 3f9f6d0142aaa68885186aff5953551795ed9232 Mon Sep 17 00:00:00 2001 From: petru Date: Fri, 8 Dec 2023 17:26:25 +0200 Subject: [PATCH 045/284] issue-auth - optimize src/middleware/client.rs --- src/middleware/client.rs | 53 ++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/src/middleware/client.rs b/src/middleware/client.rs index a047b13..27aa97b 100644 --- a/src/middleware/client.rs +++ b/src/middleware/client.rs @@ -75,7 +75,7 @@ where let service = self.service.clone(); async move { let client_id: i32 = get_header(&req, "stacker-id")?; - let hash: String = get_header(&req, "stacker-hash")?; + let header_hash: String = get_header(&req, "stacker-hash")?; let db_pool = req.app_data::>>().unwrap().get_ref(); let mut client: Client = db_fetch_client(db_pool, client_id).await?; @@ -83,32 +83,12 @@ where return Err("client is not active".to_string()); } - let content_length: usize = get_header(&req, CONTENT_LENGTH.as_str())?; - let mut bytes = BytesMut::with_capacity(content_length); - let mut payload = req.take_payload(); - while let Some(chunk) = payload.next().await { - bytes.extend_from_slice(&chunk.expect("can't unwrap the chunk")); - } - - let mut mac = - match Hmac::::new_from_slice(client.secret.as_ref().unwrap().as_bytes()) { - Ok(mac) => mac, - Err(err) => { - tracing::error!("error generating hmac {err:?}"); - return Err("".to_string()); - } - }; - - mac.update(bytes.as_ref()); - let computed_hash = format!("{:x}", mac.finalize().into_bytes()); - if hash != computed_hash { + let client_secret = client.secret.as_ref().unwrap().as_bytes(); + let body_hash = compute_body_hash(&mut req, client_secret).await?; + if header_hash != body_hash { return Err("hash is wrong".to_string()); } - let (_, mut payload) = actix_http::h1::Payload::create(true); - payload.unread_data(bytes.into()); - req.set_payload(payload.into()); - match req.extensions_mut().insert(Arc::new(client)) { Some(_) => { tracing::error!("client middleware already called once"); @@ -173,3 +153,28 @@ async fn db_fetch_client(db_pool: &Pool, client_id: i32) -> Result Result { + let content_length: usize = get_header(req, CONTENT_LENGTH.as_str())?; + let mut body = BytesMut::with_capacity(content_length); + let mut payload = req.take_payload(); + while let Some(chunk) = payload.next().await { + body.extend_from_slice(&chunk.expect("can't unwrap the chunk")); + } + + let mut mac = + match Hmac::::new_from_slice(client_secret) { + Ok(mac) => mac, + Err(err) => { + tracing::error!("error generating hmac {err:?}"); + return Err("".to_string()); + } + }; + + mac.update(body.as_ref()); + let (_, mut payload) = actix_http::h1::Payload::create(true); + payload.unread_data(body.into()); + req.set_payload(payload.into()); + + Ok(format!("{:x}", mac.finalize().into_bytes())) +} From 02de6cb344424276553bf8ded06f5a77c3fa5d34 Mon Sep 17 00:00:00 2001 From: vsilent Date: Fri, 8 Dec 2023 20:42:46 +0200 Subject: [PATCH 046/284] working non-optimized version of dc generator --- src/forms/stack.rs | 6 +-- src/helpers/stack/builder.rs | 66 ++++++++++++++++++++++++++---- tests/custom-stack-payload-11.json | 2 +- 3 files changed, 61 insertions(+), 13 deletions(-) diff --git a/src/forms/stack.rs b/src/forms/stack.rs index 544dc3d..f09b052 100644 --- a/src/forms/stack.rs +++ b/src/forms/stack.rs @@ -264,12 +264,12 @@ pub struct App { #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Environment { - environment: Option>> + pub(crate) environment: Option>> } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Volume { - host_path: Option, - container_path: Option + pub(crate) host_path: Option, + pub(crate) container_path: Option } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 0026257..e718dd1 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -1,11 +1,6 @@ -use crate::helpers::stack::dctypes::{ - Compose, - Port, - Ports, - PublishedPort, - Service, - Services -}; +use std::collections::HashMap; +use indexmap::IndexMap; +use crate::helpers::stack::dctypes::{Compose, Port, Ports, PublishedPort, Service, Services, Volumes, Environment, Entrypoint, AdvancedVolumes, SingleValue}; use serde_yaml; use crate::forms::{StackForm, stack}; use crate::models::stack::Stack; @@ -37,6 +32,24 @@ pub struct DcBuilder { pub(crate) stack: Stack } +impl TryInto for &stack::Volume { + type Error = String; + fn try_into(self) -> Result { + + let source = self.host_path.clone(); + let target = self.container_path.clone(); + tracing::debug!("Volume conversion result: source: {:?} target: {:?}", source, target); + Ok(AdvancedVolumes { + source: source, + target: target.unwrap_or("".to_string()), + _type: "".to_string(), + read_only: false, + bind: None, + volume: None, + tmpfs: None, + }) + } +} impl TryInto for &stack::Port { type Error = String; @@ -79,6 +92,21 @@ fn convert_shared_ports(ports: Option>) -> Result, St Ok(_ports) } +// impl TryInto>> for HashMap { +// type Error = String; +// +// fn try_into(self) -> Result>, Self::Error> { +// let mut index_map = IndexMap::new(); +// +// for (key, value) in self { +// let single_value = Some(SingleValue::String(value)); +// index_map.insert(key, single_value); +// } +// +// Ok(index_map) +// } +// } + impl DcBuilder { pub fn new(stack: Stack) -> Self { @@ -110,9 +138,28 @@ impl DcBuilder { .iter() .map(|x| x.try_into().unwrap()) .collect(); + + let volumes: Vec = app_type.app.volumes + .unwrap() + .iter() + .map(|x| x.try_into().unwrap()) + .collect(); + + let mut envs = IndexMap::new(); + for item in app_type.app.environment.environment.unwrap() { + let items = item + .into_iter() + .map(|(k, v)| (k, Some(SingleValue::String(v.clone())))) + .collect::>(); + + envs.extend(items); + } + // tracing::debug!("envs: {:?}", envs); service.ports = Ports::Long(ports); service.restart = Some("always".to_owned()); - tracing::debug!("service 1 {:?}", &service); + service.volumes = Volumes::Advanced(volumes); + service.environment = Environment::KvPair(envs); + // tracing::debug!("service 1 {:?}", &service); services.insert( code, Some(service), @@ -183,6 +230,7 @@ impl DcBuilder { } } + let compose_content = Compose { version: Some("3.8".to_string()), services: { diff --git a/tests/custom-stack-payload-11.json b/tests/custom-stack-payload-11.json index d87ce41..ab0314d 100644 --- a/tests/custom-stack-payload-11.json +++ b/tests/custom-stack-payload-11.json @@ -1 +1 @@ -{"commonDomain":"justates222t.com","domainList":{},"region":"fsn1","zone":null,"server":"cx21","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":["portainer_ce_feature"],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":true,"disk_type":"pd-standart","cloud_token":"**********","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"web":[{"_etag":null,"_id":180,"_created":"2021-12-17T08:11:40.875486","_updated":"2023-11-21T17:37:24.594545","name":"Airflow","code":"airflow","role":["airflow"],"type":"web","default":true,"popularity":null,"descr":null,"ports":{"private":["31"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":150,"height":150,"image":"7f41d873-2de5-4c6e-a037-42eeff572db6.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":"

Airflow description

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"airflow","form":null,"category":[null],"group":[],"versions":[{"_id":425,"name":"Airflow","version":"2.7.3","update_status":"published","tag":"latest"},{"_id":426,"name":"Airflow","version":"2.7.1-unstable","update_status":"published","tag":"stable"}],"links":[],"domain":"latestports.com","sharedPorts":[{"host_port":"5000","container_port":"5000"}],"main":true,"version":{"_id":426,"name":"Airflow","version":"2.7.1-unstable","update_status":"published","tag":"stable"},"environment":[{"ENV_VAR1":"ENV_VAR1_VALUE"}],"network":"testnetwork","restart":"always","volumes":[{"host_path":"/airflow/host/path/","container_path":"/airflow/container/path"}]},{"category":[{"name":"integrated_features"}],"name":"CustomNginx","code":"customnginx","domain":"customnginx.latestports.com","sharedPorts":[{"host_port":"80","container_port":"8080"},{"host_port":"443","container_port":"8443"}],"versions":[],"custom":true,"type":"web","main":false,"_id":0,"dockerhub_user":"trydirect","dockerhub_name":"nginx","disk_size":"0.9Gb","ram_size":"1.3Gb","cpu":"0.3","volumes":[{"host_path":"asdfasdf","container_path":"asdfasdf"}],"environment":[{"CUSTOM_NGINX_ENV_VAR1":"CUSTOM_NGINX_ENV_VAR1_VALUE"},{"/customnginx/host/path":"/customnginx/container/path"}],"network":"testnetwork","restart":"always"}],"feature":[{"_etag":null,"_id":198,"_created":"2022-04-27T14:10:27.280327","_updated":"2023-08-03T08:24:18.958721","name":"Portainer CE Feature","code":"portainer_ce_feature","role":["portainer-ce-feature"],"type":"feature","default":null,"popularity":null,"descr":null,"ports":{"public":["9000","8000"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":1138,"height":1138,"image":"08589075-44e6-430e-98a5-f9dcf711e054.svg"},"dark":{}},"category_id":2,"parent_app_id":null,"full_description":null,"description":"

Portainer is a lightweight management UI which allows you to easily manage your different Docker environments (Docker hosts or Swarm clusters)

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.6","ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"portainer-ce-feature","form":null,"category":[{"name":"integrated_features"}],"group":[],"versions":[{"_id":456,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"}],"links":[],"version":{"_id":456,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"},"sharedPorts":[{"host_port":"9000","container_port":"9000"}],"environment":[{"PORTAINER_ENV_VAR1":"PORTAINER_ENV_VAR1_VALUE"}],"volumes":[{"host_path":"/portainer/test/path","container_path":"/portainer/test/path"}],"network":"testnetwork","restart":"always"}],"service":[{"_etag":null,"_id":24,"_created":"2020-06-19T13:07:24.228389","_updated":"2023-11-23T10:18:28.095813","name":"PostgreSQL","code":"postgres","role":["postgres"],"type":"service","default":null,"popularity":null,"descr":null,"ports":{"private":["5432"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":576,"height":594,"image":"fd23f54c-e250-4228-8d56-7e5d93ffb925.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":null,"plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"postgres","form":null,"category":[null],"group":[{"_etag":null,"_id":12,"_created":null,"_updated":null,"name":"Database","code":"database"}],"versions":[{"_id":458,"name":"15","version":"15","update_status":"published","tag":"15"},{"_id":288,"name":"10.22","version":"10.22","update_status":"published","tag":"10.22"},{"_id":303,"name":"13.8","version":"13.8","update_status":"published","tag":"13.8"},{"_id":266,"name":"11","version":"11","update_status":"published","tag":"11"},{"_id":267,"name":"12.12","version":"12.12","update_status":"published","tag":"12.12"},{"_id":38,"name":"14.5","version":"14.5","update_status":"published","tag":"14.5"},{"_id":596,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"}],"links":[],"domain":"","sharedPorts":[{"host_port":"5432","container_port":"5432"}],"main":false,"version":{"_id":596,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"},"environment":[{"POSTGRES_ENV_VAR1":"POSTGRES_ENV_VAR1_VALUE"},{"POSTGRES_ENV_VAR2":"POSTGRES_ENV_VAR2_VALUE"}],"network":"testnetwork","restart":"always","volumes":[{"host_path":"./pg.conf","container_path":"/etc/postgres/pg.conf"}]}],"servers_count":3,"project_name":"LatestPorts","custom_stack_code":"latestports","project_git_url":"https://github.com/latestports","custom_stack_category":[],"networks":["testnetwork","testnetwork2"]}} \ No newline at end of file +{"commonDomain":"justates222t.com","domainList":{},"region":"fsn1","zone":null,"server":"cx21","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":["portainer_ce_feature"],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":true,"disk_type":"pd-standart","cloud_token":"***********","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"web":[{"_etag":null,"_id":180,"_created":"2021-12-17T08:11:40.875486","_updated":"2023-11-21T17:37:24.594545","name":"Airflow","code":"airflow","role":["airflow"],"type":"web","default":true,"popularity":null,"descr":null,"ports":{"private":["31"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":150,"height":150,"image":"7f41d873-2de5-4c6e-a037-42eeff572db6.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":"

Airflow description

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"airflow","form":null,"category":[null],"group":[],"versions":[{"_id":425,"name":"Airflow","version":"2.7.3","update_status":"published","tag":"latest"},{"_id":426,"name":"Airflow","version":"2.7.1-unstable","update_status":"published","tag":"stable"}],"links":[],"domain":"latestports.com","sharedPorts":[{"host_port":"5000","container_port":"5000"}],"main":true,"version":{"_id":426,"name":"Airflow","version":"2.7.1-unstable","update_status":"published","tag":"stable"},"environment":[{"ENV_VAR1":"ENV_VAR1_VALUE"}, {"ENV_VAR2":"ENV_VAR1_VALUe2"}],"network":"testnetwork","restart":"always","volumes":[{"host_path":"/airflow/host/path/","container_path":"/airflow/container/path"}, {"host_path":"/airflow/host/path2/","container_path":"/airflow/container/path2"}]},{"category":[{"name":"integrated_features"}],"name":"CustomNginx","code":"customnginx","domain":"customnginx.latestports.com","sharedPorts":[{"host_port":"80","container_port":"8080"},{"host_port":"443","container_port":"8443"}],"versions":[],"custom":true,"type":"web","main":false,"_id":0,"dockerhub_user":"trydirect","dockerhub_name":"nginx","disk_size":"0.9Gb","ram_size":"1.3Gb","cpu":"0.3","volumes":[{"host_path":"/host/path","container_path":"/container/path"}],"environment":[{"CUSTOM_NGINX_ENV_VAR1":"CUSTOM_NGINX_ENV_VAR1_VALUE"},{"CUSTOM_NGINX_VAR2": "CUSTOM_NGINX_VAR_VALUE2"}, {"CUSTOM_NGINX_ENV_VAR3":"CUSTOM_NGINX_ENV_VAR1_VALUE3"},{"CUSTOM_NGINX_VAR4": "CUSTOM_NGINX_VAR_VALUE4"}],"network":"testnetwork","restart":"always"}],"feature":[{"_etag":null,"_id":198,"_created":"2022-04-27T14:10:27.280327","_updated":"2023-08-03T08:24:18.958721","name":"Portainer CE Feature","code":"portainer_ce_feature","role":["portainer-ce-feature"],"type":"feature","default":null,"popularity":null,"descr":null,"ports":{"public":["9000","8000"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":1138,"height":1138,"image":"08589075-44e6-430e-98a5-f9dcf711e054.svg"},"dark":{}},"category_id":2,"parent_app_id":null,"full_description":null,"description":"

Portainer is a lightweight management UI which allows you to easily manage your different Docker environments (Docker hosts or Swarm clusters)

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.6","ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"portainer-ce-feature","form":null,"category":[{"name":"integrated_features"}],"group":[],"versions":[{"_id":456,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"}],"links":[],"version":{"_id":456,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"},"sharedPorts":[{"host_port":"9000","container_port":"9000"}],"environment":[{"PORTAINER_ENV_VAR1":"PORTAINER_ENV_VAR1_VALUE"}],"volumes":[{"host_path":"/portainer/test/path","container_path":"/portainer/test/path"}],"network":"testnetwork","restart":"always"}],"service":[{"_etag":null,"_id":24,"_created":"2020-06-19T13:07:24.228389","_updated":"2023-11-23T10:18:28.095813","name":"PostgreSQL","code":"postgres","role":["postgres"],"type":"service","default":null,"popularity":null,"descr":null,"ports":{"private":["5432"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":576,"height":594,"image":"fd23f54c-e250-4228-8d56-7e5d93ffb925.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":null,"plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"postgres","form":null,"category":[null],"group":[{"_etag":null,"_id":12,"_created":null,"_updated":null,"name":"Database","code":"database"}],"versions":[{"_id":458,"name":"15","version":"15","update_status":"published","tag":"15"},{"_id":288,"name":"10.22","version":"10.22","update_status":"published","tag":"10.22"},{"_id":303,"name":"13.8","version":"13.8","update_status":"published","tag":"13.8"},{"_id":266,"name":"11","version":"11","update_status":"published","tag":"11"},{"_id":267,"name":"12.12","version":"12.12","update_status":"published","tag":"12.12"},{"_id":38,"name":"14.5","version":"14.5","update_status":"published","tag":"14.5"},{"_id":596,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"}],"links":[],"domain":"","sharedPorts":[{"host_port":"5432","container_port":"5432"}],"main":false,"version":{"_id":596,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"},"environment":[{"POSTGRES_ENV_VAR1":"POSTGRES_ENV_VAR1_VALUE"},{"POSTGRES_ENV_VAR2":"POSTGRES_ENV_VAR2_VALUE"}],"network":"testnetwork","restart":"always","volumes":[{"host_path":"./pg.conf","container_path":"/etc/postgres/pg.conf"}]}],"servers_count":3,"project_name":"LatestPorts","custom_stack_code":"latestports","project_git_url":"https://github.com/latestports","custom_stack_category":[],"networks":["testnetwork","testnetwork2"]}} \ No newline at end of file From 093a0c91373e8d2e250ebb86294ecc42905b7673 Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 9 Dec 2023 08:46:46 +0200 Subject: [PATCH 047/284] issue-auth Arc --- src/console/commands/appclient/new.rs | 2 +- src/middleware/trydirect.rs | 3 ++- src/models/user.rs | 12 ------------ src/routes/client/add.rs | 13 +++++++------ src/routes/client/disable.rs | 3 ++- src/routes/client/enable.rs | 3 ++- src/routes/client/update.rs | 2 +- src/routes/rating/add.rs | 3 ++- src/routes/stack/add.rs | 3 ++- src/routes/stack/compose.rs | 5 +++-- src/routes/stack/deploy.rs | 2 +- src/routes/stack/get.rs | 5 +++-- 12 files changed, 26 insertions(+), 30 deletions(-) diff --git a/src/console/commands/appclient/new.rs b/src/console/commands/appclient/new.rs index 138f11f..448ac78 100644 --- a/src/console/commands/appclient/new.rs +++ b/src/console/commands/appclient/new.rs @@ -32,7 +32,7 @@ impl crate::console::commands::CallableTrait for NewCommand { email: "email".to_string(), email_confirmed: true, }; - crate::routes::client::add_handler_inner(user, settings, db_pool).await?; + crate::routes::client::add_handler_inner(&user.id, settings, db_pool).await?; Ok(()) }) diff --git a/src/middleware/trydirect.rs b/src/middleware/trydirect.rs index 3e1db80..340d06f 100644 --- a/src/middleware/trydirect.rs +++ b/src/middleware/trydirect.rs @@ -3,6 +3,7 @@ use actix_web::{web, dev::ServiceRequest, Error, HttpMessage, error::{ErrorInter use actix_web_httpauth::extractors::bearer::BearerAuth; use futures::future::{FutureExt}; use reqwest::header::{ACCEPT, CONTENT_TYPE}; +use std::sync::Arc; #[tracing::instrument(name = "Trydirect bearer guard.")] pub async fn bearer_guard( req: ServiceRequest, credentials: BearerAuth) -> Result { @@ -14,7 +15,7 @@ pub async fn bearer_guard( req: ServiceRequest, credentials: BearerAuth) -> Resu } let user = user.unwrap(); - if req.extensions_mut().insert(user).is_some() { + if req.extensions_mut().insert(Arc::new(user)).is_some() { return Err((ErrorUnauthorized(JsonResponse::::build().set_msg("user already logged").to_string()), req)); } diff --git a/src/models/user.rs b/src/models/user.rs index 4e77598..8217ac8 100644 --- a/src/models/user.rs +++ b/src/models/user.rs @@ -10,15 +10,3 @@ pub struct User { // pub phone: Option, // pub website: Option, } - -impl Clone for User { - fn clone(&self) -> Self { - User { - id: self.id.clone(), - first_name: self.first_name.clone(), - last_name: self.last_name.clone(), - email: self.email.clone(), - email_confirmed: self.email_confirmed.clone(), - } - } -} \ No newline at end of file diff --git a/src/routes/client/add.rs b/src/routes/client/add.rs index db98705..2a0757e 100644 --- a/src/routes/client/add.rs +++ b/src/routes/client/add.rs @@ -6,22 +6,23 @@ use crate::models::user::User; use actix_web::{post, web, Responder, Result}; use sqlx::PgPool; use tracing::Instrument; +use std::sync::Arc; #[tracing::instrument(name = "Add client.")] #[post("")] pub async fn add_handler( - user: web::ReqData, + user: web::ReqData>, settings: web::Data, pool: web::Data, ) -> Result { - match add_handler_inner(user.into_inner(), settings, pool).await { + match add_handler_inner(&user.id, settings, pool).await { Ok(client) => JsonResponse::build().set_item(client).ok("Ok"), Err(msg) => JsonResponse::build().bad_request(msg), } } pub async fn add_handler_inner( - user: User, + user_id: &String, settings: web::Data, pool: web::Data, ) -> Result { @@ -34,7 +35,7 @@ pub async fn add_handler_inner( FROM client c WHERE c.user_id = $1 "#, - user.id.clone(), + user_id.clone(), ) .fetch_one(pool.get_ref()) .instrument(query_span) @@ -45,7 +46,7 @@ pub async fn add_handler_inner( if client_count >= settings.max_clients_number { tracing::error!( "Too many clients. The user {} has {} clients", - user.id, + user_id, client_count ); @@ -59,7 +60,7 @@ pub async fn add_handler_inner( }; let mut client = models::Client::default(); - client.user_id = user.id.clone(); + client.user_id = user_id.clone(); client.secret = client::generate_secret(pool.get_ref(), 255) .await .map(|s| Some(s))?; diff --git a/src/routes/client/disable.rs b/src/routes/client/disable.rs index b0d2cde..c80df8c 100644 --- a/src/routes/client/disable.rs +++ b/src/routes/client/disable.rs @@ -5,11 +5,12 @@ use crate::models::Client; use actix_web::{error::ErrorInternalServerError, put, web, Responder, Result}; use sqlx::PgPool; use tracing::Instrument; +use std::sync::Arc; #[tracing::instrument(name = "Disable client.")] #[put("/{id}/disable")] pub async fn disable_handler( - user: web::ReqData, + user: web::ReqData>, settings: web::Data, pool: web::Data, path: web::Path<(i32,)>, diff --git a/src/routes/client/enable.rs b/src/routes/client/enable.rs index ef0548d..de09451 100644 --- a/src/routes/client/enable.rs +++ b/src/routes/client/enable.rs @@ -6,11 +6,12 @@ use crate::models::Client; use actix_web::{error::ErrorBadRequest, put, web, Responder, Result}; use sqlx::PgPool; use tracing::Instrument; +use std::sync::Arc; #[tracing::instrument(name = "Enable client.")] #[put("/{id}/enable")] pub async fn enable_handler( - user: web::ReqData, + user: web::ReqData>, settings: web::Data, pool: web::Data, path: web::Path<(i32,)>, diff --git a/src/routes/client/update.rs b/src/routes/client/update.rs index 64604d3..7aa28eb 100644 --- a/src/routes/client/update.rs +++ b/src/routes/client/update.rs @@ -10,7 +10,7 @@ use tracing::Instrument; #[tracing::instrument(name = "Update client.")] #[put("/{id}")] pub async fn update_handler( - user: web::ReqData, + user: web::ReqData>, settings: web::Data, pool: web::Data, path: web::Path<(i32,)>, diff --git a/src/routes/rating/add.rs b/src/routes/rating/add.rs index b099cfe..922cee0 100644 --- a/src/routes/rating/add.rs +++ b/src/routes/rating/add.rs @@ -6,6 +6,7 @@ use crate::models::RateCategory; use actix_web::{post, web, Responder, Result}; use sqlx::PgPool; use tracing::Instrument; +use std::sync::Arc; // workflow // add, update, list, get(user_id), ACL, @@ -15,7 +16,7 @@ use tracing::Instrument; #[tracing::instrument(name = "Add rating.")] #[post("")] pub async fn add_handler( - user: web::ReqData, + user: web::ReqData>, form: web::Json, pool: web::Data, ) -> Result { diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index 8176cfa..3e6aa6c 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -14,12 +14,13 @@ use sqlx::PgPool; use std::str; use tracing::Instrument; use uuid::Uuid; +use std::sync::Arc; #[tracing::instrument(name = "Add stack.")] #[post("")] pub async fn add( body: Bytes, - user: web::ReqData, + user: web::ReqData>, pool: Data, ) -> Result { let body_bytes = actix_web::body::to_bytes(body).await.unwrap(); diff --git a/src/routes/stack/compose.rs b/src/routes/stack/compose.rs index 7b2f8a4..e52ebff 100644 --- a/src/routes/stack/compose.rs +++ b/src/routes/stack/compose.rs @@ -13,11 +13,12 @@ use sqlx::PgPool; use std::str; use tracing::Instrument; use uuid::Uuid; +use std::sync::Arc; #[tracing::instrument(name = "User's generate docker-compose.")] #[post("/{id}")] pub async fn add( - user: web::ReqData, + user: web::ReqData>, path: web::Path<(i32,)>, pool: Data, ) -> Result { @@ -70,7 +71,7 @@ pub async fn add( #[tracing::instrument(name = "Generate docker-compose. Admin")] #[get("/{id}/compose")] pub async fn admin( - user: web::ReqData, + user: web::ReqData>, path: web::Path<(i32,)>, pool: Data, ) -> Result { diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs index 5c9fa66..3243947 100644 --- a/src/routes/stack/deploy.rs +++ b/src/routes/stack/deploy.rs @@ -15,7 +15,7 @@ use std::sync::Arc; #[tracing::instrument(name = "Deploy for every user. Admin endpoint")] #[post("/{id}/deploy")] pub async fn add( - user: web::ReqData, + user: web::ReqData>, path: web::Path<(i32,)>, pool: Data, sets: Data, diff --git a/src/routes/stack/get.rs b/src/routes/stack/get.rs index 2264a14..d38ab3d 100644 --- a/src/routes/stack/get.rs +++ b/src/routes/stack/get.rs @@ -5,11 +5,12 @@ use actix_web::{get, web, Responder, Result}; use sqlx::PgPool; use std::convert::From; use tracing::Instrument; +use std::sync::Arc; #[tracing::instrument(name = "Get logged user stack.")] #[get("/{id}")] pub async fn item( - user: web::ReqData, + user: web::ReqData>, path: web::Path<(i32,)>, pool: web::Data, ) -> Result { @@ -43,7 +44,7 @@ pub async fn item( #[tracing::instrument(name = "Get user's stack list.")] #[get("/user/{id}")] pub async fn list( - user: web::ReqData, + user: web::ReqData>, path: web::Path<(String,)>, pool: web::Data, ) -> Result { From dbe5a06cf50f0c2ba3d5da48d1d89ca9738cd67a Mon Sep 17 00:00:00 2001 From: vsilent Date: Sat, 9 Dec 2023 17:04:46 +0200 Subject: [PATCH 048/284] walk through app types optimized --- src/helpers/stack/builder.rs | 177 ++++++++++++++--------------------- 1 file changed, 71 insertions(+), 106 deletions(-) diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index e718dd1..e7826f2 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -2,7 +2,8 @@ use std::collections::HashMap; use indexmap::IndexMap; use crate::helpers::stack::dctypes::{Compose, Port, Ports, PublishedPort, Service, Services, Volumes, Environment, Entrypoint, AdvancedVolumes, SingleValue}; use serde_yaml; -use crate::forms::{StackForm, stack}; +use crate::forms; +use crate::forms::{StackForm, stack, Web, Feature, App}; use crate::models::stack::Stack; #[derive(Clone, Debug)] struct Config {} @@ -32,7 +33,7 @@ pub struct DcBuilder { pub(crate) stack: Stack } -impl TryInto for &stack::Volume { +impl TryInto for stack::Volume { type Error = String; fn try_into(self) -> Result { @@ -51,7 +52,7 @@ impl TryInto for &stack::Volume { } } -impl TryInto for &stack::Port { +impl TryInto for stack::Port { type Error = String; fn try_into(self) -> Result { let cp = self.container_port.clone() @@ -92,21 +93,63 @@ fn convert_shared_ports(ports: Option>) -> Result, St Ok(_ports) } -// impl TryInto>> for HashMap { -// type Error = String; +trait TryIntoService { + fn try_into_service(&self) -> Service; +} + +impl TryIntoService for App { + fn try_into_service(&self) -> Service { + let mut service = Service { + image: Some(self.docker_image.to_string()), + ..Default::default() + }; + + let ports: Vec = self.ports + .clone() + .unwrap_or_default() + .into_iter() + .map(|x| x.try_into().unwrap()) + .collect(); + + let volumes: Vec = self.volumes + .clone() + .unwrap_or_default() + .into_iter() + .map(|x| x.try_into().unwrap()) + .collect(); + + let mut envs = IndexMap::new(); + for item in self.environment.environment.clone().unwrap_or_default() { + let items = item + .into_iter() + .map(|(k, v)| (k, Some(SingleValue::String(v.clone())))) + .collect::>(); + + envs.extend(items); + } + + service.ports = Ports::Long(ports); + service.restart = Some("always".to_owned()); + service.volumes = Volumes::Advanced(volumes); + service.environment = Environment::KvPair(envs); + + service + } +} + +// fn create_service(app_type: T) -> Service +// where +// T: TryIntoService, +// { // -// fn try_into(self) -> Result>, Self::Error> { -// let mut index_map = IndexMap::new(); +// let mut service = Service { +// image: Some(app_type.try_into_service().image.unwrap_or_default()), +// ..Default::default() +// }; // -// for (key, value) in self { -// let single_value = Some(SingleValue::String(value)); -// index_map.insert(key, single_value); -// } +// service // -// Ok(index_map) -// } // } - impl DcBuilder { pub fn new(stack: Stack) -> Self { @@ -118,119 +161,41 @@ impl DcBuilder { pub fn build(&self) -> Option { - tracing::debug!("Start build docker compose from {:?}", &self.stack.body); let _stack = serde_json::from_value::(self.stack.body.clone()); let mut services = indexmap::IndexMap::new(); - match _stack { - Ok(apps) => { - // tracing::debug!("stack item {:?}", apps.custom.web); + match _stack { + Ok(apps) => { for app_type in apps.custom.web { - let code = app_type.app.code.clone().to_owned(); - let mut service = Service { - image: Some(app_type.app.docker_image.to_string()), - ..Default::default() - }; - - let ports: Vec = app_type.app.ports - .unwrap() - .iter() - .map(|x| x.try_into().unwrap()) - .collect(); - - let volumes: Vec = app_type.app.volumes - .unwrap() - .iter() - .map(|x| x.try_into().unwrap()) - .collect(); - - let mut envs = IndexMap::new(); - for item in app_type.app.environment.environment.unwrap() { - let items = item - .into_iter() - .map(|(k, v)| (k, Some(SingleValue::String(v.clone())))) - .collect::>(); - - envs.extend(items); - } - // tracing::debug!("envs: {:?}", envs); - service.ports = Ports::Long(ports); - service.restart = Some("always".to_owned()); - service.volumes = Volumes::Advanced(volumes); - service.environment = Environment::KvPair(envs); - // tracing::debug!("service 1 {:?}", &service); - services.insert( - code, - Some(service), - ); + // let service = create_service(app_type.app.clone()); + let service = app_type.app.try_into_service(); + services.insert(app_type.app.code.clone().to_owned(), Some(service)); } - if let Some(srvs) = apps.custom.service { - - if !srvs.is_empty() { - - for app_type in srvs { - let code = app_type.app.code.to_owned(); - let mut service = Service { - image: Some(app_type.app.docker_image.to_string()), - ..Default::default() - }; - - let ports: Vec = app_type.app.ports - .unwrap() - .iter() - .map(|x| x.try_into().unwrap()) - .collect(); - - service.ports = Ports::Long(ports); - service.restart = Some("always".to_owned()); - services.insert( - code, - Some(service), - ); - } - // tracing::debug!("services {:?}", services); + for app_type in srvs { + // let service = create_service(app_type.app.clone()); + let service = app_type.app.try_into_service(); + services.insert(app_type.app.code.clone().to_owned(), Some(service)); } } if let Some(features) = apps.custom.feature { - - if !features.is_empty() { - - for app_type in features { - let code = app_type.app.code.to_owned(); - let mut service = Service { - // image: Some(app.dockerhub_image.as_ref().unwrap().to_owned()), - image: Some(app_type.app.docker_image.to_string()), - ..Default::default() - }; - - let ports: Vec = app_type.app.ports - .unwrap() - .iter() - .map(|x| x.try_into().unwrap()) - .collect(); - service.ports = Ports::Long(ports); - service.restart = Some("always".to_owned()); - services.insert( - code, - Some(service), - ); - } - // tracing::debug!("services### {:?}", &service); + for app_type in features { + // let service = create_service(app_type.app.clone()); + let service = app_type.app.try_into_service(); + services.insert(app_type.app.code.clone().to_owned(), Some(service)); } } + tracing::debug!("services {:?}", &services); } Err(e) => { tracing::debug!("Unpack stack form error {:?}", e); - () } } - let compose_content = Compose { version: Some("3.8".to_string()), services: { From f1d0c334b5b3df0b0ee1928b213185d6afdee434 Mon Sep 17 00:00:00 2001 From: vsilent Date: Sat, 9 Dec 2023 17:06:16 +0200 Subject: [PATCH 049/284] walk through app types optimized --- src/helpers/stack/builder.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index e7826f2..dc10fa0 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -1,8 +1,6 @@ -use std::collections::HashMap; use indexmap::IndexMap; use crate::helpers::stack::dctypes::{Compose, Port, Ports, PublishedPort, Service, Services, Volumes, Environment, Entrypoint, AdvancedVolumes, SingleValue}; use serde_yaml; -use crate::forms; use crate::forms::{StackForm, stack, Web, Feature, App}; use crate::models::stack::Stack; #[derive(Clone, Debug)] From 107a66bb743b541dd0ad3dd1c4e47dff2725c074 Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 9 Dec 2023 19:48:00 +0200 Subject: [PATCH 050/284] issue-auth db_count_clients_by_user --- src/routes/client/add.rs | 58 ++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 32 deletions(-) diff --git a/src/routes/client/add.rs b/src/routes/client/add.rs index 2a0757e..b07e8a7 100644 --- a/src/routes/client/add.rs +++ b/src/routes/client/add.rs @@ -26,38 +26,10 @@ pub async fn add_handler_inner( settings: web::Data, pool: web::Data, ) -> Result { - let query_span = tracing::info_span!("Counting the user's clients"); - - match sqlx::query!( - r#" - SELECT - count(*) as client_count - FROM client c - WHERE c.user_id = $1 - "#, - user_id.clone(), - ) - .fetch_one(pool.get_ref()) - .instrument(query_span) - .await - { - Ok(result) => { - let client_count = result.client_count.unwrap(); - if client_count >= settings.max_clients_number { - tracing::error!( - "Too many clients. The user {} has {} clients", - user_id, - client_count - ); - - return Err("Too many clients created".to_string()); - } - } - Err(e) => { - tracing::error!("Failed to execute query: {:?}", e); - return Err("Internal Server Error".to_string()); - } - }; + let client_count = db_count_client_by_user(pool.get_ref(), user_id).await?; + if client_count >= settings.max_clients_number { + return Err("Too many clients created".to_string()); + } let mut client = models::Client::default(); client.user_id = user_id.clone(); @@ -91,3 +63,25 @@ pub async fn add_handler_inner( } } } + +async fn db_count_client_by_user(pool: &PgPool , user_id: &String) -> Result { + let query_span = tracing::info_span!("Counting the user's clients"); + + sqlx::query!( + r#" + SELECT + count(*) as client_count + FROM client c + WHERE c.user_id = $1 + "#, + user_id.clone(), + ) + .fetch_one(pool) + .instrument(query_span) + .await + .map(|result| {result.client_count.unwrap()}) + .map_err(|err| { + tracing::error!("Failed to execute query: {:?}", err); + "Internal Server Error".to_string() + }) +} From 581786d90701a463ca9408bce58e67618b65eec5 Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 9 Dec 2023 20:22:53 +0200 Subject: [PATCH 051/284] issue-auth src/routes/client/add.rs --- src/models/mod.rs | 1 + src/routes/client/add.rs | 73 +++++++++++++++++++++------------------- 2 files changed, 39 insertions(+), 35 deletions(-) diff --git a/src/models/mod.rs b/src/models/mod.rs index 32ecf55..b695114 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -6,3 +6,4 @@ pub mod user; pub use client::*; pub use rating::*; pub use stack::*; +pub use user::*; diff --git a/src/routes/client/add.rs b/src/routes/client/add.rs index b07e8a7..8883f25 100644 --- a/src/routes/client/add.rs +++ b/src/routes/client/add.rs @@ -2,7 +2,6 @@ use crate::configuration::Settings; use crate::helpers::client; use crate::helpers::JsonResponse; use crate::models; -use crate::models::user::User; use actix_web::{post, web, Responder, Result}; use sqlx::PgPool; use tracing::Instrument; @@ -11,7 +10,7 @@ use std::sync::Arc; #[tracing::instrument(name = "Add client.")] #[post("")] pub async fn add_handler( - user: web::ReqData>, + user: web::ReqData>, settings: web::Data, pool: web::Data, ) -> Result { @@ -26,45 +25,16 @@ pub async fn add_handler_inner( settings: web::Data, pool: web::Data, ) -> Result { - let client_count = db_count_client_by_user(pool.get_ref(), user_id).await?; + let client_count = db_count_clients_by_user(pool.get_ref(), user_id).await?; if client_count >= settings.max_clients_number { return Err("Too many clients created".to_string()); } - let mut client = models::Client::default(); - client.user_id = user_id.clone(); - client.secret = client::generate_secret(pool.get_ref(), 255) - .await - .map(|s| Some(s))?; - - let query_span = tracing::info_span!("Saving new client into the database"); - match sqlx::query!( - r#" - INSERT INTO client (user_id, secret, created_at, updated_at) - VALUES ($1, $2, NOW() at time zone 'utc', NOW() at time zone 'utc') - RETURNING id - "#, - client.user_id.clone(), - client.secret, - ) - .fetch_one(pool.get_ref()) - .instrument(query_span) - .await - { - Ok(result) => { - tracing::info!("New client {} have been saved to database", result.id); - client.id = result.id; - - return Ok(client); - } - Err(e) => { - tracing::error!("Failed to execute query: {:?}", e); - return Err("Failed to insert".to_string()); - } - } + let client = create_client(pool.get_ref(), user_id).await?; + db_insert_client(pool.get_ref(), client).await } -async fn db_count_client_by_user(pool: &PgPool , user_id: &String) -> Result { +async fn db_count_clients_by_user(pool: &PgPool , user_id: &String) -> Result { let query_span = tracing::info_span!("Counting the user's clients"); sqlx::query!( @@ -85,3 +55,36 @@ async fn db_count_client_by_user(pool: &PgPool , user_id: &String) -> Result Result { + let query_span = tracing::info_span!("Saving new client into the database"); + sqlx::query!( + r#" + INSERT INTO client (user_id, secret, created_at, updated_at) + VALUES ($1, $2, NOW() at time zone 'utc', NOW() at time zone 'utc') + RETURNING id + "#, + client.user_id.clone(), + client.secret, + ) + .fetch_one(pool) + .instrument(query_span) + .await + .map(move |result| { + client.id = result.id; + client + }).map_err(|e| { + tracing::error!("Failed to execute query: {:?}", e); + "Failed to insert".to_string() + }) +} + +async fn create_client(pool: &PgPool, user_id: &String) -> Result { + let mut client = models::Client::default(); + client.user_id = user_id.clone(); + client.secret = client::generate_secret(pool, 255) + .await + .map(|s| Some(s))?; + + Ok(client) +} From 7669952f1a773971a0fc603bf3533eaf7fd35fe6 Mon Sep 17 00:00:00 2001 From: petru Date: Sun, 10 Dec 2023 08:48:33 +0200 Subject: [PATCH 052/284] issue-auth disable client route --- src/routes/client/disable.rs | 83 +++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 34 deletions(-) diff --git a/src/routes/client/disable.rs b/src/routes/client/disable.rs index c80df8c..921eaa1 100644 --- a/src/routes/client/disable.rs +++ b/src/routes/client/disable.rs @@ -1,7 +1,6 @@ use crate::configuration::Settings; use crate::helpers::JsonResponse; -use crate::models::user::User; -use crate::models::Client; +use crate::models; use actix_web::{error::ErrorInternalServerError, put, web, Responder, Result}; use sqlx::PgPool; use tracing::Instrument; @@ -10,61 +9,77 @@ use std::sync::Arc; #[tracing::instrument(name = "Disable client.")] #[put("/{id}/disable")] pub async fn disable_handler( - user: web::ReqData>, + user: web::ReqData>, settings: web::Data, pool: web::Data, path: web::Path<(i32,)>, ) -> Result { - let client_id = path.0; + match async { + let client_id = path.0; + let mut client = db_fetch_client_by_id(pool.get_ref(), client_id).await?; + if client.secret.is_none() { + return Err("client is not active".to_string()); + } + + client.secret = None; + db_update_client(pool.get_ref(), client).await + }.await { + Ok(msg) => { + JsonResponse::::build().ok(msg) + } + Err(msg) => { + JsonResponse::::build().bad_request(msg) + } + } +} + +async fn db_fetch_client_by_id(pool: &PgPool, id: i32) -> Result { let query_span = tracing::info_span!("Fetching the client by ID"); - let mut client: Client = match sqlx::query_as!( - Client, + sqlx::query_as!( + models::Client, r#" SELECT id, user_id, secret FROM client c WHERE c.id = $1 "#, - client_id, + id, ) - .fetch_one(pool.get_ref()) + .fetch_one(pool) .instrument(query_span) .await - { - Ok(client) if client.secret.is_some() => Ok(client), - Ok(_client) => Err("client is not active"), - Err(sqlx::Error::RowNotFound) => Err("client not found"), - Err(e) => { - tracing::error!("Failed to execute fetch query: {:?}", e); - Err("") + .map_err(|e| { + match e { + sqlx::Error::RowNotFound => "client not found".to_string(), + s => { + tracing::error!("Failed to execute fetch query: {:?}", s); + "".to_string() + } } - } - .map_err(|s| { - ErrorInternalServerError(JsonResponse::::build().set_msg(s).to_string()) - })?; + }) +} - client.secret = None; +async fn db_update_client(pool: &PgPool, client: models::Client) -> Result { let query_span = tracing::info_span!("Updating client into the database"); - match sqlx::query!( + sqlx::query!( r#" UPDATE client SET - secret=null, + secret=$1, updated_at=NOW() at time zone 'utc' - WHERE id = $1 + WHERE id = $2 "#, + client.secret, client.id ) - .execute(pool.get_ref()) + .execute(pool) .instrument(query_span) .await - { - Ok(_) => { - tracing::info!("Client {} have been saved to database", client.id); - JsonResponse::build().set_item(client).ok("success") - } - Err(e) => { - tracing::error!("Failed to execute query: {:?}", e); - JsonResponse::build().bad_request("") - } - } + .map(|_|{ + tracing::info!("Client {} have been saved to database", client.id); + "success".to_string() + }) + .map_err(|err| { + tracing::error!("Failed to execute query: {:?}", err); + "".to_string() + }) } From e8f63e6d32133ae8d911ac215d242c707afa95bf Mon Sep 17 00:00:00 2001 From: petru Date: Sun, 10 Dec 2023 09:04:44 +0200 Subject: [PATCH 053/284] issue-auth optimize /client/{id}/enable --- src/routes/client/disable.rs | 10 ++--- src/routes/client/enable.rs | 83 ++++++++++++++++++++---------------- 2 files changed, 52 insertions(+), 41 deletions(-) diff --git a/src/routes/client/disable.rs b/src/routes/client/disable.rs index 921eaa1..a513bd5 100644 --- a/src/routes/client/disable.rs +++ b/src/routes/client/disable.rs @@ -1,7 +1,7 @@ use crate::configuration::Settings; use crate::helpers::JsonResponse; use crate::models; -use actix_web::{error::ErrorInternalServerError, put, web, Responder, Result}; +use actix_web::{put, web, Responder, Result}; use sqlx::PgPool; use tracing::Instrument; use std::sync::Arc; @@ -24,8 +24,8 @@ pub async fn disable_handler( client.secret = None; db_update_client(pool.get_ref(), client).await }.await { - Ok(msg) => { - JsonResponse::::build().ok(msg) + Ok(client) => { + JsonResponse::build().set_item(client).ok("success") } Err(msg) => { JsonResponse::::build().bad_request(msg) @@ -59,7 +59,7 @@ async fn db_fetch_client_by_id(pool: &PgPool, id: i32) -> Result Result { +async fn db_update_client(pool: &PgPool, client: models::Client) -> Result { let query_span = tracing::info_span!("Updating client into the database"); sqlx::query!( r#" @@ -76,7 +76,7 @@ async fn db_update_client(pool: &PgPool, client: models::Client) -> Result>, + user: web::ReqData>, settings: web::Data, pool: web::Data, path: web::Path<(i32,)>, ) -> Result { - let client_id = path.0; + match async { + let client_id = path.0; + let mut client = db_fetch_client_by_id(pool.get_ref(), client_id).await?; + if client.secret.is_some() { + return Err("client is already active".to_string()); + } + + client.secret = Some(client::generate_secret(pool.get_ref(), 255).await?); + db_update_client(pool.get_ref(), client).await + }.await { + Ok(client) => { + JsonResponse::build().set_item(client).ok("success") + } + Err(msg) => { + JsonResponse::::build().bad_request(msg) + } + } +} + +async fn db_fetch_client_by_id(pool: &PgPool, id: i32) -> Result { let query_span = tracing::info_span!("Fetching the client by ID"); - let mut client: Client = match sqlx::query_as!( - Client, + sqlx::query_as!( + models::Client, r#" SELECT id, user_id, secret FROM client c WHERE c.id = $1 "#, - client_id, + id, ) - .fetch_one(pool.get_ref()) + .fetch_one(pool) .instrument(query_span) .await - { - Ok(client) if client.secret.is_none() => Ok(client), - Ok(_client) => Err("client is already enabled"), - Err(sqlx::Error::RowNotFound) => Err("the client is not found"), - Err(e) => { - tracing::error!("Failed to execute fetch query: {:?}", e); - - Err("") + .map_err(|e| { + match e { + sqlx::Error::RowNotFound => "client not found".to_string(), + s => { + tracing::error!("Failed to execute fetch query: {:?}", s); + "".to_string() + } } - } - .map_err(|s| ErrorBadRequest(JsonResponse::::build().set_msg(s).to_string()))?; - - client.secret = client::generate_secret(pool.get_ref(), 255) - .await - .map(|s| Some(s)) - .map_err(|s| ErrorBadRequest(s))?; + }) +} +async fn db_update_client(pool: &PgPool, client: models::Client) -> Result { let query_span = tracing::info_span!("Updating client into the database"); - match sqlx::query!( + sqlx::query!( r#" UPDATE client SET secret=$1, @@ -59,17 +72,15 @@ pub async fn enable_handler( client.secret, client.id ) - .execute(pool.get_ref()) + .execute(pool) .instrument(query_span) .await - { - Ok(_) => { - tracing::info!("Client {} have been saved to database", client.id); - JsonResponse::build().set_item(client).ok("success") - } - Err(e) => { - tracing::error!("Failed to execute query: {:?}", e); - JsonResponse::build().internal_server_error("") - } - } + .map(|_|{ + tracing::info!("Client {} have been saved to database", client.id); + client + }) + .map_err(|err| { + tracing::error!("Failed to execute query: {:?}", err); + "".to_string() + }) } From f9a31b12b6d3f37e2ba09211bdbfe7e387744b29 Mon Sep 17 00:00:00 2001 From: vsilent Date: Sun, 10 Dec 2023 11:46:47 +0200 Subject: [PATCH 054/284] compose networks, volumes hardcoded --- src/forms/stack.rs | 21 ++++-- src/helpers/stack/builder.rs | 102 +++++++++++++++++++++-------- src/routes/stack/compose.rs | 4 +- tests/custom-stack-payload-11.json | 2 +- 4 files changed, 94 insertions(+), 35 deletions(-) diff --git a/src/forms/stack.rs b/src/forms/stack.rs index f09b052..e0fc876 100644 --- a/src/forms/stack.rs +++ b/src/forms/stack.rs @@ -193,9 +193,16 @@ pub struct Custom { pub project_name: String, pub project_overview: Option, pub project_description: Option, - pub networks: Option>, // all networks + #[serde(flatten)] + pub networks: ComposeNetworks, // all networks } +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct Network { + name: String +} + + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct App { #[serde(rename = "_etag")] @@ -253,7 +260,7 @@ pub struct App { #[serde(flatten)] pub environment: Environment, #[serde(flatten)] - pub network: Networks, + pub network: ServiceNetworks, // #[serde(flatten)] // pub ports: Ports, #[serde(rename(deserialize = "sharedPorts"))] @@ -277,10 +284,14 @@ pub struct Volumes { volumes: Vec } +// pub(crate) type Networks = Option>; +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ServiceNetworks { + pub network: Option> +} #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Networks { - //network: Option> - network: Option +pub struct ComposeNetworks { + pub networks: Option> } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index dc10fa0..1d93623 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -1,7 +1,11 @@ use indexmap::IndexMap; -use crate::helpers::stack::dctypes::{Compose, Port, Ports, PublishedPort, Service, Services, Volumes, Environment, Entrypoint, AdvancedVolumes, SingleValue}; +use crate::helpers::stack::dctypes::{Compose, Port, Ports, PublishedPort, Service, Services, + Volumes, Environment, Entrypoint, AdvancedVolumes, SingleValue, + Networks, TopLevelVolumes, ComposeVolume, ComposeNetwork, + ComposeNetworks, MapOrEmpty, ComposeNetworkSettingDetails, + NetworkSettings}; use serde_yaml; -use crate::forms::{StackForm, stack, Web, Feature, App}; +use crate::forms::{StackForm, stack, App}; use crate::models::stack::Stack; #[derive(Clone, Debug)] struct Config {} @@ -71,6 +75,20 @@ impl TryInto for stack::Port { } } +impl TryInto for stack::ServiceNetworks { + type Error = (); + fn try_into(self) -> Result { + Ok(Networks::Simple(self.network.unwrap())) + } +} + +impl TryInto for stack::ComposeNetworks { + type Error = (); + fn try_into(self) -> Result { + Ok(Networks::Simple(self.networks.unwrap())) + } +} + fn convert_shared_ports(ports: Option>) -> Result, String> { tracing::debug!("convert shared ports {:?}", &ports); @@ -102,6 +120,11 @@ impl TryIntoService for App { ..Default::default() }; + let networks: Networks = self.network + .clone() + .try_into() + .unwrap_or_default(); + let ports: Vec = self.ports .clone() .unwrap_or_default() @@ -126,6 +149,7 @@ impl TryIntoService for App { envs.extend(items); } + service.networks = networks; service.ports = Ports::Long(ports); service.restart = Some("always".to_owned()); service.volumes = Volumes::Advanced(volumes); @@ -135,19 +159,36 @@ impl TryIntoService for App { } } -// fn create_service(app_type: T) -> Service -// where -// T: TryIntoService, -// { -// -// let mut service = Service { -// image: Some(app_type.try_into_service().image.unwrap_or_default()), -// ..Default::default() -// }; -// -// service -// -// } +impl Into>> for stack::ComposeNetworks { + fn into(self) -> IndexMap> { + + tracing::debug!("networks found {:?}", self.networks); + let mut networks = self.networks.unwrap_or(vec![]); + tracing::debug!("networks found {:?}", networks); + let networks = networks + .into_iter() + .map(|net| // ["testnetwork", "testnetwork2"] + (net, + MapOrEmpty::Map( + NetworkSettings { + attachable: false, + driver: None, + driver_opts: Default::default(), + enable_ipv6: false, + internal: false, + external: None, + ipam: None, + labels: Default::default(), + name: Some("Anothername".to_string()), + } + )) + ) + .collect::>(); + tracing::debug!("nets: {:?}", networks); + networks + } +} + impl DcBuilder { pub fn new(stack: Stack) -> Self { @@ -160,20 +201,23 @@ impl DcBuilder { pub fn build(&self) -> Option { tracing::debug!("Start build docker compose from {:?}", &self.stack.body); + let mut compose_content = Compose { + version: Some("3.8".to_string()), + ..Default::default() + }; let _stack = serde_json::from_value::(self.stack.body.clone()); - let mut services = indexmap::IndexMap::new(); + let mut services = IndexMap::new(); + let mut volumes = IndexMap::new(); match _stack { Ok(apps) => { for app_type in apps.custom.web { - // let service = create_service(app_type.app.clone()); let service = app_type.app.try_into_service(); services.insert(app_type.app.code.clone().to_owned(), Some(service)); } if let Some(srvs) = apps.custom.service { for app_type in srvs { - // let service = create_service(app_type.app.clone()); let service = app_type.app.try_into_service(); services.insert(app_type.app.code.clone().to_owned(), Some(service)); } @@ -181,26 +225,30 @@ impl DcBuilder { if let Some(features) = apps.custom.feature { for app_type in features { - // let service = create_service(app_type.app.clone()); let service = app_type.app.try_into_service(); services.insert(app_type.app.code.clone().to_owned(), Some(service)); } } - tracing::debug!("services {:?}", &services); + let volume = ComposeVolume{ + driver: None, + driver_opts: Default::default(), + external: None, + labels: Default::default(), + name: Some("Testvolumes".to_string()), + }; + volumes.insert("mykey".to_string(), MapOrEmpty::Map(volume)); + compose_content.volumes = TopLevelVolumes(volumes); + compose_content.networks = ComposeNetworks(apps.custom.networks.into()); + } Err(e) => { tracing::debug!("Unpack stack form error {:?}", e); } } + tracing::debug!("services {:?}", &services); + compose_content.services = Services(services); - let compose_content = Compose { - version: Some("3.8".to_string()), - services: { - Services(services) - }, - ..Default::default() - }; let fname= format!("./files/{}.yml", self.stack.stack_id); tracing::debug!("Saving docker compose to file {:?}", fname); diff --git a/src/routes/stack/compose.rs b/src/routes/stack/compose.rs index 321f88b..ea768fb 100644 --- a/src/routes/stack/compose.rs +++ b/src/routes/stack/compose.rs @@ -88,11 +88,11 @@ pub async fn admin( .await { Ok(stack) => { - tracing::info!("stack found: {:?}", stack.id); + tracing::info!("Record found: {:?}", stack.id); Some(stack) } Err(sqlx::Error::RowNotFound) => { - tracing::error!("Row not found 404"); + tracing::error!("Record not found"); None } Err(e) => { diff --git a/tests/custom-stack-payload-11.json b/tests/custom-stack-payload-11.json index ab0314d..f5d7106 100644 --- a/tests/custom-stack-payload-11.json +++ b/tests/custom-stack-payload-11.json @@ -1 +1 @@ -{"commonDomain":"justates222t.com","domainList":{},"region":"fsn1","zone":null,"server":"cx21","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":["portainer_ce_feature"],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":true,"disk_type":"pd-standart","cloud_token":"***********","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"web":[{"_etag":null,"_id":180,"_created":"2021-12-17T08:11:40.875486","_updated":"2023-11-21T17:37:24.594545","name":"Airflow","code":"airflow","role":["airflow"],"type":"web","default":true,"popularity":null,"descr":null,"ports":{"private":["31"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":150,"height":150,"image":"7f41d873-2de5-4c6e-a037-42eeff572db6.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":"

Airflow description

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"airflow","form":null,"category":[null],"group":[],"versions":[{"_id":425,"name":"Airflow","version":"2.7.3","update_status":"published","tag":"latest"},{"_id":426,"name":"Airflow","version":"2.7.1-unstable","update_status":"published","tag":"stable"}],"links":[],"domain":"latestports.com","sharedPorts":[{"host_port":"5000","container_port":"5000"}],"main":true,"version":{"_id":426,"name":"Airflow","version":"2.7.1-unstable","update_status":"published","tag":"stable"},"environment":[{"ENV_VAR1":"ENV_VAR1_VALUE"}, {"ENV_VAR2":"ENV_VAR1_VALUe2"}],"network":"testnetwork","restart":"always","volumes":[{"host_path":"/airflow/host/path/","container_path":"/airflow/container/path"}, {"host_path":"/airflow/host/path2/","container_path":"/airflow/container/path2"}]},{"category":[{"name":"integrated_features"}],"name":"CustomNginx","code":"customnginx","domain":"customnginx.latestports.com","sharedPorts":[{"host_port":"80","container_port":"8080"},{"host_port":"443","container_port":"8443"}],"versions":[],"custom":true,"type":"web","main":false,"_id":0,"dockerhub_user":"trydirect","dockerhub_name":"nginx","disk_size":"0.9Gb","ram_size":"1.3Gb","cpu":"0.3","volumes":[{"host_path":"/host/path","container_path":"/container/path"}],"environment":[{"CUSTOM_NGINX_ENV_VAR1":"CUSTOM_NGINX_ENV_VAR1_VALUE"},{"CUSTOM_NGINX_VAR2": "CUSTOM_NGINX_VAR_VALUE2"}, {"CUSTOM_NGINX_ENV_VAR3":"CUSTOM_NGINX_ENV_VAR1_VALUE3"},{"CUSTOM_NGINX_VAR4": "CUSTOM_NGINX_VAR_VALUE4"}],"network":"testnetwork","restart":"always"}],"feature":[{"_etag":null,"_id":198,"_created":"2022-04-27T14:10:27.280327","_updated":"2023-08-03T08:24:18.958721","name":"Portainer CE Feature","code":"portainer_ce_feature","role":["portainer-ce-feature"],"type":"feature","default":null,"popularity":null,"descr":null,"ports":{"public":["9000","8000"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":1138,"height":1138,"image":"08589075-44e6-430e-98a5-f9dcf711e054.svg"},"dark":{}},"category_id":2,"parent_app_id":null,"full_description":null,"description":"

Portainer is a lightweight management UI which allows you to easily manage your different Docker environments (Docker hosts or Swarm clusters)

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.6","ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"portainer-ce-feature","form":null,"category":[{"name":"integrated_features"}],"group":[],"versions":[{"_id":456,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"}],"links":[],"version":{"_id":456,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"},"sharedPorts":[{"host_port":"9000","container_port":"9000"}],"environment":[{"PORTAINER_ENV_VAR1":"PORTAINER_ENV_VAR1_VALUE"}],"volumes":[{"host_path":"/portainer/test/path","container_path":"/portainer/test/path"}],"network":"testnetwork","restart":"always"}],"service":[{"_etag":null,"_id":24,"_created":"2020-06-19T13:07:24.228389","_updated":"2023-11-23T10:18:28.095813","name":"PostgreSQL","code":"postgres","role":["postgres"],"type":"service","default":null,"popularity":null,"descr":null,"ports":{"private":["5432"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":576,"height":594,"image":"fd23f54c-e250-4228-8d56-7e5d93ffb925.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":null,"plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"postgres","form":null,"category":[null],"group":[{"_etag":null,"_id":12,"_created":null,"_updated":null,"name":"Database","code":"database"}],"versions":[{"_id":458,"name":"15","version":"15","update_status":"published","tag":"15"},{"_id":288,"name":"10.22","version":"10.22","update_status":"published","tag":"10.22"},{"_id":303,"name":"13.8","version":"13.8","update_status":"published","tag":"13.8"},{"_id":266,"name":"11","version":"11","update_status":"published","tag":"11"},{"_id":267,"name":"12.12","version":"12.12","update_status":"published","tag":"12.12"},{"_id":38,"name":"14.5","version":"14.5","update_status":"published","tag":"14.5"},{"_id":596,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"}],"links":[],"domain":"","sharedPorts":[{"host_port":"5432","container_port":"5432"}],"main":false,"version":{"_id":596,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"},"environment":[{"POSTGRES_ENV_VAR1":"POSTGRES_ENV_VAR1_VALUE"},{"POSTGRES_ENV_VAR2":"POSTGRES_ENV_VAR2_VALUE"}],"network":"testnetwork","restart":"always","volumes":[{"host_path":"./pg.conf","container_path":"/etc/postgres/pg.conf"}]}],"servers_count":3,"project_name":"LatestPorts","custom_stack_code":"latestports","project_git_url":"https://github.com/latestports","custom_stack_category":[],"networks":["testnetwork","testnetwork2"]}} \ No newline at end of file +{"commonDomain":"justates222t.com","domainList":{},"region":"fsn1","zone":null,"server":"cx21","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":["portainer_ce_feature"],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":true,"disk_type":"pd-standart","cloud_token":"***********","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"web":[{"_etag":null,"_id":180,"_created":"2021-12-17T08:11:40.875486","_updated":"2023-11-21T17:37:24.594545","name":"Airflow","code":"airflow","role":["airflow"],"type":"web","default":true,"popularity":null,"descr":null,"ports":{"private":["31"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":150,"height":150,"image":"7f41d873-2de5-4c6e-a037-42eeff572db6.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":"

Airflow description

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"airflow","form":null,"category":[null],"group":[],"versions":[{"_id":425,"name":"Airflow","version":"2.7.3","update_status":"published","tag":"latest"},{"_id":426,"name":"Airflow","version":"2.7.1-unstable","update_status":"published","tag":"stable"}],"links":[],"domain":"latestports.com","sharedPorts":[{"host_port":"5000","container_port":"5000"}],"main":true,"version":{"_id":426,"name":"Airflow","version":"2.7.1-unstable","update_status":"published","tag":"stable"},"environment":[{"ENV_VAR1":"ENV_VAR1_VALUE"}, {"ENV_VAR2":"ENV_VAR1_VALUe2"}],"network":["testnetwork"],"restart":"always","volumes":[{"host_path":"/airflow/host/path/","container_path":"/airflow/container/path"}, {"host_path":"/airflow/host/path2/","container_path":"/airflow/container/path2"}]},{"category":[{"name":"integrated_features"}],"name":"CustomNginx","code":"customnginx","domain":"customnginx.latestports.com","sharedPorts":[{"host_port":"80","container_port":"8080"},{"host_port":"443","container_port":"8443"}],"versions":[],"custom":true,"type":"web","main":false,"_id":0,"dockerhub_user":"trydirect","dockerhub_name":"nginx","disk_size":"0.9Gb","ram_size":"1.3Gb","cpu":"0.3","volumes":[{"host_path":"/host/path","container_path":"/container/path"}],"environment":[{"CUSTOM_NGINX_ENV_VAR1":"CUSTOM_NGINX_ENV_VAR1_VALUE"},{"CUSTOM_NGINX_VAR2": "CUSTOM_NGINX_VAR_VALUE2"}, {"CUSTOM_NGINX_ENV_VAR3":"CUSTOM_NGINX_ENV_VAR1_VALUE3"},{"CUSTOM_NGINX_VAR4": "CUSTOM_NGINX_VAR_VALUE4"}],"network":["testnetwork"],"restart":"always"}],"feature":[{"_etag":null,"_id":198,"_created":"2022-04-27T14:10:27.280327","_updated":"2023-08-03T08:24:18.958721","name":"Portainer CE Feature","code":"portainer_ce_feature","role":["portainer-ce-feature"],"type":"feature","default":null,"popularity":null,"descr":null,"ports":{"public":["9000","8000"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":1138,"height":1138,"image":"08589075-44e6-430e-98a5-f9dcf711e054.svg"},"dark":{}},"category_id":2,"parent_app_id":null,"full_description":null,"description":"

Portainer is a lightweight management UI which allows you to easily manage your different Docker environments (Docker hosts or Swarm clusters)

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.6","ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"portainer-ce-feature","form":null,"category":[{"name":"integrated_features"}],"group":[],"versions":[{"_id":456,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"}],"links":[],"version":{"_id":456,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"},"sharedPorts":[{"host_port":"9000","container_port":"9000"}],"environment":[{"PORTAINER_ENV_VAR1":"PORTAINER_ENV_VAR1_VALUE"}],"volumes":[{"host_path":"/portainer/test/path","container_path":"/portainer/test/path"}],"network":["testnetwork"],"restart":"always"}],"service":[{"_etag":null,"_id":24,"_created":"2020-06-19T13:07:24.228389","_updated":"2023-11-23T10:18:28.095813","name":"PostgreSQL","code":"postgres","role":["postgres"],"type":"service","default":null,"popularity":null,"descr":null,"ports":{"private":["5432"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":576,"height":594,"image":"fd23f54c-e250-4228-8d56-7e5d93ffb925.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":null,"plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"postgres","form":null,"category":[null],"group":[{"_etag":null,"_id":12,"_created":null,"_updated":null,"name":"Database","code":"database"}],"versions":[{"_id":458,"name":"15","version":"15","update_status":"published","tag":"15"},{"_id":288,"name":"10.22","version":"10.22","update_status":"published","tag":"10.22"},{"_id":303,"name":"13.8","version":"13.8","update_status":"published","tag":"13.8"},{"_id":266,"name":"11","version":"11","update_status":"published","tag":"11"},{"_id":267,"name":"12.12","version":"12.12","update_status":"published","tag":"12.12"},{"_id":38,"name":"14.5","version":"14.5","update_status":"published","tag":"14.5"},{"_id":596,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"}],"links":[],"domain":"","sharedPorts":[{"host_port":"5432","container_port":"5432"}],"main":false,"version":{"_id":596,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"},"environment":[{"POSTGRES_ENV_VAR1":"POSTGRES_ENV_VAR1_VALUE"},{"POSTGRES_ENV_VAR2":"POSTGRES_ENV_VAR2_VALUE"}],"network":["testnetwork"],"restart":"always","volumes":[{"host_path":"./pg.conf","container_path":"/etc/postgres/pg.conf"}]}],"servers_count":3,"project_name":"LatestPorts","custom_stack_code":"latestports","project_git_url":"https://github.com/latestports","custom_stack_category":[],"networks":["testnetwork","testnetwork2"]}} \ No newline at end of file From 24953ffde2ceba9bd7cdeb70b8cdba3fd04d37f7 Mon Sep 17 00:00:00 2001 From: vsilent Date: Mon, 11 Dec 2023 17:32:25 +0200 Subject: [PATCH 055/284] named volumes from each service --- src/helpers/stack/builder.rs | 84 ++++++++++++++++++++++-------- src/routes/stack/deploy.rs | 1 - tests/custom-stack-payload-11.json | 2 +- 3 files changed, 62 insertions(+), 25 deletions(-) diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 1d93623..c7f18eb 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -5,7 +5,7 @@ use crate::helpers::stack::dctypes::{Compose, Port, Ports, PublishedPort, Servic ComposeNetworks, MapOrEmpty, ComposeNetworkSettingDetails, NetworkSettings}; use serde_yaml; -use crate::forms::{StackForm, stack, App}; +use crate::forms::{StackForm, stack, App, Volume, Web}; use crate::models::stack::Stack; #[derive(Clone, Debug)] struct Config {} @@ -32,10 +32,10 @@ impl Default for Port{ #[derive(Clone, Debug)] pub struct DcBuilder { config: Config, - pub(crate) stack: Stack + pub(crate) stack: Stack, } -impl TryInto for stack::Volume { +impl TryInto for Volume { type Error = String; fn try_into(self) -> Result { @@ -109,6 +109,16 @@ fn convert_shared_ports(ports: Option>) -> Result, St Ok(_ports) } +fn is_named_docker_volume(volume: &str) -> bool { + // Docker named volumes typically don't contain special characters or slashes + // They are alphanumeric and may include underscores or hyphens + let is_alphanumeric = volume + .chars() + .all(|c| c.is_alphanumeric() || c == '_' || c == '-'); + let does_not_contain_slash = !volume.contains('/'); + is_alphanumeric && does_not_contain_slash +} + trait TryIntoService { fn try_into_service(&self) -> Service; } @@ -136,7 +146,9 @@ impl TryIntoService for App { .clone() .unwrap_or_default() .into_iter() - .map(|x| x.try_into().unwrap()) + .map(|x| { + x.try_into().unwrap() + }) .collect(); let mut envs = IndexMap::new(); @@ -162,12 +174,11 @@ impl TryIntoService for App { impl Into>> for stack::ComposeNetworks { fn into(self) -> IndexMap> { - tracing::debug!("networks found {:?}", self.networks); + // tracing::debug!("networks found {:?}", self.networks); let mut networks = self.networks.unwrap_or(vec![]); - tracing::debug!("networks found {:?}", networks); let networks = networks .into_iter() - .map(|net| // ["testnetwork", "testnetwork2"] + .map(|net| (net, MapOrEmpty::Map( NetworkSettings { @@ -177,28 +188,56 @@ impl Into>> for stack::ComposeNetwo enable_ipv6: false, internal: false, external: None, + // external: Some(ComposeNetwork::Bool(true)), ipam: None, labels: Default::default(), - name: Some("Anothername".to_string()), + name: Some("default".to_string()), } )) ) .collect::>(); - tracing::debug!("nets: {:?}", networks); networks } } + +pub fn extract_named_volumes(app: App) -> IndexMap> { + + let mut named_volumes = IndexMap::default(); + + let volumes = app.volumes + .unwrap() + .into_iter() + .filter(|volume| is_named_docker_volume( + volume.host_path.clone().unwrap().as_str()) + ) + .map(|volume| { + let k = volume.host_path.clone().unwrap(); + (k.clone(), MapOrEmpty::Map(ComposeVolume { + driver: None, + driver_opts: Default::default(), + external: None, + labels: Default::default(), + name: Some(k.clone()) + })) + }) + .collect::>>(); + + named_volumes.extend(volumes); + // tracing::debug!("Named volumes: {:?}", named_volumes); + + named_volumes +} + impl DcBuilder { pub fn new(stack: Stack) -> Self { DcBuilder { config: Config::default(), - stack: stack, + stack, } } - pub fn build(&self) -> Option { tracing::debug!("Start build docker compose from {:?}", &self.stack.body); let mut compose_content = Compose { @@ -207,19 +246,21 @@ impl DcBuilder { }; let _stack = serde_json::from_value::(self.stack.body.clone()); let mut services = IndexMap::new(); - let mut volumes = IndexMap::new(); + let mut named_volumes = IndexMap::default(); match _stack { Ok(apps) => { - for app_type in apps.custom.web { + for app_type in &apps.custom.web { let service = app_type.app.try_into_service(); services.insert(app_type.app.code.clone().to_owned(), Some(service)); + named_volumes.extend(extract_named_volumes(app_type.app.clone())); } if let Some(srvs) = apps.custom.service { for app_type in srvs { let service = app_type.app.try_into_service(); services.insert(app_type.app.code.clone().to_owned(), Some(service)); + named_volumes.extend(extract_named_volumes(app_type.app.clone())); } } @@ -227,19 +268,16 @@ impl DcBuilder { for app_type in features { let service = app_type.app.try_into_service(); services.insert(app_type.app.code.clone().to_owned(), Some(service)); + named_volumes.extend(extract_named_volumes(app_type.app.clone())); } } - let volume = ComposeVolume{ - driver: None, - driver_opts: Default::default(), - external: None, - labels: Default::default(), - name: Some("Testvolumes".to_string()), - }; - volumes.insert("mykey".to_string(), MapOrEmpty::Map(volume)); - compose_content.volumes = TopLevelVolumes(volumes); - compose_content.networks = ComposeNetworks(apps.custom.networks.into()); + let networks = apps.custom.networks.clone(); + compose_content.networks = ComposeNetworks(networks.into()); + + if !named_volumes.is_empty() { + compose_content.volumes = TopLevelVolumes(named_volumes); + } } Err(e) => { diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs index b0f512c..0f14dd8 100644 --- a/src/routes/stack/deploy.rs +++ b/src/routes/stack/deploy.rs @@ -15,7 +15,6 @@ use lapin::{ use crate::configuration::Settings; use crate::helpers::JsonResponse; use crate::helpers::stack::builder::DcBuilder; -use futures_lite::stream::StreamExt; use crate::forms::StackPayload; diff --git a/tests/custom-stack-payload-11.json b/tests/custom-stack-payload-11.json index f5d7106..811f74f 100644 --- a/tests/custom-stack-payload-11.json +++ b/tests/custom-stack-payload-11.json @@ -1 +1 @@ -{"commonDomain":"justates222t.com","domainList":{},"region":"fsn1","zone":null,"server":"cx21","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":["portainer_ce_feature"],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":true,"disk_type":"pd-standart","cloud_token":"***********","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"web":[{"_etag":null,"_id":180,"_created":"2021-12-17T08:11:40.875486","_updated":"2023-11-21T17:37:24.594545","name":"Airflow","code":"airflow","role":["airflow"],"type":"web","default":true,"popularity":null,"descr":null,"ports":{"private":["31"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":150,"height":150,"image":"7f41d873-2de5-4c6e-a037-42eeff572db6.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":"

Airflow description

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"airflow","form":null,"category":[null],"group":[],"versions":[{"_id":425,"name":"Airflow","version":"2.7.3","update_status":"published","tag":"latest"},{"_id":426,"name":"Airflow","version":"2.7.1-unstable","update_status":"published","tag":"stable"}],"links":[],"domain":"latestports.com","sharedPorts":[{"host_port":"5000","container_port":"5000"}],"main":true,"version":{"_id":426,"name":"Airflow","version":"2.7.1-unstable","update_status":"published","tag":"stable"},"environment":[{"ENV_VAR1":"ENV_VAR1_VALUE"}, {"ENV_VAR2":"ENV_VAR1_VALUe2"}],"network":["testnetwork"],"restart":"always","volumes":[{"host_path":"/airflow/host/path/","container_path":"/airflow/container/path"}, {"host_path":"/airflow/host/path2/","container_path":"/airflow/container/path2"}]},{"category":[{"name":"integrated_features"}],"name":"CustomNginx","code":"customnginx","domain":"customnginx.latestports.com","sharedPorts":[{"host_port":"80","container_port":"8080"},{"host_port":"443","container_port":"8443"}],"versions":[],"custom":true,"type":"web","main":false,"_id":0,"dockerhub_user":"trydirect","dockerhub_name":"nginx","disk_size":"0.9Gb","ram_size":"1.3Gb","cpu":"0.3","volumes":[{"host_path":"/host/path","container_path":"/container/path"}],"environment":[{"CUSTOM_NGINX_ENV_VAR1":"CUSTOM_NGINX_ENV_VAR1_VALUE"},{"CUSTOM_NGINX_VAR2": "CUSTOM_NGINX_VAR_VALUE2"}, {"CUSTOM_NGINX_ENV_VAR3":"CUSTOM_NGINX_ENV_VAR1_VALUE3"},{"CUSTOM_NGINX_VAR4": "CUSTOM_NGINX_VAR_VALUE4"}],"network":["testnetwork"],"restart":"always"}],"feature":[{"_etag":null,"_id":198,"_created":"2022-04-27T14:10:27.280327","_updated":"2023-08-03T08:24:18.958721","name":"Portainer CE Feature","code":"portainer_ce_feature","role":["portainer-ce-feature"],"type":"feature","default":null,"popularity":null,"descr":null,"ports":{"public":["9000","8000"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":1138,"height":1138,"image":"08589075-44e6-430e-98a5-f9dcf711e054.svg"},"dark":{}},"category_id":2,"parent_app_id":null,"full_description":null,"description":"

Portainer is a lightweight management UI which allows you to easily manage your different Docker environments (Docker hosts or Swarm clusters)

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.6","ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"portainer-ce-feature","form":null,"category":[{"name":"integrated_features"}],"group":[],"versions":[{"_id":456,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"}],"links":[],"version":{"_id":456,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"},"sharedPorts":[{"host_port":"9000","container_port":"9000"}],"environment":[{"PORTAINER_ENV_VAR1":"PORTAINER_ENV_VAR1_VALUE"}],"volumes":[{"host_path":"/portainer/test/path","container_path":"/portainer/test/path"}],"network":["testnetwork"],"restart":"always"}],"service":[{"_etag":null,"_id":24,"_created":"2020-06-19T13:07:24.228389","_updated":"2023-11-23T10:18:28.095813","name":"PostgreSQL","code":"postgres","role":["postgres"],"type":"service","default":null,"popularity":null,"descr":null,"ports":{"private":["5432"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":576,"height":594,"image":"fd23f54c-e250-4228-8d56-7e5d93ffb925.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":null,"plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"postgres","form":null,"category":[null],"group":[{"_etag":null,"_id":12,"_created":null,"_updated":null,"name":"Database","code":"database"}],"versions":[{"_id":458,"name":"15","version":"15","update_status":"published","tag":"15"},{"_id":288,"name":"10.22","version":"10.22","update_status":"published","tag":"10.22"},{"_id":303,"name":"13.8","version":"13.8","update_status":"published","tag":"13.8"},{"_id":266,"name":"11","version":"11","update_status":"published","tag":"11"},{"_id":267,"name":"12.12","version":"12.12","update_status":"published","tag":"12.12"},{"_id":38,"name":"14.5","version":"14.5","update_status":"published","tag":"14.5"},{"_id":596,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"}],"links":[],"domain":"","sharedPorts":[{"host_port":"5432","container_port":"5432"}],"main":false,"version":{"_id":596,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"},"environment":[{"POSTGRES_ENV_VAR1":"POSTGRES_ENV_VAR1_VALUE"},{"POSTGRES_ENV_VAR2":"POSTGRES_ENV_VAR2_VALUE"}],"network":["testnetwork"],"restart":"always","volumes":[{"host_path":"./pg.conf","container_path":"/etc/postgres/pg.conf"}]}],"servers_count":3,"project_name":"LatestPorts","custom_stack_code":"latestports","project_git_url":"https://github.com/latestports","custom_stack_category":[],"networks":["testnetwork","testnetwork2"]}} \ No newline at end of file +{"commonDomain":"justates222t.com","domainList":{},"region":"fsn1","zone":null,"server":"cx21","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":["portainer_ce_feature"],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":true,"disk_type":"pd-standart","cloud_token":"***********","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"web":[{"_etag":null,"_id":180,"_created":"2021-12-17T08:11:40.875486","_updated":"2023-11-21T17:37:24.594545","name":"Airflow","code":"airflow","role":["airflow"],"type":"web","default":true,"popularity":null,"descr":null,"ports":{"private":["31"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":150,"height":150,"image":"7f41d873-2de5-4c6e-a037-42eeff572db6.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":"

Airflow description

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"airflow","form":null,"category":[null],"group":[],"versions":[{"_id":425,"name":"Airflow","version":"2.7.3","update_status":"published","tag":"latest"},{"_id":426,"name":"Airflow","version":"2.7.1-unstable","update_status":"published","tag":"stable"}],"links":[],"domain":"latestports.com","sharedPorts":[{"host_port":"5000","container_port":"5000"}],"main":true,"version":{"_id":426,"name":"Airflow","version":"2.7.1-unstable","update_status":"published","tag":"stable"},"environment":[{"ENV_VAR1":"ENV_VAR1_VALUE"}, {"ENV_VAR2":"ENV_VAR1_VALUe2"}],"network":["testnetwork"],"restart":"always","volumes":[{"host_path":"./airflow/host/path/","container_path":"/airflow/container/path"}, {"host_path":"./airflow/host/path2/","container_path":"/airflow/container/path2"}, {"host_path":"airflow","container_path":"/airflow/named/volume/path"}]},{"category":[{"name":"integrated_features"}],"name":"CustomNginx","code":"customnginx","domain":"customnginx.latestports.com","sharedPorts":[{"host_port":"80","container_port":"8080"},{"host_port":"443","container_port":"8443"}],"versions":[],"custom":true,"type":"web","main":false,"_id":0,"dockerhub_user":"trydirect","dockerhub_name":"nginx","disk_size":"0.9Gb","ram_size":"1.3Gb","cpu":"0.3","volumes":[{"host_path":"./host/path","container_path":"/container/path"}, {"host_path": "namedvolume", "container_path": "/container/path/to/"}],"environment":[{"CUSTOM_NGINX_ENV_VAR1":"CUSTOM_NGINX_ENV_VAR1_VALUE"},{"CUSTOM_NGINX_VAR2": "CUSTOM_NGINX_VAR_VALUE2"}, {"CUSTOM_NGINX_ENV_VAR3":"CUSTOM_NGINX_ENV_VAR1_VALUE3"},{"CUSTOM_NGINX_VAR4": "CUSTOM_NGINX_VAR_VALUE4"}],"network":["testnetwork"],"restart":"always"}],"feature":[{"_etag":null,"_id":198,"_created":"2022-04-27T14:10:27.280327","_updated":"2023-08-03T08:24:18.958721","name":"Portainer CE Feature","code":"portainer_ce_feature","role":["portainer-ce-feature"],"type":"feature","default":null,"popularity":null,"descr":null,"ports":{"public":["9000","8000"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":1138,"height":1138,"image":"08589075-44e6-430e-98a5-f9dcf711e054.svg"},"dark":{}},"category_id":2,"parent_app_id":null,"full_description":null,"description":"

Portainer is a lightweight management UI which allows you to easily manage your different Docker environments (Docker hosts or Swarm clusters)

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.6","ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"portainer-ce-feature","form":null,"category":[{"name":"integrated_features"}],"group":[],"versions":[{"_id":456,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"}],"links":[],"version":{"_id":456,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"},"sharedPorts":[{"host_port":"9000","container_port":"9000"}],"environment":[{"PORTAINER_ENV_VAR1":"PORTAINER_ENV_VAR1_VALUE"}],"volumes":[{"host_path":"/portainer/test/path","container_path":"/portainer/test/path"}],"network":["testnetwork"],"restart":"always"}],"service":[{"_etag":null,"_id":24,"_created":"2020-06-19T13:07:24.228389","_updated":"2023-11-23T10:18:28.095813","name":"PostgreSQL","code":"postgres","role":["postgres"],"type":"service","default":null,"popularity":null,"descr":null,"ports":{"private":["5432"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":576,"height":594,"image":"fd23f54c-e250-4228-8d56-7e5d93ffb925.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":null,"plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"postgres","form":null,"category":[null],"group":[{"_etag":null,"_id":12,"_created":null,"_updated":null,"name":"Database","code":"database"}],"versions":[{"_id":458,"name":"15","version":"15","update_status":"published","tag":"15"},{"_id":288,"name":"10.22","version":"10.22","update_status":"published","tag":"10.22"},{"_id":303,"name":"13.8","version":"13.8","update_status":"published","tag":"13.8"},{"_id":266,"name":"11","version":"11","update_status":"published","tag":"11"},{"_id":267,"name":"12.12","version":"12.12","update_status":"published","tag":"12.12"},{"_id":38,"name":"14.5","version":"14.5","update_status":"published","tag":"14.5"},{"_id":596,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"}],"links":[],"domain":"","sharedPorts":[{"host_port":"5432","container_port":"5432"}],"main":false,"version":{"_id":596,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"},"environment":[{"POSTGRES_ENV_VAR1":"POSTGRES_ENV_VAR1_VALUE"},{"POSTGRES_ENV_VAR2":"POSTGRES_ENV_VAR2_VALUE"}],"network":["testnetwork"],"restart":"always","volumes":[{"host_path":"./pg.conf","container_path":"/etc/postgres/pg.conf"}]}],"servers_count":3,"project_name":"LatestPorts","custom_stack_code":"latestports","project_git_url":"https://github.com/latestports","custom_stack_category":[],"networks":["testnetwork","testnetwork2"]}} \ No newline at end of file From 18d20a1bdbe4b63baab5be6f813ae6a6d7abdd3f Mon Sep 17 00:00:00 2001 From: petru Date: Mon, 11 Dec 2023 18:03:45 +0200 Subject: [PATCH 056/284] issue-auth configuration.yaml.dist --- configuration.yaml.dist | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 configuration.yaml.dist diff --git a/configuration.yaml.dist b/configuration.yaml.dist new file mode 100644 index 0000000..030dd49 --- /dev/null +++ b/configuration.yaml.dist @@ -0,0 +1,17 @@ +#auth_url: http://127.0.0.1:8080/me +app_host: 127.0.0.1 +app_port: 8000 +auth_url: https://dev.try.direct/server/user/oauth_server/api/me +max_clients_number: 2 +database: + host: 127.0.0.1 + port: 5432 + username: postgres + password: postgres + database_name: stacker + +amqp: + host: 127.0.0.1 + port: 5672 + username: guest + password: guest From 8ae6b9071834b861a0415f88a6e39fd654fcb5e3 Mon Sep 17 00:00:00 2001 From: vsilent Date: Mon, 11 Dec 2023 19:49:22 +0200 Subject: [PATCH 057/284] always set default_network for testing --- src/forms/stack.rs | 1 + src/helpers/stack/builder.rs | 23 +++++++++++------------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/forms/stack.rs b/src/forms/stack.rs index e0fc876..b67a856 100644 --- a/src/forms/stack.rs +++ b/src/forms/stack.rs @@ -289,6 +289,7 @@ pub struct Volumes { pub struct ServiceNetworks { pub network: Option> } + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct ComposeNetworks { pub networks: Option> diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index c7f18eb..1db77c5 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -78,18 +78,14 @@ impl TryInto for stack::Port { impl TryInto for stack::ServiceNetworks { type Error = (); fn try_into(self) -> Result { - Ok(Networks::Simple(self.network.unwrap())) - } -} - -impl TryInto for stack::ComposeNetworks { - type Error = (); - fn try_into(self) -> Result { - Ok(Networks::Simple(self.networks.unwrap())) + let mut networks = vec!["default_network".to_string()]; + if self.network.is_some() { + networks.append(&mut self.network.unwrap()); + } + Ok(Networks::Simple(networks)) } } - fn convert_shared_ports(ports: Option>) -> Result, String> { tracing::debug!("convert shared ports {:?}", &ports); let mut _ports: Vec = vec![]; @@ -175,7 +171,10 @@ impl Into>> for stack::ComposeNetwo fn into(self) -> IndexMap> { // tracing::debug!("networks found {:?}", self.networks); - let mut networks = self.networks.unwrap_or(vec![]); + let mut networks = vec!["default_network".to_string()]; + if self.networks.is_some() { + networks.append(&mut self.networks.unwrap()); + } let networks = networks .into_iter() .map(|net| @@ -187,8 +186,8 @@ impl Into>> for stack::ComposeNetwo driver_opts: Default::default(), enable_ipv6: false, internal: false, - external: None, - // external: Some(ComposeNetwork::Bool(true)), + // external: None, + external: Some(ComposeNetwork::Bool(true)), ipam: None, labels: Default::default(), name: Some("default".to_string()), From 95ccbd405df627c0362f0536ffde42e506293ddf Mon Sep 17 00:00:00 2001 From: petru Date: Tue, 12 Dec 2023 17:43:38 +0200 Subject: [PATCH 058/284] issue-auth new approach for JsonResponse --- src/helpers/json.rs | 21 ++++++++++----------- src/routes/client/add.rs | 4 ++-- src/routes/client/disable.rs | 22 ++++++++++------------ src/routes/client/enable.rs | 4 ++-- src/routes/client/update.rs | 17 ++++++++--------- src/routes/rating/add.rs | 10 +++++----- src/routes/rating/get.rs | 12 ++++++------ src/routes/stack/add.rs | 13 ++++++------- src/routes/stack/compose.rs | 13 +++++++------ src/routes/stack/deploy.rs | 4 ++-- src/routes/stack/get.rs | 14 +++++++------- src/routes/stack/update.rs | 10 +++++----- src/routes/test/deploy.rs | 2 +- 13 files changed, 71 insertions(+), 75 deletions(-) diff --git a/src/helpers/json.rs b/src/helpers/json.rs index 8990788..629f65e 100644 --- a/src/helpers/json.rs +++ b/src/helpers/json.rs @@ -1,7 +1,6 @@ use actix_web::error::{ErrorBadRequest, ErrorConflict, ErrorInternalServerError, ErrorNotFound}; use actix_web::web::Json; use actix_web::Error; -use actix_web::Result; use serde_derive::Serialize; #[derive(Serialize)] @@ -64,30 +63,30 @@ where serde_json::to_string(&json_response).unwrap() } - pub(crate) fn ok>(self, msg: I) -> Result>, Error> { - Ok(Json(self.set_msg(msg).to_json_response())) + pub(crate) fn ok>(self, msg: I) -> Json> { + Json(self.set_msg(msg).to_json_response()) } pub(crate) fn bad_request>( self, msg: I, - ) -> Result>, Error> { - Err(ErrorBadRequest(self.set_msg(msg).to_string())) + ) -> Error { + ErrorBadRequest(self.set_msg(msg).to_string()) } - pub(crate) fn not_found>(self, msg: I) -> Result>, Error> { - Err(ErrorNotFound(self.set_msg(msg).to_string())) + pub(crate) fn not_found>(self, msg: I) -> Error { + ErrorNotFound(self.set_msg(msg).to_string()) } pub(crate) fn internal_server_error>( self, msg: I, - ) -> Result>, Error> { - Err(ErrorInternalServerError(self.set_msg(msg).to_string())) + ) -> Error { + ErrorInternalServerError(self.set_msg(msg).to_string()) } - pub(crate) fn conflict>(self, msg: I) -> Result>, Error> { - Err(ErrorConflict(self.set_msg(msg).to_string())) + pub(crate) fn conflict>(self, msg: I) -> Error { + ErrorConflict(self.set_msg(msg).to_string()) } } diff --git a/src/routes/client/add.rs b/src/routes/client/add.rs index 8883f25..f922718 100644 --- a/src/routes/client/add.rs +++ b/src/routes/client/add.rs @@ -15,8 +15,8 @@ pub async fn add_handler( pool: web::Data, ) -> Result { match add_handler_inner(&user.id, settings, pool).await { - Ok(client) => JsonResponse::build().set_item(client).ok("Ok"), - Err(msg) => JsonResponse::build().bad_request(msg), + Ok(client) => Ok(JsonResponse::build().set_item(client).ok("Ok")), + Err(msg) => Err(JsonResponse::::build().bad_request(msg)), } } diff --git a/src/routes/client/disable.rs b/src/routes/client/disable.rs index a513bd5..c5d2ac3 100644 --- a/src/routes/client/disable.rs +++ b/src/routes/client/disable.rs @@ -14,23 +14,21 @@ pub async fn disable_handler( pool: web::Data, path: web::Path<(i32,)>, ) -> Result { - match async { let client_id = path.0; - let mut client = db_fetch_client_by_id(pool.get_ref(), client_id).await?; + let mut client = db_fetch_client_by_id(pool.get_ref(), client_id) + .await + .map_err(|msg| JsonResponse::::build().not_found(msg)) + ?; if client.secret.is_none() { - return Err("client is not active".to_string()); + return Err(JsonResponse::::build().bad_request("client is not active")); } client.secret = None; - db_update_client(pool.get_ref(), client).await - }.await { - Ok(client) => { - JsonResponse::build().set_item(client).ok("success") - } - Err(msg) => { - JsonResponse::::build().bad_request(msg) - } - } + let client = db_update_client(pool.get_ref(), client) + .await + .map_err(|msg| JsonResponse::::build().bad_request(msg))?; + + Ok(JsonResponse::build().set_item(client).ok("success")) } async fn db_fetch_client_by_id(pool: &PgPool, id: i32) -> Result { diff --git a/src/routes/client/enable.rs b/src/routes/client/enable.rs index 6f10beb..59bde80 100644 --- a/src/routes/client/enable.rs +++ b/src/routes/client/enable.rs @@ -26,10 +26,10 @@ pub async fn enable_handler( db_update_client(pool.get_ref(), client).await }.await { Ok(client) => { - JsonResponse::build().set_item(client).ok("success") + Ok(JsonResponse::build().set_item(client).ok("success")) } Err(msg) => { - JsonResponse::::build().bad_request(msg) + Err(JsonResponse::::build().bad_request(msg)) } } } diff --git a/src/routes/client/update.rs b/src/routes/client/update.rs index 7aa28eb..0fff40e 100644 --- a/src/routes/client/update.rs +++ b/src/routes/client/update.rs @@ -1,6 +1,5 @@ use crate::helpers::client; -use crate::models::user::User; -use crate::models::Client; +use crate::models; use crate::{configuration::Settings, helpers::JsonResponse}; use actix_web::{error::ErrorBadRequest, put, web, Responder, Result}; use sqlx::PgPool; @@ -10,15 +9,15 @@ use tracing::Instrument; #[tracing::instrument(name = "Update client.")] #[put("/{id}")] pub async fn update_handler( - user: web::ReqData>, + user: web::ReqData>, settings: web::Data, pool: web::Data, path: web::Path<(i32,)>, ) -> Result { let client_id = path.0; let query_span = tracing::info_span!("Fetching the client by ID"); - let mut client: Client = match sqlx::query_as!( - Client, + let mut client: models::Client = match sqlx::query_as!( + models::Client, r#" SELECT id, user_id, secret @@ -40,12 +39,12 @@ pub async fn update_handler( Err("") } } - .map_err(|s| ErrorBadRequest(JsonResponse::::build().set_msg(s).to_string()))?; + .map_err(|s| ErrorBadRequest(JsonResponse::::build().set_msg(s).to_string()))?; client.secret = client::generate_secret(pool.get_ref(), 255) .await .map(|s| Some(s)) - .map_err(|s| ErrorBadRequest(JsonResponse::::build().set_msg(s).to_string()))?; + .map_err(|s| ErrorBadRequest(JsonResponse::::build().set_msg(s).to_string()))?; let query_span = tracing::info_span!("Updating client into the database"); match sqlx::query!( @@ -64,11 +63,11 @@ pub async fn update_handler( { Ok(_) => { tracing::info!("Client {} have been saved to database", client.id); - JsonResponse::build().set_item(client).ok("success") + Ok(JsonResponse::::build().set_item(client).ok("success")) } Err(e) => { tracing::error!("Failed to execute query: {:?}", e); - JsonResponse::build().internal_server_error("") + Err(JsonResponse::::build().internal_server_error("")) } } } diff --git a/src/routes/rating/add.rs b/src/routes/rating/add.rs index 922cee0..5e2e874 100644 --- a/src/routes/rating/add.rs +++ b/src/routes/rating/add.rs @@ -35,7 +35,7 @@ pub async fn add_handler( } Err(e) => { tracing::error!("Failed to fetch product: {:?}, error: {:?}", form.obj_id, e); - return JsonResponse::::build().bad_request("Object not found"); + return Err(JsonResponse::::build().bad_request("Object not found")); } }; @@ -58,12 +58,12 @@ pub async fn add_handler( form.obj_id, form.category ); - return JsonResponse::build().conflict("Already rated"); + return Err(JsonResponse::::build().conflict("Already rated")); } Err(sqlx::Error::RowNotFound) => {} Err(e) => { tracing::error!("Failed to fetch rating, error: {:?}", e); - return JsonResponse::build().internal_server_error("Internal Server Error"); + return Err(JsonResponse::::build().internal_server_error("Internal Server Error")); } } @@ -91,11 +91,11 @@ pub async fn add_handler( Ok(result) => { tracing::info!("New rating {} have been saved to database", result.id); - JsonResponse::build().set_id(result.id).ok("Saved") + Ok(JsonResponse::::build().set_id(result.id).ok("Saved")) } Err(e) => { tracing::error!("Failed to execute query: {:?}", e); - JsonResponse::build().internal_server_error("Failed to insert") + Err(JsonResponse::::build().internal_server_error("Failed to insert")) } } } diff --git a/src/routes/rating/get.rs b/src/routes/rating/get.rs index e781d9a..49fccb4 100644 --- a/src/routes/rating/get.rs +++ b/src/routes/rating/get.rs @@ -29,14 +29,14 @@ pub async fn get_handler( { Ok(rating) => { tracing::info!("rating found: {:?}", rating.id); - return JsonResponse::build().set_item(Some(rating)).ok("OK"); + return Ok(JsonResponse::build().set_item(Some(rating)).ok("OK")); } Err(sqlx::Error::RowNotFound) => { - return JsonResponse::build().not_found(""); + return Err(JsonResponse::::build().not_found("")); } Err(e) => { tracing::error!("Failed to fetch rating, error: {:?}", e); - return JsonResponse::build().internal_server_error(""); + return Err(JsonResponse::::build().internal_server_error("")); } } } @@ -54,14 +54,14 @@ pub async fn list_handler(path: web::Path<()>, pool: web::Data) -> Resul { Ok(rating) => { tracing::info!("Ratings found: {:?}", rating.len()); - return JsonResponse::build().set_list(rating).ok("OK"); + return Ok(JsonResponse::build().set_list(rating).ok("OK")); } Err(sqlx::Error::RowNotFound) => { - return JsonResponse::build().not_found(""); + return Err(JsonResponse::::build().not_found("")); } Err(e) => { tracing::error!("Failed to fetch rating, error: {:?}", e); - return JsonResponse::build().internal_server_error(""); + return Err(JsonResponse::::build().internal_server_error("")); } } } diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index 7a12bfe..690a02a 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -32,7 +32,7 @@ pub async fn add( Ok(f) => f, Err(_err) => { let msg = format!("Invalid data. {:?}", _err); - return JsonResponse::::build().bad_request(msg); + return Err(JsonResponse::::build().bad_request(msg)); } }; @@ -51,13 +51,12 @@ pub async fn add( { Ok(record) => { tracing::info!("record exists: id: {}, name: {}", record.id, record.name); - return JsonResponse::build().conflict("Stack with that name already exists" - .to_owned()); + return Err(JsonResponse::::build().conflict("Stack with that name already exists")); } Err(sqlx::Error::RowNotFound) => {} Err(e) => { tracing::error!("Failed to fetch stack info, error: {:?}", e); - return JsonResponse::build().bad_request(format!("Internal Server Error")); + return Err(JsonResponse::::build().bad_request("Internal Server Error")); } }; @@ -85,7 +84,7 @@ pub async fn add( let errors = form.validate().unwrap_err(); let err_msg = format!("Invalid data received {:?}", &errors.to_string()); tracing::debug!(err_msg); - return JsonResponse::build().bad_request(errors.to_string());// tmp solution + return Err(JsonResponse::::build().bad_request(errors.to_string()));// tmp solution } let body: Value = match serde_json::to_value::(form) { @@ -118,11 +117,11 @@ pub async fn add( "req_id: {} New stack details have been saved to database", request_id ); - return JsonResponse::build().set_id(record.id).ok("OK"); + return Ok(JsonResponse::::build().set_id(record.id).ok("OK")); } Err(e) => { tracing::error!("req_id: {} Failed to execute query: {:?}", request_id, e); - return JsonResponse::build().internal_server_error("Internal Server Error"); + return Err(JsonResponse::::build().internal_server_error("Internal Server Error")); } }; } diff --git a/src/routes/stack/compose.rs b/src/routes/stack/compose.rs index 819a886..b92930b 100644 --- a/src/routes/stack/compose.rs +++ b/src/routes/stack/compose.rs @@ -56,13 +56,14 @@ pub async fn add( let fc = dc.build(); tracing::debug!("Docker compose file content {:?}", fc); - return JsonResponse::build() + return Ok(JsonResponse::build() .set_id(id) .set_item(fc.unwrap()) - .ok("Success"); + .ok("Success") + ); } None => { - return JsonResponse::build().bad_request("Could not generate compose file"); + return Err(JsonResponse::::build().bad_request("Could not generate compose file")); } } } @@ -117,13 +118,13 @@ pub async fn admin( }; // tracing::debug!("Docker compose file content {:?}", fc); - return JsonResponse::build() + return Ok(JsonResponse::build() .set_id(id) - .set_item(fc).ok("Success"); + .set_item(fc).ok("Success")); } None => { - return JsonResponse::build().bad_request("Could not generate compose file"); + return Err(JsonResponse::::build().bad_request("Could not generate compose file")); } } } diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs index d1224c5..1d52caa 100644 --- a/src/routes/stack/deploy.rs +++ b/src/routes/stack/deploy.rs @@ -91,10 +91,10 @@ pub async fn add( assert_eq!(confirm, Confirmation::NotRequested); tracing::debug!("Message sent to rabbitmq"); - return JsonResponse::::build().set_id(id).ok("Success"); + return Ok(JsonResponse::::build().set_id(id).ok("Success")); } None => { - JsonResponse::build().internal_server_error("Deployment failed") + Err(JsonResponse::::build().internal_server_error("Deployment failed")) } } } diff --git a/src/routes/stack/get.rs b/src/routes/stack/get.rs index dc8c09f..88114dc 100644 --- a/src/routes/stack/get.rs +++ b/src/routes/stack/get.rs @@ -1,4 +1,4 @@ -use crate::helpers::{JsonResponse, JsonResponseBuilder}; +use crate::helpers::JsonResponse; use crate::models; use crate::models::user::User; use actix_web::{get, web, Responder, Result}; @@ -31,12 +31,12 @@ pub async fn item( { Ok(stack) => { tracing::info!("Stack found: {:?}", stack.id,); - return JsonResponse::build().set_item(Some(stack)).ok("OK"); + return Ok(JsonResponse::build().set_item(Some(stack)).ok("OK")); } - Err(sqlx::Error::RowNotFound) => JsonResponse::build().not_found("Record not found"), + Err(sqlx::Error::RowNotFound) => Err(JsonResponse::::build().not_found("Record not found")), Err(e) => { tracing::error!("Failed to fetch stack, error: {:?}", e); - return JsonResponse::build().internal_server_error("Could not fetch data"); + return Err(JsonResponse::::build().internal_server_error("Could not fetch data")); } } } @@ -69,15 +69,15 @@ pub async fn list( .await { Ok(list) => { - return JsonResponse::build().set_list(list).ok("OK"); + return Ok(JsonResponse::build().set_list(list).ok("OK")); } Err(sqlx::Error::RowNotFound) => { tracing::error!("No stacks found for user: {:?}", &user.id); - return JsonResponse::build().not_found("No stacks found for user"); + return Err(JsonResponse::::build().not_found("No stacks found for user")); } Err(e) => { tracing::error!("Failed to fetch stack, error: {:?}", e); - return JsonResponse::build().internal_server_error("Could not fetch".to_string()); + return Err(JsonResponse::::build().internal_server_error("Could not fetch")); } } } diff --git a/src/routes/stack/update.rs b/src/routes/stack/update.rs index d51c95f..a418b53 100644 --- a/src/routes/stack/update.rs +++ b/src/routes/stack/update.rs @@ -43,8 +43,8 @@ pub async fn update( } Err(e) => { tracing::error!("Failed to fetch record: {:?}, error: {:?}", id, e); - return JsonResponse::::build() - .not_found(format!("Object not found {}", id)); + return Err(JsonResponse::::build() + .not_found(format!("Object not found {}", id))); } }; @@ -72,7 +72,7 @@ pub async fn update( let errors = form.validate().unwrap_err(); let err_msg = format!("Invalid data received {:?}", &errors.to_string()); tracing::debug!(err_msg); - return JsonResponse::build().bad_request(errors.to_string()); + return Err(JsonResponse::::build().bad_request(errors.to_string())); } let body: Value = match serde_json::to_value::(form.into_inner()) { @@ -106,11 +106,11 @@ pub async fn update( "req_id: {} stack details have been saved to database", request_id ); - return JsonResponse::build().set_id(id).ok("OK"); + return Ok(JsonResponse::::build().set_id(id).ok("OK")); } Err(e) => { tracing::error!("req_id: {} Failed to execute query: {:?}", request_id, e); - return JsonResponse::build().bad_request("Internal Server Error"); + return Err(JsonResponse::::build().bad_request("Internal Server Error")); } }; } diff --git a/src/routes/test/deploy.rs b/src/routes/test/deploy.rs index 51cc201..4f36a3a 100644 --- a/src/routes/test/deploy.rs +++ b/src/routes/test/deploy.rs @@ -13,5 +13,5 @@ struct DeployResponse { #[tracing::instrument(name = "Test deploy.")] #[post("/deploy")] pub async fn handler(client: web::ReqData>) -> Result { - JsonResponse::build().set_item(client.into_inner()).ok("success") + Ok(JsonResponse::build().set_item(client.into_inner()).ok("success")) } From 65d6f431f125a6c7c07aa0f2907973c10133623d Mon Sep 17 00:00:00 2001 From: petru Date: Tue, 12 Dec 2023 18:02:07 +0200 Subject: [PATCH 059/284] issue-auth json. unauthorized response --- src/helpers/json.rs | 7 +++++++ src/middleware/trydirect.rs | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/helpers/json.rs b/src/helpers/json.rs index 629f65e..e92c1f7 100644 --- a/src/helpers/json.rs +++ b/src/helpers/json.rs @@ -85,6 +85,13 @@ where ErrorInternalServerError(self.set_msg(msg).to_string()) } + pub(crate) fn unauthorized>( + self, + msg: I, + ) -> Error { + ErrorUnauthorized(self.set_msg(msg).to_string()) + } + pub(crate) fn conflict>(self, msg: I) -> Error { ErrorConflict(self.set_msg(msg).to_string()) } diff --git a/src/middleware/trydirect.rs b/src/middleware/trydirect.rs index bbe5e4b..823680a 100644 --- a/src/middleware/trydirect.rs +++ b/src/middleware/trydirect.rs @@ -1,5 +1,5 @@ use crate::{models, configuration::Settings, forms::user::UserForm, helpers::JsonResponse}; -use actix_web::{web, dev::ServiceRequest, Error, HttpMessage, error::{ErrorInternalServerError, ErrorUnauthorized}}; +use actix_web::{web, dev::ServiceRequest, Error, HttpMessage}; use actix_web_httpauth::extractors::bearer::BearerAuth; use futures::future::{FutureExt}; use reqwest::header::{ACCEPT, CONTENT_TYPE}; @@ -11,12 +11,12 @@ pub async fn bearer_guard( req: ServiceRequest, credentials: BearerAuth) -> Resu let token = credentials.token(); let user = fetch_user(settings.auth_url.as_str(), token).await; if let Err(err) = user { - return Err((ErrorUnauthorized(JsonResponse::::build().set_msg(err).to_string()), req)); + return Err((JsonResponse::::build().unauthorized(err), req)); } let user = user.unwrap(); if req.extensions_mut().insert(Arc::new(user)).is_some() { - return Err((ErrorUnauthorized(JsonResponse::::build().set_msg("user already logged").to_string()), req)); + return Err((JsonResponse::::build().unauthorized("user already logged"), req)); } Ok(req) From 6630ab74fb16fb5735d877e511b0f8439c74cbd3 Mon Sep 17 00:00:00 2001 From: petru Date: Tue, 12 Dec 2023 18:07:42 +0200 Subject: [PATCH 060/284] issue-auth src/middleware/trydirect.rs --- src/helpers/json.rs | 2 +- src/middleware/trydirect.rs | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/helpers/json.rs b/src/helpers/json.rs index e92c1f7..952d768 100644 --- a/src/helpers/json.rs +++ b/src/helpers/json.rs @@ -1,4 +1,4 @@ -use actix_web::error::{ErrorBadRequest, ErrorConflict, ErrorInternalServerError, ErrorNotFound}; +use actix_web::error::{ErrorBadRequest, ErrorConflict, ErrorInternalServerError, ErrorNotFound, ErrorUnauthorized}; use actix_web::web::Json; use actix_web::Error; use serde_derive::Serialize; diff --git a/src/middleware/trydirect.rs b/src/middleware/trydirect.rs index 823680a..d370a47 100644 --- a/src/middleware/trydirect.rs +++ b/src/middleware/trydirect.rs @@ -9,12 +9,14 @@ use std::sync::Arc; pub async fn bearer_guard( req: ServiceRequest, credentials: BearerAuth) -> Result { let settings = req.app_data::>().unwrap(); let token = credentials.token(); - let user = fetch_user(settings.auth_url.as_str(), token).await; - if let Err(err) = user { - return Err((JsonResponse::::build().unauthorized(err), req)); - } + let user = match fetch_user(settings.auth_url.as_str(), token) + .await { + Ok(user) => user, + Err(err) => { + return Err((JsonResponse::::build().unauthorized(err), req)); + } + }; - let user = user.unwrap(); if req.extensions_mut().insert(Arc::new(user)).is_some() { return Err((JsonResponse::::build().unauthorized("user already logged"), req)); } From 899b8f8a1f4cbaceb92c0e2e8ed9bcb671f04cbf Mon Sep 17 00:00:00 2001 From: petru Date: Tue, 12 Dec 2023 18:11:02 +0200 Subject: [PATCH 061/284] issue-auth src/routes/client/add.rs --- src/middleware/trydirect.rs | 11 +++++------ src/routes/client/add.rs | 8 ++++---- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/middleware/trydirect.rs b/src/middleware/trydirect.rs index d370a47..e40f89b 100644 --- a/src/middleware/trydirect.rs +++ b/src/middleware/trydirect.rs @@ -9,12 +9,11 @@ use std::sync::Arc; pub async fn bearer_guard( req: ServiceRequest, credentials: BearerAuth) -> Result { let settings = req.app_data::>().unwrap(); let token = credentials.token(); - let user = match fetch_user(settings.auth_url.as_str(), token) - .await { - Ok(user) => user, - Err(err) => { - return Err((JsonResponse::::build().unauthorized(err), req)); - } + let user = match fetch_user(settings.auth_url.as_str(), token).await { + Ok(user) => user, + Err(err) => { + return Err((JsonResponse::::build().unauthorized(err), req)); + } }; if req.extensions_mut().insert(Arc::new(user)).is_some() { diff --git a/src/routes/client/add.rs b/src/routes/client/add.rs index f922718..74040e5 100644 --- a/src/routes/client/add.rs +++ b/src/routes/client/add.rs @@ -14,10 +14,10 @@ pub async fn add_handler( settings: web::Data, pool: web::Data, ) -> Result { - match add_handler_inner(&user.id, settings, pool).await { - Ok(client) => Ok(JsonResponse::build().set_item(client).ok("Ok")), - Err(msg) => Err(JsonResponse::::build().bad_request(msg)), - } + add_handler_inner(&user.id, settings, pool) + .await + .map(|client| JsonResponse::build().set_item(client).ok("Ok")) + .map_err(|err| JsonResponse::::build().bad_request(err)) } pub async fn add_handler_inner( From 892ff9def9e09de4ee68501d799398af47132597 Mon Sep 17 00:00:00 2001 From: petru Date: Tue, 12 Dec 2023 18:22:49 +0200 Subject: [PATCH 062/284] issue-auth enable client --- src/routes/client/enable.rs | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/routes/client/enable.rs b/src/routes/client/enable.rs index 59bde80..527e6db 100644 --- a/src/routes/client/enable.rs +++ b/src/routes/client/enable.rs @@ -15,23 +15,24 @@ pub async fn enable_handler( pool: web::Data, path: web::Path<(i32,)>, ) -> Result { - match async { - let client_id = path.0; - let mut client = db_fetch_client_by_id(pool.get_ref(), client_id).await?; - if client.secret.is_some() { - return Err("client is already active".to_string()); - } + let client_id = path.0; + let mut client = db_fetch_client_by_id(pool.get_ref(), client_id) + .await + .map_err(|err| JsonResponse::::build().bad_request(err))?; - client.secret = Some(client::generate_secret(pool.get_ref(), 255).await?); - db_update_client(pool.get_ref(), client).await - }.await { - Ok(client) => { - Ok(JsonResponse::build().set_item(client).ok("success")) - } - Err(msg) => { - Err(JsonResponse::::build().bad_request(msg)) - } + if client.secret.is_some() { + return Err(JsonResponse::::build().bad_request("client is already active")); } + + client.secret = client::generate_secret(pool.get_ref(), 255) + .await + .map(|secret| Some(secret)) + .map_err(|err| JsonResponse::::build().bad_request(err))?; + + db_update_client(pool.get_ref(), client) + .await + .map(|client| JsonResponse::build().set_item(client).ok("success")) + .map_err(|err| JsonResponse::::build().bad_request(err)) } async fn db_fetch_client_by_id(pool: &PgPool, id: i32) -> Result { From 9989b118cc4f2a66a85b992e3b154522a47afa51 Mon Sep 17 00:00:00 2001 From: petru Date: Wed, 13 Dec 2023 16:52:17 +0200 Subject: [PATCH 063/284] issue-auth client logic refactor --- src/db/client/mod.rs | 99 ++++++++++++++++++++++++++++++++++++ src/db/mod.rs | 1 + src/lib.rs | 1 + src/routes/client/add.rs | 50 ++---------------- src/routes/client/disable.rs | 64 +++-------------------- src/routes/client/enable.rs | 60 ++-------------------- 6 files changed, 115 insertions(+), 160 deletions(-) create mode 100644 src/db/client/mod.rs create mode 100644 src/db/mod.rs diff --git a/src/db/client/mod.rs b/src/db/client/mod.rs new file mode 100644 index 0000000..b006d97 --- /dev/null +++ b/src/db/client/mod.rs @@ -0,0 +1,99 @@ +use sqlx::PgPool; +use crate::models; +use tracing::Instrument; + +pub async fn update(pool: &PgPool, client: models::Client) -> Result { + let query_span = tracing::info_span!("Updating client into the database"); + sqlx::query!( + r#" + UPDATE client SET + secret=$1, + updated_at=NOW() at time zone 'utc' + WHERE id = $2 + "#, + client.secret, + client.id + ) + .execute(pool) + .instrument(query_span) + .await + .map(|_|{ + tracing::info!("Client {} have been saved to database", client.id); + client + }) + .map_err(|err| { + tracing::error!("Failed to execute query: {:?}", err); + "".to_string() + }) +} + +pub async fn fetch(pool: &PgPool, id: i32) -> Result { + let query_span = tracing::info_span!("Fetching the client by ID"); + sqlx::query_as!( + models::Client, + r#" + SELECT + id, user_id, secret + FROM client c + WHERE c.id = $1 + "#, + id, + ) + .fetch_one(pool) + .instrument(query_span) + .await + .map_err(|e| { + match e { + sqlx::Error::RowNotFound => "client not found".to_string(), + s => { + tracing::error!("Failed to execute fetch query: {:?}", s); + "".to_string() + } + } + }) +} + +pub async fn count_by_user(pool: &PgPool , user_id: &String) -> Result { + let query_span = tracing::info_span!("Counting the user's clients"); + + sqlx::query!( + r#" + SELECT + count(*) as client_count + FROM client c + WHERE c.user_id = $1 + "#, + user_id.clone(), + ) + .fetch_one(pool) + .instrument(query_span) + .await + .map(|result| {result.client_count.unwrap()}) + .map_err(|err| { + tracing::error!("Failed to execute query: {:?}", err); + "Internal Server Error".to_string() + }) +} + +pub async fn insert(pool: &PgPool, mut client: models::Client) -> Result { + let query_span = tracing::info_span!("Saving new client into the database"); + sqlx::query!( + r#" + INSERT INTO client (user_id, secret, created_at, updated_at) + VALUES ($1, $2, NOW() at time zone 'utc', NOW() at time zone 'utc') + RETURNING id + "#, + client.user_id.clone(), + client.secret, + ) + .fetch_one(pool) + .instrument(query_span) + .await + .map(move |result| { + client.id = result.id; + client + }).map_err(|e| { + tracing::error!("Failed to execute query: {:?}", e); + "Failed to insert".to_string() + }) +} diff --git a/src/db/mod.rs b/src/db/mod.rs new file mode 100644 index 0000000..b9babe5 --- /dev/null +++ b/src/db/mod.rs @@ -0,0 +1 @@ +pub mod client; diff --git a/src/lib.rs b/src/lib.rs index 37e4fae..3c6af7c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ pub mod configuration; pub mod console; +pub mod db; pub mod forms; pub mod helpers; mod middleware; diff --git a/src/routes/client/add.rs b/src/routes/client/add.rs index 74040e5..b3d90d9 100644 --- a/src/routes/client/add.rs +++ b/src/routes/client/add.rs @@ -2,6 +2,7 @@ use crate::configuration::Settings; use crate::helpers::client; use crate::helpers::JsonResponse; use crate::models; +use crate::db; use actix_web::{post, web, Responder, Result}; use sqlx::PgPool; use tracing::Instrument; @@ -25,58 +26,13 @@ pub async fn add_handler_inner( settings: web::Data, pool: web::Data, ) -> Result { - let client_count = db_count_clients_by_user(pool.get_ref(), user_id).await?; + let client_count = db::client::count_by_user(pool.get_ref(), user_id).await?; if client_count >= settings.max_clients_number { return Err("Too many clients created".to_string()); } let client = create_client(pool.get_ref(), user_id).await?; - db_insert_client(pool.get_ref(), client).await -} - -async fn db_count_clients_by_user(pool: &PgPool , user_id: &String) -> Result { - let query_span = tracing::info_span!("Counting the user's clients"); - - sqlx::query!( - r#" - SELECT - count(*) as client_count - FROM client c - WHERE c.user_id = $1 - "#, - user_id.clone(), - ) - .fetch_one(pool) - .instrument(query_span) - .await - .map(|result| {result.client_count.unwrap()}) - .map_err(|err| { - tracing::error!("Failed to execute query: {:?}", err); - "Internal Server Error".to_string() - }) -} - -async fn db_insert_client(pool: &PgPool, mut client: models::Client) -> Result { - let query_span = tracing::info_span!("Saving new client into the database"); - sqlx::query!( - r#" - INSERT INTO client (user_id, secret, created_at, updated_at) - VALUES ($1, $2, NOW() at time zone 'utc', NOW() at time zone 'utc') - RETURNING id - "#, - client.user_id.clone(), - client.secret, - ) - .fetch_one(pool) - .instrument(query_span) - .await - .map(move |result| { - client.id = result.id; - client - }).map_err(|e| { - tracing::error!("Failed to execute query: {:?}", e); - "Failed to insert".to_string() - }) + db::client::insert(pool.get_ref(), client).await } async fn create_client(pool: &PgPool, user_id: &String) -> Result { diff --git a/src/routes/client/disable.rs b/src/routes/client/disable.rs index c5d2ac3..2159feb 100644 --- a/src/routes/client/disable.rs +++ b/src/routes/client/disable.rs @@ -1,6 +1,7 @@ use crate::configuration::Settings; use crate::helpers::JsonResponse; use crate::models; +use crate::db; use actix_web::{put, web, Responder, Result}; use sqlx::PgPool; use tracing::Instrument; @@ -15,69 +16,16 @@ pub async fn disable_handler( path: web::Path<(i32,)>, ) -> Result { let client_id = path.0; - let mut client = db_fetch_client_by_id(pool.get_ref(), client_id) + let mut client = db::client::fetch(pool.get_ref(), client_id) .await - .map_err(|msg| JsonResponse::::build().not_found(msg)) - ?; + .map_err(|msg| JsonResponse::::build().not_found(msg))?; if client.secret.is_none() { return Err(JsonResponse::::build().bad_request("client is not active")); } client.secret = None; - let client = db_update_client(pool.get_ref(), client) + db::client::update(pool.get_ref(), client) .await - .map_err(|msg| JsonResponse::::build().bad_request(msg))?; - - Ok(JsonResponse::build().set_item(client).ok("success")) -} - -async fn db_fetch_client_by_id(pool: &PgPool, id: i32) -> Result { - let query_span = tracing::info_span!("Fetching the client by ID"); - sqlx::query_as!( - models::Client, - r#" - SELECT - id, user_id, secret - FROM client c - WHERE c.id = $1 - "#, - id, - ) - .fetch_one(pool) - .instrument(query_span) - .await - .map_err(|e| { - match e { - sqlx::Error::RowNotFound => "client not found".to_string(), - s => { - tracing::error!("Failed to execute fetch query: {:?}", s); - "".to_string() - } - } - }) -} - -async fn db_update_client(pool: &PgPool, client: models::Client) -> Result { - let query_span = tracing::info_span!("Updating client into the database"); - sqlx::query!( - r#" - UPDATE client SET - secret=$1, - updated_at=NOW() at time zone 'utc' - WHERE id = $2 - "#, - client.secret, - client.id - ) - .execute(pool) - .instrument(query_span) - .await - .map(|_|{ - tracing::info!("Client {} have been saved to database", client.id); - client - }) - .map_err(|err| { - tracing::error!("Failed to execute query: {:?}", err); - "".to_string() - }) + .map(|client| JsonResponse::build().set_item(client).ok("success")) + .map_err(|msg| JsonResponse::::build().bad_request(msg)) } diff --git a/src/routes/client/enable.rs b/src/routes/client/enable.rs index 527e6db..6ed95d2 100644 --- a/src/routes/client/enable.rs +++ b/src/routes/client/enable.rs @@ -2,9 +2,10 @@ use crate::configuration::Settings; use crate::helpers::client; use crate::helpers::JsonResponse; use crate::models; +use crate::db; use actix_web::{put, web, Responder, Result}; -use sqlx::PgPool; use tracing::Instrument; +use sqlx::PgPool; use std::sync::Arc; #[tracing::instrument(name = "Enable client.")] @@ -16,9 +17,9 @@ pub async fn enable_handler( path: web::Path<(i32,)>, ) -> Result { let client_id = path.0; - let mut client = db_fetch_client_by_id(pool.get_ref(), client_id) + let mut client = db::client::fetch(pool.get_ref(), client_id) .await - .map_err(|err| JsonResponse::::build().bad_request(err))?; + .map_err(|msg| JsonResponse::::build().not_found(msg))?; if client.secret.is_some() { return Err(JsonResponse::::build().bad_request("client is already active")); @@ -29,59 +30,8 @@ pub async fn enable_handler( .map(|secret| Some(secret)) .map_err(|err| JsonResponse::::build().bad_request(err))?; - db_update_client(pool.get_ref(), client) + db::client::update(pool.get_ref(), client) .await .map(|client| JsonResponse::build().set_item(client).ok("success")) .map_err(|err| JsonResponse::::build().bad_request(err)) } - -async fn db_fetch_client_by_id(pool: &PgPool, id: i32) -> Result { - let query_span = tracing::info_span!("Fetching the client by ID"); - sqlx::query_as!( - models::Client, - r#" - SELECT - id, user_id, secret - FROM client c - WHERE c.id = $1 - "#, - id, - ) - .fetch_one(pool) - .instrument(query_span) - .await - .map_err(|e| { - match e { - sqlx::Error::RowNotFound => "client not found".to_string(), - s => { - tracing::error!("Failed to execute fetch query: {:?}", s); - "".to_string() - } - } - }) -} - -async fn db_update_client(pool: &PgPool, client: models::Client) -> Result { - let query_span = tracing::info_span!("Updating client into the database"); - sqlx::query!( - r#" - UPDATE client SET - secret=$1, - updated_at=NOW() at time zone 'utc' - WHERE id = $2 - "#, - client.secret, - client.id - ) - .execute(pool) - .instrument(query_span) - .await - .map(|_|{ - tracing::info!("Client {} have been saved to database", client.id); - client - }) - .map_err(|err| { - tracing::error!("Failed to execute query: {:?}", err); - "".to_string() - }) -} From ee200c45499c6eb38a3120020be8bdf61194360b Mon Sep 17 00:00:00 2001 From: petru Date: Wed, 13 Dec 2023 17:02:33 +0200 Subject: [PATCH 064/284] issue-auth src/routes/client/update.rs --- src/routes/client/update.rs | 64 +++++++++---------------------------- 1 file changed, 15 insertions(+), 49 deletions(-) diff --git a/src/routes/client/update.rs b/src/routes/client/update.rs index 0fff40e..4a0fe8e 100644 --- a/src/routes/client/update.rs +++ b/src/routes/client/update.rs @@ -1,10 +1,12 @@ use crate::helpers::client; use crate::models; +use crate::db; use crate::{configuration::Settings, helpers::JsonResponse}; use actix_web::{error::ErrorBadRequest, put, web, Responder, Result}; use sqlx::PgPool; use std::sync::Arc; use tracing::Instrument; +use futures::TryFutureExt; #[tracing::instrument(name = "Update client.")] #[put("/{id}")] @@ -15,59 +17,23 @@ pub async fn update_handler( path: web::Path<(i32,)>, ) -> Result { let client_id = path.0; - let query_span = tracing::info_span!("Fetching the client by ID"); - let mut client: models::Client = match sqlx::query_as!( - models::Client, - r#" - SELECT - id, user_id, secret - FROM client c - WHERE c.id = $1 - "#, - client_id, - ) - .fetch_one(pool.get_ref()) - .instrument(query_span) - .await - { - Ok(client) if client.secret.is_some() => Ok(client), - Ok(_client) => Err("client is not active"), - Err(sqlx::Error::RowNotFound) => Err("the client is not found"), - Err(e) => { - tracing::error!("Failed to execute fetch query: {:?}", e); - - Err("") - } + let mut client = db::client::fetch(pool.get_ref(), client_id) + .await + .map_err(|msg| JsonResponse::::build().not_found(msg))?; + if client.secret.is_none() { + return Err(JsonResponse::::build().bad_request("client is not active")); } - .map_err(|s| ErrorBadRequest(JsonResponse::::build().set_msg(s).to_string()))?; client.secret = client::generate_secret(pool.get_ref(), 255) .await .map(|s| Some(s)) - .map_err(|s| ErrorBadRequest(JsonResponse::::build().set_msg(s).to_string()))?; + .map_err(|msg| JsonResponse::::build().bad_request(msg))?; - let query_span = tracing::info_span!("Updating client into the database"); - match sqlx::query!( - r#" - UPDATE client SET - secret=$1, - updated_at=NOW() at time zone 'utc' - WHERE id = $2 - "#, - client.secret, - client.id - ) - .execute(pool.get_ref()) - .instrument(query_span) - .await - { - Ok(_) => { - tracing::info!("Client {} have been saved to database", client.id); - Ok(JsonResponse::::build().set_item(client).ok("success")) - } - Err(e) => { - tracing::error!("Failed to execute query: {:?}", e); - Err(JsonResponse::::build().internal_server_error("")) - } - } + db::client::update(pool.get_ref(), client) + .await + .map(|client| JsonResponse::::build().set_item(client).ok("success")) + .map_err(|err| { + tracing::error!("Failed to execute query: {:?}", err); + JsonResponse::::build().internal_server_error("") + }) } From f1cba7e5c8cd48aa57195e1e3b51b84c2a0243e4 Mon Sep 17 00:00:00 2001 From: petru Date: Wed, 13 Dec 2023 17:06:07 +0200 Subject: [PATCH 065/284] issue-auth --- src/middleware/client.rs | 1 - src/routes/client/update.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/middleware/client.rs b/src/middleware/client.rs index 27aa97b..60bce27 100644 --- a/src/middleware/client.rs +++ b/src/middleware/client.rs @@ -1,7 +1,6 @@ use crate::helpers::JsonResponse; use crate::models::Client; use actix_http::header::CONTENT_LENGTH; -use actix_web::error::{ErrorForbidden, ErrorInternalServerError, ErrorNotFound, PayloadError}; use actix_web::web::BytesMut; use actix_web::HttpMessage; use futures::future::{FutureExt, LocalBoxFuture}; diff --git a/src/routes/client/update.rs b/src/routes/client/update.rs index 4a0fe8e..63b02a1 100644 --- a/src/routes/client/update.rs +++ b/src/routes/client/update.rs @@ -2,7 +2,7 @@ use crate::helpers::client; use crate::models; use crate::db; use crate::{configuration::Settings, helpers::JsonResponse}; -use actix_web::{error::ErrorBadRequest, put, web, Responder, Result}; +use actix_web::{put, web, Responder, Result}; use sqlx::PgPool; use std::sync::Arc; use tracing::Instrument; From 3ba9b904ef732bdf0db4da11d3fe545c870597a8 Mon Sep 17 00:00:00 2001 From: petru Date: Wed, 13 Dec 2023 17:08:39 +0200 Subject: [PATCH 066/284] issue-auth renamed client/mod.rs into client.rs --- src/db/{client/mod.rs => client.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/db/{client/mod.rs => client.rs} (100%) diff --git a/src/db/client/mod.rs b/src/db/client.rs similarity index 100% rename from src/db/client/mod.rs rename to src/db/client.rs From 33d9cd8788a6edf5021c000c1903bba342170d52 Mon Sep 17 00:00:00 2001 From: petru Date: Wed, 13 Dec 2023 18:09:43 +0200 Subject: [PATCH 067/284] issue-auth working on src/routes/rating/add.rs --- src/db/client.rs | 3 +- src/db/mod.rs | 2 + src/db/product.rs | 24 ++++++++++ src/db/rating.rs | 55 +++++++++++++++++++++++ src/routes/rating/add.rs | 97 +++++++++------------------------------- 5 files changed, 105 insertions(+), 76 deletions(-) create mode 100644 src/db/product.rs create mode 100644 src/db/rating.rs diff --git a/src/db/client.rs b/src/db/client.rs index b006d97..750eefd 100644 --- a/src/db/client.rs +++ b/src/db/client.rs @@ -92,7 +92,8 @@ pub async fn insert(pool: &PgPool, mut client: models::Client) -> Result Result { + let query_span = tracing::info_span!("Check product existence by id."); + sqlx::query_as!( + models::Product, + r"SELECT * FROM product WHERE obj_id = $1", + obj_id + ) + .fetch_one(pg_pool) + .instrument(query_span) + .await + .map_err(|e| { + match e { + sqlx::Error::RowNotFound => "client not found".to_string(), + s => { + tracing::error!("Failed to execute fetch query: {:?}", s); + "".to_string() + } + } + }) +} diff --git a/src/db/rating.rs b/src/db/rating.rs new file mode 100644 index 0000000..7d6a12e --- /dev/null +++ b/src/db/rating.rs @@ -0,0 +1,55 @@ +use sqlx::PgPool; +use crate::models; +use tracing::Instrument; + +pub async fn fetch_by_obj_and_user_and_category(pool: &PgPool, obj_id: i32, user_id: String, category: models::RateCategory) -> Result { + let query_span = tracing::info_span!("Search for existing vote."); + sqlx::query_as!( + models::Rating, + r"SELECT * FROM rating where user_id=$1 AND obj_id=$2 AND category=$3 LIMIT 1", + user_id, + obj_id, + "ok" //todo put there the category + //category.into() //todo + ) + .fetch_one(pool) + .instrument(query_span) + .await + .map_err(|e| { + match e { + sqlx::Error::RowNotFound => "client not found".to_string(), + s => { + tracing::error!("Failed to execute fetch query: {:?}", s); + "".to_string() + } + } + }) +} + +pub async fn insert(pool: &PgPool, mut rating: models::Rating) -> Result { + let query_span = tracing::info_span!("Saving new rating details into the database"); + sqlx::query!( + r#" + INSERT INTO rating (user_id, obj_id, category, comment, hidden, rate, created_at, updated_at) + VALUES ($1, $2, $3, $4, $5, $6, NOW() at time zone 'utc', NOW() at time zone 'utc') + RETURNING id + "#, + rating.user_id, + rating.obj_id, + rating.category, + rating.comment, + rating.hidden, + rating.rate + ) + .fetch_one(pool) + .instrument(query_span) + .await + .map(move |result| { + rating.id = result.id; + rating + }) + .map_err(|e| { + tracing::error!("Failed to execute query: {:?}", e); + "Failed to insert".to_string() + }) +} diff --git a/src/routes/rating/add.rs b/src/routes/rating/add.rs index 5e2e874..54a1ada 100644 --- a/src/routes/rating/add.rs +++ b/src/routes/rating/add.rs @@ -1,12 +1,12 @@ use crate::forms; use crate::helpers::JsonResponse; use crate::models; -use crate::models::user::User; -use crate::models::RateCategory; +use crate::db; use actix_web::{post, web, Responder, Result}; use sqlx::PgPool; use tracing::Instrument; use std::sync::Arc; +use futures::TryFutureExt; // workflow // add, update, list, get(user_id), ACL, @@ -16,86 +16,33 @@ use std::sync::Arc; #[tracing::instrument(name = "Add rating.")] #[post("")] pub async fn add_handler( - user: web::ReqData>, + user: web::ReqData>, form: web::Json, - pool: web::Data, + pg_pool: web::Data, ) -> Result { - let query_span = tracing::info_span!("Check product existence by id."); - match sqlx::query_as!( - models::Product, - r"SELECT * FROM product WHERE obj_id = $1", - form.obj_id - ) - .fetch_one(pool.get_ref()) - .instrument(query_span) - .await - { - Ok(product) => { - tracing::info!("Found product: {:?}", product.obj_id); - } - Err(e) => { - tracing::error!("Failed to fetch product: {:?}, error: {:?}", form.obj_id, e); - return Err(JsonResponse::::build().bad_request("Object not found")); - } - }; + let _product = db::product::fetch_by_obj(pg_pool.get_ref(), form.obj_id) + .await + .map_err(|msg| JsonResponse::::build().not_found(msg))?; - let query_span = tracing::info_span!("Search for existing vote."); - match sqlx::query!( - r"SELECT id FROM rating where user_id=$1 AND obj_id=$2 AND category=$3 LIMIT 1", - user.id, - form.obj_id, - form.category as RateCategory - ) - .fetch_one(pool.get_ref()) - .instrument(query_span) - .await - { + match db::rating::fetch_by_obj_and_user_and_category(pg_pool.get_ref(), form.obj_id, user.id.clone(), form.category).await { Ok(record) => { - tracing::info!( - "rating exists: {:?}, user: {}, product: {}, category: {:?}", - record.id, - user.id, - form.obj_id, - form.category - ); return Err(JsonResponse::::build().conflict("Already rated")); } - Err(sqlx::Error::RowNotFound) => {} - Err(e) => { - tracing::error!("Failed to fetch rating, error: {:?}", e); - return Err(JsonResponse::::build().internal_server_error("Internal Server Error")); - } + Err(_e) => {} } - let query_span = tracing::info_span!("Saving new rating details into the database"); - // Insert rating - match sqlx::query!( - r#" - INSERT INTO rating (user_id, obj_id, category, comment, hidden,rate, - created_at, - updated_at) - VALUES ($1, $2, $3, $4, $5, $6, NOW() at time zone 'utc', NOW() at time zone 'utc') - RETURNING id - "#, - user.id, - form.obj_id, - form.category as models::RateCategory, - form.comment, - false, - form.rate - ) - .fetch_one(pool.get_ref()) - .instrument(query_span) - .await - { - Ok(result) => { - tracing::info!("New rating {} have been saved to database", result.id); + let mut rating = models::Rating::default(); //todo into trait + rating.user_id = user.id.clone(); + rating.obj_id = form.obj_id; + rating.category = form.category.into(); //todo change the type of category field to the + //RateCategory + rating.comment = form.comment.clone(); //todo how to do it correctly? + rating.hidden = Some(false); //todo add to form + rating.rate = Some(form.rate); - Ok(JsonResponse::::build().set_id(result.id).ok("Saved")) - } - Err(e) => { - tracing::error!("Failed to execute query: {:?}", e); - Err(JsonResponse::::build().internal_server_error("Failed to insert")) - } - } + db::rating::insert(pg_pool.get_ref(), rating) + .await + .map(|rating| JsonResponse::build().set_item(rating).ok("success")) + .map_err(|err| JsonResponse::::build().internal_server_error("Failed to insert")) + //todo. verify that created_at and updated_at are also added to the response } From ccd134042e2554a8bbf0da4a06f6a71ac18b0a16 Mon Sep 17 00:00:00 2001 From: petru Date: Thu, 14 Dec 2023 17:46:08 +0200 Subject: [PATCH 068/284] issue-auth message product --- src/db/product.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/product.rs b/src/db/product.rs index d80092c..d409d57 100644 --- a/src/db/product.rs +++ b/src/db/product.rs @@ -14,7 +14,7 @@ pub async fn fetch_by_obj(pg_pool: &PgPool, obj_id: i32) -> Result "client not found".to_string(), + sqlx::Error::RowNotFound => "product not found".to_string(), s => { tracing::error!("Failed to execute fetch query: {:?}", s); "".to_string() From c8fca0b0de5d81aa71c70545a80f45b73e7f7fb1 Mon Sep 17 00:00:00 2001 From: petru Date: Thu, 14 Dec 2023 18:02:45 +0200 Subject: [PATCH 069/284] issue-auth src/routes/rating/add.rs --- src/forms/rating.rs | 13 +++++++++++++ src/models/rating.rs | 1 + src/routes/rating/add.rs | 9 +-------- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/forms/rating.rs b/src/forms/rating.rs index 76efca4..d7a4bd7 100644 --- a/src/forms/rating.rs +++ b/src/forms/rating.rs @@ -12,3 +12,16 @@ pub struct Rating { #[validate(maximum = 10)] pub rate: i32, // } + +impl Into for Rating { + fn into(self) -> models::Rating { + let mut rating = models::Rating::default(); + rating.obj_id = self.obj_id; + rating.category = self.category.into(); //todo change the type of category field to the RateCategory + rating.hidden = Some(false); + rating.rate = Some(self.rate); + rating.comment = self.comment; + + rating + } +} diff --git a/src/models/rating.rs b/src/models/rating.rs index c9ba705..7279fc2 100644 --- a/src/models/rating.rs +++ b/src/models/rating.rs @@ -28,6 +28,7 @@ pub struct Rating { pub created_at: DateTime, pub updated_at: DateTime, } +//todo consider to change the type of category into RateCategory diff --git a/src/routes/rating/add.rs b/src/routes/rating/add.rs index 54a1ada..88ec9b9 100644 --- a/src/routes/rating/add.rs +++ b/src/routes/rating/add.rs @@ -31,18 +31,11 @@ pub async fn add_handler( Err(_e) => {} } - let mut rating = models::Rating::default(); //todo into trait + let mut rating: models::Rating = form.into_inner().into(); rating.user_id = user.id.clone(); - rating.obj_id = form.obj_id; - rating.category = form.category.into(); //todo change the type of category field to the - //RateCategory - rating.comment = form.comment.clone(); //todo how to do it correctly? - rating.hidden = Some(false); //todo add to form - rating.rate = Some(form.rate); db::rating::insert(pg_pool.get_ref(), rating) .await .map(|rating| JsonResponse::build().set_item(rating).ok("success")) .map_err(|err| JsonResponse::::build().internal_server_error("Failed to insert")) - //todo. verify that created_at and updated_at are also added to the response } From 6ae6a484e26b915cf3d0903d67fd0db418b8846e Mon Sep 17 00:00:00 2001 From: vsilent Date: Fri, 15 Dec 2023 14:59:14 +0200 Subject: [PATCH 070/284] default_network fix --- .dockerignore | 0 .env | 2 + Cargo.lock | 1 + Cargo.toml | 1 + Dockerfile | 57 +++++++++--------- docker-compose.yml | 49 +++++++--------- docker/dev/configuration.yaml | 6 ++ docker/dev/docker-compose.yml | 14 ++++- docker/local/configuration.yaml | 6 ++ src/forms/stack.rs | 19 +----- src/helpers/compressor.rs | 20 +++++++ src/helpers/mod.rs | 3 +- src/helpers/stack/builder.rs | 100 +++++++++++++++++--------------- src/middleware/trydirect.rs | 2 +- src/routes/rating/get.rs | 1 - src/routes/stack/deploy.rs | 5 +- 16 files changed, 158 insertions(+), 128 deletions(-) create mode 100644 .dockerignore create mode 100644 src/helpers/compressor.rs diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..e69de29 diff --git a/.env b/.env index dffc672..14bdc64 100644 --- a/.env +++ b/.env @@ -1,3 +1,5 @@ +#BUILDKIT_PROGRESS=plain +#DOCKER_BUILDKIT=1 DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/stacker POSTGRES_USER=postgres POSTGRES_PASSWORD=postgres diff --git a/Cargo.lock b/Cargo.lock index 6c5834b..4c8f8db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3090,6 +3090,7 @@ dependencies = [ "actix-http", "actix-web", "actix-web-httpauth", + "brotli", "chrono", "clap", "config", diff --git a/Cargo.toml b/Cargo.toml index b23bf3b..14d368b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,6 +52,7 @@ serde_yaml = "0.9" lapin = { version = "2.3.1", features = ["serde_json"] } futures-lite = "1.13.0" clap = { version = "4.4.8", features = ["derive"] } +brotli = "3.4.0" [dependencies.sqlx] version = "0.6.3" diff --git a/Dockerfile b/Dockerfile index 666567e..29b6b73 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,55 +1,56 @@ FROM rust:bookworm as builder -RUN apt-get update; \ - #apt-get install --no-install-recommends -y libpq-dev libssl-dev pkg-config; \ - apt-get install --no-install-recommends -y libssl-dev; \ - rm -rf /var/lib/apt/lists/*; \ - USER=root cargo new --bin app; +#RUN apt-get update; \ +# apt-get install --no-install-recommends -y libssl-dev; \ +# rm -rf /var/lib/apt/lists/*; \ +# USER=root cargo new --bin app; RUN cargo install sqlx-cli WORKDIR /app # copy manifests -COPY ../Cargo.toml . -COPY ../Cargo.lock . -COPY ../rustfmt.toml . -COPY ../Makefile . -COPY ../docker/local/.env . -COPY ../docker/local/configuration.yaml . +COPY ./Cargo.toml . +COPY ./Cargo.lock . +COPY ./rustfmt.toml . +COPY ./Makefile . +COPY ./docker/local/.env . +COPY ./docker/local/configuration.yaml . # build this project to cache dependencies #RUN sqlx database create && sqlx migrate run -RUN cargo build --release; \ - rm src/*.rs +# build skeleton and remove src after +#RUN cargo build --release; \ +# rm src/*.rs -# add .env and secret.key for Docker env -#RUN touch .env; -# copy project source and necessary files -COPY ../src ./src +COPY ./src ./src + +# for ls output use BUILDKIT_PROGRESS=plain docker build . +#RUN ls -la /app/ >&2 #RUN sqlx migrate run #RUN cargo sqlx prepare -- --bin stacker # rebuild app with project source -RUN rm -rf ./target/release/deps/stacker*; \ +#RUN rm -rf ./target/release/deps/server*; \ +# apt-get install --no-install-recommends -y libssl-dev; \ +# cargo build --release + +RUN apt-get update && apt-get install --no-install-recommends -y libssl-dev; \ cargo build --release -# deploy stage -FROM debian:bookworm as production +#RUN ls -la /app/target/release/ >&2 +# deploy production +FROM debian:bookworm-slim as production + +RUN apt-get update && apt-get install --no-install-recommends -y libssl-dev; # create app directory WORKDIR /app RUN mkdir ./files && chmod 0777 ./files -# install libpq -RUN apt-get update; \ - apt-get install --no-install-recommends -y libssl-dev \ - && rm -rf /var/lib/apt/lists/* - # copy binary and configuration files -#COPY --from=builder ~/.cargo/bin/sqlx-cli sqlx-cli -COPY --from=builder /app/target/release/stacker . +COPY --from=builder /app/target/release/server . COPY --from=builder /app/.env . COPY --from=builder /app/configuration.yaml . COPY --from=builder /usr/local/cargo/bin/sqlx sqlx @@ -57,4 +58,4 @@ COPY --from=builder /usr/local/cargo/bin/sqlx sqlx EXPOSE 8000 # run the binary -ENTRYPOINT ["/app/stacker"] +ENTRYPOINT ["/app/server"] diff --git a/docker-compose.yml b/docker-compose.yml index 26311c4..9cba7b2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,16 +4,11 @@ volumes: stackerdb: driver: local -networks: - backend: - driver: bridge - name: backend - external: true services: stacker: - image: trydirect/stacker:0.0.4 + image: trydirect/stacker:0.0.5 build: . container_name: stacker restart: always @@ -29,28 +24,24 @@ services: environment: - RUST_LOG=debug - RUST_BACKTRACE=1 - depends_on: - stackerdb: - condition: service_healthy - networks: - - backend +# depends_on: +# stackerdb: +# condition: service_healthy - stackerdb: - container_name: stackerdb - healthcheck: - test: ["CMD-SHELL", "pg_isready -U postgres"] - interval: 10s - timeout: 5s - retries: 5 - image: postgres:16.0 - restart: always - ports: - - 5432:5432 - env_file: - - ./docker/local/.env - volumes: - - stackerdb:/var/lib/postgresql/data - - ./docker/local/postgresql.conf:/etc/postgresql/postgresql.conf - networks: - - backend \ No newline at end of file +# stackerdb: +# container_name: stackerdb +# healthcheck: +# test: ["CMD-SHELL", "pg_isready -U postgres"] +# interval: 10s +# timeout: 5s +# retries: 5 +# image: postgres:16.0 +# restart: always +# ports: +# - 5432:5432 +# env_file: +# - ./docker/local/.env +# volumes: +# - stackerdb:/var/lib/postgresql/data +# - ./docker/local/postgresql.conf:/etc/postgresql/postgresql.conf \ No newline at end of file diff --git a/docker/dev/configuration.yaml b/docker/dev/configuration.yaml index 5eef969..5538317 100644 --- a/docker/dev/configuration.yaml +++ b/docker/dev/configuration.yaml @@ -7,3 +7,9 @@ database: username: postgres password: postgres database_name: stacker + +amqp: + host: 127.0.0.1 + port: 5672 + username: guest + password: guest diff --git a/docker/dev/docker-compose.yml b/docker/dev/docker-compose.yml index bdfdd89..c1a022b 100644 --- a/docker/dev/docker-compose.yml +++ b/docker/dev/docker-compose.yml @@ -4,10 +4,16 @@ volumes: stackerdb: driver: local +networks: + backend: + driver: bridge + name: backend + external: true + services: stacker: - image: trydirect/stacker:0.0.4 + image: trydirect/stacker:0.0.5 build: . container_name: stacker restart: always @@ -26,6 +32,8 @@ services: depends_on: stackerdb: condition: service_healthy + networks: + - backend stackerdb: @@ -43,4 +51,6 @@ services: - ./.env volumes: - stackerdb:/var/lib/postgresql/data - - ./postgresql.conf:/etc/postgresql/postgresql.conf \ No newline at end of file + - ./postgresql.conf:/etc/postgresql/postgresql.conf + networks: + - backend diff --git a/docker/local/configuration.yaml b/docker/local/configuration.yaml index 9c1848f..a0bb4c0 100644 --- a/docker/local/configuration.yaml +++ b/docker/local/configuration.yaml @@ -7,3 +7,9 @@ database: username: postgres password: postgres database_name: stacker + +amqp: + host: 127.0.0.1 + port: 5672 + username: guest + password: guest diff --git a/src/forms/stack.rs b/src/forms/stack.rs index b67a856..cd8f786 100644 --- a/src/forms/stack.rs +++ b/src/forms/stack.rs @@ -34,14 +34,6 @@ pub struct Port { pub container_port: Option } -// #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -// pub struct Ports { -// #[serde(rename(deserialize = "sharedPorts"))] -// #[serde(rename(serialize = "shared_ports"))] -// // #[serde(alias = "shared_ports")] -// pub shared_ports: Option>, -// pub ports: Option>, -// } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct DockerImage { @@ -155,6 +147,7 @@ pub struct StackPayload { #[serde(rename = "selected_plan")] pub selected_plan: String, pub custom: Custom, + pub docker_compose: Option> } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -261,8 +254,6 @@ pub struct App { pub environment: Environment, #[serde(flatten)] pub network: ServiceNetworks, - // #[serde(flatten)] - // pub ports: Ports, #[serde(rename(deserialize = "sharedPorts"))] #[serde(rename(serialize = "shared_ports"))] #[serde(alias = "shared_ports")] @@ -305,20 +296,12 @@ pub struct Web { #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Feature { - // #[serde(rename(deserialize = "sharedPorts"))] - // #[serde(rename(serialize = "shared_ports"))] - // #[serde(alias = "shared_ports")] - // pub shared_ports: Option>, #[serde(flatten)] pub app: App, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Service { - // #[serde(rename(deserialize = "sharedPorts"))] - // #[serde(rename(serialize = "shared_ports"))] - // #[serde(alias = "shared_ports")] - // pub shared_ports: Option>, #[serde(flatten)] pub(crate) app: App, } diff --git a/src/helpers/compressor.rs b/src/helpers/compressor.rs new file mode 100644 index 0000000..8061329 --- /dev/null +++ b/src/helpers/compressor.rs @@ -0,0 +1,20 @@ +use brotli::{CompressorWriter, Decompressor}; +use std::io::{Read, Write}; + +pub fn compress(input: &str) -> Vec { + let mut compressed = Vec::new(); + let mut compressor = CompressorWriter::new( + &mut compressed, 4096, 11, 22 + ); + compressor.write_all(input.as_bytes()).unwrap(); + compressor.flush().unwrap(); + drop(compressor); + compressed +} + +pub fn decompress(input: &[u8]) -> String { + let mut decompressed = String::new(); + let mut decompressor = Decompressor::new(input, 4096); + decompressor.read_to_string(&mut decompressed).unwrap(); + decompressed +} diff --git a/src/helpers/mod.rs b/src/helpers/mod.rs index e5439f7..5397875 100644 --- a/src/helpers/mod.rs +++ b/src/helpers/mod.rs @@ -1,5 +1,6 @@ pub mod client; pub(crate) mod json; pub(crate) mod stack; - pub use json::*; +pub(crate) mod compressor; +pub use compressor::*; \ No newline at end of file diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 1db77c5..3df222b 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -78,33 +78,23 @@ impl TryInto for stack::Port { impl TryInto for stack::ServiceNetworks { type Error = (); fn try_into(self) -> Result { - let mut networks = vec!["default_network".to_string()]; - if self.network.is_some() { - networks.append(&mut self.network.unwrap()); - } - Ok(Networks::Simple(networks)) - } -} - -fn convert_shared_ports(ports: Option>) -> Result, String> { - tracing::debug!("convert shared ports {:?}", &ports); - let mut _ports: Vec = vec![]; - match ports { - Some(ports) => { - tracing::debug!("Ports >>>> {:?}", ports); - for port in ports { + let mut default_networks = vec!["default_network".to_string()]; + let nets = match self.network { + Some(mut _nets) => { + if !_nets.contains(&"default_network".to_string()) { + _nets.append(&mut default_networks); + } + _nets } - } - None => { - tracing::debug!("No ports defined by user"); - return Ok(_ports); - } + None => { + default_networks + } + }; + Ok(Networks::Simple(nets)) } - - tracing::debug!("ports {:?}", _ports); - Ok(_ports) } + fn is_named_docker_volume(volume: &str) -> bool { // Docker named volumes typically don't contain special characters or slashes // They are alphanumeric and may include underscores or hyphens @@ -170,14 +160,23 @@ impl TryIntoService for App { impl Into>> for stack::ComposeNetworks { fn into(self) -> IndexMap> { - // tracing::debug!("networks found {:?}", self.networks); - let mut networks = vec!["default_network".to_string()]; - if self.networks.is_some() { - networks.append(&mut self.networks.unwrap()); - } + let mut default_network = vec!["default_network".to_string()]; + + let networks = match self.networks { + None => { + default_network + } + Some(mut nets) => { + if !nets.contains(&"default_network".to_string()) { + nets.append(&mut default_network); + } + nets + } + }; + let networks = networks .into_iter() - .map(|net| + .map(|net| { (net, MapOrEmpty::Map( NetworkSettings { @@ -193,8 +192,12 @@ impl Into>> for stack::ComposeNetwo name: Some("default".to_string()), } )) + } ) .collect::>(); + + tracing::debug!("networks collected {:?}", &networks); + networks } } @@ -203,26 +206,29 @@ impl Into>> for stack::ComposeNetwo pub fn extract_named_volumes(app: App) -> IndexMap> { let mut named_volumes = IndexMap::default(); + if app.volumes.is_none() { + return named_volumes; + } - let volumes = app.volumes - .unwrap() - .into_iter() - .filter(|volume| is_named_docker_volume( - volume.host_path.clone().unwrap().as_str()) - ) - .map(|volume| { - let k = volume.host_path.clone().unwrap(); - (k.clone(), MapOrEmpty::Map(ComposeVolume { - driver: None, - driver_opts: Default::default(), - external: None, - labels: Default::default(), - name: Some(k.clone()) - })) - }) - .collect::>>(); + let volumes = app.volumes + .unwrap() + .into_iter() + .filter(|volume| is_named_docker_volume( + volume.host_path.clone().unwrap().as_str()) + ) + .map(|volume| { + let k = volume.host_path.clone().unwrap(); + (k.clone(), MapOrEmpty::Map(ComposeVolume { + driver: None, + driver_opts: Default::default(), + external: None, + labels: Default::default(), + name: Some(k.clone()) + })) + }) + .collect::>>(); - named_volumes.extend(volumes); + named_volumes.extend(volumes); // tracing::debug!("Named volumes: {:?}", named_volumes); named_volumes diff --git a/src/middleware/trydirect.rs b/src/middleware/trydirect.rs index bbe5e4b..c8bbfd1 100644 --- a/src/middleware/trydirect.rs +++ b/src/middleware/trydirect.rs @@ -5,7 +5,7 @@ use futures::future::{FutureExt}; use reqwest::header::{ACCEPT, CONTENT_TYPE}; use std::sync::Arc; -#[tracing::instrument(name = "Trydirect bearer guard.")] +#[tracing::instrument(name = "TryDirect bearer guard.")] pub async fn bearer_guard( req: ServiceRequest, credentials: BearerAuth) -> Result { let settings = req.app_data::>().unwrap(); let token = credentials.token(); diff --git a/src/routes/rating/get.rs b/src/routes/rating/get.rs index e781d9a..0db7801 100644 --- a/src/routes/rating/get.rs +++ b/src/routes/rating/get.rs @@ -46,7 +46,6 @@ pub async fn get_handler( pub async fn list_handler(path: web::Path<()>, pool: web::Data) -> Result { /// Get ratings of all users let query_span = tracing::info_span!("Get all rates."); - // let category = path.0; match sqlx::query_as!(models::Rating, r"SELECT * FROM rating") .fetch_all(pool.get_ref()) .instrument(query_span) diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs index d1224c5..625fba6 100644 --- a/src/routes/stack/deploy.rs +++ b/src/routes/stack/deploy.rs @@ -11,6 +11,7 @@ use lapin::{ }; use sqlx::PgPool; use std::sync::Arc; +use crate::helpers::compressor::compress; #[tracing::instrument(name = "Deploy for every user. Admin endpoint")] @@ -52,7 +53,7 @@ pub async fn add( Some(stack) => { let id = stack.id.clone(); let dc = DcBuilder::new(stack); - dc.build(); + let fc = dc.build(); let addr = sets.amqp.connection_string(); let routing_key = "install.start.tfa.all.all".to_string(); @@ -72,6 +73,8 @@ pub async fn add( stack_data.user_token = Some(user.id.clone()); stack_data.user_email = Some(user.email.clone()); stack_data.stack_code = stack_data.custom.custom_stack_code.clone(); + let compressed = fc.unwrap_or("".to_string()); + stack_data.docker_compose = Some(compress(compressed.as_str())); let payload = serde_json::to_string::(&stack_data).unwrap(); let _payload = payload.as_bytes(); From 3453c3e6900afffad4c9eff1ec9655b7e553e30a Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 16 Dec 2023 09:32:49 +0200 Subject: [PATCH 071/284] issue-auth models into files --- src/models/mod.rs | 6 ++++++ src/models/product.rs | 16 ++++++++++++++ src/models/ratecategory.rs | 22 +++++++++++++++++++ src/models/rating.rs | 44 -------------------------------------- src/models/rules.rs | 5 +++++ 5 files changed, 49 insertions(+), 44 deletions(-) create mode 100644 src/models/product.rs create mode 100644 src/models/ratecategory.rs create mode 100644 src/models/rules.rs diff --git a/src/models/mod.rs b/src/models/mod.rs index b695114..a17ea32 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -1,4 +1,7 @@ mod client; +mod product; +mod ratecategory; +mod rules; pub mod rating; pub mod stack; pub mod user; @@ -7,3 +10,6 @@ pub use client::*; pub use rating::*; pub use stack::*; pub use user::*; +pub use product::*; +pub use ratecategory::*; +pub use rules::*; diff --git a/src/models/product.rs b/src/models/product.rs new file mode 100644 index 0000000..992818d --- /dev/null +++ b/src/models/product.rs @@ -0,0 +1,16 @@ +use chrono::{DateTime, Utc}; + +pub struct Product { + // Product - is an external object that we want to store in the database, + // that can be a stack or an app in the stack. feature, service, web app etc. + // id - is a unique identifier for the product + // user_id - is a unique identifier for the user + // rating - is a rating of the product + // product type stack & app, + // id is generated based on the product type and external obj_id + pub id: i32, //primary key, for better data management + pub obj_id: i32, // external product ID db, no autoincrement, example: 100 + pub obj_type: String, // stack | app, unique index + pub created_at: DateTime, + pub updated_at: DateTime, +} diff --git a/src/models/ratecategory.rs b/src/models/ratecategory.rs new file mode 100644 index 0000000..82eefd8 --- /dev/null +++ b/src/models/ratecategory.rs @@ -0,0 +1,22 @@ +use serde::{Deserialize, Serialize}; + +#[derive(sqlx::Type, Serialize, Deserialize, Debug, Clone, Copy)] +#[sqlx(rename_all = "lowercase", type_name = "varchar")] +pub enum RateCategory { + Application, // app, feature, extension + Cloud, // is user satisfied working with this cloud + Stack, // app stack + DeploymentSpeed, + Documentation, + Design, + TechSupport, + Price, + MemoryUsage, +} + +impl Into for RateCategory { + fn into(self) -> String { + format!("{:?}", self) + } +} + diff --git a/src/models/rating.rs b/src/models/rating.rs index 7279fc2..beb5ef1 100644 --- a/src/models/rating.rs +++ b/src/models/rating.rs @@ -1,21 +1,6 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; -pub struct Product { - // Product - is an external object that we want to store in the database, - // that can be a stack or an app in the stack. feature, service, web app etc. - // id - is a unique identifier for the product - // user_id - is a unique identifier for the user - // rating - is a rating of the product - // product type stack & app, - // id is generated based on the product type and external obj_id - pub id: i32, //primary key, for better data management - pub obj_id: i32, // external product ID db, no autoincrement, example: 100 - pub obj_type: String, // stack | app, unique index - pub created_at: DateTime, - pub updated_at: DateTime, -} - #[derive(Debug, Serialize, Default)] pub struct Rating { pub id: i32, @@ -28,32 +13,3 @@ pub struct Rating { pub created_at: DateTime, pub updated_at: DateTime, } -//todo consider to change the type of category into RateCategory - - - -#[derive(sqlx::Type, Serialize, Deserialize, Debug, Clone, Copy)] -#[sqlx(rename_all = "lowercase", type_name = "varchar")] -pub enum RateCategory { - Application, // app, feature, extension - Cloud, // is user satisfied working with this cloud - Stack, // app stack - DeploymentSpeed, - Documentation, - Design, - TechSupport, - Price, - MemoryUsage, -} - -impl Into for RateCategory { - fn into(self) -> String { - format!("{:?}", self) - } -} - -pub struct Rules { - //-> Product.id - // example: allow to add only a single comment - comments_per_user: i32, // default = 1 -} diff --git a/src/models/rules.rs b/src/models/rules.rs new file mode 100644 index 0000000..58afbd9 --- /dev/null +++ b/src/models/rules.rs @@ -0,0 +1,5 @@ +pub struct Rules { + //-> Product.id + // example: allow to add only a single comment + comments_per_user: i32, // default = 1 +} From dd202db25de3a40bf8fdb02b34f47184fafb2d0f Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 16 Dec 2023 10:18:30 +0200 Subject: [PATCH 072/284] issue-auth postgres enum rate_category --- .../20230903063840_creating_rating_tables.down.sql | 2 ++ .../20230903063840_creating_rating_tables.up.sql | 14 +++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/migrations/20230903063840_creating_rating_tables.down.sql b/migrations/20230903063840_creating_rating_tables.down.sql index e12e4ab..b32b52b 100644 --- a/migrations/20230903063840_creating_rating_tables.down.sql +++ b/migrations/20230903063840_creating_rating_tables.down.sql @@ -6,3 +6,5 @@ DROP INDEX idx_obj_id_rating_id; DROP table rating; DROP table product; + +DROP TYPE rate_category; diff --git a/migrations/20230903063840_creating_rating_tables.up.sql b/migrations/20230903063840_creating_rating_tables.up.sql index 579bef6..945cdb6 100644 --- a/migrations/20230903063840_creating_rating_tables.up.sql +++ b/migrations/20230903063840_creating_rating_tables.up.sql @@ -1,5 +1,17 @@ -- Add up migration script here +CREATE TYPE rate_category AS ENUM ( + 'Application', + 'Cloud', + 'Stack', + 'DeploymentSpeed', + 'Documentation', + 'Design', + 'TechSupport', + 'Price', + 'MemoryUsage' +); + CREATE TABLE product ( id integer NOT NULL, PRIMARY KEY(id), obj_id integer NOT NULL, @@ -12,7 +24,7 @@ CREATE TABLE rating ( id serial, user_id VARCHAR(50) NOT NULL, obj_id integer NOT NULL, - category VARCHAR(255) NOT NULL, + category rate_category NOT NULL, comment TEXT DEFAULT NULL, hidden BOOLEAN DEFAULT FALSE, rate INTEGER, From 412d0da6a6c2bd9c67a8edc1c3950a9c43b90a4a Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 16 Dec 2023 17:42:45 +0200 Subject: [PATCH 073/284] issue-auth RateCategory enum saved in db --- ...230903063840_creating_rating_tables.up.sql | 18 ++-- src/db/client.rs | 8 +- src/db/product.rs | 7 +- src/db/rating.rs | 83 +++++++++++++++++-- src/models/ratecategory.rs | 7 +- src/models/rating.rs | 3 +- src/routes/rating/get.rs | 50 ++--------- 7 files changed, 114 insertions(+), 62 deletions(-) diff --git a/migrations/20230903063840_creating_rating_tables.up.sql b/migrations/20230903063840_creating_rating_tables.up.sql index 945cdb6..2842270 100644 --- a/migrations/20230903063840_creating_rating_tables.up.sql +++ b/migrations/20230903063840_creating_rating_tables.up.sql @@ -1,15 +1,15 @@ -- Add up migration script here CREATE TYPE rate_category AS ENUM ( - 'Application', - 'Cloud', - 'Stack', - 'DeploymentSpeed', - 'Documentation', - 'Design', - 'TechSupport', - 'Price', - 'MemoryUsage' + 'application', + 'cloud', + 'stack', + 'deploymentSpeed', + 'documentation', + 'design', + 'techSupport', + 'price', + 'memoryUsage' ); CREATE TABLE product ( diff --git a/src/db/client.rs b/src/db/client.rs index 750eefd..477dbf5 100644 --- a/src/db/client.rs +++ b/src/db/client.rs @@ -6,7 +6,8 @@ pub async fn update(pool: &PgPool, client: models::Client) -> Result Result { models::Client, r#" SELECT - id, user_id, secret + id, + user_id, + secret FROM client c WHERE c.id = $1 + LIMIT 1 "#, id, ) diff --git a/src/db/product.rs b/src/db/product.rs index d409d57..56431b1 100644 --- a/src/db/product.rs +++ b/src/db/product.rs @@ -6,7 +6,12 @@ pub async fn fetch_by_obj(pg_pool: &PgPool, obj_id: i32) -> Result Result, String> { + let query_span = tracing::info_span!("Fetch all ratings."); + sqlx::query_as!( + models::Rating, + r#"SELECT + id, + user_id, + obj_id, + category as "category: _", + comment, + hidden, + rate, + created_at, + updated_at + FROM rating"# + ) + .fetch_all(pool) + .instrument(query_span) + .await + .map_err(|e| { + tracing::error!("Failed to execute fetch query: {:?}", e); + "".to_string() + }) +} + +pub async fn fetch(pool: &PgPool, id: i32) -> Result { + let query_span = tracing::info_span!("Fetch rating by id"); + sqlx::query_as!( + models::Rating, + r#"SELECT + id, + user_id, + obj_id, + category as "category: _", + comment, + hidden, + rate, + created_at, + updated_at + FROM rating + WHERE id=$1 + LIMIT 1"#, + id + ) + .fetch_one(pool) + .instrument(query_span) + .await + .map_err(|e| { + match e { + sqlx::Error::RowNotFound => "rating not found".to_string(), + s => { + tracing::error!("Failed to execute fetch query: {:?}", s); + "".to_string() + } + } + }) +} + pub async fn fetch_by_obj_and_user_and_category(pool: &PgPool, obj_id: i32, user_id: String, category: models::RateCategory) -> Result { - let query_span = tracing::info_span!("Search for existing vote."); + let query_span = tracing::info_span!("Fetch rating by obj, user and category."); sqlx::query_as!( models::Rating, - r"SELECT * FROM rating where user_id=$1 AND obj_id=$2 AND category=$3 LIMIT 1", + r#"SELECT + id, + user_id, + obj_id, + category as "category: _", + comment, + hidden, + rate, + created_at, + updated_at + FROM rating + WHERE user_id=$1 + AND obj_id=$2 + AND category=$3 + LIMIT 1"#, user_id, obj_id, - "ok" //todo put there the category - //category.into() //todo + category as _ ) .fetch_one(pool) .instrument(query_span) .await .map_err(|e| { match e { - sqlx::Error::RowNotFound => "client not found".to_string(), + sqlx::Error::RowNotFound => "fetch not found".to_string(), s => { tracing::error!("Failed to execute fetch query: {:?}", s); "".to_string() @@ -36,7 +107,7 @@ pub async fn insert(pool: &PgPool, mut rating: models::Rating) -> Result for RateCategory { } } +impl Default for RateCategory { + fn default() -> Self { + RateCategory::Application + } +} diff --git a/src/models/rating.rs b/src/models/rating.rs index beb5ef1..e1522de 100644 --- a/src/models/rating.rs +++ b/src/models/rating.rs @@ -1,12 +1,13 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; +use crate::models; #[derive(Debug, Serialize, Default)] pub struct Rating { pub id: i32, pub user_id: String, // external user_id, 100, taken using token (middleware?) pub obj_id: i32, // id of the external object - pub category: String, // rating of product | rating of service etc + pub category: models::RateCategory, // rating of product | rating of service etc pub comment: Option, // always linked to a product pub hidden: Option, // rating can be hidden for non-adequate user behaviour pub rate: Option, diff --git a/src/routes/rating/get.rs b/src/routes/rating/get.rs index 49fccb4..86c0e57 100644 --- a/src/routes/rating/get.rs +++ b/src/routes/rating/get.rs @@ -1,5 +1,6 @@ use crate::helpers::JsonResponse; use crate::models; +use crate::db; use actix_web::{get, web, Responder, Result}; use sqlx::PgPool; use tracing::Instrument; @@ -15,53 +16,18 @@ pub async fn get_handler( path: web::Path<(i32,)>, pool: web::Data, ) -> Result { - /// Get rating of any user let rate_id = path.0; - let query_span = tracing::info_span!("Search for rate id={}.", rate_id); - match sqlx::query_as!( - models::Rating, - r"SELECT * FROM rating WHERE id=$1 LIMIT 1", - rate_id - ) - .fetch_one(pool.get_ref()) - .instrument(query_span) - .await - { - Ok(rating) => { - tracing::info!("rating found: {:?}", rating.id); - return Ok(JsonResponse::build().set_item(Some(rating)).ok("OK")); - } - Err(sqlx::Error::RowNotFound) => { - return Err(JsonResponse::::build().not_found("")); - } - Err(e) => { - tracing::error!("Failed to fetch rating, error: {:?}", e); - return Err(JsonResponse::::build().internal_server_error("")); - } - } + db::rating::fetch(pool.get_ref(), rate_id) + .await + .map(|rating| JsonResponse::build().set_item(rating).ok("OK")) + .map_err(|err| JsonResponse::::build().not_found("not found")) } #[tracing::instrument(name = "Get all ratings.")] #[get("")] pub async fn list_handler(path: web::Path<()>, pool: web::Data) -> Result { - /// Get ratings of all users - let query_span = tracing::info_span!("Get all rates."); - // let category = path.0; - match sqlx::query_as!(models::Rating, r"SELECT * FROM rating") - .fetch_all(pool.get_ref()) - .instrument(query_span) + db::rating::fetch_all(pool.get_ref()) .await - { - Ok(rating) => { - tracing::info!("Ratings found: {:?}", rating.len()); - return Ok(JsonResponse::build().set_list(rating).ok("OK")); - } - Err(sqlx::Error::RowNotFound) => { - return Err(JsonResponse::::build().not_found("")); - } - Err(e) => { - tracing::error!("Failed to fetch rating, error: {:?}", e); - return Err(JsonResponse::::build().internal_server_error("")); - } - } + .map(|ratings| JsonResponse::build().set_list(ratings).ok("OK")) + .map_err(|err| JsonResponse::::build().internal_server_error("")) } From ecf28fef289a9d7e7e7224d43e5eda2257d11e09 Mon Sep 17 00:00:00 2001 From: petru Date: Sun, 17 Dec 2023 11:03:01 +0200 Subject: [PATCH 074/284] issue-auth stack get refactor --- src/db/mod.rs | 1 + src/db/stack.rs | 30 ++++++++++++++++++++++++++++++ src/routes/stack/get.rs | 39 ++++++++++++++------------------------- 3 files changed, 45 insertions(+), 25 deletions(-) create mode 100644 src/db/stack.rs diff --git a/src/db/mod.rs b/src/db/mod.rs index 0aec037..a4fe3ae 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -1,3 +1,4 @@ pub mod client; pub mod product; pub mod rating; +pub mod stack; diff --git a/src/db/stack.rs b/src/db/stack.rs new file mode 100644 index 0000000..8b16ef6 --- /dev/null +++ b/src/db/stack.rs @@ -0,0 +1,30 @@ +use sqlx::PgPool; +use crate::models; +use tracing::Instrument; + +pub async fn fetch(pool: &PgPool, id: i32) -> Result { + tracing::info!("Fecth stack {}", id); + sqlx::query_as!( + models::Stack, + r#" + SELECT + * + FROM user_stack + WHERE id=$1 + LIMIT 1 + "#, + id + ) + .fetch_one(pool) + .await + .map_err(|err| { + match err { + sqlx::Error::RowNotFound => "".to_string(), + e => { + tracing::error!("Failed to fetch stack, error: {:?}", e); + return "Could not fetch data".to_string(); + } + + } + }) +} diff --git a/src/routes/stack/get.rs b/src/routes/stack/get.rs index 88114dc..2538b69 100644 --- a/src/routes/stack/get.rs +++ b/src/routes/stack/get.rs @@ -1,6 +1,6 @@ use crate::helpers::JsonResponse; use crate::models; -use crate::models::user::User; +use crate::db; use actix_web::{get, web, Responder, Result}; use sqlx::PgPool; use std::convert::From; @@ -10,41 +10,30 @@ use std::sync::Arc; #[tracing::instrument(name = "Get logged user stack.")] #[get("/{id}")] pub async fn item( - user: web::ReqData>, + user: web::ReqData>, path: web::Path<(i32,)>, - pool: web::Data, + pool: web::Data, //&Web::Data + //get_ref + //* ) -> Result { /// Get stack apps of logged user only let (id,) = path.into_inner(); - tracing::info!("User {:?} gets stack by id {:?}", user.id, id); - match sqlx::query_as!( - models::Stack, - r#" - SELECT * FROM user_stack WHERE id=$1 AND user_id=$2 LIMIT 1 - "#, - id, - user.id - ) - .fetch_one(pool.get_ref()) - .await - { - Ok(stack) => { - tracing::info!("Stack found: {:?}", stack.id,); - return Ok(JsonResponse::build().set_item(Some(stack)).ok("OK")); - } - Err(sqlx::Error::RowNotFound) => Err(JsonResponse::::build().not_found("Record not found")), - Err(e) => { - tracing::error!("Failed to fetch stack, error: {:?}", e); - return Err(JsonResponse::::build().internal_server_error("Could not fetch data")); - } + let stack = db::stack::fetch(pool.get_ref(), id) + .await + .map_err(|err| JsonResponse::::build().not_found("Record not found"))?; + + if stack.user_id != user.id { + return Err(JsonResponse::::build().bad_request("Forbidden")); } + + Ok(JsonResponse::build().set_item(Some(stack)).ok("OK")) } #[tracing::instrument(name = "Get user's stack list.")] #[get("/user/{id}")] pub async fn list( - user: web::ReqData>, + user: web::ReqData>, path: web::Path<(String,)>, pool: web::Data, ) -> Result { From e6600986dd180903bebcb5223099ba0c24b9d5d5 Mon Sep 17 00:00:00 2001 From: petru Date: Mon, 18 Dec 2023 17:01:07 +0200 Subject: [PATCH 075/284] issue-auth new command. updated --- src/console/commands/appclient/new.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/console/commands/appclient/new.rs b/src/console/commands/appclient/new.rs index 448ac78..ada01ac 100644 --- a/src/console/commands/appclient/new.rs +++ b/src/console/commands/appclient/new.rs @@ -26,7 +26,7 @@ impl crate::console::commands::CallableTrait for NewCommand { //todo get user from trydirect let user = crate::models::user::User { - id: "first_name".to_string(), + id: format!("{}", self.user_id), first_name: "first_name".to_string(), last_name: "last_name".to_string(), email: "email".to_string(), From 9e4042a1d13c34dc2a1084f1b6dc286fc00cb79c Mon Sep 17 00:00:00 2001 From: petru Date: Mon, 18 Dec 2023 17:14:00 +0200 Subject: [PATCH 076/284] issue-auth routes/stack/get.rs --- src/db/stack.rs | 21 +++++++++++++++++++++ src/routes/stack/get.rs | 37 ++++++------------------------------- 2 files changed, 27 insertions(+), 31 deletions(-) diff --git a/src/db/stack.rs b/src/db/stack.rs index 8b16ef6..5cb2f92 100644 --- a/src/db/stack.rs +++ b/src/db/stack.rs @@ -28,3 +28,24 @@ pub async fn fetch(pool: &PgPool, id: i32) -> Result { } }) } + +pub async fn fetch_by_user(pool: &PgPool, user_id: String) -> Result, String> { + let query_span = tracing::info_span!("Fetch stacks by user id."); + sqlx::query_as!( + models::Stack, + r#" + SELECT + * + FROM user_stack + WHERE user_id=$1 + "#, + user_id + ) + .fetch_all(pool) + .instrument(query_span) + .await + .map_err(|err| { + tracing::error!("Failed to fetch stack, error: {:?}", err); + "".to_string() + }) +} diff --git a/src/routes/stack/get.rs b/src/routes/stack/get.rs index 2538b69..7ac8fb5 100644 --- a/src/routes/stack/get.rs +++ b/src/routes/stack/get.rs @@ -12,9 +12,7 @@ use std::sync::Arc; pub async fn item( user: web::ReqData>, path: web::Path<(i32,)>, - pool: web::Data, //&Web::Data - //get_ref - //* + pool: web::Data, ) -> Result { /// Get stack apps of logged user only let (id,) = path.into_inner(); @@ -40,33 +38,10 @@ pub async fn list( /// This is admin endpoint, used by a m2m app, client app is confidential /// it should return stacks by user id /// in order to pass validation at external deployment service - let (id,) = path.into_inner(); - tracing::info!("Logged user: {:?}", user.id); - tracing::info!("Get stack list for user {:?}", id); - - let query_span = tracing::info_span!("Get stacks by user id."); + let (user_id,) = path.into_inner(); - match sqlx::query_as!( - models::Stack, - r#" - SELECT * FROM user_stack WHERE user_id=$1 - "#, - id - ) - .fetch_all(pool.get_ref()) - .instrument(query_span) - .await - { - Ok(list) => { - return Ok(JsonResponse::build().set_list(list).ok("OK")); - } - Err(sqlx::Error::RowNotFound) => { - tracing::error!("No stacks found for user: {:?}", &user.id); - return Err(JsonResponse::::build().not_found("No stacks found for user")); - } - Err(e) => { - tracing::error!("Failed to fetch stack, error: {:?}", e); - return Err(JsonResponse::::build().internal_server_error("Could not fetch")); - } - } + db::stack::fetch_by_user(pool.get_ref(), user_id) + .await + .map_err(|err| JsonResponse::::build().internal_server_error("")) + .map(|stacks| JsonResponse::build().set_list(stacks).ok("OK")) } From 8fbf9d76de521704128657cb29921e0542f08238 Mon Sep 17 00:00:00 2001 From: petru Date: Mon, 18 Dec 2023 17:18:10 +0200 Subject: [PATCH 077/284] issue-auth routes/stack/add.rs --- src/routes/stack/add.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index 690a02a..6bbae22 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -1,7 +1,6 @@ use crate::forms::stack::StackForm; use crate::helpers::JsonResponse; use crate::models; -use crate::models::user::User; use actix_web::post; use actix_web::{ web, @@ -21,20 +20,18 @@ use std::sync::Arc; #[post("")] pub async fn add( body: Bytes, - user: web::ReqData>, + user: web::ReqData>, pool: Data, ) -> Result { // @todo ACL let body_bytes = actix_web::body::to_bytes(body).await.unwrap(); let body_str = str::from_utf8(&body_bytes).unwrap(); - let form = match serde_json::from_str::(body_str) { - Ok(f) => f, - Err(_err) => { - let msg = format!("Invalid data. {:?}", _err); - return Err(JsonResponse::::build().bad_request(msg)); - } - }; + let form = serde_json::from_str::(body_str) + .map_err(|err| { + let msg = format!("Invalid data. {:?}", err); + JsonResponse::::build().bad_request(msg) + })?; let stack_name = form.custom.custom_stack_code.clone(); tracing::debug!("form before convert {:?}", form); From 985a1a5102d2b933c7f425c499b8b62cc5e26987 Mon Sep 17 00:00:00 2001 From: petru Date: Mon, 18 Dec 2023 17:40:47 +0200 Subject: [PATCH 078/284] issue-auth src/routes/stack/add.rs --- src/db/stack.rs | 29 +++++++++++++++++++++++++++++ src/routes/stack/add.rs | 27 +++++++-------------------- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/src/db/stack.rs b/src/db/stack.rs index 5cb2f92..a6aeb59 100644 --- a/src/db/stack.rs +++ b/src/db/stack.rs @@ -49,3 +49,32 @@ pub async fn fetch_by_user(pool: &PgPool, user_id: String) -> Result Result, String> { + let query_span = tracing::info_span!("Fetch one stack by name."); + sqlx::query_as!( + models::Stack, + r#" + SELECT + * + FROM user_stack + WHERE name=$1 + LIMIT 1 + "#, + name + ) + .fetch_one(pool) + .instrument(query_span) + .await + .map(|stack| Some(stack)) + .or_else(|err| { + match err { + sqlx::Error::RowNotFound => Ok(None), + err => { + tracing::error!("Failed to fetch one stack by name, error: {:?}", err); + Err("".to_string()) + } + + } + }) +} diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index 6bbae22..2f12a2d 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -1,8 +1,9 @@ use crate::forms::stack::StackForm; use crate::helpers::JsonResponse; use crate::models; -use actix_web::post; +use crate::db; use actix_web::{ + post, web, web::{Bytes, Data}, Responder, Result, @@ -34,28 +35,14 @@ pub async fn add( })?; let stack_name = form.custom.custom_stack_code.clone(); - tracing::debug!("form before convert {:?}", form); - - let query_span = tracing::info_span!("Check project/stack existence by custom_stack_code."); - match sqlx::query_as!( - models::Stack, - r"SELECT * FROM user_stack WHERE name = $1", - stack_name - ) - .fetch_one(pool.get_ref()) - .instrument(query_span) - .await { - Ok(record) => { - tracing::info!("record exists: id: {}, name: {}", record.id, record.name); + let stack = db::stack::fetch_one_by_name(pool.get_ref(), stack_name.clone()) + .await + .map_err(|err| JsonResponse::::build().internal_server_error("Internal Server Error"))?; + if stack.is_some() { return Err(JsonResponse::::build().conflict("Stack with that name already exists")); } - Err(sqlx::Error::RowNotFound) => {} - Err(e) => { - tracing::error!("Failed to fetch stack info, error: {:?}", e); - return Err(JsonResponse::::build().bad_request("Internal Server Error")); - } - }; + } let user_id = user.id.clone(); let request_id = Uuid::new_v4(); From fa8f86ec96c1bf53ec1d5c7528f785a9a4578885 Mon Sep 17 00:00:00 2001 From: petru Date: Mon, 18 Dec 2023 17:43:37 +0200 Subject: [PATCH 079/284] issue-auth src/routes/stack/add.rs --- src/db/stack.rs | 4 ++-- src/routes/stack/add.rs | 2 +- src/routes/stack/get.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/db/stack.rs b/src/db/stack.rs index a6aeb59..3c0f753 100644 --- a/src/db/stack.rs +++ b/src/db/stack.rs @@ -29,7 +29,7 @@ pub async fn fetch(pool: &PgPool, id: i32) -> Result { }) } -pub async fn fetch_by_user(pool: &PgPool, user_id: String) -> Result, String> { +pub async fn fetch_by_user(pool: &PgPool, user_id: &str) -> Result, String> { let query_span = tracing::info_span!("Fetch stacks by user id."); sqlx::query_as!( models::Stack, @@ -50,7 +50,7 @@ pub async fn fetch_by_user(pool: &PgPool, user_id: String) -> Result Result, String> { +pub async fn fetch_one_by_name(pool: &PgPool, name: &str) -> Result, String> { let query_span = tracing::info_span!("Fetch one stack by name."); sqlx::query_as!( models::Stack, diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index 2f12a2d..8876a02 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -36,7 +36,7 @@ pub async fn add( let stack_name = form.custom.custom_stack_code.clone(); { - let stack = db::stack::fetch_one_by_name(pool.get_ref(), stack_name.clone()) + let stack = db::stack::fetch_one_by_name(pool.get_ref(), &stack_name) .await .map_err(|err| JsonResponse::::build().internal_server_error("Internal Server Error"))?; if stack.is_some() { diff --git a/src/routes/stack/get.rs b/src/routes/stack/get.rs index 7ac8fb5..b050720 100644 --- a/src/routes/stack/get.rs +++ b/src/routes/stack/get.rs @@ -38,9 +38,9 @@ pub async fn list( /// This is admin endpoint, used by a m2m app, client app is confidential /// it should return stacks by user id /// in order to pass validation at external deployment service - let (user_id,) = path.into_inner(); + let user_id = path.into_inner().0; - db::stack::fetch_by_user(pool.get_ref(), user_id) + db::stack::fetch_by_user(pool.get_ref(), &user_id) .await .map_err(|err| JsonResponse::::build().internal_server_error("")) .map(|stacks| JsonResponse::build().set_list(stacks).ok("OK")) From 46aa43dcf97b56b14ff5d7c34653d1615e7cce7f Mon Sep 17 00:00:00 2001 From: petru Date: Mon, 18 Dec 2023 19:01:44 +0200 Subject: [PATCH 080/284] issue-auth src/routes/stack/add.rs --- src/routes/stack/add.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index 8876a02..65b8c75 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -71,13 +71,11 @@ pub async fn add( return Err(JsonResponse::::build().bad_request(errors.to_string()));// tmp solution } - let body: Value = match serde_json::to_value::(form) { - Ok(body) => body, - Err(err) => { + let body: Value = serde_json::to_value::(form) + .or_else(|err| { tracing::error!("Request_id {} error unwrap body {:?}", request_id, err); - serde_json::to_value::(StackForm::default()).unwrap() - } - }; + Ok::(serde_json::to_value::(StackForm::default()).unwrap()) + }).unwrap(); match sqlx::query!( r#" From 295f36c5f6894d12b947f8b5e3270bf465a3003c Mon Sep 17 00:00:00 2001 From: petru Date: Wed, 20 Dec 2023 17:14:10 +0200 Subject: [PATCH 081/284] issue-auth client db. api --- src/db/client.rs | 9 +++++---- src/routes/client/disable.rs | 4 +++- src/routes/client/enable.rs | 4 +++- src/routes/client/update.rs | 4 +++- src/routes/stack/add.rs | 6 ++---- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/db/client.rs b/src/db/client.rs index 477dbf5..b8307a7 100644 --- a/src/db/client.rs +++ b/src/db/client.rs @@ -28,7 +28,7 @@ pub async fn update(pool: &PgPool, client: models::Client) -> Result Result { +pub async fn fetch(pool: &PgPool, id: i32) -> Result, String> { let query_span = tracing::info_span!("Fetching the client by ID"); sqlx::query_as!( models::Client, @@ -46,12 +46,13 @@ pub async fn fetch(pool: &PgPool, id: i32) -> Result { .fetch_one(pool) .instrument(query_span) .await - .map_err(|e| { + .map(|client| Some(client)) + .or_else(|e| { match e { - sqlx::Error::RowNotFound => "client not found".to_string(), + sqlx::Error::RowNotFound => Ok(None), s => { tracing::error!("Failed to execute fetch query: {:?}", s); - "".to_string() + Err("".to_string()) } } }) diff --git a/src/routes/client/disable.rs b/src/routes/client/disable.rs index 2159feb..057a183 100644 --- a/src/routes/client/disable.rs +++ b/src/routes/client/disable.rs @@ -18,7 +18,9 @@ pub async fn disable_handler( let client_id = path.0; let mut client = db::client::fetch(pool.get_ref(), client_id) .await - .map_err(|msg| JsonResponse::::build().not_found(msg))?; + .map_err(|msg| JsonResponse::::build().internal_server_error(msg))? + .ok_or_else(|| JsonResponse::::build().not_found("not found"))?; + if client.secret.is_none() { return Err(JsonResponse::::build().bad_request("client is not active")); } diff --git a/src/routes/client/enable.rs b/src/routes/client/enable.rs index 6ed95d2..5669acc 100644 --- a/src/routes/client/enable.rs +++ b/src/routes/client/enable.rs @@ -19,7 +19,9 @@ pub async fn enable_handler( let client_id = path.0; let mut client = db::client::fetch(pool.get_ref(), client_id) .await - .map_err(|msg| JsonResponse::::build().not_found(msg))?; + .map_err(|msg| JsonResponse::::build().internal_server_error(msg))? + .ok_or_else(|| JsonResponse::::build().not_found("not found"))? + ; if client.secret.is_some() { return Err(JsonResponse::::build().bad_request("client is already active")); diff --git a/src/routes/client/update.rs b/src/routes/client/update.rs index 63b02a1..b100316 100644 --- a/src/routes/client/update.rs +++ b/src/routes/client/update.rs @@ -19,7 +19,9 @@ pub async fn update_handler( let client_id = path.0; let mut client = db::client::fetch(pool.get_ref(), client_id) .await - .map_err(|msg| JsonResponse::::build().not_found(msg))?; + .map_err(|msg| JsonResponse::::build().internal_server_error(msg))? + .ok_or_else(|| JsonResponse::::build().not_found("not found"))?; + if client.secret.is_none() { return Err(JsonResponse::::build().bad_request("client is not active")); } diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index 65b8c75..dd744d2 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -72,10 +72,8 @@ pub async fn add( } let body: Value = serde_json::to_value::(form) - .or_else(|err| { - tracing::error!("Request_id {} error unwrap body {:?}", request_id, err); - Ok::(serde_json::to_value::(StackForm::default()).unwrap()) - }).unwrap(); + .or(serde_json::to_value::(StackForm::default())) + .unwrap(); match sqlx::query!( r#" From 7a3ca1a28543071e08f8e29892a6e906665e525b Mon Sep 17 00:00:00 2001 From: petru Date: Wed, 20 Dec 2023 17:18:24 +0200 Subject: [PATCH 082/284] issue-auth product db api --- src/db/product.rs | 9 +++++---- src/routes/rating/add.rs | 4 +++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/db/product.rs b/src/db/product.rs index 56431b1..e9c591a 100644 --- a/src/db/product.rs +++ b/src/db/product.rs @@ -2,7 +2,7 @@ use sqlx::PgPool; use crate::models; use tracing::Instrument; -pub async fn fetch_by_obj(pg_pool: &PgPool, obj_id: i32) -> Result { +pub async fn fetch_by_obj(pg_pool: &PgPool, obj_id: i32) -> Result, String> { let query_span = tracing::info_span!("Check product existence by id."); sqlx::query_as!( models::Product, @@ -17,12 +17,13 @@ pub async fn fetch_by_obj(pg_pool: &PgPool, obj_id: i32) -> Result "product not found".to_string(), + sqlx::Error::RowNotFound => Ok(None), s => { tracing::error!("Failed to execute fetch query: {:?}", s); - "".to_string() + Err("".to_string()) } } }) diff --git a/src/routes/rating/add.rs b/src/routes/rating/add.rs index 88ec9b9..7ab543c 100644 --- a/src/routes/rating/add.rs +++ b/src/routes/rating/add.rs @@ -22,7 +22,9 @@ pub async fn add_handler( ) -> Result { let _product = db::product::fetch_by_obj(pg_pool.get_ref(), form.obj_id) .await - .map_err(|msg| JsonResponse::::build().not_found(msg))?; + .map_err(|msg| JsonResponse::::build().internal_server_error(msg))? + .ok_or_else(|| JsonResponse::::build().not_found("not found"))? + ; match db::rating::fetch_by_obj_and_user_and_category(pg_pool.get_ref(), form.obj_id, user.id.clone(), form.category).await { Ok(record) => { From da380cf4ce104df1f1c8c6ac9a7952c1a46deb8f Mon Sep 17 00:00:00 2001 From: petru Date: Wed, 20 Dec 2023 17:22:55 +0200 Subject: [PATCH 083/284] issue-auth rating db api --- src/db/rating.rs | 9 +++++---- src/routes/rating/get.rs | 8 +++++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/db/rating.rs b/src/db/rating.rs index e5cb40f..d1b1455 100644 --- a/src/db/rating.rs +++ b/src/db/rating.rs @@ -27,7 +27,7 @@ pub async fn fetch_all(pool: &PgPool) -> Result, String> { }) } -pub async fn fetch(pool: &PgPool, id: i32) -> Result { +pub async fn fetch(pool: &PgPool, id: i32) -> Result, String> { let query_span = tracing::info_span!("Fetch rating by id"); sqlx::query_as!( models::Rating, @@ -49,12 +49,13 @@ pub async fn fetch(pool: &PgPool, id: i32) -> Result { .fetch_one(pool) .instrument(query_span) .await - .map_err(|e| { + .map(|rating| Some(rating)) + .or_else(|e| { match e { - sqlx::Error::RowNotFound => "rating not found".to_string(), + sqlx::Error::RowNotFound => Ok(None), s => { tracing::error!("Failed to execute fetch query: {:?}", s); - "".to_string() + Err("".to_string()) } } }) diff --git a/src/routes/rating/get.rs b/src/routes/rating/get.rs index 86c0e57..4bc0c1f 100644 --- a/src/routes/rating/get.rs +++ b/src/routes/rating/get.rs @@ -17,10 +17,12 @@ pub async fn get_handler( pool: web::Data, ) -> Result { let rate_id = path.0; - db::rating::fetch(pool.get_ref(), rate_id) + let rating = db::rating::fetch(pool.get_ref(), rate_id) .await - .map(|rating| JsonResponse::build().set_item(rating).ok("OK")) - .map_err(|err| JsonResponse::::build().not_found("not found")) + .map_err(|_err| JsonResponse::::build().internal_server_error(""))? + .ok_or_else(|| JsonResponse::::build().not_found("not found"))?; + + Ok(JsonResponse::build().set_item(rating).ok("OK")) } #[tracing::instrument(name = "Get all ratings.")] From 0262171f093b1a8f4e6c1aa127dfbb92c0035c5b Mon Sep 17 00:00:00 2001 From: petru Date: Thu, 21 Dec 2023 18:00:28 +0200 Subject: [PATCH 084/284] issue-auth db::rating::fetch_by_obj_and_user_and_category --- src/db/rating.rs | 14 ++++++++++---- src/routes/rating/add.rs | 10 +++++----- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/db/rating.rs b/src/db/rating.rs index d1b1455..599c49c 100644 --- a/src/db/rating.rs +++ b/src/db/rating.rs @@ -61,7 +61,12 @@ pub async fn fetch(pool: &PgPool, id: i32) -> Result, Str }) } -pub async fn fetch_by_obj_and_user_and_category(pool: &PgPool, obj_id: i32, user_id: String, category: models::RateCategory) -> Result { +pub async fn fetch_by_obj_and_user_and_category( + pool: &PgPool, + obj_id: i32, + user_id: String, + category: models::RateCategory, +) -> Result, String> { let query_span = tracing::info_span!("Fetch rating by obj, user and category."); sqlx::query_as!( models::Rating, @@ -87,12 +92,13 @@ pub async fn fetch_by_obj_and_user_and_category(pool: &PgPool, obj_id: i32, user .fetch_one(pool) .instrument(query_span) .await - .map_err(|e| { + .map(|rating| Some(rating)) + .or_else(|e| { match e { - sqlx::Error::RowNotFound => "fetch not found".to_string(), + sqlx::Error::RowNotFound => Ok(None), s => { tracing::error!("Failed to execute fetch query: {:?}", s); - "".to_string() + Err("".to_string()) } } }) diff --git a/src/routes/rating/add.rs b/src/routes/rating/add.rs index 7ab543c..48f0330 100644 --- a/src/routes/rating/add.rs +++ b/src/routes/rating/add.rs @@ -26,11 +26,11 @@ pub async fn add_handler( .ok_or_else(|| JsonResponse::::build().not_found("not found"))? ; - match db::rating::fetch_by_obj_and_user_and_category(pg_pool.get_ref(), form.obj_id, user.id.clone(), form.category).await { - Ok(record) => { - return Err(JsonResponse::::build().conflict("Already rated")); - } - Err(_e) => {} + let rating = db::rating::fetch_by_obj_and_user_and_category(pg_pool.get_ref(), form.obj_id, user.id.clone(), form.category) + .await + .map_err(|err| JsonResponse::::build().internal_server_error(err))?; + if rating.is_some() { + return Err(JsonResponse::::build().bad_request("already rated")); } let mut rating: models::Rating = form.into_inner().into(); From a4998fc840de9ec430ada57ee26bc8e509dbc733 Mon Sep 17 00:00:00 2001 From: petru Date: Thu, 21 Dec 2023 18:06:48 +0200 Subject: [PATCH 085/284] issue-auth db::stack::fetch --- src/db/stack.rs | 9 +++++---- src/routes/stack/get.rs | 4 +++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/db/stack.rs b/src/db/stack.rs index 3c0f753..ec0970b 100644 --- a/src/db/stack.rs +++ b/src/db/stack.rs @@ -2,7 +2,7 @@ use sqlx::PgPool; use crate::models; use tracing::Instrument; -pub async fn fetch(pool: &PgPool, id: i32) -> Result { +pub async fn fetch(pool: &PgPool, id: i32) -> Result, String> { tracing::info!("Fecth stack {}", id); sqlx::query_as!( models::Stack, @@ -17,12 +17,13 @@ pub async fn fetch(pool: &PgPool, id: i32) -> Result { ) .fetch_one(pool) .await - .map_err(|err| { + .map(|stack| Some(stack)) + .or_else(|err| { match err { - sqlx::Error::RowNotFound => "".to_string(), + sqlx::Error::RowNotFound => Ok(None), e => { tracing::error!("Failed to fetch stack, error: {:?}", e); - return "Could not fetch data".to_string(); + Err("Could not fetch data".to_string()) } } diff --git a/src/routes/stack/get.rs b/src/routes/stack/get.rs index b050720..18a044c 100644 --- a/src/routes/stack/get.rs +++ b/src/routes/stack/get.rs @@ -19,7 +19,9 @@ pub async fn item( let stack = db::stack::fetch(pool.get_ref(), id) .await - .map_err(|err| JsonResponse::::build().not_found("Record not found"))?; + .map_err(|err| JsonResponse::::build().internal_server_error(err))? + .ok_or_else(|| JsonResponse::::build().not_found("not found"))? + ; if stack.user_id != user.id { return Err(JsonResponse::::build().bad_request("Forbidden")); From 2e6f5e390c68e80b50faad97234b5841ec3d2840 Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 23 Dec 2023 09:06:38 +0200 Subject: [PATCH 086/284] issue-auth db::stack::insert --- src/db/stack.rs | 56 +++++++++++++++++++++++----------- src/models/stack.rs | 26 ++++++++++++---- src/routes/stack/add.rs | 66 ++++++++++++++--------------------------- 3 files changed, 82 insertions(+), 66 deletions(-) diff --git a/src/db/stack.rs b/src/db/stack.rs index ec0970b..92725cd 100644 --- a/src/db/stack.rs +++ b/src/db/stack.rs @@ -1,5 +1,5 @@ -use sqlx::PgPool; use crate::models; +use sqlx::PgPool; use tracing::Instrument; pub async fn fetch(pool: &PgPool, id: i32) -> Result, String> { @@ -18,14 +18,11 @@ pub async fn fetch(pool: &PgPool, id: i32) -> Result, Stri .fetch_one(pool) .await .map(|stack| Some(stack)) - .or_else(|err| { - match err { - sqlx::Error::RowNotFound => Ok(None), - e => { - tracing::error!("Failed to fetch stack, error: {:?}", e); - Err("Could not fetch data".to_string()) - } - + .or_else(|err| match err { + sqlx::Error::RowNotFound => Ok(None), + e => { + tracing::error!("Failed to fetch stack, error: {:?}", e); + Err("Could not fetch data".to_string()) } }) } @@ -68,14 +65,39 @@ pub async fn fetch_one_by_name(pool: &PgPool, name: &str) -> Result Ok(None), - err => { - tracing::error!("Failed to fetch one stack by name, error: {:?}", err); - Err("".to_string()) - } - + .or_else(|err| match err { + sqlx::Error::RowNotFound => Ok(None), + err => { + tracing::error!("Failed to fetch one stack by name, error: {:?}", err); + Err("".to_string()) } }) } + +pub async fn insert(pool: &PgPool, mut stack: models::Stack) -> Result { + let query_span = tracing::info_span!("Saving new stack into the database"); + sqlx::query!( + r#" + INSERT INTO user_stack (stack_id, user_id, name, body, created_at, updated_at) + VALUES ($1, $2, $3, $4, $5, $6) + RETURNING id; + "#, + stack.stack_id, + stack.user_id, + stack.name, + stack.body, + stack.created_at, + stack.updated_at, + ) + .fetch_one(pool) + .instrument(query_span) + .await + .map(move |result| { + stack.id = result.id; + stack + }) + .map_err(|e| { + tracing::error!("Failed to execute query: {:?}", e); + "Failed to insert".to_string() + }) +} diff --git a/src/models/stack.rs b/src/models/stack.rs index f9ce272..a808f13 100644 --- a/src/models/stack.rs +++ b/src/models/stack.rs @@ -1,13 +1,13 @@ use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; use serde_json::Value; use uuid::Uuid; -use serde::{Serialize,Deserialize}; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Stack { - pub id: i32, // id - is a unique identifier for the app stack - pub stack_id: Uuid, // external stack ID - pub user_id: String, // external unique identifier for the user + pub id: i32, // id - is a unique identifier for the app stack + pub stack_id: Uuid, // external stack ID + pub user_id: String, // external unique identifier for the user pub name: String, // pub body: sqlx::types::Json, pub body: Value, //json type @@ -15,12 +15,26 @@ pub struct Stack { pub updated_at: DateTime, } +impl Stack { + pub fn new(user_id: String, name: String, body: Value) -> Self { + Self { + id: 0, + stack_id: Uuid::new_v4(), + user_id: user_id, + name: name, + body: body, + created_at: Utc::now(), + updated_at: Utc::now(), + } + } +} + impl Default for Stack { fn default() -> Self { Stack { user_id: "".to_string(), name: "".to_string(), - ..Default::default() + ..Default::default() } } -} \ No newline at end of file +} diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index dd744d2..c08255f 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -1,21 +1,20 @@ +use crate::db; use crate::forms::stack::StackForm; use crate::helpers::JsonResponse; use crate::models; -use crate::db; use actix_web::{ - post, - web, + post, web, web::{Bytes, Data}, Responder, Result, }; use chrono::Utc; use serde_json::Value; +use serde_valid::Validate; use sqlx::PgPool; use std::str; -use serde_valid::Validate; +use std::sync::Arc; use tracing::Instrument; use uuid::Uuid; -use std::sync::Arc; #[tracing::instrument(name = "Add stack.")] #[post("")] @@ -24,23 +23,25 @@ pub async fn add( user: web::ReqData>, pool: Data, ) -> Result { - // @todo ACL let body_bytes = actix_web::body::to_bytes(body).await.unwrap(); let body_str = str::from_utf8(&body_bytes).unwrap(); - let form = serde_json::from_str::(body_str) - .map_err(|err| { - let msg = format!("Invalid data. {:?}", err); - JsonResponse::::build().bad_request(msg) - })?; + let form = serde_json::from_str::(body_str).map_err(|err| { + let msg = format!("Invalid data. {:?}", err); + JsonResponse::::build().bad_request(msg) + })?; let stack_name = form.custom.custom_stack_code.clone(); { let stack = db::stack::fetch_one_by_name(pool.get_ref(), &stack_name) .await - .map_err(|err| JsonResponse::::build().internal_server_error("Internal Server Error"))?; + .map_err(|err| { + JsonResponse::::build() + .internal_server_error("Internal Server Error") + })?; if stack.is_some() { - return Err(JsonResponse::::build().conflict("Stack with that name already exists")); + return Err(JsonResponse::::build() + .conflict("Stack with that name already exists")); } } @@ -68,40 +69,19 @@ pub async fn add( let errors = form.validate().unwrap_err(); let err_msg = format!("Invalid data received {:?}", &errors.to_string()); tracing::debug!(err_msg); - return Err(JsonResponse::::build().bad_request(errors.to_string()));// tmp solution + return Err(JsonResponse::::build().bad_request(errors.to_string())); + // tmp solution } let body: Value = serde_json::to_value::(form) .or(serde_json::to_value::(StackForm::default())) .unwrap(); - match sqlx::query!( - r#" - INSERT INTO user_stack (stack_id, user_id, name, body, created_at, updated_at) - VALUES ($1, $2, $3, $4, $5, $6) - RETURNING id; - "#, - Uuid::new_v4(), - user_id, - stack_name, - body, - Utc::now(), - Utc::now(), - ) - .fetch_one(pool.get_ref()) - .instrument(query_span) - .await - { - Ok(record) => { - tracing::info!( - "req_id: {} New stack details have been saved to database", - request_id - ); - return Ok(JsonResponse::::build().set_id(record.id).ok("OK")); - } - Err(e) => { - tracing::error!("req_id: {} Failed to execute query: {:?}", request_id, e); - return Err(JsonResponse::::build().internal_server_error("Internal Server Error")); - } - }; + let stack = models::Stack::new(user_id, stack_name, body); + db::stack::insert(pool.get_ref(), stack) + .await + .map(|stack| JsonResponse::build().set_item(stack).ok("Ok")) + .map_err(|_| { + JsonResponse::::build().internal_server_error("Internal Server Error") + }) } From 4f13c4cf9ddb1adb916769b367b1a92e6884dc8b Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 23 Dec 2023 09:09:23 +0200 Subject: [PATCH 087/284] issue-auth removed tracings --- src/routes/stack/add.rs | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index c08255f..2db892b 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -45,26 +45,6 @@ pub async fn add( } } - let user_id = user.id.clone(); - let request_id = Uuid::new_v4(); - let request_span = tracing::info_span!( - "Validating a new stack", %request_id, - commonDomain=?&form.custom.project_name, - region=?&form.region, - domainList=?&form.domain_list - ); - // using `enter` is an async function - let _request_span_guard = request_span.enter(); // ->exit - - tracing::info!( - "request_id {} Adding '{}' '{}' as a new stack", - request_id, - form.custom.project_name, - form.region - ); - - let query_span = tracing::info_span!("Saving new stack details into the database"); - if !form.validate().is_ok() { let errors = form.validate().unwrap_err(); let err_msg = format!("Invalid data received {:?}", &errors.to_string()); @@ -77,7 +57,7 @@ pub async fn add( .or(serde_json::to_value::(StackForm::default())) .unwrap(); - let stack = models::Stack::new(user_id, stack_name, body); + let stack = models::Stack::new(user.id.clone(), stack_name, body); db::stack::insert(pool.get_ref(), stack) .await .map(|stack| JsonResponse::build().set_item(stack).ok("Ok")) From a10eca7d6691ba9ec5665b578959007eec587f70 Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 23 Dec 2023 09:29:08 +0200 Subject: [PATCH 088/284] issue-auth src/routes/stack.add.rs internal server error --- src/routes/stack/add.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index 2db892b..9757f22 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -7,14 +7,11 @@ use actix_web::{ web::{Bytes, Data}, Responder, Result, }; -use chrono::Utc; use serde_json::Value; use serde_valid::Validate; use sqlx::PgPool; use std::str; use std::sync::Arc; -use tracing::Instrument; -use uuid::Uuid; #[tracing::instrument(name = "Add stack.")] #[post("")] @@ -25,7 +22,8 @@ pub async fn add( ) -> Result { // @todo ACL let body_bytes = actix_web::body::to_bytes(body).await.unwrap(); - let body_str = str::from_utf8(&body_bytes).unwrap(); + let body_str = str::from_utf8(&body_bytes) + .map_err(|err| JsonResponse::::build().internal_server_error(err.to_string()))?; let form = serde_json::from_str::(body_str).map_err(|err| { let msg = format!("Invalid data. {:?}", err); JsonResponse::::build().bad_request(msg) From e569835d7b0c1615dd38dd0b1584b31f8b5db248 Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 23 Dec 2023 09:47:15 +0200 Subject: [PATCH 089/284] issue-auth check_if_stack_exists --- src/routes/stack/add.rs | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index 9757f22..71d73b2 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -2,6 +2,7 @@ use crate::db; use crate::forms::stack::StackForm; use crate::helpers::JsonResponse; use crate::models; +use actix_web::Error; use actix_web::{ post, web, web::{Bytes, Data}, @@ -30,18 +31,7 @@ pub async fn add( })?; let stack_name = form.custom.custom_stack_code.clone(); - { - let stack = db::stack::fetch_one_by_name(pool.get_ref(), &stack_name) - .await - .map_err(|err| { - JsonResponse::::build() - .internal_server_error("Internal Server Error") - })?; - if stack.is_some() { - return Err(JsonResponse::::build() - .conflict("Stack with that name already exists")); - } - } + check_if_stack_exists(pool.get_ref(), &stack_name).await?; if !form.validate().is_ok() { let errors = form.validate().unwrap_err(); @@ -63,3 +53,16 @@ pub async fn add( JsonResponse::::build().internal_server_error("Internal Server Error") }) } + +async fn check_if_stack_exists(pool: &PgPool, stack_name: &String) -> Result<(), Error> { + db::stack::fetch_one_by_name(pool, stack_name) + .await + .map_err(|_| { + JsonResponse::::build().internal_server_error("Internal Server Error") + }) + .and_then(|stack| match stack { + Some(_) => Err(JsonResponse::::build() + .conflict("Stack with that name already exists")), + None => Ok(()), + }) +} From 32b571dc64d49cedb7cd74955ac3fed580d43a81 Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 23 Dec 2023 09:55:49 +0200 Subject: [PATCH 090/284] issue-auth convert body to form --- src/forms/stack.rs | 157 +++++++++++++++++++--------------------- src/routes/stack/add.rs | 20 +++-- 2 files changed, 88 insertions(+), 89 deletions(-) diff --git a/src/forms/stack.rs b/src/forms/stack.rs index b67a856..cc32233 100644 --- a/src/forms/stack.rs +++ b/src/forms/stack.rs @@ -1,10 +1,9 @@ -use std::collections::HashMap; use serde::{Deserialize, Serialize}; use serde_json::Value; use serde_valid::Validate; +use std::collections::HashMap; use std::fmt; - #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Role { pub role: Option>, @@ -12,18 +11,18 @@ pub struct Role { #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Requirements { - #[validate(min_length=1)] - #[validate(max_length=10)] + #[validate(min_length = 1)] + #[validate(max_length = 10)] #[validate(pattern = r"^\d+\.?[0-9]+$")] pub cpu: Option, - #[validate(min_length=1)] - #[validate(max_length=10)] + #[validate(min_length = 1)] + #[validate(max_length = 10)] #[validate(pattern = r"^\d+G$")] #[serde(rename = "disk_size")] pub disk_size: Option, #[serde(rename = "ram_size")] - #[validate(min_length=1)] - #[validate(max_length=10)] + #[validate(min_length = 1)] + #[validate(max_length = 10)] #[validate(pattern = r"^\d+G$")] pub ram_size: Option, } @@ -31,7 +30,7 @@ pub struct Requirements { #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Port { pub host_port: Option, - pub container_port: Option + pub container_port: Option, } // #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -45,27 +44,31 @@ pub struct Port { #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct DockerImage { - #[validate(min_length=3)] - #[validate(max_length=50)] + #[validate(min_length = 3)] + #[validate(max_length = 50)] pub dockerhub_user: Option, - #[validate(min_length=3)] - #[validate(max_length=50)] + #[validate(min_length = 3)] + #[validate(max_length = 50)] pub dockerhub_name: Option, - #[validate(min_length=3)] - #[validate(max_length=100)] + #[validate(min_length = 3)] + #[validate(max_length = 100)] pub dockerhub_image: Option, } -impl fmt::Display for DockerImage -{ +impl fmt::Display for DockerImage { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let tag = "latest"; - let dim = self.dockerhub_image.clone() - .unwrap_or("".to_string()); - write!(f, "{}/{}:{}", self.dockerhub_user.clone() - .unwrap_or("trydirect".to_string()).clone(), - self.dockerhub_name.clone().unwrap_or(dim), tag + let dim = self.dockerhub_image.clone().unwrap_or("".to_string()); + write!( + f, + "{}/{}:{}", + self.dockerhub_user + .clone() + .unwrap_or("trydirect".to_string()) + .clone(), + self.dockerhub_name.clone().unwrap_or(dim), + tag ) } } @@ -76,61 +79,59 @@ impl AsRef for App { } } - #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct StackForm { // #[validate(min_length=2)] // #[validate(max_length=255)] - #[serde(rename= "commonDomain")] + #[serde(rename = "commonDomain")] pub common_domain: Option, pub domain_list: Option, - #[validate(min_length=2)] - #[validate(max_length=255)] + #[validate(min_length = 2)] + #[validate(max_length = 255)] pub stack_code: Option, - #[validate(min_length=2)] - #[validate(max_length=50)] + #[validate(min_length = 2)] + #[validate(max_length = 50)] pub region: String, - #[validate(min_length=2)] - #[validate(max_length=50)] + #[validate(min_length = 2)] + #[validate(max_length = 50)] pub zone: Option, - #[validate(min_length=2)] - #[validate(max_length=50)] + #[validate(min_length = 2)] + #[validate(max_length = 50)] pub server: String, - #[validate(min_length=2)] - #[validate(max_length=50)] + #[validate(min_length = 2)] + #[validate(max_length = 50)] pub os: String, - #[validate(min_length=3)] - #[validate(max_length=50)] + #[validate(min_length = 3)] + #[validate(max_length = 50)] pub ssl: String, pub vars: Option>, pub integrated_features: Option>, pub extended_features: Option>, pub subscriptions: Option>, pub form_app: Option>, - #[validate(min_length=3)] - #[validate(max_length=50)] + #[validate(min_length = 3)] + #[validate(max_length = 50)] pub disk_type: Option, pub save_token: bool, - #[validate(min_length=10)] - #[validate(max_length=255)] + #[validate(min_length = 10)] + #[validate(max_length = 255)] pub cloud_token: String, - #[validate(min_length=2)] - #[validate(max_length=50)] + #[validate(min_length = 2)] + #[validate(max_length = 50)] pub provider: String, - #[validate(min_length=3)] - #[validate(max_length=50)] + #[validate(min_length = 3)] + #[validate(max_length = 50)] pub selected_plan: String, pub custom: Custom, } - #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] #[serde(rename_all = "snake_case")] pub struct StackPayload { pub(crate) id: Option, pub(crate) user_token: Option, pub(crate) user_email: Option, - #[serde(rename= "commonDomain")] + #[serde(rename = "commonDomain")] pub common_domain: String, pub domain_list: Option, pub region: String, @@ -159,17 +160,15 @@ pub struct StackPayload { #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct DomainList { -} +pub struct DomainList {} #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct Var { -} +pub struct Var {} #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Price { - pub value: f64 + pub value: f64, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Custom { @@ -179,17 +178,17 @@ pub struct Custom { #[validate(minimum = 0)] #[validate(maximum = 10)] pub servers_count: u32, - #[validate(min_length=3)] - #[validate(max_length=50)] + #[validate(min_length = 3)] + #[validate(max_length = 50)] pub custom_stack_code: String, - #[validate(min_length=3)] - #[validate(max_length=255)] + #[validate(min_length = 3)] + #[validate(max_length = 255)] pub project_git_url: Option, pub custom_stack_category: Option>, pub custom_stack_short_description: Option, pub custom_stack_description: Option, - #[validate(min_length=3)] - #[validate(max_length=255)] + #[validate(min_length = 3)] + #[validate(max_length = 255)] pub project_name: String, pub project_overview: Option, pub project_description: Option, @@ -199,15 +198,14 @@ pub struct Custom { #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Network { - name: String + name: String, } - #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct App { #[serde(rename = "_etag")] - #[validate(min_length=3)] - #[validate(max_length=255)] + #[validate(min_length = 3)] + #[validate(max_length = 255)] pub etag: Option, #[serde(rename = "_id")] pub id: u32, @@ -215,14 +213,14 @@ pub struct App { pub created: Option, #[serde(rename = "_updated")] pub updated: Option, - #[validate(min_length=3)] - #[validate(max_length=50)] + #[validate(min_length = 3)] + #[validate(max_length = 50)] pub name: String, - #[validate(min_length=3)] - #[validate(max_length=50)] + #[validate(min_length = 3)] + #[validate(max_length = 50)] pub code: String, - #[validate(min_length=3)] - #[validate(max_length=50)] + #[validate(min_length = 3)] + #[validate(max_length = 50)] #[serde(rename = "type")] pub type_field: String, #[serde(flatten)] @@ -233,7 +231,7 @@ pub struct App { pub docker_image: DockerImage, #[serde(flatten)] pub requirements: Requirements, - #[validate(minimum=1)] + #[validate(minimum = 1)] pub popularity: Option, pub commercial: Option, pub subscription: Option, @@ -271,28 +269,28 @@ pub struct App { #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Environment { - pub(crate) environment: Option>> + pub(crate) environment: Option>>, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Volume { pub(crate) host_path: Option, - pub(crate) container_path: Option + pub(crate) container_path: Option, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Volumes { - volumes: Vec + volumes: Vec, } // pub(crate) type Networks = Option>; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct ServiceNetworks { - pub network: Option> + pub network: Option>, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct ComposeNetworks { - pub networks: Option> + pub networks: Option>, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -337,8 +335,7 @@ pub struct IconLight { } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct IconDark { -} +pub struct IconDark {} #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Version { @@ -352,14 +349,12 @@ pub struct Version { pub updated: Option, pub app_id: Option, pub name: String, - #[validate(min_length=3)] - #[validate(max_length=20)] + #[validate(min_length = 3)] + #[validate(max_length = 20)] pub version: String, #[serde(rename = "update_status")] pub update_status: Option, - #[validate(min_length=3)] - #[validate(max_length=20)] + #[validate(min_length = 3)] + #[validate(max_length = 20)] pub tag: String, } - - diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index 71d73b2..4c940c8 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -22,15 +22,9 @@ pub async fn add( pool: Data, ) -> Result { // @todo ACL - let body_bytes = actix_web::body::to_bytes(body).await.unwrap(); - let body_str = str::from_utf8(&body_bytes) - .map_err(|err| JsonResponse::::build().internal_server_error(err.to_string()))?; - let form = serde_json::from_str::(body_str).map_err(|err| { - let msg = format!("Invalid data. {:?}", err); - JsonResponse::::build().bad_request(msg) - })?; - + let form = convert_body_to_form(body).await?; let stack_name = form.custom.custom_stack_code.clone(); + check_if_stack_exists(pool.get_ref(), &stack_name).await?; if !form.validate().is_ok() { @@ -66,3 +60,13 @@ async fn check_if_stack_exists(pool: &PgPool, stack_name: &String) -> Result<(), None => Ok(()), }) } + +async fn convert_body_to_form(body: Bytes) -> Result { + let body_bytes = actix_web::body::to_bytes(body).await.unwrap(); + let body_str = str::from_utf8(&body_bytes) + .map_err(|err| JsonResponse::::build().internal_server_error(err.to_string()))?; + serde_json::from_str::(body_str).map_err(|err| { + let msg = format!("Invalid data. {:?}", err); + JsonResponse::::build().bad_request(msg) + }) +} From 0626be0384021a0408ad5960f2ad1ff1de24ac0e Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 23 Dec 2023 10:08:57 +0200 Subject: [PATCH 091/284] issue-auth body_to_form --- src/routes/stack/add.rs | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index 4c940c8..ec9c806 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -22,19 +22,11 @@ pub async fn add( pool: Data, ) -> Result { // @todo ACL - let form = convert_body_to_form(body).await?; + let form = body_into_form(body).await?; let stack_name = form.custom.custom_stack_code.clone(); check_if_stack_exists(pool.get_ref(), &stack_name).await?; - if !form.validate().is_ok() { - let errors = form.validate().unwrap_err(); - let err_msg = format!("Invalid data received {:?}", &errors.to_string()); - tracing::debug!(err_msg); - return Err(JsonResponse::::build().bad_request(errors.to_string())); - // tmp solution - } - let body: Value = serde_json::to_value::(form) .or(serde_json::to_value::(StackForm::default())) .unwrap(); @@ -61,12 +53,23 @@ async fn check_if_stack_exists(pool: &PgPool, stack_name: &String) -> Result<(), }) } -async fn convert_body_to_form(body: Bytes) -> Result { +async fn body_into_form(body: Bytes) -> Result { let body_bytes = actix_web::body::to_bytes(body).await.unwrap(); let body_str = str::from_utf8(&body_bytes) .map_err(|err| JsonResponse::::build().internal_server_error(err.to_string()))?; - serde_json::from_str::(body_str).map_err(|err| { - let msg = format!("Invalid data. {:?}", err); - JsonResponse::::build().bad_request(msg) - }) + serde_json::from_str::(body_str) + .map_err(|err| { + let msg = format!("Invalid data. {:?}", err); + JsonResponse::::build().bad_request(msg) + }) + .and_then(|form| { + if !form.validate().is_ok() { + let errors = form.validate().unwrap_err(); + let err_msg = format!("Invalid data received {:?}", &errors.to_string()); + tracing::debug!(err_msg); + return Err(JsonResponse::::build().bad_request(errors.to_string())); + } + + Ok(form) + }) } From 63fa86b77ccb97ec27e2bb1885ae885bf63aef8c Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 23 Dec 2023 18:03:13 +0200 Subject: [PATCH 092/284] issue-auth json error path --- Cargo.lock | 11 +++++++++++ Cargo.toml | 1 + src/routes/stack/add.rs | 18 ++++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 6c5834b..73e0b28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2803,6 +2803,16 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335" +dependencies = [ + "itoa", + "serde", +] + [[package]] name = "serde_qs" version = "0.8.5" @@ -3107,6 +3117,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", + "serde_path_to_error", "serde_valid", "serde_yaml", "sha2", diff --git a/Cargo.toml b/Cargo.toml index b23bf3b..54ee40f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,6 +52,7 @@ serde_yaml = "0.9" lapin = { version = "2.3.1", features = ["serde_json"] } futures-lite = "1.13.0" clap = { version = "4.4.8", features = ["derive"] } +serde_path_to_error = "0.1.14" [dependencies.sqlx] version = "0.6.3" diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index ec9c806..b8c3e26 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -57,6 +57,23 @@ async fn body_into_form(body: Bytes) -> Result { let body_bytes = actix_web::body::to_bytes(body).await.unwrap(); let body_str = str::from_utf8(&body_bytes) .map_err(|err| JsonResponse::::build().internal_server_error(err.to_string()))?; + let deserializer = &mut serde_json::Deserializer::from_str(body_str); + serde_path_to_error::deserialize(deserializer) + .map_err(|err| { + let msg = format!("{}:{:?}", err.path().to_string(), err); + JsonResponse::::build().bad_request(msg) + }) + .and_then(|form: StackForm| { + if !form.validate().is_ok() { + let errors = form.validate().unwrap_err(); + let err_msg = format!("Invalid data received {:?}", &errors.to_string()); + tracing::debug!(err_msg); + return Err(JsonResponse::::build().bad_request(errors.to_string())); + } + + Ok(form) + }) + /* serde_json::from_str::(body_str) .map_err(|err| { let msg = format!("Invalid data. {:?}", err); @@ -72,4 +89,5 @@ async fn body_into_form(body: Bytes) -> Result { Ok(form) }) + */ } From 623e5ddd012a9d1ea52973853a24be5af1f3dd6a Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 23 Dec 2023 18:05:35 +0200 Subject: [PATCH 093/284] issue-auth removed comments --- src/routes/stack/add.rs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index b8c3e26..ef38ac5 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -73,21 +73,4 @@ async fn body_into_form(body: Bytes) -> Result { Ok(form) }) - /* - serde_json::from_str::(body_str) - .map_err(|err| { - let msg = format!("Invalid data. {:?}", err); - JsonResponse::::build().bad_request(msg) - }) - .and_then(|form| { - if !form.validate().is_ok() { - let errors = form.validate().unwrap_err(); - let err_msg = format!("Invalid data received {:?}", &errors.to_string()); - tracing::debug!(err_msg); - return Err(JsonResponse::::build().bad_request(errors.to_string())); - } - - Ok(form) - }) - */ } From a197ba53de7796fa768027e47acb1b72a6a9e1e6 Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 23 Dec 2023 18:28:14 +0200 Subject: [PATCH 094/284] issue-auth stack/compose.rs add --- src/routes/stack/compose.rs | 92 +++++++++++-------------------------- 1 file changed, 28 insertions(+), 64 deletions(-) diff --git a/src/routes/stack/compose.rs b/src/routes/stack/compose.rs index b92930b..508d234 100644 --- a/src/routes/stack/compose.rs +++ b/src/routes/stack/compose.rs @@ -1,77 +1,46 @@ -use actix_web::{ - web, - web::{Data, Json}, - Responder, Result, -}; +use actix_web::{get, web, web::Data, Responder, Result}; +use crate::db; use crate::helpers::stack::builder::DcBuilder; use crate::helpers::JsonResponse; -use crate::models::user::User; -use crate::models::Stack; -use actix_web::{get, post}; +use crate::models; use sqlx::PgPool; -use std::str; -use tracing::Instrument; use std::sync::Arc; #[tracing::instrument(name = "User's generate docker-compose.")] #[get("/{id}")] pub async fn add( - user: web::ReqData>, + user: web::ReqData>, path: web::Path<(i32,)>, pool: Data, ) -> Result { let id = path.0; - tracing::debug!("Received id: {}", id); - - let stack = match sqlx::query_as!( - Stack, - r#" - SELECT * FROM user_stack WHERE id=$1 AND user_id=$2 LIMIT 1 - "#, - id, - user.id - ) - .fetch_one(pool.get_ref()) - .await - { - Ok(stack) => { - tracing::info!("stack found: {:?}", stack.id); - Some(stack) - } - Err(sqlx::Error::RowNotFound) => { - tracing::error!("Row not found 404"); - None - } - Err(e) => { - tracing::error!("Failed to fetch stack, error: {:?}", e); - None - } - }; + let stack = db::stack::fetch(pool.get_ref(), id) + .await + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .and_then(|stack| match stack { + Some(stack) if stack.user_id != user.id => { + Err(JsonResponse::::build().not_found("not found")) + } + Some(stack) => Ok(stack), + None => Err(JsonResponse::::build().not_found("not found")), + })?; - match stack { - Some(stack) => { - let id = stack.id.clone(); - let dc = DcBuilder::new(stack); - let fc = dc.build(); - tracing::debug!("Docker compose file content {:?}", fc); + let id = stack.id.clone(); + let dc = DcBuilder::new(stack); + let fc = dc.build(); + tracing::debug!("Docker compose file content {:?}", fc); - return Ok(JsonResponse::build() - .set_id(id) - .set_item(fc.unwrap()) - .ok("Success") - ); - } - None => { - return Err(JsonResponse::::build().bad_request("Could not generate compose file")); - } - } + Ok(JsonResponse::build() + .set_id(id) + .set_item(fc.unwrap()) + .ok("Success")) } #[tracing::instrument(name = "Generate docker-compose. Admin")] #[get("/{id}/compose")] pub async fn admin( - user: web::ReqData>, + user: web::ReqData>, path: web::Path<(i32,)>, pool: Data, ) -> Result { @@ -80,7 +49,7 @@ pub async fn admin( tracing::debug!("Received id: {}", id); let stack = match sqlx::query_as!( - Stack, + models::Stack, r#" SELECT * FROM user_stack WHERE id=$1 LIMIT 1 "#, @@ -108,23 +77,18 @@ pub async fn admin( let id = stack.id.clone(); let dc = DcBuilder::new(stack); let fc = match dc.build() { - Some(fc) => { - fc - } + Some(fc) => fc, None => { tracing::error!("Error. Compose builder returned an empty string"); "".to_string() } - }; // tracing::debug!("Docker compose file content {:?}", fc); - return Ok(JsonResponse::build() - .set_id(id) - .set_item(fc).ok("Success")); - + return Ok(JsonResponse::build().set_id(id).set_item(fc).ok("Success")); } None => { - return Err(JsonResponse::::build().bad_request("Could not generate compose file")); + return Err(JsonResponse::::build() + .bad_request("Could not generate compose file")); } } } From 335b62ac3986a290ebbb511089ef5eab19597a02 Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 23 Dec 2023 18:35:42 +0200 Subject: [PATCH 095/284] issue-auth compose.rs admin route --- src/routes/stack/compose.rs | 59 +++++++++++-------------------------- 1 file changed, 17 insertions(+), 42 deletions(-) diff --git a/src/routes/stack/compose.rs b/src/routes/stack/compose.rs index 508d234..d4e3eb4 100644 --- a/src/routes/stack/compose.rs +++ b/src/routes/stack/compose.rs @@ -28,7 +28,7 @@ pub async fn add( let id = stack.id.clone(); let dc = DcBuilder::new(stack); - let fc = dc.build(); + let fc = dc.build(); //todo process the error tracing::debug!("Docker compose file content {:?}", fc); Ok(JsonResponse::build() @@ -46,49 +46,24 @@ pub async fn admin( ) -> Result { /// Admin function for generating compose file for specified user let id = path.0; - tracing::debug!("Received id: {}", id); + let stack = db::stack::fetch(pool.get_ref(), id) + .await + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .and_then(|stack| match stack { + Some(stack) => Ok(stack), + None => Err(JsonResponse::::build().not_found("not found")), + })?; - let stack = match sqlx::query_as!( - models::Stack, - r#" - SELECT * FROM user_stack WHERE id=$1 LIMIT 1 - "#, - id, - ) - .fetch_one(pool.get_ref()) - .await - { - Ok(stack) => { - tracing::info!("Record found: {:?}", stack.id); - Some(stack) - } - Err(sqlx::Error::RowNotFound) => { - tracing::error!("Record not found"); - None - } - Err(e) => { - tracing::error!("Failed to fetch stack, error: {:?}", e); - None + let id = stack.id.clone(); + let dc = DcBuilder::new(stack); + let fc = match dc.build() { + //todo process the error + Some(fc) => fc, + None => { + tracing::error!("Error. Compose builder returned an empty string"); + "".to_string() } }; - match stack { - Some(stack) => { - let id = stack.id.clone(); - let dc = DcBuilder::new(stack); - let fc = match dc.build() { - Some(fc) => fc, - None => { - tracing::error!("Error. Compose builder returned an empty string"); - "".to_string() - } - }; - // tracing::debug!("Docker compose file content {:?}", fc); - return Ok(JsonResponse::build().set_id(id).set_item(fc).ok("Success")); - } - None => { - return Err(JsonResponse::::build() - .bad_request("Could not generate compose file")); - } - } + Ok(JsonResponse::build().set_id(id).set_item(fc).ok("Success")) } From 6d6bc2e8b051004d94403904bea35ecbb932cbce Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 23 Dec 2023 18:39:51 +0200 Subject: [PATCH 096/284] issue-auth compose logic. optimized --- src/routes/stack/compose.rs | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/routes/stack/compose.rs b/src/routes/stack/compose.rs index d4e3eb4..b92b004 100644 --- a/src/routes/stack/compose.rs +++ b/src/routes/stack/compose.rs @@ -28,13 +28,12 @@ pub async fn add( let id = stack.id.clone(); let dc = DcBuilder::new(stack); - let fc = dc.build(); //todo process the error - tracing::debug!("Docker compose file content {:?}", fc); + let fc = dc.build().ok_or_else(|| { + tracing::error!("Error. Compose builder returned an empty string"); + JsonResponse::::build().internal_server_error("troubles at building") + })?; - Ok(JsonResponse::build() - .set_id(id) - .set_item(fc.unwrap()) - .ok("Success")) + Ok(JsonResponse::build().set_id(id).set_item(fc).ok("Success")) } #[tracing::instrument(name = "Generate docker-compose. Admin")] @@ -56,14 +55,10 @@ pub async fn admin( let id = stack.id.clone(); let dc = DcBuilder::new(stack); - let fc = match dc.build() { - //todo process the error - Some(fc) => fc, - None => { - tracing::error!("Error. Compose builder returned an empty string"); - "".to_string() - } - }; + let fc = dc.build().ok_or_else(|| { + tracing::error!("Error. Compose builder returned an empty string"); + JsonResponse::::build().internal_server_error("troubles at building") + })?; Ok(JsonResponse::build().set_id(id).set_item(fc).ok("Success")) } From a77681cc7c152627d4fdd54a053563429fbc5bda Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 23 Dec 2023 18:45:00 +0200 Subject: [PATCH 097/284] issue-auth compose logic --- src/routes/stack/compose.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/routes/stack/compose.rs b/src/routes/stack/compose.rs index b92b004..2829090 100644 --- a/src/routes/stack/compose.rs +++ b/src/routes/stack/compose.rs @@ -1,9 +1,8 @@ -use actix_web::{get, web, web::Data, Responder, Result}; - use crate::db; use crate::helpers::stack::builder::DcBuilder; use crate::helpers::JsonResponse; use crate::models; +use actix_web::{get, web, web::Data, Responder, Result}; use sqlx::PgPool; use std::sync::Arc; @@ -27,8 +26,7 @@ pub async fn add( })?; let id = stack.id.clone(); - let dc = DcBuilder::new(stack); - let fc = dc.build().ok_or_else(|| { + let fc = DcBuilder::new(stack).build().ok_or_else(|| { tracing::error!("Error. Compose builder returned an empty string"); JsonResponse::::build().internal_server_error("troubles at building") })?; @@ -54,8 +52,7 @@ pub async fn admin( })?; let id = stack.id.clone(); - let dc = DcBuilder::new(stack); - let fc = dc.build().ok_or_else(|| { + let fc = DcBuilder::new(stack).build().ok_or_else(|| { tracing::error!("Error. Compose builder returned an empty string"); JsonResponse::::build().internal_server_error("troubles at building") })?; From d584a685eb7fa79fcd8b2fb81c792a889f71392e Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 23 Dec 2023 18:52:42 +0200 Subject: [PATCH 098/284] issue-auth optimisation --- src/routes/stack/get.rs | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/routes/stack/get.rs b/src/routes/stack/get.rs index 18a044c..ac21f34 100644 --- a/src/routes/stack/get.rs +++ b/src/routes/stack/get.rs @@ -1,31 +1,32 @@ +use crate::db; use crate::helpers::JsonResponse; use crate::models; -use crate::db; use actix_web::{get, web, Responder, Result}; use sqlx::PgPool; use std::convert::From; -use tracing::Instrument; use std::sync::Arc; +use tracing::Instrument; #[tracing::instrument(name = "Get logged user stack.")] #[get("/{id}")] pub async fn item( user: web::ReqData>, path: web::Path<(i32,)>, - pool: web::Data, + pool: web::Data, ) -> Result { /// Get stack apps of logged user only let (id,) = path.into_inner(); - let stack = db::stack::fetch(pool.get_ref(), id) + let stack = db::stack::fetch(pool.get_ref(), id) .await - .map_err(|err| JsonResponse::::build().internal_server_error(err))? - .ok_or_else(|| JsonResponse::::build().not_found("not found"))? - ; - - if stack.user_id != user.id { - return Err(JsonResponse::::build().bad_request("Forbidden")); - } + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .and_then(|stack| match stack { + Some(stack) if stack.user_id != user.id => { + Err(JsonResponse::::build().not_found("not found")) + } + Some(stack) => Ok(stack), + None => Err(JsonResponse::::build().not_found("not found")), + })?; Ok(JsonResponse::build().set_item(Some(stack)).ok("OK")) } @@ -42,8 +43,8 @@ pub async fn list( /// in order to pass validation at external deployment service let user_id = path.into_inner().0; - db::stack::fetch_by_user(pool.get_ref(), &user_id) + db::stack::fetch_by_user(pool.get_ref(), &user_id) .await - .map_err(|err| JsonResponse::::build().internal_server_error("")) + .map_err(|err| JsonResponse::::build().internal_server_error(err)) .map(|stacks| JsonResponse::build().set_list(stacks).ok("OK")) } From 874162b8272890cbc378379cfd06fcefd6ff045a Mon Sep 17 00:00:00 2001 From: Petru Date: Tue, 26 Dec 2023 18:21:47 +0200 Subject: [PATCH 099/284] issue-auth stack/deploy --- src/routes/stack/deploy.rs | 117 +++++++++++++++---------------------- 1 file changed, 47 insertions(+), 70 deletions(-) diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs index 1d52caa..3b0bc01 100644 --- a/src/routes/stack/deploy.rs +++ b/src/routes/stack/deploy.rs @@ -1,9 +1,9 @@ use crate::configuration::Settings; +use crate::db; use crate::forms::StackPayload; use crate::helpers::stack::builder::DcBuilder; use crate::helpers::JsonResponse; -use crate::models::stack::Stack; -use crate::models::user::User; +use crate::models; use actix_web::{post, web, web::Data, Responder, Result}; use futures_lite::stream::StreamExt; use lapin::{ @@ -12,89 +12,66 @@ use lapin::{ use sqlx::PgPool; use std::sync::Arc; - #[tracing::instrument(name = "Deploy for every user. Admin endpoint")] #[post("/{id}/deploy")] pub async fn add( - user: web::ReqData>, + user: web::ReqData>, path: web::Path<(i32,)>, pool: Data, sets: Data, ) -> Result { let id = path.0; - tracing::debug!("Received id: {}", id); - - let stack = match sqlx::query_as!( - Stack, - r#" - SELECT * FROM user_stack WHERE id=$1 LIMIT 1 - "#, - id - ) - .fetch_one(pool.get_ref()) - .await - { - Ok(stack) => { - tracing::info!("Stack found: {:?}", stack.id,); - Some(stack) - } - Err(sqlx::Error::RowNotFound) => { - tracing::error!("Row not found 404"); - None - } - Err(e) => { - tracing::error!("Failed to fetch stack, error: {:?}", e); - None - } - }; + let stack = db::stack::fetch(pool.get_ref(), id) + .await + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .and_then(|stack| match stack { + Some(stack) => Ok(stack), + None => Err(JsonResponse::::build().not_found("not found")), + })?; - return match stack { - Some(stack) => { - let id = stack.id.clone(); - let dc = DcBuilder::new(stack); - dc.build(); + let id = stack.id.clone(); + let dc = DcBuilder::new(stack); + dc.build().ok_or_else(|| { + tracing::error!("Error. Compose builder returned an empty string"); + JsonResponse::::build().internal_server_error("troubles at building") + })?; - let addr = sets.amqp.connection_string(); - let routing_key = "install.start.tfa.all.all".to_string(); - tracing::debug!("Sending message to {:?}", routing_key); + let addr = sets.amqp.connection_string(); + let routing_key = "install.start.tfa.all.all".to_string(); + tracing::debug!("Sending message to {:?}", routing_key); - let conn = Connection::connect(&addr, ConnectionProperties::default()) - .await - .expect("Could not connect RabbitMQ"); + let conn = Connection::connect(&addr, ConnectionProperties::default()) + .await + .expect("Could not connect RabbitMQ"); - tracing::info!("RABBITMQ CONNECTED"); + tracing::info!("RABBITMQ CONNECTED"); - let channel = conn.create_channel().await.unwrap(); - let mut stack_data = - serde_json::from_value::(dc.stack.body.clone()).unwrap(); + let channel = conn.create_channel().await.unwrap(); + let mut stack_data = serde_json::from_value::(dc.stack.body.clone()).unwrap(); - stack_data.id = Some(id); - stack_data.user_token = Some(user.id.clone()); - stack_data.user_email = Some(user.email.clone()); - stack_data.stack_code = stack_data.custom.custom_stack_code.clone(); + stack_data.id = Some(id); + stack_data.user_token = Some(user.id.clone()); + stack_data.user_email = Some(user.email.clone()); + stack_data.stack_code = stack_data.custom.custom_stack_code.clone(); - let payload = serde_json::to_string::(&stack_data).unwrap(); - let _payload = payload.as_bytes(); + let payload = serde_json::to_string::(&stack_data).unwrap(); + let _payload = payload.as_bytes(); - let confirm = channel - .basic_publish( - "install", - routing_key.as_str(), - BasicPublishOptions::default(), - _payload, - BasicProperties::default(), - ) - .await - .unwrap() - .await - .unwrap(); + let confirm = channel + .basic_publish( + "install", + routing_key.as_str(), + BasicPublishOptions::default(), + _payload, + BasicProperties::default(), + ) + .await + .unwrap() + .await + .unwrap(); - assert_eq!(confirm, Confirmation::NotRequested); - tracing::debug!("Message sent to rabbitmq"); - return Ok(JsonResponse::::build().set_id(id).ok("Success")); - } - None => { - Err(JsonResponse::::build().internal_server_error("Deployment failed")) - } - } + assert_eq!(confirm, Confirmation::NotRequested); + return Ok(JsonResponse::::build() + .set_id(id) + .ok("Success")); } From 7ae0f1f13656cd9f5286f827d3cdef371f707754 Mon Sep 17 00:00:00 2001 From: Petru Date: Tue, 26 Dec 2023 18:36:32 +0200 Subject: [PATCH 100/284] issue-auth stack/deploy --- src/routes/stack/deploy.rs | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs index 3b0bc01..928d6ef 100644 --- a/src/routes/stack/deploy.rs +++ b/src/routes/stack/deploy.rs @@ -42,13 +42,24 @@ pub async fn add( let conn = Connection::connect(&addr, ConnectionProperties::default()) .await - .expect("Could not connect RabbitMQ"); - - tracing::info!("RABBITMQ CONNECTED"); + .map_err(|err| { + JsonResponse::::build() + .internal_server_error("Could not connect RabbitMQ") + })?; - let channel = conn.create_channel().await.unwrap(); - let mut stack_data = serde_json::from_value::(dc.stack.body.clone()).unwrap(); + let channel = conn.create_channel().await.map_err(|err| { + JsonResponse::::build() + .internal_server_error("Can't create rabbitMQ channel") + })?; + let mut stack_data = serde_json::from_value::(dc.stack.body.clone()) + .map_err(|err| JsonResponse::::build().bad_request("can't deserialize"))?; //todo + //add + //json + //error + //path + Ok(JsonResponse::::build().ok("bdc")) + /* stack_data.id = Some(id); stack_data.user_token = Some(user.id.clone()); stack_data.user_email = Some(user.email.clone()); @@ -66,12 +77,16 @@ pub async fn add( BasicProperties::default(), ) .await - .unwrap() + .unwrap() //todo .await - .unwrap(); - - assert_eq!(confirm, Confirmation::NotRequested); - return Ok(JsonResponse::::build() + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .and_then(|confirm| { + match confirm { + Confirmation::NotRequested => Err(JsonResponse::::build().bad_request("confirmation is NotRequested")), + _ => Ok(JsonResponse::::build() .set_id(id) - .ok("Success")); + .ok("Success")) + } + }) + */ } From 36a88207c8ed97afc9ba2fb1e5d46a61129a4e5e Mon Sep 17 00:00:00 2001 From: Petru Date: Wed, 27 Dec 2023 17:29:47 +0200 Subject: [PATCH 101/284] issue-auth src/routes/stack/deploy.rs --- src/routes/stack/deploy.rs | 39 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs index 928d6ef..03c5264 100644 --- a/src/routes/stack/deploy.rs +++ b/src/routes/stack/deploy.rs @@ -52,41 +52,40 @@ pub async fn add( .internal_server_error("Can't create rabbitMQ channel") })?; let mut stack_data = serde_json::from_value::(dc.stack.body.clone()) - .map_err(|err| JsonResponse::::build().bad_request("can't deserialize"))?; //todo - //add - //json - //error - //path + .map_err(|err| JsonResponse::::build().bad_request("can't deserialize"))?; - Ok(JsonResponse::::build().ok("bdc")) - /* stack_data.id = Some(id); stack_data.user_token = Some(user.id.clone()); stack_data.user_email = Some(user.email.clone()); stack_data.stack_code = stack_data.custom.custom_stack_code.clone(); - let payload = serde_json::to_string::(&stack_data).unwrap(); - let _payload = payload.as_bytes(); + let payload = serde_json::to_string::(&stack_data).map_err(|err| { + JsonResponse::::build().internal_server_error(format!("{}", err)) + })?; - let confirm = channel + channel .basic_publish( "install", routing_key.as_str(), BasicPublishOptions::default(), - _payload, + payload.as_bytes(), BasicProperties::default(), ) .await - .unwrap() //todo + .map_err(|_| { + JsonResponse::::build().internal_server_error("internal server error") + })? //todo the correct err .await - .map_err(|err| JsonResponse::::build().internal_server_error(err)) - .and_then(|confirm| { - match confirm { - Confirmation::NotRequested => Err(JsonResponse::::build().bad_request("confirmation is NotRequested")), - _ => Ok(JsonResponse::::build() - .set_id(id) - .ok("Success")) + .map_err(|_| { + JsonResponse::::build().internal_server_error("internal server error") + }) + .and_then(|confirm| match confirm { + Confirmation::NotRequested => { + Err(JsonResponse::::build() + .bad_request("confirmation is NotRequested")) } + _ => Ok(JsonResponse::::build() + .set_id(id) + .ok("Success")), }) - */ } From d38f220031e279000f61c8543d09b0a3e6dc1909 Mon Sep 17 00:00:00 2001 From: Petru Date: Wed, 27 Dec 2023 17:41:24 +0200 Subject: [PATCH 102/284] issue-auth src/routes/stack/deploy.rs --- src/routes/stack/deploy.rs | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs index 03c5264..36fbc28 100644 --- a/src/routes/stack/deploy.rs +++ b/src/routes/stack/deploy.rs @@ -33,7 +33,7 @@ pub async fn add( let dc = DcBuilder::new(stack); dc.build().ok_or_else(|| { tracing::error!("Error. Compose builder returned an empty string"); - JsonResponse::::build().internal_server_error("troubles at building") + JsonResponse::::build().internal_server_error("") })?; let addr = sets.amqp.connection_string(); @@ -43,16 +43,19 @@ pub async fn add( let conn = Connection::connect(&addr, ConnectionProperties::default()) .await .map_err(|err| { - JsonResponse::::build() - .internal_server_error("Could not connect RabbitMQ") + tracing::error!("connecting to RabbitMQ {:?}", err); + JsonResponse::::build().internal_server_error("") })?; let channel = conn.create_channel().await.map_err(|err| { - JsonResponse::::build() - .internal_server_error("Can't create rabbitMQ channel") + tracing::error!("creating RabbitMQ channel {:?}", err); + JsonResponse::::build().internal_server_error("") })?; - let mut stack_data = serde_json::from_value::(dc.stack.body.clone()) - .map_err(|err| JsonResponse::::build().bad_request("can't deserialize"))?; + let mut stack_data = + serde_json::from_value::(dc.stack.body.clone()).map_err(|err| { + tracing::error!("transforming json Value into StackPayload {:?}", err); + JsonResponse::::build().bad_request("") + })?; stack_data.id = Some(id); stack_data.user_token = Some(user.id.clone()); @@ -60,7 +63,8 @@ pub async fn add( stack_data.stack_code = stack_data.custom.custom_stack_code.clone(); let payload = serde_json::to_string::(&stack_data).map_err(|err| { - JsonResponse::::build().internal_server_error(format!("{}", err)) + tracing::error!("serializing StackPayload {:?}", err); + JsonResponse::::build().internal_server_error("") })?; channel @@ -72,12 +76,14 @@ pub async fn add( BasicProperties::default(), ) .await - .map_err(|_| { - JsonResponse::::build().internal_server_error("internal server error") - })? //todo the correct err + .map_err(|err| { + tracing::error!("publishing the message {:?}", err); + JsonResponse::::build().internal_server_error("") + })? .await - .map_err(|_| { - JsonResponse::::build().internal_server_error("internal server error") + .map_err(|err| { + tracing::error!("confirming the publication {:?}", err); + JsonResponse::::build().internal_server_error("") }) .and_then(|confirm| match confirm { Confirmation::NotRequested => { From 1852cb623a5d7222a4f269e31cec7544cdfb65cd Mon Sep 17 00:00:00 2001 From: Petru Date: Wed, 27 Dec 2023 17:47:36 +0200 Subject: [PATCH 103/284] issue-auth channel --- src/routes/stack/deploy.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs index 36fbc28..9432f55 100644 --- a/src/routes/stack/deploy.rs +++ b/src/routes/stack/deploy.rs @@ -47,10 +47,6 @@ pub async fn add( JsonResponse::::build().internal_server_error("") })?; - let channel = conn.create_channel().await.map_err(|err| { - tracing::error!("creating RabbitMQ channel {:?}", err); - JsonResponse::::build().internal_server_error("") - })?; let mut stack_data = serde_json::from_value::(dc.stack.body.clone()).map_err(|err| { tracing::error!("transforming json Value into StackPayload {:?}", err); @@ -67,7 +63,12 @@ pub async fn add( JsonResponse::::build().internal_server_error("") })?; - channel + conn.create_channel() + .await + .map_err(|err| { + tracing::error!("creating RabbitMQ channel {:?}", err); + JsonResponse::::build().internal_server_error("") + })? .basic_publish( "install", routing_key.as_str(), From 3383358c5afcf024f7e1217adf1113ef7864a9fe Mon Sep 17 00:00:00 2001 From: Petru Date: Wed, 27 Dec 2023 17:51:17 +0200 Subject: [PATCH 104/284] issue-auth RabbitMQ logic --- src/routes/stack/deploy.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs index 9432f55..c92aa70 100644 --- a/src/routes/stack/deploy.rs +++ b/src/routes/stack/deploy.rs @@ -36,17 +36,6 @@ pub async fn add( JsonResponse::::build().internal_server_error("") })?; - let addr = sets.amqp.connection_string(); - let routing_key = "install.start.tfa.all.all".to_string(); - tracing::debug!("Sending message to {:?}", routing_key); - - let conn = Connection::connect(&addr, ConnectionProperties::default()) - .await - .map_err(|err| { - tracing::error!("connecting to RabbitMQ {:?}", err); - JsonResponse::::build().internal_server_error("") - })?; - let mut stack_data = serde_json::from_value::(dc.stack.body.clone()).map_err(|err| { tracing::error!("transforming json Value into StackPayload {:?}", err); @@ -63,7 +52,17 @@ pub async fn add( JsonResponse::::build().internal_server_error("") })?; - conn.create_channel() + let addr = sets.amqp.connection_string(); + let routing_key = "install.start.tfa.all.all".to_string(); + tracing::debug!("Sending message to {:?}", routing_key); + + Connection::connect(&addr, ConnectionProperties::default()) + .await + .map_err(|err| { + tracing::error!("connecting to RabbitMQ {:?}", err); + JsonResponse::::build().internal_server_error("") + })? + .create_channel() .await .map_err(|err| { tracing::error!("creating RabbitMQ channel {:?}", err); From 055988c936b9c76d127751461f0f4fdb2a2c0dbf Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 30 Dec 2023 09:33:15 +0200 Subject: [PATCH 105/284] issue-auth pg_pool --- src/routes/client/add.rs | 22 +++++++++++----------- src/routes/client/disable.rs | 32 ++++++++++++++++---------------- src/routes/client/enable.rs | 15 +++++++-------- src/routes/client/update.rs | 20 ++++++++++++-------- src/routes/rating/get.rs | 13 ++++++++----- src/routes/stack/add.rs | 10 +++++----- src/routes/stack/compose.rs | 8 ++++---- src/routes/stack/deploy.rs | 4 ++-- src/routes/stack/get.rs | 8 ++++---- src/routes/stack/update.rs | 34 +++++++++++++--------------------- 10 files changed, 82 insertions(+), 84 deletions(-) diff --git a/src/routes/client/add.rs b/src/routes/client/add.rs index b3d90d9..0b526d1 100644 --- a/src/routes/client/add.rs +++ b/src/routes/client/add.rs @@ -1,21 +1,21 @@ use crate::configuration::Settings; +use crate::db; use crate::helpers::client; use crate::helpers::JsonResponse; use crate::models; -use crate::db; use actix_web::{post, web, Responder, Result}; use sqlx::PgPool; -use tracing::Instrument; use std::sync::Arc; +use tracing::Instrument; #[tracing::instrument(name = "Add client.")] #[post("")] pub async fn add_handler( user: web::ReqData>, settings: web::Data, - pool: web::Data, + pg_pool: web::Data, ) -> Result { - add_handler_inner(&user.id, settings, pool) + add_handler_inner(&user.id, settings, pg_pool) .await .map(|client| JsonResponse::build().set_item(client).ok("Ok")) .map_err(|err| JsonResponse::::build().bad_request(err)) @@ -24,21 +24,21 @@ pub async fn add_handler( pub async fn add_handler_inner( user_id: &String, settings: web::Data, - pool: web::Data, + pg_pool: web::Data, ) -> Result { - let client_count = db::client::count_by_user(pool.get_ref(), user_id).await?; + let client_count = db::client::count_by_user(pg_pool.get_ref(), user_id).await?; if client_count >= settings.max_clients_number { return Err("Too many clients created".to_string()); } - let client = create_client(pool.get_ref(), user_id).await?; - db::client::insert(pool.get_ref(), client).await + let client = create_client(pg_pool.get_ref(), user_id).await?; + db::client::insert(pg_pool.get_ref(), client).await } -async fn create_client(pool: &PgPool, user_id: &String) -> Result { - let mut client = models::Client::default(); +async fn create_client(pg_pool: &PgPool, user_id: &String) -> Result { + let mut client = models::Client::default(); client.user_id = user_id.clone(); - client.secret = client::generate_secret(pool, 255) + client.secret = client::generate_secret(pg_pool, 255) .await .map(|s| Some(s))?; diff --git a/src/routes/client/disable.rs b/src/routes/client/disable.rs index 057a183..70d2a1c 100644 --- a/src/routes/client/disable.rs +++ b/src/routes/client/disable.rs @@ -1,33 +1,33 @@ use crate::configuration::Settings; +use crate::db; use crate::helpers::JsonResponse; use crate::models; -use crate::db; use actix_web::{put, web, Responder, Result}; use sqlx::PgPool; -use tracing::Instrument; use std::sync::Arc; +use tracing::Instrument; #[tracing::instrument(name = "Disable client.")] #[put("/{id}/disable")] pub async fn disable_handler( user: web::ReqData>, settings: web::Data, - pool: web::Data, + pg_pool: web::Data, path: web::Path<(i32,)>, ) -> Result { - let client_id = path.0; - let mut client = db::client::fetch(pool.get_ref(), client_id) - .await - .map_err(|msg| JsonResponse::::build().internal_server_error(msg))? - .ok_or_else(|| JsonResponse::::build().not_found("not found"))?; + let client_id = path.0; + let mut client = db::client::fetch(pg_pool.get_ref(), client_id) + .await + .map_err(|msg| JsonResponse::::build().internal_server_error(msg))? + .ok_or_else(|| JsonResponse::::build().not_found("not found"))?; - if client.secret.is_none() { - return Err(JsonResponse::::build().bad_request("client is not active")); - } + if client.secret.is_none() { + return Err(JsonResponse::::build().bad_request("client is not active")); + } - client.secret = None; - db::client::update(pool.get_ref(), client) - .await - .map(|client| JsonResponse::build().set_item(client).ok("success")) - .map_err(|msg| JsonResponse::::build().bad_request(msg)) + client.secret = None; + db::client::update(pg_pool.get_ref(), client) + .await + .map(|client| JsonResponse::build().set_item(client).ok("success")) + .map_err(|msg| JsonResponse::::build().bad_request(msg)) } diff --git a/src/routes/client/enable.rs b/src/routes/client/enable.rs index 5669acc..c87fc44 100644 --- a/src/routes/client/enable.rs +++ b/src/routes/client/enable.rs @@ -1,38 +1,37 @@ use crate::configuration::Settings; +use crate::db; use crate::helpers::client; use crate::helpers::JsonResponse; use crate::models; -use crate::db; use actix_web::{put, web, Responder, Result}; -use tracing::Instrument; use sqlx::PgPool; use std::sync::Arc; +use tracing::Instrument; #[tracing::instrument(name = "Enable client.")] #[put("/{id}/enable")] pub async fn enable_handler( user: web::ReqData>, settings: web::Data, - pool: web::Data, + pg_pool: web::Data, path: web::Path<(i32,)>, ) -> Result { let client_id = path.0; - let mut client = db::client::fetch(pool.get_ref(), client_id) + let mut client = db::client::fetch(pg_pool.get_ref(), client_id) .await .map_err(|msg| JsonResponse::::build().internal_server_error(msg))? - .ok_or_else(|| JsonResponse::::build().not_found("not found"))? - ; + .ok_or_else(|| JsonResponse::::build().not_found("not found"))?; if client.secret.is_some() { return Err(JsonResponse::::build().bad_request("client is already active")); } - client.secret = client::generate_secret(pool.get_ref(), 255) + client.secret = client::generate_secret(pg_pool.get_ref(), 255) .await .map(|secret| Some(secret)) .map_err(|err| JsonResponse::::build().bad_request(err))?; - db::client::update(pool.get_ref(), client) + db::client::update(pg_pool.get_ref(), client) .await .map(|client| JsonResponse::build().set_item(client).ok("success")) .map_err(|err| JsonResponse::::build().bad_request(err)) diff --git a/src/routes/client/update.rs b/src/routes/client/update.rs index b100316..a52af9b 100644 --- a/src/routes/client/update.rs +++ b/src/routes/client/update.rs @@ -1,39 +1,43 @@ +use crate::db; use crate::helpers::client; use crate::models; -use crate::db; use crate::{configuration::Settings, helpers::JsonResponse}; use actix_web::{put, web, Responder, Result}; +use futures::TryFutureExt; use sqlx::PgPool; use std::sync::Arc; use tracing::Instrument; -use futures::TryFutureExt; #[tracing::instrument(name = "Update client.")] #[put("/{id}")] pub async fn update_handler( user: web::ReqData>, settings: web::Data, - pool: web::Data, + pg_pool: web::Data, path: web::Path<(i32,)>, ) -> Result { let client_id = path.0; - let mut client = db::client::fetch(pool.get_ref(), client_id) + let mut client = db::client::fetch(pg_pool.get_ref(), client_id) .await .map_err(|msg| JsonResponse::::build().internal_server_error(msg))? - .ok_or_else(|| JsonResponse::::build().not_found("not found"))?; + .ok_or_else(|| JsonResponse::::build().not_found("not found"))?; if client.secret.is_none() { return Err(JsonResponse::::build().bad_request("client is not active")); } - client.secret = client::generate_secret(pool.get_ref(), 255) + client.secret = client::generate_secret(pg_pool.get_ref(), 255) .await .map(|s| Some(s)) .map_err(|msg| JsonResponse::::build().bad_request(msg))?; - db::client::update(pool.get_ref(), client) + db::client::update(pg_pool.get_ref(), client) .await - .map(|client| JsonResponse::::build().set_item(client).ok("success")) + .map(|client| { + JsonResponse::::build() + .set_item(client) + .ok("success") + }) .map_err(|err| { tracing::error!("Failed to execute query: {:?}", err); JsonResponse::::build().internal_server_error("") diff --git a/src/routes/rating/get.rs b/src/routes/rating/get.rs index 4bc0c1f..9081960 100644 --- a/src/routes/rating/get.rs +++ b/src/routes/rating/get.rs @@ -1,6 +1,6 @@ +use crate::db; use crate::helpers::JsonResponse; use crate::models; -use crate::db; use actix_web::{get, web, Responder, Result}; use sqlx::PgPool; use tracing::Instrument; @@ -14,10 +14,10 @@ use tracing::Instrument; #[get("/{id}")] pub async fn get_handler( path: web::Path<(i32,)>, - pool: web::Data, + pg_pool: web::Data, ) -> Result { let rate_id = path.0; - let rating = db::rating::fetch(pool.get_ref(), rate_id) + let rating = db::rating::fetch(pg_pool.get_ref(), rate_id) .await .map_err(|_err| JsonResponse::::build().internal_server_error(""))? .ok_or_else(|| JsonResponse::::build().not_found("not found"))?; @@ -27,8 +27,11 @@ pub async fn get_handler( #[tracing::instrument(name = "Get all ratings.")] #[get("")] -pub async fn list_handler(path: web::Path<()>, pool: web::Data) -> Result { - db::rating::fetch_all(pool.get_ref()) +pub async fn list_handler( + path: web::Path<()>, + pg_pool: web::Data, +) -> Result { + db::rating::fetch_all(pg_pool.get_ref()) .await .map(|ratings| JsonResponse::build().set_list(ratings).ok("OK")) .map_err(|err| JsonResponse::::build().internal_server_error("")) diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index ef38ac5..7ed5a09 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -19,20 +19,20 @@ use std::sync::Arc; pub async fn add( body: Bytes, user: web::ReqData>, - pool: Data, + pg_pool: Data, ) -> Result { // @todo ACL let form = body_into_form(body).await?; let stack_name = form.custom.custom_stack_code.clone(); - check_if_stack_exists(pool.get_ref(), &stack_name).await?; + check_if_stack_exists(pg_pool.get_ref(), &stack_name).await?; let body: Value = serde_json::to_value::(form) .or(serde_json::to_value::(StackForm::default())) .unwrap(); let stack = models::Stack::new(user.id.clone(), stack_name, body); - db::stack::insert(pool.get_ref(), stack) + db::stack::insert(pg_pool.get_ref(), stack) .await .map(|stack| JsonResponse::build().set_item(stack).ok("Ok")) .map_err(|_| { @@ -40,8 +40,8 @@ pub async fn add( }) } -async fn check_if_stack_exists(pool: &PgPool, stack_name: &String) -> Result<(), Error> { - db::stack::fetch_one_by_name(pool, stack_name) +async fn check_if_stack_exists(pg_pool: &PgPool, stack_name: &String) -> Result<(), Error> { + db::stack::fetch_one_by_name(pg_pool, stack_name) .await .map_err(|_| { JsonResponse::::build().internal_server_error("Internal Server Error") diff --git a/src/routes/stack/compose.rs b/src/routes/stack/compose.rs index 2829090..4e58141 100644 --- a/src/routes/stack/compose.rs +++ b/src/routes/stack/compose.rs @@ -11,10 +11,10 @@ use std::sync::Arc; pub async fn add( user: web::ReqData>, path: web::Path<(i32,)>, - pool: Data, + pg_pool: Data, ) -> Result { let id = path.0; - let stack = db::stack::fetch(pool.get_ref(), id) + let stack = db::stack::fetch(pg_pool.get_ref(), id) .await .map_err(|err| JsonResponse::::build().internal_server_error(err)) .and_then(|stack| match stack { @@ -39,11 +39,11 @@ pub async fn add( pub async fn admin( user: web::ReqData>, path: web::Path<(i32,)>, - pool: Data, + pg_pool: Data, ) -> Result { /// Admin function for generating compose file for specified user let id = path.0; - let stack = db::stack::fetch(pool.get_ref(), id) + let stack = db::stack::fetch(pg_pool.get_ref(), id) .await .map_err(|err| JsonResponse::::build().internal_server_error(err)) .and_then(|stack| match stack { diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs index c92aa70..f18c99d 100644 --- a/src/routes/stack/deploy.rs +++ b/src/routes/stack/deploy.rs @@ -17,11 +17,11 @@ use std::sync::Arc; pub async fn add( user: web::ReqData>, path: web::Path<(i32,)>, - pool: Data, + pg_pool: Data, sets: Data, ) -> Result { let id = path.0; - let stack = db::stack::fetch(pool.get_ref(), id) + let stack = db::stack::fetch(pg_pool.get_ref(), id) .await .map_err(|err| JsonResponse::::build().internal_server_error(err)) .and_then(|stack| match stack { diff --git a/src/routes/stack/get.rs b/src/routes/stack/get.rs index ac21f34..1e9492a 100644 --- a/src/routes/stack/get.rs +++ b/src/routes/stack/get.rs @@ -12,12 +12,12 @@ use tracing::Instrument; pub async fn item( user: web::ReqData>, path: web::Path<(i32,)>, - pool: web::Data, + pg_pool: web::Data, ) -> Result { /// Get stack apps of logged user only let (id,) = path.into_inner(); - let stack = db::stack::fetch(pool.get_ref(), id) + let stack = db::stack::fetch(pg_pool.get_ref(), id) .await .map_err(|err| JsonResponse::::build().internal_server_error(err)) .and_then(|stack| match stack { @@ -36,14 +36,14 @@ pub async fn item( pub async fn list( user: web::ReqData>, path: web::Path<(String,)>, - pool: web::Data, + pg_pool: web::Data, ) -> Result { /// This is admin endpoint, used by a m2m app, client app is confidential /// it should return stacks by user id /// in order to pass validation at external deployment service let user_id = path.into_inner().0; - db::stack::fetch_by_user(pool.get_ref(), &user_id) + db::stack::fetch_by_user(pg_pool.get_ref(), &user_id) .await .map_err(|err| JsonResponse::::build().internal_server_error(err)) .map(|stacks| JsonResponse::build().set_list(stacks).ok("OK")) diff --git a/src/routes/stack/update.rs b/src/routes/stack/update.rs index a418b53..229553f 100644 --- a/src/routes/stack/update.rs +++ b/src/routes/stack/update.rs @@ -1,21 +1,16 @@ -use chrono::Utc; -use actix_web::{ - web, - web::{Data}, - Responder, Result, -}; use crate::forms::stack::StackForm; use crate::helpers::JsonResponse; +use crate::models; use crate::models::user::User; use actix_web::post; +use actix_web::{web, web::Data, Responder, Result}; +use chrono::Utc; use serde_json::Value; -use sqlx::PgPool; use serde_valid::Validate; +use sqlx::PgPool; +use std::sync::Arc; use tracing::Instrument; use uuid::Uuid; -use crate::models; -use std::sync::Arc; - #[tracing::instrument(name = "Update stack.")] #[post("/{id}")] @@ -23,18 +18,14 @@ pub async fn update( path: web::Path<(i32,)>, form: web::Json, user: web::ReqData>, - pool: Data, + pg_pool: Data, ) -> Result { // @todo ACL let (id,) = path.into_inner(); let query_span = tracing::info_span!("Check existence by id."); - match sqlx::query_as!( - models::Stack, - r"SELECT * FROM user_stack WHERE id = $1", - id - ) - .fetch_one(pool.get_ref()) + match sqlx::query_as!(models::Stack, r"SELECT * FROM user_stack WHERE id = $1", id) + .fetch_one(pg_pool.get_ref()) .instrument(query_span) .await { @@ -60,7 +51,8 @@ pub async fn update( ); let _request_span_guard = request_span.enter(); // ->exit - tracing::info!("request_id {} Updating '{}' '{}'", + tracing::info!( + "request_id {} Updating '{}' '{}'", request_id, form.custom.project_name, form.region @@ -97,9 +89,9 @@ pub async fn update( Utc::now(), Utc::now(), ) - .execute(pool.get_ref()) - .instrument(query_span) - .await + .execute(pg_pool.get_ref()) + .instrument(query_span) + .await { Ok(record) => { tracing::info!( From ace2c26cfb382913459864d2f02f5a9133c86935 Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 30 Dec 2023 09:39:20 +0200 Subject: [PATCH 106/284] issue-auth db_pool renamed to pg_pool --- src/startup.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/startup.rs b/src/startup.rs index 8b966ee..b592a4f 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -12,17 +12,16 @@ use tracing_actix_web::TracingLogger; pub async fn run( listener: TcpListener, - db_pool: Pool, + pg_pool: Pool, settings: Settings, ) -> Result { let settings = web::Data::new(settings); - let db_pool = web::Data::new(db_pool); + let pg_pool = web::Data::new(pg_pool); let server = HttpServer::new(move || { App::new() .wrap(TracingLogger::default()) - .service(web::scope("/health_check") - .service(crate::routes::health_check)) + .service(web::scope("/health_check").service(crate::routes::health_check)) .service( web::scope("/client") .wrap(HttpAuthentication::bearer( @@ -64,7 +63,7 @@ pub async fn run( .service(crate::routes::stack::add::add) .service(crate::routes::stack::update::update), ) - .app_data(db_pool.clone()) + .app_data(pg_pool.clone()) .app_data(settings.clone()) }) .listen(listener)? From 1d4fc9688f5b0c715b752f660075fa68c056ecb3 Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 30 Dec 2023 10:21:13 +0200 Subject: [PATCH 107/284] issue-auth helpers::MqPool --- Cargo.lock | 40 +++++++++++++++++++++++++++++++++++++- Cargo.toml | 1 + src/helpers/mod.rs | 2 ++ src/helpers/mq_pool.rs | 27 +++++++++++++++++++++++++ src/main.rs | 4 ++-- src/routes/stack/deploy.rs | 3 ++- src/startup.rs | 5 +++++ 7 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 src/helpers/mq_pool.rs diff --git a/Cargo.lock b/Cargo.lock index 73e0b28..e7d155c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -975,11 +975,37 @@ dependencies = [ "tokio", ] +[[package]] +name = "deadpool" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb84100978c1c7b37f09ed3ce3e5f843af02c2a2c431bae5b19230dad2c1b490" +dependencies = [ + "async-trait", + "deadpool-runtime", + "num_cpus", + "tokio", +] + +[[package]] +name = "deadpool-lapin" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce11c0dc86703e59a8921bb9afee10b13c242e47624347bd3a3b545c41db556e" +dependencies = [ + "deadpool 0.10.0", + "lapin", + "tokio-executor-trait", +] + [[package]] name = "deadpool-runtime" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63dfa964fe2a66f3fde91fc70b267fe193d822c7e603e2a675a49a7f46ad3f49" +dependencies = [ + "tokio", +] [[package]] name = "deranged" @@ -3103,6 +3129,7 @@ dependencies = [ "chrono", "clap", "config", + "deadpool-lapin", "derive_builder", "futures", "futures-lite 1.13.0", @@ -3329,6 +3356,17 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "tokio-executor-trait" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "802ccf58e108fe16561f35348fabe15ff38218968f033d587e399a84937533cc" +dependencies = [ + "async-trait", + "executor-trait", + "tokio", +] + [[package]] name = "tokio-macros" version = "2.2.0" @@ -3940,7 +3978,7 @@ dependencies = [ "assert-json-diff", "async-trait", "base64 0.21.5", - "deadpool", + "deadpool 0.9.5", "futures", "futures-timer", "http-types", diff --git a/Cargo.toml b/Cargo.toml index 54ee40f..4555de3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,6 +53,7 @@ lapin = { version = "2.3.1", features = ["serde_json"] } futures-lite = "1.13.0" clap = { version = "4.4.8", features = ["derive"] } serde_path_to_error = "0.1.14" +deadpool-lapin = "0.11.0" [dependencies.sqlx] version = "0.6.3" diff --git a/src/helpers/mod.rs b/src/helpers/mod.rs index e5439f7..6d7d2a1 100644 --- a/src/helpers/mod.rs +++ b/src/helpers/mod.rs @@ -1,5 +1,7 @@ pub mod client; pub(crate) mod json; +mod mq_pool; pub(crate) mod stack; pub use json::*; +pub use mq_pool::MqPool; diff --git a/src/helpers/mq_pool.rs b/src/helpers/mq_pool.rs new file mode 100644 index 0000000..4e5bcbd --- /dev/null +++ b/src/helpers/mq_pool.rs @@ -0,0 +1,27 @@ +use deadpool_lapin::{Config, CreatePoolError, Pool, Runtime}; + +#[derive(Debug)] +pub struct MqPool { + pool: Pool, +} + +impl MqPool { + pub fn try_new(url: String) -> Result { + let mut cfg = Config::default(); + cfg.url = Some(url); + let pool = cfg.create_pool(Some(Runtime::Tokio1)).map_err(|err| { + tracing::error!("{:?}", err); + + match err { + CreatePoolError::Config(_) => { + std::io::Error::new(std::io::ErrorKind::Other, "config error") + } + CreatePoolError::Build(_) => { + std::io::Error::new(std::io::ErrorKind::Other, "build error") + } + } + })?; + + Ok(MqPool { pool }) + } +} diff --git a/src/main.rs b/src/main.rs index ebf4987..8132f58 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,7 @@ async fn main() -> std::io::Result<()> { let settings = get_configuration().expect("Failed to read configuration."); - let db_pool = PgPool::connect(&settings.database.connection_string()) + let pg_pool = PgPool::connect(&settings.database.connection_string()) .await .expect("Failed to connect to database."); @@ -20,5 +20,5 @@ async fn main() -> std::io::Result<()> { let listener = TcpListener::bind(address).expect(&format!("failed to bind to {}", settings.app_port)); - run(listener, db_pool, settings).await?.await + run(listener, pg_pool, settings).await?.await } diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs index f18c99d..2593c46 100644 --- a/src/routes/stack/deploy.rs +++ b/src/routes/stack/deploy.rs @@ -2,7 +2,7 @@ use crate::configuration::Settings; use crate::db; use crate::forms::StackPayload; use crate::helpers::stack::builder::DcBuilder; -use crate::helpers::JsonResponse; +use crate::helpers::{JsonResponse, MqPool}; use crate::models; use actix_web::{post, web, web::Data, Responder, Result}; use futures_lite::stream::StreamExt; @@ -18,6 +18,7 @@ pub async fn add( user: web::ReqData>, path: web::Path<(i32,)>, pg_pool: Data, + mq_pool: Data, sets: Data, ) -> Result { let id = path.0; diff --git a/src/startup.rs b/src/startup.rs index b592a4f..8831202 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -1,4 +1,5 @@ use crate::configuration::Settings; +use crate::helpers; use actix_cors::Cors; use actix_web::dev::Server; use actix_web::{ @@ -18,6 +19,9 @@ pub async fn run( let settings = web::Data::new(settings); let pg_pool = web::Data::new(pg_pool); + let mq_pool = helpers::MqPool::try_new(settings.amqp.connection_string())?; + let mq_pool = web::Data::new(mq_pool); + let server = HttpServer::new(move || { App::new() .wrap(TracingLogger::default()) @@ -64,6 +68,7 @@ pub async fn run( .service(crate::routes::stack::update::update), ) .app_data(pg_pool.clone()) + .app_data(mq_pool.clone()) .app_data(settings.clone()) }) .listen(listener)? From c6bf4a2c222ab43d2550c85e6d34e7d6f192b403 Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 30 Dec 2023 10:31:31 +0200 Subject: [PATCH 108/284] issue-auth mq_manager --- src/helpers/mod.rs | 4 ++-- src/helpers/{mq_pool.rs => mq_manager.rs} | 8 +++++--- src/routes/stack/deploy.rs | 4 ++-- src/startup.rs | 6 +++--- 4 files changed, 12 insertions(+), 10 deletions(-) rename src/helpers/{mq_pool.rs => mq_manager.rs} (87%) diff --git a/src/helpers/mod.rs b/src/helpers/mod.rs index 6d7d2a1..6d3b169 100644 --- a/src/helpers/mod.rs +++ b/src/helpers/mod.rs @@ -1,7 +1,7 @@ pub mod client; pub(crate) mod json; -mod mq_pool; +mod mq_manager; pub(crate) mod stack; pub use json::*; -pub use mq_pool::MqPool; +pub use mq_manager::MqManager; diff --git a/src/helpers/mq_pool.rs b/src/helpers/mq_manager.rs similarity index 87% rename from src/helpers/mq_pool.rs rename to src/helpers/mq_manager.rs index 4e5bcbd..00b9526 100644 --- a/src/helpers/mq_pool.rs +++ b/src/helpers/mq_manager.rs @@ -1,11 +1,11 @@ use deadpool_lapin::{Config, CreatePoolError, Pool, Runtime}; #[derive(Debug)] -pub struct MqPool { +pub struct MqManager { pool: Pool, } -impl MqPool { +impl MqManager { pub fn try_new(url: String) -> Result { let mut cfg = Config::default(); cfg.url = Some(url); @@ -22,6 +22,8 @@ impl MqPool { } })?; - Ok(MqPool { pool }) + Ok(Self { pool }) } + + pub async fn create_channel() {} } diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs index 2593c46..dc00eaf 100644 --- a/src/routes/stack/deploy.rs +++ b/src/routes/stack/deploy.rs @@ -2,7 +2,7 @@ use crate::configuration::Settings; use crate::db; use crate::forms::StackPayload; use crate::helpers::stack::builder::DcBuilder; -use crate::helpers::{JsonResponse, MqPool}; +use crate::helpers::{JsonResponse, MqManager}; use crate::models; use actix_web::{post, web, web::Data, Responder, Result}; use futures_lite::stream::StreamExt; @@ -18,7 +18,7 @@ pub async fn add( user: web::ReqData>, path: web::Path<(i32,)>, pg_pool: Data, - mq_pool: Data, + mq_manager: Data, sets: Data, ) -> Result { let id = path.0; diff --git a/src/startup.rs b/src/startup.rs index 8831202..b510af6 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -19,8 +19,8 @@ pub async fn run( let settings = web::Data::new(settings); let pg_pool = web::Data::new(pg_pool); - let mq_pool = helpers::MqPool::try_new(settings.amqp.connection_string())?; - let mq_pool = web::Data::new(mq_pool); + let mq_manager = helpers::MqManager::try_new(settings.amqp.connection_string())?; + let mq_manager = web::Data::new(mq_manager); let server = HttpServer::new(move || { App::new() @@ -68,7 +68,7 @@ pub async fn run( .service(crate::routes::stack::update::update), ) .app_data(pg_pool.clone()) - .app_data(mq_pool.clone()) + .app_data(mq_manager.clone()) .app_data(settings.clone()) }) .listen(listener)? From d870fcac78a1ed21f0293b993e2bb5dde1542259 Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 30 Dec 2023 22:13:28 +0200 Subject: [PATCH 109/284] issue-auth mq_manager::publish_and_confirm --- src/helpers/mq_manager.rs | 64 +++++++++++++++++++++++++++++++++++++- src/routes/stack/deploy.rs | 51 ++++++------------------------ 2 files changed, 73 insertions(+), 42 deletions(-) diff --git a/src/helpers/mq_manager.rs b/src/helpers/mq_manager.rs index 00b9526..ed7a9b1 100644 --- a/src/helpers/mq_manager.rs +++ b/src/helpers/mq_manager.rs @@ -1,4 +1,9 @@ use deadpool_lapin::{Config, CreatePoolError, Pool, Runtime}; +use lapin::{ + options::*, + publisher_confirm::{Confirmation, PublisherConfirm}, + BasicProperties, Connection, ConnectionProperties, +}; #[derive(Debug)] pub struct MqManager { @@ -25,5 +30,62 @@ impl MqManager { Ok(Self { pool }) } - pub async fn create_channel() {} + pub async fn publish( + &self, + exchange: String, + routing_key: String, + payload: &[u8], + ) -> Result { + let addr = String::new(); + Connection::connect(&addr, ConnectionProperties::default()) + .await + .map_err(|err| { + tracing::error!("connecting to RabbitMQ {:?}", err); + format!("connecting to RabbitMQ {:?}", err) + })? + .create_channel() + .await + .map_err(|err| { + tracing::error!("creating RabbitMQ channel {:?}", err); + format!("creating RabbitMQ channel {:?}", err) + })? + .basic_publish( + "install", + routing_key.as_str(), + BasicPublishOptions::default(), + payload, + BasicProperties::default(), + ) + .await + .map_err(|err| { + tracing::error!("publishing message {:?}", err); + format!("publishing message {:?}", err) + }) + } + + pub async fn publish_and_confirm( + &self, + exchange: String, + routing_key: String, + payload: &[u8], + ) -> Result<(), String> { + self.publish(exchange, routing_key, payload) + .await + .map_err(|err| { + tracing::error!("publishing the message {:?}", err); + format!("publishing the message {:?}", err) + })? + .await + .map_err(|err| { + tracing::error!("confirming the publication {:?}", err); + format!("confirming the publication {:?}", err) + }) + .and_then(|confirm| match confirm { + Confirmation::NotRequested => { + tracing::error!("confirmation is NotRequested"); + Err(format!("confirmation is NotRequested")) + } + _ => Ok(()), + }) + } } diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs index dc00eaf..8653119 100644 --- a/src/routes/stack/deploy.rs +++ b/src/routes/stack/deploy.rs @@ -6,9 +6,7 @@ use crate::helpers::{JsonResponse, MqManager}; use crate::models; use actix_web::{post, web, web::Data, Responder, Result}; use futures_lite::stream::StreamExt; -use lapin::{ - options::*, publisher_confirm::Confirmation, BasicProperties, Connection, ConnectionProperties, -}; +use lapin::publisher_confirm::Confirmation; use sqlx::PgPool; use std::sync::Arc; @@ -51,48 +49,19 @@ pub async fn add( let payload = serde_json::to_string::(&stack_data).map_err(|err| { tracing::error!("serializing StackPayload {:?}", err); JsonResponse::::build().internal_server_error("") - })?; - - let addr = sets.amqp.connection_string(); - let routing_key = "install.start.tfa.all.all".to_string(); - tracing::debug!("Sending message to {:?}", routing_key); + })?; //todo is it possible to use lapin serde - Connection::connect(&addr, ConnectionProperties::default()) - .await - .map_err(|err| { - tracing::error!("connecting to RabbitMQ {:?}", err); - JsonResponse::::build().internal_server_error("") - })? - .create_channel() - .await - .map_err(|err| { - tracing::error!("creating RabbitMQ channel {:?}", err); - JsonResponse::::build().internal_server_error("") - })? - .basic_publish( - "install", - routing_key.as_str(), - BasicPublishOptions::default(), + mq_manager + .publish_and_confirm( + "install".to_string(), + "install.start.tfa.all.all".to_string(), payload.as_bytes(), - BasicProperties::default(), ) .await - .map_err(|err| { - tracing::error!("publishing the message {:?}", err); - JsonResponse::::build().internal_server_error("") - })? - .await - .map_err(|err| { - tracing::error!("confirming the publication {:?}", err); - JsonResponse::::build().internal_server_error("") - }) - .and_then(|confirm| match confirm { - Confirmation::NotRequested => { - Err(JsonResponse::::build() - .bad_request("confirmation is NotRequested")) - } - _ => Ok(JsonResponse::::build() + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .map(|_| { + JsonResponse::::build() .set_id(id) - .ok("Success")), + .ok("Success") }) } From bf8cadc53164f58bfd48912b313bd1ce6a79856c Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 30 Dec 2023 22:31:13 +0200 Subject: [PATCH 110/284] issue-auth move to deadpool --- src/helpers/mq_manager.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/helpers/mq_manager.rs b/src/helpers/mq_manager.rs index ed7a9b1..898f5af 100644 --- a/src/helpers/mq_manager.rs +++ b/src/helpers/mq_manager.rs @@ -36,13 +36,12 @@ impl MqManager { routing_key: String, payload: &[u8], ) -> Result { - let addr = String::new(); - Connection::connect(&addr, ConnectionProperties::default()) - .await - .map_err(|err| { - tracing::error!("connecting to RabbitMQ {:?}", err); - format!("connecting to RabbitMQ {:?}", err) - })? + let connection = self.pool.get().await.map_err(|err| { + tracing::error!("getting connection from pool {:?}", err); + format!("getting connection from pool {:?}", err) + })?; + + connection .create_channel() .await .map_err(|err| { @@ -50,7 +49,7 @@ impl MqManager { format!("creating RabbitMQ channel {:?}", err) })? .basic_publish( - "install", + exchange.as_str(), routing_key.as_str(), BasicPublishOptions::default(), payload, From 67c2f592ef442150bde618ca8c2ae474ee68f5aa Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 30 Dec 2023 22:40:08 +0200 Subject: [PATCH 111/284] issue_auth mq_manager.create_channel --- src/helpers/mq_manager.rs | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/helpers/mq_manager.rs b/src/helpers/mq_manager.rs index 898f5af..707d4d1 100644 --- a/src/helpers/mq_manager.rs +++ b/src/helpers/mq_manager.rs @@ -2,7 +2,7 @@ use deadpool_lapin::{Config, CreatePoolError, Pool, Runtime}; use lapin::{ options::*, publisher_confirm::{Confirmation, PublisherConfirm}, - BasicProperties, Connection, ConnectionProperties, + BasicProperties, Channel, Connection, ConnectionProperties, }; #[derive(Debug)] @@ -30,24 +30,30 @@ impl MqManager { Ok(Self { pool }) } + async fn create_channel(&self) -> Result { + self.pool + .get() + .await + .map_err(|err| { + tracing::error!("getting connection from pool {:?}", err); + format!("getting connection from pool {:?}", err) + })? + .create_channel() + .await + .map_err(|err| { + tracing::error!("creating RabbitMQ channel {:?}", err); + format!("creating RabbitMQ channel {:?}", err) + }) + } + pub async fn publish( &self, exchange: String, routing_key: String, payload: &[u8], ) -> Result { - let connection = self.pool.get().await.map_err(|err| { - tracing::error!("getting connection from pool {:?}", err); - format!("getting connection from pool {:?}", err) - })?; - - connection - .create_channel() - .await - .map_err(|err| { - tracing::error!("creating RabbitMQ channel {:?}", err); - format!("creating RabbitMQ channel {:?}", err) - })? + self.create_channel() + .await? .basic_publish( exchange.as_str(), routing_key.as_str(), @@ -69,11 +75,7 @@ impl MqManager { payload: &[u8], ) -> Result<(), String> { self.publish(exchange, routing_key, payload) - .await - .map_err(|err| { - tracing::error!("publishing the message {:?}", err); - format!("publishing the message {:?}", err) - })? + .await? .await .map_err(|err| { tracing::error!("confirming the publication {:?}", err); From 9ad15f73b173c224b094dce934a9e5852f294de2 Mon Sep 17 00:00:00 2001 From: Petru Date: Sat, 30 Dec 2023 22:47:50 +0200 Subject: [PATCH 112/284] issue-auth mq_manager get_connection --- src/helpers/mq_manager.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/helpers/mq_manager.rs b/src/helpers/mq_manager.rs index 707d4d1..4fde261 100644 --- a/src/helpers/mq_manager.rs +++ b/src/helpers/mq_manager.rs @@ -1,8 +1,8 @@ -use deadpool_lapin::{Config, CreatePoolError, Pool, Runtime}; +use deadpool_lapin::{Config, CreatePoolError, Object, Pool, Runtime}; use lapin::{ options::*, publisher_confirm::{Confirmation, PublisherConfirm}, - BasicProperties, Channel, Connection, ConnectionProperties, + BasicProperties, Channel, }; #[derive(Debug)] @@ -30,14 +30,16 @@ impl MqManager { Ok(Self { pool }) } + async fn get_connection(&self) -> Result { + self.pool.get().await.map_err(|err| { + tracing::error!("getting connection from pool {:?}", err); + format!("getting connection from pool {:?}", err) + }) + } + async fn create_channel(&self) -> Result { - self.pool - .get() - .await - .map_err(|err| { - tracing::error!("getting connection from pool {:?}", err); - format!("getting connection from pool {:?}", err) - })? + self.get_connection() + .await? .create_channel() .await .map_err(|err| { From 8d7e9a0136cb25e877411424e0e4bc32350156bf Mon Sep 17 00:00:00 2001 From: Petru Date: Sun, 31 Dec 2023 18:34:57 +0200 Subject: [PATCH 113/284] issue-auth tracing::instrument for DcBuilder::build --- src/helpers/stack/builder.rs | 130 ++++++++++++++++++----------------- 1 file changed, 66 insertions(+), 64 deletions(-) diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 1db77c5..42df43f 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -1,12 +1,12 @@ +use crate::forms::{stack, App, StackForm, Volume, Web}; +use crate::helpers::stack::dctypes::{ + AdvancedVolumes, Compose, ComposeNetwork, ComposeNetworkSettingDetails, ComposeNetworks, + ComposeVolume, Entrypoint, Environment, MapOrEmpty, NetworkSettings, Networks, Port, Ports, + PublishedPort, Service, Services, SingleValue, TopLevelVolumes, Volumes, +}; +use crate::models::stack::Stack; use indexmap::IndexMap; -use crate::helpers::stack::dctypes::{Compose, Port, Ports, PublishedPort, Service, Services, - Volumes, Environment, Entrypoint, AdvancedVolumes, SingleValue, - Networks, TopLevelVolumes, ComposeVolume, ComposeNetwork, - ComposeNetworks, MapOrEmpty, ComposeNetworkSettingDetails, - NetworkSettings}; use serde_yaml; -use crate::forms::{StackForm, stack, App, Volume, Web}; -use crate::models::stack::Stack; #[derive(Clone, Debug)] struct Config {} @@ -16,7 +16,7 @@ impl Default for Config { } } -impl Default for Port{ +impl Default for Port { fn default() -> Self { Port { target: 80, @@ -38,10 +38,13 @@ pub struct DcBuilder { impl TryInto for Volume { type Error = String; fn try_into(self) -> Result { - let source = self.host_path.clone(); let target = self.container_path.clone(); - tracing::debug!("Volume conversion result: source: {:?} target: {:?}", source, target); + tracing::debug!( + "Volume conversion result: source: {:?} target: {:?}", + source, + target + ); Ok(AdvancedVolumes { source: source, target: target.unwrap_or("".to_string()), @@ -57,12 +60,18 @@ impl TryInto for Volume { impl TryInto for stack::Port { type Error = String; fn try_into(self) -> Result { - let cp = self.container_port.clone() + let cp = self + .container_port + .clone() .unwrap_or("".to_string()) - .parse::().map_err(|err| "Could not parse port".to_string() )?; - let hp = self.host_port.clone() + .parse::() + .map_err(|err| "Could not parse port".to_string())?; + let hp = self + .host_port + .clone() .unwrap_or("".to_string()) - .parse::().map_err(|err| "Could not parse port".to_string() )?; + .parse::() + .map_err(|err| "Could not parse port".to_string())?; tracing::debug!("Port conversion result: cp: {:?} hp: {:?}", cp, hp); Ok(Port { @@ -92,8 +101,7 @@ fn convert_shared_ports(ports: Option>) -> Result, St match ports { Some(ports) => { tracing::debug!("Ports >>>> {:?}", ports); - for port in ports { - } + for port in ports {} } None => { tracing::debug!("No ports defined by user"); @@ -126,25 +134,22 @@ impl TryIntoService for App { ..Default::default() }; - let networks: Networks = self.network - .clone() - .try_into() - .unwrap_or_default(); + let networks: Networks = self.network.clone().try_into().unwrap_or_default(); - let ports: Vec = self.ports + let ports: Vec = self + .ports .clone() .unwrap_or_default() .into_iter() .map(|x| x.try_into().unwrap()) .collect(); - let volumes: Vec = self.volumes + let volumes: Vec = self + .volumes .clone() .unwrap_or_default() .into_iter() - .map(|x| { - x.try_into().unwrap() - }) + .map(|x| x.try_into().unwrap()) .collect(); let mut envs = IndexMap::new(); @@ -152,7 +157,7 @@ impl TryIntoService for App { let items = item .into_iter() .map(|(k, v)| (k, Some(SingleValue::String(v.clone())))) - .collect::>(); + .collect::>(); envs.extend(items); } @@ -169,7 +174,6 @@ impl TryIntoService for App { impl Into>> for stack::ComposeNetworks { fn into(self) -> IndexMap> { - // tracing::debug!("networks found {:?}", self.networks); let mut networks = vec!["default_network".to_string()]; if self.networks.is_some() { @@ -177,59 +181,58 @@ impl Into>> for stack::ComposeNetwo } let networks = networks .into_iter() - .map(|net| - (net, - MapOrEmpty::Map( - NetworkSettings { - attachable: false, - driver: None, - driver_opts: Default::default(), - enable_ipv6: false, - internal: false, - // external: None, - external: Some(ComposeNetwork::Bool(true)), - ipam: None, - labels: Default::default(), - name: Some("default".to_string()), - } - )) - ) + .map(|net| { + ( + net, + MapOrEmpty::Map(NetworkSettings { + attachable: false, + driver: None, + driver_opts: Default::default(), + enable_ipv6: false, + internal: false, + // external: None, + external: Some(ComposeNetwork::Bool(true)), + ipam: None, + labels: Default::default(), + name: Some("default".to_string()), + }), + ) + }) .collect::>(); networks } } - pub fn extract_named_volumes(app: App) -> IndexMap> { - let mut named_volumes = IndexMap::default(); - let volumes = app.volumes - .unwrap() - .into_iter() - .filter(|volume| is_named_docker_volume( - volume.host_path.clone().unwrap().as_str()) - ) - .map(|volume| { - let k = volume.host_path.clone().unwrap(); - (k.clone(), MapOrEmpty::Map(ComposeVolume { + let volumes = app + .volumes + .unwrap() + .into_iter() + .filter(|volume| is_named_docker_volume(volume.host_path.clone().unwrap().as_str())) + .map(|volume| { + let k = volume.host_path.clone().unwrap(); + ( + k.clone(), + MapOrEmpty::Map(ComposeVolume { driver: None, driver_opts: Default::default(), external: None, labels: Default::default(), - name: Some(k.clone()) - })) - }) - .collect::>>(); + name: Some(k.clone()), + }), + ) + }) + .collect::>>(); - named_volumes.extend(volumes); + named_volumes.extend(volumes); // tracing::debug!("Named volumes: {:?}", named_volumes); named_volumes } impl DcBuilder { - pub fn new(stack: Stack) -> Self { DcBuilder { config: Config::default(), @@ -237,6 +240,7 @@ impl DcBuilder { } } + #[tracing::instrument(name = "building stack")] pub fn build(&self) -> Option { tracing::debug!("Start build docker compose from {:?}", &self.stack.body); let mut compose_content = Compose { @@ -277,7 +281,6 @@ impl DcBuilder { if !named_volumes.is_empty() { compose_content.volumes = TopLevelVolumes(named_volumes); } - } Err(e) => { tracing::debug!("Unpack stack form error {:?}", e); @@ -286,8 +289,7 @@ impl DcBuilder { tracing::debug!("services {:?}", &services); compose_content.services = Services(services); - - let fname= format!("./files/{}.yml", self.stack.stack_id); + let fname = format!("./files/{}.yml", self.stack.stack_id); tracing::debug!("Saving docker compose to file {:?}", fname); let target_file = std::path::Path::new(fname.as_str()); // serialize to string From ea374d7d054e81da977565812c1ee5d6b18631ef Mon Sep 17 00:00:00 2001 From: Petru Date: Sun, 31 Dec 2023 19:04:34 +0200 Subject: [PATCH 114/284] issue-auth DcBuilder build() --- src/helpers/stack/builder.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 42df43f..5a42b75 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -206,8 +206,12 @@ impl Into>> for stack::ComposeNetwo pub fn extract_named_volumes(app: App) -> IndexMap> { let mut named_volumes = IndexMap::default(); - let volumes = app - .volumes + let volumes = app.volumes; + if volumes.is_none() { + return named_volumes; + } + + let volumes = volumes .unwrap() .into_iter() .filter(|volume| is_named_docker_volume(volume.host_path.clone().unwrap().as_str())) @@ -293,12 +297,11 @@ impl DcBuilder { tracing::debug!("Saving docker compose to file {:?}", fname); let target_file = std::path::Path::new(fname.as_str()); // serialize to string - let serialized = match serde_yaml::to_string(&compose_content) { - Ok(s) => s, - Err(e) => panic!("Failed to serialize docker-compose file: {}", e), - }; - // serialize to file - std::fs::write(target_file, serialized.clone()).unwrap(); + let serialized = serde_yaml::to_string(&compose_content) + .map_err(|err| panic!("Failed to serialize docker-compose file: {}", err)) + .unwrap(); + + std::fs::write(target_file, serialized.clone()).map_err(|err| panic!("{}", err)); Some(serialized) } From fb7b13203b682efb19fe43185c23f8d2c22a1a46 Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 6 Jan 2024 15:09:36 +0200 Subject: [PATCH 115/284] issue-auth mq_manager. publish. Serialize --- src/helpers/mq_manager.rs | 17 +++++++++++------ src/routes/stack/deploy.rs | 7 +------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/helpers/mq_manager.rs b/src/helpers/mq_manager.rs index 4fde261..5b058ea 100644 --- a/src/helpers/mq_manager.rs +++ b/src/helpers/mq_manager.rs @@ -4,6 +4,7 @@ use lapin::{ publisher_confirm::{Confirmation, PublisherConfirm}, BasicProperties, Channel, }; +use serde::ser::Serialize; #[derive(Debug)] pub struct MqManager { @@ -48,19 +49,23 @@ impl MqManager { }) } - pub async fn publish( + pub async fn publish( &self, exchange: String, routing_key: String, - payload: &[u8], + msg: &T, ) -> Result { + let payload = serde_json::to_string::(msg).map_err(|err| { + format!("{:?}", err) + })?; + self.create_channel() .await? .basic_publish( exchange.as_str(), routing_key.as_str(), BasicPublishOptions::default(), - payload, + payload.as_bytes(), BasicProperties::default(), ) .await @@ -70,13 +75,13 @@ impl MqManager { }) } - pub async fn publish_and_confirm( + pub async fn publish_and_confirm( &self, exchange: String, routing_key: String, - payload: &[u8], + msg: &T ) -> Result<(), String> { - self.publish(exchange, routing_key, payload) + self.publish(exchange, routing_key, msg) .await? .await .map_err(|err| { diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs index 8653119..f626cc0 100644 --- a/src/routes/stack/deploy.rs +++ b/src/routes/stack/deploy.rs @@ -46,16 +46,11 @@ pub async fn add( stack_data.user_email = Some(user.email.clone()); stack_data.stack_code = stack_data.custom.custom_stack_code.clone(); - let payload = serde_json::to_string::(&stack_data).map_err(|err| { - tracing::error!("serializing StackPayload {:?}", err); - JsonResponse::::build().internal_server_error("") - })?; //todo is it possible to use lapin serde - mq_manager .publish_and_confirm( "install".to_string(), "install.start.tfa.all.all".to_string(), - payload.as_bytes(), + &stack_data, ) .await .map_err(|err| JsonResponse::::build().internal_server_error(err)) From 6ddd62ccef1363159ae9d73fbab93d5ddb7ec7e7 Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 6 Jan 2024 21:44:03 +0200 Subject: [PATCH 116/284] issue-auth DcBuilder stack. try from --- src/forms/mod.rs | 4 +-- src/forms/stack.rs | 33 ---------------------- src/forms/stack_payload.rs | 54 ++++++++++++++++++++++++++++++++++++ src/helpers/stack/builder.rs | 6 ++-- src/routes/stack/deploy.rs | 12 ++------ 5 files changed, 62 insertions(+), 47 deletions(-) create mode 100644 src/forms/stack_payload.rs diff --git a/src/forms/mod.rs b/src/forms/mod.rs index ae65e1c..cee99fe 100644 --- a/src/forms/mod.rs +++ b/src/forms/mod.rs @@ -1,8 +1,8 @@ mod rating; - pub mod stack; pub mod user; +mod stack_payload; pub use rating::*; - pub use stack::*; +pub use stack_payload::*; diff --git a/src/forms/stack.rs b/src/forms/stack.rs index cc32233..febd2af 100644 --- a/src/forms/stack.rs +++ b/src/forms/stack.rs @@ -125,39 +125,6 @@ pub struct StackForm { pub custom: Custom, } -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -#[serde(rename_all = "snake_case")] -pub struct StackPayload { - pub(crate) id: Option, - pub(crate) user_token: Option, - pub(crate) user_email: Option, - #[serde(rename = "commonDomain")] - pub common_domain: String, - pub domain_list: Option, - pub region: String, - pub zone: Option, - pub server: String, - pub os: String, - pub ssl: String, - pub vars: Option>, - #[serde(rename = "integrated_features")] - pub integrated_features: Option>, - #[serde(rename = "extended_features")] - pub extended_features: Option>, - pub subscriptions: Option>, - pub form_app: Option>, - pub disk_type: Option, - #[serde(rename = "save_token")] - pub save_token: bool, - #[serde(rename = "cloud_token")] - pub cloud_token: String, - pub provider: String, - pub stack_code: String, - #[serde(rename = "selected_plan")] - pub selected_plan: String, - pub custom: Custom, -} - #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct DomainList {} diff --git a/src/forms/stack_payload.rs b/src/forms/stack_payload.rs new file mode 100644 index 0000000..521642d --- /dev/null +++ b/src/forms/stack_payload.rs @@ -0,0 +1,54 @@ +use std::convert::TryFrom; +use crate::models; +use crate::forms; +use serde_json::Value; +use serde::{Deserialize, Serialize}; +use serde_valid::Validate; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +#[serde(rename_all = "snake_case")] +pub struct StackPayload { + pub(crate) id: Option, + pub(crate) user_token: Option, + pub(crate) user_email: Option, + #[serde(rename = "commonDomain")] + pub common_domain: String, + pub domain_list: Option, + pub region: String, + pub zone: Option, + pub server: String, + pub os: String, + pub ssl: String, + pub vars: Option>, + #[serde(rename = "integrated_features")] + pub integrated_features: Option>, + #[serde(rename = "extended_features")] + pub extended_features: Option>, + pub subscriptions: Option>, + pub form_app: Option>, + pub disk_type: Option, + #[serde(rename = "save_token")] + pub save_token: bool, + #[serde(rename = "cloud_token")] + pub cloud_token: String, + pub provider: String, + pub stack_code: String, + #[serde(rename = "selected_plan")] + pub selected_plan: String, + pub custom: forms::stack::Custom, +} + +impl TryFrom<&models::Stack> for StackPayload { + type Error = String; + + fn try_from(stack: &models::Stack) -> Result { + let mut stack_data = serde_json::from_value::(stack.body.clone()).map_err(|err| { + format!("{:?}", err) + })?; + + stack_data.id = Some(stack.id.clone()); + stack_data.stack_code = stack_data.custom.custom_stack_code.clone(); + + Ok(stack_data) + } +} diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 5a42b75..eeca4a2 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -4,7 +4,7 @@ use crate::helpers::stack::dctypes::{ ComposeVolume, Entrypoint, Environment, MapOrEmpty, NetworkSettings, Networks, Port, Ports, PublishedPort, Service, Services, SingleValue, TopLevelVolumes, Volumes, }; -use crate::models::stack::Stack; +use crate::models; use indexmap::IndexMap; use serde_yaml; #[derive(Clone, Debug)] @@ -32,7 +32,7 @@ impl Default for Port { #[derive(Clone, Debug)] pub struct DcBuilder { config: Config, - pub(crate) stack: Stack, + pub(crate) stack: models::Stack, } impl TryInto for Volume { @@ -237,7 +237,7 @@ pub fn extract_named_volumes(app: App) -> IndexMap Self { + pub fn new(stack: models::Stack) -> Self { DcBuilder { config: Config::default(), stack, diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs index f626cc0..80f4985 100644 --- a/src/routes/stack/deploy.rs +++ b/src/routes/stack/deploy.rs @@ -1,6 +1,6 @@ use crate::configuration::Settings; use crate::db; -use crate::forms::StackPayload; +use crate::forms; use crate::helpers::stack::builder::DcBuilder; use crate::helpers::{JsonResponse, MqManager}; use crate::models; @@ -35,16 +35,10 @@ pub async fn add( JsonResponse::::build().internal_server_error("") })?; - let mut stack_data = - serde_json::from_value::(dc.stack.body.clone()).map_err(|err| { - tracing::error!("transforming json Value into StackPayload {:?}", err); - JsonResponse::::build().bad_request("") - })?; - - stack_data.id = Some(id); + let mut stack_data = forms::StackPayload::try_from(&dc.stack) + .map_err(|err| JsonResponse::::build().bad_request(err))?; stack_data.user_token = Some(user.id.clone()); stack_data.user_email = Some(user.email.clone()); - stack_data.stack_code = stack_data.custom.custom_stack_code.clone(); mq_manager .publish_and_confirm( From 0c8936690caf53e6e3e31ff7ca5039460be21c92 Mon Sep 17 00:00:00 2001 From: petru Date: Sun, 7 Jan 2024 08:51:14 +0200 Subject: [PATCH 117/284] issue-auth Option->Result for DcBuilder::build --- src/helpers/stack/builder.rs | 74 ++++++++++++++++-------------------- src/routes/stack/compose.rs | 18 +++++---- src/routes/stack/deploy.rs | 5 +-- 3 files changed, 45 insertions(+), 52 deletions(-) diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index eeca4a2..1b7c0a9 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -124,7 +124,7 @@ fn is_named_docker_volume(volume: &str) -> bool { } trait TryIntoService { - fn try_into_service(&self) -> Service; + fn try_into_service(&self) -> Service; //todo transform into try_into } impl TryIntoService for App { @@ -245,64 +245,56 @@ impl DcBuilder { } #[tracing::instrument(name = "building stack")] - pub fn build(&self) -> Option { - tracing::debug!("Start build docker compose from {:?}", &self.stack.body); + pub fn build(&self) -> Result { let mut compose_content = Compose { version: Some("3.8".to_string()), ..Default::default() }; - let _stack = serde_json::from_value::(self.stack.body.clone()); + let apps = serde_json::from_value::(self.stack.body.clone()) + .map_err(|err| format!("{:?}", err))?; let mut services = IndexMap::new(); let mut named_volumes = IndexMap::default(); - match _stack { - Ok(apps) => { - for app_type in &apps.custom.web { - let service = app_type.app.try_into_service(); - services.insert(app_type.app.code.clone().to_owned(), Some(service)); - named_volumes.extend(extract_named_volumes(app_type.app.clone())); - } - - if let Some(srvs) = apps.custom.service { - for app_type in srvs { - let service = app_type.app.try_into_service(); - services.insert(app_type.app.code.clone().to_owned(), Some(service)); - named_volumes.extend(extract_named_volumes(app_type.app.clone())); - } - } - - if let Some(features) = apps.custom.feature { - for app_type in features { - let service = app_type.app.try_into_service(); - services.insert(app_type.app.code.clone().to_owned(), Some(service)); - named_volumes.extend(extract_named_volumes(app_type.app.clone())); - } - } - - let networks = apps.custom.networks.clone(); - compose_content.networks = ComposeNetworks(networks.into()); - - if !named_volumes.is_empty() { - compose_content.volumes = TopLevelVolumes(named_volumes); - } + for app_type in &apps.custom.web { + let service = app_type.app.try_into_service(); //todo + services.insert(app_type.app.code.clone().to_owned(), Some(service)); + named_volumes.extend(extract_named_volumes(app_type.app.clone())); + } + + if let Some(srvs) = apps.custom.service { + for app_type in srvs { + let service = app_type.app.try_into_service(); //todo + services.insert(app_type.app.code.clone().to_owned(), Some(service)); + named_volumes.extend(extract_named_volumes(app_type.app.clone())); } - Err(e) => { - tracing::debug!("Unpack stack form error {:?}", e); + } + + if let Some(features) = apps.custom.feature { + for app_type in features { + let service = app_type.app.try_into_service(); //todo + services.insert(app_type.app.code.clone().to_owned(), Some(service)); + named_volumes.extend(extract_named_volumes(app_type.app.clone())); } } + + let networks = apps.custom.networks.clone(); + compose_content.networks = ComposeNetworks(networks.into()); + + if !named_volumes.is_empty() { + compose_content.volumes = TopLevelVolumes(named_volumes); + } + tracing::debug!("services {:?}", &services); compose_content.services = Services(services); let fname = format!("./files/{}.yml", self.stack.stack_id); tracing::debug!("Saving docker compose to file {:?}", fname); let target_file = std::path::Path::new(fname.as_str()); - // serialize to string let serialized = serde_yaml::to_string(&compose_content) - .map_err(|err| panic!("Failed to serialize docker-compose file: {}", err)) - .unwrap(); + .map_err(|err| format!("Failed to serialize docker-compose file: {}", err))?; - std::fs::write(target_file, serialized.clone()).map_err(|err| panic!("{}", err)); + std::fs::write(target_file, serialized.clone()).map_err(|err| format!("{}", err))?; - Some(serialized) + Ok(serialized) } } diff --git a/src/routes/stack/compose.rs b/src/routes/stack/compose.rs index 4e58141..b8b5123 100644 --- a/src/routes/stack/compose.rs +++ b/src/routes/stack/compose.rs @@ -26,10 +26,11 @@ pub async fn add( })?; let id = stack.id.clone(); - let fc = DcBuilder::new(stack).build().ok_or_else(|| { - tracing::error!("Error. Compose builder returned an empty string"); - JsonResponse::::build().internal_server_error("troubles at building") - })?; + let fc = DcBuilder::new(stack) + .build() + .map_err(|err| { + JsonResponse::::build().internal_server_error(err) + })?; Ok(JsonResponse::build().set_id(id).set_item(fc).ok("Success")) } @@ -52,10 +53,11 @@ pub async fn admin( })?; let id = stack.id.clone(); - let fc = DcBuilder::new(stack).build().ok_or_else(|| { - tracing::error!("Error. Compose builder returned an empty string"); - JsonResponse::::build().internal_server_error("troubles at building") - })?; + let fc = DcBuilder::new(stack) + .build() + .map_err(|err| { + JsonResponse::::build().internal_server_error(err) + })?; Ok(JsonResponse::build().set_id(id).set_item(fc).ok("Success")) } diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs index 80f4985..005ac53 100644 --- a/src/routes/stack/deploy.rs +++ b/src/routes/stack/deploy.rs @@ -30,9 +30,8 @@ pub async fn add( let id = stack.id.clone(); let dc = DcBuilder::new(stack); - dc.build().ok_or_else(|| { - tracing::error!("Error. Compose builder returned an empty string"); - JsonResponse::::build().internal_server_error("") + dc.build().map_err(|err| { + JsonResponse::::build().internal_server_error(err) })?; let mut stack_data = forms::StackPayload::try_from(&dc.stack) From 3bad20d8927ee81c9e2a8b1b05ca9667e79344e6 Mon Sep 17 00:00:00 2001 From: petru Date: Sun, 7 Jan 2024 09:48:53 +0200 Subject: [PATCH 118/284] issue-auth StackForm::try_from --- src/forms/mod.rs | 2 ++ src/forms/stack.rs | 46 --------------------------- src/forms/stack_form.rs | 61 ++++++++++++++++++++++++++++++++++++ src/helpers/stack/builder.rs | 4 +-- src/routes/stack/add.rs | 14 ++++----- src/routes/stack/update.rs | 8 ++--- 6 files changed, 76 insertions(+), 59 deletions(-) create mode 100644 src/forms/stack_form.rs diff --git a/src/forms/mod.rs b/src/forms/mod.rs index cee99fe..a1379de 100644 --- a/src/forms/mod.rs +++ b/src/forms/mod.rs @@ -2,7 +2,9 @@ mod rating; pub mod stack; pub mod user; mod stack_payload; +mod stack_form; pub use rating::*; pub use stack::*; pub use stack_payload::*; +pub use stack_form::*; diff --git a/src/forms/stack.rs b/src/forms/stack.rs index febd2af..a9fc3cc 100644 --- a/src/forms/stack.rs +++ b/src/forms/stack.rs @@ -79,52 +79,6 @@ impl AsRef for App { } } -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct StackForm { - // #[validate(min_length=2)] - // #[validate(max_length=255)] - #[serde(rename = "commonDomain")] - pub common_domain: Option, - pub domain_list: Option, - #[validate(min_length = 2)] - #[validate(max_length = 255)] - pub stack_code: Option, - #[validate(min_length = 2)] - #[validate(max_length = 50)] - pub region: String, - #[validate(min_length = 2)] - #[validate(max_length = 50)] - pub zone: Option, - #[validate(min_length = 2)] - #[validate(max_length = 50)] - pub server: String, - #[validate(min_length = 2)] - #[validate(max_length = 50)] - pub os: String, - #[validate(min_length = 3)] - #[validate(max_length = 50)] - pub ssl: String, - pub vars: Option>, - pub integrated_features: Option>, - pub extended_features: Option>, - pub subscriptions: Option>, - pub form_app: Option>, - #[validate(min_length = 3)] - #[validate(max_length = 50)] - pub disk_type: Option, - pub save_token: bool, - #[validate(min_length = 10)] - #[validate(max_length = 255)] - pub cloud_token: String, - #[validate(min_length = 2)] - #[validate(max_length = 50)] - pub provider: String, - #[validate(min_length = 3)] - #[validate(max_length = 50)] - pub selected_plan: String, - pub custom: Custom, -} - #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct DomainList {} diff --git a/src/forms/stack_form.rs b/src/forms/stack_form.rs new file mode 100644 index 0000000..989205a --- /dev/null +++ b/src/forms/stack_form.rs @@ -0,0 +1,61 @@ +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use serde_valid::Validate; +use std::collections::HashMap; +use std::fmt; +use crate::models; +use crate::forms; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct StackForm { + // #[validate(min_length=2)] + // #[validate(max_length=255)] + #[serde(rename = "commonDomain")] + pub common_domain: Option, + pub domain_list: Option, + #[validate(min_length = 2)] + #[validate(max_length = 255)] + pub stack_code: Option, + #[validate(min_length = 2)] + #[validate(max_length = 50)] + pub region: String, + #[validate(min_length = 2)] + #[validate(max_length = 50)] + pub zone: Option, + #[validate(min_length = 2)] + #[validate(max_length = 50)] + pub server: String, + #[validate(min_length = 2)] + #[validate(max_length = 50)] + pub os: String, + #[validate(min_length = 3)] + #[validate(max_length = 50)] + pub ssl: String, + pub vars: Option>, + pub integrated_features: Option>, + pub extended_features: Option>, + pub subscriptions: Option>, + pub form_app: Option>, + #[validate(min_length = 3)] + #[validate(max_length = 50)] + pub disk_type: Option, + pub save_token: bool, + #[validate(min_length = 10)] + #[validate(max_length = 255)] + pub cloud_token: String, + #[validate(min_length = 2)] + #[validate(max_length = 50)] + pub provider: String, + #[validate(min_length = 3)] + #[validate(max_length = 50)] + pub selected_plan: String, + pub custom: forms::Custom, +} + +impl TryFrom<&models::Stack> for StackForm { + type Error = String; + + fn try_from(stack: &models::Stack) -> Result { + serde_json::from_value::(stack.body.clone()).map_err(|err| format!("{:?}", err)) + } +} diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 1b7c0a9..ea91da7 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -250,8 +250,8 @@ impl DcBuilder { version: Some("3.8".to_string()), ..Default::default() }; - let apps = serde_json::from_value::(self.stack.body.clone()) - .map_err(|err| format!("{:?}", err))?; + + let apps = StackForm::try_from(&self.stack)?; let mut services = IndexMap::new(); let mut named_volumes = IndexMap::default(); diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index 7ed5a09..bcf281c 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -1,5 +1,5 @@ use crate::db; -use crate::forms::stack::StackForm; +use crate::forms; use crate::helpers::JsonResponse; use crate::models; use actix_web::Error; @@ -27,8 +27,8 @@ pub async fn add( check_if_stack_exists(pg_pool.get_ref(), &stack_name).await?; - let body: Value = serde_json::to_value::(form) - .or(serde_json::to_value::(StackForm::default())) + let body: Value = serde_json::to_value::(form) + .or(serde_json::to_value::(forms::StackForm::default())) .unwrap(); let stack = models::Stack::new(user.id.clone(), stack_name, body); @@ -53,17 +53,17 @@ async fn check_if_stack_exists(pg_pool: &PgPool, stack_name: &String) -> Result< }) } -async fn body_into_form(body: Bytes) -> Result { +async fn body_into_form(body: Bytes) -> Result { let body_bytes = actix_web::body::to_bytes(body).await.unwrap(); let body_str = str::from_utf8(&body_bytes) - .map_err(|err| JsonResponse::::build().internal_server_error(err.to_string()))?; + .map_err(|err| JsonResponse::::build().internal_server_error(err.to_string()))?; let deserializer = &mut serde_json::Deserializer::from_str(body_str); serde_path_to_error::deserialize(deserializer) .map_err(|err| { let msg = format!("{}:{:?}", err.path().to_string(), err); - JsonResponse::::build().bad_request(msg) + JsonResponse::::build().bad_request(msg) }) - .and_then(|form: StackForm| { + .and_then(|form: forms::StackForm| { if !form.validate().is_ok() { let errors = form.validate().unwrap_err(); let err_msg = format!("Invalid data received {:?}", &errors.to_string()); diff --git a/src/routes/stack/update.rs b/src/routes/stack/update.rs index 229553f..a22be0c 100644 --- a/src/routes/stack/update.rs +++ b/src/routes/stack/update.rs @@ -1,4 +1,4 @@ -use crate::forms::stack::StackForm; +use crate::forms; use crate::helpers::JsonResponse; use crate::models; use crate::models::user::User; @@ -16,7 +16,7 @@ use uuid::Uuid; #[post("/{id}")] pub async fn update( path: web::Path<(i32,)>, - form: web::Json, + form: web::Json, user: web::ReqData>, pg_pool: Data, ) -> Result { @@ -67,11 +67,11 @@ pub async fn update( return Err(JsonResponse::::build().bad_request(errors.to_string())); } - let body: Value = match serde_json::to_value::(form.into_inner()) { + let body: Value = match serde_json::to_value::(form.into_inner()) { Ok(body) => body, Err(err) => { tracing::error!("Request_id {} error unwrap body {:?}", request_id, err); - serde_json::to_value::(StackForm::default()).unwrap() + serde_json::to_value::(forms::StackForm::default()).unwrap() } }; From 27e66b97acd49e65bbcf488d86bd2656edfb87ca Mon Sep 17 00:00:00 2001 From: petru Date: Sun, 7 Jan 2024 22:58:15 +0200 Subject: [PATCH 119/284] issue-auth Networks::try_from --- src/helpers/stack/builder.rs | 44 +++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index ea91da7..4acf963 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -84,14 +84,18 @@ impl TryInto for stack::Port { } } -impl TryInto for stack::ServiceNetworks { +impl TryFrom<&stack::ServiceNetworks> for Networks { type Error = (); - fn try_into(self) -> Result { - let mut networks = vec!["default_network".to_string()]; - if self.network.is_some() { - networks.append(&mut self.network.unwrap()); - } - Ok(Networks::Simple(networks)) + + fn try_from(serviceNetworks: &stack::ServiceNetworks) -> Result { + let mut result = vec!["default_network".to_string()]; + serviceNetworks.network.as_ref().map(|networks| { + for n in networks { + result.push(n.to_string()); + } + }); + + Ok(Networks::Simple(result)) } } @@ -123,20 +127,18 @@ fn is_named_docker_volume(volume: &str) -> bool { is_alphanumeric && does_not_contain_slash } -trait TryIntoService { - fn try_into_service(&self) -> Service; //todo transform into try_into -} +impl TryFrom<&App> for Service { + type Error = String; -impl TryIntoService for App { - fn try_into_service(&self) -> Service { + fn try_from(app: &App) -> Result { let mut service = Service { - image: Some(self.docker_image.to_string()), + image: Some(app.docker_image.to_string()), ..Default::default() }; - let networks: Networks = self.network.clone().try_into().unwrap_or_default(); + let networks = Networks::try_from(&app.network).unwrap_or_default(); - let ports: Vec = self + let ports: Vec = app //todo .ports .clone() .unwrap_or_default() @@ -144,7 +146,7 @@ impl TryIntoService for App { .map(|x| x.try_into().unwrap()) .collect(); - let volumes: Vec = self + let volumes: Vec = app //todo .volumes .clone() .unwrap_or_default() @@ -153,7 +155,7 @@ impl TryIntoService for App { .collect(); let mut envs = IndexMap::new(); - for item in self.environment.environment.clone().unwrap_or_default() { + for item in app.environment.environment.clone().unwrap_or_default() { //todo let items = item .into_iter() .map(|(k, v)| (k, Some(SingleValue::String(v.clone())))) @@ -168,7 +170,7 @@ impl TryIntoService for App { service.volumes = Volumes::Advanced(volumes); service.environment = Environment::KvPair(envs); - service + Ok(service) } } @@ -256,14 +258,14 @@ impl DcBuilder { let mut named_volumes = IndexMap::default(); for app_type in &apps.custom.web { - let service = app_type.app.try_into_service(); //todo + let service = Service::try_from(&app_type.app)?; services.insert(app_type.app.code.clone().to_owned(), Some(service)); named_volumes.extend(extract_named_volumes(app_type.app.clone())); } if let Some(srvs) = apps.custom.service { for app_type in srvs { - let service = app_type.app.try_into_service(); //todo + let service = Service::try_from(&app_type.app)?; services.insert(app_type.app.code.clone().to_owned(), Some(service)); named_volumes.extend(extract_named_volumes(app_type.app.clone())); } @@ -271,7 +273,7 @@ impl DcBuilder { if let Some(features) = apps.custom.feature { for app_type in features { - let service = app_type.app.try_into_service(); //todo + let service = Service::try_from(&app_type.app)?; services.insert(app_type.app.code.clone().to_owned(), Some(service)); named_volumes.extend(extract_named_volumes(app_type.app.clone())); } From 3e01e8741207c96b4c2963de66365cf3368b8493 Mon Sep 17 00:00:00 2001 From: petru Date: Sun, 7 Jan 2024 23:50:43 +0200 Subject: [PATCH 120/284] issue-auth TryInto --- src/helpers/stack/builder.rs | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 4acf963..55314ce 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -1,4 +1,5 @@ use crate::forms::{stack, App, StackForm, Volume, Web}; +use crate::forms; use crate::helpers::stack::dctypes::{ AdvancedVolumes, Compose, ComposeNetwork, ComposeNetworkSettingDetails, ComposeNetworks, ComposeVolume, Entrypoint, Environment, MapOrEmpty, NetworkSettings, Networks, Port, Ports, @@ -57,23 +58,21 @@ impl TryInto for Volume { } } -impl TryInto for stack::Port { +impl TryInto for &stack::Port { type Error = String; fn try_into(self) -> Result { let cp = self .container_port - .clone() - .unwrap_or("".to_string()) - .parse::() + .as_ref() + .map_or(Ok(0u16), |s| s.parse::()) .map_err(|err| "Could not parse port".to_string())?; + let hp = self .host_port - .clone() - .unwrap_or("".to_string()) - .parse::() + .as_ref() + .map_or(Ok(0u16), |s| s.parse::()) .map_err(|err| "Could not parse port".to_string())?; - tracing::debug!("Port conversion result: cp: {:?} hp: {:?}", cp, hp); Ok(Port { target: cp, host_ip: None, @@ -138,13 +137,16 @@ impl TryFrom<&App> for Service { let networks = Networks::try_from(&app.network).unwrap_or_default(); - let ports: Vec = app //todo - .ports - .clone() - .unwrap_or_default() - .into_iter() - .map(|x| x.try_into().unwrap()) - .collect(); + let ports: Vec = match &app.ports { + Some(ports) => { + let mut collector = vec![]; + for port in ports { + collector.push(port.try_into()?); + } + collector + } + None => vec![] + }; let volumes: Vec = app //todo .volumes From bddf56fc8e28e1f12964bfe8f82b78bb0bc61cc5 Mon Sep 17 00:00:00 2001 From: petru Date: Mon, 8 Jan 2024 21:47:11 +0200 Subject: [PATCH 121/284] issue_auth stack_app --- src/forms/mod.rs | 4 ++ src/forms/stack.rs | 105 ++--------------------------- src/forms/stack_app.rs | 126 +++++++++++++++++++++++++++++++++++ src/forms/stack_custom.rs | 81 ++++++++++++++++++++++ src/forms/stack_payload.rs | 2 +- src/helpers/stack/builder.rs | 69 +------------------ 6 files changed, 218 insertions(+), 169 deletions(-) create mode 100644 src/forms/stack_app.rs create mode 100644 src/forms/stack_custom.rs diff --git a/src/forms/mod.rs b/src/forms/mod.rs index a1379de..b7ef2dc 100644 --- a/src/forms/mod.rs +++ b/src/forms/mod.rs @@ -3,8 +3,12 @@ pub mod stack; pub mod user; mod stack_payload; mod stack_form; +mod stack_custom; +mod stack_app; pub use rating::*; pub use stack::*; pub use stack_payload::*; pub use stack_form::*; +pub use stack_custom::*; +pub use stack_app::*; diff --git a/src/forms/stack.rs b/src/forms/stack.rs index a9fc3cc..d62fa31 100644 --- a/src/forms/stack.rs +++ b/src/forms/stack.rs @@ -3,6 +3,7 @@ use serde_json::Value; use serde_valid::Validate; use std::collections::HashMap; use std::fmt; +use crate::forms; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Role { @@ -73,12 +74,6 @@ impl fmt::Display for DockerImage { } } -impl AsRef for App { - fn as_ref(&self) -> &DockerImage { - &self.docker_image - } -} - #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct DomainList {} @@ -91,103 +86,11 @@ pub struct Var {} pub struct Price { pub value: f64, } -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Custom { - pub web: Vec, - pub feature: Option>, - pub service: Option>, - #[validate(minimum = 0)] - #[validate(maximum = 10)] - pub servers_count: u32, - #[validate(min_length = 3)] - #[validate(max_length = 50)] - pub custom_stack_code: String, - #[validate(min_length = 3)] - #[validate(max_length = 255)] - pub project_git_url: Option, - pub custom_stack_category: Option>, - pub custom_stack_short_description: Option, - pub custom_stack_description: Option, - #[validate(min_length = 3)] - #[validate(max_length = 255)] - pub project_name: String, - pub project_overview: Option, - pub project_description: Option, - #[serde(flatten)] - pub networks: ComposeNetworks, // all networks -} - #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Network { name: String, } -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct App { - #[serde(rename = "_etag")] - #[validate(min_length = 3)] - #[validate(max_length = 255)] - pub etag: Option, - #[serde(rename = "_id")] - pub id: u32, - #[serde(rename = "_created")] - pub created: Option, - #[serde(rename = "_updated")] - pub updated: Option, - #[validate(min_length = 3)] - #[validate(max_length = 50)] - pub name: String, - #[validate(min_length = 3)] - #[validate(max_length = 50)] - pub code: String, - #[validate(min_length = 3)] - #[validate(max_length = 50)] - #[serde(rename = "type")] - pub type_field: String, - #[serde(flatten)] - pub role: Role, - pub default: Option, - pub versions: Option>, - #[serde(flatten)] - pub docker_image: DockerImage, - #[serde(flatten)] - pub requirements: Requirements, - #[validate(minimum = 1)] - pub popularity: Option, - pub commercial: Option, - pub subscription: Option, - pub autodeploy: Option, - pub suggested: Option, - pub dependency: Option, - pub avoid_render: Option, - pub price: Option, - pub icon: Option, - pub domain: Option, - pub category_id: Option, - pub parent_app_id: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub descr: Option, - pub full_description: Option, - pub description: Option, - pub plan_type: Option, - pub ansible_var: Option, - pub repo_dir: Option, - pub url_app: Option, - pub url_git: Option, - pub restart: Option, - pub volumes: Option>, - #[serde(flatten)] - pub environment: Environment, - #[serde(flatten)] - pub network: ServiceNetworks, - // #[serde(flatten)] - // pub ports: Ports, - #[serde(rename(deserialize = "sharedPorts"))] - #[serde(rename(serialize = "shared_ports"))] - #[serde(alias = "shared_ports")] - pub ports: Option>, -} - #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Environment { pub(crate) environment: Option>>, @@ -217,7 +120,7 @@ pub struct ComposeNetworks { #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Web { #[serde(flatten)] - pub app: App, + pub app: forms::App, pub custom: Option, pub main: bool, } @@ -229,7 +132,7 @@ pub struct Feature { // #[serde(alias = "shared_ports")] // pub shared_ports: Option>, #[serde(flatten)] - pub app: App, + pub app: forms::App, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] @@ -239,7 +142,7 @@ pub struct Service { // #[serde(alias = "shared_ports")] // pub shared_ports: Option>, #[serde(flatten)] - pub(crate) app: App, + pub(crate) app: forms::App, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] diff --git a/src/forms/stack_app.rs b/src/forms/stack_app.rs new file mode 100644 index 0000000..8ebdec3 --- /dev/null +++ b/src/forms/stack_app.rs @@ -0,0 +1,126 @@ +use crate::forms; +use crate::helpers::stack::dctypes; +use indexmap::IndexMap; +use serde_json::Value; +use serde::{Deserialize, Serialize}; +use serde_valid::Validate; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct App { + #[serde(rename = "_etag")] + #[validate(min_length = 3)] + #[validate(max_length = 255)] + pub etag: Option, + #[serde(rename = "_id")] + pub id: u32, + #[serde(rename = "_created")] + pub created: Option, + #[serde(rename = "_updated")] + pub updated: Option, + #[validate(min_length = 3)] + #[validate(max_length = 50)] + pub name: String, + #[validate(min_length = 3)] + #[validate(max_length = 50)] + pub code: String, + #[validate(min_length = 3)] + #[validate(max_length = 50)] + #[serde(rename = "type")] + pub type_field: String, + #[serde(flatten)] + pub role: forms::Role, + pub default: Option, + pub versions: Option>, + #[serde(flatten)] + pub docker_image: forms::DockerImage, + #[serde(flatten)] + pub requirements: forms::Requirements, + #[validate(minimum = 1)] + pub popularity: Option, + pub commercial: Option, + pub subscription: Option, + pub autodeploy: Option, + pub suggested: Option, + pub dependency: Option, + pub avoid_render: Option, + pub price: Option, + pub icon: Option, + pub domain: Option, + pub category_id: Option, + pub parent_app_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub descr: Option, + pub full_description: Option, + pub description: Option, + pub plan_type: Option, + pub ansible_var: Option, + pub repo_dir: Option, + pub url_app: Option, + pub url_git: Option, + pub restart: Option, + pub volumes: Option>, + #[serde(flatten)] + pub environment: forms::Environment, + #[serde(flatten)] + pub network: forms::ServiceNetworks, + // #[serde(flatten)] + // pub ports: Ports, + #[serde(rename(deserialize = "sharedPorts"))] + #[serde(rename(serialize = "shared_ports"))] + #[serde(alias = "shared_ports")] + pub ports: Option>, +} + +impl App { + pub fn named_volumes(&self) -> IndexMap> { //todo Result + let mut named_volumes = IndexMap::default(); + + let volumes = &self.volumes; + if volumes.is_none() { + return named_volumes; + } + + let volumes = volumes + .clone() //todo remove it + .unwrap() + .into_iter() + .filter(|volume| is_named_docker_volume(volume.host_path.clone().unwrap().as_str())) + .map(|volume| { + let k = volume.host_path.clone().unwrap(); + ( + k.clone(), + dctypes::MapOrEmpty::Map(dctypes::ComposeVolume { + driver: None, + driver_opts: Default::default(), + external: None, + labels: Default::default(), + name: Some(k.clone()), + }), + ) + }) + .collect::>>(); + + named_volumes.extend(volumes); + // tracing::debug!("Named volumes: {:?}", named_volumes); + + named_volumes + } +} + +impl AsRef for App { + fn as_ref(&self) -> &forms::DockerImage { + &self.docker_image + } +} + + +fn is_named_docker_volume(volume: &str) -> bool { //todo + // Docker named volumes typically don't contain special characters or slashes + // They are alphanumeric and may include underscores or hyphens + let is_alphanumeric = volume + .chars() + .all(|c| c.is_alphanumeric() || c == '_' || c == '-'); + let does_not_contain_slash = !volume.contains('/'); + is_alphanumeric && does_not_contain_slash +} + diff --git a/src/forms/stack_custom.rs b/src/forms/stack_custom.rs new file mode 100644 index 0000000..b6277a2 --- /dev/null +++ b/src/forms/stack_custom.rs @@ -0,0 +1,81 @@ +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use serde_valid::Validate; +use crate::forms; +use indexmap::IndexMap; +use crate::helpers::stack::dctypes; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct Custom { + pub web: Vec, + pub feature: Option>, + pub service: Option>, + #[validate(minimum = 0)] + #[validate(maximum = 10)] + pub servers_count: u32, + #[validate(min_length = 3)] + #[validate(max_length = 50)] + pub custom_stack_code: String, + #[validate(min_length = 3)] + #[validate(max_length = 255)] + pub project_git_url: Option, + pub custom_stack_category: Option>, + pub custom_stack_short_description: Option, + pub custom_stack_description: Option, + #[validate(min_length = 3)] + #[validate(max_length = 255)] + pub project_name: String, + pub project_overview: Option, + pub project_description: Option, + #[serde(flatten)] + pub networks: forms::ComposeNetworks, // all networks +} + +impl Custom { + pub fn services(&self) -> Result>, String> { + let mut services = IndexMap::new(); + + for app_type in &self.web { + let service = dctypes::Service::try_from(&app_type.app)?; + services.insert(app_type.app.code.clone().to_owned(), Some(service)); + } + + if let Some(srvs) = &self.service { + for app_type in srvs { + let service = dctypes::Service::try_from(&app_type.app)?; + services.insert(app_type.app.code.clone().to_owned(), Some(service)); + } + } + + if let Some(features) = &self.feature { + for app_type in features { + let service = dctypes::Service::try_from(&app_type.app)?; + services.insert(app_type.app.code.clone().to_owned(), Some(service)); + } + } + + Ok(services) + } + + pub fn named_volumes(&self) -> Result>, String> { + let mut named_volumes = IndexMap::new(); + + for app_type in &self.web { + named_volumes.extend(app_type.app.named_volumes()); + } + + if let Some(srvs) = &self.service { + for app_type in srvs { + named_volumes.extend(app_type.app.named_volumes()); + } + } + + if let Some(features) = &self.feature { + for app_type in features { + named_volumes.extend(app_type.app.named_volumes()); + } + } + + Ok(named_volumes) + } +} diff --git a/src/forms/stack_payload.rs b/src/forms/stack_payload.rs index 521642d..e7a56cd 100644 --- a/src/forms/stack_payload.rs +++ b/src/forms/stack_payload.rs @@ -35,7 +35,7 @@ pub struct StackPayload { pub stack_code: String, #[serde(rename = "selected_plan")] pub selected_plan: String, - pub custom: forms::stack::Custom, + pub custom: forms::Custom, } impl TryFrom<&models::Stack> for StackPayload { diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 55314ce..4457cd2 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -116,16 +116,6 @@ fn convert_shared_ports(ports: Option>) -> Result, St Ok(_ports) } -fn is_named_docker_volume(volume: &str) -> bool { - // Docker named volumes typically don't contain special characters or slashes - // They are alphanumeric and may include underscores or hyphens - let is_alphanumeric = volume - .chars() - .all(|c| c.is_alphanumeric() || c == '_' || c == '-'); - let does_not_contain_slash = !volume.contains('/'); - is_alphanumeric && does_not_contain_slash -} - impl TryFrom<&App> for Service { type Error = String; @@ -207,39 +197,6 @@ impl Into>> for stack::ComposeNetwo } } -pub fn extract_named_volumes(app: App) -> IndexMap> { - let mut named_volumes = IndexMap::default(); - - let volumes = app.volumes; - if volumes.is_none() { - return named_volumes; - } - - let volumes = volumes - .unwrap() - .into_iter() - .filter(|volume| is_named_docker_volume(volume.host_path.clone().unwrap().as_str())) - .map(|volume| { - let k = volume.host_path.clone().unwrap(); - ( - k.clone(), - MapOrEmpty::Map(ComposeVolume { - driver: None, - driver_opts: Default::default(), - external: None, - labels: Default::default(), - name: Some(k.clone()), - }), - ) - }) - .collect::>>(); - - named_volumes.extend(volumes); - // tracing::debug!("Named volumes: {:?}", named_volumes); - - named_volumes -} - impl DcBuilder { pub fn new(stack: models::Stack) -> Self { DcBuilder { @@ -256,30 +213,8 @@ impl DcBuilder { }; let apps = StackForm::try_from(&self.stack)?; - let mut services = IndexMap::new(); - let mut named_volumes = IndexMap::default(); - - for app_type in &apps.custom.web { - let service = Service::try_from(&app_type.app)?; - services.insert(app_type.app.code.clone().to_owned(), Some(service)); - named_volumes.extend(extract_named_volumes(app_type.app.clone())); - } - - if let Some(srvs) = apps.custom.service { - for app_type in srvs { - let service = Service::try_from(&app_type.app)?; - services.insert(app_type.app.code.clone().to_owned(), Some(service)); - named_volumes.extend(extract_named_volumes(app_type.app.clone())); - } - } - - if let Some(features) = apps.custom.feature { - for app_type in features { - let service = Service::try_from(&app_type.app)?; - services.insert(app_type.app.code.clone().to_owned(), Some(service)); - named_volumes.extend(extract_named_volumes(app_type.app.clone())); - } - } + let services = apps.custom.services()?; + let named_volumes = apps.custom.named_volumes()?; let networks = apps.custom.networks.clone(); compose_content.networks = ComposeNetworks(networks.into()); From b8334e4b6818dce890553ada7790746b10a9705d Mon Sep 17 00:00:00 2001 From: petru Date: Wed, 10 Jan 2024 17:53:32 +0200 Subject: [PATCH 122/284] issue-auth Volume::is_named_docker --- src/forms/stack.rs | 13 +++++++++++ src/forms/stack_app.rs | 52 +++++++++++++----------------------------- 2 files changed, 29 insertions(+), 36 deletions(-) diff --git a/src/forms/stack.rs b/src/forms/stack.rs index d62fa31..5a1296c 100644 --- a/src/forms/stack.rs +++ b/src/forms/stack.rs @@ -101,6 +101,19 @@ pub struct Volume { pub(crate) container_path: Option, } +impl Volume { + pub fn is_named_docker(&self) -> bool { + // Docker named volumes typically don't contain special characters or slashes + // They are alphanumeric and may include underscores or hyphens + self + .host_path + .as_ref() + .unwrap() + .chars() + .all(|c| c.is_alphanumeric() || c == '_' || c == '-') + } +} + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Volumes { volumes: Vec, diff --git a/src/forms/stack_app.rs b/src/forms/stack_app.rs index 8ebdec3..5608d76 100644 --- a/src/forms/stack_app.rs +++ b/src/forms/stack_app.rs @@ -72,36 +72,28 @@ pub struct App { } impl App { - pub fn named_volumes(&self) -> IndexMap> { //todo Result + pub fn named_volumes(&self) -> IndexMap> { let mut named_volumes = IndexMap::default(); - let volumes = &self.volumes; - if volumes.is_none() { + if self.volumes.is_none() { return named_volumes; } - let volumes = volumes - .clone() //todo remove it - .unwrap() - .into_iter() - .filter(|volume| is_named_docker_volume(volume.host_path.clone().unwrap().as_str())) - .map(|volume| { - let k = volume.host_path.clone().unwrap(); - ( - k.clone(), - dctypes::MapOrEmpty::Map(dctypes::ComposeVolume { - driver: None, - driver_opts: Default::default(), - external: None, - labels: Default::default(), - name: Some(k.clone()), - }), - ) - }) - .collect::>>(); + for volume in self.volumes.as_ref().unwrap() { + if !volume.is_named_docker() { + continue; + } - named_volumes.extend(volumes); - // tracing::debug!("Named volumes: {:?}", named_volumes); + let k = volume.host_path.as_ref().unwrap().clone(); + let v = dctypes::MapOrEmpty::Map(dctypes::ComposeVolume { + driver: None, + driver_opts: Default::default(), + external: None, + labels: Default::default(), + name: Some(k.clone()), + }); + named_volumes.insert(k, v); + } named_volumes } @@ -112,15 +104,3 @@ impl AsRef for App { &self.docker_image } } - - -fn is_named_docker_volume(volume: &str) -> bool { //todo - // Docker named volumes typically don't contain special characters or slashes - // They are alphanumeric and may include underscores or hyphens - let is_alphanumeric = volume - .chars() - .all(|c| c.is_alphanumeric() || c == '_' || c == '-'); - let does_not_contain_slash = !volume.contains('/'); - is_alphanumeric && does_not_contain_slash -} - From ea055ccfcd320c615972b57c46ae9a96003b0dc4 Mon Sep 17 00:00:00 2001 From: petru Date: Thu, 11 Jan 2024 18:02:00 +0200 Subject: [PATCH 123/284] issue-auth forms::stack --- src/forms/mod.rs | 9 ------- src/forms/{stack_app.rs => stack/app.rs} | 24 ++++++++--------- .../{stack_custom.rs => stack/custom.rs} | 8 +++--- src/forms/{stack_form.rs => stack/form.rs} | 12 ++++----- src/forms/{stack.rs => stack/mod.rs} | 16 ++++++++--- .../{stack_payload.rs => stack/payload.rs} | 8 +++--- src/helpers/stack/builder.rs | 27 +++++++++---------- src/helpers/stack/dctypes.rs | 8 +----- src/middleware/client.rs | 2 +- src/middleware/trydirect.rs | 4 +-- src/routes/client/update.rs | 1 - src/routes/rating/add.rs | 3 +-- src/routes/rating/get.rs | 2 +- src/routes/stack/add.rs | 12 ++++----- src/routes/stack/deploy.rs | 3 +-- src/routes/stack/update.rs | 8 +++--- src/services/rating.rs | 2 -- src/telemetry.rs | 2 +- 18 files changed, 70 insertions(+), 81 deletions(-) rename src/forms/{stack_app.rs => stack/app.rs} (83%) rename src/forms/{stack_custom.rs => stack/custom.rs} (92%) rename src/forms/{stack_form.rs => stack/form.rs} (84%) rename src/forms/{stack.rs => stack/mod.rs} (96%) rename src/forms/{stack_payload.rs => stack/payload.rs} (87%) diff --git a/src/forms/mod.rs b/src/forms/mod.rs index b7ef2dc..9647ea6 100644 --- a/src/forms/mod.rs +++ b/src/forms/mod.rs @@ -1,14 +1,5 @@ mod rating; pub mod stack; pub mod user; -mod stack_payload; -mod stack_form; -mod stack_custom; -mod stack_app; pub use rating::*; -pub use stack::*; -pub use stack_payload::*; -pub use stack_form::*; -pub use stack_custom::*; -pub use stack_app::*; diff --git a/src/forms/stack_app.rs b/src/forms/stack/app.rs similarity index 83% rename from src/forms/stack_app.rs rename to src/forms/stack/app.rs index 5608d76..7150926 100644 --- a/src/forms/stack_app.rs +++ b/src/forms/stack/app.rs @@ -28,13 +28,13 @@ pub struct App { #[serde(rename = "type")] pub type_field: String, #[serde(flatten)] - pub role: forms::Role, + pub role: forms::stack::Role, pub default: Option, - pub versions: Option>, + pub versions: Option>, #[serde(flatten)] - pub docker_image: forms::DockerImage, + pub docker_image: forms::stack::DockerImage, #[serde(flatten)] - pub requirements: forms::Requirements, + pub requirements: forms::stack::Requirements, #[validate(minimum = 1)] pub popularity: Option, pub commercial: Option, @@ -43,8 +43,8 @@ pub struct App { pub suggested: Option, pub dependency: Option, pub avoid_render: Option, - pub price: Option, - pub icon: Option, + pub price: Option, + pub icon: Option, pub domain: Option, pub category_id: Option, pub parent_app_id: Option, @@ -58,17 +58,17 @@ pub struct App { pub url_app: Option, pub url_git: Option, pub restart: Option, - pub volumes: Option>, + pub volumes: Option>, #[serde(flatten)] - pub environment: forms::Environment, + pub environment: forms::stack::Environment, #[serde(flatten)] - pub network: forms::ServiceNetworks, + pub network: forms::stack::ServiceNetworks, // #[serde(flatten)] // pub ports: Ports, #[serde(rename(deserialize = "sharedPorts"))] #[serde(rename(serialize = "shared_ports"))] #[serde(alias = "shared_ports")] - pub ports: Option>, + pub ports: Option>, } impl App { @@ -99,8 +99,8 @@ impl App { } } -impl AsRef for App { - fn as_ref(&self) -> &forms::DockerImage { +impl AsRef for App { + fn as_ref(&self) -> &forms::stack::DockerImage { &self.docker_image } } diff --git a/src/forms/stack_custom.rs b/src/forms/stack/custom.rs similarity index 92% rename from src/forms/stack_custom.rs rename to src/forms/stack/custom.rs index b6277a2..34f5437 100644 --- a/src/forms/stack_custom.rs +++ b/src/forms/stack/custom.rs @@ -7,9 +7,9 @@ use crate::helpers::stack::dctypes; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Custom { - pub web: Vec, - pub feature: Option>, - pub service: Option>, + pub web: Vec, + pub feature: Option>, + pub service: Option>, #[validate(minimum = 0)] #[validate(maximum = 10)] pub servers_count: u32, @@ -28,7 +28,7 @@ pub struct Custom { pub project_overview: Option, pub project_description: Option, #[serde(flatten)] - pub networks: forms::ComposeNetworks, // all networks + pub networks: forms::stack::ComposeNetworks, // all networks } impl Custom { diff --git a/src/forms/stack_form.rs b/src/forms/stack/form.rs similarity index 84% rename from src/forms/stack_form.rs rename to src/forms/stack/form.rs index 989205a..4e11776 100644 --- a/src/forms/stack_form.rs +++ b/src/forms/stack/form.rs @@ -7,12 +7,12 @@ use crate::models; use crate::forms; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct StackForm { +pub struct Stack { // #[validate(min_length=2)] // #[validate(max_length=255)] #[serde(rename = "commonDomain")] pub common_domain: Option, - pub domain_list: Option, + pub domain_list: Option, #[validate(min_length = 2)] #[validate(max_length = 255)] pub stack_code: Option, @@ -31,7 +31,7 @@ pub struct StackForm { #[validate(min_length = 3)] #[validate(max_length = 50)] pub ssl: String, - pub vars: Option>, + pub vars: Option>, pub integrated_features: Option>, pub extended_features: Option>, pub subscriptions: Option>, @@ -49,13 +49,13 @@ pub struct StackForm { #[validate(min_length = 3)] #[validate(max_length = 50)] pub selected_plan: String, - pub custom: forms::Custom, + pub custom: forms::stack::Custom, } -impl TryFrom<&models::Stack> for StackForm { +impl TryFrom<&models::Stack> for Stack { type Error = String; fn try_from(stack: &models::Stack) -> Result { - serde_json::from_value::(stack.body.clone()).map_err(|err| format!("{:?}", err)) + serde_json::from_value::(stack.body.clone()).map_err(|err| format!("{:?}", err)) } } diff --git a/src/forms/stack.rs b/src/forms/stack/mod.rs similarity index 96% rename from src/forms/stack.rs rename to src/forms/stack/mod.rs index 5a1296c..aadeddc 100644 --- a/src/forms/stack.rs +++ b/src/forms/stack/mod.rs @@ -5,6 +5,16 @@ use std::collections::HashMap; use std::fmt; use crate::forms; +mod app; +mod custom; +mod form; +mod payload; + +pub use app::*; +pub use custom::*; +pub use form::*; +pub use payload::*; + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Role { pub role: Option>, @@ -133,7 +143,7 @@ pub struct ComposeNetworks { #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Web { #[serde(flatten)] - pub app: forms::App, + pub app: forms::stack::App, pub custom: Option, pub main: bool, } @@ -145,7 +155,7 @@ pub struct Feature { // #[serde(alias = "shared_ports")] // pub shared_ports: Option>, #[serde(flatten)] - pub app: forms::App, + pub app: forms::stack::App, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] @@ -155,7 +165,7 @@ pub struct Service { // #[serde(alias = "shared_ports")] // pub shared_ports: Option>, #[serde(flatten)] - pub(crate) app: forms::App, + pub(crate) app: forms::stack::App, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] diff --git a/src/forms/stack_payload.rs b/src/forms/stack/payload.rs similarity index 87% rename from src/forms/stack_payload.rs rename to src/forms/stack/payload.rs index e7a56cd..70be841 100644 --- a/src/forms/stack_payload.rs +++ b/src/forms/stack/payload.rs @@ -7,7 +7,7 @@ use serde_valid::Validate; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] #[serde(rename_all = "snake_case")] -pub struct StackPayload { +pub struct Payload { pub(crate) id: Option, pub(crate) user_token: Option, pub(crate) user_email: Option, @@ -35,14 +35,14 @@ pub struct StackPayload { pub stack_code: String, #[serde(rename = "selected_plan")] pub selected_plan: String, - pub custom: forms::Custom, + pub custom: forms::stack::Custom, } -impl TryFrom<&models::Stack> for StackPayload { +impl TryFrom<&models::Stack> for Payload { type Error = String; fn try_from(stack: &models::Stack) -> Result { - let mut stack_data = serde_json::from_value::(stack.body.clone()).map_err(|err| { + let mut stack_data = serde_json::from_value::(stack.body.clone()).map_err(|err| { format!("{:?}", err) })?; diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 4457cd2..9068c9d 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -1,4 +1,3 @@ -use crate::forms::{stack, App, StackForm, Volume, Web}; use crate::forms; use crate::helpers::stack::dctypes::{ AdvancedVolumes, Compose, ComposeNetwork, ComposeNetworkSettingDetails, ComposeNetworks, @@ -36,7 +35,7 @@ pub struct DcBuilder { pub(crate) stack: models::Stack, } -impl TryInto for Volume { +impl TryInto for forms::stack::Volume { type Error = String; fn try_into(self) -> Result { let source = self.host_path.clone(); @@ -58,20 +57,20 @@ impl TryInto for Volume { } } -impl TryInto for &stack::Port { +impl TryInto for &forms::stack::Port { type Error = String; fn try_into(self) -> Result { let cp = self .container_port .as_ref() .map_or(Ok(0u16), |s| s.parse::()) - .map_err(|err| "Could not parse port".to_string())?; + .map_err(|_| "Could not parse port".to_string())?; let hp = self .host_port .as_ref() .map_or(Ok(0u16), |s| s.parse::()) - .map_err(|err| "Could not parse port".to_string())?; + .map_err(|_| "Could not parse port".to_string())?; Ok(Port { target: cp, @@ -83,12 +82,12 @@ impl TryInto for &stack::Port { } } -impl TryFrom<&stack::ServiceNetworks> for Networks { +impl TryFrom<&forms::stack::ServiceNetworks> for Networks { type Error = (); - fn try_from(serviceNetworks: &stack::ServiceNetworks) -> Result { + fn try_from(service_networks: &forms::stack::ServiceNetworks) -> Result { let mut result = vec!["default_network".to_string()]; - serviceNetworks.network.as_ref().map(|networks| { + service_networks.network.as_ref().map(|networks| { for n in networks { result.push(n.to_string()); } @@ -98,13 +97,13 @@ impl TryFrom<&stack::ServiceNetworks> for Networks { } } -fn convert_shared_ports(ports: Option>) -> Result, String> { +//todo +fn convert_shared_ports(ports: Option>) -> Result, String> { tracing::debug!("convert shared ports {:?}", &ports); let mut _ports: Vec = vec![]; match ports { Some(ports) => { tracing::debug!("Ports >>>> {:?}", ports); - for port in ports {} } None => { tracing::debug!("No ports defined by user"); @@ -116,10 +115,10 @@ fn convert_shared_ports(ports: Option>) -> Result, St Ok(_ports) } -impl TryFrom<&App> for Service { +impl TryFrom<&forms::stack::App> for Service { type Error = String; - fn try_from(app: &App) -> Result { + fn try_from(app: &forms::stack::App) -> Result { let mut service = Service { image: Some(app.docker_image.to_string()), ..Default::default() @@ -166,7 +165,7 @@ impl TryFrom<&App> for Service { } } -impl Into>> for stack::ComposeNetworks { +impl Into>> for forms::stack::ComposeNetworks { fn into(self) -> IndexMap> { // tracing::debug!("networks found {:?}", self.networks); let mut networks = vec!["default_network".to_string()]; @@ -212,7 +211,7 @@ impl DcBuilder { ..Default::default() }; - let apps = StackForm::try_from(&self.stack)?; + let apps = forms::stack::Stack::try_from(&self.stack)?; let services = apps.custom.services()?; let named_volumes = apps.custom.named_volumes()?; diff --git a/src/helpers/stack/dctypes.rs b/src/helpers/stack/dctypes.rs index 931deab..2238393 100644 --- a/src/helpers/stack/dctypes.rs +++ b/src/helpers/stack/dctypes.rs @@ -46,12 +46,6 @@ pub struct Compose { pub extensions: HashMap, } -impl Compose { - pub fn new() -> Self { - Default::default() - } -} - #[derive(Builder, Clone, Debug, Deserialize, Serialize, PartialEq, Default)] #[builder(setter(into), default)] pub struct Service { @@ -839,4 +833,4 @@ impl Serialize for MapOrEmpty } } } -} \ No newline at end of file +} diff --git a/src/middleware/client.rs b/src/middleware/client.rs index 60bce27..a6915d5 100644 --- a/src/middleware/client.rs +++ b/src/middleware/client.rs @@ -77,7 +77,7 @@ where let header_hash: String = get_header(&req, "stacker-hash")?; let db_pool = req.app_data::>>().unwrap().get_ref(); - let mut client: Client = db_fetch_client(db_pool, client_id).await?; + let client: Client = db_fetch_client(db_pool, client_id).await?; if client.secret.is_none() { return Err("client is not active".to_string()); } diff --git a/src/middleware/trydirect.rs b/src/middleware/trydirect.rs index e40f89b..62b4704 100644 --- a/src/middleware/trydirect.rs +++ b/src/middleware/trydirect.rs @@ -32,7 +32,7 @@ async fn fetch_user(auth_url: &str, token: &str) -> Result .header(ACCEPT, "application/json") .send() .await - .map_err(|err| "no resp from auth server".to_string())?; + .map_err(|_err| "no resp from auth server".to_string())?; if !resp.status().is_success() { return Err("401 Unauthorized".to_string()); @@ -41,6 +41,6 @@ async fn fetch_user(auth_url: &str, token: &str) -> Result resp .json::() .await - .map_err(|err| "can't parse the response body".to_string())? + .map_err(|_err| "can't parse the response body".to_string())? .try_into() } diff --git a/src/routes/client/update.rs b/src/routes/client/update.rs index a52af9b..5f19de5 100644 --- a/src/routes/client/update.rs +++ b/src/routes/client/update.rs @@ -3,7 +3,6 @@ use crate::helpers::client; use crate::models; use crate::{configuration::Settings, helpers::JsonResponse}; use actix_web::{put, web, Responder, Result}; -use futures::TryFutureExt; use sqlx::PgPool; use std::sync::Arc; use tracing::Instrument; diff --git a/src/routes/rating/add.rs b/src/routes/rating/add.rs index 48f0330..ea9657b 100644 --- a/src/routes/rating/add.rs +++ b/src/routes/rating/add.rs @@ -6,7 +6,6 @@ use actix_web::{post, web, Responder, Result}; use sqlx::PgPool; use tracing::Instrument; use std::sync::Arc; -use futures::TryFutureExt; // workflow // add, update, list, get(user_id), ACL, @@ -39,5 +38,5 @@ pub async fn add_handler( db::rating::insert(pg_pool.get_ref(), rating) .await .map(|rating| JsonResponse::build().set_item(rating).ok("success")) - .map_err(|err| JsonResponse::::build().internal_server_error("Failed to insert")) + .map_err(|_err| JsonResponse::::build().internal_server_error("Failed to insert")) } diff --git a/src/routes/rating/get.rs b/src/routes/rating/get.rs index 9081960..c759189 100644 --- a/src/routes/rating/get.rs +++ b/src/routes/rating/get.rs @@ -34,5 +34,5 @@ pub async fn list_handler( db::rating::fetch_all(pg_pool.get_ref()) .await .map(|ratings| JsonResponse::build().set_list(ratings).ok("OK")) - .map_err(|err| JsonResponse::::build().internal_server_error("")) + .map_err(|_err| JsonResponse::::build().internal_server_error("")) } diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index bcf281c..5a850c0 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -27,8 +27,8 @@ pub async fn add( check_if_stack_exists(pg_pool.get_ref(), &stack_name).await?; - let body: Value = serde_json::to_value::(form) - .or(serde_json::to_value::(forms::StackForm::default())) + let body: Value = serde_json::to_value::(form) + .or(serde_json::to_value::(forms::stack::Stack::default())) .unwrap(); let stack = models::Stack::new(user.id.clone(), stack_name, body); @@ -53,17 +53,17 @@ async fn check_if_stack_exists(pg_pool: &PgPool, stack_name: &String) -> Result< }) } -async fn body_into_form(body: Bytes) -> Result { +async fn body_into_form(body: Bytes) -> Result { let body_bytes = actix_web::body::to_bytes(body).await.unwrap(); let body_str = str::from_utf8(&body_bytes) - .map_err(|err| JsonResponse::::build().internal_server_error(err.to_string()))?; + .map_err(|err| JsonResponse::::build().internal_server_error(err.to_string()))?; let deserializer = &mut serde_json::Deserializer::from_str(body_str); serde_path_to_error::deserialize(deserializer) .map_err(|err| { let msg = format!("{}:{:?}", err.path().to_string(), err); - JsonResponse::::build().bad_request(msg) + JsonResponse::::build().bad_request(msg) }) - .and_then(|form: forms::StackForm| { + .and_then(|form: forms::stack::Stack| { if !form.validate().is_ok() { let errors = form.validate().unwrap_err(); let err_msg = format!("Invalid data received {:?}", &errors.to_string()); diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs index 005ac53..71d459f 100644 --- a/src/routes/stack/deploy.rs +++ b/src/routes/stack/deploy.rs @@ -5,7 +5,6 @@ use crate::helpers::stack::builder::DcBuilder; use crate::helpers::{JsonResponse, MqManager}; use crate::models; use actix_web::{post, web, web::Data, Responder, Result}; -use futures_lite::stream::StreamExt; use lapin::publisher_confirm::Confirmation; use sqlx::PgPool; use std::sync::Arc; @@ -34,7 +33,7 @@ pub async fn add( JsonResponse::::build().internal_server_error(err) })?; - let mut stack_data = forms::StackPayload::try_from(&dc.stack) + let mut stack_data = forms::stack::Payload::try_from(&dc.stack) .map_err(|err| JsonResponse::::build().bad_request(err))?; stack_data.user_token = Some(user.id.clone()); stack_data.user_email = Some(user.email.clone()); diff --git a/src/routes/stack/update.rs b/src/routes/stack/update.rs index a22be0c..316a1ba 100644 --- a/src/routes/stack/update.rs +++ b/src/routes/stack/update.rs @@ -16,7 +16,7 @@ use uuid::Uuid; #[post("/{id}")] pub async fn update( path: web::Path<(i32,)>, - form: web::Json, + form: web::Json, user: web::ReqData>, pg_pool: Data, ) -> Result { @@ -67,11 +67,11 @@ pub async fn update( return Err(JsonResponse::::build().bad_request(errors.to_string())); } - let body: Value = match serde_json::to_value::(form.into_inner()) { + let body: Value = match serde_json::to_value::(form.into_inner()) { Ok(body) => body, Err(err) => { tracing::error!("Request_id {} error unwrap body {:?}", request_id, err); - serde_json::to_value::(forms::StackForm::default()).unwrap() + serde_json::to_value::(forms::stack::Stack::default()).unwrap() } }; @@ -93,7 +93,7 @@ pub async fn update( .instrument(query_span) .await { - Ok(record) => { + Ok(_record) => { tracing::info!( "req_id: {} stack details have been saved to database", request_id diff --git a/src/services/rating.rs b/src/services/rating.rs index 22f4202..8222221 100644 --- a/src/services/rating.rs +++ b/src/services/rating.rs @@ -1,6 +1,4 @@ use crate::models::rating::Rating; -use sqlx::PgPool; -use reqwest::Url; use tracing::Instrument; use tracing_subscriber::fmt::format; diff --git a/src/telemetry.rs b/src/telemetry.rs index 724381a..fb57df1 100644 --- a/src/telemetry.rs +++ b/src/telemetry.rs @@ -1,4 +1,4 @@ -use tracing::subscriber::{self, set_global_default}; +use tracing::subscriber::set_global_default; use tracing::Subscriber; use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer}; use tracing_log::LogTracer; From 11e315ad793bbead1745c066cd2504f702025a06 Mon Sep 17 00:00:00 2001 From: petru Date: Fri, 12 Jan 2024 18:37:51 +0200 Subject: [PATCH 124/284] issue-auth dctypes --- src/helpers/stack/builder.rs | 37 ---- src/helpers/stack/dctypes/compose_file.rs | 18 ++ .../stack/{dctypes.rs => dctypes/mod.rs} | 193 ++---------------- src/helpers/stack/dctypes/port.rs | 53 +++++ src/helpers/stack/dctypes/published_port.rs | 8 + src/helpers/stack/dctypes/service.rs | 120 +++++++++++ src/helpers/stack/dctypes/single_service.rs | 8 + src/helpers/stack/dctypes/sys_ctls.rs | 30 +++ 8 files changed, 254 insertions(+), 213 deletions(-) create mode 100644 src/helpers/stack/dctypes/compose_file.rs rename src/helpers/stack/{dctypes.rs => dctypes/mod.rs} (75%) create mode 100644 src/helpers/stack/dctypes/port.rs create mode 100644 src/helpers/stack/dctypes/published_port.rs create mode 100644 src/helpers/stack/dctypes/service.rs create mode 100644 src/helpers/stack/dctypes/single_service.rs create mode 100644 src/helpers/stack/dctypes/sys_ctls.rs diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 9068c9d..334f5ca 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -16,18 +16,6 @@ impl Default for Config { } } -impl Default for Port { - fn default() -> Self { - Port { - target: 80, - host_ip: None, - published: None, - protocol: None, - mode: None, - } - } -} - /// A builder for constructing docker compose. #[derive(Clone, Debug)] pub struct DcBuilder { @@ -57,31 +45,6 @@ impl TryInto for forms::stack::Volume { } } -impl TryInto for &forms::stack::Port { - type Error = String; - fn try_into(self) -> Result { - let cp = self - .container_port - .as_ref() - .map_or(Ok(0u16), |s| s.parse::()) - .map_err(|_| "Could not parse port".to_string())?; - - let hp = self - .host_port - .as_ref() - .map_or(Ok(0u16), |s| s.parse::()) - .map_err(|_| "Could not parse port".to_string())?; - - Ok(Port { - target: cp, - host_ip: None, - published: Some(PublishedPort::Single(hp)), - protocol: None, - mode: None, - }) - } -} - impl TryFrom<&forms::stack::ServiceNetworks> for Networks { type Error = (); diff --git a/src/helpers/stack/dctypes/compose_file.rs b/src/helpers/stack/dctypes/compose_file.rs new file mode 100644 index 0000000..1131f67 --- /dev/null +++ b/src/helpers/stack/dctypes/compose_file.rs @@ -0,0 +1,18 @@ +use serde::{Deserialize, Serialize}; +use crate::helpers::stack::dctypes; + +#[cfg(feature = "indexmap")] +use indexmap::IndexMap; + +#[allow(clippy::large_enum_variant)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[serde(untagged)] +pub enum ComposeFile { + V2Plus(dctypes::Compose), + #[cfg(feature = "indexmap")] + V1(IndexMap), + #[cfg(not(feature = "indexmap"))] + V1(HashMap), + Single(dctypes::SingleService), +} + diff --git a/src/helpers/stack/dctypes.rs b/src/helpers/stack/dctypes/mod.rs similarity index 75% rename from src/helpers/stack/dctypes.rs rename to src/helpers/stack/dctypes/mod.rs index 2238393..507a696 100644 --- a/src/helpers/stack/dctypes.rs +++ b/src/helpers/stack/dctypes/mod.rs @@ -1,3 +1,19 @@ +mod port; +mod published_port; +mod compose_file; +mod single_service; +mod service; +mod sys_ctls; + +pub use port::*; +pub use published_port::*; +pub use compose_file::*; +pub use single_service::*; +pub use service::*; +pub use sys_ctls::*; + +use crate::helpers::stack::dctypes; + use derive_builder::*; #[cfg(feature = "indexmap")] use indexmap::IndexMap; @@ -9,23 +25,6 @@ use std::convert::TryFrom; use std::fmt; use std::str::FromStr; -#[allow(clippy::large_enum_variant)] -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -#[serde(untagged)] -pub enum ComposeFile { - V2Plus(Compose), - #[cfg(feature = "indexmap")] - V1(IndexMap), - #[cfg(not(feature = "indexmap"))] - V1(HashMap), - Single(SingleService), -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)] -pub struct SingleService { - pub service: Service, -} - #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)] pub struct Compose { #[serde(skip_serializing_if = "Option::is_none")] @@ -46,119 +45,6 @@ pub struct Compose { pub extensions: HashMap, } -#[derive(Builder, Clone, Debug, Deserialize, Serialize, PartialEq, Default)] -#[builder(setter(into), default)] -pub struct Service { - #[serde(skip_serializing_if = "Option::is_none")] - pub hostname: Option, - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub privileged: bool, - #[serde(skip_serializing_if = "Option::is_none")] - pub healthcheck: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub deploy: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub image: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub container_name: Option, - #[serde(skip_serializing_if = "Option::is_none", rename = "build")] - pub build_: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub pid: Option, - #[serde(default, skip_serializing_if = "Ports::is_empty")] - pub ports: Ports, - #[serde(default, skip_serializing_if = "Environment::is_empty")] - pub environment: Environment, - #[serde(skip_serializing_if = "Option::is_none")] - pub network_mode: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub devices: Vec, - #[serde(skip_serializing_if = "Option::is_none")] - pub restart: Option, - #[serde(default, skip_serializing_if = "Labels::is_empty")] - pub labels: Labels, - #[serde(skip_serializing_if = "Option::is_none")] - pub tmpfs: Option, - #[serde(default, skip_serializing_if = "Ulimits::is_empty")] - pub ulimits: Ulimits, - #[serde(default, skip_serializing_if = "Volumes::is_empty")] - pub volumes: Volumes, - #[serde(default, skip_serializing_if = "Networks::is_empty")] - pub networks: Networks, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub cap_add: Vec, - #[serde(default, skip_serializing_if = "DependsOnOptions::is_empty")] - pub depends_on: DependsOnOptions, - #[serde(skip_serializing_if = "Option::is_none")] - pub command: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub entrypoint: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub env_file: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub stop_grace_period: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub profiles: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub links: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub dns: Vec, - #[serde(skip_serializing_if = "Option::is_none")] - pub ipc: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub net: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub stop_signal: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub user: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub working_dir: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub expose: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub volumes_from: Vec, - #[cfg(feature = "indexmap")] - #[serde(default, skip_serializing_if = "IndexMap::is_empty")] - pub extends: IndexMap, - #[cfg(not(feature = "indexmap"))] - #[serde(default, skip_serializing_if = "HashMap::is_empty")] - pub extends: HashMap, - #[serde(skip_serializing_if = "Option::is_none")] - pub logging: Option, - #[serde(default, skip_serializing_if = "is_zero")] - pub scale: i64, - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub init: bool, - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub stdin_open: bool, - #[serde(skip_serializing_if = "Option::is_none")] - pub shm_size: Option, - #[cfg(feature = "indexmap")] - #[serde(flatten, skip_serializing_if = "IndexMap::is_empty")] - pub extensions: IndexMap, - #[cfg(not(feature = "indexmap"))] - #[serde(flatten, skip_serializing_if = "HashMap::is_empty")] - pub extensions: HashMap, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub extra_hosts: Vec, - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub tty: bool, - #[serde(default, skip_serializing_if = "SysCtls::is_empty")] - pub sysctls: SysCtls, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub security_opt: Vec, -} - -impl Service { - pub fn image(&self) -> &str { - self.image.as_deref().unwrap_or_default() - } - - pub fn network_mode(&self) -> &str { - self.network_mode.as_deref().unwrap_or_default() - } -} - #[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] #[serde(untagged)] pub enum EnvFile { @@ -211,7 +97,7 @@ pub struct LoggingParameters { #[serde(untagged)] pub enum Ports { Short(Vec), - Long(Vec), + Long(Vec), } impl Default for Ports { @@ -229,26 +115,6 @@ impl Ports { } } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -pub struct Port { - pub target: u16, - #[serde(skip_serializing_if = "Option::is_none")] - pub host_ip: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub published: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub protocol: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub mode: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -#[serde(untagged)] -pub enum PublishedPort { - Single(u16), - Range(String), -} - #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[serde(untagged)] pub enum Environment { @@ -457,31 +323,6 @@ pub struct AdvancedNetworkSettings { pub aliases: Vec, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -#[serde(untagged)] -pub enum SysCtls { - List(Vec), - #[cfg(feature = "indexmap")] - Map(IndexMap>), - #[cfg(not(feature = "indexmap"))] - Map(HashMap>), -} - -impl Default for SysCtls { - fn default() -> Self { - Self::List(Vec::new()) - } -} - -impl SysCtls { - pub fn is_empty(&self) -> bool { - match self { - Self::List(v) => v.is_empty(), - Self::Map(m) => m.is_empty(), - } - } -} - #[cfg(feature = "indexmap")] #[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] pub struct TopLevelVolumes(pub IndexMap>); diff --git a/src/helpers/stack/dctypes/port.rs b/src/helpers/stack/dctypes/port.rs new file mode 100644 index 0000000..2555758 --- /dev/null +++ b/src/helpers/stack/dctypes/port.rs @@ -0,0 +1,53 @@ +use serde::{Deserialize, Serialize}; +use crate::helpers::stack::dctypes; +use crate::forms; + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct Port { + pub target: u16, + #[serde(skip_serializing_if = "Option::is_none")] + pub host_ip: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub published: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub protocol: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub mode: Option, +} + +impl Default for Port { + fn default() -> Self { + Port { + target: 80, + host_ip: None, + published: None, + protocol: None, + mode: None, + } + } +} + +impl TryInto for &forms::stack::Port { + type Error = String; + fn try_into(self) -> Result { + let cp = self + .container_port + .as_ref() + .map_or(Ok(0u16), |s| s.parse::()) + .map_err(|_| "Could not parse port".to_string())?; + + let hp = self + .host_port + .as_ref() + .map_or(Ok(0u16), |s| s.parse::()) + .map_err(|_| "Could not parse port".to_string())?; + + Ok(Port { + target: cp, + host_ip: None, + published: Some(dctypes::PublishedPort::Single(hp)), + protocol: None, + mode: None, + }) + } +} diff --git a/src/helpers/stack/dctypes/published_port.rs b/src/helpers/stack/dctypes/published_port.rs new file mode 100644 index 0000000..57a24ab --- /dev/null +++ b/src/helpers/stack/dctypes/published_port.rs @@ -0,0 +1,8 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[serde(untagged)] +pub enum PublishedPort { + Single(u16), + Range(String), +} diff --git a/src/helpers/stack/dctypes/service.rs b/src/helpers/stack/dctypes/service.rs new file mode 100644 index 0000000..4cebefc --- /dev/null +++ b/src/helpers/stack/dctypes/service.rs @@ -0,0 +1,120 @@ +use serde::{Deserialize, Serialize}; +#[cfg(feature = "indexmap")] +use indexmap::IndexMap; +use crate::helpers::stack::dctypes; +use serde_json::Value; +use derive_builder::*; + +#[derive(Builder, Clone, Debug, Deserialize, Serialize, PartialEq, Default)] +#[builder(setter(into), default)] +pub struct Service { + #[serde(skip_serializing_if = "Option::is_none")] + pub hostname: Option, + #[serde(default, skip_serializing_if = "std::ops::Not::not")] + pub privileged: bool, + #[serde(skip_serializing_if = "Option::is_none")] + pub healthcheck: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub deploy: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub image: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub container_name: Option, + #[serde(skip_serializing_if = "Option::is_none", rename = "build")] + pub build_: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub pid: Option, + #[serde(default, skip_serializing_if = "dctypes::Ports::is_empty")] + pub ports: dctypes::Ports, + #[serde(default, skip_serializing_if = "dctypes::Environment::is_empty")] + pub environment: dctypes::Environment, + #[serde(skip_serializing_if = "Option::is_none")] + pub network_mode: Option, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub devices: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub restart: Option, + #[serde(default, skip_serializing_if = "dctypes::Labels::is_empty")] + pub labels: dctypes::Labels, + #[serde(skip_serializing_if = "Option::is_none")] + pub tmpfs: Option, + #[serde(default, skip_serializing_if = "dctypes::Ulimits::is_empty")] + pub ulimits: dctypes::Ulimits, + #[serde(default, skip_serializing_if = "dctypes::Volumes::is_empty")] + pub volumes: dctypes::Volumes, + #[serde(default, skip_serializing_if = "dctypes::Networks::is_empty")] + pub networks: dctypes::Networks, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub cap_add: Vec, + #[serde(default, skip_serializing_if = "dctypes::DependsOnOptions::is_empty")] + pub depends_on: dctypes::DependsOnOptions, + #[serde(skip_serializing_if = "Option::is_none")] + pub command: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub entrypoint: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub env_file: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub stop_grace_period: Option, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub profiles: Vec, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub links: Vec, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub dns: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub ipc: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub net: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub stop_signal: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub user: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub working_dir: Option, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub expose: Vec, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub volumes_from: Vec, + #[cfg(feature = "indexmap")] + #[serde(default, skip_serializing_if = "IndexMap::is_empty")] + pub extends: IndexMap, + #[cfg(not(feature = "indexmap"))] + #[serde(default, skip_serializing_if = "HashMap::is_empty")] + pub extends: HashMap, + #[serde(skip_serializing_if = "Option::is_none")] + pub logging: Option, + #[serde(default, skip_serializing_if = "dctypes::is_zero")] + pub scale: i64, + #[serde(default, skip_serializing_if = "std::ops::Not::not")] + pub init: bool, + #[serde(default, skip_serializing_if = "std::ops::Not::not")] + pub stdin_open: bool, + #[serde(skip_serializing_if = "Option::is_none")] + pub shm_size: Option, + #[cfg(feature = "indexmap")] + #[serde(flatten, skip_serializing_if = "IndexMap::is_empty")] + pub extensions: IndexMap, + #[cfg(not(feature = "indexmap"))] + #[serde(flatten, skip_serializing_if = "HashMap::is_empty")] + pub extensions: HashMap, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub extra_hosts: Vec, + #[serde(default, skip_serializing_if = "std::ops::Not::not")] + pub tty: bool, + #[serde(default, skip_serializing_if = "dctypes::SysCtls::is_empty")] + pub sysctls: dctypes::SysCtls, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub security_opt: Vec, +} + +impl Service { + pub fn image(&self) -> &str { + self.image.as_deref().unwrap_or_default() + } + + pub fn network_mode(&self) -> &str { + self.network_mode.as_deref().unwrap_or_default() + } +} + diff --git a/src/helpers/stack/dctypes/single_service.rs b/src/helpers/stack/dctypes/single_service.rs new file mode 100644 index 0000000..489a306 --- /dev/null +++ b/src/helpers/stack/dctypes/single_service.rs @@ -0,0 +1,8 @@ +use serde::{Deserialize, Serialize}; +use crate::helpers::stack::dctypes; + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)] +pub struct SingleService { + pub service: dctypes::Service, +} + diff --git a/src/helpers/stack/dctypes/sys_ctls.rs b/src/helpers/stack/dctypes/sys_ctls.rs new file mode 100644 index 0000000..45d0a7c --- /dev/null +++ b/src/helpers/stack/dctypes/sys_ctls.rs @@ -0,0 +1,30 @@ +use serde::{Deserialize, Serialize}; +use crate::helpers::stack::dctypes; +#[cfg(feature = "indexmap")] +use indexmap::IndexMap; + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[serde(untagged)] +pub enum SysCtls { + List(Vec), + #[cfg(feature = "indexmap")] + Map(IndexMap>), + #[cfg(not(feature = "indexmap"))] + Map(HashMap>), +} + +impl Default for SysCtls { + fn default() -> Self { + Self::List(Vec::new()) + } +} + +impl SysCtls { + pub fn is_empty(&self) -> bool { + match self { + Self::List(v) => v.is_empty(), + Self::Map(m) => m.is_empty(), + } + } +} + From 58ec7c916a92722c610d6962778ff6574f04eab0 Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 13 Jan 2024 09:59:54 +0200 Subject: [PATCH 125/284] issue-auth dctypes --- src/forms/stack/mod.rs | 1 - src/helpers/stack/dctypes/compose.rs | 25 +++ .../stack/dctypes/depends_condition.rs | 6 + .../stack/dctypes/depends_on_options.rs | 30 +++ src/helpers/stack/dctypes/env_file.rs | 9 + src/helpers/stack/dctypes/environment.rs | 30 +++ src/helpers/stack/dctypes/extension.rs | 28 +++ .../stack/dctypes/extension_parse_error.rs | 15 ++ .../stack/dctypes/logging_parameters.rs | 15 ++ src/helpers/stack/dctypes/mod.rs | 188 ++---------------- src/helpers/stack/dctypes/ports.rs | 25 +++ src/helpers/stack/dctypes/services.rs | 19 ++ src/models/rating.rs | 2 +- 13 files changed, 223 insertions(+), 170 deletions(-) create mode 100644 src/helpers/stack/dctypes/compose.rs create mode 100644 src/helpers/stack/dctypes/depends_condition.rs create mode 100644 src/helpers/stack/dctypes/depends_on_options.rs create mode 100644 src/helpers/stack/dctypes/env_file.rs create mode 100644 src/helpers/stack/dctypes/environment.rs create mode 100644 src/helpers/stack/dctypes/extension.rs create mode 100644 src/helpers/stack/dctypes/extension_parse_error.rs create mode 100644 src/helpers/stack/dctypes/logging_parameters.rs create mode 100644 src/helpers/stack/dctypes/ports.rs create mode 100644 src/helpers/stack/dctypes/services.rs diff --git a/src/forms/stack/mod.rs b/src/forms/stack/mod.rs index aadeddc..01a9589 100644 --- a/src/forms/stack/mod.rs +++ b/src/forms/stack/mod.rs @@ -1,5 +1,4 @@ use serde::{Deserialize, Serialize}; -use serde_json::Value; use serde_valid::Validate; use std::collections::HashMap; use std::fmt; diff --git a/src/helpers/stack/dctypes/compose.rs b/src/helpers/stack/dctypes/compose.rs new file mode 100644 index 0000000..82372d6 --- /dev/null +++ b/src/helpers/stack/dctypes/compose.rs @@ -0,0 +1,25 @@ +use serde::{Deserialize, Serialize}; +use crate::helpers::stack::dctypes; +#[cfg(feature = "indexmap")] +use indexmap::IndexMap; +use serde_yaml::Value; + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)] +pub struct Compose { + #[serde(skip_serializing_if = "Option::is_none")] + pub version: Option, + #[serde(default, skip_serializing_if = "dctypes::Services::is_empty")] + pub services: dctypes::Services, + #[serde(default, skip_serializing_if = "dctypes::TopLevelVolumes::is_empty")] + pub volumes: dctypes::TopLevelVolumes, + #[serde(default, skip_serializing_if = "dctypes::ComposeNetworks::is_empty")] + pub networks: dctypes::ComposeNetworks, + #[serde(skip_serializing_if = "Option::is_none")] + pub service: Option, + #[cfg(feature = "indexmap")] + #[serde(flatten, skip_serializing_if = "IndexMap::is_empty")] + pub extensions: IndexMap, + #[cfg(not(feature = "indexmap"))] + #[serde(flatten, skip_serializing_if = "HashMap::is_empty")] + pub extensions: HashMap, +} diff --git a/src/helpers/stack/dctypes/depends_condition.rs b/src/helpers/stack/dctypes/depends_condition.rs new file mode 100644 index 0000000..863c7b5 --- /dev/null +++ b/src/helpers/stack/dctypes/depends_condition.rs @@ -0,0 +1,6 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] +pub struct DependsCondition { + pub condition: String, +} diff --git a/src/helpers/stack/dctypes/depends_on_options.rs b/src/helpers/stack/dctypes/depends_on_options.rs new file mode 100644 index 0000000..6e12300 --- /dev/null +++ b/src/helpers/stack/dctypes/depends_on_options.rs @@ -0,0 +1,30 @@ +use serde::{Deserialize, Serialize}; +#[cfg(feature = "indexmap")] +use indexmap::IndexMap; +use crate::helpers::stack::dctypes; + +#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] +#[serde(untagged)] +pub enum DependsOnOptions { + Simple(Vec), + #[cfg(feature = "indexmap")] + Conditional(IndexMap), + #[cfg(not(feature = "indexmap"))] + Conditional(HashMap), +} + +impl Default for DependsOnOptions { + fn default() -> Self { + Self::Simple(Vec::new()) + } +} + +impl DependsOnOptions { + pub fn is_empty(&self) -> bool { + match self { + Self::Simple(v) => v.is_empty(), + Self::Conditional(m) => m.is_empty(), + } + } +} + diff --git a/src/helpers/stack/dctypes/env_file.rs b/src/helpers/stack/dctypes/env_file.rs new file mode 100644 index 0000000..643d6b9 --- /dev/null +++ b/src/helpers/stack/dctypes/env_file.rs @@ -0,0 +1,9 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] +#[serde(untagged)] +pub enum EnvFile { + Simple(String), + List(Vec), +} + diff --git a/src/helpers/stack/dctypes/environment.rs b/src/helpers/stack/dctypes/environment.rs new file mode 100644 index 0000000..3afafed --- /dev/null +++ b/src/helpers/stack/dctypes/environment.rs @@ -0,0 +1,30 @@ +use serde::{Deserialize, Serialize}; +use serde_yaml::Value; +#[cfg(feature = "indexmap")] +use indexmap::IndexMap; +use crate::helpers::stack::dctypes; + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[serde(untagged)] +pub enum Environment { + List(Vec), + #[cfg(feature = "indexmap")] + KvPair(IndexMap>), + #[cfg(not(feature = "indexmap"))] + KvPair(HashMap>), +} + +impl Default for Environment { + fn default() -> Self { + Self::List(Vec::new()) + } +} + +impl Environment { + pub fn is_empty(&self) -> bool { + match self { + Self::List(v) => v.is_empty(), + Self::KvPair(m) => m.is_empty(), + } + } +} diff --git a/src/helpers/stack/dctypes/extension.rs b/src/helpers/stack/dctypes/extension.rs new file mode 100644 index 0000000..f70871c --- /dev/null +++ b/src/helpers/stack/dctypes/extension.rs @@ -0,0 +1,28 @@ +use serde::{Deserialize, Serialize}; +use crate::helpers::stack::dctypes; +use std::str::FromStr; + +#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash, Default, Ord, PartialOrd)] +#[serde(try_from = "String")] +pub struct Extension(String); + +impl FromStr for Extension { + type Err = dctypes::ExtensionParseError; + + fn from_str(s: &str) -> Result { + let owned = s.to_owned(); + Extension::try_from(owned) + } +} + +impl TryFrom for Extension { + type Error = dctypes::ExtensionParseError; + + fn try_from(s: String) -> Result { + if s.starts_with("x-") { + Ok(Self(s)) + } else { + Err(dctypes::ExtensionParseError(s)) + } + } +} diff --git a/src/helpers/stack/dctypes/extension_parse_error.rs b/src/helpers/stack/dctypes/extension_parse_error.rs new file mode 100644 index 0000000..9fcec51 --- /dev/null +++ b/src/helpers/stack/dctypes/extension_parse_error.rs @@ -0,0 +1,15 @@ +use std::fmt; + +/// The result of a failed TryFrom conversion for [`Extension`] +/// +/// Contains the string that was being converted +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +pub struct ExtensionParseError(pub String); + +impl fmt::Display for ExtensionParseError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "unknown attribute {:?}, extensions must start with 'x-' (see https://docs.docker.com/compose/compose-file/#extension)", self.0) + } +} + +impl std::error::Error for ExtensionParseError {} diff --git a/src/helpers/stack/dctypes/logging_parameters.rs b/src/helpers/stack/dctypes/logging_parameters.rs new file mode 100644 index 0000000..bae66fc --- /dev/null +++ b/src/helpers/stack/dctypes/logging_parameters.rs @@ -0,0 +1,15 @@ +use serde::{Deserialize, Serialize}; +#[cfg(feature = "indexmap")] +use indexmap::IndexMap; +use crate::helpers::stack::dctypes; + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct LoggingParameters { + pub driver: String, + #[cfg(feature = "indexmap")] + #[serde(skip_serializing_if = "Option::is_none")] + pub options: Option>, + #[cfg(not(feature = "indexmap"))] + #[serde(skip_serializing_if = "Option::is_none")] + pub options: Option>, +} diff --git a/src/helpers/stack/dctypes/mod.rs b/src/helpers/stack/dctypes/mod.rs index 507a696..efde67a 100644 --- a/src/helpers/stack/dctypes/mod.rs +++ b/src/helpers/stack/dctypes/mod.rs @@ -4,6 +4,16 @@ mod compose_file; mod single_service; mod service; mod sys_ctls; +mod compose; +mod env_file; +mod depends_on_options; +mod depends_condition; +mod logging_parameters; +mod ports; +mod environment; +mod extension; +mod extension_parse_error; +mod services; pub use port::*; pub use published_port::*; @@ -11,6 +21,16 @@ pub use compose_file::*; pub use single_service::*; pub use service::*; pub use sys_ctls::*; +pub use compose::*; +pub use env_file::*; +pub use depends_on_options::*; +pub use depends_condition::*; +pub use logging_parameters::*; +pub use ports::*; +pub use environment::*; +pub use extension::*; +pub use extension_parse_error::*; +pub use services::*; use crate::helpers::stack::dctypes; @@ -23,174 +43,6 @@ use serde_yaml::Value; use std::collections::HashMap; use std::convert::TryFrom; use std::fmt; -use std::str::FromStr; - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)] -pub struct Compose { - #[serde(skip_serializing_if = "Option::is_none")] - pub version: Option, - #[serde(default, skip_serializing_if = "Services::is_empty")] - pub services: Services, - #[serde(default, skip_serializing_if = "TopLevelVolumes::is_empty")] - pub volumes: TopLevelVolumes, - #[serde(default, skip_serializing_if = "ComposeNetworks::is_empty")] - pub networks: ComposeNetworks, - #[serde(skip_serializing_if = "Option::is_none")] - pub service: Option, - #[cfg(feature = "indexmap")] - #[serde(flatten, skip_serializing_if = "IndexMap::is_empty")] - pub extensions: IndexMap, - #[cfg(not(feature = "indexmap"))] - #[serde(flatten, skip_serializing_if = "HashMap::is_empty")] - pub extensions: HashMap, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(untagged)] -pub enum EnvFile { - Simple(String), - List(Vec), -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] -#[serde(untagged)] -pub enum DependsOnOptions { - Simple(Vec), - #[cfg(feature = "indexmap")] - Conditional(IndexMap), - #[cfg(not(feature = "indexmap"))] - Conditional(HashMap), -} - -impl Default for DependsOnOptions { - fn default() -> Self { - Self::Simple(Vec::new()) - } -} - -impl DependsOnOptions { - pub fn is_empty(&self) -> bool { - match self { - Self::Simple(v) => v.is_empty(), - Self::Conditional(m) => m.is_empty(), - } - } -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -pub struct DependsCondition { - pub condition: String, -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -pub struct LoggingParameters { - pub driver: String, - #[cfg(feature = "indexmap")] - #[serde(skip_serializing_if = "Option::is_none")] - pub options: Option>, - #[cfg(not(feature = "indexmap"))] - #[serde(skip_serializing_if = "Option::is_none")] - pub options: Option>, -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -#[serde(untagged)] -pub enum Ports { - Short(Vec), - Long(Vec), -} - -impl Default for Ports { - fn default() -> Self { - Self::Short(Vec::default()) - } -} - -impl Ports { - pub fn is_empty(&self) -> bool { - match self { - Self::Short(v) => v.is_empty(), - Self::Long(v) => v.is_empty(), - } - } -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -#[serde(untagged)] -pub enum Environment { - List(Vec), - #[cfg(feature = "indexmap")] - KvPair(IndexMap>), - #[cfg(not(feature = "indexmap"))] - KvPair(HashMap>), -} - -impl Default for Environment { - fn default() -> Self { - Self::List(Vec::new()) - } -} - -impl Environment { - pub fn is_empty(&self) -> bool { - match self { - Self::List(v) => v.is_empty(), - Self::KvPair(m) => m.is_empty(), - } - } -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash, Default, Ord, PartialOrd)] -#[serde(try_from = "String")] -pub struct Extension(String); - -impl FromStr for Extension { - type Err = ExtensionParseError; - - fn from_str(s: &str) -> Result { - let owned = s.to_owned(); - Extension::try_from(owned) - } -} - -impl TryFrom for Extension { - type Error = ExtensionParseError; - - fn try_from(s: String) -> Result { - if s.starts_with("x-") { - Ok(Self(s)) - } else { - Err(ExtensionParseError(s)) - } - } -} - -/// The result of a failed TryFrom conversion for [`Extension`] -/// -/// Contains the string that was being converted -#[derive(Clone, Debug, Eq, PartialEq, Hash)] -pub struct ExtensionParseError(pub String); - -impl fmt::Display for ExtensionParseError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "unknown attribute {:?}, extensions must start with 'x-' (see https://docs.docker.com/compose/compose-file/#extension)", self.0) - } -} - -impl std::error::Error for ExtensionParseError {} - -#[cfg(feature = "indexmap")] -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] -pub struct Services(pub IndexMap>); -#[cfg(not(feature = "indexmap"))] -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] -pub struct Services(pub HashMap>); - -impl Services { - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } -} #[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] #[serde(untagged)] diff --git a/src/helpers/stack/dctypes/ports.rs b/src/helpers/stack/dctypes/ports.rs new file mode 100644 index 0000000..bdcc6a8 --- /dev/null +++ b/src/helpers/stack/dctypes/ports.rs @@ -0,0 +1,25 @@ +use serde::{Deserialize, Serialize}; +use crate::helpers::stack::dctypes; + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[serde(untagged)] +pub enum Ports { + Short(Vec), + Long(Vec), +} + +impl Default for Ports { + fn default() -> Self { + Self::Short(Vec::default()) + } +} + +impl Ports { + pub fn is_empty(&self) -> bool { + match self { + Self::Short(v) => v.is_empty(), + Self::Long(v) => v.is_empty(), + } + } +} + diff --git a/src/helpers/stack/dctypes/services.rs b/src/helpers/stack/dctypes/services.rs new file mode 100644 index 0000000..b41ff10 --- /dev/null +++ b/src/helpers/stack/dctypes/services.rs @@ -0,0 +1,19 @@ +use serde::{Deserialize, Serialize}; +#[cfg(feature = "indexmap")] +use indexmap::IndexMap; +#[cfg(not(feature = "indexmap"))] +use std::collections::HashMap; +use crate::helpers::stack::dctypes; + +#[cfg(feature = "indexmap")] +#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] +pub struct Services(pub IndexMap>); +#[cfg(not(feature = "indexmap"))] +#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] +pub struct Services(pub HashMap>); + +impl Services { + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } +} diff --git a/src/models/rating.rs b/src/models/rating.rs index e1522de..55a4444 100644 --- a/src/models/rating.rs +++ b/src/models/rating.rs @@ -1,5 +1,5 @@ use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; +use serde::{Serialize}; use crate::models; #[derive(Debug, Serialize, Default)] From 69f8fe888a0f448bfa0834fbad0977b5f7cbea8c Mon Sep 17 00:00:00 2001 From: vsilent Date: Sat, 13 Jan 2024 12:16:00 +0200 Subject: [PATCH 126/284] incomplete dockerhub image validation --- src/forms/stack.rs | 55 ++++++++++-- src/helpers/dockerhub.rs | 124 +++++++++++++++++++++++++ src/helpers/mod.rs | 6 +- src/routes/rating/add.rs | 9 +- src/routes/rating/get.rs | 2 +- src/routes/stack/add.rs | 12 +-- src/routes/stack/service.rs | 0 src/routes/stack/update.rs | 1 + tests/custom-stack-payload-12.json | 1 + tests/dockerhub.rs | 139 +++++++++++++++++++++++++++++ tests/model_user_stack.rs | 113 +++++++++++++++++++---- 11 files changed, 424 insertions(+), 38 deletions(-) create mode 100644 src/helpers/dockerhub.rs create mode 100644 src/routes/stack/service.rs create mode 100644 tests/custom-stack-payload-12.json create mode 100644 tests/dockerhub.rs diff --git a/src/forms/stack.rs b/src/forms/stack.rs index 00742c6..0459e66 100644 --- a/src/forms/stack.rs +++ b/src/forms/stack.rs @@ -3,6 +3,7 @@ use serde_json::Value; use serde_valid::Validate; use std::collections::HashMap; use std::fmt; +use crate::helpers::{login, docker_image_exists}; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Role { @@ -33,38 +34,74 @@ pub struct Port { pub container_port: Option, } +async fn validate_dockerhub_image( + dockerhub_user: &Option, + dockerhub_password: &Option, + dockerhub_name: &Option) -> Result<(), serde_valid::validation::Error> { + let result = login( + dockerhub_user.clone().unwrap_or("".to_string()).as_ref(), + dockerhub_password.clone().unwrap_or("".to_string()).as_ref() + ).await; + + let exists: bool = match result.unwrap().token { + Some(tok) => { + let exists = docker_image_exists( + dockerhub_user.clone().unwrap().as_str(), + dockerhub_name.clone().unwrap().as_str(), tok).await; + match exists { + Ok(_) => true, + Err(err) => { + println!("{:?}", err); + false + } + } + } + _ => false, + }; + if !exists { + return Err(serde_valid::validation::Error::Custom( + "Could not access docker image repository, please check credentials.".to_owned(), + )); + } + Ok(()) +} #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +#[validate(custom(|s| validate_dockerhub_image(dockerhub_user,dockerhub_name, dockerhub_password)))] pub struct DockerImage { #[validate(min_length = 3)] #[validate(max_length = 50)] + #[validate(pattern = r"^[a-z0-9]+([-_.][a-z0-9]+)*$")] pub dockerhub_user: Option, #[validate(min_length = 3)] #[validate(max_length = 50)] + #[validate(pattern = r"^[a-z0-9]+([-_.][a-z0-9]+)*$")] pub dockerhub_name: Option, #[validate(min_length = 3)] #[validate(max_length = 100)] + #[validate(pattern = r"^(?:(?=[^:\/]{1,253})(?!-)[a-zA-Z0-9-]{1,63}(?, + pub dockerhub_password: Option, } impl fmt::Display for DockerImage { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let tag = "latest"; + let dh_image = self.dockerhub_image.as_ref().map(String::as_str).unwrap_or(""); + let dh_nmspc = self.dockerhub_user.as_ref().map(String::as_str).unwrap_or(""); + let dh_name = self.dockerhub_name.as_ref().map(String::as_str).unwrap_or(""); - let dim = self.dockerhub_image.clone().unwrap_or("".to_string()); write!( f, - "{}/{}:{}", - self.dockerhub_user - .clone() - .unwrap_or("trydirect".to_string()) - .clone(), - self.dockerhub_name.clone().unwrap_or(dim), - tag + "{}{}{}", + if !dh_nmspc.is_empty() { format!("{}/", dh_nmspc) } else { String::new() }, + if !dh_name.is_empty() { dh_name } else { dh_image }, + if !dh_name.contains(":") && dh_image.is_empty() { ":latest".to_string() } else { String::new() }, ) } } + impl AsRef for App { fn as_ref(&self) -> &DockerImage { &self.docker_image diff --git a/src/helpers/dockerhub.rs b/src/helpers/dockerhub.rs new file mode 100644 index 0000000..e766b16 --- /dev/null +++ b/src/helpers/dockerhub.rs @@ -0,0 +1,124 @@ +use serde_derive::{Deserialize, Serialize}; +use serde_valid::Validate; +// use tracing_subscriber::fmt::format; +use serde_json::Value; + +// #[tokio::main] +// async fn main() -> Result<(), String> { + // tokio::select! { + // Ok(true) = docker_image_exist() => { + // println!("first branch. image exists."); + // } + // Ok(true) = docker_image_exist() => { + // println!("second branch. image exists."); + // } + // Ok(true) = docker_image_exist() => { + // println!("third branch. image exists."); + // } + // else => { + // println!("else branch. image does not exists"); + // } + // }; +// Ok(()) +// } + + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct DockerHubToken { + pub token: Option +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct DockerHubCreds<'a> { + username: &'a str, + password: &'a str +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +struct Image { + architecture: String, + digest: Option, + features: Option, + last_pulled: Option, + last_pushed: Option, + os: String, + os_features: Option, + os_version: Option, + size: i64, + status: String, + variant: Option, +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +struct Tag { + content_type: String, + creator: i64, + digest: Option, + full_size: i64, + id: i64, + images: Vec, + last_updated: String, + last_updater: i64, + last_updater_username: String, + media_type: String, + name: String, + repository: i64, + tag_last_pulled: Option, + tag_last_pushed: Option, + tag_status: String, + v2: bool +} +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +struct TagResult { + count: i64, + next: Value, + previous: Value, + results: Vec +} +pub async fn login(username: &str, password: &str) -> Result { + let endpoint = "https://hub.docker.com/v2/users/login"; + let creds = DockerHubCreds { username, password }; + let token = reqwest::Client::new() + .post(endpoint) + .json(&creds) + .send() + .await + .map_err(|err| format!("{}", err))? + .json::() + .await + .map_err(|err| format!("{}", err))?; + + Ok(token) +} + + +pub async fn docker_image_exists(user: &str, repo: &str, token: String) -> Result { + // get repo images + let tags_url = format!("https://hub.docker.com/v2/namespaces/{}/repositories/{}/tags", + user, repo); + + let tags = reqwest::Client::new() + .get(tags_url) + .header("Accept", "application/json") + .bearer_auth(token) + .send() + .await + .map_err(|err| format!("{}", err))? + .json::() + // .json::() + .await + .map_err(|err| format!("{}", err))?; + + // println!("tags count: {:?}", tags.count); + + if tags.count > 0 { + // let's find at least one active tag + let active = tags.results + .into_iter() + .any(|tag| tag.tag_status.contains("active") ); + // println!("is active {:?}", active); + Ok(active) + } else { + Err(String::from("There was no active images found in this repository")) + } +} diff --git a/src/helpers/mod.rs b/src/helpers/mod.rs index 5397875..3fe765f 100644 --- a/src/helpers/mod.rs +++ b/src/helpers/mod.rs @@ -3,4 +3,8 @@ pub(crate) mod json; pub(crate) mod stack; pub use json::*; pub(crate) mod compressor; -pub use compressor::*; \ No newline at end of file +pub mod dockerhub; + +pub use compressor::*; + +pub use dockerhub::*; diff --git a/src/routes/rating/add.rs b/src/routes/rating/add.rs index 48f0330..e191bd1 100644 --- a/src/routes/rating/add.rs +++ b/src/routes/rating/add.rs @@ -22,13 +22,15 @@ pub async fn add_handler( ) -> Result { let _product = db::product::fetch_by_obj(pg_pool.get_ref(), form.obj_id) .await - .map_err(|msg| JsonResponse::::build().internal_server_error(msg))? + .map_err(|_msg| JsonResponse::::build().internal_server_error(_msg))? .ok_or_else(|| JsonResponse::::build().not_found("not found"))? ; - let rating = db::rating::fetch_by_obj_and_user_and_category(pg_pool.get_ref(), form.obj_id, user.id.clone(), form.category) + let rating = db::rating::fetch_by_obj_and_user_and_category( + pg_pool.get_ref(), form.obj_id, user.id.clone(), form.category) .await .map_err(|err| JsonResponse::::build().internal_server_error(err))?; + if rating.is_some() { return Err(JsonResponse::::build().bad_request("already rated")); } @@ -39,5 +41,6 @@ pub async fn add_handler( db::rating::insert(pg_pool.get_ref(), rating) .await .map(|rating| JsonResponse::build().set_item(rating).ok("success")) - .map_err(|err| JsonResponse::::build().internal_server_error("Failed to insert")) + .map_err(|_err| JsonResponse::::build() + .internal_server_error("Failed to insert")) } diff --git a/src/routes/rating/get.rs b/src/routes/rating/get.rs index 824180f..2edfa7e 100644 --- a/src/routes/rating/get.rs +++ b/src/routes/rating/get.rs @@ -36,5 +36,5 @@ pub async fn list_handler(path: web::Path<()>, pool: web::Data) -> Resul db::rating::fetch_all(pool.get_ref()) .await .map(|ratings| JsonResponse::build().set_list(ratings).ok("OK")) - .map_err(|err| JsonResponse::::build().internal_server_error("")) + .map_err(|_err| JsonResponse::::build().internal_server_error("")) } diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index ef38ac5..b576734 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -25,7 +25,7 @@ pub async fn add( let form = body_into_form(body).await?; let stack_name = form.custom.custom_stack_code.clone(); - check_if_stack_exists(pool.get_ref(), &stack_name).await?; + stack_exists(pool.get_ref(), &stack_name).await?; let body: Value = serde_json::to_value::(form) .or(serde_json::to_value::(StackForm::default())) @@ -40,7 +40,8 @@ pub async fn add( }) } -async fn check_if_stack_exists(pool: &PgPool, stack_name: &String) -> Result<(), Error> { + +async fn stack_exists(pool: &PgPool, stack_name: &String) -> Result<(), Error> { db::stack::fetch_one_by_name(pool, stack_name) .await .map_err(|_| { @@ -56,14 +57,15 @@ async fn check_if_stack_exists(pool: &PgPool, stack_name: &String) -> Result<(), async fn body_into_form(body: Bytes) -> Result { let body_bytes = actix_web::body::to_bytes(body).await.unwrap(); let body_str = str::from_utf8(&body_bytes) - .map_err(|err| JsonResponse::::build().internal_server_error(err.to_string()))?; + .map_err(|_err| JsonResponse::::build().internal_server_error(_err.to_string()))?; let deserializer = &mut serde_json::Deserializer::from_str(body_str); serde_path_to_error::deserialize(deserializer) - .map_err(|err| { - let msg = format!("{}:{:?}", err.path().to_string(), err); + .map_err(|_err| { + let msg = format!("{}:{:?}", _err.path().to_string(), _err); JsonResponse::::build().bad_request(msg) }) .and_then(|form: StackForm| { + if !form.validate().is_ok() { let errors = form.validate().unwrap_err(); let err_msg = format!("Invalid data received {:?}", &errors.to_string()); diff --git a/src/routes/stack/service.rs b/src/routes/stack/service.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/routes/stack/update.rs b/src/routes/stack/update.rs index a418b53..ed4d3b7 100644 --- a/src/routes/stack/update.rs +++ b/src/routes/stack/update.rs @@ -72,6 +72,7 @@ pub async fn update( let errors = form.validate().unwrap_err(); let err_msg = format!("Invalid data received {:?}", &errors.to_string()); tracing::debug!(err_msg); + return Err(JsonResponse::::build().bad_request(errors.to_string())); } diff --git a/tests/custom-stack-payload-12.json b/tests/custom-stack-payload-12.json new file mode 100644 index 0000000..d405ff4 --- /dev/null +++ b/tests/custom-stack-payload-12.json @@ -0,0 +1 @@ +{"commonDomain":"justates222tee.com","domainList":{},"region":"fsn1","zone":null,"server":"cx21","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":["portainer_ce_feature"],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":true,"disk_type":"pd-standart","cloud_token":"***********","provider":"htz","stack_code":"custom-stack-2","selected_plan":"plan-individual-monthly","custom":{"web":[{"_etag":null,"_id":180,"_created":"2021-12-17T08:11:40.875486","_updated":"2023-11-21T17:37:24.594545","name":"Airflow","code":"airflow","role":["airflow"],"type":"web","default":true,"popularity":null,"descr":null,"ports":{"private":["31"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":150,"height":150,"image":"7f41d873-2de5-4c6e-a037-42eeff572db6.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":"

Airflow description

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"airflow","form":null,"category":[null],"group":[],"versions":[{"_id":425,"name":"Airflow","version":"2.7.3","update_status":"published","tag":"latest"},{"_id":426,"name":"Airflow","version":"2.7.1-unstable","update_status":"published","tag":"stable"}],"links":[],"domain":"latestports.com","sharedPorts":[{"host_port":"5000","container_port":"5000"}],"main":true,"version":{"_id":426,"name":"Airflow","version":"2.7.1-unstable","update_status":"published","tag":"stable"},"environment":[{"ENV_VAR1":"ENV_VAR1_VALUE"}, {"ENV_VAR2":"ENV_VAR1_VALUe2"}],"network":["testnetwork"],"restart":"always","volumes":[{"host_path":"./airflow/host/path/","container_path":"/airflow/container/path"}, {"host_path":"./airflow/host/path2/","container_path":"/airflow/container/path2"}, {"host_path":"airflow","container_path":"/airflow/named/volume/path"}]},{"category":[{"name":"integrated_features"}],"name":"CustomNginx","code":"customnginx","domain":"customnginx.latestports.com","sharedPorts":[{"host_port":"80","container_port":"8080"},{"host_port":"443","container_port":"8443"}],"versions":[],"custom":true,"type":"web","main":false,"_id":0,"dockerhub_user":"trydirect","dockerhub_name":"nginx","disk_size":"0.9Gb","ram_size":"1.3Gb","cpu":"0.3","volumes":[{"host_path":"./host/path","container_path":"/container/path"}, {"host_path": "namedvolume", "container_path": "/container/path/to/"}],"environment":[{"CUSTOM_NGINX_ENV_VAR1":"CUSTOM_NGINX_ENV_VAR1_VALUE"},{"CUSTOM_NGINX_VAR2": "CUSTOM_NGINX_VAR_VALUE2"}, {"CUSTOM_NGINX_ENV_VAR3":"CUSTOM_NGINX_ENV_VAR1_VALUE3"},{"CUSTOM_NGINX_VAR4": "CUSTOM_NGINX_VAR_VALUE4"}],"network":["testnetwork"],"restart":"always"}],"feature":[{"_etag":null,"_id":198,"_created":"2022-04-27T14:10:27.280327","_updated":"2023-08-03T08:24:18.958721","name":"Portainer CE Feature","code":"portainer_ce_feature","role":["portainer-ce-feature"],"type":"feature","default":null,"popularity":null,"descr":null,"ports":{"public":["9000","8000"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":1138,"height":1138,"image":"08589075-44e6-430e-98a5-f9dcf711e054.svg"},"dark":{}},"category_id":2,"parent_app_id":null,"full_description":null,"description":"

Portainer is a lightweight management UI which allows you to easily manage your different Docker environments (Docker hosts or Swarm clusters)

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.6","ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"portainer-ce-feature","form":null,"category":[{"name":"integrated_features"}],"group":[],"versions":[{"_id":456,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"}],"links":[],"version":{"_id":456,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"},"sharedPorts":[{"host_port":"9000","container_port":"9000"}],"environment":[{"PORTAINER_ENV_VAR1":"PORTAINER_ENV_VAR1_VALUE"}],"volumes":[{"host_path":"/portainer/test/path","container_path":"/portainer/test/path"}],"network":["testnetwork"],"restart":"always"}],"service":[{"_etag":null,"_id":24,"_created":"2020-06-19T13:07:24.228389","_updated":"2023-11-23T10:18:28.095813","name":"PostgreSQL","code":"postgres","role":["postgres"],"type":"service","default":null,"popularity":null,"descr":null,"ports":{"private":["5432"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":576,"height":594,"image":"fd23f54c-e250-4228-8d56-7e5d93ffb925.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":null,"plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"postgres","form":null,"category":[null],"group":[{"_etag":null,"_id":12,"_created":null,"_updated":null,"name":"Database","code":"database"}],"versions":[{"_id":458,"name":"15","version":"15","update_status":"published","tag":"15"},{"_id":288,"name":"10.22","version":"10.22","update_status":"published","tag":"10.22"},{"_id":303,"name":"13.8","version":"13.8","update_status":"published","tag":"13.8"},{"_id":266,"name":"11","version":"11","update_status":"published","tag":"11"},{"_id":267,"name":"12.12","version":"12.12","update_status":"published","tag":"12.12"},{"_id":38,"name":"14.5","version":"14.5","update_status":"published","tag":"14.5"},{"_id":596,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"}],"links":[],"domain":"","sharedPorts":[{"host_port":"5432","container_port":"5432"}],"main":false,"version":{"_id":596,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"},"environment":[{"POSTGRES_ENV_VAR1":"POSTGRES_ENV_VAR1_VALUE"},{"POSTGRES_ENV_VAR2":"POSTGRES_ENV_VAR2_VALUE"}],"network":["testnetwork"],"restart":"always","volumes":[{"host_path":"./pg.conf","container_path":"/etc/postgres/pg.conf"}]}],"servers_count":3,"project_name":"DockerHubCheck1","custom_stack_code":"hubcheck","project_git_url":"https://github.com/latestports","custom_stack_category":[],"networks":["testnetwork","testnetwork2"]}} \ No newline at end of file diff --git a/tests/dockerhub.rs b/tests/dockerhub.rs new file mode 100644 index 0000000..e13fe55 --- /dev/null +++ b/tests/dockerhub.rs @@ -0,0 +1,139 @@ +// use std::fs; +// use std::collections::HashMap; +use std::env; +mod common; +use stacker::helpers::dockerhub::{login, docker_image_exists}; + +const DOCKER_USERNAME: &str = "trydirect"; +const DOCKER_PASSWORD: &str = "dckr_pat_NyQoqqA2VFtBtCuZRp8YcjbuFkU"; + +// Unit Test + +// #[test] +// fn test_deserialize_user_stack_web() { +// +// let body_str = fs::read_to_string("./tests/web-item.json").unwrap(); +// // let form:serde_json::Value = serde_json::from_str(&body_str).unwrap(); +// let form:App = serde_json::from_str(&body_str).unwrap(); +// println!("{:?}", form); +// // { +// // Ok(f) => { +// // f +// // } +// // Err(_err) => { +// // let msg = format!("Invalid data. {:?}", _err); +// // return JsonResponse::::build().bad_request(msg); +// // } +// // }; +// // +// // assert_eq!(result, 12); +// } +// #[test] +// fn test_deserialize_user_stack() { +// +// let body_str = fs::read_to_string("./tests/custom-stack-payload-11.json").unwrap(); +// let form = serde_json::from_str::(&body_str).unwrap(); +// println!("{:?}", form); +// // @todo assert required data +// +// // { +// // Ok(f) => { +// // f +// // } +// // Err(_err) => { +// // let msg = format!("Invalid data. {:?}", _err); +// // return JsonResponse::::build().bad_request(msg); +// // } +// // }; +// // +// // assert_eq!(result, 12); +// +// // let form:Environment = serde_json::from_str(&body_str).unwrap(); +// // let form:Vec> = serde_json::from_str(&body_str).unwrap(); +// // println!("{:?}", form); +// } + +#[tokio::test] +async fn test_docker_hub_login() { + + common::spawn_app().await; // server + // let username = env::var("TEST_DOCKER_USERNAME") + // .expect("username environment variable is not set"); + // + // let password= env::var("TEST_DOCKER_PASSWORD") + // .expect("password environment variable is not set"); + let result = login( + DOCKER_USERNAME.as_ref(), + DOCKER_PASSWORD.as_ref() + ).await; + let token = result.unwrap().token; + + let exists: bool = match token { + Some(tok) => { + let exists = docker_image_exists(DOCKER_USERNAME, "nginx", tok).await; + match exists { + Ok(_) => true, + Err(err) => { + println!("{:?}", err); + false + } + } + } + _ => false, + }; + + assert_eq!(exists, true); +} + +#[tokio::test] +async fn test_docker_private_exists() { + + common::spawn_app().await; // server + let result = login( + DOCKER_USERNAME.as_ref(), DOCKER_PASSWORD.as_ref() + ).await; + let token = result.unwrap().token; + + let exists: bool = match token { + Some(tok) => { + let exists = docker_image_exists(DOCKER_USERNAME, "nginx-waf", tok).await; + match exists { + Ok(_) => true, + Err(err) => { + println!("{:?}", err); + false + } + } + } + _ => false, + }; + + assert_eq!(exists, true); +} + +#[tokio::test] +async fn test_docker_non_existent_repo() { + + common::spawn_app().await; // server + let result= login( + DOCKER_USERNAME.as_ref(), DOCKER_PASSWORD.as_ref() + ).await; + let token = result.unwrap().token; + + // println!("{:?}", token); + let exists: bool = match token { + Some(tok) => { + let exists = docker_image_exists(DOCKER_USERNAME, "nonexistent", tok).await; + match exists { + Ok(_) => true, + Err(err) => { + println!("{:?}", err); + false + } + } + } + _ => false, + }; + + assert_eq!(exists, false); +} diff --git a/tests/model_user_stack.rs b/tests/model_user_stack.rs index e8ee9b6..57e5f16 100644 --- a/tests/model_user_stack.rs +++ b/tests/model_user_stack.rs @@ -1,29 +1,30 @@ use stacker::forms::stack::StackForm; +use stacker::forms::stack::DockerImage; use stacker::forms::stack::App; use std::fs; use std::collections::HashMap; // Unit Test -#[test] -fn test_deserialize_user_stack_web() { - - let body_str = fs::read_to_string("./tests/web-item.json").unwrap(); - // let form:serde_json::Value = serde_json::from_str(&body_str).unwrap(); - let form:App = serde_json::from_str(&body_str).unwrap(); - println!("{:?}", form); - // { - // Ok(f) => { - // f - // } - // Err(_err) => { - // let msg = format!("Invalid data. {:?}", _err); - // return JsonResponse::::build().bad_request(msg); - // } - // }; - // - // assert_eq!(result, 12); -} +// #[test] +// fn test_deserialize_user_stack_web() { +// +// let body_str = fs::read_to_string("./tests/web-item.json").unwrap(); +// // let form:serde_json::Value = serde_json::from_str(&body_str).unwrap(); +// let form:App = serde_json::from_str(&body_str).unwrap(); +// println!("{:?}", form); +// // { +// // Ok(f) => { +// // f +// // } +// // Err(_err) => { +// // let msg = format!("Invalid data. {:?}", _err); +// // return JsonResponse::::build().bad_request(msg); +// // } +// // }; +// // +// // assert_eq!(result, 12); +// } #[test] fn test_deserialize_user_stack() { @@ -60,3 +61,77 @@ fn test_deserialize_user_stack() { // let form:Vec> = serde_json::from_str(&body_str).unwrap(); // println!("{:?}", form); } + +#[test] +fn test_docker_image_only_name_other_empty() { + let docker_image = DockerImage { + dockerhub_user: Some("".to_string()), + dockerhub_name: Some("mysql".to_string()), + dockerhub_image: Some("".to_string(),) + }; + let output = docker_image.to_string(); + assert_eq!(String::from("mysql:latest"), output); +} + +#[test] +fn test_docker_image_only_name_other_none() { + let docker_image = DockerImage { + dockerhub_user: None, + dockerhub_name: Some("mysql".to_string()), + dockerhub_image: None + }; + let output = docker_image.to_string(); + assert_eq!(String::from("mysql:latest"), output); +} +#[test] +fn test_docker_image_namespace_and_repo() { + let docker_image = DockerImage { + dockerhub_user: Some("trydirect".to_string()), + dockerhub_name: Some("mysql".to_string()), + dockerhub_image: Some("".to_string(),) + }; + let output = docker_image.to_string(); + assert_eq!(String::from("trydirect/mysql:latest"), output); +} + +#[test] +fn test_docker_image_namespace_and_repo_tag() { + let docker_image = DockerImage { + dockerhub_user: Some("trydirect".to_string()), + dockerhub_name: Some("mysql:8.1".to_string()), + dockerhub_image: Some("".to_string(),) + }; + let output = docker_image.to_string(); + assert_eq!(String::from("trydirect/mysql:8.1"), output); +} +#[test] +fn test_docker_image_only_image() { + let docker_image = DockerImage { + dockerhub_user: None, + dockerhub_name: None, + dockerhub_image: Some("trydirect/mysql:stable".to_string(),) + }; + let output = docker_image.to_string(); + assert_eq!(String::from("trydirect/mysql:stable"), output); +} + +#[test] +fn test_docker_image_only_image_other_empty() { + let docker_image = DockerImage { + dockerhub_user: Some("".to_string()), + dockerhub_name: Some("".to_string()), + dockerhub_image: Some("trydirect/mysql:stable".to_string()) + }; + let output = docker_image.to_string(); + assert_eq!(String::from("trydirect/mysql:stable"), output); +} +#[test] +fn test_docker_repo_name_with_tag_other_none() { + let docker_image = DockerImage { + dockerhub_user: None, + dockerhub_name: Some("mysql:stable".to_string()), + dockerhub_image: None + }; + let output = docker_image.to_string(); + assert_eq!(String::from("mysql:stable"), output); +} From 37f8d7a09bcec40f5c5b0db98588615865b7967e Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 13 Jan 2024 23:32:14 +0200 Subject: [PATCH 127/284] issue-auth dctypes --- .../stack/dctypes/advanced_build_step.rs | 23 +++ .../dctypes/advanced_network_settings.rs | 12 ++ .../stack/dctypes/advanced_networks.rs | 13 ++ src/helpers/stack/dctypes/build_args.rs | 16 ++ src/helpers/stack/dctypes/build_step.rs | 9 + src/helpers/stack/dctypes/compose_volume.rs | 25 +++ src/helpers/stack/dctypes/external_volume.rs | 8 + src/helpers/stack/dctypes/labels.rs | 31 +++ src/helpers/stack/dctypes/mod.rs | 195 +++--------------- src/helpers/stack/dctypes/networks.rs | 24 +++ src/helpers/stack/dctypes/tmpfs.rs | 9 + .../stack/dctypes/top_level_volumes.rs | 19 ++ src/helpers/stack/dctypes/ulimit.rs | 8 + src/helpers/stack/dctypes/ulimits.rs | 20 ++ 14 files changed, 243 insertions(+), 169 deletions(-) create mode 100644 src/helpers/stack/dctypes/advanced_build_step.rs create mode 100644 src/helpers/stack/dctypes/advanced_network_settings.rs create mode 100644 src/helpers/stack/dctypes/advanced_networks.rs create mode 100644 src/helpers/stack/dctypes/build_args.rs create mode 100644 src/helpers/stack/dctypes/build_step.rs create mode 100644 src/helpers/stack/dctypes/compose_volume.rs create mode 100644 src/helpers/stack/dctypes/external_volume.rs create mode 100644 src/helpers/stack/dctypes/labels.rs create mode 100644 src/helpers/stack/dctypes/networks.rs create mode 100644 src/helpers/stack/dctypes/tmpfs.rs create mode 100644 src/helpers/stack/dctypes/top_level_volumes.rs create mode 100644 src/helpers/stack/dctypes/ulimit.rs create mode 100644 src/helpers/stack/dctypes/ulimits.rs diff --git a/src/helpers/stack/dctypes/advanced_build_step.rs b/src/helpers/stack/dctypes/advanced_build_step.rs new file mode 100644 index 0000000..c0e6e06 --- /dev/null +++ b/src/helpers/stack/dctypes/advanced_build_step.rs @@ -0,0 +1,23 @@ +use serde::{Deserialize, Serialize}; +use crate::helpers::stack::dctypes::*; + +#[derive(Builder, Clone, Debug, Deserialize, Serialize, Eq, PartialEq, Default)] +#[serde(deny_unknown_fields)] +#[builder(setter(into), default)] +pub struct AdvancedBuildStep { + pub context: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub dockerfile: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub args: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub shm_size: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub target: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub network: Option, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub cache_from: Vec, + #[serde(default, skip_serializing_if = "Labels::is_empty")] + pub labels: Labels, +} diff --git a/src/helpers/stack/dctypes/advanced_network_settings.rs b/src/helpers/stack/dctypes/advanced_network_settings.rs new file mode 100644 index 0000000..730c9cb --- /dev/null +++ b/src/helpers/stack/dctypes/advanced_network_settings.rs @@ -0,0 +1,12 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Default, Serialize, Deserialize, Eq, PartialEq, Hash)] +#[serde(deny_unknown_fields)] +pub struct AdvancedNetworkSettings { + #[serde(skip_serializing_if = "Option::is_none")] + pub ipv4_address: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub ipv6_address: Option, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub aliases: Vec, +} diff --git a/src/helpers/stack/dctypes/advanced_networks.rs b/src/helpers/stack/dctypes/advanced_networks.rs new file mode 100644 index 0000000..d26aba1 --- /dev/null +++ b/src/helpers/stack/dctypes/advanced_networks.rs @@ -0,0 +1,13 @@ +use serde::{Deserialize, Serialize}; +#[cfg(feature = "indexmap")] +use indexmap::IndexMap; +#[cfg(not(feature = "indexmap"))] +use std::collections::HashMap; +use crate::helpers::stack::dctypes::*; + +#[cfg(feature = "indexmap")] +#[derive(Clone, Default, Debug, Serialize, Deserialize, Eq, PartialEq)] +pub struct AdvancedNetworks(pub IndexMap>); +#[cfg(not(feature = "indexmap"))] +#[derive(Clone, Default, Debug, Serialize, Deserialize, Eq, PartialEq)] +pub struct AdvancedNetworks(pub HashMap>); diff --git a/src/helpers/stack/dctypes/build_args.rs b/src/helpers/stack/dctypes/build_args.rs new file mode 100644 index 0000000..8f62966 --- /dev/null +++ b/src/helpers/stack/dctypes/build_args.rs @@ -0,0 +1,16 @@ +use serde::{Deserialize, Serialize}; +#[cfg(feature = "indexmap")] +use indexmap::IndexMap; +#[cfg(not(feature = "indexmap"))] +use std::collections::HashMap; + +#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] +#[serde(untagged)] +pub enum BuildArgs { + Simple(String), + List(Vec), + #[cfg(feature = "indexmap")] + KvPair(IndexMap), + #[cfg(not(feature = "indexmap"))] + KvPair(HashMap), +} diff --git a/src/helpers/stack/dctypes/build_step.rs b/src/helpers/stack/dctypes/build_step.rs new file mode 100644 index 0000000..25a468d --- /dev/null +++ b/src/helpers/stack/dctypes/build_step.rs @@ -0,0 +1,9 @@ +use serde::{Deserialize, Serialize}; +use crate::helpers::stack::dctypes; + +#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] +#[serde(untagged)] +pub enum BuildStep { + Simple(String), + Advanced(dctypes::AdvancedBuildStep), +} diff --git a/src/helpers/stack/dctypes/compose_volume.rs b/src/helpers/stack/dctypes/compose_volume.rs new file mode 100644 index 0000000..4d40b23 --- /dev/null +++ b/src/helpers/stack/dctypes/compose_volume.rs @@ -0,0 +1,25 @@ +use serde::{Deserialize, Serialize}; +use crate::helpers::stack::dctypes::*; +#[cfg(feature = "indexmap")] +use indexmap::IndexMap; +#[cfg(not(feature = "indexmap"))] +use std::collections::HashMap; + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct ComposeVolume { + #[serde(skip_serializing_if = "Option::is_none")] + pub driver: Option, + #[cfg(feature = "indexmap")] + #[serde(default, skip_serializing_if = "IndexMap::is_empty")] + pub driver_opts: IndexMap>, + #[cfg(not(feature = "indexmap"))] + #[serde(default, skip_serializing_if = "HashMap::is_empty")] + pub driver_opts: HashMap>, + #[serde(skip_serializing_if = "Option::is_none")] + pub external: Option, + #[serde(default, skip_serializing_if = "Labels::is_empty")] + pub labels: Labels, + #[serde(skip_serializing_if = "Option::is_none")] + pub name: Option, +} + diff --git a/src/helpers/stack/dctypes/external_volume.rs b/src/helpers/stack/dctypes/external_volume.rs new file mode 100644 index 0000000..ba03e26 --- /dev/null +++ b/src/helpers/stack/dctypes/external_volume.rs @@ -0,0 +1,8 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[serde(untagged)] +pub enum ExternalVolume { + Bool(bool), + Name { name: String }, +} diff --git a/src/helpers/stack/dctypes/labels.rs b/src/helpers/stack/dctypes/labels.rs new file mode 100644 index 0000000..e4296af --- /dev/null +++ b/src/helpers/stack/dctypes/labels.rs @@ -0,0 +1,31 @@ +use serde::{Deserialize, Serialize}; +#[cfg(feature = "indexmap")] +use indexmap::IndexMap; +#[cfg(not(feature = "indexmap"))] +use std::collections::HashMap; + +#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] +#[serde(untagged)] +pub enum Labels { + List(Vec), + #[cfg(feature = "indexmap")] + Map(IndexMap), + #[cfg(not(feature = "indexmap"))] + Map(HashMap), +} + +impl Default for Labels { + fn default() -> Self { + Self::List(Vec::new()) + } +} + +impl Labels { + pub fn is_empty(&self) -> bool { + match self { + Self::List(v) => v.is_empty(), + Self::Map(m) => m.is_empty(), + } + } +} + diff --git a/src/helpers/stack/dctypes/mod.rs b/src/helpers/stack/dctypes/mod.rs index efde67a..ae2fc4c 100644 --- a/src/helpers/stack/dctypes/mod.rs +++ b/src/helpers/stack/dctypes/mod.rs @@ -14,6 +14,19 @@ mod environment; mod extension; mod extension_parse_error; mod services; +mod labels; +mod tmpfs; +mod ulimit; +mod ulimits; +mod networks; +mod build_step; +mod advanced_build_step; +mod build_args; +mod advanced_networks; +mod advanced_network_settings; +mod top_level_volumes; +mod compose_volume; +mod external_volume; pub use port::*; pub use published_port::*; @@ -31,6 +44,19 @@ pub use environment::*; pub use extension::*; pub use extension_parse_error::*; pub use services::*; +pub use labels::*; +pub use tmpfs::*; +pub use ulimit::*; +pub use ulimits::*; +pub use networks::*; +pub use build_step::*; +pub use advanced_build_step::*; +pub use build_args::*; +pub use advanced_networks::*; +pub use advanced_network_settings::*; +pub use top_level_volumes::*; +pub use compose_volume::*; +pub use external_volume::*; use crate::helpers::stack::dctypes; @@ -44,175 +70,6 @@ use std::collections::HashMap; use std::convert::TryFrom; use std::fmt; -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] -#[serde(untagged)] -pub enum Labels { - List(Vec), - #[cfg(feature = "indexmap")] - Map(IndexMap), - #[cfg(not(feature = "indexmap"))] - Map(HashMap), -} - -impl Default for Labels { - fn default() -> Self { - Self::List(Vec::new()) - } -} - -impl Labels { - pub fn is_empty(&self) -> bool { - match self { - Self::List(v) => v.is_empty(), - Self::Map(m) => m.is_empty(), - } - } -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] -#[serde(untagged)] -pub enum Tmpfs { - Simple(String), - List(Vec), -} - -#[cfg(feature = "indexmap")] -#[derive(Clone, Default, Debug, Serialize, Deserialize, Eq, PartialEq)] -pub struct Ulimits(pub IndexMap); -#[cfg(not(feature = "indexmap"))] -#[derive(Clone, Default, Debug, Serialize, Deserialize, Eq, PartialEq)] -pub struct Ulimits(pub HashMap); - -impl Ulimits { - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] -#[serde(untagged)] -pub enum Ulimit { - Single(i64), - SoftHard { soft: i64, hard: i64 }, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] -#[serde(untagged)] -pub enum Networks { - Simple(Vec), - Advanced(AdvancedNetworks), -} - -impl Default for Networks { - fn default() -> Self { - Self::Simple(Vec::new()) - } -} - -impl Networks { - pub fn is_empty(&self) -> bool { - match self { - Self::Simple(n) => n.is_empty(), - Self::Advanced(n) => n.0.is_empty(), - } - } -} - -#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] -#[serde(untagged)] -pub enum BuildStep { - Simple(String), - Advanced(AdvancedBuildStep), -} - -#[derive(Builder, Clone, Debug, Deserialize, Serialize, Eq, PartialEq, Default)] -#[serde(deny_unknown_fields)] -#[builder(setter(into), default)] -pub struct AdvancedBuildStep { - pub context: String, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub dockerfile: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub args: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub shm_size: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub target: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub network: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub cache_from: Vec, - #[serde(default, skip_serializing_if = "Labels::is_empty")] - pub labels: Labels, -} - -#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] -#[serde(untagged)] -pub enum BuildArgs { - Simple(String), - List(Vec), - #[cfg(feature = "indexmap")] - KvPair(IndexMap), - #[cfg(not(feature = "indexmap"))] - KvPair(HashMap), -} - -#[cfg(feature = "indexmap")] -#[derive(Clone, Default, Debug, Serialize, Deserialize, Eq, PartialEq)] -pub struct AdvancedNetworks(pub IndexMap>); -#[cfg(not(feature = "indexmap"))] -#[derive(Clone, Default, Debug, Serialize, Deserialize, Eq, PartialEq)] -pub struct AdvancedNetworks(pub HashMap>); - -#[derive(Clone, Debug, Default, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(deny_unknown_fields)] -pub struct AdvancedNetworkSettings { - #[serde(skip_serializing_if = "Option::is_none")] - pub ipv4_address: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub ipv6_address: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub aliases: Vec, -} - -#[cfg(feature = "indexmap")] -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] -pub struct TopLevelVolumes(pub IndexMap>); -#[cfg(not(feature = "indexmap"))] -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] -pub struct TopLevelVolumes(pub HashMap>); - -impl TopLevelVolumes { - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -pub struct ComposeVolume { - #[serde(skip_serializing_if = "Option::is_none")] - pub driver: Option, - #[cfg(feature = "indexmap")] - #[serde(default, skip_serializing_if = "IndexMap::is_empty")] - pub driver_opts: IndexMap>, - #[cfg(not(feature = "indexmap"))] - #[serde(default, skip_serializing_if = "HashMap::is_empty")] - pub driver_opts: HashMap>, - #[serde(skip_serializing_if = "Option::is_none")] - pub external: Option, - #[serde(default, skip_serializing_if = "Labels::is_empty")] - pub labels: Labels, - #[serde(skip_serializing_if = "Option::is_none")] - pub name: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -#[serde(untagged)] -pub enum ExternalVolume { - Bool(bool), - Name { name: String }, -} - #[cfg(feature = "indexmap")] #[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] pub struct ComposeNetworks(pub IndexMap>); diff --git a/src/helpers/stack/dctypes/networks.rs b/src/helpers/stack/dctypes/networks.rs new file mode 100644 index 0000000..bbcfdb1 --- /dev/null +++ b/src/helpers/stack/dctypes/networks.rs @@ -0,0 +1,24 @@ +use serde::{Deserialize, Serialize}; +use crate::helpers::stack::dctypes; + +#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] +#[serde(untagged)] +pub enum Networks { + Simple(Vec), + Advanced(dctypes::AdvancedNetworks), +} + +impl Default for Networks { + fn default() -> Self { + Self::Simple(Vec::new()) + } +} + +impl Networks { + pub fn is_empty(&self) -> bool { + match self { + Self::Simple(n) => n.is_empty(), + Self::Advanced(n) => n.0.is_empty(), + } + } +} diff --git a/src/helpers/stack/dctypes/tmpfs.rs b/src/helpers/stack/dctypes/tmpfs.rs new file mode 100644 index 0000000..1bea9b6 --- /dev/null +++ b/src/helpers/stack/dctypes/tmpfs.rs @@ -0,0 +1,9 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] +#[serde(untagged)] +pub enum Tmpfs { + Simple(String), + List(Vec), +} + diff --git a/src/helpers/stack/dctypes/top_level_volumes.rs b/src/helpers/stack/dctypes/top_level_volumes.rs new file mode 100644 index 0000000..7216953 --- /dev/null +++ b/src/helpers/stack/dctypes/top_level_volumes.rs @@ -0,0 +1,19 @@ +use serde::{Deserialize, Serialize}; +#[cfg(feature = "indexmap")] +use indexmap::IndexMap; +#[cfg(not(feature = "indexmap"))] +use std::collections::HashMap; +use crate::helpers::stack::dctypes::*; + +#[cfg(feature = "indexmap")] +#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] +pub struct TopLevelVolumes(pub IndexMap>); +#[cfg(not(feature = "indexmap"))] +#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] +pub struct TopLevelVolumes(pub HashMap>); + +impl TopLevelVolumes { + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } +} diff --git a/src/helpers/stack/dctypes/ulimit.rs b/src/helpers/stack/dctypes/ulimit.rs new file mode 100644 index 0000000..6589931 --- /dev/null +++ b/src/helpers/stack/dctypes/ulimit.rs @@ -0,0 +1,8 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] +#[serde(untagged)] +pub enum Ulimit { + Single(i64), + SoftHard { soft: i64, hard: i64 }, +} diff --git a/src/helpers/stack/dctypes/ulimits.rs b/src/helpers/stack/dctypes/ulimits.rs new file mode 100644 index 0000000..721eaf9 --- /dev/null +++ b/src/helpers/stack/dctypes/ulimits.rs @@ -0,0 +1,20 @@ +use serde::{Deserialize, Serialize}; +#[cfg(feature = "indexmap")] +use indexmap::IndexMap; +#[cfg(not(feature = "indexmap"))] +use std::collections::HashMap; +use crate::helpers::stack::dctypes; + +#[cfg(feature = "indexmap")] +#[derive(Clone, Default, Debug, Serialize, Deserialize, Eq, PartialEq)] +pub struct Ulimits(pub IndexMap); +#[cfg(not(feature = "indexmap"))] +#[derive(Clone, Default, Debug, Serialize, Deserialize, Eq, PartialEq)] +pub struct Ulimits(pub HashMap); + +impl Ulimits { + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } +} + From c95fe1ffee0a3f17b3e6e3e478bb23a671b005e0 Mon Sep 17 00:00:00 2001 From: petru Date: Sun, 14 Jan 2024 09:50:24 +0200 Subject: [PATCH 128/284] issue-auth dctypes --- src/helpers/stack/dctypes/compose.rs | 20 ++--- src/helpers/stack/dctypes/compose_network.rs | 9 ++ .../compose_network_setting_details.rs | 7 ++ src/helpers/stack/dctypes/compose_networks.rs | 19 ++++ .../dctypes/external_network_setting_bool.rs | 5 ++ src/helpers/stack/dctypes/ipam.rs | 12 +++ src/helpers/stack/dctypes/ipam_config.rs | 9 ++ src/helpers/stack/dctypes/mod.rs | 88 +++---------------- src/helpers/stack/dctypes/network_settings.rs | 29 ++++++ 9 files changed, 114 insertions(+), 84 deletions(-) create mode 100644 src/helpers/stack/dctypes/compose_network.rs create mode 100644 src/helpers/stack/dctypes/compose_network_setting_details.rs create mode 100644 src/helpers/stack/dctypes/compose_networks.rs create mode 100644 src/helpers/stack/dctypes/external_network_setting_bool.rs create mode 100644 src/helpers/stack/dctypes/ipam.rs create mode 100644 src/helpers/stack/dctypes/ipam_config.rs create mode 100644 src/helpers/stack/dctypes/network_settings.rs diff --git a/src/helpers/stack/dctypes/compose.rs b/src/helpers/stack/dctypes/compose.rs index 82372d6..46d43c2 100644 --- a/src/helpers/stack/dctypes/compose.rs +++ b/src/helpers/stack/dctypes/compose.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use crate::helpers::stack::dctypes; +use crate::helpers::stack::dctypes::*; #[cfg(feature = "indexmap")] use indexmap::IndexMap; use serde_yaml::Value; @@ -8,18 +8,18 @@ use serde_yaml::Value; pub struct Compose { #[serde(skip_serializing_if = "Option::is_none")] pub version: Option, - #[serde(default, skip_serializing_if = "dctypes::Services::is_empty")] - pub services: dctypes::Services, - #[serde(default, skip_serializing_if = "dctypes::TopLevelVolumes::is_empty")] - pub volumes: dctypes::TopLevelVolumes, - #[serde(default, skip_serializing_if = "dctypes::ComposeNetworks::is_empty")] - pub networks: dctypes::ComposeNetworks, + #[serde(default, skip_serializing_if = "Services::is_empty")] + pub services: Services, + #[serde(default, skip_serializing_if = "TopLevelVolumes::is_empty")] + pub volumes: TopLevelVolumes, + #[serde(default, skip_serializing_if = "ComposeNetworks::is_empty")] + pub networks: ComposeNetworks, #[serde(skip_serializing_if = "Option::is_none")] - pub service: Option, + pub service: Option, #[cfg(feature = "indexmap")] #[serde(flatten, skip_serializing_if = "IndexMap::is_empty")] - pub extensions: IndexMap, + pub extensions: IndexMap, #[cfg(not(feature = "indexmap"))] #[serde(flatten, skip_serializing_if = "HashMap::is_empty")] - pub extensions: HashMap, + pub extensions: HashMap, } diff --git a/src/helpers/stack/dctypes/compose_network.rs b/src/helpers/stack/dctypes/compose_network.rs new file mode 100644 index 0000000..da36434 --- /dev/null +++ b/src/helpers/stack/dctypes/compose_network.rs @@ -0,0 +1,9 @@ +use serde::{Deserialize, Serialize}; +use crate::helpers::stack::dctypes::*; + +#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] +#[serde(untagged)] +pub enum ComposeNetwork { + Detailed(ComposeNetworkSettingDetails), + Bool(bool), +} diff --git a/src/helpers/stack/dctypes/compose_network_setting_details.rs b/src/helpers/stack/dctypes/compose_network_setting_details.rs new file mode 100644 index 0000000..59d0348 --- /dev/null +++ b/src/helpers/stack/dctypes/compose_network_setting_details.rs @@ -0,0 +1,7 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] +#[serde(deny_unknown_fields)] +pub struct ComposeNetworkSettingDetails { + pub name: String, +} diff --git a/src/helpers/stack/dctypes/compose_networks.rs b/src/helpers/stack/dctypes/compose_networks.rs new file mode 100644 index 0000000..f1374f0 --- /dev/null +++ b/src/helpers/stack/dctypes/compose_networks.rs @@ -0,0 +1,19 @@ +#[cfg(feature = "indexmap")] +use indexmap::IndexMap; +#[cfg(not(feature = "indexmap"))] +use std::collections::HashMap; +use serde::{Deserialize, Serialize}; +use crate::helpers::stack::dctypes::*; + +#[cfg(feature = "indexmap")] +#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] +pub struct ComposeNetworks(pub IndexMap>); +#[cfg(not(feature = "indexmap"))] +#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] +pub struct ComposeNetworks(pub HashMap>); + +impl ComposeNetworks { + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } +} diff --git a/src/helpers/stack/dctypes/external_network_setting_bool.rs b/src/helpers/stack/dctypes/external_network_setting_bool.rs new file mode 100644 index 0000000..1d1ad3d --- /dev/null +++ b/src/helpers/stack/dctypes/external_network_setting_bool.rs @@ -0,0 +1,5 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] +#[serde(deny_unknown_fields)] +pub struct ExternalNetworkSettingBool(bool); diff --git a/src/helpers/stack/dctypes/ipam.rs b/src/helpers/stack/dctypes/ipam.rs new file mode 100644 index 0000000..592c2a6 --- /dev/null +++ b/src/helpers/stack/dctypes/ipam.rs @@ -0,0 +1,12 @@ +use serde::{Deserialize, Serialize}; +use crate::helpers::stack::dctypes::*; + +#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] +#[serde(deny_unknown_fields)] +pub struct Ipam { + #[serde(skip_serializing_if = "Option::is_none")] + pub driver: Option, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub config: Vec, +} + diff --git a/src/helpers/stack/dctypes/ipam_config.rs b/src/helpers/stack/dctypes/ipam_config.rs new file mode 100644 index 0000000..f40c2f5 --- /dev/null +++ b/src/helpers/stack/dctypes/ipam_config.rs @@ -0,0 +1,9 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] +#[serde(deny_unknown_fields)] +pub struct IpamConfig { + pub subnet: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub gateway: Option, +} diff --git a/src/helpers/stack/dctypes/mod.rs b/src/helpers/stack/dctypes/mod.rs index ae2fc4c..66bda09 100644 --- a/src/helpers/stack/dctypes/mod.rs +++ b/src/helpers/stack/dctypes/mod.rs @@ -27,6 +27,13 @@ mod advanced_network_settings; mod top_level_volumes; mod compose_volume; mod external_volume; +mod compose_network; +mod compose_networks; +mod compose_network_setting_details; +mod external_network_setting_bool; +mod network_settings; +mod ipam; +mod ipam_config; pub use port::*; pub use published_port::*; @@ -57,6 +64,13 @@ pub use advanced_network_settings::*; pub use top_level_volumes::*; pub use compose_volume::*; pub use external_volume::*; +pub use compose_networks::*; +pub use compose_network::*; +pub use compose_network_setting_details::*; +pub use external_network_setting_bool::*; +pub use network_settings::*; +pub use ipam::*; +pub use ipam_config::*; use crate::helpers::stack::dctypes; @@ -70,80 +84,6 @@ use std::collections::HashMap; use std::convert::TryFrom; use std::fmt; -#[cfg(feature = "indexmap")] -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] -pub struct ComposeNetworks(pub IndexMap>); - -#[cfg(not(feature = "indexmap"))] -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] -pub struct ComposeNetworks(pub HashMap>); - -impl ComposeNetworks { - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(untagged)] -pub enum ComposeNetwork { - Detailed(ComposeNetworkSettingDetails), - Bool(bool), -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(deny_unknown_fields)] -pub struct ComposeNetworkSettingDetails { - pub name: String, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(deny_unknown_fields)] -pub struct ExternalNetworkSettingBool(bool); - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)] -#[serde(deny_unknown_fields)] -pub struct NetworkSettings { - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub attachable: bool, - #[serde(skip_serializing_if = "Option::is_none")] - pub driver: Option, - #[cfg(feature = "indexmap")] - #[serde(default, skip_serializing_if = "IndexMap::is_empty")] - pub driver_opts: IndexMap>, - #[cfg(not(feature = "indexmap"))] - #[serde(default, skip_serializing_if = "HashMap::is_empty")] - pub driver_opts: HashMap>, - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub enable_ipv6: bool, - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub internal: bool, - #[serde(skip_serializing_if = "Option::is_none")] - pub external: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub ipam: Option, - #[serde(default, skip_serializing_if = "Labels::is_empty")] - pub labels: Labels, - #[serde(skip_serializing_if = "Option::is_none")] - pub name: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(deny_unknown_fields)] -pub struct Ipam { - #[serde(skip_serializing_if = "Option::is_none")] - pub driver: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub config: Vec, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(deny_unknown_fields)] -pub struct IpamConfig { - pub subnet: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub gateway: Option, -} #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)] #[serde(deny_unknown_fields)] diff --git a/src/helpers/stack/dctypes/network_settings.rs b/src/helpers/stack/dctypes/network_settings.rs new file mode 100644 index 0000000..9c45bc1 --- /dev/null +++ b/src/helpers/stack/dctypes/network_settings.rs @@ -0,0 +1,29 @@ +use serde::{Deserialize, Serialize}; +use crate::helpers::stack::dctypes::*; + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)] +#[serde(deny_unknown_fields)] +pub struct NetworkSettings { + #[serde(default, skip_serializing_if = "std::ops::Not::not")] + pub attachable: bool, + #[serde(skip_serializing_if = "Option::is_none")] + pub driver: Option, + #[cfg(feature = "indexmap")] + #[serde(default, skip_serializing_if = "IndexMap::is_empty")] + pub driver_opts: IndexMap>, + #[cfg(not(feature = "indexmap"))] + #[serde(default, skip_serializing_if = "HashMap::is_empty")] + pub driver_opts: HashMap>, + #[serde(default, skip_serializing_if = "std::ops::Not::not")] + pub enable_ipv6: bool, + #[serde(default, skip_serializing_if = "std::ops::Not::not")] + pub internal: bool, + #[serde(skip_serializing_if = "Option::is_none")] + pub external: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub ipam: Option, + #[serde(default, skip_serializing_if = "Labels::is_empty")] + pub labels: Labels, + #[serde(skip_serializing_if = "Option::is_none")] + pub name: Option, +} From 2cb0723f6eedc1212c25d310cb43a5399c2539a5 Mon Sep 17 00:00:00 2001 From: vsilent Date: Mon, 15 Jan 2024 12:54:30 +0200 Subject: [PATCH 129/284] environment variables structure is changed, service _id type is changed to String (reason: simplifies front end functionality) --- configuration.yaml | 16 +++++ docker-compose.yml | 2 +- src/forms/stack.rs | 74 +++++++++++++---------- src/helpers/stack/builder.rs | 12 ++-- tests/custom-stack-payload-11.json | 1 - tests/custom-stack-payload-12.json | 1 - tests/custom-stack-payload-2.json | 1 - tests/custom-stack-payload-3.json | 1 - tests/custom-stack-payload-4.json | 1 - tests/custom-stack-payload-5.json | 1 - tests/custom-stack-payload-6.json | 1 - tests/custom-stack-payload-7.json | 1 - tests/custom-stack-payload-8.json | 1 - tests/custom-stack-payload-9.json | 1 - tests/custom-stack-payload-singleapp.json | 1 - tests/custom-stack-payload.json | 5 +- tests/model_user_stack.rs | 21 ++++--- 17 files changed, 80 insertions(+), 61 deletions(-) create mode 100644 configuration.yaml delete mode 100644 tests/custom-stack-payload-11.json delete mode 100644 tests/custom-stack-payload-12.json delete mode 100644 tests/custom-stack-payload-2.json delete mode 100644 tests/custom-stack-payload-3.json delete mode 100644 tests/custom-stack-payload-4.json delete mode 100644 tests/custom-stack-payload-5.json delete mode 100644 tests/custom-stack-payload-6.json delete mode 100644 tests/custom-stack-payload-7.json delete mode 100644 tests/custom-stack-payload-8.json delete mode 100644 tests/custom-stack-payload-9.json delete mode 100644 tests/custom-stack-payload-singleapp.json diff --git a/configuration.yaml b/configuration.yaml new file mode 100644 index 0000000..2e5d296 --- /dev/null +++ b/configuration.yaml @@ -0,0 +1,16 @@ +app_host: 127.0.0.1 +app_port: 8000 +auth_url: https://dev.try.direct/server/user/oauth_server/api/me +max_clients_number: 2 +database: + host: 127.0.0.1 + port: 5432 + username: postgres + password: postgres + database_name: stacker + +amqp: + host: 51.15.74.139 + port: 5672 + username: guest + password: rabbitdev2023rabbitmqctl@@ diff --git a/docker-compose.yml b/docker-compose.yml index 9cba7b2..9a66dde 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,7 @@ volumes: services: stacker: - image: trydirect/stacker:0.0.5 + image: trydirect/stacker:0.0.6 build: . container_name: stacker restart: always diff --git a/src/forms/stack.rs b/src/forms/stack.rs index 0459e66..205aae3 100644 --- a/src/forms/stack.rs +++ b/src/forms/stack.rs @@ -4,6 +4,7 @@ use serde_valid::Validate; use std::collections::HashMap; use std::fmt; use crate::helpers::{login, docker_image_exists}; +use tokio::runtime::Runtime; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Role { @@ -28,46 +29,51 @@ pub struct Requirements { pub ram_size: Option, } -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Port { + #[validate(pattern = r"^\d+$")] pub host_port: Option, + #[validate(pattern = r"^\d+$")] pub container_port: Option, + #[validate(enumerate("tcp", "udp"))] + pub protocol: Option } -async fn validate_dockerhub_image( - dockerhub_user: &Option, - dockerhub_password: &Option, - dockerhub_name: &Option) -> Result<(), serde_valid::validation::Error> { +fn validate_dockerhub_image(docker_image: DockerImage) -> Result<(), serde_valid::validation::Error> { + + // Create the runtime + let rt = Runtime::new().unwrap(); + + // Spawn a blocking function onto the runtime + rt.block_on(async { + let result = login( + docker_image.dockerhub_user.clone().unwrap_or("".to_string()).as_ref(), + docker_image.dockerhub_password.clone().unwrap_or("".to_string()).as_ref() + ) + .await + .map_err(|err| serde_valid::validation::Error::Custom(format!("{:?}", err)))?; - let result = login( - dockerhub_user.clone().unwrap_or("".to_string()).as_ref(), - dockerhub_password.clone().unwrap_or("".to_string()).as_ref() - ).await; + match result.token { + None => { + return Err(serde_valid::validation::Error::Custom( + "Could not access docker image repository, please check credentials.".to_owned(), + )); + }, + Some(tok) => { - let exists: bool = match result.unwrap().token { - Some(tok) => { - let exists = docker_image_exists( - dockerhub_user.clone().unwrap().as_str(), - dockerhub_name.clone().unwrap().as_str(), tok).await; - match exists { - Ok(_) => true, - Err(err) => { - println!("{:?}", err); - false - } + tracing::debug!("We were able to login hub.docker.com!"); + docker_image_exists( + docker_image.dockerhub_user.clone().unwrap().as_str(), + docker_image.dockerhub_name.clone().unwrap().as_str(), tok) + .await + .map_err(|err| serde_valid::validation::Error::Custom("Not exists".to_string())) + .map(|_| ()) } } - _ => false, - }; - if !exists { - return Err(serde_valid::validation::Error::Custom( - "Could not access docker image repository, please check credentials.".to_owned(), - )); - } - Ok(()) + }) } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -#[validate(custom(|s| validate_dockerhub_image(dockerhub_user,dockerhub_name, dockerhub_password)))] +#[validate(custom(|docker_image| validate_dockerhub_image(docker_image)))] pub struct DockerImage { #[validate(min_length = 3)] #[validate(max_length = 50)] @@ -238,7 +244,7 @@ pub struct App { #[validate(max_length = 255)] pub etag: Option, #[serde(rename = "_id")] - pub id: u32, + pub id: String, #[serde(rename = "_created")] pub created: Option, #[serde(rename = "_updated")] @@ -295,9 +301,15 @@ pub struct App { pub ports: Option>, } +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct EnvVar { + pub(crate) key: String, + pub(crate) value: String +} + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Environment { - pub(crate) environment: Option>>, + pub(crate) environment: Option>, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Volume { diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 3df222b..77b648c 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -138,14 +138,12 @@ impl TryIntoService for App { .collect(); let mut envs = IndexMap::new(); - for item in self.environment.environment.clone().unwrap_or_default() { - let items = item - .into_iter() - .map(|(k, v)| (k, Some(SingleValue::String(v.clone())))) - .collect::>(); + let items = self.environment.environment.clone().unwrap_or_default() + .into_iter() + .map(|env_var| (env_var.key, Some(SingleValue::String(env_var.value.clone())))) + .collect::>(); - envs.extend(items); - } + envs.extend(items); service.networks = networks; service.ports = Ports::Long(ports); diff --git a/tests/custom-stack-payload-11.json b/tests/custom-stack-payload-11.json deleted file mode 100644 index 811f74f..0000000 --- a/tests/custom-stack-payload-11.json +++ /dev/null @@ -1 +0,0 @@ -{"commonDomain":"justates222t.com","domainList":{},"region":"fsn1","zone":null,"server":"cx21","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":["portainer_ce_feature"],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":true,"disk_type":"pd-standart","cloud_token":"***********","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"web":[{"_etag":null,"_id":180,"_created":"2021-12-17T08:11:40.875486","_updated":"2023-11-21T17:37:24.594545","name":"Airflow","code":"airflow","role":["airflow"],"type":"web","default":true,"popularity":null,"descr":null,"ports":{"private":["31"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":150,"height":150,"image":"7f41d873-2de5-4c6e-a037-42eeff572db6.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":"

Airflow description

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"airflow","form":null,"category":[null],"group":[],"versions":[{"_id":425,"name":"Airflow","version":"2.7.3","update_status":"published","tag":"latest"},{"_id":426,"name":"Airflow","version":"2.7.1-unstable","update_status":"published","tag":"stable"}],"links":[],"domain":"latestports.com","sharedPorts":[{"host_port":"5000","container_port":"5000"}],"main":true,"version":{"_id":426,"name":"Airflow","version":"2.7.1-unstable","update_status":"published","tag":"stable"},"environment":[{"ENV_VAR1":"ENV_VAR1_VALUE"}, {"ENV_VAR2":"ENV_VAR1_VALUe2"}],"network":["testnetwork"],"restart":"always","volumes":[{"host_path":"./airflow/host/path/","container_path":"/airflow/container/path"}, {"host_path":"./airflow/host/path2/","container_path":"/airflow/container/path2"}, {"host_path":"airflow","container_path":"/airflow/named/volume/path"}]},{"category":[{"name":"integrated_features"}],"name":"CustomNginx","code":"customnginx","domain":"customnginx.latestports.com","sharedPorts":[{"host_port":"80","container_port":"8080"},{"host_port":"443","container_port":"8443"}],"versions":[],"custom":true,"type":"web","main":false,"_id":0,"dockerhub_user":"trydirect","dockerhub_name":"nginx","disk_size":"0.9Gb","ram_size":"1.3Gb","cpu":"0.3","volumes":[{"host_path":"./host/path","container_path":"/container/path"}, {"host_path": "namedvolume", "container_path": "/container/path/to/"}],"environment":[{"CUSTOM_NGINX_ENV_VAR1":"CUSTOM_NGINX_ENV_VAR1_VALUE"},{"CUSTOM_NGINX_VAR2": "CUSTOM_NGINX_VAR_VALUE2"}, {"CUSTOM_NGINX_ENV_VAR3":"CUSTOM_NGINX_ENV_VAR1_VALUE3"},{"CUSTOM_NGINX_VAR4": "CUSTOM_NGINX_VAR_VALUE4"}],"network":["testnetwork"],"restart":"always"}],"feature":[{"_etag":null,"_id":198,"_created":"2022-04-27T14:10:27.280327","_updated":"2023-08-03T08:24:18.958721","name":"Portainer CE Feature","code":"portainer_ce_feature","role":["portainer-ce-feature"],"type":"feature","default":null,"popularity":null,"descr":null,"ports":{"public":["9000","8000"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":1138,"height":1138,"image":"08589075-44e6-430e-98a5-f9dcf711e054.svg"},"dark":{}},"category_id":2,"parent_app_id":null,"full_description":null,"description":"

Portainer is a lightweight management UI which allows you to easily manage your different Docker environments (Docker hosts or Swarm clusters)

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.6","ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"portainer-ce-feature","form":null,"category":[{"name":"integrated_features"}],"group":[],"versions":[{"_id":456,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"}],"links":[],"version":{"_id":456,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"},"sharedPorts":[{"host_port":"9000","container_port":"9000"}],"environment":[{"PORTAINER_ENV_VAR1":"PORTAINER_ENV_VAR1_VALUE"}],"volumes":[{"host_path":"/portainer/test/path","container_path":"/portainer/test/path"}],"network":["testnetwork"],"restart":"always"}],"service":[{"_etag":null,"_id":24,"_created":"2020-06-19T13:07:24.228389","_updated":"2023-11-23T10:18:28.095813","name":"PostgreSQL","code":"postgres","role":["postgres"],"type":"service","default":null,"popularity":null,"descr":null,"ports":{"private":["5432"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":576,"height":594,"image":"fd23f54c-e250-4228-8d56-7e5d93ffb925.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":null,"plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"postgres","form":null,"category":[null],"group":[{"_etag":null,"_id":12,"_created":null,"_updated":null,"name":"Database","code":"database"}],"versions":[{"_id":458,"name":"15","version":"15","update_status":"published","tag":"15"},{"_id":288,"name":"10.22","version":"10.22","update_status":"published","tag":"10.22"},{"_id":303,"name":"13.8","version":"13.8","update_status":"published","tag":"13.8"},{"_id":266,"name":"11","version":"11","update_status":"published","tag":"11"},{"_id":267,"name":"12.12","version":"12.12","update_status":"published","tag":"12.12"},{"_id":38,"name":"14.5","version":"14.5","update_status":"published","tag":"14.5"},{"_id":596,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"}],"links":[],"domain":"","sharedPorts":[{"host_port":"5432","container_port":"5432"}],"main":false,"version":{"_id":596,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"},"environment":[{"POSTGRES_ENV_VAR1":"POSTGRES_ENV_VAR1_VALUE"},{"POSTGRES_ENV_VAR2":"POSTGRES_ENV_VAR2_VALUE"}],"network":["testnetwork"],"restart":"always","volumes":[{"host_path":"./pg.conf","container_path":"/etc/postgres/pg.conf"}]}],"servers_count":3,"project_name":"LatestPorts","custom_stack_code":"latestports","project_git_url":"https://github.com/latestports","custom_stack_category":[],"networks":["testnetwork","testnetwork2"]}} \ No newline at end of file diff --git a/tests/custom-stack-payload-12.json b/tests/custom-stack-payload-12.json deleted file mode 100644 index d405ff4..0000000 --- a/tests/custom-stack-payload-12.json +++ /dev/null @@ -1 +0,0 @@ -{"commonDomain":"justates222tee.com","domainList":{},"region":"fsn1","zone":null,"server":"cx21","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":["portainer_ce_feature"],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":true,"disk_type":"pd-standart","cloud_token":"***********","provider":"htz","stack_code":"custom-stack-2","selected_plan":"plan-individual-monthly","custom":{"web":[{"_etag":null,"_id":180,"_created":"2021-12-17T08:11:40.875486","_updated":"2023-11-21T17:37:24.594545","name":"Airflow","code":"airflow","role":["airflow"],"type":"web","default":true,"popularity":null,"descr":null,"ports":{"private":["31"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":150,"height":150,"image":"7f41d873-2de5-4c6e-a037-42eeff572db6.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":"

Airflow description

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"airflow","form":null,"category":[null],"group":[],"versions":[{"_id":425,"name":"Airflow","version":"2.7.3","update_status":"published","tag":"latest"},{"_id":426,"name":"Airflow","version":"2.7.1-unstable","update_status":"published","tag":"stable"}],"links":[],"domain":"latestports.com","sharedPorts":[{"host_port":"5000","container_port":"5000"}],"main":true,"version":{"_id":426,"name":"Airflow","version":"2.7.1-unstable","update_status":"published","tag":"stable"},"environment":[{"ENV_VAR1":"ENV_VAR1_VALUE"}, {"ENV_VAR2":"ENV_VAR1_VALUe2"}],"network":["testnetwork"],"restart":"always","volumes":[{"host_path":"./airflow/host/path/","container_path":"/airflow/container/path"}, {"host_path":"./airflow/host/path2/","container_path":"/airflow/container/path2"}, {"host_path":"airflow","container_path":"/airflow/named/volume/path"}]},{"category":[{"name":"integrated_features"}],"name":"CustomNginx","code":"customnginx","domain":"customnginx.latestports.com","sharedPorts":[{"host_port":"80","container_port":"8080"},{"host_port":"443","container_port":"8443"}],"versions":[],"custom":true,"type":"web","main":false,"_id":0,"dockerhub_user":"trydirect","dockerhub_name":"nginx","disk_size":"0.9Gb","ram_size":"1.3Gb","cpu":"0.3","volumes":[{"host_path":"./host/path","container_path":"/container/path"}, {"host_path": "namedvolume", "container_path": "/container/path/to/"}],"environment":[{"CUSTOM_NGINX_ENV_VAR1":"CUSTOM_NGINX_ENV_VAR1_VALUE"},{"CUSTOM_NGINX_VAR2": "CUSTOM_NGINX_VAR_VALUE2"}, {"CUSTOM_NGINX_ENV_VAR3":"CUSTOM_NGINX_ENV_VAR1_VALUE3"},{"CUSTOM_NGINX_VAR4": "CUSTOM_NGINX_VAR_VALUE4"}],"network":["testnetwork"],"restart":"always"}],"feature":[{"_etag":null,"_id":198,"_created":"2022-04-27T14:10:27.280327","_updated":"2023-08-03T08:24:18.958721","name":"Portainer CE Feature","code":"portainer_ce_feature","role":["portainer-ce-feature"],"type":"feature","default":null,"popularity":null,"descr":null,"ports":{"public":["9000","8000"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":1138,"height":1138,"image":"08589075-44e6-430e-98a5-f9dcf711e054.svg"},"dark":{}},"category_id":2,"parent_app_id":null,"full_description":null,"description":"

Portainer is a lightweight management UI which allows you to easily manage your different Docker environments (Docker hosts or Swarm clusters)

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.6","ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"portainer-ce-feature","form":null,"category":[{"name":"integrated_features"}],"group":[],"versions":[{"_id":456,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"}],"links":[],"version":{"_id":456,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"},"sharedPorts":[{"host_port":"9000","container_port":"9000"}],"environment":[{"PORTAINER_ENV_VAR1":"PORTAINER_ENV_VAR1_VALUE"}],"volumes":[{"host_path":"/portainer/test/path","container_path":"/portainer/test/path"}],"network":["testnetwork"],"restart":"always"}],"service":[{"_etag":null,"_id":24,"_created":"2020-06-19T13:07:24.228389","_updated":"2023-11-23T10:18:28.095813","name":"PostgreSQL","code":"postgres","role":["postgres"],"type":"service","default":null,"popularity":null,"descr":null,"ports":{"private":["5432"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":576,"height":594,"image":"fd23f54c-e250-4228-8d56-7e5d93ffb925.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":null,"plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"postgres","form":null,"category":[null],"group":[{"_etag":null,"_id":12,"_created":null,"_updated":null,"name":"Database","code":"database"}],"versions":[{"_id":458,"name":"15","version":"15","update_status":"published","tag":"15"},{"_id":288,"name":"10.22","version":"10.22","update_status":"published","tag":"10.22"},{"_id":303,"name":"13.8","version":"13.8","update_status":"published","tag":"13.8"},{"_id":266,"name":"11","version":"11","update_status":"published","tag":"11"},{"_id":267,"name":"12.12","version":"12.12","update_status":"published","tag":"12.12"},{"_id":38,"name":"14.5","version":"14.5","update_status":"published","tag":"14.5"},{"_id":596,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"}],"links":[],"domain":"","sharedPorts":[{"host_port":"5432","container_port":"5432"}],"main":false,"version":{"_id":596,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"},"environment":[{"POSTGRES_ENV_VAR1":"POSTGRES_ENV_VAR1_VALUE"},{"POSTGRES_ENV_VAR2":"POSTGRES_ENV_VAR2_VALUE"}],"network":["testnetwork"],"restart":"always","volumes":[{"host_path":"./pg.conf","container_path":"/etc/postgres/pg.conf"}]}],"servers_count":3,"project_name":"DockerHubCheck1","custom_stack_code":"hubcheck","project_git_url":"https://github.com/latestports","custom_stack_category":[],"networks":["testnetwork","testnetwork2"]}} \ No newline at end of file diff --git a/tests/custom-stack-payload-2.json b/tests/custom-stack-payload-2.json deleted file mode 100644 index e64ec97..0000000 --- a/tests/custom-stack-payload-2.json +++ /dev/null @@ -1 +0,0 @@ -{"commonDomain":"","domainList":{},"region":"fsn1","zone":null,"server":"cx21","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":[],"extended_features":[],"subscriptions":["stack_migration"],"save_token":false,"cloud_token":"r6LAjqrynVt7pUwctVkzBlJmKjLOCxJIWjZFMLTkPYCCB4rsgphhEVhiL4DuO757","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"web":[{"name":"Smarty Bot","code":"smarty-bot","domain":"smartybot.xyz","sharedPorts":["8000"],"versions":[],"custom":true,"type":"web","main":true,"_id":"lltkpq6p347kystct","dockerhub_user":"trydirect","dockerhub_name":"smarty-bot","url_app":"smartybot.xyz","url_git":"https://github.com/vsilent/smarty.git","disk_size":"1Gb","ram_size":"1Gb","cpu":1}],"feature":[{"_etag":null,"_id":198,"_created":"2022-04-27T14:10:27.280327","_updated":"2023-08-03T08:24:18.958721","name":"Portainer CE Feature","code":"portainer_ce_feature","role":["portainer-ce-feature"],"type":"feature","default":null,"popularity":null,"descr":null,"ports":{"public":["9000","8000"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":1138,"height":1138,"image":"08589075-44e6-430e-98a5-f9dcf711e054.svg"},"dark":{}},"category_id":2,"parent_app_id":null,"full_description":null,"description":"

Portainer is a lightweight management UI which allows you to easily manage your different Docker environments (Docker hosts or Swarm clusters)

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.6","ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"portainer-ce-feature","versions":[{"_etag":null,"_id":456,"_created":"2022-04-25T12:44:30.964547","_updated":"2023-03-17T13:46:51.433539","app_id":198,"name":"latest","version":"latest","update_status":"published","tag":"latest"}],"domain":"","sharedPorts":["9000"],"main":true,"version":{"_etag":null,"_id":456,"_created":"2022-04-25T12:44:30.964547","_updated":"2023-03-17T13:46:51.433539","app_id":198,"name":"latest","version":"latest","update_status":"published","tag":"latest"}}],"service":[{"_etag":null,"_id":230,"_created":"2023-05-24T12:51:52.108972","_updated":"2023-08-04T12:18:34.670194","name":"pgrst","code":"pgrst","role":null,"type":"service","default":null,"popularity":null,"descr":null,"ports":null,"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":null,"category_id":null,"parent_app_id":null,"full_description":null,"description":"

PostgREST description

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"1","ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"pgrst","versions":[{"_etag":"566","_id":566,"_created":"2023-08-15T12:10:44","_updated":"2023-08-15T12:10:44.905249","app_id":230,"name":"PostgreSQL","version":"15_4","update_status":"ready_for_testing","tag":"unstable"},{"_etag":null,"_id":563,"_created":null,"_updated":"2023-05-24T12:52:15.351522","app_id":230,"name":"0.0.5","version":"0.0.5","update_status":"ready_for_testing","tag":"0.0.5"}],"domain":"","sharedPorts":["9999"],"main":true,"version":{"_etag":"566","_id":566,"_created":"2023-08-15T12:10:44","_updated":"2023-08-15T12:10:44.905249","app_id":230,"name":"PostgreSQL","version":"15_4","update_status":"ready_for_testing","tag":"unstable"}}],"servers_count":3,"custom_stack_name":"mysampleproject","custom_stack_code":"smarty-bot","custom_stack_category":["New"],"custom_stack_short_description":"sample short description","custom_stack_description":"stack description","custom_stack_publish":false,"project_name":"Smarty Bot","project_git_url":"https://github.com/vsilent/smarty.git","project_overview":"my product 1","project_description":"my product 1"}} diff --git a/tests/custom-stack-payload-3.json b/tests/custom-stack-payload-3.json deleted file mode 100644 index 4008848..0000000 --- a/tests/custom-stack-payload-3.json +++ /dev/null @@ -1 +0,0 @@ -{"commonDomain":"","domainList":{},"region":"fsn1","zone":null,"server":"cx21","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":[],"extended_features":[],"subscriptions":["stack_migration"],"save_token":false,"cloud_token":"r6LAjqrynVt7pUwctVkzBlJmKjLOCxJIWjZFMLTkPYCCB4rsgphhEVhiL4DuO757","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"web":[{"name":"Smarty Bot","code":"smarty-bot","domain":"smartybot.xyz","sharedPorts":["8000"],"versions":[],"custom":true,"type":"web","main":true,"_id":"lltkpq6p347kystct","dockerhub_user":"trydirect","dockerhub_name":"smarty-bot","url_app":"smartybot.xyz","url_git":"https://github.com/vsilent/smarty.git","disk_size":"1Gb","ram_size":"1Gb","cpu":1}],"feature":[{"_etag":null,"_id":198,"_created":"2022-04-27T14:10:27.280327","_updated":"2023-08-03T08:24:18.958721","name":"Portainer CE Feature","code":"portainer_ce_feature","role":["portainer-ce-feature"],"type":"feature","default":null,"popularity":null,"descr":null,"ports":{"public":["9000","8000"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":1138,"height":1138,"image":"08589075-44e6-430e-98a5-f9dcf711e054.svg"},"dark":{}},"category_id":2,"parent_app_id":null,"full_description":null,"description":"

Portainer is a lightweight management UI which allows you to easily manage your different Docker environments (Docker hosts or Swarm clusters)

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.6","ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"portainer-ce-feature","versions":[{"_etag":null,"_id":456,"_created":"2022-04-25T12:44:30.964547","_updated":"2023-03-17T13:46:51.433539","app_id":198,"name":"latest","version":"latest","update_status":"published","tag":"latest"}],"domain":"","sharedPorts":["9000"],"main":true,"version":{"_etag":null,"_id":456,"_created":"2022-04-25T12:44:30.964547","_updated":"2023-03-17T13:46:51.433539","app_id":198,"name":"latest","version":"latest","update_status":"published","tag":"latest"}}],"service":[{"_etag":null,"_id":230,"_created":"2023-05-24T12:51:52.108972","_updated":"2023-08-04T12:18:34.670194","name":"pgrst","code":"pgrst","role":null,"type":"service","default":null,"popularity":null,"descr":null,"ports":null,"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":null,"category_id":null,"parent_app_id":null,"full_description":null,"description":"

PostgREST description

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"1","ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"pgrst","versions":[{"_etag":"566","_id":566,"_created":"2023-08-15T12:10:44","_updated":"2023-08-15T12:10:44.905249","app_id":230,"name":"PostgreSQL","version":"15_4","update_status":"ready_for_testing","tag":"unstable"},{"_etag":null,"_id":563,"_created":null,"_updated":"2023-05-24T12:52:15.351522","app_id":230,"name":"0.0.5","version":"0.0.5","update_status":"ready_for_testing","tag":"0.0.5"}],"domain":"","sharedPorts":["9999"],"main":true,"version":{"_etag":"566","_id":566,"_created":"2023-08-15T12:10:44","_updated":"2023-08-15T12:10:44.905249","app_id":230,"name":"PostgreSQL","version":"15_4","update_status":"ready_for_testing","tag":"unstable"}}],"servers_count":3,"custom_stack_name":"mysampleproject","custom_stack_code":"another-bot","custom_stack_category":["New"],"custom_stack_short_description":"sample short description","custom_stack_description":"stack description","custom_stack_publish":false,"project_name":"Smarty Bot","project_git_url":"https://github.com/vsilent/smarty.git","project_overview":"my product 1","project_description":"my product 1"}} diff --git a/tests/custom-stack-payload-4.json b/tests/custom-stack-payload-4.json deleted file mode 100644 index 6f4bc7c..0000000 --- a/tests/custom-stack-payload-4.json +++ /dev/null @@ -1 +0,0 @@ -{"commonDomain":"", "domainList":{}, "region":"fsn1", "zone":null, "server":"cx21", "os":"ubuntu-20.04", "ssl":"letsencrypt", "vars":[], "integrated_features":[],"extended_features":[],"subscriptions":["stack_migration"],"save_token":false,"cloud_token":"r6LAjqrynVt7pUwctVkzBlJmKjLOCxJIWjZFMLTkPYCCB4rsgphhEVhiL4DuO757","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"web":[{"name":"Smarty Bot","code":"smarty-bot","domain":"smartybot.xyz","sharedPorts":["8000"],"versions":[],"custom":true,"type":"web","main":true,"_id":"lltkpq6p347kystct","dockerhub_user":"trydirect","dockerhub_name":"smarty-bot","url_app":"smartybot.xyz","url_git":"https://github.com/vsilent/smarty.git","disk_size":"1Gb","ram_size":"1Gb","cpu":1}],"feature":[{"_etag":null,"_id":198,"_created":"2022-04-27T14:10:27.280327","_updated":"2023-08-03T08:24:18.958721","name":"Portainer CE Feature","code":"portainer_ce_feature","role":["portainer-ce-feature"],"type":"feature","default":null,"popularity":null,"descr":null,"ports":{"public":["9000","8000"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":1138,"height":1138,"image":"08589075-44e6-430e-98a5-f9dcf711e054.svg"},"dark":{}},"category_id":2,"parent_app_id":null,"full_description":null,"description":"

Portainer is a lightweight management UI which allows you to easily manage your different Docker environments (Docker hosts or Swarm clusters)

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.6","ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"portainer-ce-feature","versions":[{"_etag":null,"_id":456,"_created":"2022-04-25T12:44:30.964547","_updated":"2023-03-17T13:46:51.433539","app_id":198,"name":"latest","version":"latest","update_status":"published","tag":"latest"}],"domain":"","sharedPorts":["9000"],"main":true,"version":{"_etag":null,"_id":456,"_created":"2022-04-25T12:44:30.964547","_updated":"2023-03-17T13:46:51.433539","app_id":198,"name":"latest","version":"latest","update_status":"published","tag":"latest"}}],"service":[{"_etag":null,"_id":230,"_created":"2023-05-24T12:51:52.108972","_updated":"2023-08-04T12:18:34.670194","name":"pgrst","code":"pgrst","role":null,"type":"service","default":null,"popularity":null,"descr":null,"ports":null,"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":null,"category_id":null,"parent_app_id":null,"full_description":null,"description":"

PostgREST description

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"1","ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"pgrst","versions":[{"_etag":"566","_id":566,"_created":"2023-08-15T12:10:44","_updated":"2023-08-15T12:10:44.905249","app_id":230,"name":"PostgreSQL","version":"15_4","update_status":"ready_for_testing","tag":"unstable"},{"_etag":null,"_id":563,"_created":null,"_updated":"2023-05-24T12:52:15.351522","app_id":230,"name":"0.0.5","version":"0.0.5","update_status":"ready_for_testing","tag":"0.0.5"}],"domain":"","sharedPorts":["9999"],"main":true,"version":{"_etag":"566","_id":566,"_created":"2023-08-15T12:10:44","_updated":"2023-08-15T12:10:44.905249","app_id":230,"name":"PostgreSQL","version":"15_4","update_status":"ready_for_testing","tag":"unstable"}}],"servers_count":3,"custom_stack_name":"mysampleproject4","custom_stack_code":"another-bot4","custom_stack_category":["New"],"custom_stack_short_description":"sample short description","custom_stack_description":"stack description","custom_stack_publish":false,"project_name":"Smarty Bot","project_git_url":"https://github.com/vsilent/smarty.git","project_overview":"my product 1","project_description":"my product 1"}} diff --git a/tests/custom-stack-payload-5.json b/tests/custom-stack-payload-5.json deleted file mode 100644 index 70bda71..0000000 --- a/tests/custom-stack-payload-5.json +++ /dev/null @@ -1 +0,0 @@ -{"commonDomain":"test.app", "domainList":{}, "region":"fsn1", "zone":null, "server":"cx21", "os":"ubuntu-20.04", "ssl":"letsencrypt", "vars":[], "integrated_features":[],"extended_features":[],"subscriptions":["stack_migration"],"save_token":false,"cloud_token":"r6LAjqrynVt7pUwctVkzBlJmKjLOCxJIWjZFMLTkPYCCB4rsgphhEVhiL4DuO757","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"web":[{"name":"Smarty Bot","code":"smarty-bot","domain":"smartybot.xyz","sharedPorts":["8000"],"versions":[],"custom":true,"type":"web","main":true,"_id":"lltkpq6p347kystct","dockerhub_user":"trydirect","dockerhub_name":"smarty-bot","url_app":"smartybot.xyz","url_git":"https://github.com/vsilent/smarty.git","disk_size":"1Gb","ram_size":"1Gb","cpu":1}],"feature":[{"_etag":null,"_id":198,"_created":"2022-04-27T14:10:27.280327","_updated":"2023-08-03T08:24:18.958721","name":"Portainer CE Feature","code":"portainer_ce_feature","role":["portainer-ce-feature"],"type":"feature","default":null,"popularity":null,"descr":null,"ports":{"public":["9000","8000"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":1138,"height":1138,"image":"08589075-44e6-430e-98a5-f9dcf711e054.svg"},"dark":{}},"category_id":2,"parent_app_id":null,"full_description":null,"description":"

Portainer is a lightweight management UI which allows you to easily manage your different Docker environments (Docker hosts or Swarm clusters)

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":0.6,"ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"portainer-ce-feature","versions":[{"_etag":null,"_id":456,"_created":"2022-04-25T12:44:30.964547","_updated":"2023-03-17T13:46:51.433539","app_id":198,"name":"latest","version":"latest","update_status":"published","tag":"latest"}],"domain":"","sharedPorts":["9000"],"main":true,"version":{"_etag":null,"_id":456,"_created":"2022-04-25T12:44:30.964547","_updated":"2023-03-17T13:46:51.433539","app_id":198,"name":"latest","version":"latest","update_status":"published","tag":"latest"}}],"service":[{"_etag":null,"_id":230,"_created":"2023-05-24T12:51:52.108972","_updated":"2023-08-04T12:18:34.670194","name":"pgrst","code":"pgrst","role":null,"type":"service","default":null,"popularity":null,"descr":null,"ports":null,"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":null,"category_id":null,"parent_app_id":null,"full_description":null,"description":"

PostgREST description

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":1,"ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"pgrst","versions":[{"_etag":"566","_id":566,"_created":"2023-08-15T12:10:44","_updated":"2023-08-15T12:10:44.905249","app_id":230,"name":"PostgreSQL","version":"15_4","update_status":"ready_for_testing","tag":"unstable"},{"_etag":null,"_id":563,"_created":null,"_updated":"2023-05-24T12:52:15.351522","app_id":230,"name":"0.0.5","version":"0.0.5","update_status":"ready_for_testing","tag":"0.0.5"}],"domain":"","sharedPorts":["9999"],"main":true,"version":{"_etag":"566","_id":566,"_created":"2023-08-15T12:10:44","_updated":"2023-08-15T12:10:44.905249","app_id":230,"name":"PostgreSQL","version":"15_4","update_status":"ready_for_testing","tag":"unstable"}}],"servers_count":3,"custom_stack_name":"mysampleproject5","custom_stack_code":"another-bot5","custom_stack_category":["New"],"custom_stack_short_description":"sample short description","custom_stack_description":"stack description","custom_stack_publish":false,"project_name":"Smarty Bot","project_git_url":"https://github.com/vsilent/smarty.git","project_overview":"my product 1","project_description":"my product 1"}} diff --git a/tests/custom-stack-payload-6.json b/tests/custom-stack-payload-6.json deleted file mode 100644 index 61dedb9..0000000 --- a/tests/custom-stack-payload-6.json +++ /dev/null @@ -1 +0,0 @@ -{"commonDomain":"test.app", "domainList":{}, "region":"fsn1", "zone":null, "server":"cx21", "os":"ubuntu-20.04", "ssl":"letsencrypt", "vars":[], "integrated_features":[],"extended_features":[],"subscriptions":["stack_migration"],"save_token":false,"cloud_token":"r6LAjqrynVt7pUwctVkzBlJmKjLOCxJIWjZFMLTkPYCCB4rsgphhEVhiL4DuO757","provider":"htz","stack_code":"another-bot8","selected_plan":"plan-individual-monthly","custom":{"web":[{"name":"Smarty Bot","code":"smarty-bot","domain":"smartybot.xyz","sharedPorts":["8000"],"versions":[],"custom":true,"type":"web","main":true,"_id":0,"dockerhub_user":"trydirect","dockerhub_name":"smarty-bot","url_app":"smartybot.xyz","url_git":"https://github.com/vsilent/smarty.git","disk_size":"1Gb","ram_size":"1Gb","cpu":1}],"feature":[{"_etag":null,"_id":198,"_created":"2022-04-27T14:10:27.280327","_updated":"2023-08-03T08:24:18.958721","name":"Portainer CE Feature","code":"portainer_ce_feature","role":["portainer-ce-feature"],"type":"feature","default":null,"popularity":null,"descr":null,"ports":{"public":["9000","8000"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":1138,"height":1138,"image":"08589075-44e6-430e-98a5-f9dcf711e054.svg"},"dark":{}},"category_id":2,"parent_app_id":null,"full_description":null,"description":"

Portainer is a lightweight management UI which allows you to easily manage your different Docker environments (Docker hosts or Swarm clusters)

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":0.6,"ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"portainer-ce-feature","versions":[{"_etag":null,"_id":456,"_created":"2022-04-25T12:44:30.964547","_updated":"2023-03-17T13:46:51.433539","app_id":198,"name":"latest","version":"latest","update_status":"published","tag":"latest"}],"domain":"","sharedPorts":["9000"],"main":true,"version":{"_etag":null,"_id":456,"_created":"2022-04-25T12:44:30.964547","_updated":"2023-03-17T13:46:51.433539","app_id":198,"name":"latest","version":"latest","update_status":"published","tag":"latest"}}],"service":[{"_etag":null,"_id":230,"_created":"2023-05-24T12:51:52.108972","_updated":"2023-08-04T12:18:34.670194","name":"pgrst","code":"pgrst","role":null,"type":"service","default":null,"popularity":null,"descr":null,"ports":null,"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":null,"category_id":null,"parent_app_id":null,"full_description":null,"description":"

PostgREST description

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":1,"ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"pgrst","versions":[{"_etag":"566","_id":566,"_created":"2023-08-15T12:10:44","_updated":"2023-08-15T12:10:44.905249","app_id":230,"name":"PostgreSQL","version":"15_4","update_status":"ready_for_testing","tag":"unstable"},{"_etag":null,"_id":563,"_created":null,"_updated":"2023-05-24T12:52:15.351522","app_id":230,"name":"0.0.5","version":"0.0.5","update_status":"ready_for_testing","tag":"0.0.5"}],"domain":"","sharedPorts":["9999"],"main":true,"version":{"_etag":"566","_id":566,"_created":"2023-08-15T12:10:44","_updated":"2023-08-15T12:10:44.905249","app_id":230,"name":"PostgreSQL","version":"15_4","update_status":"ready_for_testing","tag":"unstable"}}],"servers_count":3,"custom_stack_name":"mysampleproject6","custom_stack_code":"another-bot8","custom_stack_category":["New"],"custom_stack_short_description":"sample short description","custom_stack_description":"stack description","custom_stack_publish":false,"project_name":"Smarty Bot","project_git_url":"https://github.com/vsilent/smarty.git","project_overview":"my product 1","project_description":"my product 1"}} diff --git a/tests/custom-stack-payload-7.json b/tests/custom-stack-payload-7.json deleted file mode 100644 index 1fbfbbd..0000000 --- a/tests/custom-stack-payload-7.json +++ /dev/null @@ -1 +0,0 @@ -{"commonDomain":"test.app", "domainList":{}, "region":"fsn1", "zone":null, "server":"cx21", "os":"ubuntu-20.04", "ssl":"letsencrypt", "vars":[], "integrated_features":[],"extended_features":[],"subscriptions":["stack_migration"],"save_token":false,"cloud_token":"r6LAjqrynVt7pUwctVkzBlJmKjLOCxJIWjZFMLTkPYCCB4rsgphhEVhiL4DuO757","provider":"htz","stack_code":"another-bot8","selected_plan":"plan-individual-monthly","custom":{"web":[{"name":"Smarty Bot","code":"smarty-bot","domain":"smartybot.xyz","sharedPorts":["8000"],"versions":[],"custom":true,"type":"web","main":true,"_id":0,"dockerhub_user":"trydirect","dockerhub_name":"smarty-bot","url_app":"smartybot.xyz","url_git":"https://github.com/vsilent/smarty.git","disk_size":"1Gb","ram_size":"1Gb","cpu":1}],"feature":[{"_etag":null,"_id":198,"_created":"2022-04-27T14:10:27.280327","_updated":"2023-08-03T08:24:18.958721","name":"Portainer CE Feature","code":"portainer_ce_feature","role":["portainer-ce-feature"],"type":"feature","default":null,"popularity":null,"descr":null,"ports":{"public":["9000","8000"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":1138,"height":1138,"image":"08589075-44e6-430e-98a5-f9dcf711e054.svg"},"dark":{}},"category_id":2,"parent_app_id":null,"full_description":null,"description":"

Portainer is a lightweight management UI which allows you to easily manage your different Docker environments (Docker hosts or Swarm clusters)

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":0.6,"ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"portainer-ce-feature","versions":[{"_etag":null,"_id":456,"_created":"2022-04-25T12:44:30.964547","_updated":"2023-03-17T13:46:51.433539","app_id":198,"name":"latest","version":"latest","update_status":"published","tag":"latest"}],"domain":"","sharedPorts":["9000"],"main":true,"version":{"_etag":null,"_id":456,"_created":"2022-04-25T12:44:30.964547","_updated":"2023-03-17T13:46:51.433539","app_id":198,"name":"latest","version":"latest","update_status":"published","tag":"latest"}}],"service":[{"_etag":null,"_id":230,"_created":"2023-05-24T12:51:52.108972","_updated":"2023-08-04T12:18:34.670194","name":"pgrst","code":"pgrst","role":null,"type":"service","default":null,"popularity":null,"descr":null,"ports":null,"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":null,"category_id":null,"parent_app_id":null,"full_description":null,"description":"

PostgREST description

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":1,"ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"pgrst","versions":[{"_etag":"566","_id":566,"_created":"2023-08-15T12:10:44","_updated":"2023-08-15T12:10:44.905249","app_id":230,"name":"PostgreSQL","version":"15_4","update_status":"ready_for_testing","tag":"unstable"},{"_etag":null,"_id":563,"_created":null,"_updated":"2023-05-24T12:52:15.351522","app_id":230,"name":"0.0.5","version":"0.0.5","update_status":"ready_for_testing","tag":"0.0.5"}],"domain":"","sharedPorts":["9999"],"main":true,"version":{"_etag":"566","_id":566,"_created":"2023-08-15T12:10:44","_updated":"2023-08-15T12:10:44.905249","app_id":230,"name":"PostgreSQL","version":"15_4","update_status":"ready_for_testing","tag":"unstable"}}],"servers_count":3,"custom_stack_name":"mysampleproject7","custom_stack_code":"another-bot9","custom_stack_category":["New"],"custom_stack_short_description":"sample short description","custom_stack_description":"stack description","custom_stack_publish":false,"project_name":"Smarty Bot","project_git_url":"https://github.com/vsilent/smarty.git","project_overview":"my product 1","project_description":"my product 1"}} diff --git a/tests/custom-stack-payload-8.json b/tests/custom-stack-payload-8.json deleted file mode 100644 index 7a55fc9..0000000 --- a/tests/custom-stack-payload-8.json +++ /dev/null @@ -1 +0,0 @@ -{"commonDomain":"","domainList":{},"region":"fsn1","zone":null,"server":"cpx11","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":[],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":false,"disk_type":"pd-standart","cloud_token":"****","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"web":[{"_etag":null,"_id":233,"_created":"2023-07-19T06:38:57.608807","_updated":"2023-08-15T11:12:14.921797","name":"FastAPI","code":"fastapi","role":null,"type":"web","default":true,"popularity":null,"descr":null,"ports":{"public":["5050","8000","8080"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":2500,"height":2500,"image":"8d1ba06d-04e2-4523-879e-2846c86a10d8.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":null,"plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":0.1,"ram_size":"0.2Gb","disk_size":"0.2Gb","dockerhub_image":"fastapi","form":null,"versions":[{"_etag":null,"_id":587,"_created":null,"_updated":"2023-07-20T12:51:20.321999","app_id":233,"name":"0.0.1","version":"0.0.1","update_status":"ready_for_testing","tag":"0.0.1"},{"_etag":null,"_id":590,"_created":null,"_updated":"2023-07-20T08:36:49.651219","app_id":233,"name":"0.0.1","version":"0.0.1","update_status":"ready_for_testing","tag":"latest"},{"_etag":null,"_id":589,"_created":null,"_updated":"2023-07-20T08:36:55.200575","app_id":233,"name":"0.0.1","version":"0.0.1","update_status":"ready_for_testing","tag":"unstable"},{"_etag":"591","_id":591,"_created":null,"_updated":"2023-08-15T08:17:40.226186","app_id":233,"name":"Fastapi","version":"0.100.0","update_status":"published","tag":"stable"}],"domain":"fastapi.test","sharedPorts":["8000"],"main":true,"version":{"_etag":"591","_id":591,"_created":null,"_updated":"2023-08-15T08:17:40.226186","app_id":233,"name":"Fastapi","version":"0.100.0","update_status":"published","tag":"stable"}}],"feature":[{"_etag":null,"_id":198,"_created":"2022-04-27T14:10:27.280327","_updated":"2023-08-03T08:24:18.958721","name":"Portainer CE Feature","code":"portainer_ce_feature","role":["portainer-ce-feature"],"type":"feature","default":null,"popularity":null,"descr":null,"ports":{"public":["9000","8000"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":1138,"height":1138,"image":"08589075-44e6-430e-98a5-f9dcf711e054.svg"},"dark":{}},"category_id":2,"parent_app_id":null,"full_description":null,"description":"

Portainer is a lightweight management UI which allows you to easily manage your different Docker environments (Docker hosts or Swarm clusters)

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":0.6,"ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"portainer-ce-feature","form":null,"versions":[{"_etag":null,"_id":456,"_created":"2022-04-25T12:44:30.964547","_updated":"2023-09-07T07:28:51.18965","app_id":198,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"}],"domain":"","sharedPorts":["9000"],"main":false,"version":{"_etag":null,"_id":456,"_created":"2022-04-25T12:44:30.964547","_updated":"2023-09-07T07:28:51.18965","app_id":198,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"}}],"service":[{"_etag":null,"_id":24,"_created":"2020-06-19T13:07:24.228389","_updated":"2023-08-08T10:34:13.4985","name":"PostgreSQL","code":"postgres","role":[],"type":"service","default":null,"popularity":null,"descr":null,"ports":null,"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":576,"height":594,"image":"fd23f54c-e250-4228-8d56-7e5d93ffb925.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":null,"plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":0,"ram_size":null,"disk_size":null,"dockerhub_image":"postgres","form":null,"versions":[{"_etag":null,"_id":458,"_created":"2022-10-20T07:57:05.88997","_updated":"2023-04-05T07:24:39.637749","app_id":24,"name":"15","version":"15","update_status":"published","tag":"15"},{"_etag":null,"_id":288,"_created":"2022-10-20T07:56:16.160116","_updated":"2023-03-17T13:46:51.433539","app_id":24,"name":"10.22","version":"10.22","update_status":"published","tag":"10.22"},{"_etag":null,"_id":303,"_created":"2022-10-20T07:57:24.710286","_updated":"2023-03-17T13:46:51.433539","app_id":24,"name":"13.8","version":"13.8","update_status":"published","tag":"13.8"},{"_etag":null,"_id":266,"_created":"2022-10-20T07:56:32.360852","_updated":"2023-04-05T06:49:31.782132","app_id":24,"name":"11","version":"11","update_status":"published","tag":"11"},{"_etag":null,"_id":267,"_created":"2022-10-20T07:57:35.552085","_updated":"2023-03-17T13:46:51.433539","app_id":24,"name":"12.12","version":"12.12","update_status":"published","tag":"12.12"},{"_etag":null,"_id":38,"_created":"2020-06-19T13:07:24.258724","_updated":"2022-10-20T07:58:06.882602","app_id":24,"name":"14.5","version":"14.5","update_status":"published","tag":"14.5"},{"_etag":null,"_id":564,"_created":null,"_updated":"2023-05-24T12:55:57.894215","app_id":24,"name":"0.0.5","version":"0.0.5","update_status":"ready_for_testing","tag":"0.0.5"},{"_etag":null,"_id":596,"_created":null,"_updated":"2023-08-09T11:00:33.004267","app_id":24,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"}],"domain":"","sharedPorts":["6372"],"main":false,"version":{"_etag":null,"_id":596,"_created":null,"_updated":"2023-08-09T11:00:33.004267","app_id":24,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"}}],"servers_count":3,"project_name":"FastAPI example","custom_stack_code":"fastapi-example","project_git_url":"https://github.com/trydirect/fastapi.git"}} diff --git a/tests/custom-stack-payload-9.json b/tests/custom-stack-payload-9.json deleted file mode 100644 index 3bf473d..0000000 --- a/tests/custom-stack-payload-9.json +++ /dev/null @@ -1 +0,0 @@ -{"commonDomain":"","domainList":{},"region":"fsn1","zone":null,"server":"cx21","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":[],"extended_features":[],"subscriptions":["stack_migration"],"form_app":[],"save_token":true,"disk_type":"pd-standart","cloud_token":"D3dkDL4Qy1NpFezTl60V5RYfB5p0BSwLLoKVHhEqmJQ3jObSG77irP86e9YtCYVi","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"web":[{"_etag":null,"_id":233,"_created":"2023-07-19T06:38:57.608807","_updated":"2023-08-15T11:12:14.921797","name":"FastAPI","code":"fastapi","role":null,"type":"web","default":true,"popularity":null,"descr":null,"ports":{"public":["5050","8000","8080"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":2500,"height":2500,"image":"8d1ba06d-04e2-4523-879e-2846c86a10d8.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":null,"plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":0.1,"ram_size":"0.2Gb","disk_size":"0.2Gb","dockerhub_image":"fastapi","form":null,"versions":[{"_etag":null,"_id":587,"_created":null,"_updated":"2023-07-20T12:51:20.321999","app_id":233,"name":"0.0.1","version":"0.0.1","update_status":"ready_for_testing","tag":"0.0.1"},{"_etag":null,"_id":590,"_created":null,"_updated":"2023-07-20T08:36:49.651219","app_id":233,"name":"0.0.1","version":"0.0.1","update_status":"ready_for_testing","tag":"latest"},{"_etag":null,"_id":589,"_created":null,"_updated":"2023-07-20T08:36:55.200575","app_id":233,"name":"0.0.1","version":"0.0.1","update_status":"ready_for_testing","tag":"unstable"},{"_etag":"591","_id":591,"_created":null,"_updated":"2023-08-15T08:17:40.226186","app_id":233,"name":"Fastapi","version":"0.100.0","update_status":"published","tag":"stable"}],"domain":"fastapi.test","sharedPorts":["8000"],"main":true,"version":{"_etag":"591","_id":591,"_created":null,"_updated":"2023-08-15T08:17:40.226186","app_id":233,"name":"Fastapi","version":"0.100.0","update_status":"published","tag":"stable"}},{"name":"smarty bot","code":"smarty-bot","domain":"smarty-bot.fastapi.test","sharedPorts":["8080"],"versions":[],"custom":true,"type":"web","main":false,"_id":0,"dockerhub_user":"vsilent","dockerhub_name":"smarty","disk_size":"1Gb","ram_size":"1Gb","cpu":1}],"feature":[{"_etag":null,"_id":198,"_created":"2022-04-27T14:10:27.280327","_updated":"2023-08-03T08:24:18.958721","name":"Portainer CE Feature","code":"portainer_ce_feature","role":["portainer-ce-feature"],"type":"feature","default":null,"popularity":null,"descr":null,"ports":{"public":["9000","8000"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":1138,"height":1138,"image":"08589075-44e6-430e-98a5-f9dcf711e054.svg"},"dark":{}},"category_id":2,"parent_app_id":null,"full_description":null,"description":"

Portainer is a lightweight management UI which allows you to easily manage your different Docker environments (Docker hosts or Swarm clusters)

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":0.6,"ram_size":"1Gb","disk_size":"1Gb","dockerhub_image":"portainer-ce-feature","form":null,"versions":[{"_etag":null,"_id":456,"_created":"2022-04-25T12:44:30.964547","_updated":"2023-09-07T07:28:51.18965","app_id":198,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"}],"domain":"","sharedPorts":["9000"],"main":false,"version":{"_etag":null,"_id":456,"_created":"2022-04-25T12:44:30.964547","_updated":"2023-09-07T07:28:51.18965","app_id":198,"name":"2.18.4","version":"2.18.4","update_status":"published","tag":"2.18.4"}}],"service":[{"_etag":null,"_id":246,"_created":"2023-09-15T11:41:21.353013","_updated":"2023-09-15T11:45:40.307663","name":"Mailhog","code":"mailhog_service","role":["mailhog"],"type":"service","default":null,"popularity":null,"descr":null,"ports":{"public":["8025"],"private":["1025","8025"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":48,"height":48,"image":"9ed27fd5-4745-4fa1-86a6-e53557d700ff.png"},"dark":{"width":48,"height":48,"image":"0d7b38f8-d2ad-4068-a5bd-aa32c7e1958f.png"}},"category_id":null,"parent_app_id":null,"full_description":null,"description":"

MailHog is an email testing tool for developers.

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":0,"ram_size":null,"disk_size":null,"dockerhub_image":null,"form":null,"versions":[{"_etag":null,"_id":625,"_created":null,"_updated":"2023-09-15T11:42:10.48131","app_id":246,"name":"latest","version":"latest","update_status":"ready_for_production","tag":"latest"}],"domain":"","sharedPorts":["8025"],"main":false,"version":{"_etag":null,"_id":625,"_created":null,"_updated":"2023-09-15T11:42:10.48131","app_id":246,"name":"latest","version":"latest","update_status":"ready_for_production","tag":"latest"}},{"_etag":null,"_id":24,"_created":"2020-06-19T13:07:24.228389","_updated":"2023-08-08T10:34:13.4985","name":"PostgreSQL","code":"postgres","role":[],"type":"service","default":null,"popularity":null,"descr":null,"ports":null,"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":576,"height":594,"image":"fd23f54c-e250-4228-8d56-7e5d93ffb925.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":null,"plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":0,"ram_size":null,"disk_size":null,"dockerhub_image":"postgres","form":null,"versions":[{"_etag":null,"_id":458,"_created":"2022-10-20T07:57:05.88997","_updated":"2023-04-05T07:24:39.637749","app_id":24,"name":"15","version":"15","update_status":"published","tag":"15"},{"_etag":null,"_id":288,"_created":"2022-10-20T07:56:16.160116","_updated":"2023-03-17T13:46:51.433539","app_id":24,"name":"10.22","version":"10.22","update_status":"published","tag":"10.22"},{"_etag":null,"_id":303,"_created":"2022-10-20T07:57:24.710286","_updated":"2023-03-17T13:46:51.433539","app_id":24,"name":"13.8","version":"13.8","update_status":"published","tag":"13.8"},{"_etag":null,"_id":266,"_created":"2022-10-20T07:56:32.360852","_updated":"2023-04-05T06:49:31.782132","app_id":24,"name":"11","version":"11","update_status":"published","tag":"11"},{"_etag":null,"_id":267,"_created":"2022-10-20T07:57:35.552085","_updated":"2023-03-17T13:46:51.433539","app_id":24,"name":"12.12","version":"12.12","update_status":"published","tag":"12.12"},{"_etag":null,"_id":38,"_created":"2020-06-19T13:07:24.258724","_updated":"2022-10-20T07:58:06.882602","app_id":24,"name":"14.5","version":"14.5","update_status":"published","tag":"14.5"},{"_etag":null,"_id":564,"_created":null,"_updated":"2023-05-24T12:55:57.894215","app_id":24,"name":"0.0.5","version":"0.0.5","update_status":"ready_for_testing","tag":"0.0.5"},{"_etag":null,"_id":596,"_created":null,"_updated":"2023-08-09T11:00:33.004267","app_id":24,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"}],"domain":"","sharedPorts":["6372"],"main":false,"version":{"_etag":null,"_id":596,"_created":null,"_updated":"2023-08-09T11:00:33.004267","app_id":24,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"}}],"servers_count":3,"project_name":"FastAPI example 3","custom_stack_code":"fastapi-example-3","project_git_url":"https://github.com/trydirect/fastapi.git"}} diff --git a/tests/custom-stack-payload-singleapp.json b/tests/custom-stack-payload-singleapp.json deleted file mode 100644 index e1b3998..0000000 --- a/tests/custom-stack-payload-singleapp.json +++ /dev/null @@ -1 +0,0 @@ -{"commonDomain":"","domainList":{},"region":"fsn1","zone":null,"server":"cx11","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":[],"extended_features":[],"subscriptions":[],"save_token":false,"cloud_token":"nUDKdUk0b6fUOcW6I4zhmdMfhH8kR4nJrxWjRPxrfqTJ9smOSoKB4qZpsYjS8As6","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-free-periodically","custom":{"web":[{"name":"Smarty Bot","code":"smarty-bot","domain":"smartybot.com","sharedPorts":["8000"],"versions":[],"custom":true,"type":"web","main":true,"_id":"lmg1mg6c1acxn9bs7","dockerhub_user":"vsilent","dockerhub_name":"smarty"}],"feature":[],"service":[],"servers_count":3,"project_name":"sample1","custom_stack_code":"sample1"}} diff --git a/tests/custom-stack-payload.json b/tests/custom-stack-payload.json index a9ca754..574ab3c 100644 --- a/tests/custom-stack-payload.json +++ b/tests/custom-stack-payload.json @@ -1,4 +1 @@ -{"commonDomain":"","domainList":{},"region":"fsn1","zone":null,"server":"cx21","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":[],"extended_features":[],"subscriptions":["stack_migration","stack_health_monitoring","stack_security_monitoring"],"save_token":true,"cloud_token":"r6LAjqrynVt7pUwctVkzBlJmKjLOCxJIWjZFMLTkPYCCB4rsgphhEVhiL4DuO757","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"web":[{"name":"smarty database","code":"smarty-database","domain":"smarty-db.example.com","sharedPorts":["6532"],"versions":[],"custom":true,"type":"feature","main":true,"_id":"lm0gdh732y2qrojfl","dockerhub_user":"trydirect","dockerhub_name":"smarty-db","ram_size":"1Gb","cpu":1,"disk_size":"1Gb"}],"feature":[{"_etag":null,"_id":235,"_created":"2023-08-11T07:07:12.123355","_updated":"2023-08-15T13:07:30.597485","name":"Nginx Proxy Manager","code":"nginx_proxy_manager","role":["nginx_proxy_manager"],"type":"feature","default":null,"popularity":null,"descr":null,"ports":{"public":["80","81","443"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":192,"height":192,"image":"205128e6-0303-4b62-b946-9810b61f3d04.png"},"dark":{}},"category_id":2,"parent_app_id":null,"full_description":null,"description":"

Nginx Proxy Manager is a user-friendly software application designed to effortlessly route traffic to your websites, whether they're hosted at home or elsewhere. It comes equipped with free SSL capabilities, eliminating the need for extensive Nginx or Letsencrypt knowledge. This tool proves especially handy for simplifying SSL generation and seamlessly proxying your docker containers.

","plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"1","ram_size":"1Gb","disk_size":"0.3Gb","dockerhub_image":"nginx-proxy-manager","versions":[{"_etag":"599","_id":599,"_created":"2023-08-11T10:23:33","_updated":"2023-08-11T10:23:34.420583","app_id":235,"name":"Nginx proxy manager","version":"2.10.4","update_status":"ready_for_testing","tag":"unstable"},{"_etag":"601","_id":601,"_created":null,"_updated":"2023-08-15T08:11:19.703882","app_id":235,"name":"Nginx proxy manager","version":"2.10.4","update_status":"published","tag":"stable"},{"_etag":null,"_id":600,"_created":null,"_updated":"2023-08-11T07:08:43.944998","app_id":235,"name":"Nginx proxy manager","version":"2.10.4","update_status":"ready_for_testing","tag":"latest"}],"domain":"","sharedPorts":["443"],"main":true}],"service":[{"_etag":null,"_id":24,"_created":"2020-06-19T13:07:24.228389","_updated":"2023-08-08T10:34:13.4985","name":"PostgreSQL","code":"postgres","role":[],"type":"service","default":null,"popularity":null,"descr":null,"ports":null,"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":576,"height":594,"image":"fd23f54c-e250-4228-8d56-7e5d93ffb925.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":null,"plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":null,"ram_size":null,"disk_size":null,"dockerhub_image":"postgres","versions":[{"_etag":null,"_id":458,"_created":"2022-10-20T07:57:05.88997","_updated":"2023-04-05T07:24:39.637749","app_id":24,"name":"15","version":"15","update_status":"published","tag":"15"},{"_etag":null,"_id":288,"_created":"2022-10-20T07:56:16.160116","_updated":"2023-03-17T13:46:51.433539","app_id":24,"name":"10.22","version":"10.22","update_status":"published","tag":"10.22"},{"_etag":null,"_id":303,"_created":"2022-10-20T07:57:24.710286","_updated":"2023-03-17T13:46:51.433539","app_id":24,"name":"13.8","version":"13.8","update_status":"published","tag":"13.8"},{"_etag":null,"_id":266,"_created":"2022-10-20T07:56:32.360852","_updated":"2023-04-05T06:49:31.782132","app_id":24,"name":"11","version":"11","update_status":"published","tag":"11"},{"_etag":null,"_id":267,"_created":"2022-10-20T07:57:35.552085","_updated":"2023-03-17T13:46:51.433539","app_id":24,"name":"12.12","version":"12.12","update_status":"published","tag":"12.12"},{"_etag":null,"_id":38,"_created":"2020-06-19T13:07:24.258724","_updated":"2022-10-20T07:58:06.882602","app_id":24,"name":"14.5","version":"14.5","update_status":"published","tag":"14.5"},{"_etag":null,"_id":564,"_created":null,"_updated":"2023-05-24T12:55:57.894215","app_id":24,"name":"0.0.5","version":"0.0.5","update_status":"ready_for_testing","tag":"0.0.5"},{"_etag":null,"_id":596,"_created":null,"_updated":"2023-08-09T11:00:33.004267","app_id":24,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"}],"domain":"","sharedPorts":["5432"],"main":true}],"servers_count":3,"custom_stack_name":"SMBO","custom_stack_code":"sample-stack","custom_stack_git_url":"https://github.com/vsilent/smbo.git","custom_stack_category":["New","Marketing Automation"],"custom_stack_short_description":"Should be what is my project about shortly","custom_stack_description":"what is my project about more detailed","project_name":"sample stack","project_overview":"my short description, stack to marketplace, keep my token","project_description":"my full description, stack to marketplace, keep my token"}} - - - +{"commonDomain":"","domainList":{},"region":"fsn1","zone":null,"server":"cx11","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":[],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":false,"disk_type":"pd-standart","cloud_token":"****************************","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"networks":["default_network"],"web":[{"name":"MyApp","code":"myapp","domain":"myapp.com","shared_ports":[{"host_port":"80","container_port":"8080"}],"versions":[],"custom":true,"type":"web","network":["default_network"],"restart":"always","timestamp":"2024-01-15T09:47:46.580Z","_id":"lreqrvv81ifrmng39","dockerhub_user":"trydirect","dockerhub_name":"nginx-waf","environment":[{"key":"SOMEENVVAR1","value":"SOMEENVVAR_VALUE1"},{"key":"SOMEENVVAR2","value":"SOMEENVVAR_VALUE2"}],"volumes":[]}],"feature":[],"service":[],"servers_count":3,"project_git_url":"info@optimum-web.com","project_name":"Sample2024","custom_stack_code":"sample2024"}} \ No newline at end of file diff --git a/tests/model_user_stack.rs b/tests/model_user_stack.rs index 57e5f16..88a005b 100644 --- a/tests/model_user_stack.rs +++ b/tests/model_user_stack.rs @@ -67,7 +67,8 @@ fn test_docker_image_only_name_other_empty() { let docker_image = DockerImage { dockerhub_user: Some("".to_string()), dockerhub_name: Some("mysql".to_string()), - dockerhub_image: Some("".to_string(),) + dockerhub_image: Some("".to_string(),), + dockerhub_password: None, }; let output = docker_image.to_string(); assert_eq!(String::from("mysql:latest"), output); @@ -78,7 +79,8 @@ fn test_docker_image_only_name_other_none() { let docker_image = DockerImage { dockerhub_user: None, dockerhub_name: Some("mysql".to_string()), - dockerhub_image: None + dockerhub_image: None, + dockerhub_password: None, }; let output = docker_image.to_string(); assert_eq!(String::from("mysql:latest"), output); @@ -88,7 +90,8 @@ fn test_docker_image_namespace_and_repo() { let docker_image = DockerImage { dockerhub_user: Some("trydirect".to_string()), dockerhub_name: Some("mysql".to_string()), - dockerhub_image: Some("".to_string(),) + dockerhub_image: Some("".to_string(),), + dockerhub_password: None, }; let output = docker_image.to_string(); assert_eq!(String::from("trydirect/mysql:latest"), output); @@ -99,7 +102,8 @@ fn test_docker_image_namespace_and_repo_tag() { let docker_image = DockerImage { dockerhub_user: Some("trydirect".to_string()), dockerhub_name: Some("mysql:8.1".to_string()), - dockerhub_image: Some("".to_string(),) + dockerhub_image: Some("".to_string(),), + dockerhub_password: None, }; let output = docker_image.to_string(); assert_eq!(String::from("trydirect/mysql:8.1"), output); @@ -109,7 +113,8 @@ fn test_docker_image_only_image() { let docker_image = DockerImage { dockerhub_user: None, dockerhub_name: None, - dockerhub_image: Some("trydirect/mysql:stable".to_string(),) + dockerhub_image: Some("trydirect/mysql:stable".to_string(),), + dockerhub_password: None, }; let output = docker_image.to_string(); assert_eq!(String::from("trydirect/mysql:stable"), output); @@ -120,7 +125,8 @@ fn test_docker_image_only_image_other_empty() { let docker_image = DockerImage { dockerhub_user: Some("".to_string()), dockerhub_name: Some("".to_string()), - dockerhub_image: Some("trydirect/mysql:stable".to_string()) + dockerhub_image: Some("trydirect/mysql:stable".to_string()), + dockerhub_password: None, }; let output = docker_image.to_string(); assert_eq!(String::from("trydirect/mysql:stable"), output); @@ -130,7 +136,8 @@ fn test_docker_repo_name_with_tag_other_none() { let docker_image = DockerImage { dockerhub_user: None, dockerhub_name: Some("mysql:stable".to_string()), - dockerhub_image: None + dockerhub_image: None, + dockerhub_password: None, }; let output = docker_image.to_string(); assert_eq!(String::from("mysql:stable"), output); From 6731fdf091e91e6488ae3e71cc107c19ea516d0a Mon Sep 17 00:00:00 2001 From: vsilent Date: Mon, 15 Jan 2024 12:57:59 +0200 Subject: [PATCH 130/284] remove configuration.yaml from repo --- .gitignore | 1 + configuration.yaml => configuration.yaml.backup | 0 2 files changed, 1 insertion(+) rename configuration.yaml => configuration.yaml.backup (100%) diff --git a/.gitignore b/.gitignore index 32da6d8..547e8c8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ target .idea/ files +configuration.yaml diff --git a/configuration.yaml b/configuration.yaml.backup similarity index 100% rename from configuration.yaml rename to configuration.yaml.backup From 27b2eda43da9477dc8222faadd30dec4ddf72fae Mon Sep 17 00:00:00 2001 From: vsilent Date: Mon, 15 Jan 2024 13:00:12 +0200 Subject: [PATCH 131/284] remove configuration.yaml from repo --- configuration.yaml.orig | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 configuration.yaml.orig diff --git a/configuration.yaml.orig b/configuration.yaml.orig new file mode 100644 index 0000000..2e5d296 --- /dev/null +++ b/configuration.yaml.orig @@ -0,0 +1,16 @@ +app_host: 127.0.0.1 +app_port: 8000 +auth_url: https://dev.try.direct/server/user/oauth_server/api/me +max_clients_number: 2 +database: + host: 127.0.0.1 + port: 5432 + username: postgres + password: postgres + database_name: stacker + +amqp: + host: 51.15.74.139 + port: 5672 + username: guest + password: rabbitdev2023rabbitmqctl@@ From e00f4edac1ea504974f7fffbc2b53181b1a8f78b Mon Sep 17 00:00:00 2001 From: vsilent Date: Mon, 15 Jan 2024 13:00:50 +0200 Subject: [PATCH 132/284] remove configuration.yaml from repo --- .gitignore | 1 + configuration.yaml.backup | 16 ---------------- 2 files changed, 1 insertion(+), 16 deletions(-) delete mode 100644 configuration.yaml.backup diff --git a/.gitignore b/.gitignore index 547e8c8..e84716b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ target .idea/ files configuration.yaml +configuration.yaml.backup diff --git a/configuration.yaml.backup b/configuration.yaml.backup deleted file mode 100644 index 2e5d296..0000000 --- a/configuration.yaml.backup +++ /dev/null @@ -1,16 +0,0 @@ -app_host: 127.0.0.1 -app_port: 8000 -auth_url: https://dev.try.direct/server/user/oauth_server/api/me -max_clients_number: 2 -database: - host: 127.0.0.1 - port: 5432 - username: postgres - password: postgres - database_name: stacker - -amqp: - host: 51.15.74.139 - port: 5672 - username: guest - password: rabbitdev2023rabbitmqctl@@ From 81647e797df179e82d64a644f930dc88b3fc1e5b Mon Sep 17 00:00:00 2001 From: vsilent Date: Mon, 15 Jan 2024 13:03:34 +0200 Subject: [PATCH 133/284] remove configuration.yaml from repo --- .gitignore | 1 + configuration.yaml.orig | 16 ---------------- 2 files changed, 1 insertion(+), 16 deletions(-) delete mode 100644 configuration.yaml.orig diff --git a/.gitignore b/.gitignore index e84716b..5be6467 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ target files configuration.yaml configuration.yaml.backup +configuration.yaml.orig diff --git a/configuration.yaml.orig b/configuration.yaml.orig deleted file mode 100644 index 2e5d296..0000000 --- a/configuration.yaml.orig +++ /dev/null @@ -1,16 +0,0 @@ -app_host: 127.0.0.1 -app_port: 8000 -auth_url: https://dev.try.direct/server/user/oauth_server/api/me -max_clients_number: 2 -database: - host: 127.0.0.1 - port: 5432 - username: postgres - password: postgres - database_name: stacker - -amqp: - host: 51.15.74.139 - port: 5672 - username: guest - password: rabbitdev2023rabbitmqctl@@ From 9d4f4995395bb842ed3a9487c213078457773ce3 Mon Sep 17 00:00:00 2001 From: petru Date: Mon, 15 Jan 2024 18:05:42 +0200 Subject: [PATCH 134/284] issue-auth dctypes removed --- Cargo.lock | 13 + Cargo.toml | 1 + src/forms/stack/app.rs | 2 +- src/forms/stack/custom.rs | 2 +- src/helpers/stack/builder.rs | 20 +- src/helpers/stack/dctypes.rs | 836 ----------------------------------- src/helpers/stack/mod.rs | 1 - 7 files changed, 20 insertions(+), 855 deletions(-) delete mode 100644 src/helpers/stack/dctypes.rs diff --git a/Cargo.lock b/Cargo.lock index 759526e..aae6152 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1112,6 +1112,18 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "docker-compose-types" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608ffe949fbffae4034bdde4bfa224238736ecc9e1a362997245c7282f49fa60" +dependencies = [ + "derive_builder", + "indexmap 2.1.0", + "serde", + "serde_yaml", +] + [[package]] name = "dotenvy" version = "0.15.7" @@ -3132,6 +3144,7 @@ dependencies = [ "config", "deadpool-lapin", "derive_builder", + "docker-compose-types", "futures", "futures-lite 1.13.0", "futures-util", diff --git a/Cargo.toml b/Cargo.toml index 80d2070..649ae23 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,6 +55,7 @@ clap = { version = "4.4.8", features = ["derive"] } brotli = "3.4.0" serde_path_to_error = "0.1.14" deadpool-lapin = "0.11.0" +docker-compose-types = "0.7.0" [dependencies.sqlx] version = "0.6.3" diff --git a/src/forms/stack/app.rs b/src/forms/stack/app.rs index 7150926..f38a81f 100644 --- a/src/forms/stack/app.rs +++ b/src/forms/stack/app.rs @@ -1,5 +1,5 @@ use crate::forms; -use crate::helpers::stack::dctypes; +use docker_compose_types as dctypes; use indexmap::IndexMap; use serde_json::Value; use serde::{Deserialize, Serialize}; diff --git a/src/forms/stack/custom.rs b/src/forms/stack/custom.rs index 34f5437..29cb2cd 100644 --- a/src/forms/stack/custom.rs +++ b/src/forms/stack/custom.rs @@ -3,7 +3,7 @@ use serde_json::Value; use serde_valid::Validate; use crate::forms; use indexmap::IndexMap; -use crate::helpers::stack::dctypes; +use docker_compose_types as dctypes; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Custom { diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 5a30c9f..730c4e5 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -1,5 +1,5 @@ use crate::forms; -use crate::helpers::stack::dctypes::{ +use docker_compose_types::{ AdvancedVolumes, Compose, ComposeNetwork, ComposeNetworkSettingDetails, ComposeNetworks, ComposeVolume, Entrypoint, Environment, MapOrEmpty, NetworkSettings, Networks, Port, Ports, PublishedPort, Service, Services, SingleValue, TopLevelVolumes, Volumes, @@ -16,18 +16,6 @@ impl Default for Config { } } -impl Default for Port { - fn default() -> Self { - Port { - target: 80, - host_ip: None, - published: None, - protocol: None, - mode: None, - } - } -} - /// A builder for constructing docker compose. #[derive(Clone, Debug)] pub struct DcBuilder { @@ -120,12 +108,12 @@ impl TryFrom<&forms::stack::App> for Service { None => vec![] }; - let volumes: Vec = app //todo + let volumes: Vec = app .volumes .clone() .unwrap_or_default() .into_iter() - .map(|x| x.try_into().unwrap()) + .map(|x| Volumes::Advanced(x.try_into().unwrap())) //todo .collect(); let mut envs = IndexMap::new(); @@ -141,7 +129,7 @@ impl TryFrom<&forms::stack::App> for Service { service.networks = networks; service.ports = Ports::Long(ports); service.restart = Some("always".to_owned()); - service.volumes = Volumes::Advanced(volumes); + service.volumes = volumes; service.environment = Environment::KvPair(envs); Ok(service) diff --git a/src/helpers/stack/dctypes.rs b/src/helpers/stack/dctypes.rs deleted file mode 100644 index 2238393..0000000 --- a/src/helpers/stack/dctypes.rs +++ /dev/null @@ -1,836 +0,0 @@ -use derive_builder::*; -#[cfg(feature = "indexmap")] -use indexmap::IndexMap; -use serde::{Deserialize, Serialize}; -use serde_yaml::Value; -#[cfg(not(feature = "indexmap"))] -use std::collections::HashMap; -use std::convert::TryFrom; -use std::fmt; -use std::str::FromStr; - -#[allow(clippy::large_enum_variant)] -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -#[serde(untagged)] -pub enum ComposeFile { - V2Plus(Compose), - #[cfg(feature = "indexmap")] - V1(IndexMap), - #[cfg(not(feature = "indexmap"))] - V1(HashMap), - Single(SingleService), -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)] -pub struct SingleService { - pub service: Service, -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)] -pub struct Compose { - #[serde(skip_serializing_if = "Option::is_none")] - pub version: Option, - #[serde(default, skip_serializing_if = "Services::is_empty")] - pub services: Services, - #[serde(default, skip_serializing_if = "TopLevelVolumes::is_empty")] - pub volumes: TopLevelVolumes, - #[serde(default, skip_serializing_if = "ComposeNetworks::is_empty")] - pub networks: ComposeNetworks, - #[serde(skip_serializing_if = "Option::is_none")] - pub service: Option, - #[cfg(feature = "indexmap")] - #[serde(flatten, skip_serializing_if = "IndexMap::is_empty")] - pub extensions: IndexMap, - #[cfg(not(feature = "indexmap"))] - #[serde(flatten, skip_serializing_if = "HashMap::is_empty")] - pub extensions: HashMap, -} - -#[derive(Builder, Clone, Debug, Deserialize, Serialize, PartialEq, Default)] -#[builder(setter(into), default)] -pub struct Service { - #[serde(skip_serializing_if = "Option::is_none")] - pub hostname: Option, - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub privileged: bool, - #[serde(skip_serializing_if = "Option::is_none")] - pub healthcheck: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub deploy: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub image: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub container_name: Option, - #[serde(skip_serializing_if = "Option::is_none", rename = "build")] - pub build_: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub pid: Option, - #[serde(default, skip_serializing_if = "Ports::is_empty")] - pub ports: Ports, - #[serde(default, skip_serializing_if = "Environment::is_empty")] - pub environment: Environment, - #[serde(skip_serializing_if = "Option::is_none")] - pub network_mode: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub devices: Vec, - #[serde(skip_serializing_if = "Option::is_none")] - pub restart: Option, - #[serde(default, skip_serializing_if = "Labels::is_empty")] - pub labels: Labels, - #[serde(skip_serializing_if = "Option::is_none")] - pub tmpfs: Option, - #[serde(default, skip_serializing_if = "Ulimits::is_empty")] - pub ulimits: Ulimits, - #[serde(default, skip_serializing_if = "Volumes::is_empty")] - pub volumes: Volumes, - #[serde(default, skip_serializing_if = "Networks::is_empty")] - pub networks: Networks, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub cap_add: Vec, - #[serde(default, skip_serializing_if = "DependsOnOptions::is_empty")] - pub depends_on: DependsOnOptions, - #[serde(skip_serializing_if = "Option::is_none")] - pub command: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub entrypoint: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub env_file: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub stop_grace_period: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub profiles: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub links: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub dns: Vec, - #[serde(skip_serializing_if = "Option::is_none")] - pub ipc: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub net: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub stop_signal: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub user: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub working_dir: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub expose: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub volumes_from: Vec, - #[cfg(feature = "indexmap")] - #[serde(default, skip_serializing_if = "IndexMap::is_empty")] - pub extends: IndexMap, - #[cfg(not(feature = "indexmap"))] - #[serde(default, skip_serializing_if = "HashMap::is_empty")] - pub extends: HashMap, - #[serde(skip_serializing_if = "Option::is_none")] - pub logging: Option, - #[serde(default, skip_serializing_if = "is_zero")] - pub scale: i64, - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub init: bool, - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub stdin_open: bool, - #[serde(skip_serializing_if = "Option::is_none")] - pub shm_size: Option, - #[cfg(feature = "indexmap")] - #[serde(flatten, skip_serializing_if = "IndexMap::is_empty")] - pub extensions: IndexMap, - #[cfg(not(feature = "indexmap"))] - #[serde(flatten, skip_serializing_if = "HashMap::is_empty")] - pub extensions: HashMap, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub extra_hosts: Vec, - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub tty: bool, - #[serde(default, skip_serializing_if = "SysCtls::is_empty")] - pub sysctls: SysCtls, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub security_opt: Vec, -} - -impl Service { - pub fn image(&self) -> &str { - self.image.as_deref().unwrap_or_default() - } - - pub fn network_mode(&self) -> &str { - self.network_mode.as_deref().unwrap_or_default() - } -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(untagged)] -pub enum EnvFile { - Simple(String), - List(Vec), -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] -#[serde(untagged)] -pub enum DependsOnOptions { - Simple(Vec), - #[cfg(feature = "indexmap")] - Conditional(IndexMap), - #[cfg(not(feature = "indexmap"))] - Conditional(HashMap), -} - -impl Default for DependsOnOptions { - fn default() -> Self { - Self::Simple(Vec::new()) - } -} - -impl DependsOnOptions { - pub fn is_empty(&self) -> bool { - match self { - Self::Simple(v) => v.is_empty(), - Self::Conditional(m) => m.is_empty(), - } - } -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -pub struct DependsCondition { - pub condition: String, -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -pub struct LoggingParameters { - pub driver: String, - #[cfg(feature = "indexmap")] - #[serde(skip_serializing_if = "Option::is_none")] - pub options: Option>, - #[cfg(not(feature = "indexmap"))] - #[serde(skip_serializing_if = "Option::is_none")] - pub options: Option>, -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -#[serde(untagged)] -pub enum Ports { - Short(Vec), - Long(Vec), -} - -impl Default for Ports { - fn default() -> Self { - Self::Short(Vec::default()) - } -} - -impl Ports { - pub fn is_empty(&self) -> bool { - match self { - Self::Short(v) => v.is_empty(), - Self::Long(v) => v.is_empty(), - } - } -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -pub struct Port { - pub target: u16, - #[serde(skip_serializing_if = "Option::is_none")] - pub host_ip: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub published: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub protocol: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub mode: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -#[serde(untagged)] -pub enum PublishedPort { - Single(u16), - Range(String), -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -#[serde(untagged)] -pub enum Environment { - List(Vec), - #[cfg(feature = "indexmap")] - KvPair(IndexMap>), - #[cfg(not(feature = "indexmap"))] - KvPair(HashMap>), -} - -impl Default for Environment { - fn default() -> Self { - Self::List(Vec::new()) - } -} - -impl Environment { - pub fn is_empty(&self) -> bool { - match self { - Self::List(v) => v.is_empty(), - Self::KvPair(m) => m.is_empty(), - } - } -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash, Default, Ord, PartialOrd)] -#[serde(try_from = "String")] -pub struct Extension(String); - -impl FromStr for Extension { - type Err = ExtensionParseError; - - fn from_str(s: &str) -> Result { - let owned = s.to_owned(); - Extension::try_from(owned) - } -} - -impl TryFrom for Extension { - type Error = ExtensionParseError; - - fn try_from(s: String) -> Result { - if s.starts_with("x-") { - Ok(Self(s)) - } else { - Err(ExtensionParseError(s)) - } - } -} - -/// The result of a failed TryFrom conversion for [`Extension`] -/// -/// Contains the string that was being converted -#[derive(Clone, Debug, Eq, PartialEq, Hash)] -pub struct ExtensionParseError(pub String); - -impl fmt::Display for ExtensionParseError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "unknown attribute {:?}, extensions must start with 'x-' (see https://docs.docker.com/compose/compose-file/#extension)", self.0) - } -} - -impl std::error::Error for ExtensionParseError {} - -#[cfg(feature = "indexmap")] -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] -pub struct Services(pub IndexMap>); -#[cfg(not(feature = "indexmap"))] -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] -pub struct Services(pub HashMap>); - -impl Services { - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] -#[serde(untagged)] -pub enum Labels { - List(Vec), - #[cfg(feature = "indexmap")] - Map(IndexMap), - #[cfg(not(feature = "indexmap"))] - Map(HashMap), -} - -impl Default for Labels { - fn default() -> Self { - Self::List(Vec::new()) - } -} - -impl Labels { - pub fn is_empty(&self) -> bool { - match self { - Self::List(v) => v.is_empty(), - Self::Map(m) => m.is_empty(), - } - } -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] -#[serde(untagged)] -pub enum Tmpfs { - Simple(String), - List(Vec), -} - -#[cfg(feature = "indexmap")] -#[derive(Clone, Default, Debug, Serialize, Deserialize, Eq, PartialEq)] -pub struct Ulimits(pub IndexMap); -#[cfg(not(feature = "indexmap"))] -#[derive(Clone, Default, Debug, Serialize, Deserialize, Eq, PartialEq)] -pub struct Ulimits(pub HashMap); - -impl Ulimits { - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] -#[serde(untagged)] -pub enum Ulimit { - Single(i64), - SoftHard { soft: i64, hard: i64 }, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] -#[serde(untagged)] -pub enum Networks { - Simple(Vec), - Advanced(AdvancedNetworks), -} - -impl Default for Networks { - fn default() -> Self { - Self::Simple(Vec::new()) - } -} - -impl Networks { - pub fn is_empty(&self) -> bool { - match self { - Self::Simple(n) => n.is_empty(), - Self::Advanced(n) => n.0.is_empty(), - } - } -} - -#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] -#[serde(untagged)] -pub enum BuildStep { - Simple(String), - Advanced(AdvancedBuildStep), -} - -#[derive(Builder, Clone, Debug, Deserialize, Serialize, Eq, PartialEq, Default)] -#[serde(deny_unknown_fields)] -#[builder(setter(into), default)] -pub struct AdvancedBuildStep { - pub context: String, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub dockerfile: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub args: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub shm_size: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub target: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub network: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub cache_from: Vec, - #[serde(default, skip_serializing_if = "Labels::is_empty")] - pub labels: Labels, -} - -#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] -#[serde(untagged)] -pub enum BuildArgs { - Simple(String), - List(Vec), - #[cfg(feature = "indexmap")] - KvPair(IndexMap), - #[cfg(not(feature = "indexmap"))] - KvPair(HashMap), -} - -#[cfg(feature = "indexmap")] -#[derive(Clone, Default, Debug, Serialize, Deserialize, Eq, PartialEq)] -pub struct AdvancedNetworks(pub IndexMap>); -#[cfg(not(feature = "indexmap"))] -#[derive(Clone, Default, Debug, Serialize, Deserialize, Eq, PartialEq)] -pub struct AdvancedNetworks(pub HashMap>); - -#[derive(Clone, Debug, Default, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(deny_unknown_fields)] -pub struct AdvancedNetworkSettings { - #[serde(skip_serializing_if = "Option::is_none")] - pub ipv4_address: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub ipv6_address: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub aliases: Vec, -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -#[serde(untagged)] -pub enum SysCtls { - List(Vec), - #[cfg(feature = "indexmap")] - Map(IndexMap>), - #[cfg(not(feature = "indexmap"))] - Map(HashMap>), -} - -impl Default for SysCtls { - fn default() -> Self { - Self::List(Vec::new()) - } -} - -impl SysCtls { - pub fn is_empty(&self) -> bool { - match self { - Self::List(v) => v.is_empty(), - Self::Map(m) => m.is_empty(), - } - } -} - -#[cfg(feature = "indexmap")] -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] -pub struct TopLevelVolumes(pub IndexMap>); -#[cfg(not(feature = "indexmap"))] -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] -pub struct TopLevelVolumes(pub HashMap>); - -impl TopLevelVolumes { - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -pub struct ComposeVolume { - #[serde(skip_serializing_if = "Option::is_none")] - pub driver: Option, - #[cfg(feature = "indexmap")] - #[serde(default, skip_serializing_if = "IndexMap::is_empty")] - pub driver_opts: IndexMap>, - #[cfg(not(feature = "indexmap"))] - #[serde(default, skip_serializing_if = "HashMap::is_empty")] - pub driver_opts: HashMap>, - #[serde(skip_serializing_if = "Option::is_none")] - pub external: Option, - #[serde(default, skip_serializing_if = "Labels::is_empty")] - pub labels: Labels, - #[serde(skip_serializing_if = "Option::is_none")] - pub name: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -#[serde(untagged)] -pub enum ExternalVolume { - Bool(bool), - Name { name: String }, -} - -#[cfg(feature = "indexmap")] -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] -pub struct ComposeNetworks(pub IndexMap>); - -#[cfg(not(feature = "indexmap"))] -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] -pub struct ComposeNetworks(pub HashMap>); - -impl ComposeNetworks { - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(untagged)] -pub enum ComposeNetwork { - Detailed(ComposeNetworkSettingDetails), - Bool(bool), -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(deny_unknown_fields)] -pub struct ComposeNetworkSettingDetails { - pub name: String, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(deny_unknown_fields)] -pub struct ExternalNetworkSettingBool(bool); - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)] -#[serde(deny_unknown_fields)] -pub struct NetworkSettings { - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub attachable: bool, - #[serde(skip_serializing_if = "Option::is_none")] - pub driver: Option, - #[cfg(feature = "indexmap")] - #[serde(default, skip_serializing_if = "IndexMap::is_empty")] - pub driver_opts: IndexMap>, - #[cfg(not(feature = "indexmap"))] - #[serde(default, skip_serializing_if = "HashMap::is_empty")] - pub driver_opts: HashMap>, - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub enable_ipv6: bool, - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub internal: bool, - #[serde(skip_serializing_if = "Option::is_none")] - pub external: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub ipam: Option, - #[serde(default, skip_serializing_if = "Labels::is_empty")] - pub labels: Labels, - #[serde(skip_serializing_if = "Option::is_none")] - pub name: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(deny_unknown_fields)] -pub struct Ipam { - #[serde(skip_serializing_if = "Option::is_none")] - pub driver: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub config: Vec, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(deny_unknown_fields)] -pub struct IpamConfig { - pub subnet: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub gateway: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)] -#[serde(deny_unknown_fields)] -pub struct Deploy { - #[serde(skip_serializing_if = "Option::is_none")] - pub mode: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub replicas: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub labels: Vec, - #[serde(skip_serializing_if = "Option::is_none")] - pub update_config: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub resources: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub restart_policy: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub placement: Option, -} - -fn is_zero(val: &i64) -> bool { - *val == 0 -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(deny_unknown_fields)] -pub struct Healthcheck { - #[serde(skip_serializing_if = "Option::is_none")] - pub test: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub interval: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub timeout: Option, - #[serde(default, skip_serializing_if = "is_zero")] - pub retries: i64, - #[serde(skip_serializing_if = "Option::is_none")] - pub start_period: Option, - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub disable: bool, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(untagged)] -pub enum HealthcheckTest { - Single(String), - Multiple(Vec), -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash, Default)] -#[serde(deny_unknown_fields)] -pub struct Limits { - #[serde(skip_serializing_if = "Option::is_none")] - pub cpus: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub memory: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash, Default)] -#[serde(deny_unknown_fields)] -pub struct Placement { - #[serde(skip_serializing_if = "Vec::is_empty", default)] - pub constraints: Vec, - #[serde(skip_serializing_if = "Vec::is_empty", default)] - pub preferences: Vec, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(deny_unknown_fields)] -pub struct Preferences { - pub spread: String, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash, Default)] -#[serde(deny_unknown_fields)] -pub struct Resources { - pub limits: Option, - pub reservations: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash, Default)] -#[serde(deny_unknown_fields)] -pub struct RestartPolicy { - #[serde(skip_serializing_if = "Option::is_none")] - pub condition: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub delay: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub max_attempts: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub window: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)] -#[serde(deny_unknown_fields)] -pub struct UpdateConfig { - #[serde(skip_serializing_if = "Option::is_none")] - pub parallelism: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub delay: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub failure_action: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub monitor: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub max_failure_ratio: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(untagged)] -pub enum Volumes { - Simple(Vec), - Advanced(Vec), -} - -impl Default for Volumes { - fn default() -> Self { - Self::Simple(Vec::new()) - } -} - -impl Volumes { - pub fn is_empty(&self) -> bool { - match self { - Self::Simple(v) => v.is_empty(), - Self::Advanced(v) => v.is_empty(), - } - } -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(deny_unknown_fields)] -pub struct AdvancedVolumes { - #[serde(skip_serializing_if = "Option::is_none")] - pub source: Option, - pub target: String, - #[serde(rename = "type")] - pub _type: String, - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub read_only: bool, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub bind: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub volume: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub tmpfs: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash, Default)] -#[serde(deny_unknown_fields)] -pub struct Bind { - pub propagation: String, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash, Default)] -#[serde(deny_unknown_fields)] -pub struct Volume { - pub nocopy: bool, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash, Default)] -#[serde(deny_unknown_fields)] -pub struct TmpfsSettings { - pub size: u64, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(untagged)] -pub enum Command { - Simple(String), - Args(Vec), -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(untagged)] -pub enum Entrypoint { - Simple(String), - List(Vec), -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, PartialOrd)] -#[serde(untagged)] -pub enum SingleValue { - String(String), - Bool(bool), - Unsigned(u64), - Signed(i64), - Float(f64), -} - -impl fmt::Display for SingleValue { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::String(s) => f.write_str(s), - Self::Bool(b) => write!(f, "{b}"), - Self::Unsigned(u) => write!(f, "{u}"), - Self::Signed(i) => write!(f, "{i}"), - Self::Float(fl) => write!(f, "{fl}"), - } - } -} - -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Hash)] -#[serde(untagged)] -pub enum MapOrEmpty { - Map(T), - Empty, -} - -impl Default for MapOrEmpty { - fn default() -> Self { - Self::Empty - } -} - -impl From> for Option { - fn from(value: MapOrEmpty) -> Self { - match value { - MapOrEmpty::Map(t) => Some(t), - MapOrEmpty::Empty => None, - } - } -} - -impl Serialize for MapOrEmpty - where - T: Serialize, -{ - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - match self { - Self::Map(t) => t.serialize(serializer), - Self::Empty => { - use serde::ser::SerializeMap; - serializer.serialize_map(None)?.end() - } - } - } -} diff --git a/src/helpers/stack/mod.rs b/src/helpers/stack/mod.rs index 7da2d2e..9b5530b 100644 --- a/src/helpers/stack/mod.rs +++ b/src/helpers/stack/mod.rs @@ -1,2 +1 @@ pub(crate) mod builder; -pub(crate) mod dctypes; \ No newline at end of file From 362cb14bfb9be81769498a966e89c9cba69ee560 Mon Sep 17 00:00:00 2001 From: petru Date: Tue, 16 Jan 2024 18:16:36 +0200 Subject: [PATCH 135/284] issue-auth volumes --- src/helpers/stack/builder.rs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 730c4e5..7f2e57f 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -96,7 +96,6 @@ impl TryFrom<&forms::stack::App> for Service { }; let networks = Networks::try_from(&app.network).unwrap_or_default(); - let ports: Vec = match &app.ports { Some(ports) => { let mut collector = vec![]; @@ -108,16 +107,20 @@ impl TryFrom<&forms::stack::App> for Service { None => vec![] }; - let volumes: Vec = app - .volumes - .clone() - .unwrap_or_default() - .into_iter() - .map(|x| Volumes::Advanced(x.try_into().unwrap())) //todo - .collect(); + let volumes: Vec = match &app.volumes { + Some(volumes) => { + let mut collector = vec![]; + for volume in volumes { + collector.push(Volumes::Advanced(volume.clone().try_into()?)); + } + + collector + }, + None => vec![] + }; let mut envs = IndexMap::new(); - for item in app.environment.environment.clone().unwrap_or_default() { //todo + for item in app.environment.environment.clone().unwrap_or_default() { let items = item .into_iter() .map(|(k, v)| (k, Some(SingleValue::String(v.clone())))) From 3dfe453bc0fcb489ae6ce2370696e6fb228a31ea Mon Sep 17 00:00:00 2001 From: petru Date: Tue, 16 Jan 2024 18:32:22 +0200 Subject: [PATCH 136/284] issue-auth forms::stack::volume --- src/forms/stack/mod.rs | 34 +++++--------------------- src/forms/stack/port.rs | 33 +++++++++++++++++++++++++ src/forms/stack/volume.rs | 43 +++++++++++++++++++++++++++++++++ src/forms/stack/volumes.rs | 7 ++++++ src/helpers/stack/builder.rs | 47 ------------------------------------ 5 files changed, 89 insertions(+), 75 deletions(-) create mode 100644 src/forms/stack/port.rs create mode 100644 src/forms/stack/volume.rs create mode 100644 src/forms/stack/volumes.rs diff --git a/src/forms/stack/mod.rs b/src/forms/stack/mod.rs index aadeddc..2ea7aa0 100644 --- a/src/forms/stack/mod.rs +++ b/src/forms/stack/mod.rs @@ -8,12 +8,18 @@ use crate::forms; mod app; mod custom; mod form; +mod port; mod payload; +mod volumes; +mod volume; pub use app::*; pub use custom::*; pub use form::*; +pub use port::*; pub use payload::*; +pub use volumes::*; +pub use volume::*; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Role { @@ -38,11 +44,6 @@ pub struct Requirements { pub ram_size: Option, } -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Port { - pub host_port: Option, - pub container_port: Option, -} // #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] // pub struct Ports { @@ -105,29 +106,6 @@ pub struct Network { pub struct Environment { pub(crate) environment: Option>>, } -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Volume { - pub(crate) host_path: Option, - pub(crate) container_path: Option, -} - -impl Volume { - pub fn is_named_docker(&self) -> bool { - // Docker named volumes typically don't contain special characters or slashes - // They are alphanumeric and may include underscores or hyphens - self - .host_path - .as_ref() - .unwrap() - .chars() - .all(|c| c.is_alphanumeric() || c == '_' || c == '-') - } -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Volumes { - volumes: Vec, -} // pub(crate) type Networks = Option>; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] diff --git a/src/forms/stack/port.rs b/src/forms/stack/port.rs new file mode 100644 index 0000000..9b96c72 --- /dev/null +++ b/src/forms/stack/port.rs @@ -0,0 +1,33 @@ +use serde::{Deserialize, Serialize}; +use docker_compose_types as dctypes; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Port { + pub host_port: Option, + pub container_port: Option, +} + +impl TryInto for &Port { + type Error = String; + fn try_into(self) -> Result { + let cp = self + .container_port + .as_ref() + .map_or(Ok(0u16), |s| s.parse::()) + .map_err(|_| "Could not parse port".to_string())?; + + let hp = self + .host_port + .as_ref() + .map_or(Ok(0u16), |s| s.parse::()) + .map_err(|_| "Could not parse port".to_string())?; + + Ok(dctypes::Port { + target: cp, + host_ip: None, + published: Some(dctypes::PublishedPort::Single(hp)), + protocol: None, + mode: None, + }) + } +} diff --git a/src/forms/stack/volume.rs b/src/forms/stack/volume.rs new file mode 100644 index 0000000..67263f0 --- /dev/null +++ b/src/forms/stack/volume.rs @@ -0,0 +1,43 @@ +use serde::{Deserialize, Serialize}; +use docker_compose_types as dctypes; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Volume { + pub(crate) host_path: Option, + pub(crate) container_path: Option, +} + +impl Volume { + pub fn is_named_docker(&self) -> bool { + // Docker named volumes typically don't contain special characters or slashes + // They are alphanumeric and may include underscores or hyphens + self + .host_path + .as_ref() + .unwrap() + .chars() + .all(|c| c.is_alphanumeric() || c == '_' || c == '-') + } +} + +impl TryInto for Volume { //todo reference + type Error = String; + fn try_into(self) -> Result { + let source = self.host_path.clone(); + let target = self.container_path.clone(); + tracing::debug!( + "Volume conversion result: source: {:?} target: {:?}", + source, + target + ); + Ok(dctypes::AdvancedVolumes { + source: source, + target: target.unwrap_or("".to_string()), + _type: "".to_string(), + read_only: false, + bind: None, + volume: None, + tmpfs: None, + }) + } +} diff --git a/src/forms/stack/volumes.rs b/src/forms/stack/volumes.rs new file mode 100644 index 0000000..39ec33e --- /dev/null +++ b/src/forms/stack/volumes.rs @@ -0,0 +1,7 @@ +use serde::{Deserialize, Serialize}; +use crate::forms::stack::*; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Volumes { + volumes: Vec, +} diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 7f2e57f..dd36f23 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -23,53 +23,6 @@ pub struct DcBuilder { pub(crate) stack: models::Stack, } -impl TryInto for forms::stack::Volume { - type Error = String; - fn try_into(self) -> Result { - let source = self.host_path.clone(); - let target = self.container_path.clone(); - tracing::debug!( - "Volume conversion result: source: {:?} target: {:?}", - source, - target - ); - Ok(AdvancedVolumes { - source: source, - target: target.unwrap_or("".to_string()), - _type: "".to_string(), - read_only: false, - bind: None, - volume: None, - tmpfs: None, - }) - } -} - -impl TryInto for &forms::stack::Port { - type Error = String; - fn try_into(self) -> Result { - let cp = self - .container_port - .as_ref() - .map_or(Ok(0u16), |s| s.parse::()) - .map_err(|_| "Could not parse port".to_string())?; - - let hp = self - .host_port - .as_ref() - .map_or(Ok(0u16), |s| s.parse::()) - .map_err(|_| "Could not parse port".to_string())?; - - Ok(Port { - target: cp, - host_ip: None, - published: Some(PublishedPort::Single(hp)), - protocol: None, - mode: None, - }) - } -} - impl TryFrom<&forms::stack::ServiceNetworks> for Networks { type Error = (); From 7f69bc8b9fcdf7789023d5e51f867d46282cd9e0 Mon Sep 17 00:00:00 2001 From: vsilent Date: Wed, 17 Jan 2024 13:50:48 +0200 Subject: [PATCH 137/284] container_port is required --- Cargo.lock | 576 ++++++++++++++++---------------- Cargo.toml | 4 +- scripts/init_db.sh | 3 +- src/forms/stack.rs | 17 +- src/helpers/dockerhub.rs | 22 +- src/helpers/stack/builder.rs | 6 +- tests/custom-stack-payload.json | 2 +- 7 files changed, 301 insertions(+), 329 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 56d7a9a..6bc8dd8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,9 +21,9 @@ dependencies = [ [[package]] name = "actix-cors" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b340e9cfa5b08690aae90fb61beb44e9b06f44fe3d0f93781aaa58cfba86245e" +checksum = "0346d8c1f762b41b458ed3145eea914966bb9ad20b9be0d6d463b20d45586370" dependencies = [ "actix-utils", "actix-web", @@ -36,16 +36,16 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.4.0" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92ef85799cba03f76e4f7c10f533e66d87c9a7e7055f3391f09000ad8351bc9" +checksum = "129d4c88e98860e1758c5de288d1632b07970a16d59bdf7b8d66053d582bb71f" dependencies = [ "actix-codec", "actix-rt", "actix-service", "actix-utils", - "ahash 0.8.6", - "base64 0.21.5", + "ahash 0.8.7", + "base64 0.21.7", "bitflags 2.4.1", "brotli", "bytes", @@ -80,14 +80,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] name = "actix-router" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66ff4d247d2b160861fa2866457e85706833527840e4133f8f49aa423a38799" +checksum = "d22475596539443685426b6bdadb926ad0ecaefdfc5fb05e5e3441f15463c511" dependencies = [ "bytestring", "http", @@ -146,9 +146,9 @@ dependencies = [ [[package]] name = "actix-web" -version = "4.4.0" +version = "4.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4a5b5e29603ca8c94a77c65cf874718ceb60292c5a5c3e5f4ace041af462b9" +checksum = "e43428f3bf11dee6d166b00ec2df4e3aa8cc1606aaa0b7433c146852e2f4e03b" dependencies = [ "actix-codec", "actix-http", @@ -159,7 +159,7 @@ dependencies = [ "actix-service", "actix-utils", "actix-web-codegen", - "ahash 0.8.6", + "ahash 0.8.7", "bytes", "bytestring", "cfg-if", @@ -180,7 +180,7 @@ dependencies = [ "serde_urlencoded", "smallvec", "socket2 0.5.5", - "time 0.3.30", + "time 0.3.31", "url", ] @@ -193,7 +193,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -204,7 +204,7 @@ checksum = "1d613edf08a42ccc6864c941d30fe14e1b676a77d16f1dbadc1174d065a0a775" dependencies = [ "actix-utils", "actix-web", - "base64 0.21.5", + "base64 0.21.7", "futures-core", "futures-util", "log", @@ -232,19 +232,19 @@ version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.12", "once_cell", "version_check", ] [[package]] name = "ahash" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" +checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" dependencies = [ "cfg-if", - "getrandom 0.2.11", + "getrandom 0.2.12", "once_cell", "version_check", "zerocopy", @@ -345,9 +345,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.4" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" +checksum = "4cd2405b3ac1faab2990b74d728624cd9fd115651fcecc7c2d8daf01376275ba" dependencies = [ "anstyle", "anstyle-parse", @@ -365,37 +365,37 @@ checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" [[package]] name = "anstyle-parse" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.1" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" dependencies = [ "anstyle", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "anyhow" -version = "1.0.75" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" [[package]] name = "assert-json-diff" @@ -425,7 +425,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ca33f4bc4ed1babef42cad36cc1f51fa88be00420404e5b1e80ab1b18f7678c" dependencies = [ "concurrent-queue", - "event-listener 4.0.0", + "event-listener 4.0.3", "event-listener-strategy", "futures-core", "pin-project-lite", @@ -437,26 +437,26 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17ae5ebefcc48e7452b4987947920dac9450be1110cadf34d1b8c116bdbaf97c" dependencies = [ - "async-lock 3.1.2", + "async-lock 3.3.0", "async-task", "concurrent-queue", "fastrand 2.0.1", - "futures-lite 2.0.1", + "futures-lite 2.2.0", "slab", ] [[package]] name = "async-global-executor" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4353121d5644cdf2beb5726ab752e79a8db1ebb52031770ec47db31d245526" +checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ "async-channel 2.1.1", "async-executor", - "async-io 2.2.1", - "async-lock 3.1.2", + "async-io 2.3.0", + "async-lock 3.3.0", "blocking", - "futures-lite 2.0.1", + "futures-lite 2.2.0", "once_cell", ] @@ -493,18 +493,18 @@ dependencies = [ [[package]] name = "async-io" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6d3b15875ba253d1110c740755e246537483f152fa334f91abd7fe84c88b3ff" +checksum = "fb41eb19024a91746eba0773aa5e16036045bbf45733766661099e182ea6a744" dependencies = [ - "async-lock 3.1.2", + "async-lock 3.3.0", "cfg-if", "concurrent-queue", "futures-io", - "futures-lite 2.0.1", + "futures-lite 2.2.0", "parking", - "polling 3.3.1", - "rustix 0.38.25", + "polling 3.3.2", + "rustix 0.38.30", "slab", "tracing", "windows-sys 0.52.0", @@ -521,11 +521,11 @@ dependencies = [ [[package]] name = "async-lock" -version = "3.1.2" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea8b3453dd7cc96711834b75400d671b73e3656975fa68d9f277163b7f7e316" +checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" dependencies = [ - "event-listener 4.0.0", + "event-listener 4.0.3", "event-listener-strategy", "pin-project-lite", ] @@ -544,19 +544,19 @@ dependencies = [ [[package]] name = "async-task" -version = "4.5.0" +version = "4.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4eb2cdb97421e01129ccb49169d8279ed21e829929144f4a22a6e54ac549ca1" +checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799" [[package]] name = "async-trait" -version = "0.1.74" +version = "0.1.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -603,9 +603,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.5" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "bitflags" @@ -644,11 +644,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118" dependencies = [ "async-channel 2.1.1", - "async-lock 3.1.2", + "async-lock 3.3.0", "async-task", "fastrand 2.0.1", "futures-io", - "futures-lite 2.0.1", + "futures-lite 2.2.0", "piper", "tracing", ] @@ -754,9 +754,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.8" +version = "4.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64" +checksum = "80932e03c33999b9235edb8655bc9df3204adc9887c2f95b50cb1deb9fd54253" dependencies = [ "clap_builder", "clap_derive", @@ -764,14 +764,14 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.8" +version = "4.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc" +checksum = "d6c0db58c659eef1c73e444d298c27322a1b52f6927d2ad470c0c0f96fa7b8fa" dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim", + "strsim 0.10.0", ] [[package]] @@ -783,7 +783,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -800,9 +800,9 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "concurrent-queue" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f057a694a54f12365049b0958a1685bb52d567f5593b355fbf685838e873d400" +checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" dependencies = [ "crossbeam-utils", ] @@ -839,7 +839,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" dependencies = [ "percent-encoding", - "time 0.3.30", + "time 0.3.31", "version_check", ] @@ -851,9 +851,9 @@ checksum = "396de984970346b0d9e93d1415082923c679e5ae5c3ee3dcbd104f5610af126b" [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -861,15 +861,15 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "cpufeatures" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] @@ -900,22 +900,18 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crypto-common" @@ -947,7 +943,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.10.0", "syn 1.0.109", ] @@ -983,9 +979,9 @@ checksum = "63dfa964fe2a66f3fde91fc70b267fe193d822c7e603e2a675a49a7f46ad3f49" [[package]] name = "deranged" -version = "0.3.9" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", ] @@ -1118,12 +1114,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -1134,9 +1130,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" -version = "4.0.0" +version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "770d968249b5d99410d61f5bf89057f3199a077a04d087092f58e7d10692baae" +checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" dependencies = [ "concurrent-queue", "parking", @@ -1149,7 +1145,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" dependencies = [ - "event-listener 4.0.0", + "event-listener 4.0.3", "pin-project-lite", ] @@ -1246,9 +1242,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -1261,9 +1257,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -1271,15 +1267,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -1299,9 +1295,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-lite" @@ -1320,40 +1316,39 @@ dependencies = [ [[package]] name = "futures-lite" -version = "2.0.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3831c2651acb5177cbd83943f3d9c8912c5ad03c76afcc0e9511ba568ec5ebb" +checksum = "445ba825b27408685aaecefd65178908c36c6e96aaf6d8599419d46e624192ba" dependencies = [ "fastrand 2.0.1", "futures-core", "futures-io", - "memchr", "parking", "pin-project-lite", ] [[package]] name = "futures-macro" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] name = "futures-sink" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-timer" @@ -1363,9 +1358,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", @@ -1412,9 +1407,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", @@ -1435,9 +1430,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "h2" -version = "0.3.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" +checksum = "b553656127a00601c8ae5590fcfdc118e4083a7924b6cf4ffc1ea4b99dc429d7" dependencies = [ "bytes", "fnv", @@ -1463,11 +1458,11 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.7", "allocator-api2", ] @@ -1477,7 +1472,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.14.2", + "hashbrown 0.14.3", ] [[package]] @@ -1503,9 +1498,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hkdf" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ "hmac", ] @@ -1532,9 +1527,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", @@ -1576,9 +1571,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.27" +version = "0.14.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" dependencies = [ "bytes", "futures-channel", @@ -1591,7 +1586,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.10", + "socket2 0.5.5", "tokio", "tower-service", "tracing", @@ -1613,9 +1608,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.58" +version = "0.1.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1658,7 +1653,6 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", - "serde", ] [[package]] @@ -1668,7 +1662,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown 0.14.2", + "hashbrown 0.14.3", "serde", ] @@ -1716,27 +1710,18 @@ checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "jobserver" @@ -1749,9 +1734,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.65" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" +checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" dependencies = [ "wasm-bindgen", ] @@ -1804,9 +1789,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.150" +version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" [[package]] name = "libredox" @@ -1833,9 +1818,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] name = "local-channel" @@ -1891,9 +1876,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "mime" @@ -1918,9 +1903,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "log", @@ -1993,24 +1978,24 @@ dependencies = [ [[package]] name = "object" -version = "0.32.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" -version = "0.10.60" +version = "0.10.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800" +checksum = "8cde4d2d9200ad5909f8dac647e29482e07c3a35de8a13fce7c9c7747ad9f671" dependencies = [ "bitflags 2.4.1", "cfg-if", @@ -2029,7 +2014,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -2040,9 +2025,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.96" +version = "0.9.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f" +checksum = "c1665caf8ab2dc9aef43d1c0023bd904633a6a05cb30b0ad59bec2ae986e57a7" dependencies = [ "cc", "libc", @@ -2075,7 +2060,7 @@ dependencies = [ "cbc", "cipher", "des", - "getrandom 0.2.11", + "getrandom 0.2.12", "hmac", "lazy_static", "rc2", @@ -2157,9 +2142,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5" +checksum = "1f200d8d83c44a45b21764d1916299752ca035d15ecd46faca3e9a2a2bf6ad06" dependencies = [ "memchr", "thiserror", @@ -2168,9 +2153,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81d78524685f5ef2a3b3bd1cafbc9fcabb036253d9b1463e726a91cd16e2dfc2" +checksum = "bcd6ab1236bbdb3a49027e920e693192ebfe8913f6d60e294de57463a493cfde" dependencies = [ "pest", "pest_generator", @@ -2178,22 +2163,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68bd1206e71118b5356dae5ddc61c8b11e28b09ef6a31acbd15ea48a28e0c227" +checksum = "2a31940305ffc96863a735bef7c7994a00b325a7138fdbc5bda0f1a0476d3275" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] name = "pest_meta" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c747191d4ad9e4a4ab9c8798f1e82a39affe7ef9648390b7e5548d18e099de6" +checksum = "a7ff62f5259e53b78d1af898941cdcdccfae7385cf7d793a6e55de5d05bb4b7d" dependencies = [ "once_cell", "pest", @@ -2217,7 +2202,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -2257,9 +2242,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" [[package]] name = "polling" @@ -2279,14 +2264,14 @@ dependencies = [ [[package]] name = "polling" -version = "3.3.1" +version = "3.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf63fa624ab313c11656b4cda960bfc46c410187ad493c41f6ba2d8c1e991c9e" +checksum = "545c980a3880efd47b2e262f6a4bb6daad6555cf3367aa9c4e52895f69537a41" dependencies = [ "cfg-if", "concurrent-queue", "pin-project-lite", - "rustix 0.38.25", + "rustix 0.38.30", "tracing", "windows-sys 0.52.0", ] @@ -2329,18 +2314,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -2404,7 +2389,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.12", ] [[package]] @@ -2460,7 +2445,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.12", "libredox", "thiserror", ] @@ -2511,11 +2496,11 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.22" +version = "0.11.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" dependencies = [ - "base64 0.21.5", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", @@ -2570,12 +2555,12 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.5" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" dependencies = [ "cc", - "getrandom 0.2.11", + "getrandom 0.2.12", "libc", "spin 0.9.8", "untrusted 0.9.0", @@ -2634,15 +2619,15 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.25" +version = "0.38.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" +checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" dependencies = [ "bitflags 2.4.1", "errno", "libc", - "linux-raw-sys 0.4.11", - "windows-sys 0.48.0", + "linux-raw-sys 0.4.12", + "windows-sys 0.52.0", ] [[package]] @@ -2659,12 +2644,12 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.9" +version = "0.21.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ "log", - "ring 0.17.5", + "ring 0.17.7", "rustls-webpki", "sct", ] @@ -2676,7 +2661,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25da151615461c7347114b1ad1a7458b4cdebc69cb220cd140cd5cb324b1dd37" dependencies = [ "log", - "rustls 0.21.9", + "rustls 0.21.10", "rustls-native-certs", "rustls-webpki", ] @@ -2699,7 +2684,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64 0.21.5", + "base64 0.21.7", ] [[package]] @@ -2708,23 +2693,23 @@ version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.17.5", + "ring 0.17.7", "untrusted 0.9.0", ] [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "schannel" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2739,7 +2724,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.17.5", + "ring 0.17.7", "untrusted 0.9.0", ] @@ -2768,35 +2753,35 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" [[package]] name = "serde" -version = "1.0.193" +version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" dependencies = [ "itoa", "ryu", @@ -2805,9 +2790,9 @@ dependencies = [ [[package]] name = "serde_path_to_error" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335" +checksum = "ebd154a240de39fdebcf5775d2675c204d7c13cf39a4c697be6493c8e734337c" dependencies = [ "itoa", "serde", @@ -2838,12 +2823,12 @@ dependencies = [ [[package]] name = "serde_valid" -version = "0.16.3" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0adc7a19d45e581abc6d169c865a0b14b84bb43a9e966d1cca4d733e70f7f35a" +checksum = "3ede56947572525b2c9640542edfa35bbc2f575fa03f97d4d68e9eb4e4c5136b" dependencies = [ - "indexmap 1.9.3", - "itertools 0.10.5", + "indexmap 2.1.0", + "itertools", "num-traits", "once_cell", "paste", @@ -2858,23 +2843,23 @@ dependencies = [ [[package]] name = "serde_valid_derive" -version = "0.16.3" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071237362e267e2a76ffe4434094e089dcd8b5e9d8423ada499e5550dcb0181d" +checksum = "79ffdd7f3a5dea22dc86747bc02f5292a091977383c0124e7d77fc4fd120c486" dependencies = [ "paste", "proc-macro-error", "proc-macro2", "quote", - "strsim", - "syn 1.0.109", + "strsim 0.11.0", + "syn 2.0.48", ] [[package]] name = "serde_valid_literal" -version = "0.16.3" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f57df292b1d64449f90794fc7a67efca0b21acca91493e64a46418a29bbe36b4" +checksum = "be811ca7379637055f6474a1c0d0ed985c86966e580279ec980f77816b8f41b0" dependencies = [ "paste", "regex", @@ -2882,9 +2867,9 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.27" +version = "0.9.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cc7a1570e38322cfe4154732e5110f887ea57e22b76f4bfd32b5bdd3368666c" +checksum = "b1bf28c79a99f70ee1f1d83d10c875d2e70618417fda01ad1785e027579d9d38" dependencies = [ "indexmap 2.1.0", "itoa", @@ -2944,9 +2929,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.2" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +checksum = "2593d31f82ead8df961d8bd23a64c2ccf2eb5dd34b0a34bfb4dd54011c72009e" [[package]] name = "socket2" @@ -2985,11 +2970,11 @@ dependencies = [ [[package]] name = "sqlformat" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b7b278788e7be4d0d29c0f39497a0eef3fba6bbc8e70d8bf7fde46edeaa9e85" +checksum = "ce81b7bd7c4493975347ef60d8c7e8b742d4694f4c49f93e0a12ea263938176c" dependencies = [ - "itertools 0.11.0", + "itertools", "nom", "unicode_categories", ] @@ -3152,6 +3137,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strsim" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" + [[package]] name = "subtle" version = "2.5.0" @@ -3171,9 +3162,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -3215,35 +3206,35 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.8.1" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" dependencies = [ "cfg-if", "fastrand 2.0.1", "redox_syscall 0.4.1", - "rustix 0.38.25", - "windows-sys 0.48.0", + "rustix 0.38.30", + "windows-sys 0.52.0", ] [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -3269,9 +3260,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" dependencies = [ "deranged", "itoa", @@ -3289,9 +3280,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" dependencies = [ "time-core", ] @@ -3313,9 +3304,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.34.0" +version = "1.35.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" +checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" dependencies = [ "backtrace", "bytes", @@ -3338,7 +3329,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -3435,7 +3426,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -3444,12 +3435,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5c266b9ac83dedf0e0385ad78514949e6d89491269e7065bee51d2bb8ec7373" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.7", "gethostname", "log", "serde", "serde_json", - "time 0.3.30", + "time 0.3.31", "tracing", "tracing-core", "tracing-log 0.1.4", @@ -3508,9 +3499,9 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" @@ -3526,9 +3517,9 @@ checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" [[package]] name = "unicode-ident" @@ -3559,9 +3550,9 @@ checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" [[package]] name = "unsafe-libyaml" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa" +checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" [[package]] name = "untrusted" @@ -3599,7 +3590,7 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.12", "serde", ] @@ -3656,9 +3647,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.88" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" +checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3666,24 +3657,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.88" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" +checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.38" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" +checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461" dependencies = [ "cfg-if", "js-sys", @@ -3693,9 +3684,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.88" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" +checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3703,28 +3694,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.88" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" +checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.88" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" +checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" [[package]] name = "web-sys" -version = "0.3.65" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" +checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" dependencies = [ "js-sys", "wasm-bindgen", @@ -3736,7 +3727,7 @@ version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" dependencies = [ - "ring 0.17.5", + "ring 0.17.7", "untrusted 0.9.0", ] @@ -3783,11 +3774,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.51.1" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.48.5", + "windows-targets 0.52.0", ] [[package]] @@ -3940,7 +3931,7 @@ checksum = "13a3a53eaf34f390dd30d7b1b078287dd05df2aa2e21a589ccb80f5c7253c2e9" dependencies = [ "assert-json-diff", "async-trait", - "base64 0.21.5", + "base64 0.21.7", "deadpool", "futures", "futures-timer", @@ -3971,40 +3962,39 @@ checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" [[package]] name = "zerocopy" -version = "0.7.26" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97e415490559a91254a2979b4829267a57d2fcd741a98eee8b722fb57289aa0" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.26" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] name = "zstd" -version = "0.12.4" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" +checksum = "bffb3309596d527cfcba7dfc6ed6052f1d39dfbd7c867aa2e865e4a449c10110" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "6.0.6" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" +checksum = "43747c7422e2924c11144d5229878b98180ef8b06cca4ab5af37afc8a8d8ea3e" dependencies = [ - "libc", "zstd-sys", ] diff --git a/Cargo.toml b/Cargo.toml index bdd3f1b..75df059 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ name = "console" actix-web = "4.3.1" chrono = { version = "0.4.26", features = ["time", "serde"] } config = "0.13.3" -reqwest = { version = "0.11.17", features = ["json"] } +reqwest = { version = "0.11.17", features = ["json", "blocking"] } serde = { version = "1.0.162", features = ["derive"] } tokio = { version = "1.28.1", features = ["full"] } tracing = { version = "0.1.37", features = ["log"] } @@ -30,7 +30,7 @@ tracing-log = "0.1.3" tracing-subscriber = { version = "0.3.17", features = ["registry", "env-filter"] } uuid = { version = "1.3.4", features = ["v4", "serde"] } thiserror = "1.0" -serde_valid = "0.16.3" +serde_valid = { version = "0.17.0", features = [] } serde_json = { version = "1.0.105", features = [] } serde_derive = "1.0.188" actix-web-httpauth = "0.8.1" diff --git a/scripts/init_db.sh b/scripts/init_db.sh index 8d84403..06693cd 100755 --- a/scripts/init_db.sh +++ b/scripts/init_db.sh @@ -38,4 +38,5 @@ export DATABASE_URL=postgres://${DB_USER}:${DB_PASSWORD}@localhost:${DB_PORT}/${ sqlx database create sqlx migrate run ->&2 echo "Postgres has been migrated, ready to go!" \ No newline at end of file +>&2 echo "Postgres has been migrated, ready to go!" + diff --git a/src/forms/stack.rs b/src/forms/stack.rs index 205aae3..16c3164 100644 --- a/src/forms/stack.rs +++ b/src/forms/stack.rs @@ -1,7 +1,6 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use serde_valid::Validate; -use std::collections::HashMap; use std::fmt; use crate::helpers::{login, docker_image_exists}; use tokio::runtime::Runtime; @@ -34,21 +33,23 @@ pub struct Port { #[validate(pattern = r"^\d+$")] pub host_port: Option, #[validate(pattern = r"^\d+$")] - pub container_port: Option, + pub container_port: String, #[validate(enumerate("tcp", "udp"))] pub protocol: Option } -fn validate_dockerhub_image(docker_image: DockerImage) -> Result<(), serde_valid::validation::Error> { +fn validate_dockerhub_image(dockerhub: &DockerImage) -> Result<(), serde_valid::validation::Error> { + println!("validate dockerhub image {:?}", dockerhub); + tracing::debug!("Validate image at hub.docker.com..."); // Create the runtime let rt = Runtime::new().unwrap(); // Spawn a blocking function onto the runtime rt.block_on(async { let result = login( - docker_image.dockerhub_user.clone().unwrap_or("".to_string()).as_ref(), - docker_image.dockerhub_password.clone().unwrap_or("".to_string()).as_ref() + dockerhub.dockerhub_user.clone().unwrap_or("".to_string()).as_ref(), + dockerhub.dockerhub_password.clone().unwrap_or("".to_string()).as_ref() ) .await .map_err(|err| serde_valid::validation::Error::Custom(format!("{:?}", err)))?; @@ -63,8 +64,8 @@ fn validate_dockerhub_image(docker_image: DockerImage) -> Result<(), serde_valid tracing::debug!("We were able to login hub.docker.com!"); docker_image_exists( - docker_image.dockerhub_user.clone().unwrap().as_str(), - docker_image.dockerhub_name.clone().unwrap().as_str(), tok) + dockerhub.dockerhub_user.clone().unwrap().as_str(), + dockerhub.dockerhub_name.clone().unwrap().as_str(), tok) .await .map_err(|err| serde_valid::validation::Error::Custom("Not exists".to_string())) .map(|_| ()) @@ -73,7 +74,7 @@ fn validate_dockerhub_image(docker_image: DockerImage) -> Result<(), serde_valid }) } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -#[validate(custom(|docker_image| validate_dockerhub_image(docker_image)))] +#[validate(custom(|dockerhub|validate_dockerhub_image(dockerhub)))] pub struct DockerImage { #[validate(min_length = 3)] #[validate(max_length = 50)] diff --git a/src/helpers/dockerhub.rs b/src/helpers/dockerhub.rs index e766b16..108b438 100644 --- a/src/helpers/dockerhub.rs +++ b/src/helpers/dockerhub.rs @@ -3,25 +3,6 @@ use serde_valid::Validate; // use tracing_subscriber::fmt::format; use serde_json::Value; -// #[tokio::main] -// async fn main() -> Result<(), String> { - // tokio::select! { - // Ok(true) = docker_image_exist() => { - // println!("first branch. image exists."); - // } - // Ok(true) = docker_image_exist() => { - // println!("second branch. image exists."); - // } - // Ok(true) = docker_image_exist() => { - // println!("third branch. image exists."); - // } - // else => { - // println!("else branch. image does not exists"); - // } - // }; -// Ok(()) -// } - #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct DockerHubToken { @@ -116,9 +97,8 @@ pub async fn docker_image_exists(user: &str, repo: &str, token: String) -> Resul let active = tags.results .into_iter() .any(|tag| tag.tag_status.contains("active") ); - // println!("is active {:?}", active); Ok(active) } else { - Err(String::from("There was no active images found in this repository")) + Err(String::from("There were no active tags found in this repository")) } } diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 77b648c..84854d1 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -58,13 +58,13 @@ impl TryInto for stack::Port { type Error = String; fn try_into(self) -> Result { let cp = self.container_port.clone() - .unwrap_or("".to_string()) - .parse::().map_err(|err| "Could not parse port".to_string() )?; + .parse::().map_err(|err| "Could not parse container port".to_string() )?; let hp = self.host_port.clone() .unwrap_or("".to_string()) - .parse::().map_err(|err| "Could not parse port".to_string() )?; + .parse::().map_err(|err| "Could not parse host port".to_string() )?; tracing::debug!("Port conversion result: cp: {:?} hp: {:?}", cp, hp); + Ok(Port { target: cp, host_ip: None, diff --git a/tests/custom-stack-payload.json b/tests/custom-stack-payload.json index 574ab3c..d699f89 100644 --- a/tests/custom-stack-payload.json +++ b/tests/custom-stack-payload.json @@ -1 +1 @@ -{"commonDomain":"","domainList":{},"region":"fsn1","zone":null,"server":"cx11","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":[],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":false,"disk_type":"pd-standart","cloud_token":"****************************","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"networks":["default_network"],"web":[{"name":"MyApp","code":"myapp","domain":"myapp.com","shared_ports":[{"host_port":"80","container_port":"8080"}],"versions":[],"custom":true,"type":"web","network":["default_network"],"restart":"always","timestamp":"2024-01-15T09:47:46.580Z","_id":"lreqrvv81ifrmng39","dockerhub_user":"trydirect","dockerhub_name":"nginx-waf","environment":[{"key":"SOMEENVVAR1","value":"SOMEENVVAR_VALUE1"},{"key":"SOMEENVVAR2","value":"SOMEENVVAR_VALUE2"}],"volumes":[]}],"feature":[],"service":[],"servers_count":3,"project_git_url":"info@optimum-web.com","project_name":"Sample2024","custom_stack_code":"sample2024"}} \ No newline at end of file +{"commonDomain":"","domainList":{},"region":"fsn1","zone":null,"server":"cx11","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":[],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":false,"disk_type":"pd-standart","cloud_token":"****************************","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"networks":["default_network"],"web":[{"name":"MyApp","code":"myapp","domain":"myapp.com","shared_ports":[{"host_port":"80","container_port":"8080"}],"versions":[],"custom":true,"type":"web","network":["default_network"],"restart":"always","timestamp":"2024-01-15T09:47:46.580Z","_id":"lreqrvv81ifrmng39","dockerhub_user":"trydirect","dockerhub_name":"nginx-wafs", "dockerhub_password": "blabla", "environment":[{"key":"SOMEENVVAR1","value":"SOMEENVVAR_VALUE1"},{"key":"SOMEENVVAR2","value":"SOMEENVVAR_VALUE2"}],"volumes":[]}],"feature":[],"service":[],"servers_count":3,"project_git_url":"info@optimum-web.com","project_name":"Sample2024","custom_stack_code":"sample2024"}} \ No newline at end of file From 0431e3f349fd1297148d6c48825d05baab89982e Mon Sep 17 00:00:00 2001 From: petru Date: Wed, 17 Jan 2024 17:23:17 +0200 Subject: [PATCH 138/284] issue-auth try_into for reference --- src/forms/stack/volume.rs | 2 +- src/helpers/stack/builder.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/forms/stack/volume.rs b/src/forms/stack/volume.rs index 67263f0..b007950 100644 --- a/src/forms/stack/volume.rs +++ b/src/forms/stack/volume.rs @@ -20,7 +20,7 @@ impl Volume { } } -impl TryInto for Volume { //todo reference +impl TryInto for &Volume { type Error = String; fn try_into(self) -> Result { let source = self.host_path.clone(); diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index dd36f23..8c67ec3 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -64,7 +64,7 @@ impl TryFrom<&forms::stack::App> for Service { Some(volumes) => { let mut collector = vec![]; for volume in volumes { - collector.push(Volumes::Advanced(volume.clone().try_into()?)); + collector.push(Volumes::Advanced(volume.try_into()?)); } collector From 5c2eb32d1c2270737ad4b7386f0acea067111755 Mon Sep 17 00:00:00 2001 From: petru Date: Wed, 17 Jan 2024 17:53:33 +0200 Subject: [PATCH 139/284] issue-auth forms/stack split --- src/forms/stack/compose_networks.rs | 6 + src/forms/stack/docker_image.rs | 34 +++++ src/forms/stack/domain_list.rs | 5 + src/forms/stack/environment.rs | 7 + src/forms/stack/feature.rs | 12 ++ src/forms/stack/icon.rs | 8 ++ src/forms/stack/icon_dark.rs | 4 + src/forms/stack/icon_light.rs | 8 ++ src/forms/stack/mod.rs | 204 +++++----------------------- src/forms/stack/network.rs | 7 + src/forms/stack/price.rs | 6 + src/forms/stack/requirements.rs | 20 +++ src/forms/stack/role.rs | 7 + src/forms/stack/service.rs | 13 ++ src/forms/stack/service_networks.rs | 6 + src/forms/stack/var.rs | 6 + src/forms/stack/version.rs | 24 ++++ src/forms/stack/web.rs | 10 ++ 18 files changed, 217 insertions(+), 170 deletions(-) create mode 100644 src/forms/stack/compose_networks.rs create mode 100644 src/forms/stack/docker_image.rs create mode 100644 src/forms/stack/domain_list.rs create mode 100644 src/forms/stack/environment.rs create mode 100644 src/forms/stack/feature.rs create mode 100644 src/forms/stack/icon.rs create mode 100644 src/forms/stack/icon_dark.rs create mode 100644 src/forms/stack/icon_light.rs create mode 100644 src/forms/stack/network.rs create mode 100644 src/forms/stack/price.rs create mode 100644 src/forms/stack/requirements.rs create mode 100644 src/forms/stack/role.rs create mode 100644 src/forms/stack/service.rs create mode 100644 src/forms/stack/service_networks.rs create mode 100644 src/forms/stack/var.rs create mode 100644 src/forms/stack/version.rs create mode 100644 src/forms/stack/web.rs diff --git a/src/forms/stack/compose_networks.rs b/src/forms/stack/compose_networks.rs new file mode 100644 index 0000000..682d528 --- /dev/null +++ b/src/forms/stack/compose_networks.rs @@ -0,0 +1,6 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ComposeNetworks { + pub networks: Option>, +} diff --git a/src/forms/stack/docker_image.rs b/src/forms/stack/docker_image.rs new file mode 100644 index 0000000..b36a099 --- /dev/null +++ b/src/forms/stack/docker_image.rs @@ -0,0 +1,34 @@ +use serde::{Deserialize, Serialize}; +use serde_valid::Validate; +use std::fmt; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct DockerImage { + #[validate(min_length = 3)] + #[validate(max_length = 50)] + pub dockerhub_user: Option, + #[validate(min_length = 3)] + #[validate(max_length = 50)] + pub dockerhub_name: Option, + #[validate(min_length = 3)] + #[validate(max_length = 100)] + pub dockerhub_image: Option, +} + +impl fmt::Display for DockerImage { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let tag = "latest"; + + let dim = self.dockerhub_image.clone().unwrap_or("".to_string()); + write!( + f, + "{}/{}:{}", + self.dockerhub_user + .clone() + .unwrap_or("trydirect".to_string()) + .clone(), + self.dockerhub_name.clone().unwrap_or(dim), + tag + ) + } +} diff --git a/src/forms/stack/domain_list.rs b/src/forms/stack/domain_list.rs new file mode 100644 index 0000000..cf359ec --- /dev/null +++ b/src/forms/stack/domain_list.rs @@ -0,0 +1,5 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct DomainList {} diff --git a/src/forms/stack/environment.rs b/src/forms/stack/environment.rs new file mode 100644 index 0000000..9b6e88d --- /dev/null +++ b/src/forms/stack/environment.rs @@ -0,0 +1,7 @@ +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Environment { + pub(crate) environment: Option>>, +} diff --git a/src/forms/stack/feature.rs b/src/forms/stack/feature.rs new file mode 100644 index 0000000..8e5908c --- /dev/null +++ b/src/forms/stack/feature.rs @@ -0,0 +1,12 @@ +use serde::{Deserialize, Serialize}; +use crate::forms::stack::*; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Feature { + // #[serde(rename(deserialize = "sharedPorts"))] + // #[serde(rename(serialize = "shared_ports"))] + // #[serde(alias = "shared_ports")] + // pub shared_ports: Option>, + #[serde(flatten)] + pub app: App, +} diff --git a/src/forms/stack/icon.rs b/src/forms/stack/icon.rs new file mode 100644 index 0000000..0bcae01 --- /dev/null +++ b/src/forms/stack/icon.rs @@ -0,0 +1,8 @@ +use serde::{Deserialize, Serialize}; +use crate::forms::stack::*; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Icon { + pub light: IconLight, + pub dark: IconDark, +} diff --git a/src/forms/stack/icon_dark.rs b/src/forms/stack/icon_dark.rs new file mode 100644 index 0000000..73c543e --- /dev/null +++ b/src/forms/stack/icon_dark.rs @@ -0,0 +1,4 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct IconDark {} diff --git a/src/forms/stack/icon_light.rs b/src/forms/stack/icon_light.rs new file mode 100644 index 0000000..8e9e4b8 --- /dev/null +++ b/src/forms/stack/icon_light.rs @@ -0,0 +1,8 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct IconLight { + pub width: i64, + pub height: i64, + pub image: String, +} diff --git a/src/forms/stack/mod.rs b/src/forms/stack/mod.rs index 2ea7aa0..94d1950 100644 --- a/src/forms/stack/mod.rs +++ b/src/forms/stack/mod.rs @@ -1,10 +1,3 @@ -use serde::{Deserialize, Serialize}; -use serde_json::Value; -use serde_valid::Validate; -use std::collections::HashMap; -use std::fmt; -use crate::forms; - mod app; mod custom; mod form; @@ -12,6 +5,23 @@ mod port; mod payload; mod volumes; mod volume; +mod role; +mod requirements; +mod docker_image; +mod domain_list; +mod var; +mod price; +mod network; +mod environment; +mod service_networks; +mod compose_networks; +mod web; +mod feature; +mod service; +mod icon; +mod icon_light; +mod icon_dark; +mod version; pub use app::*; pub use custom::*; @@ -20,166 +30,20 @@ pub use port::*; pub use payload::*; pub use volumes::*; pub use volume::*; - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Role { - pub role: Option>, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Requirements { - #[validate(min_length = 1)] - #[validate(max_length = 10)] - #[validate(pattern = r"^\d+\.?[0-9]+$")] - pub cpu: Option, - #[validate(min_length = 1)] - #[validate(max_length = 10)] - #[validate(pattern = r"^\d+G$")] - #[serde(rename = "disk_size")] - pub disk_size: Option, - #[serde(rename = "ram_size")] - #[validate(min_length = 1)] - #[validate(max_length = 10)] - #[validate(pattern = r"^\d+G$")] - pub ram_size: Option, -} - - -// #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -// pub struct Ports { -// #[serde(rename(deserialize = "sharedPorts"))] -// #[serde(rename(serialize = "shared_ports"))] -// // #[serde(alias = "shared_ports")] -// pub shared_ports: Option>, -// pub ports: Option>, -// } - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct DockerImage { - #[validate(min_length = 3)] - #[validate(max_length = 50)] - pub dockerhub_user: Option, - #[validate(min_length = 3)] - #[validate(max_length = 50)] - pub dockerhub_name: Option, - #[validate(min_length = 3)] - #[validate(max_length = 100)] - pub dockerhub_image: Option, -} - -impl fmt::Display for DockerImage { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let tag = "latest"; - - let dim = self.dockerhub_image.clone().unwrap_or("".to_string()); - write!( - f, - "{}/{}:{}", - self.dockerhub_user - .clone() - .unwrap_or("trydirect".to_string()) - .clone(), - self.dockerhub_name.clone().unwrap_or(dim), - tag - ) - } -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct DomainList {} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct Var {} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Price { - pub value: f64, -} -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Network { - name: String, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Environment { - pub(crate) environment: Option>>, -} - -// pub(crate) type Networks = Option>; -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct ServiceNetworks { - pub network: Option>, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct ComposeNetworks { - pub networks: Option>, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Web { - #[serde(flatten)] - pub app: forms::stack::App, - pub custom: Option, - pub main: bool, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Feature { - // #[serde(rename(deserialize = "sharedPorts"))] - // #[serde(rename(serialize = "shared_ports"))] - // #[serde(alias = "shared_ports")] - // pub shared_ports: Option>, - #[serde(flatten)] - pub app: forms::stack::App, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Service { - // #[serde(rename(deserialize = "sharedPorts"))] - // #[serde(rename(serialize = "shared_ports"))] - // #[serde(alias = "shared_ports")] - // pub shared_ports: Option>, - #[serde(flatten)] - pub(crate) app: forms::stack::App, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Icon { - pub light: IconLight, - pub dark: IconDark, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct IconLight { - pub width: i64, - pub height: i64, - pub image: String, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct IconDark {} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Version { - #[serde(rename = "_etag")] - pub etag: Option, - #[serde(rename = "_id")] - pub id: u32, - #[serde(rename = "_created")] - pub created: Option, - #[serde(rename = "_updated")] - pub updated: Option, - pub app_id: Option, - pub name: String, - #[validate(min_length = 3)] - #[validate(max_length = 20)] - pub version: String, - #[serde(rename = "update_status")] - pub update_status: Option, - #[validate(min_length = 3)] - #[validate(max_length = 20)] - pub tag: String, -} +pub use role::*; +pub use requirements::*; +pub use docker_image::*; +pub use domain_list::*; +pub use var::*; +pub use price::*; +pub use network::*; +pub use environment::*; +pub use service_networks::*; +pub use compose_networks::*; +pub use web::*; +pub use feature::*; +pub use service::*; +pub use icon::*; +pub use icon_light::*; +pub use icon_dark::*; +pub use version::*; diff --git a/src/forms/stack/network.rs b/src/forms/stack/network.rs new file mode 100644 index 0000000..44a4970 --- /dev/null +++ b/src/forms/stack/network.rs @@ -0,0 +1,7 @@ +use serde::{Deserialize, Serialize}; +use serde_valid::Validate; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct Network { + name: String, +} diff --git a/src/forms/stack/price.rs b/src/forms/stack/price.rs new file mode 100644 index 0000000..06bbaee --- /dev/null +++ b/src/forms/stack/price.rs @@ -0,0 +1,6 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Price { + pub value: f64, +} diff --git a/src/forms/stack/requirements.rs b/src/forms/stack/requirements.rs new file mode 100644 index 0000000..02e6891 --- /dev/null +++ b/src/forms/stack/requirements.rs @@ -0,0 +1,20 @@ +use serde::{Deserialize, Serialize}; +use serde_valid::Validate; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct Requirements { + #[validate(min_length = 1)] + #[validate(max_length = 10)] + #[validate(pattern = r"^\d+\.?[0-9]+$")] + pub cpu: Option, + #[validate(min_length = 1)] + #[validate(max_length = 10)] + #[validate(pattern = r"^\d+G$")] + #[serde(rename = "disk_size")] + pub disk_size: Option, + #[serde(rename = "ram_size")] + #[validate(min_length = 1)] + #[validate(max_length = 10)] + #[validate(pattern = r"^\d+G$")] + pub ram_size: Option, +} diff --git a/src/forms/stack/role.rs b/src/forms/stack/role.rs new file mode 100644 index 0000000..5f5406a --- /dev/null +++ b/src/forms/stack/role.rs @@ -0,0 +1,7 @@ +use serde::{Deserialize, Serialize}; +use serde_valid::Validate; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct Role { + pub role: Option>, +} diff --git a/src/forms/stack/service.rs b/src/forms/stack/service.rs new file mode 100644 index 0000000..1470233 --- /dev/null +++ b/src/forms/stack/service.rs @@ -0,0 +1,13 @@ +use serde::{Deserialize, Serialize}; +use serde_valid::Validate; +use crate::forms::stack::*; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct Service { + // #[serde(rename(deserialize = "sharedPorts"))] + // #[serde(rename(serialize = "shared_ports"))] + // #[serde(alias = "shared_ports")] + // pub shared_ports: Option>, + #[serde(flatten)] + pub(crate) app: App, +} diff --git a/src/forms/stack/service_networks.rs b/src/forms/stack/service_networks.rs new file mode 100644 index 0000000..de586f8 --- /dev/null +++ b/src/forms/stack/service_networks.rs @@ -0,0 +1,6 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ServiceNetworks { + pub network: Option>, +} diff --git a/src/forms/stack/var.rs b/src/forms/stack/var.rs new file mode 100644 index 0000000..2072147 --- /dev/null +++ b/src/forms/stack/var.rs @@ -0,0 +1,6 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Var {} + diff --git a/src/forms/stack/version.rs b/src/forms/stack/version.rs new file mode 100644 index 0000000..9e7dfb3 --- /dev/null +++ b/src/forms/stack/version.rs @@ -0,0 +1,24 @@ +use serde::{Deserialize, Serialize}; +use serde_valid::Validate; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct Version { + #[serde(rename = "_etag")] + pub etag: Option, + #[serde(rename = "_id")] + pub id: u32, + #[serde(rename = "_created")] + pub created: Option, + #[serde(rename = "_updated")] + pub updated: Option, + pub app_id: Option, + pub name: String, + #[validate(min_length = 3)] + #[validate(max_length = 20)] + pub version: String, + #[serde(rename = "update_status")] + pub update_status: Option, + #[validate(min_length = 3)] + #[validate(max_length = 20)] + pub tag: String, +} diff --git a/src/forms/stack/web.rs b/src/forms/stack/web.rs new file mode 100644 index 0000000..776ea0a --- /dev/null +++ b/src/forms/stack/web.rs @@ -0,0 +1,10 @@ +use serde::{Deserialize, Serialize}; +use crate::forms::stack::*; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Web { + #[serde(flatten)] + pub app: App, + pub custom: Option, + pub main: bool, +} From 2952f3b1203ec221c1e11b2042cf2143e867d28f Mon Sep 17 00:00:00 2001 From: petru Date: Wed, 17 Jan 2024 18:17:54 +0200 Subject: [PATCH 140/284] issue-auth builder_config --- src/forms/stack/app.rs | 53 ++++++++++++ src/forms/stack/compose_networks.rs | 35 ++++++++ src/forms/stack/service_networks.rs | 16 ++++ src/helpers/stack/builder.rs | 127 ++-------------------------- src/helpers/stack/builder_config.rs | 9 ++ src/helpers/stack/mod.rs | 3 + 6 files changed, 122 insertions(+), 121 deletions(-) create mode 100644 src/helpers/stack/builder_config.rs diff --git a/src/forms/stack/app.rs b/src/forms/stack/app.rs index f38a81f..6e1f356 100644 --- a/src/forms/stack/app.rs +++ b/src/forms/stack/app.rs @@ -104,3 +104,56 @@ impl AsRef for App { &self.docker_image } } + +impl TryFrom<&App> for dctypes::Service { + type Error = String; + + fn try_from(app: &App) -> Result { + let mut service = dctypes::Service { + image: Some(app.docker_image.to_string()), + ..Default::default() + }; + + let networks = dctypes::Networks::try_from(&app.network).unwrap_or_default(); + let ports: Vec = match &app.ports { + Some(ports) => { + let mut collector = vec![]; + for port in ports { + collector.push(port.try_into()?); + } + collector + } + None => vec![] + }; + + let volumes: Vec = match &app.volumes { + Some(volumes) => { + let mut collector = vec![]; + for volume in volumes { + collector.push(dctypes::Volumes::Advanced(volume.try_into()?)); + } + + collector + }, + None => vec![] + }; + + let mut envs = IndexMap::new(); + for item in app.environment.environment.clone().unwrap_or_default() { + let items = item + .into_iter() + .map(|(k, v)| (k, Some(dctypes::SingleValue::String(v.clone())))) + .collect::>(); + + envs.extend(items); + } + + service.networks = networks; + service.ports = dctypes::Ports::Long(ports); + service.restart = Some("always".to_owned()); + service.volumes = volumes; + service.environment = dctypes::Environment::KvPair(envs); + + Ok(service) + } +} diff --git a/src/forms/stack/compose_networks.rs b/src/forms/stack/compose_networks.rs index 682d528..0dec3bf 100644 --- a/src/forms/stack/compose_networks.rs +++ b/src/forms/stack/compose_networks.rs @@ -1,6 +1,41 @@ use serde::{Deserialize, Serialize}; +use docker_compose_types as dctypes; +use indexmap::IndexMap; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct ComposeNetworks { pub networks: Option>, } + +impl Into>> for ComposeNetworks { + fn into(self) -> IndexMap> { + let mut networks = vec!["default_network".to_string()]; + if self.networks.is_some() { + networks.append(&mut self.networks.unwrap()); + } + let networks = networks + .into_iter() + .map(|net| { + ( + net, + dctypes::MapOrEmpty::Map(dctypes::NetworkSettings { + attachable: false, + driver: None, + driver_opts: Default::default(), + enable_ipv6: false, + internal: false, + // external: None, + external: Some(dctypes::ComposeNetwork::Bool(true)), + ipam: None, + labels: Default::default(), + name: Some("default".to_string()), + }), + ) + }) + .collect::>(); + + tracing::debug!("networks collected {:?}", &networks); + + networks + } +} diff --git a/src/forms/stack/service_networks.rs b/src/forms/stack/service_networks.rs index de586f8..55c729e 100644 --- a/src/forms/stack/service_networks.rs +++ b/src/forms/stack/service_networks.rs @@ -1,6 +1,22 @@ use serde::{Deserialize, Serialize}; +use docker_compose_types as dctypes; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct ServiceNetworks { pub network: Option>, } + +impl TryFrom<&ServiceNetworks> for dctypes::Networks { + type Error = (); + + fn try_from(service_networks: &ServiceNetworks) -> Result { + let mut result = vec!["default_network".to_string()]; + service_networks.network.as_ref().map(|networks| { + for n in networks { + result.push(n.to_string()); + } + }); + + Ok(dctypes::Networks::Simple(result)) + } +} diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 8c67ec3..9e7daa2 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -1,20 +1,8 @@ use crate::forms; -use docker_compose_types::{ - AdvancedVolumes, Compose, ComposeNetwork, ComposeNetworkSettingDetails, ComposeNetworks, - ComposeVolume, Entrypoint, Environment, MapOrEmpty, NetworkSettings, Networks, Port, Ports, - PublishedPort, Service, Services, SingleValue, TopLevelVolumes, Volumes, -}; +use docker_compose_types as dctypes; use crate::models; -use indexmap::IndexMap; use serde_yaml; -#[derive(Clone, Debug)] -struct Config {} - -impl Default for Config { - fn default() -> Self { - Config {} - } -} +use crate::helpers::stack::*; /// A builder for constructing docker compose. #[derive(Clone, Debug)] @@ -23,109 +11,6 @@ pub struct DcBuilder { pub(crate) stack: models::Stack, } -impl TryFrom<&forms::stack::ServiceNetworks> for Networks { - type Error = (); - - fn try_from(service_networks: &forms::stack::ServiceNetworks) -> Result { - let mut result = vec!["default_network".to_string()]; - service_networks.network.as_ref().map(|networks| { - for n in networks { - result.push(n.to_string()); - } - }); - - Ok(Networks::Simple(result)) - } -} - - -impl TryFrom<&forms::stack::App> for Service { - type Error = String; - - fn try_from(app: &forms::stack::App) -> Result { - let mut service = Service { - image: Some(app.docker_image.to_string()), - ..Default::default() - }; - - let networks = Networks::try_from(&app.network).unwrap_or_default(); - let ports: Vec = match &app.ports { - Some(ports) => { - let mut collector = vec![]; - for port in ports { - collector.push(port.try_into()?); - } - collector - } - None => vec![] - }; - - let volumes: Vec = match &app.volumes { - Some(volumes) => { - let mut collector = vec![]; - for volume in volumes { - collector.push(Volumes::Advanced(volume.try_into()?)); - } - - collector - }, - None => vec![] - }; - - let mut envs = IndexMap::new(); - for item in app.environment.environment.clone().unwrap_or_default() { - let items = item - .into_iter() - .map(|(k, v)| (k, Some(SingleValue::String(v.clone())))) - .collect::>(); - - envs.extend(items); - } - - service.networks = networks; - service.ports = Ports::Long(ports); - service.restart = Some("always".to_owned()); - service.volumes = volumes; - service.environment = Environment::KvPair(envs); - - Ok(service) - } -} - -impl Into>> for forms::stack::ComposeNetworks { - fn into(self) -> IndexMap> { - // tracing::debug!("networks found {:?}", self.networks); - let mut networks = vec!["default_network".to_string()]; - if self.networks.is_some() { - networks.append(&mut self.networks.unwrap()); - } - let networks = networks - .into_iter() - .map(|net| { - ( - net, - MapOrEmpty::Map(NetworkSettings { - attachable: false, - driver: None, - driver_opts: Default::default(), - enable_ipv6: false, - internal: false, - // external: None, - external: Some(ComposeNetwork::Bool(true)), - ipam: None, - labels: Default::default(), - name: Some("default".to_string()), - }), - ) - }) - .collect::>(); - - tracing::debug!("networks collected {:?}", &networks); - - networks - } -} - impl DcBuilder { pub fn new(stack: models::Stack) -> Self { DcBuilder { @@ -136,7 +21,7 @@ impl DcBuilder { #[tracing::instrument(name = "building stack")] pub fn build(&self) -> Result { - let mut compose_content = Compose { + let mut compose_content = dctypes::Compose { version: Some("3.8".to_string()), ..Default::default() }; @@ -146,14 +31,14 @@ impl DcBuilder { let named_volumes = apps.custom.named_volumes()?; let networks = apps.custom.networks.clone(); - compose_content.networks = ComposeNetworks(networks.into()); + compose_content.networks = dctypes::ComposeNetworks(networks.into()); if !named_volumes.is_empty() { - compose_content.volumes = TopLevelVolumes(named_volumes); + compose_content.volumes = dctypes::TopLevelVolumes(named_volumes); } tracing::debug!("services {:?}", &services); - compose_content.services = Services(services); + compose_content.services = dctypes::Services(services); let fname = format!("./files/{}.yml", self.stack.stack_id); tracing::debug!("Saving docker compose to file {:?}", fname); diff --git a/src/helpers/stack/builder_config.rs b/src/helpers/stack/builder_config.rs new file mode 100644 index 0000000..7f50a24 --- /dev/null +++ b/src/helpers/stack/builder_config.rs @@ -0,0 +1,9 @@ +#[derive(Clone, Debug)] +pub struct Config {} + +impl Default for Config { + fn default() -> Self { + Config {} + } +} + diff --git a/src/helpers/stack/mod.rs b/src/helpers/stack/mod.rs index 9b5530b..72ce537 100644 --- a/src/helpers/stack/mod.rs +++ b/src/helpers/stack/mod.rs @@ -1 +1,4 @@ pub(crate) mod builder; +mod builder_config; + +pub use builder_config::*; From d557aa3d683871e88fda806b0796d3b1e6cc3729 Mon Sep 17 00:00:00 2001 From: vsilent Date: Wed, 17 Jan 2024 22:00:19 +0200 Subject: [PATCH 141/284] broken, dockerhub validator --- Cargo.lock | 12 +- Cargo.toml | 18 +-- src/forms/stack.rs | 198 ++++++++++++++++++++++++-------- src/helpers/dockerhub.rs | 44 ++++++- src/helpers/stack/builder.rs | 2 +- src/routes/stack/add.rs | 3 + src/routes/stack/update.rs | 14 +-- tests/app.json | 2 +- tests/custom-stack-payload.json | 2 +- tests/web-item.json | 2 +- 10 files changed, 222 insertions(+), 75 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6bc8dd8..ff8780b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2823,9 +2823,9 @@ dependencies = [ [[package]] name = "serde_valid" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ede56947572525b2c9640542edfa35bbc2f575fa03f97d4d68e9eb4e4c5136b" +checksum = "70c0e00fab6460447391a1981c21341746bc2d0178a7c46a3bbf667f450ac6e4" dependencies = [ "indexmap 2.1.0", "itertools", @@ -2843,9 +2843,9 @@ dependencies = [ [[package]] name = "serde_valid_derive" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79ffdd7f3a5dea22dc86747bc02f5292a091977383c0124e7d77fc4fd120c486" +checksum = "88c60a851514741a6088b2cd18eefb3f0d02ff3a1c87234de47153f2724d395d" dependencies = [ "paste", "proc-macro-error", @@ -2857,9 +2857,9 @@ dependencies = [ [[package]] name = "serde_valid_literal" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be811ca7379637055f6474a1c0d0ed985c86966e580279ec980f77816b8f41b0" +checksum = "aced4f1b31605a2b55eeacf2ec4dcbd96583263e9ded17eed1d41ab75915d12e" dependencies = [ "paste", "regex", diff --git a/Cargo.toml b/Cargo.toml index 75df059..0fdf112 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,20 +19,20 @@ name = "console" [dependencies] actix-web = "4.3.1" -chrono = { version = "0.4.26", features = ["time", "serde"] } -config = "0.13.3" -reqwest = { version = "0.11.17", features = ["json", "blocking"] } -serde = { version = "1.0.162", features = ["derive"] } +chrono = { version = "0.4.29", features = ["time", "serde"] } +config = "0.13.4" +reqwest = { version = "0.11.23", features = ["json", "blocking"] } +serde = { version = "1.0.195", features = ["derive"] } tokio = { version = "1.28.1", features = ["full"] } tracing = { version = "0.1.37", features = ["log"] } tracing-bunyan-formatter = "0.3.8" -tracing-log = "0.1.3" -tracing-subscriber = { version = "0.3.17", features = ["registry", "env-filter"] } +tracing-log = "0.1.4" +tracing-subscriber = { version = "0.3.18", features = ["registry", "env-filter"] } uuid = { version = "1.3.4", features = ["v4", "serde"] } thiserror = "1.0" -serde_valid = { version = "0.17.0", features = [] } -serde_json = { version = "1.0.105", features = [] } -serde_derive = "1.0.188" +serde_valid = "0.18.0" +serde_json = { version = "1.0.111", features = [] } +serde_derive = "1.0.195" actix-web-httpauth = "0.8.1" actix-cors = "0.6.4" tracing-actix-web = "0.7.7" diff --git a/src/forms/stack.rs b/src/forms/stack.rs index 16c3164..b799125 100644 --- a/src/forms/stack.rs +++ b/src/forms/stack.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use serde_valid::Validate; use std::fmt; -use crate::helpers::{login, docker_image_exists}; +use crate::helpers::{login, docker_image_exists, DockerHubCreds, DockerHubToken}; use tokio::runtime::Runtime; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] @@ -25,54 +25,156 @@ pub struct Requirements { #[validate(min_length = 1)] #[validate(max_length = 10)] #[validate(pattern = r"^\d+G$")] - pub ram_size: Option, + pub ram_size: Option } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Port { - #[validate(pattern = r"^\d+$")] + #[validate(pattern = r"^\d{2,6}+$")] pub host_port: Option, - #[validate(pattern = r"^\d+$")] + #[validate(pattern = r"^\d{2,6}+$")] pub container_port: String, #[validate(enumerate("tcp", "udp"))] pub protocol: Option } -fn validate_dockerhub_image(dockerhub: &DockerImage) -> Result<(), serde_valid::validation::Error> { +// fn validate_dockerhub_image(docker_image: &DockerImage) -> Result<(), serde_valid::validation::Error> { +// +// +// let rt = Runtime::new().unwrap(); +// +// // Spawn a blocking function onto the runtime +// rt.block_on(async { +// let client = reqwest::Client::new(); +// let dockerhub_api_url = format!( +// "https://hub.docker.com/v2/repositories/{}/{}", +// docker_image.dockerhub_user.as_ref().unwrap(), +// docker_image.dockerhub_name.as_ref().unwrap() +// ); +// +// let response = client.get(&dockerhub_api_url) +// .send() +// .await; +// +// match response { +// Ok(resp) => { +// if resp.status().is_success() { +// Ok(()) +// } else { +// Err(serde_valid::validation::Error::Custom("Not exists".to_string())) +// } +// }, +// Err(_) => Err(serde_valid::validation::Error::Custom("Not exists".to_string())) +// } +// }) +// } - println!("validate dockerhub image {:?}", dockerhub); + +fn validate_dockerhub_image(docker_image: &DockerImage) -> Result<(), serde_valid::validation::Error> { + println!("validate dockerhub image {:?}", docker_image); tracing::debug!("Validate image at hub.docker.com..."); - // Create the runtime - let rt = Runtime::new().unwrap(); - - // Spawn a blocking function onto the runtime - rt.block_on(async { - let result = login( - dockerhub.dockerhub_user.clone().unwrap_or("".to_string()).as_ref(), - dockerhub.dockerhub_password.clone().unwrap_or("".to_string()).as_ref() - ) - .await - .map_err(|err| serde_valid::validation::Error::Custom(format!("{:?}", err)))?; - - match result.token { - None => { - return Err(serde_valid::validation::Error::Custom( - "Could not access docker image repository, please check credentials.".to_owned(), - )); - }, - Some(tok) => { - - tracing::debug!("We were able to login hub.docker.com!"); - docker_image_exists( - dockerhub.dockerhub_user.clone().unwrap().as_str(), - dockerhub.dockerhub_name.clone().unwrap().as_str(), tok) - .await - .map_err(|err| serde_valid::validation::Error::Custom("Not exists".to_string())) - .map(|_| ()) - } - } - }) + + let endpoint = "https://hub.docker.com/v2/users/login"; + let creds = DockerHubCreds { + username: docker_image.dockerhub_user.as_ref().unwrap(), + password: docker_image.dockerhub_password.as_ref().unwrap() + }; + let client = reqwest::blocking::Client::new(); + client.post(endpoint) + .json(&creds) + .send() + .map_err(|err| serde_valid::validation::Error::Custom(format!("{:?}", err)))? + .json::() + .map_err(|err| serde_valid::validation::Error::Custom(format!("{:?}", err))) + .and_then(|token| { + tracing::debug!("got token {:?}", token); + Ok(()) + }) } + +// +// fn validate_dockerhub_image(docker_image: &DockerImage) -> Result<(), serde_valid::validation::Error> { +// +// println!("validate dockerhub image {:?}", docker_image); +// tracing::debug!("Validate image at hub.docker.com..."); +// +// let endpoint = "https://hub.docker.com/v2/users/login"; +// let creds = DockerHubCreds { +// username: docker_image.dockerhub_user.as_ref().unwrap(), +// password: docker_image.dockerhub_password.as_ref().unwrap() +// }; +// reqwest::blocking::Client::new() +// .post(endpoint) +// .json(&creds) +// .send() +// .map_err(|err| serde_valid::validation::Error::Custom(format!("{:?}", err)))? +// .json::() +// .map_err(|err| serde_valid::validation::Error::Custom(format!("{:?}", err))) +// .and_then(|token|{ +// tracing::debug!("got token {:?}", token); +// Ok(()) +// }) +// +// +// +// // Create the runtime +// // let rt = Runtime::new().unwrap(); +// // +// // // Spawn a blocking function onto the runtime +// // rt.block_on(async { +// // let result = login( +// // docker_image.dockerhub_user.clone().unwrap_or("".to_string()).as_ref(), +// // docker_image.dockerhub_password.clone().unwrap_or("".to_string()).as_ref() +// // ) +// // .await +// // .map_err(|err| serde_valid::validation::Error::Custom(format!("{:?}", err)))?; +// // +// // match result.token { +// // None => { +// // return Err(serde_valid::validation::Error::Custom( +// // "Could not access docker image repository, please check credentials.".to_owned(), +// // )); +// // }, +// // Some(tok) => { +// // tracing::debug!("We were able to login hub.docker.com!"); +// // docker_image_exists( +// // docker_image.dockerhub_user.clone().unwrap().as_str(), +// // docker_image.dockerhub_name.clone().unwrap().as_str(), tok) +// // .await +// // .map_err(|err| serde_valid::validation::Error::Custom("Not exists".to_string())) +// // .map(|_| ()) +// // } +// // } +// // }) +// +// } + +// fn validate_dockerhub_image(docker_image: &DockerImage) -> Result<(), serde_valid::validation::Error> { +// +// tracing::debug!("validate dockerhub image {:?}", docker_image); +// let endpoint = "https://hub.docker.com/v2/users/login"; +// let creds = DockerHubCreds { +// username: docker_image.dockerhub_user.as_ref().unwrap(), +// password: docker_image.dockerhub_password.as_ref().unwrap() +// }; +// reqwest::blocking::Client::new() +// .post(endpoint) +// .json(&creds) +// .send() +// .map_err(|err| serde_valid::validation::Error::Custom(format!("{:?}", err)))? +// .json::() +// .map_err(|err| serde_valid::validation::Error::Custom(format!("{:?}", err))) +// .and_then(|token|{ +// docker_image_exists( +// docker_image.dockerhub_user.clone().unwrap().as_str(), +// docker_image.dockerhub_name.clone().unwrap().as_str(), +// token +// ) +// .map_err(|err| serde_valid::validation::Error::Custom("Not exists".to_string())) +// .map(|_| ()) +// }) +// } + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] #[validate(custom(|dockerhub|validate_dockerhub_image(dockerhub)))] pub struct DockerImage { @@ -86,8 +188,6 @@ pub struct DockerImage { pub dockerhub_name: Option, #[validate(min_length = 3)] #[validate(max_length = 100)] - #[validate(pattern = r"^(?:(?=[^:\/]{1,253})(?!-)[a-zA-Z0-9-]{1,63}(?, pub dockerhub_password: Option, } @@ -117,8 +217,7 @@ impl AsRef for App { #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct StackForm { - // #[validate(min_length=2)] - // #[validate(max_length=255)] + #[validate(max_length=255)] #[serde(rename = "commonDomain")] pub common_domain: Option, pub domain_list: Option, @@ -158,6 +257,7 @@ pub struct StackForm { #[validate(min_length = 3)] #[validate(max_length = 50)] pub selected_plan: String, + #[validate] pub custom: Custom, } @@ -209,8 +309,11 @@ pub struct Price { } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Custom { + #[validate] pub web: Vec, + #[validate] pub feature: Option>, + #[validate] pub service: Option>, #[validate(minimum = 0)] #[validate(maximum = 10)] @@ -265,8 +368,10 @@ pub struct App { pub default: Option, pub versions: Option>, #[serde(flatten)] + #[validate] pub docker_image: DockerImage, #[serde(flatten)] + #[validate] pub requirements: Requirements, #[validate(minimum = 1)] pub popularity: Option, @@ -296,10 +401,8 @@ pub struct App { pub environment: Environment, #[serde(flatten)] pub network: ServiceNetworks, - #[serde(rename(deserialize = "sharedPorts"))] - #[serde(rename(serialize = "shared_ports"))] - #[serde(alias = "shared_ports")] - pub ports: Option>, + #[validate] + pub shared_ports: Option>, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -334,23 +437,26 @@ pub struct ComposeNetworks { pub networks: Option>, } -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Web { #[serde(flatten)] + #[validate] pub app: App, pub custom: Option, pub main: Option, } -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Feature { #[serde(flatten)] + #[validate] pub app: App, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Service { #[serde(flatten)] + #[validate] pub(crate) app: App, } diff --git a/src/helpers/dockerhub.rs b/src/helpers/dockerhub.rs index 108b438..15bc6c9 100644 --- a/src/helpers/dockerhub.rs +++ b/src/helpers/dockerhub.rs @@ -11,8 +11,8 @@ pub struct DockerHubToken { #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct DockerHubCreds<'a> { - username: &'a str, - password: &'a str + pub(crate) username: &'a str, + pub(crate) password: &'a str } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] @@ -102,3 +102,43 @@ pub async fn docker_image_exists(user: &str, repo: &str, token: String) -> Resul Err(String::from("There were no active tags found in this repository")) } } + +// pub fn docker_image_exists(user: &str, repo: &str, token: DockerHubToken) -> Result { +// // get repo images +// let tags_url = format!("https://hub.docker.com/v2/namespaces/{}/repositories/{}/tags", +// user, repo); +// // +// // let tags = reqwest::Client::new() +// // .get(tags_url) +// // .header("Accept", "application/json") +// // .bearer_auth(token) +// // .send() +// // .await +// // .map_err(|err| format!("{}", err))? +// // .json::() +// // // .json::() +// // .await +// // .map_err(|err| format!("{}", err))?; +// +// reqwest::blocking::Client::new() +// .get(tags_url) +// .header("Accept", "application/json") +// .bearer_auth(token.token.unwrap()) +// .send() +// .map_err(|err| serde_valid::validation::Error::Custom(format!("{:?}", err)))? +// .json::() +// .map_err(|err| serde_valid::validation::Error::Custom(format!("{:?}", err))) +// .and_then(|tags|{ +// println!("tags count: {:?}", tags.count); +// if tags.count > 0 { +// // let's find at least one active tag +// let active = tags.results +// .into_iter() +// .any(|tag| tag.tag_status.contains("active") ); +// Ok(active) +// } else { +// Err(serde_valid::validation::Error::Custom("There were no active tags found in this repository".to_string())) +// } +// }) +// +// } diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 84854d1..024bd26 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -121,7 +121,7 @@ impl TryIntoService for App { .try_into() .unwrap_or_default(); - let ports: Vec = self.ports + let ports: Vec = self.shared_ports .clone() .unwrap_or_default() .into_iter() diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index b576734..a399f01 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -55,6 +55,7 @@ async fn stack_exists(pool: &PgPool, stack_name: &String) -> Result<(), Error> { } async fn body_into_form(body: Bytes) -> Result { + tracing::debug!("Body into form ..."); let body_bytes = actix_web::body::to_bytes(body).await.unwrap(); let body_str = str::from_utf8(&body_bytes) .map_err(|_err| JsonResponse::::build().internal_server_error(_err.to_string()))?; @@ -66,6 +67,8 @@ async fn body_into_form(body: Bytes) -> Result { }) .and_then(|form: StackForm| { + + tracing::debug!("Validating form ..."); if !form.validate().is_ok() { let errors = form.validate().unwrap_err(); let err_msg = format!("Invalid data received {:?}", &errors.to_string()); diff --git a/src/routes/stack/update.rs b/src/routes/stack/update.rs index ed4d3b7..e62dd94 100644 --- a/src/routes/stack/update.rs +++ b/src/routes/stack/update.rs @@ -60,14 +60,6 @@ pub async fn update( ); let _request_span_guard = request_span.enter(); // ->exit - tracing::info!("request_id {} Updating '{}' '{}'", - request_id, - form.custom.project_name, - form.region - ); - - let query_span = tracing::info_span!("Update stack details in db."); - if !form.validate().is_ok() { let errors = form.validate().unwrap_err(); let err_msg = format!("Invalid data received {:?}", &errors.to_string()); @@ -76,6 +68,12 @@ pub async fn update( return Err(JsonResponse::::build().bad_request(errors.to_string())); } + tracing::info!("request_id {} Updating '{}' '{}'", + request_id, + form.custom.project_name, + form.region + ); + let query_span = tracing::info_span!("Update stack details in db."); let body: Value = match serde_json::to_value::(form.into_inner()) { Ok(body) => body, Err(err) => { diff --git a/tests/app.json b/tests/app.json index cb4efb1..0a37717 100644 --- a/tests/app.json +++ b/tests/app.json @@ -69,7 +69,7 @@ "links": [ ], "domain": "latestports.com", - "sharedPorts": [ + "shared_ports": [ { "host_port": "5000", "container_port": "5000" diff --git a/tests/custom-stack-payload.json b/tests/custom-stack-payload.json index d699f89..ba6de20 100644 --- a/tests/custom-stack-payload.json +++ b/tests/custom-stack-payload.json @@ -1 +1 @@ -{"commonDomain":"","domainList":{},"region":"fsn1","zone":null,"server":"cx11","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":[],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":false,"disk_type":"pd-standart","cloud_token":"****************************","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"networks":["default_network"],"web":[{"name":"MyApp","code":"myapp","domain":"myapp.com","shared_ports":[{"host_port":"80","container_port":"8080"}],"versions":[],"custom":true,"type":"web","network":["default_network"],"restart":"always","timestamp":"2024-01-15T09:47:46.580Z","_id":"lreqrvv81ifrmng39","dockerhub_user":"trydirect","dockerhub_name":"nginx-wafs", "dockerhub_password": "blabla", "environment":[{"key":"SOMEENVVAR1","value":"SOMEENVVAR_VALUE1"},{"key":"SOMEENVVAR2","value":"SOMEENVVAR_VALUE2"}],"volumes":[]}],"feature":[],"service":[],"servers_count":3,"project_git_url":"info@optimum-web.com","project_name":"Sample2024","custom_stack_code":"sample2024"}} \ No newline at end of file +{"commonDomain":"","domainList":{},"region":"fsn1","zone":null,"server":"cx11","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":[],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":false,"disk_type":"pd-standart","cloud_token":"****************************","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"networks":["default_network"],"web":[{"name":"MyApp","code":"myapp","domain":"myapp.com","shared_ports":[{"host_port":"80","container_port":""}],"versions":[],"custom":true,"type":"web","network":["default_network"],"restart":"always","timestamp":"2024-01-15T09:47:46.580Z","_id":"lreqrvv81ifrmng39","dockerhub_user":"trydirect","dockerhub_name":"nginx-wafs", "dockerhub_password": "blabla", "environment":[{"key":"SOMEENVVAR1","value":"SOMEENVVAR_VALUE1"},{"key":"SOMEENVVAR2","value":"SOMEENVVAR_VALUE2"}],"volumes":[]}],"feature":[],"service":[],"servers_count":3,"project_git_url":"info@optimum-web.com","project_name":"Sample2024","custom_stack_code":"sample2024"}} \ No newline at end of file diff --git a/tests/web-item.json b/tests/web-item.json index cb4efb1..0a37717 100644 --- a/tests/web-item.json +++ b/tests/web-item.json @@ -69,7 +69,7 @@ "links": [ ], "domain": "latestports.com", - "sharedPorts": [ + "shared_ports": [ { "host_port": "5000", "container_port": "5000" From fd4f77b7ccb7b3eee75d2f4910917a7e617f8fb0 Mon Sep 17 00:00:00 2001 From: vsilent Date: Thu, 18 Jan 2024 10:49:10 +0200 Subject: [PATCH 142/284] default_network name fix --- src/helpers/stack/builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 024bd26..7652eb7 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -187,7 +187,7 @@ impl Into>> for stack::ComposeNetwo external: Some(ComposeNetwork::Bool(true)), ipam: None, labels: Default::default(), - name: Some("default".to_string()), + name: Some("default_network".to_string()), } )) } From b5d6de7966efc36c821bd10a859b465c7f0d29ef Mon Sep 17 00:00:00 2001 From: vsilent Date: Thu, 18 Jan 2024 17:43:43 +0200 Subject: [PATCH 143/284] request to hub.docker.com --- Cargo.lock | 46 ++++++++++++++++++ Cargo.toml | 1 + src/forms/stack.rs | 83 +++++++++++++++++++++++++-------- src/helpers/dockerhub.rs | 22 +++++++-- src/main.rs | 1 + src/services/mod.rs | 2 +- tests/custom-stack-payload.json | 2 +- 7 files changed, 131 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ff8780b..4c42887 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,31 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "actix" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cba56612922b907719d4a01cf11c8d5b458e7d3dba946d0435f20f58d6795ed2" +dependencies = [ + "actix-macros", + "actix-rt", + "actix_derive", + "bitflags 2.4.1", + "bytes", + "crossbeam-channel", + "futures-core", + "futures-sink", + "futures-task", + "futures-util", + "log", + "once_cell", + "parking_lot 0.12.1", + "pin-project-lite", + "smallvec", + "tokio", + "tokio-util", +] + [[package]] name = "actix-codec" version = "0.5.1" @@ -211,6 +236,17 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "actix_derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c7db3d5a9718568e4cf4a537cfd7070e6e6ff7481510d0237fb529ac850f6d3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "addr2line" version = "0.21.0" @@ -898,6 +934,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-queue" version = "0.3.11" @@ -3081,6 +3126,7 @@ dependencies = [ name = "stacker" version = "0.1.0" dependencies = [ + "actix", "actix-cors", "actix-http", "actix-web", diff --git a/Cargo.toml b/Cargo.toml index 0fdf112..ea4b14b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,6 +54,7 @@ futures-lite = "1.13.0" clap = { version = "4.4.8", features = ["derive"] } brotli = "3.4.0" serde_path_to_error = "0.1.14" +actix = "0.13.1" [dependencies.sqlx] version = "0.6.3" diff --git a/src/forms/stack.rs b/src/forms/stack.rs index b799125..81d0f19 100644 --- a/src/forms/stack.rs +++ b/src/forms/stack.rs @@ -4,6 +4,7 @@ use serde_valid::Validate; use std::fmt; use crate::helpers::{login, docker_image_exists, DockerHubCreds, DockerHubToken}; use tokio::runtime::Runtime; +use tokio::runtime::Handle; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Role { @@ -71,27 +72,69 @@ pub struct Port { fn validate_dockerhub_image(docker_image: &DockerImage) -> Result<(), serde_valid::validation::Error> { - println!("validate dockerhub image {:?}", docker_image); + println!("validate dockerhub image {:?}", &docker_image); tracing::debug!("Validate image at hub.docker.com..."); - - let endpoint = "https://hub.docker.com/v2/users/login"; - let creds = DockerHubCreds { - username: docker_image.dockerhub_user.as_ref().unwrap(), - password: docker_image.dockerhub_password.as_ref().unwrap() - }; - let client = reqwest::blocking::Client::new(); - client.post(endpoint) - .json(&creds) - .send() - .map_err(|err| serde_valid::validation::Error::Custom(format!("{:?}", err)))? - .json::() - .map_err(|err| serde_valid::validation::Error::Custom(format!("{:?}", err))) - .and_then(|token| { - tracing::debug!("got token {:?}", token); - Ok(()) - }) + // Ok(()) + + let name = docker_image.clone().dockerhub_user.unwrap(); + let passw = docker_image.clone().dockerhub_password.unwrap(); + let repo = docker_image.clone().dockerhub_name.unwrap(); + actix_web::rt::spawn( + async move { + let result = login(name.as_ref(),passw.as_ref()).await; + match result { + Ok(token) => { + if token.token.is_some() { + tracing::debug!("we got token {:?}", token); + // while let Ok(true) = docker_image_exists( + // name.as_ref(), + // repo.as_ref(), + // token.clone().token.unwrap() + // ).await {} + + let _ = docker_image_exists( + name.as_ref(), + repo.as_ref(), + token.clone().token.unwrap() + ).await + .map_err(|err| serde_valid::validation::Error::Custom("Not exists".to_string())) + .map(|_| ()); + } + }, + Err(err) => { + tracing::debug!("no token received {}", err); + } + } + } + ); + + Ok(()) + // let rt = Runtime::new().unwrap(); + // // Spawn a blocking function onto the runtime + // let join_handle = rt.block_on( async { + // let endpoint = "https://hub.docker.com/v2/users/login"; + // let creds = DockerHubCreds { + // username: docker_image.dockerhub_user.as_ref().unwrap(), + // password: docker_image.dockerhub_password.as_ref().unwrap() + // }; + // Ok(()) + // Err(serde_valid::validation::Error::Custom(format!("Error blablablal"))) + // let client = reqwest::Client::new(); + // client.post(endpoint) + // .json(&creds) + // .send() + // .await + // .map_err(|err| serde_valid::validation::Error::Custom(format!("{:?}", err)))? + // .json::() + // .await + // .map_err(|err| serde_valid::validation::Error::Custom(format!("{:?}", err))) + // .and_then(|token| { + // tracing::debug!("got token {:?}", token); + // Ok(()) + // }) + // }); + // join_handle } - // // fn validate_dockerhub_image(docker_image: &DockerImage) -> Result<(), serde_valid::validation::Error> { // @@ -177,7 +220,7 @@ fn validate_dockerhub_image(docker_image: &DockerImage) -> Result<(), serde_vali #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] #[validate(custom(|dockerhub|validate_dockerhub_image(dockerhub)))] -pub struct DockerImage { +pub struct DockerImage { #[validate(min_length = 3)] #[validate(max_length = 50)] #[validate(pattern = r"^[a-z0-9]+([-_.][a-z0-9]+)*$")] diff --git a/src/helpers/dockerhub.rs b/src/helpers/dockerhub.rs index 15bc6c9..39ebca1 100644 --- a/src/helpers/dockerhub.rs +++ b/src/helpers/dockerhub.rs @@ -58,8 +58,9 @@ struct TagResult { } pub async fn login(username: &str, password: &str) -> Result { let endpoint = "https://hub.docker.com/v2/users/login"; + tracing::debug!("Login to {} with user {} and passw {}",endpoint, username, password); let creds = DockerHubCreds { username, password }; - let token = reqwest::Client::new() + reqwest::Client::new() .post(endpoint) .json(&creds) .send() @@ -67,11 +68,24 @@ pub async fn login(username: &str, password: &str) -> Result() .await - .map_err(|err| format!("{}", err))?; - - Ok(token) + .map_err(|err| format!("{}", err)) + .map(|token| { token }) } +// pub async fn login(username: &str, password: &str) -> Result { +// let endpoint = "https://hub.docker.com/v2/users/login"; +// let creds = DockerHubCreds { username, password }; +// reqwest::Client::new() +// .post(endpoint) +// .json(&creds) +// .send() +// .await +// .map_err(|err| serde_valid::validation::Error::Custom(format!("{}", err)))? +// .json::() +// .await +// .map_err(|err| serde_valid::validation::Error::Custom(format!("{}", err))) +// .map(|token| { token }) +// } pub async fn docker_image_exists(user: &str, repo: &str, token: String) -> Result { // get repo images diff --git a/src/main.rs b/src/main.rs index ebf4987..d64cc58 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ use stacker::startup::run; use stacker::telemetry::{get_subscriber, init_subscriber}; use std::net::TcpListener; + #[actix_web::main] async fn main() -> std::io::Result<()> { let subscriber = get_subscriber("stacker".into(), "info".into()); diff --git a/src/services/mod.rs b/src/services/mod.rs index 33c56f4..f61186f 100644 --- a/src/services/mod.rs +++ b/src/services/mod.rs @@ -1,2 +1,2 @@ -mod stack; +pub mod stack; mod rating; \ No newline at end of file diff --git a/tests/custom-stack-payload.json b/tests/custom-stack-payload.json index ba6de20..e85b469 100644 --- a/tests/custom-stack-payload.json +++ b/tests/custom-stack-payload.json @@ -1 +1 @@ -{"commonDomain":"","domainList":{},"region":"fsn1","zone":null,"server":"cx11","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":[],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":false,"disk_type":"pd-standart","cloud_token":"****************************","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"networks":["default_network"],"web":[{"name":"MyApp","code":"myapp","domain":"myapp.com","shared_ports":[{"host_port":"80","container_port":""}],"versions":[],"custom":true,"type":"web","network":["default_network"],"restart":"always","timestamp":"2024-01-15T09:47:46.580Z","_id":"lreqrvv81ifrmng39","dockerhub_user":"trydirect","dockerhub_name":"nginx-wafs", "dockerhub_password": "blabla", "environment":[{"key":"SOMEENVVAR1","value":"SOMEENVVAR_VALUE1"},{"key":"SOMEENVVAR2","value":"SOMEENVVAR_VALUE2"}],"volumes":[]}],"feature":[],"service":[],"servers_count":3,"project_git_url":"info@optimum-web.com","project_name":"Sample2024","custom_stack_code":"sample2024"}} \ No newline at end of file +{"commonDomain":"","domainList":{},"region":"fsn1","zone":null,"server":"cx11","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":[],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":false,"disk_type":"pd-standart","cloud_token":"****************************","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"networks":["default_network"],"web":[{"name":"MyApp","code":"myapp","domain":"myapp.com","shared_ports":[{"host_port":"80","container_port":"8080"}],"versions":[],"custom":true,"type":"web","network":["default_network"],"restart":"always","timestamp":"2024-01-15T09:47:46.580Z","_id":"lreqrvv81ifrmng39","dockerhub_user":"trydirect","dockerhub_name":"nginx-waf", "dockerhub_password": "", "environment":[{"key":"SOMEENVVAR1","value":"SOMEENVVAR_VALUE1"},{"key":"SOMEENVVAR2","value":"SOMEENVVAR_VALUE2"}],"volumes":[]}],"feature":[],"service":[],"servers_count":3,"project_git_url":"info@optimum-web.com","project_name":"Sample2024","custom_stack_code":"sample2024"}} \ No newline at end of file From 4770f2fa4060b22f9fdfd3d246fb03577e41045c Mon Sep 17 00:00:00 2001 From: vsilent Date: Fri, 19 Jan 2024 16:43:22 +0200 Subject: [PATCH 144/284] yet ugly but working validation --- src/forms/stack.rs | 252 ++++++++++--------------------------- src/helpers/dockerhub.rs | 201 +++++++++++++++-------------- src/routes/stack/add.rs | 4 +- src/routes/stack/update.rs | 13 +- 4 files changed, 185 insertions(+), 285 deletions(-) diff --git a/src/forms/stack.rs b/src/forms/stack.rs index 81d0f19..99c4d6b 100644 --- a/src/forms/stack.rs +++ b/src/forms/stack.rs @@ -2,9 +2,10 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use serde_valid::Validate; use std::fmt; -use crate::helpers::{login, docker_image_exists, DockerHubCreds, DockerHubToken}; -use tokio::runtime::Runtime; -use tokio::runtime::Handle; +use serde_valid::validation::error::Format::Default; +use crate::helpers::dockerhub::{DockerHub, DockerHubCreds, DockerHubToken}; +// use tokio::runtime::Runtime; +// use tokio::runtime::Handle; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Role { @@ -39,187 +40,7 @@ pub struct Port { pub protocol: Option } -// fn validate_dockerhub_image(docker_image: &DockerImage) -> Result<(), serde_valid::validation::Error> { -// -// -// let rt = Runtime::new().unwrap(); -// -// // Spawn a blocking function onto the runtime -// rt.block_on(async { -// let client = reqwest::Client::new(); -// let dockerhub_api_url = format!( -// "https://hub.docker.com/v2/repositories/{}/{}", -// docker_image.dockerhub_user.as_ref().unwrap(), -// docker_image.dockerhub_name.as_ref().unwrap() -// ); -// -// let response = client.get(&dockerhub_api_url) -// .send() -// .await; -// -// match response { -// Ok(resp) => { -// if resp.status().is_success() { -// Ok(()) -// } else { -// Err(serde_valid::validation::Error::Custom("Not exists".to_string())) -// } -// }, -// Err(_) => Err(serde_valid::validation::Error::Custom("Not exists".to_string())) -// } -// }) -// } - - -fn validate_dockerhub_image(docker_image: &DockerImage) -> Result<(), serde_valid::validation::Error> { - println!("validate dockerhub image {:?}", &docker_image); - tracing::debug!("Validate image at hub.docker.com..."); - // Ok(()) - - let name = docker_image.clone().dockerhub_user.unwrap(); - let passw = docker_image.clone().dockerhub_password.unwrap(); - let repo = docker_image.clone().dockerhub_name.unwrap(); - actix_web::rt::spawn( - async move { - let result = login(name.as_ref(),passw.as_ref()).await; - match result { - Ok(token) => { - if token.token.is_some() { - tracing::debug!("we got token {:?}", token); - // while let Ok(true) = docker_image_exists( - // name.as_ref(), - // repo.as_ref(), - // token.clone().token.unwrap() - // ).await {} - - let _ = docker_image_exists( - name.as_ref(), - repo.as_ref(), - token.clone().token.unwrap() - ).await - .map_err(|err| serde_valid::validation::Error::Custom("Not exists".to_string())) - .map(|_| ()); - } - }, - Err(err) => { - tracing::debug!("no token received {}", err); - } - } - } - ); - - Ok(()) - // let rt = Runtime::new().unwrap(); - // // Spawn a blocking function onto the runtime - // let join_handle = rt.block_on( async { - // let endpoint = "https://hub.docker.com/v2/users/login"; - // let creds = DockerHubCreds { - // username: docker_image.dockerhub_user.as_ref().unwrap(), - // password: docker_image.dockerhub_password.as_ref().unwrap() - // }; - // Ok(()) - // Err(serde_valid::validation::Error::Custom(format!("Error blablablal"))) - // let client = reqwest::Client::new(); - // client.post(endpoint) - // .json(&creds) - // .send() - // .await - // .map_err(|err| serde_valid::validation::Error::Custom(format!("{:?}", err)))? - // .json::() - // .await - // .map_err(|err| serde_valid::validation::Error::Custom(format!("{:?}", err))) - // .and_then(|token| { - // tracing::debug!("got token {:?}", token); - // Ok(()) - // }) - // }); - // join_handle -} -// -// fn validate_dockerhub_image(docker_image: &DockerImage) -> Result<(), serde_valid::validation::Error> { -// -// println!("validate dockerhub image {:?}", docker_image); -// tracing::debug!("Validate image at hub.docker.com..."); -// -// let endpoint = "https://hub.docker.com/v2/users/login"; -// let creds = DockerHubCreds { -// username: docker_image.dockerhub_user.as_ref().unwrap(), -// password: docker_image.dockerhub_password.as_ref().unwrap() -// }; -// reqwest::blocking::Client::new() -// .post(endpoint) -// .json(&creds) -// .send() -// .map_err(|err| serde_valid::validation::Error::Custom(format!("{:?}", err)))? -// .json::() -// .map_err(|err| serde_valid::validation::Error::Custom(format!("{:?}", err))) -// .and_then(|token|{ -// tracing::debug!("got token {:?}", token); -// Ok(()) -// }) -// -// -// -// // Create the runtime -// // let rt = Runtime::new().unwrap(); -// // -// // // Spawn a blocking function onto the runtime -// // rt.block_on(async { -// // let result = login( -// // docker_image.dockerhub_user.clone().unwrap_or("".to_string()).as_ref(), -// // docker_image.dockerhub_password.clone().unwrap_or("".to_string()).as_ref() -// // ) -// // .await -// // .map_err(|err| serde_valid::validation::Error::Custom(format!("{:?}", err)))?; -// // -// // match result.token { -// // None => { -// // return Err(serde_valid::validation::Error::Custom( -// // "Could not access docker image repository, please check credentials.".to_owned(), -// // )); -// // }, -// // Some(tok) => { -// // tracing::debug!("We were able to login hub.docker.com!"); -// // docker_image_exists( -// // docker_image.dockerhub_user.clone().unwrap().as_str(), -// // docker_image.dockerhub_name.clone().unwrap().as_str(), tok) -// // .await -// // .map_err(|err| serde_valid::validation::Error::Custom("Not exists".to_string())) -// // .map(|_| ()) -// // } -// // } -// // }) -// -// } - -// fn validate_dockerhub_image(docker_image: &DockerImage) -> Result<(), serde_valid::validation::Error> { -// -// tracing::debug!("validate dockerhub image {:?}", docker_image); -// let endpoint = "https://hub.docker.com/v2/users/login"; -// let creds = DockerHubCreds { -// username: docker_image.dockerhub_user.as_ref().unwrap(), -// password: docker_image.dockerhub_password.as_ref().unwrap() -// }; -// reqwest::blocking::Client::new() -// .post(endpoint) -// .json(&creds) -// .send() -// .map_err(|err| serde_valid::validation::Error::Custom(format!("{:?}", err)))? -// .json::() -// .map_err(|err| serde_valid::validation::Error::Custom(format!("{:?}", err))) -// .and_then(|token|{ -// docker_image_exists( -// docker_image.dockerhub_user.clone().unwrap().as_str(), -// docker_image.dockerhub_name.clone().unwrap().as_str(), -// token -// ) -// .map_err(|err| serde_valid::validation::Error::Custom("Not exists".to_string())) -// .map(|_| ()) -// }) -// } - #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -#[validate(custom(|dockerhub|validate_dockerhub_image(dockerhub)))] pub struct DockerImage { #[validate(min_length = 3)] #[validate(max_length = 50)] @@ -252,6 +73,28 @@ impl fmt::Display for DockerImage { } +impl DockerImage { + + async fn is_active(&self) -> Result { + tracing::debug!("Validate image at DockerHub {:?}", &self); + let mut dockerhub = DockerHub::build(); + + dockerhub + .login( + self.dockerhub_user.clone().unwrap_or("".to_string()).as_ref(), + self.dockerhub_password.clone().unwrap().as_ref(), + ) + .await + .set_image(self.dockerhub_image.clone().unwrap_or(String::from("")).as_str()) + .await + .set_repos(self.dockerhub_name.clone().unwrap_or(String::from("")).as_str()) + .await + .is_active() + .await + } +} + + impl AsRef for App { fn as_ref(&self) -> &DockerImage { &self.docker_image @@ -304,6 +147,48 @@ pub struct StackForm { pub custom: Custom, } +impl StackForm { + + pub async fn is_readable_docker_image(&self) -> Result { + + let mut is_active = true; + for app in &self.custom.web { + if !app.app.docker_image.is_active().await? { + is_active = false; + break; + } + } + + // self.custom.service + // .into_iter() + // .map(|item| { + // item.iter() + // .any(|item| { + // item.app.docker_image.is_active()? + // }) + // .collect() + // }).collect(); + // + if let Some(service) = &self.custom.service { + for app in service { + if !app.app.docker_image.is_active().await? { + is_active = false; + break; + } + } + } + + if let Some(features) = &self.custom.feature { + for app in features { + if !app.app.docker_image.is_active().await? { + is_active = false; + break; + } + } + } + Ok(is_active) + } +} #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] #[serde(rename_all = "snake_case")] pub struct StackPayload { @@ -448,6 +333,7 @@ pub struct App { pub shared_ports: Option>, } + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct EnvVar { pub(crate) key: String, diff --git a/src/helpers/dockerhub.rs b/src/helpers/dockerhub.rs index 39ebca1..70a5e7a 100644 --- a/src/helpers/dockerhub.rs +++ b/src/helpers/dockerhub.rs @@ -1,6 +1,5 @@ use serde_derive::{Deserialize, Serialize}; use serde_valid::Validate; -// use tracing_subscriber::fmt::format; use serde_json::Value; @@ -10,7 +9,7 @@ pub struct DockerHubToken { } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct DockerHubCreds<'a> { +pub struct DockerHubCreds<'a> { pub(crate) username: &'a str, pub(crate) password: &'a str } @@ -56,103 +55,111 @@ struct TagResult { previous: Value, results: Vec } -pub async fn login(username: &str, password: &str) -> Result { - let endpoint = "https://hub.docker.com/v2/users/login"; - tracing::debug!("Login to {} with user {} and passw {}",endpoint, username, password); - let creds = DockerHubCreds { username, password }; - reqwest::Client::new() - .post(endpoint) - .json(&creds) - .send() - .await - .map_err(|err| format!("{}", err))? - .json::() - .await - .map_err(|err| format!("{}", err)) - .map(|token| { token }) + + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Validate)] +pub(crate) struct DockerHub<'a> { + pub(crate) creds: DockerHubCreds<'a>, + pub(crate) repos: String, + pub(crate) token: DockerHubToken, + pub(crate) image: String, +} +#[derive(Default, Debug, Clone, PartialEq, Serialize, Validate)] +pub(crate) struct DockerHubBuilder<'a> { + pub(crate) creds: DockerHubCreds<'a>, + pub(crate) repos: &'a str, + pub(crate) token: DockerHubToken, + pub(crate) image: &'a str, } -// pub async fn login(username: &str, password: &str) -> Result { -// let endpoint = "https://hub.docker.com/v2/users/login"; -// let creds = DockerHubCreds { username, password }; -// reqwest::Client::new() -// .post(endpoint) -// .json(&creds) -// .send() -// .await -// .map_err(|err| serde_valid::validation::Error::Custom(format!("{}", err)))? -// .json::() -// .await -// .map_err(|err| serde_valid::validation::Error::Custom(format!("{}", err))) -// .map(|token| { token }) -// } - -pub async fn docker_image_exists(user: &str, repo: &str, token: String) -> Result { - // get repo images - let tags_url = format!("https://hub.docker.com/v2/namespaces/{}/repositories/{}/tags", - user, repo); - - let tags = reqwest::Client::new() - .get(tags_url) - .header("Accept", "application/json") - .bearer_auth(token) - .send() - .await - .map_err(|err| format!("{}", err))? - .json::() - // .json::() - .await - .map_err(|err| format!("{}", err))?; - - // println!("tags count: {:?}", tags.count); - - if tags.count > 0 { - // let's find at least one active tag - let active = tags.results - .into_iter() - .any(|tag| tag.tag_status.contains("active") ); - Ok(active) - } else { - Err(String::from("There were no active tags found in this repository")) +impl<'a> DockerHubBuilder<'a> { + + pub async fn set_repos(&'a mut self, repo_name: &'a str) -> &'a mut Self { + self.repos = repo_name; + self + } + + pub async fn set_image(&'a mut self, image: &'a str) -> &'a mut Self { + self.image = image; + self + } + pub async fn login(&'a mut self, username: &'a str, password: &'a str) -> &'a mut Self { + let endpoint = "https://hub.docker.com/v2/users/login"; + + self.creds = DockerHubCreds { + username: username, + password: password + }; + + if self.creds.password.is_empty() { + tracing::debug!("DockerHub credentials were not provided, login not required/image considered public"); + return self; + } + + let response = reqwest::Client::new() + .post(endpoint) + .json(&self.creds) + .send() + .await + .map_err(|err| format!("{:?}", err)) + .unwrap() + .json::() + .await + .map_err(|err| format!("{:?}", err)) + .map(|token| { + self.token = token; + }); + + tracing::debug!("Login response was: {:?}", response); + self } + + pub async fn is_active(&'a self) -> Result { + // get repo images + let tags_url = format!("https://hub.docker.com/v2/namespaces/{}/repositories/{}/tags", + &self.creds.username, &self.repos); + + let mut client = reqwest::Client::new() + .get(tags_url) + .header("Accept", "application/json"); + + client = match self.token.token.as_ref() { + Some(token) => { + if !token.is_empty() { + client = client.bearer_auth(token); + } + client + }, + None => { + client + } + }; + + client + .send() + .await + .map_err(|err| format!("{}", err))? + .json::() + .await + .map_err(|err| format!("{}", err)) + .map(|tags| { + if tags.count > 0 { + // let's find at least one active tag + let active = tags.results + .into_iter() + .any(|tag| tag.tag_status.contains("active") ); + active + } else { + false + } + }) + } + } -// pub fn docker_image_exists(user: &str, repo: &str, token: DockerHubToken) -> Result { -// // get repo images -// let tags_url = format!("https://hub.docker.com/v2/namespaces/{}/repositories/{}/tags", -// user, repo); -// // -// // let tags = reqwest::Client::new() -// // .get(tags_url) -// // .header("Accept", "application/json") -// // .bearer_auth(token) -// // .send() -// // .await -// // .map_err(|err| format!("{}", err))? -// // .json::() -// // // .json::() -// // .await -// // .map_err(|err| format!("{}", err))?; -// -// reqwest::blocking::Client::new() -// .get(tags_url) -// .header("Accept", "application/json") -// .bearer_auth(token.token.unwrap()) -// .send() -// .map_err(|err| serde_valid::validation::Error::Custom(format!("{:?}", err)))? -// .json::() -// .map_err(|err| serde_valid::validation::Error::Custom(format!("{:?}", err))) -// .and_then(|tags|{ -// println!("tags count: {:?}", tags.count); -// if tags.count > 0 { -// // let's find at least one active tag -// let active = tags.results -// .into_iter() -// .any(|tag| tag.tag_status.contains("active") ); -// Ok(active) -// } else { -// Err(serde_valid::validation::Error::Custom("There were no active tags found in this repository".to_string())) -// } -// }) -// -// } +impl<'a> DockerHub<'a> +{ + pub fn build() -> DockerHubBuilder<'a> { + DockerHubBuilder::default() + } +} \ No newline at end of file diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index a399f01..5d0fffd 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -66,13 +66,13 @@ async fn body_into_form(body: Bytes) -> Result { JsonResponse::::build().bad_request(msg) }) .and_then(|form: StackForm| { - - tracing::debug!("Validating form ..."); + if !form.validate().is_ok() { let errors = form.validate().unwrap_err(); let err_msg = format!("Invalid data received {:?}", &errors.to_string()); tracing::debug!(err_msg); + return Err(JsonResponse::::build().bad_request(errors.to_string())); } diff --git a/src/routes/stack/update.rs b/src/routes/stack/update.rs index e62dd94..c5a3afc 100644 --- a/src/routes/stack/update.rs +++ b/src/routes/stack/update.rs @@ -62,8 +62,7 @@ pub async fn update( if !form.validate().is_ok() { let errors = form.validate().unwrap_err(); - let err_msg = format!("Invalid data received {:?}", &errors.to_string()); - tracing::debug!(err_msg); + tracing::debug!("Invalid data received {:?}", &errors.to_string()); return Err(JsonResponse::::build().bad_request(errors.to_string())); } @@ -74,7 +73,15 @@ pub async fn update( form.region ); let query_span = tracing::info_span!("Update stack details in db."); - let body: Value = match serde_json::to_value::(form.into_inner()) { + + let form_inner = form.into_inner(); + + if !form_inner.is_readable_docker_image().await.is_ok() { + + return Err(JsonResponse::::build().bad_request("Can not access docker image")); + } + + let body: Value = match serde_json::to_value::(form_inner) { Ok(body) => body, Err(err) => { tracing::error!("Request_id {} error unwrap body {:?}", request_id, err); From 0e93e1fa727a8c97a051c646bd7f9668da67725b Mon Sep 17 00:00:00 2001 From: petru Date: Fri, 19 Jan 2024 17:32:18 +0200 Subject: [PATCH 145/284] issue-auth removed compressor --- Cargo.lock | 1 - Cargo.toml | 1 - src/helpers/compressor.rs | 20 -------------------- src/helpers/mod.rs | 2 -- src/routes/stack/deploy.rs | 1 - 5 files changed, 25 deletions(-) delete mode 100644 src/helpers/compressor.rs diff --git a/Cargo.lock b/Cargo.lock index aae6152..ea10ab0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3138,7 +3138,6 @@ dependencies = [ "actix-http", "actix-web", "actix-web-httpauth", - "brotli", "chrono", "clap", "config", diff --git a/Cargo.toml b/Cargo.toml index 649ae23..e13da26 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,7 +52,6 @@ serde_yaml = "0.9" lapin = { version = "2.3.1", features = ["serde_json"] } futures-lite = "1.13.0" clap = { version = "4.4.8", features = ["derive"] } -brotli = "3.4.0" serde_path_to_error = "0.1.14" deadpool-lapin = "0.11.0" docker-compose-types = "0.7.0" diff --git a/src/helpers/compressor.rs b/src/helpers/compressor.rs deleted file mode 100644 index 8061329..0000000 --- a/src/helpers/compressor.rs +++ /dev/null @@ -1,20 +0,0 @@ -use brotli::{CompressorWriter, Decompressor}; -use std::io::{Read, Write}; - -pub fn compress(input: &str) -> Vec { - let mut compressed = Vec::new(); - let mut compressor = CompressorWriter::new( - &mut compressed, 4096, 11, 22 - ); - compressor.write_all(input.as_bytes()).unwrap(); - compressor.flush().unwrap(); - drop(compressor); - compressed -} - -pub fn decompress(input: &[u8]) -> String { - let mut decompressed = String::new(); - let mut decompressor = Decompressor::new(input, 4096); - decompressor.read_to_string(&mut decompressed).unwrap(); - decompressed -} diff --git a/src/helpers/mod.rs b/src/helpers/mod.rs index fd061b9..6d3b169 100644 --- a/src/helpers/mod.rs +++ b/src/helpers/mod.rs @@ -2,8 +2,6 @@ pub mod client; pub(crate) mod json; mod mq_manager; pub(crate) mod stack; -pub(crate) mod compressor; pub use json::*; pub use mq_manager::MqManager; -pub use compressor::*; diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs index ac7bc83..71d459f 100644 --- a/src/routes/stack/deploy.rs +++ b/src/routes/stack/deploy.rs @@ -8,7 +8,6 @@ use actix_web::{post, web, web::Data, Responder, Result}; use lapin::publisher_confirm::Confirmation; use sqlx::PgPool; use std::sync::Arc; -use crate::helpers::compressor::compress; #[tracing::instrument(name = "Deploy for every user. Admin endpoint")] #[post("/{id}/deploy")] From 1f0449ac8086b002c51a5aa18716a180b5b2c6ec Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 20 Jan 2024 19:41:33 +0200 Subject: [PATCH 146/284] issue-auth stack/update refactor --- Cargo.lock | 1565 +++++++++++++++++++++++++++--- Cargo.toml | 1 + src/db/stack.rs | 37 + src/middleware/access_control.rs | 5 + src/middleware/mod.rs | 1 + src/routes/stack/compose.rs | 16 +- src/routes/stack/get.rs | 8 +- src/routes/stack/update.rs | 111 +-- 8 files changed, 1497 insertions(+), 247 deletions(-) create mode 100644 src/middleware/access_control.rs diff --git a/Cargo.lock b/Cargo.lock index ea10ab0..39301be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,35 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "actix-casbin-auth" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feb9c094ecc5e0a561a44aee0c0de87be31c524b26f5096a8fde5c8de2eacec3" +dependencies = [ + "actix-service 1.0.6", + "actix-web 3.3.3", + "async-std", + "casbin", + "futures", +] + +[[package]] +name = "actix-codec" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78d1833b3838dbe990df0f1f87baf640cf6146e898166afe401839d1b001e570" +dependencies = [ + "bitflags 1.3.2", + "bytes 0.5.6", + "futures-core", + "futures-sink", + "log", + "pin-project 0.4.30", + "tokio 0.2.25", + "tokio-util 0.3.1", +] + [[package]] name = "actix-codec" version = "0.5.1" @@ -9,24 +38,43 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8" dependencies = [ "bitflags 1.3.2", - "bytes", + "bytes 1.5.0", "futures-core", "futures-sink", "memchr", - "pin-project-lite", - "tokio", - "tokio-util", + "pin-project-lite 0.2.13", + "tokio 1.34.0", + "tokio-util 0.7.10", "tracing", ] +[[package]] +name = "actix-connect" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "177837a10863f15ba8d3ae3ec12fac1099099529ed20083a27fdfe247381d0dc" +dependencies = [ + "actix-codec 0.3.0", + "actix-rt 1.1.1", + "actix-service 1.0.6", + "actix-utils 2.0.0", + "derive_more", + "either", + "futures-util", + "http", + "log", + "trust-dns-proto", + "trust-dns-resolver", +] + [[package]] name = "actix-cors" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b340e9cfa5b08690aae90fb61beb44e9b06f44fe3d0f93781aaa58cfba86245e" dependencies = [ - "actix-utils", - "actix-web", + "actix-utils 3.0.1", + "actix-web 4.4.0", "derive_more", "futures-util", "log", @@ -34,45 +82,100 @@ dependencies = [ "smallvec", ] +[[package]] +name = "actix-http" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2be6b66b62a794a8e6d366ac9415bb7d475ffd1e9f4671f38c1d8a8a5df950b3" +dependencies = [ + "actix-codec 0.3.0", + "actix-connect", + "actix-rt 1.1.1", + "actix-service 1.0.6", + "actix-threadpool", + "actix-utils 2.0.0", + "base64 0.13.1", + "bitflags 1.3.2", + "bytes 0.5.6", + "cookie 0.14.4", + "copyless", + "derive_more", + "either", + "encoding_rs", + "futures-channel", + "futures-core", + "futures-util", + "fxhash", + "h2 0.2.7", + "http", + "httparse", + "indexmap 1.9.3", + "itoa 0.4.8", + "language-tags 0.2.2", + "lazy_static", + "log", + "mime", + "percent-encoding", + "pin-project 1.1.3", + "rand 0.7.3", + "regex", + "serde", + "serde_json", + "serde_urlencoded", + "sha-1", + "slab", + "time 0.2.27", +] + [[package]] name = "actix-http" version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a92ef85799cba03f76e4f7c10f533e66d87c9a7e7055f3391f09000ad8351bc9" dependencies = [ - "actix-codec", - "actix-rt", - "actix-service", - "actix-utils", + "actix-codec 0.5.1", + "actix-rt 2.9.0", + "actix-service 2.0.2", + "actix-utils 3.0.1", "ahash 0.8.6", "base64 0.21.5", "bitflags 2.4.1", "brotli", - "bytes", + "bytes 1.5.0", "bytestring", "derive_more", "encoding_rs", "flate2", "futures-core", - "h2", + "h2 0.3.22", "http", "httparse", "httpdate", - "itoa", - "language-tags", + "itoa 1.0.9", + "language-tags 0.3.2", "local-channel", "mime", "percent-encoding", - "pin-project-lite", + "pin-project-lite 0.2.13", "rand 0.8.5", - "sha1", + "sha1 0.10.6", "smallvec", - "tokio", - "tokio-util", + "tokio 1.34.0", + "tokio-util 0.7.10", "tracing", "zstd", ] +[[package]] +name = "actix-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ca8ce00b267af8ccebbd647de0d61e0674b6e61185cc7a592ff88772bed655" +dependencies = [ + "quote", + "syn 1.0.109", +] + [[package]] name = "actix-macros" version = "0.2.4" @@ -83,6 +186,19 @@ dependencies = [ "syn 2.0.39", ] +[[package]] +name = "actix-router" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ad299af73649e1fc893e333ccf86f377751eb95ff875d095131574c6f43452c" +dependencies = [ + "bytestring", + "http", + "log", + "regex", + "serde", +] + [[package]] name = "actix-router" version = "0.5.1" @@ -96,6 +212,21 @@ dependencies = [ "tracing", ] +[[package]] +name = "actix-rt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "143fcc2912e0d1de2bcf4e2f720d2a60c28652ab4179685a1ee159e0fb3db227" +dependencies = [ + "actix-macros 0.1.3", + "actix-threadpool", + "copyless", + "futures-channel", + "futures-util", + "smallvec", + "tokio 0.2.25", +] + [[package]] name = "actix-rt" version = "2.9.0" @@ -103,7 +234,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28f32d40287d3f402ae0028a9d54bef51af15c8769492826a69d28f81893151d" dependencies = [ "futures-core", - "tokio", + "tokio 1.34.0", +] + +[[package]] +name = "actix-server" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45407e6e672ca24784baa667c5d32ef109ccdd8d5e0b5ebb9ef8a67f4dfb708e" +dependencies = [ + "actix-codec 0.3.0", + "actix-rt 1.1.1", + "actix-service 1.0.6", + "actix-utils 2.0.0", + "futures-channel", + "futures-util", + "log", + "mio 0.6.23", + "mio-uds", + "num_cpus", + "slab", + "socket2 0.3.19", ] [[package]] @@ -112,17 +263,27 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3eb13e7eef0423ea6eab0e59f6c72e7cb46d33691ad56a726b3cd07ddec2c2d4" dependencies = [ - "actix-rt", - "actix-service", - "actix-utils", + "actix-rt 2.9.0", + "actix-service 2.0.2", + "actix-utils 3.0.1", "futures-core", "futures-util", - "mio", + "mio 0.8.9", "socket2 0.5.5", - "tokio", + "tokio 1.34.0", "tracing", ] +[[package]] +name = "actix-service" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0052435d581b5be835d11f4eb3bce417c8af18d87ddf8ace99f8e67e595882bb" +dependencies = [ + "futures-util", + "pin-project 0.4.30", +] + [[package]] name = "actix-service" version = "2.0.2" @@ -131,7 +292,68 @@ checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" dependencies = [ "futures-core", "paste", - "pin-project-lite", + "pin-project-lite 0.2.13", +] + +[[package]] +name = "actix-testing" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47239ca38799ab74ee6a8a94d1ce857014b2ac36f242f70f3f75a66f691e791c" +dependencies = [ + "actix-macros 0.1.3", + "actix-rt 1.1.1", + "actix-server 1.0.4", + "actix-service 1.0.6", + "log", + "socket2 0.3.19", +] + +[[package]] +name = "actix-threadpool" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d209f04d002854b9afd3743032a27b066158817965bf5d036824d19ac2cc0e30" +dependencies = [ + "derive_more", + "futures-channel", + "lazy_static", + "log", + "num_cpus", + "parking_lot 0.11.2", + "threadpool", +] + +[[package]] +name = "actix-tls" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24789b7d7361cf5503a504ebe1c10806896f61e96eca9a7350e23001aca715fb" +dependencies = [ + "actix-codec 0.3.0", + "actix-service 1.0.6", + "actix-utils 2.0.0", + "futures-util", +] + +[[package]] +name = "actix-utils" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9022dec56632d1d7979e59af14f0597a28a830a9c1c7fec8b2327eb9f16b5a" +dependencies = [ + "actix-codec 0.3.0", + "actix-rt 1.1.1", + "actix-service 1.0.6", + "bitflags 1.3.2", + "bytes 0.5.6", + "either", + "futures-channel", + "futures-sink", + "futures-util", + "log", + "pin-project 0.4.30", + "slab", ] [[package]] @@ -141,7 +363,46 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" dependencies = [ "local-waker", - "pin-project-lite", + "pin-project-lite 0.2.13", +] + +[[package]] +name = "actix-web" +version = "3.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6534a126df581caf443ba2751cab42092c89b3f1d06a9d829b1e17edfe3e277" +dependencies = [ + "actix-codec 0.3.0", + "actix-http 2.2.2", + "actix-macros 0.1.3", + "actix-router 0.2.7", + "actix-rt 1.1.1", + "actix-server 1.0.4", + "actix-service 1.0.6", + "actix-testing", + "actix-threadpool", + "actix-tls", + "actix-utils 2.0.0", + "actix-web-codegen 0.4.0", + "awc", + "bytes 0.5.6", + "derive_more", + "encoding_rs", + "futures-channel", + "futures-core", + "futures-util", + "fxhash", + "log", + "mime", + "pin-project 1.1.3", + "regex", + "serde", + "serde_json", + "serde_urlencoded", + "socket2 0.3.19", + "time 0.2.27", + "tinyvec", + "url", ] [[package]] @@ -150,30 +411,30 @@ version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e4a5b5e29603ca8c94a77c65cf874718ceb60292c5a5c3e5f4ace041af462b9" dependencies = [ - "actix-codec", - "actix-http", - "actix-macros", - "actix-router", - "actix-rt", - "actix-server", - "actix-service", - "actix-utils", - "actix-web-codegen", + "actix-codec 0.5.1", + "actix-http 3.4.0", + "actix-macros 0.2.4", + "actix-router 0.5.1", + "actix-rt 2.9.0", + "actix-server 2.3.0", + "actix-service 2.0.2", + "actix-utils 3.0.1", + "actix-web-codegen 4.2.2", "ahash 0.8.6", - "bytes", + "bytes 1.5.0", "bytestring", - "cfg-if", - "cookie", + "cfg-if 1.0.0", + "cookie 0.16.2", "derive_more", "encoding_rs", "futures-core", "futures-util", - "itoa", - "language-tags", + "itoa 1.0.9", + "language-tags 0.3.2", "log", "mime", "once_cell", - "pin-project-lite", + "pin-project-lite 0.2.13", "regex", "serde", "serde_json", @@ -184,13 +445,24 @@ dependencies = [ "url", ] +[[package]] +name = "actix-web-codegen" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad26f77093333e0e7c6ffe54ebe3582d908a104e448723eec6d43d08b07143fb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "actix-web-codegen" version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb1f50ebbb30eca122b188319a4398b3f7bb4a8cdf50ecfb73bfc6a3c3ce54f5" dependencies = [ - "actix-router", + "actix-router 0.5.1", "proc-macro2", "quote", "syn 2.0.39", @@ -202,13 +474,13 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d613edf08a42ccc6864c941d30fe14e1b676a77d16f1dbadc1174d065a0a775" dependencies = [ - "actix-utils", - "actix-web", + "actix-utils 3.0.1", + "actix-web 4.4.0", "base64 0.21.5", "futures-core", "futures-util", "log", - "pin-project-lite", + "pin-project-lite 0.2.13", ] [[package]] @@ -243,7 +515,8 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", + "const-random", "getrandom 0.2.11", "once_cell", "version_check", @@ -428,7 +701,7 @@ dependencies = [ "event-listener 4.0.0", "event-listener-strategy", "futures-core", - "pin-project-lite", + "pin-project-lite 0.2.13", ] [[package]] @@ -479,7 +752,7 @@ checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" dependencies = [ "async-lock 2.8.0", "autocfg", - "cfg-if", + "cfg-if 1.0.0", "concurrent-queue", "futures-lite 1.13.0", "log", @@ -498,7 +771,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6d3b15875ba253d1110c740755e246537483f152fa334f91abd7fe84c88b3ff" dependencies = [ "async-lock 3.1.2", - "cfg-if", + "cfg-if 1.0.0", "concurrent-queue", "futures-io", "futures-lite 2.0.1", @@ -527,7 +800,7 @@ checksum = "dea8b3453dd7cc96711834b75400d671b73e3656975fa68d9f277163b7f7e316" dependencies = [ "event-listener 4.0.0", "event-listener-strategy", - "pin-project-lite", + "pin-project-lite 0.2.13", ] [[package]] @@ -542,6 +815,32 @@ dependencies = [ "reactor-trait", ] +[[package]] +name = "async-std" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +dependencies = [ + "async-channel 1.9.0", + "async-global-executor", + "async-io 1.13.0", + "async-lock 2.8.0", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite 1.13.0", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite 0.2.13", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + [[package]] name = "async-task" version = "4.5.0" @@ -580,6 +879,30 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "awc" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b381e490e7b0cfc37ebc54079b0413d8093ef43d14a4e4747083f7fa47a9e691" +dependencies = [ + "actix-codec 0.3.0", + "actix-http 2.2.2", + "actix-rt 1.1.1", + "actix-service 1.0.6", + "base64 0.13.1", + "bytes 0.5.6", + "cfg-if 1.0.0", + "derive_more", + "futures-core", + "log", + "mime", + "percent-encoding", + "rand 0.7.3", + "serde", + "serde_json", + "serde_urlencoded", +] + [[package]] name = "backtrace" version = "0.3.69" @@ -588,13 +911,19 @@ checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", - "cfg-if", + "cfg-if 1.0.0", "libc", "miniz_oxide", "object", "rustc-demangle", ] +[[package]] +name = "base-x" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" + [[package]] name = "base64" version = "0.13.1" @@ -619,6 +948,15 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -680,12 +1018,24 @@ version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +[[package]] +name = "bytecount" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205" + [[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "bytes" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" + [[package]] name = "bytes" version = "1.5.0" @@ -698,7 +1048,59 @@ version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74d80203ea6b29df88012294f62733de21cfeab47f17b41af3a38bc30a03ee72" dependencies = [ - "bytes", + "bytes 1.5.0", +] + +[[package]] +name = "camino" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceed8ef69d8518a5dda55c07425450b58a4e1946f4951eab6d7191ee86c2443d" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" +dependencies = [ + "camino", + "cargo-platform", + "semver 1.0.20", + "serde", + "serde_json", +] + +[[package]] +name = "casbin" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fd06051bc34aa7ee753647dbd36506fa9f84026993d9871e65e0ee71ac3632" +dependencies = [ + "async-std", + "async-trait", + "fixedbitset", + "getrandom 0.2.11", + "mini-moka", + "once_cell", + "parking_lot 0.12.1", + "petgraph", + "regex", + "rhai", + "ritelinked", + "serde", + "thiserror", ] [[package]] @@ -720,6 +1122,12 @@ dependencies = [ "libc", ] +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + [[package]] name = "cfg-if" version = "1.0.0" @@ -826,12 +1234,49 @@ dependencies = [ "yaml-rust", ] +[[package]] +name = "const-random" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aaf16c9c2c612020bcfd042e170f6e32de9b9d75adb5277cdbbd2e2c8c8299a" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.11", + "once_cell", + "tiny-keccak", +] + +[[package]] +name = "const_fn" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935" + [[package]] name = "convert_case" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "cookie" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951" +dependencies = [ + "percent-encoding", + "time 0.2.27", + "version_check", +] + [[package]] name = "cookie" version = "0.16.2" @@ -849,6 +1294,12 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396de984970346b0d9e93d1415082923c679e5ae5c3ee3dcbd104f5610af126b" +[[package]] +name = "copyless" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2df960f5d869b2dd8532793fde43eb5427cceb126c929747a26823ab0eeb536" + [[package]] name = "core-foundation" version = "0.9.3" @@ -895,7 +1346,17 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", ] [[package]] @@ -904,7 +1365,7 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "crossbeam-utils", ] @@ -914,9 +1375,15 @@ version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-common" version = "0.1.6" @@ -962,6 +1429,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if 1.0.0", + "hashbrown 0.14.2", + "lock_api", + "once_cell", + "parking_lot_core 0.9.9", +] + [[package]] name = "deadpool" version = "0.9.5" @@ -972,7 +1452,7 @@ dependencies = [ "deadpool-runtime", "num_cpus", "retain_mut", - "tokio", + "tokio 1.34.0", ] [[package]] @@ -984,7 +1464,7 @@ dependencies = [ "async-trait", "deadpool-runtime", "num_cpus", - "tokio", + "tokio 1.34.0", ] [[package]] @@ -1004,7 +1484,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63dfa964fe2a66f3fde91fc70b267fe193d822c7e603e2a675a49a7f46ad3f49" dependencies = [ - "tokio", + "tokio 1.34.0", ] [[package]] @@ -1056,7 +1536,7 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "rustc_version", + "rustc_version 0.4.0", "syn 1.0.109", ] @@ -1064,9 +1544,18 @@ dependencies = [ name = "des" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdd80ce8ce993de27e9f063a444a4d53ce8e8db4c1f00cc03af5ad5a9867a1e" +checksum = "ffdd80ce8ce993de27e9f063a444a4d53ce8e8db4c1f00cc03af5ad5a9867a1e" +dependencies = [ + "cipher", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "cipher", + "generic-array", ] [[package]] @@ -1075,7 +1564,7 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", + "block-buffer 0.10.4", "crypto-common", "subtle", ] @@ -1097,9 +1586,15 @@ checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" dependencies = [ "libc", "redox_users", - "winapi", + "winapi 0.3.9", ] +[[package]] +name = "discard" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" + [[package]] name = "dlv-list" version = "0.3.0" @@ -1145,7 +1640,19 @@ version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", +] + +[[package]] +name = "enum-as-inner" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "570d109b813e904becc80d8d5da38376818a143348413f7149f1340fe04754d4" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] @@ -1164,6 +1671,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "error-chain" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" +dependencies = [ + "version_check", +] + [[package]] name = "event-listener" version = "2.5.3" @@ -1178,7 +1694,7 @@ checksum = "770d968249b5d99410d61f5bf89057f3199a077a04d087092f58e7d10692baae" dependencies = [ "concurrent-queue", "parking", - "pin-project-lite", + "pin-project-lite 0.2.13", ] [[package]] @@ -1188,7 +1704,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" dependencies = [ "event-listener 4.0.0", - "pin-project-lite", + "pin-project-lite 0.2.13", ] [[package]] @@ -1221,6 +1737,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + [[package]] name = "flate2" version = "1.0.28" @@ -1239,7 +1761,7 @@ checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" dependencies = [ "futures-core", "futures-sink", - "pin-project", + "pin-project 1.1.3", "spin 0.9.8", ] @@ -1282,6 +1804,22 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +dependencies = [ + "bitflags 1.3.2", + "fuchsia-zircon-sys", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" + [[package]] name = "futures" version = "0.3.29" @@ -1352,7 +1890,7 @@ dependencies = [ "futures-io", "memchr", "parking", - "pin-project-lite", + "pin-project-lite 0.2.13", "waker-fn", ] @@ -1367,7 +1905,7 @@ dependencies = [ "futures-io", "memchr", "parking", - "pin-project-lite", + "pin-project-lite 0.2.13", ] [[package]] @@ -1412,11 +1950,20 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite", + "pin-project-lite 0.2.13", "pin-utils", "slab", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -1434,7 +1981,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" dependencies = [ "libc", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -1443,7 +1990,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "wasi 0.9.0+wasi-snapshot-preview1", ] @@ -1454,9 +2001,11 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", + "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -1471,13 +2020,45 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "h2" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e4728fd124914ad25e99e3d15a9361a879f6620f63cb56bbb08f95abb97a535" +dependencies = [ + "bytes 0.5.6", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 1.9.3", + "slab", + "tokio 0.2.25", + "tokio-util 0.3.1", + "tracing", + "tracing-futures", +] + [[package]] name = "h2" version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" dependencies = [ - "bytes", + "bytes 1.5.0", "fnv", "futures-core", "futures-sink", @@ -1485,11 +2066,20 @@ dependencies = [ "http", "indexmap 2.1.0", "slab", - "tokio", - "tokio-util", + "tokio 1.34.0", + "tokio-util 0.7.10", "tracing", ] +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash 0.7.7", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -1554,7 +2144,18 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", +] + +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi 0.3.9", ] [[package]] @@ -1563,9 +2164,9 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ - "bytes", + "bytes 1.5.0", "fnv", - "itoa", + "itoa 1.0.9", ] [[package]] @@ -1574,9 +2175,9 @@ version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ - "bytes", + "bytes 1.5.0", "http", - "pin-project-lite", + "pin-project-lite 0.2.13", ] [[package]] @@ -1591,7 +2192,7 @@ dependencies = [ "futures-lite 1.13.0", "http", "infer", - "pin-project-lite", + "pin-project-lite 0.2.13", "rand 0.7.3", "serde", "serde_json", @@ -1618,19 +2219,19 @@ version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ - "bytes", + "bytes 1.5.0", "futures-channel", "futures-core", "futures-util", - "h2", + "h2 0.3.22", "http", "http-body", "httparse", "httpdate", - "itoa", - "pin-project-lite", + "itoa 1.0.9", + "pin-project-lite 0.2.13", "socket2 0.4.10", - "tokio", + "tokio 1.34.0", "tower-service", "tracing", "want", @@ -1642,10 +2243,10 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ - "bytes", + "bytes 1.5.0", "hyper", "native-tls", - "tokio", + "tokio 1.34.0", "tokio-native-tls", ] @@ -1678,6 +2279,17 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "idna" version = "0.5.0" @@ -1732,7 +2344,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -1746,6 +2358,27 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "iovec" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +dependencies = [ + "libc", +] + +[[package]] +name = "ipconfig" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7e2f18aece9709094573a9f24f483c4f65caa4298e2f7ae1b71cc65d853fad7" +dependencies = [ + "socket2 0.3.19", + "widestring", + "winapi 0.3.9", + "winreg 0.6.2", +] + [[package]] name = "ipnet" version = "2.9.0" @@ -1770,6 +2403,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + [[package]] name = "itoa" version = "1.0.9" @@ -1805,6 +2444,31 @@ dependencies = [ "serde", ] +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + +[[package]] +name = "language-tags" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" + [[package]] name = "language-tags" version = "0.3.2" @@ -1907,6 +2571,24 @@ name = "log" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +dependencies = [ + "value-bag", +] + +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" [[package]] name = "matchers" @@ -1917,14 +2599,20 @@ dependencies = [ "regex-automata 0.1.10", ] +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + [[package]] name = "md-5" version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ - "cfg-if", - "digest", + "cfg-if 1.0.0", + "digest 0.10.7", ] [[package]] @@ -1939,6 +2627,21 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mini-moka" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c325dfab65f261f386debee8b0969da215b3fa0037e74c8a1234db7ba986d803" +dependencies = [ + "crossbeam-channel", + "crossbeam-utils", + "dashmap", + "skeptic", + "smallvec", + "tagptr", + "triomphe", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1954,6 +2657,25 @@ dependencies = [ "adler", ] +[[package]] +name = "mio" +version = "0.6.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +dependencies = [ + "cfg-if 0.1.10", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", + "libc", + "log", + "miow", + "net2", + "slab", + "winapi 0.2.8", +] + [[package]] name = "mio" version = "0.8.9" @@ -1966,6 +2688,29 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "mio-uds" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" +dependencies = [ + "iovec", + "libc", + "mio 0.6.23", +] + +[[package]] +name = "miow" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" +dependencies = [ + "kernel32-sys", + "net2", + "winapi 0.2.8", + "ws2_32-sys", +] + [[package]] name = "mutually_exclusive_features" version = "0.0.3" @@ -1990,6 +2735,17 @@ dependencies = [ "tempfile", ] +[[package]] +name = "net2" +version = "0.2.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b13b648036a2339d06de780866fbdfda0dde886de7b3af2ddeba8b14f4ee34ac" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "winapi 0.3.9", +] + [[package]] name = "nom" version = "7.1.3" @@ -2007,7 +2763,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" dependencies = [ "overload", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -2044,6 +2800,12 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + [[package]] name = "openssl" version = "0.10.60" @@ -2051,7 +2813,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800" dependencies = [ "bitflags 2.4.1", - "cfg-if", + "cfg-if 1.0.0", "foreign-types", "libc", "once_cell", @@ -2117,7 +2879,7 @@ dependencies = [ "hmac", "lazy_static", "rc2", - "sha1", + "sha1 0.10.6", "yasna", ] @@ -2154,12 +2916,12 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "instant", "libc", "redox_syscall 0.2.16", "smallvec", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -2168,7 +2930,7 @@ version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "redox_syscall 0.4.1", "smallvec", @@ -2238,13 +3000,43 @@ dependencies = [ "sha2", ] +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset", + "indexmap 2.1.0", +] + +[[package]] +name = "pin-project" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ef0f924a5ee7ea9cbcea77529dba45f8a9ba9f622419fe3386ca581a3ae9d5a" +dependencies = [ + "pin-project-internal 0.4.30", +] + [[package]] name = "pin-project" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" dependencies = [ - "pin-project-internal", + "pin-project-internal 1.1.3", +] + +[[package]] +name = "pin-project-internal" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "851c8d0ce9bebe43790dedfc86614c23494ac9f423dd618d3a61fc693eafe61e" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] @@ -2258,6 +3050,12 @@ dependencies = [ "syn 2.0.39", ] +[[package]] +name = "pin-project-lite" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -2307,11 +3105,11 @@ checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" dependencies = [ "autocfg", "bitflags 1.3.2", - "cfg-if", + "cfg-if 1.0.0", "concurrent-queue", "libc", "log", - "pin-project-lite", + "pin-project-lite 0.2.13", "windows-sys 0.48.0", ] @@ -2321,9 +3119,9 @@ version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf63fa624ab313c11656b4cda960bfc46c410187ad493c41f6ba2d8c1e991c9e" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "concurrent-queue", - "pin-project-lite", + "pin-project-lite 0.2.13", "rustix 0.38.25", "tracing", "windows-sys 0.52.0", @@ -2365,6 +3163,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + [[package]] name = "proc-macro2" version = "1.0.70" @@ -2374,6 +3178,23 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "pulldown-cmark" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998" +dependencies = [ + "bitflags 1.3.2", + "memchr", + "unicase", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quote" version = "1.0.33" @@ -2554,11 +3375,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" dependencies = [ "base64 0.21.5", - "bytes", + "bytes 1.5.0", "encoding_rs", "futures-core", "futures-util", - "h2", + "h2 0.3.22", "http", "http-body", "hyper", @@ -2570,19 +3391,29 @@ dependencies = [ "native-tls", "once_cell", "percent-encoding", - "pin-project-lite", + "pin-project-lite 0.2.13", "serde", "serde_json", "serde_urlencoded", "system-configuration", - "tokio", + "tokio 1.34.0", "tokio-native-tls", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "winreg", + "winreg 0.50.0", +] + +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error", ] [[package]] @@ -2591,6 +3422,34 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4389f1d5789befaf6029ebd9f7dac4af7f7e3d61b69d4f30e2ac02b57e7712b0" +[[package]] +name = "rhai" +version = "1.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3625f343d89990133d013e39c46e350915178cf94f1bec9f49b0cbef98a3e3c" +dependencies = [ + "ahash 0.8.6", + "bitflags 2.4.1", + "instant", + "num-traits", + "once_cell", + "rhai_codegen", + "serde", + "smallvec", + "smartstring", +] + +[[package]] +name = "rhai_codegen" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "853977598f084a492323fe2f7896b4100a86284ee8473612de60021ea341310f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "ring" version = "0.16.20" @@ -2603,7 +3462,7 @@ dependencies = [ "spin 0.5.2", "untrusted 0.7.1", "web-sys", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -2620,6 +3479,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "ritelinked" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98f2771d255fd99f0294f13249fecd0cae6e074f86b4197ec1f1689d537b44d3" +dependencies = [ + "ahash 0.7.7", + "hashbrown 0.11.2", +] + [[package]] name = "ron" version = "0.7.1" @@ -2637,7 +3506,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "ordered-multimap", ] @@ -2647,13 +3516,22 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver", + "semver 1.0.20", ] [[package]] @@ -2756,6 +3634,15 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.22" @@ -2804,11 +3691,29 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + [[package]] name = "semver" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +dependencies = [ + "serde", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" @@ -2836,7 +3741,7 @@ version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ - "itoa", + "itoa 1.0.9", "ryu", "serde", ] @@ -2847,7 +3752,7 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335" dependencies = [ - "itoa", + "itoa 1.0.9", "serde", ] @@ -2869,7 +3774,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa", + "itoa 1.0.9", "ryu", "serde", ] @@ -2925,32 +3830,60 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cc7a1570e38322cfe4154732e5110f887ea57e22b76f4bfd32b5bdd3368666c" dependencies = [ "indexmap 2.1.0", - "itoa", + "itoa 1.0.9", "ryu", "serde", "unsafe-libyaml", ] +[[package]] +name = "sha-1" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha1" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +dependencies = [ + "sha1_smol", +] + [[package]] name = "sha1" version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", - "digest", + "digest 0.10.7", ] +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + [[package]] name = "sha2" version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", - "digest", + "digest 0.10.7", ] [[package]] @@ -2971,6 +3904,21 @@ dependencies = [ "libc", ] +[[package]] +name = "skeptic" +version = "0.13.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" +dependencies = [ + "bytecount", + "cargo_metadata", + "error-chain", + "glob", + "pulldown-cmark", + "tempfile", + "walkdir", +] + [[package]] name = "slab" version = "0.4.9" @@ -2985,6 +3933,32 @@ name = "smallvec" version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +dependencies = [ + "serde", +] + +[[package]] +name = "smartstring" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" +dependencies = [ + "autocfg", + "serde", + "static_assertions", + "version_check", +] + +[[package]] +name = "socket2" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "winapi 0.3.9", +] [[package]] name = "socket2" @@ -2993,7 +3967,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -3053,7 +4027,7 @@ dependencies = [ "base64 0.13.1", "bitflags 1.3.2", "byteorder", - "bytes", + "bytes 1.5.0", "chrono", "crc", "crossbeam-queue", @@ -3070,7 +4044,7 @@ dependencies = [ "hkdf", "hmac", "indexmap 1.9.3", - "itoa", + "itoa 1.0.9", "libc", "log", "md-5", @@ -3083,7 +4057,7 @@ dependencies = [ "rustls-pemfile", "serde", "serde_json", - "sha1", + "sha1 0.10.6", "sha2", "smallvec", "sqlformat", @@ -3126,7 +4100,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "804d3f245f894e61b1e6263c84b23ca675d96753b5abfd5cc8597d86806e8024" dependencies = [ "once_cell", - "tokio", + "tokio 1.34.0", "tokio-rustls", ] @@ -3134,9 +4108,10 @@ dependencies = [ name = "stacker" version = "0.1.0" dependencies = [ + "actix-casbin-auth", "actix-cors", - "actix-http", - "actix-web", + "actix-http 3.4.0", + "actix-web 4.4.0", "actix-web-httpauth", "chrono", "clap", @@ -3163,7 +4138,7 @@ dependencies = [ "sha2", "sqlx", "thiserror", - "tokio", + "tokio 1.34.0", "tokio-stream", "tracing", "tracing-actix-web", @@ -3174,6 +4149,70 @@ dependencies = [ "wiremock", ] +[[package]] +name = "standback" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" +dependencies = [ + "version_check", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stdweb" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +dependencies = [ + "discard", + "rustc_version 0.2.3", + "stdweb-derive", + "stdweb-internal-macros", + "stdweb-internal-runtime", + "wasm-bindgen", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "serde_derive", + "syn 1.0.109", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +dependencies = [ + "base-x", + "proc-macro2", + "quote", + "serde", + "serde_derive", + "serde_json", + "sha1 0.6.1", + "syn 1.0.109", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" + [[package]] name = "stringprep" version = "0.1.4" @@ -3240,13 +4279,19 @@ dependencies = [ "libc", ] +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + [[package]] name = "tcp-stream" version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4da30af7998f51ee1aa48ab24276fe303a697b004e31ff542b192c088d5630a5" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "p12", "rustls-connector", "rustls-pemfile", @@ -3258,7 +4303,7 @@ version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "fastrand 2.0.1", "redox_syscall 0.4.1", "rustix 0.38.25", @@ -3291,10 +4336,19 @@ version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "once_cell", ] +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + [[package]] name = "time" version = "0.1.45" @@ -3303,7 +4357,22 @@ checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" dependencies = [ "libc", "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", + "winapi 0.3.9", +] + +[[package]] +name = "time" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" +dependencies = [ + "const_fn", + "libc", + "standback", + "stdweb", + "time-macros 0.1.1", + "version_check", + "winapi 0.3.9", ] [[package]] @@ -3313,11 +4382,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" dependencies = [ "deranged", - "itoa", + "itoa 1.0.9", "powerfmt", "serde", "time-core", - "time-macros", + "time-macros 0.2.15", ] [[package]] @@ -3326,6 +4395,16 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +[[package]] +name = "time-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" +dependencies = [ + "proc-macro-hack", + "time-macros-impl", +] + [[package]] name = "time-macros" version = "0.2.15" @@ -3335,6 +4414,28 @@ dependencies = [ "time-core", ] +[[package]] +name = "time-macros-impl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "standback", + "syn 1.0.109", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -3350,6 +4451,26 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "tokio" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092" +dependencies = [ + "bytes 0.5.6", + "futures-core", + "iovec", + "lazy_static", + "libc", + "memchr", + "mio 0.6.23", + "mio-uds", + "pin-project-lite 0.1.12", + "signal-hook-registry", + "slab", + "winapi 0.3.9", +] + [[package]] name = "tokio" version = "1.34.0" @@ -3357,12 +4478,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ "backtrace", - "bytes", + "bytes 1.5.0", "libc", - "mio", + "mio 0.8.9", "num_cpus", "parking_lot 0.12.1", - "pin-project-lite", + "pin-project-lite 0.2.13", "signal-hook-registry", "socket2 0.5.5", "tokio-macros", @@ -3377,7 +4498,7 @@ checksum = "802ccf58e108fe16561f35348fabe15ff38218968f033d587e399a84937533cc" dependencies = [ "async-trait", "executor-trait", - "tokio", + "tokio 1.34.0", ] [[package]] @@ -3398,7 +4519,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" dependencies = [ "native-tls", - "tokio", + "tokio 1.34.0", ] [[package]] @@ -3408,7 +4529,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" dependencies = [ "rustls 0.20.9", - "tokio", + "tokio 1.34.0", "webpki", ] @@ -3419,8 +4540,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ "futures-core", - "pin-project-lite", - "tokio", + "pin-project-lite 0.2.13", + "tokio 1.34.0", +] + +[[package]] +name = "tokio-util" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" +dependencies = [ + "bytes 0.5.6", + "futures-core", + "futures-sink", + "log", + "pin-project-lite 0.1.12", + "tokio 0.2.25", ] [[package]] @@ -3429,11 +4564,11 @@ version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ - "bytes", + "bytes 1.5.0", "futures-core", "futures-sink", - "pin-project-lite", - "tokio", + "pin-project-lite 0.2.13", + "tokio 1.34.0", "tracing", ] @@ -3459,7 +4594,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "log", - "pin-project-lite", + "pin-project-lite 0.2.13", "tracing-attributes", "tracing-core", ] @@ -3470,9 +4605,9 @@ version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fe0d5feac3f4ca21ba33496bcb1ccab58cca6412b1405ae80f0581541e0ca78" dependencies = [ - "actix-web", + "actix-web 4.4.0", "mutually_exclusive_features", - "pin-project", + "pin-project 1.1.3", "tracing", "uuid", ] @@ -3516,6 +4651,16 @@ dependencies = [ "valuable", ] +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project 1.1.3", + "tracing", +] + [[package]] name = "tracing-log" version = "0.1.4" @@ -3556,6 +4701,51 @@ dependencies = [ "tracing-log 0.2.0", ] +[[package]] +name = "triomphe" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3" + +[[package]] +name = "trust-dns-proto" +version = "0.19.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cad71a0c0d68ab9941d2fb6e82f8fb2e86d9945b94e1661dd0aaea2b88215a9" +dependencies = [ + "async-trait", + "cfg-if 1.0.0", + "enum-as-inner", + "futures", + "idna 0.2.3", + "lazy_static", + "log", + "rand 0.7.3", + "smallvec", + "thiserror", + "tokio 0.2.25", + "url", +] + +[[package]] +name = "trust-dns-resolver" +version = "0.19.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "710f593b371175db53a26d0b38ed2978fafb9e9e8d3868b1acd753ea18df0ceb" +dependencies = [ + "cfg-if 0.1.10", + "futures", + "ipconfig", + "lazy_static", + "log", + "lru-cache", + "resolv-conf", + "smallvec", + "thiserror", + "tokio 0.2.25", + "trust-dns-proto", +] + [[package]] name = "try-lock" version = "0.2.4" @@ -3574,6 +4764,15 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.13" @@ -3632,7 +4831,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", - "idna", + "idna 0.5.0", "percent-encoding", "serde", ] @@ -3659,6 +4858,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "value-bag" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cdbaf5e132e593e9fc1de6a15bbec912395b11fb9719e061cf64f804524c503" + [[package]] name = "vcpkg" version = "0.2.15" @@ -3677,6 +4882,16 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -3710,7 +4925,7 @@ version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "wasm-bindgen-macro", ] @@ -3735,7 +4950,7 @@ version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "js-sys", "wasm-bindgen", "web-sys", @@ -3809,6 +5024,18 @@ dependencies = [ "web-sys", ] +[[package]] +name = "widestring" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c" + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + [[package]] name = "winapi" version = "0.3.9" @@ -3819,12 +5046,27 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu", ] +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" + [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -3972,13 +5214,22 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +[[package]] +name = "winreg" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "winreg" version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "windows-sys 0.48.0", ] @@ -4001,7 +5252,17 @@ dependencies = [ "regex", "serde", "serde_json", - "tokio", + "tokio 1.34.0", +] + +[[package]] +name = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +dependencies = [ + "winapi 0.2.8", + "winapi-build", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e13da26..024d61b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,6 +55,7 @@ clap = { version = "4.4.8", features = ["derive"] } serde_path_to_error = "0.1.14" deadpool-lapin = "0.11.0" docker-compose-types = "0.7.0" +actix-casbin-auth = "0.4.4" [dependencies.sqlx] version = "0.6.3" diff --git a/src/db/stack.rs b/src/db/stack.rs index 92725cd..def7a36 100644 --- a/src/db/stack.rs +++ b/src/db/stack.rs @@ -101,3 +101,40 @@ pub async fn insert(pool: &PgPool, mut stack: models::Stack) -> Result Result { + let query_span = tracing::info_span!("Updating user stack into the database"); + sqlx::query_as!( + models::Stack, + r#" + UPDATE user_stack + SET + stack_id=$2, + user_id=$3, + name=$4, + body=$5, + created_at=$6, + updated_at=NOW() at time zone 'utc' + WHERE id = $1 + RETURNING * + "#, + stack.id, + stack.stack_id, + stack.user_id, + stack.name, + stack.body, + stack.created_at, + ) + .fetch_one(pool) + .instrument(query_span) + .await + .map(|result|{ + tracing::info!("Stack {} have been saved to database", stack.id); + stack.updated_at = result.updated_at; + stack + }) + .map_err(|err| { + tracing::error!("Failed to execute query: {:?}", err); + "".to_string() + }) +} diff --git a/src/middleware/access_control.rs b/src/middleware/access_control.rs new file mode 100644 index 0000000..80e4881 --- /dev/null +++ b/src/middleware/access_control.rs @@ -0,0 +1,5 @@ +pub struct AccessControl{} + +impl AccessControl { + +} diff --git a/src/middleware/mod.rs b/src/middleware/mod.rs index 20dda30..66bc6dc 100644 --- a/src/middleware/mod.rs +++ b/src/middleware/mod.rs @@ -1,2 +1,3 @@ pub mod client; pub mod trydirect; +pub mod access_control; diff --git a/src/routes/stack/compose.rs b/src/routes/stack/compose.rs index b8b5123..7c926b5 100644 --- a/src/routes/stack/compose.rs +++ b/src/routes/stack/compose.rs @@ -25,14 +25,12 @@ pub async fn add( None => Err(JsonResponse::::build().not_found("not found")), })?; - let id = stack.id.clone(); - let fc = DcBuilder::new(stack) + DcBuilder::new(stack) .build() .map_err(|err| { JsonResponse::::build().internal_server_error(err) - })?; - - Ok(JsonResponse::build().set_id(id).set_item(fc).ok("Success")) + }) + .map(|fc| JsonResponse::build().set_id(id).set_item(fc).ok("Success")) } #[tracing::instrument(name = "Generate docker-compose. Admin")] @@ -52,12 +50,10 @@ pub async fn admin( None => Err(JsonResponse::::build().not_found("not found")), })?; - let id = stack.id.clone(); - let fc = DcBuilder::new(stack) + DcBuilder::new(stack) .build() .map_err(|err| { JsonResponse::::build().internal_server_error(err) - })?; - - Ok(JsonResponse::build().set_id(id).set_item(fc).ok("Success")) + }) + .map(|fc| JsonResponse::build().set_id(id).set_item(fc).ok("Success")) } diff --git a/src/routes/stack/get.rs b/src/routes/stack/get.rs index 1e9492a..b261896 100644 --- a/src/routes/stack/get.rs +++ b/src/routes/stack/get.rs @@ -17,18 +17,16 @@ pub async fn item( /// Get stack apps of logged user only let (id,) = path.into_inner(); - let stack = db::stack::fetch(pg_pool.get_ref(), id) + db::stack::fetch(pg_pool.get_ref(), id) .await .map_err(|err| JsonResponse::::build().internal_server_error(err)) .and_then(|stack| match stack { Some(stack) if stack.user_id != user.id => { Err(JsonResponse::::build().not_found("not found")) } - Some(stack) => Ok(stack), + Some(stack) => Ok(JsonResponse::build().set_item(Some(stack)).ok("OK")), None => Err(JsonResponse::::build().not_found("not found")), - })?; - - Ok(JsonResponse::build().set_item(Some(stack)).ok("OK")) + }) } #[tracing::instrument(name = "Get user's stack list.")] diff --git a/src/routes/stack/update.rs b/src/routes/stack/update.rs index 316a1ba..9768a6f 100644 --- a/src/routes/stack/update.rs +++ b/src/routes/stack/update.rs @@ -1,10 +1,8 @@ use crate::forms; use crate::helpers::JsonResponse; use crate::models; -use crate::models::user::User; -use actix_web::post; -use actix_web::{web, web::Data, Responder, Result}; -use chrono::Utc; +use crate::db; +use actix_web::{web, web::Data, Responder, Result, post}; use serde_json::Value; use serde_valid::Validate; use sqlx::PgPool; @@ -17,92 +15,45 @@ use uuid::Uuid; pub async fn update( path: web::Path<(i32,)>, form: web::Json, - user: web::ReqData>, + user: web::ReqData>, pg_pool: Data, ) -> Result { - // @todo ACL - - let (id,) = path.into_inner(); - let query_span = tracing::info_span!("Check existence by id."); - match sqlx::query_as!(models::Stack, r"SELECT * FROM user_stack WHERE id = $1", id) - .fetch_one(pg_pool.get_ref()) - .instrument(query_span) + let id = path.0; + let mut stack = db::stack::fetch(pg_pool.get_ref(), id) .await - { - Ok(stack) => { - tracing::info!("Found record: {:?}", stack.id); - } - Err(e) => { - tracing::error!("Failed to fetch record: {:?}, error: {:?}", id, e); - return Err(JsonResponse::::build() - .not_found(format!("Object not found {}", id))); - } - }; + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .and_then(|stack| match stack { + Some(stack) => Ok(stack), + None => Err(JsonResponse::::build().not_found("not found")), + })?; let stack_name = form.custom.custom_stack_code.clone(); tracing::debug!("form data: {:?}", form); let user_id = user.id.clone(); - let request_id = Uuid::new_v4(); - let request_span = tracing::info_span!( - "Validating a stack", %request_id, - commonDomain=?&form.custom.project_name, - region=?&form.region, - domainList=?&form.domain_list - ); - let _request_span_guard = request_span.enter(); // ->exit - - tracing::info!( - "request_id {} Updating '{}' '{}'", - request_id, - form.custom.project_name, - form.region - ); - - let query_span = tracing::info_span!("Update stack details in db."); - if !form.validate().is_ok() { - let errors = form.validate().unwrap_err(); - let err_msg = format!("Invalid data received {:?}", &errors.to_string()); - tracing::debug!(err_msg); + if let Err(errors) = form.validate() { return Err(JsonResponse::::build().bad_request(errors.to_string())); } - let body: Value = match serde_json::to_value::(form.into_inner()) { - Ok(body) => body, - Err(err) => { - tracing::error!("Request_id {} error unwrap body {:?}", request_id, err); - serde_json::to_value::(forms::stack::Stack::default()).unwrap() - } - }; + let body: Value = serde_json::to_value::(form.into_inner()) + .map_err(|err| + JsonResponse::::build().bad_request(format!("{err}")) + )?; - match sqlx::query!( - r#" - UPDATE user_stack - SET stack_id=$2, user_id=$3, name=$4, body=$5, created_at=$6, updated_at=$7 - WHERE id=$1 - "#, - id, - Uuid::new_v4(), - user_id, - stack_name, - body, - Utc::now(), - Utc::now(), - ) - .execute(pg_pool.get_ref()) - .instrument(query_span) - .await - { - Ok(_record) => { - tracing::info!( - "req_id: {} stack details have been saved to database", - request_id - ); - return Ok(JsonResponse::::build().set_id(id).ok("OK")); - } - Err(e) => { - tracing::error!("req_id: {} Failed to execute query: {:?}", request_id, e); - return Err(JsonResponse::::build().bad_request("Internal Server Error")); - } - }; + stack.stack_id = Uuid::new_v4(); + stack.user_id = user_id; + stack.name = stack_name; + stack.body = body; + + db::stack::update(pg_pool.get_ref(), stack) + .await + .map(|stack| { + JsonResponse::::build() + .set_item(stack) + .ok("success") + }) + .map_err(|err| { + tracing::error!("Failed to execute query: {:?}", err); + JsonResponse::::build().internal_server_error("") + }) } From 05c9cc2f49cddb0f6c20b56fd052945af4f8d2fc Mon Sep 17 00:00:00 2001 From: vsilent Date: Sun, 21 Jan 2024 11:57:02 +0200 Subject: [PATCH 147/284] dockerhub functionality refactoring --- src/forms/stack.rs | 17 +----- src/helpers/dockerhub.rs | 102 +++++++++++++++----------------- tests/custom-stack-payload.json | 1 - 3 files changed, 50 insertions(+), 70 deletions(-) delete mode 100644 tests/custom-stack-payload.json diff --git a/src/forms/stack.rs b/src/forms/stack.rs index 99c4d6b..4ee56b2 100644 --- a/src/forms/stack.rs +++ b/src/forms/stack.rs @@ -75,22 +75,9 @@ impl fmt::Display for DockerImage { impl DockerImage { + #[tracing::instrument(name="is_active")] async fn is_active(&self) -> Result { - tracing::debug!("Validate image at DockerHub {:?}", &self); - let mut dockerhub = DockerHub::build(); - - dockerhub - .login( - self.dockerhub_user.clone().unwrap_or("".to_string()).as_ref(), - self.dockerhub_password.clone().unwrap().as_ref(), - ) - .await - .set_image(self.dockerhub_image.clone().unwrap_or(String::from("")).as_str()) - .await - .set_repos(self.dockerhub_name.clone().unwrap_or(String::from("")).as_str()) - .await - .is_active() - .await + DockerHub::from(self).is_active().await } } diff --git a/src/helpers/dockerhub.rs b/src/helpers/dockerhub.rs index 70a5e7a..5074cb2 100644 --- a/src/helpers/dockerhub.rs +++ b/src/helpers/dockerhub.rs @@ -1,6 +1,8 @@ +use reqwest::RequestBuilder; use serde_derive::{Deserialize, Serialize}; use serde_valid::Validate; use serde_json::Value; +use crate::forms::stack::DockerImage; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] @@ -61,79 +63,35 @@ struct TagResult { pub(crate) struct DockerHub<'a> { pub(crate) creds: DockerHubCreds<'a>, pub(crate) repos: String, - pub(crate) token: DockerHubToken, pub(crate) image: String, } -#[derive(Default, Debug, Clone, PartialEq, Serialize, Validate)] -pub(crate) struct DockerHubBuilder<'a> { - pub(crate) creds: DockerHubCreds<'a>, - pub(crate) repos: &'a str, - pub(crate) token: DockerHubToken, - pub(crate) image: &'a str, -} -impl<'a> DockerHubBuilder<'a> { - - pub async fn set_repos(&'a mut self, repo_name: &'a str) -> &'a mut Self { - self.repos = repo_name; - self - } +impl<'a> DockerHub<'a> { - pub async fn set_image(&'a mut self, image: &'a str) -> &'a mut Self { - self.image = image; - self - } - pub async fn login(&'a mut self, username: &'a str, password: &'a str) -> &'a mut Self { + pub async fn login(&'a self) -> Result { let endpoint = "https://hub.docker.com/v2/users/login"; - self.creds = DockerHubCreds { - username: username, - password: password - }; - - if self.creds.password.is_empty() { - tracing::debug!("DockerHub credentials were not provided, login not required/image considered public"); - return self; - } - - let response = reqwest::Client::new() + reqwest::Client::new() .post(endpoint) .json(&self.creds) .send() .await - .map_err(|err| format!("{:?}", err)) - .unwrap() + .map_err(|err| format!("{:?}", err))? .json::() .await .map_err(|err| format!("{:?}", err)) - .map(|token| { - self.token = token; - }); - - tracing::debug!("Login response was: {:?}", response); - self } pub async fn is_active(&'a self) -> Result { + // get repo images let tags_url = format!("https://hub.docker.com/v2/namespaces/{}/repositories/{}/tags", &self.creds.username, &self.repos); - let mut client = reqwest::Client::new() .get(tags_url) .header("Accept", "application/json"); - client = match self.token.token.as_ref() { - Some(token) => { - if !token.is_empty() { - client = client.bearer_auth(token); - } - client - }, - None => { - client - } - }; + let mut client = self.set_token(client).await?; client .send() @@ -155,11 +113,47 @@ impl<'a> DockerHubBuilder<'a> { }) } + pub async fn set_token(&self, mut client: RequestBuilder) -> Result { + + if self.creds.password.is_empty() { + return Ok(client); + } + let token = self.login().await?; + + match token.token { + None => { + Ok(client) + }, + Some(token) => { + Ok(client.bearer_auth(token)) + } + } + } } -impl<'a> DockerHub<'a> -{ - pub fn build() -> DockerHubBuilder<'a> { - DockerHubBuilder::default() +impl<'a> From <&'a DockerImage> for DockerHub<'a> { + + fn from(image: &'a DockerImage) -> Self { + let username = match image.dockerhub_user { + Some(ref username) => { + username + }, + None => "" + }; + let password = match image.dockerhub_password { + Some(ref password) => { + password + }, + None => "" + }; + + DockerHub { + creds: DockerHubCreds { + username: username, + password: password + }, + repos: image.dockerhub_name.clone().unwrap_or("".to_string()), + image: format!("{}", image), + } } } \ No newline at end of file diff --git a/tests/custom-stack-payload.json b/tests/custom-stack-payload.json deleted file mode 100644 index e85b469..0000000 --- a/tests/custom-stack-payload.json +++ /dev/null @@ -1 +0,0 @@ -{"commonDomain":"","domainList":{},"region":"fsn1","zone":null,"server":"cx11","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":[],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":false,"disk_type":"pd-standart","cloud_token":"****************************","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"networks":["default_network"],"web":[{"name":"MyApp","code":"myapp","domain":"myapp.com","shared_ports":[{"host_port":"80","container_port":"8080"}],"versions":[],"custom":true,"type":"web","network":["default_network"],"restart":"always","timestamp":"2024-01-15T09:47:46.580Z","_id":"lreqrvv81ifrmng39","dockerhub_user":"trydirect","dockerhub_name":"nginx-waf", "dockerhub_password": "", "environment":[{"key":"SOMEENVVAR1","value":"SOMEENVVAR_VALUE1"},{"key":"SOMEENVVAR2","value":"SOMEENVVAR_VALUE2"}],"volumes":[]}],"feature":[],"service":[],"servers_count":3,"project_git_url":"info@optimum-web.com","project_name":"Sample2024","custom_stack_code":"sample2024"}} \ No newline at end of file From 6fa70cffd6879bcab325bae5ea409fad2c0c0edf Mon Sep 17 00:00:00 2001 From: vsilent Date: Mon, 22 Jan 2024 21:54:52 +0200 Subject: [PATCH 148/284] validate public/private repos --- src/forms/stack.rs | 24 ++++------- src/helpers/dockerhub.rs | 89 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 89 insertions(+), 24 deletions(-) diff --git a/src/forms/stack.rs b/src/forms/stack.rs index 4ee56b2..09512d4 100644 --- a/src/forms/stack.rs +++ b/src/forms/stack.rs @@ -40,17 +40,21 @@ pub struct Port { pub protocol: Option } + + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct DockerImage { - #[validate(min_length = 3)] + // #[validate(min_length = 3)] #[validate(max_length = 50)] - #[validate(pattern = r"^[a-z0-9]+([-_.][a-z0-9]+)*$")] + // @todo conditional check, if not empty + // #[validate(pattern = r"^[a-z0-9]+([-_.][a-z0-9]+)*$")] pub dockerhub_user: Option, - #[validate(min_length = 3)] + // #[validate(min_length = 3)] #[validate(max_length = 50)] - #[validate(pattern = r"^[a-z0-9]+([-_.][a-z0-9]+)*$")] + // @todo conditional check, if not empty + // #[validate(pattern = r"^[a-z0-9]+([-_.][a-z0-9]+)*$")] pub dockerhub_name: Option, - #[validate(min_length = 3)] + // #[validate(min_length = 3)] #[validate(max_length = 100)] pub dockerhub_image: Option, pub dockerhub_password: Option, @@ -146,16 +150,6 @@ impl StackForm { } } - // self.custom.service - // .into_iter() - // .map(|item| { - // item.iter() - // .any(|item| { - // item.app.docker_image.is_active()? - // }) - // .collect() - // }).collect(); - // if let Some(service) = &self.custom.service { for app in service { if !app.app.docker_image.is_active().await? { diff --git a/src/helpers/dockerhub.rs b/src/helpers/dockerhub.rs index 5074cb2..e93783a 100644 --- a/src/helpers/dockerhub.rs +++ b/src/helpers/dockerhub.rs @@ -58,6 +58,31 @@ struct TagResult { results: Vec } +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct RepoResults { + pub count: i64, + pub next: Value, + pub previous: Value, + pub results: Vec, +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct RepoResult { + pub name: String, + pub namespace: String, + pub repository_type: String, + pub status: i64, + pub status_description: String, + pub description: String, + pub is_private: bool, + pub star_count: i64, + pub pull_count: i64, + pub last_updated: String, + pub date_registered: String, + pub affiliation: String, + pub media_types: Vec, + pub content_types: Vec, +} #[derive(Default, Debug, Clone, PartialEq, Serialize, Validate)] pub(crate) struct DockerHub<'a> { @@ -82,25 +107,58 @@ impl<'a> DockerHub<'a> { .map_err(|err| format!("{:?}", err)) } - pub async fn is_active(&'a self) -> Result { - - // get repo images - let tags_url = format!("https://hub.docker.com/v2/namespaces/{}/repositories/{}/tags", - &self.creds.username, &self.repos); - let mut client = reqwest::Client::new() - .get(tags_url) + pub async fn lookup_public_repo(&self) -> Result { + let url = format!("https://hub.docker.com/v2/repositories/{}", &self.repos); + tracing::debug!("Validate public repositories {:?}", url); + let client = reqwest::Client::new() + .get(url) .header("Accept", "application/json"); - let mut client = self.set_token(client).await?; + client + .send() + .await + .map_err(|err| { + tracing::debug!("Error response {:?}", err); + format!("{}", err) + })? + .json::() + .await + .map_err(|err| format!("{}", err)) + .map(|repositories| { + tracing::debug!("Get public image repositories response {:?}", repositories); + if repositories.count > 0 { + // let's find at least one active tag + let active = repositories.results + .into_iter() + .any(|mut repo| repo.status == 1 ); + active + } else { + false + } + }) + } + pub async fn lookup_private_repo(&self) -> Result { + let url = format!("https://hub.docker.com/v2/namespaces/{}/repositories/{}/tags", + &self.creds.username, + &self.repos); + tracing::debug!("Validate image {:?}", url); + let client = reqwest::Client::new() + .get(url) + .header("Accept", "application/json"); + let mut client = self.set_token(client).await?; client .send() .await .map_err(|err| format!("{}", err))? .json::() .await - .map_err(|err| format!("{}", err)) + .map_err(|err| { + tracing::debug!("Error response {:?}", err); + format!("{}", err) + }) .map(|tags| { + tracing::debug!("Validate private image response {:?}", tags); if tags.count > 0 { // let's find at least one active tag let active = tags.results @@ -112,12 +170,25 @@ impl<'a> DockerHub<'a> { } }) } + pub async fn is_active(&'a self) -> Result { + + // if namespace/user is not set change endpoint and return a different response + if self.creds.username.is_empty() { + return self.lookup_public_repo().await; + } + return self.lookup_private_repo().await; + + } pub async fn set_token(&self, mut client: RequestBuilder) -> Result { if self.creds.password.is_empty() { + tracing::debug!("Password is empty. Image should be public"); return Ok(client); + } else{ + } + tracing::debug!("Password is set. Login.."); let token = self.login().await?; match token.token { From b954bd6f7489016db7e17bcee8a1b7c719fd2ed0 Mon Sep 17 00:00:00 2001 From: vsilent Date: Mon, 22 Jan 2024 22:47:52 +0200 Subject: [PATCH 149/284] install ca-certificates, fix external https call --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 29b6b73..c068fc2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -44,7 +44,7 @@ RUN apt-get update && apt-get install --no-install-recommends -y libssl-dev; \ # deploy production FROM debian:bookworm-slim as production -RUN apt-get update && apt-get install --no-install-recommends -y libssl-dev; +RUN apt-get update && apt-get install --no-install-recommends -y libssl-dev ca-certificates; # create app directory WORKDIR /app RUN mkdir ./files && chmod 0777 ./files From 745e57b8460a517ffb3245fb38caeb5031a3462d Mon Sep 17 00:00:00 2001 From: vsilent Date: Tue, 23 Jan 2024 15:53:39 +0200 Subject: [PATCH 150/284] host port conditional validation, variant 1 --- src/forms/stack.rs | 61 +++++++++++++++++++++++++----------- src/helpers/stack/builder.rs | 28 +++++++++++++---- 2 files changed, 64 insertions(+), 25 deletions(-) diff --git a/src/forms/stack.rs b/src/forms/stack.rs index 09512d4..07674fa 100644 --- a/src/forms/stack.rs +++ b/src/forms/stack.rs @@ -2,10 +2,8 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use serde_valid::Validate; use std::fmt; -use serde_valid::validation::error::Format::Default; +use regex::Regex; use crate::helpers::dockerhub::{DockerHub, DockerHubCreds, DockerHubToken}; -// use tokio::runtime::Runtime; -// use tokio::runtime::Handle; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Role { @@ -27,23 +25,48 @@ pub struct Requirements { #[validate(min_length = 1)] #[validate(max_length = 10)] #[validate(pattern = r"^\d+G$")] - pub ram_size: Option + pub ram_size: Option, +} + +fn validate_non_empty(v: &Option) -> Result<(), serde_valid::validation::Error> { + if v.is_none() { + return Ok(()); + } + + if let Some(value) = v { + if value.is_empty() { + return Ok(()); + } + + // #[validate(pattern = r"^\d{2,6}+$")] + let re = Regex::new(r"^\d{2,6}+$").unwrap(); + + if !re.is_match(value.as_str()) { + return Err(serde_valid::validation::Error::Custom("Port is not valid.".to_owned())); + } + } + + Ok(()) +} + +#[derive(Validate)] +struct Data { + val: i32, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Port { - #[validate(pattern = r"^\d{2,6}+$")] + #[validate(custom(|v| validate_non_empty(v)))] pub host_port: Option, #[validate(pattern = r"^\d{2,6}+$")] pub container_port: String, #[validate(enumerate("tcp", "udp"))] - pub protocol: Option + pub protocol: Option, } - #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct DockerImage { +pub struct DockerImage { // #[validate(min_length = 3)] #[validate(max_length = 50)] // @todo conditional check, if not empty @@ -78,8 +101,7 @@ impl fmt::Display for DockerImage { impl DockerImage { - - #[tracing::instrument(name="is_active")] + #[tracing::instrument(name = "is_active")] async fn is_active(&self) -> Result { DockerHub::from(self).is_active().await } @@ -94,7 +116,7 @@ impl AsRef for App { #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct StackForm { - #[validate(max_length=255)] + #[validate(max_length = 255)] #[serde(rename = "commonDomain")] pub common_domain: Option, pub domain_list: Option, @@ -139,15 +161,13 @@ pub struct StackForm { } impl StackForm { - pub async fn is_readable_docker_image(&self) -> Result { - let mut is_active = true; for app in &self.custom.web { - if !app.app.docker_image.is_active().await? { - is_active = false; - break; - } + if !app.app.docker_image.is_active().await? { + is_active = false; + break; + } } if let Some(service) = &self.custom.service { @@ -170,6 +190,7 @@ impl StackForm { Ok(is_active) } } + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] #[serde(rename_all = "snake_case")] pub struct StackPayload { @@ -201,7 +222,7 @@ pub struct StackPayload { #[serde(rename = "selected_plan")] pub selected_plan: String, pub custom: Custom, - pub docker_compose: Option> + pub docker_compose: Option>, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -216,6 +237,7 @@ pub struct Var {} pub struct Price { pub value: f64, } + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Custom { #[validate] @@ -318,13 +340,14 @@ pub struct App { #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct EnvVar { pub(crate) key: String, - pub(crate) value: String + pub(crate) value: String, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Environment { pub(crate) environment: Option>, } + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Volume { pub(crate) host_path: Option, diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 7652eb7..501d22e 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -57,18 +57,34 @@ impl TryInto for Volume { impl TryInto for stack::Port { type Error = String; fn try_into(self) -> Result { - let cp = self.container_port.clone() - .parse::().map_err(|err| "Could not parse container port".to_string() )?; - let hp = self.host_port.clone() - .unwrap_or("".to_string()) - .parse::().map_err(|err| "Could not parse host port".to_string() )?; + let cp = self.container_port + .clone() + .parse::() + .map_err(|err| "Could not parse container port".to_string() )?; + + let hp = match self.host_port.clone() { + Some(hp) => { + if hp.is_empty() { + None + } else { + match hp.parse::() { + Ok(port) => Some(PublishedPort::Single(port)), + Err(_) => { + tracing::debug!("Could not parse host port: {}", hp); + None + } + } + } + } + _ => None + }; tracing::debug!("Port conversion result: cp: {:?} hp: {:?}", cp, hp); Ok(Port { target: cp, host_ip: None, - published: Some(PublishedPort::Single(hp)), + published: hp, protocol: None, mode: None, }) From 1ed72dbe095faf8e531dea1590dae08d4bc6f711 Mon Sep 17 00:00:00 2001 From: petru Date: Tue, 23 Jan 2024 18:35:10 +0200 Subject: [PATCH 151/284] issue-auth working on casbin --- Cargo.lock | 1265 ++++------------------------- Cargo.toml | 2 +- rbac/rbac_with_pattern_model.conf | 15 + rbac/rbac_with_pattern_policy.csv | 10 + src/middleware/trydirect.rs | 7 + src/routes/test/casbin.rs | 8 + src/routes/test/deploy.rs | 7 - src/routes/test/mod.rs | 1 + src/startup.rs | 31 + 9 files changed, 234 insertions(+), 1112 deletions(-) create mode 100644 rbac/rbac_with_pattern_model.conf create mode 100644 rbac/rbac_with_pattern_policy.csv create mode 100644 src/routes/test/casbin.rs diff --git a/Cargo.lock b/Cargo.lock index 39301be..35a4403 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,30 +5,13 @@ version = 3 [[package]] name = "actix-casbin-auth" version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feb9c094ecc5e0a561a44aee0c0de87be31c524b26f5096a8fde5c8de2eacec3" +source = "git+https://github.com/casbin-rs/actix-casbin-auth.git#5f8550953a29460d18029fb50785773d6957d717" dependencies = [ - "actix-service 1.0.6", - "actix-web 3.3.3", - "async-std", + "actix-service", + "actix-web", "casbin", "futures", -] - -[[package]] -name = "actix-codec" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78d1833b3838dbe990df0f1f87baf640cf6146e898166afe401839d1b001e570" -dependencies = [ - "bitflags 1.3.2", - "bytes 0.5.6", - "futures-core", - "futures-sink", - "log", - "pin-project 0.4.30", - "tokio 0.2.25", - "tokio-util 0.3.1", + "tokio", ] [[package]] @@ -38,43 +21,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8" dependencies = [ "bitflags 1.3.2", - "bytes 1.5.0", + "bytes", "futures-core", "futures-sink", "memchr", - "pin-project-lite 0.2.13", - "tokio 1.34.0", - "tokio-util 0.7.10", + "pin-project-lite", + "tokio", + "tokio-util", "tracing", ] -[[package]] -name = "actix-connect" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "177837a10863f15ba8d3ae3ec12fac1099099529ed20083a27fdfe247381d0dc" -dependencies = [ - "actix-codec 0.3.0", - "actix-rt 1.1.1", - "actix-service 1.0.6", - "actix-utils 2.0.0", - "derive_more", - "either", - "futures-util", - "http", - "log", - "trust-dns-proto", - "trust-dns-resolver", -] - [[package]] name = "actix-cors" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b340e9cfa5b08690aae90fb61beb44e9b06f44fe3d0f93781aaa58cfba86245e" dependencies = [ - "actix-utils 3.0.1", - "actix-web 4.4.0", + "actix-utils", + "actix-web", "derive_more", "futures-util", "log", @@ -82,100 +46,45 @@ dependencies = [ "smallvec", ] -[[package]] -name = "actix-http" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2be6b66b62a794a8e6d366ac9415bb7d475ffd1e9f4671f38c1d8a8a5df950b3" -dependencies = [ - "actix-codec 0.3.0", - "actix-connect", - "actix-rt 1.1.1", - "actix-service 1.0.6", - "actix-threadpool", - "actix-utils 2.0.0", - "base64 0.13.1", - "bitflags 1.3.2", - "bytes 0.5.6", - "cookie 0.14.4", - "copyless", - "derive_more", - "either", - "encoding_rs", - "futures-channel", - "futures-core", - "futures-util", - "fxhash", - "h2 0.2.7", - "http", - "httparse", - "indexmap 1.9.3", - "itoa 0.4.8", - "language-tags 0.2.2", - "lazy_static", - "log", - "mime", - "percent-encoding", - "pin-project 1.1.3", - "rand 0.7.3", - "regex", - "serde", - "serde_json", - "serde_urlencoded", - "sha-1", - "slab", - "time 0.2.27", -] - [[package]] name = "actix-http" version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a92ef85799cba03f76e4f7c10f533e66d87c9a7e7055f3391f09000ad8351bc9" dependencies = [ - "actix-codec 0.5.1", - "actix-rt 2.9.0", - "actix-service 2.0.2", - "actix-utils 3.0.1", + "actix-codec", + "actix-rt", + "actix-service", + "actix-utils", "ahash 0.8.6", "base64 0.21.5", "bitflags 2.4.1", "brotli", - "bytes 1.5.0", + "bytes", "bytestring", "derive_more", "encoding_rs", "flate2", "futures-core", - "h2 0.3.22", + "h2", "http", "httparse", "httpdate", - "itoa 1.0.9", - "language-tags 0.3.2", + "itoa", + "language-tags", "local-channel", "mime", "percent-encoding", - "pin-project-lite 0.2.13", + "pin-project-lite", "rand 0.8.5", - "sha1 0.10.6", + "sha1", "smallvec", - "tokio 1.34.0", - "tokio-util 0.7.10", + "tokio", + "tokio-util", "tracing", "zstd", ] -[[package]] -name = "actix-macros" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ca8ce00b267af8ccebbd647de0d61e0674b6e61185cc7a592ff88772bed655" -dependencies = [ - "quote", - "syn 1.0.109", -] - [[package]] name = "actix-macros" version = "0.2.4" @@ -186,19 +95,6 @@ dependencies = [ "syn 2.0.39", ] -[[package]] -name = "actix-router" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ad299af73649e1fc893e333ccf86f377751eb95ff875d095131574c6f43452c" -dependencies = [ - "bytestring", - "http", - "log", - "regex", - "serde", -] - [[package]] name = "actix-router" version = "0.5.1" @@ -212,21 +108,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "actix-rt" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143fcc2912e0d1de2bcf4e2f720d2a60c28652ab4179685a1ee159e0fb3db227" -dependencies = [ - "actix-macros 0.1.3", - "actix-threadpool", - "copyless", - "futures-channel", - "futures-util", - "smallvec", - "tokio 0.2.25", -] - [[package]] name = "actix-rt" version = "2.9.0" @@ -234,27 +115,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28f32d40287d3f402ae0028a9d54bef51af15c8769492826a69d28f81893151d" dependencies = [ "futures-core", - "tokio 1.34.0", -] - -[[package]] -name = "actix-server" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45407e6e672ca24784baa667c5d32ef109ccdd8d5e0b5ebb9ef8a67f4dfb708e" -dependencies = [ - "actix-codec 0.3.0", - "actix-rt 1.1.1", - "actix-service 1.0.6", - "actix-utils 2.0.0", - "futures-channel", - "futures-util", - "log", - "mio 0.6.23", - "mio-uds", - "num_cpus", - "slab", - "socket2 0.3.19", + "tokio", ] [[package]] @@ -263,27 +124,17 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3eb13e7eef0423ea6eab0e59f6c72e7cb46d33691ad56a726b3cd07ddec2c2d4" dependencies = [ - "actix-rt 2.9.0", - "actix-service 2.0.2", - "actix-utils 3.0.1", + "actix-rt", + "actix-service", + "actix-utils", "futures-core", "futures-util", - "mio 0.8.9", + "mio", "socket2 0.5.5", - "tokio 1.34.0", + "tokio", "tracing", ] -[[package]] -name = "actix-service" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0052435d581b5be835d11f4eb3bce417c8af18d87ddf8ace99f8e67e595882bb" -dependencies = [ - "futures-util", - "pin-project 0.4.30", -] - [[package]] name = "actix-service" version = "2.0.2" @@ -292,68 +143,7 @@ checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" dependencies = [ "futures-core", "paste", - "pin-project-lite 0.2.13", -] - -[[package]] -name = "actix-testing" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47239ca38799ab74ee6a8a94d1ce857014b2ac36f242f70f3f75a66f691e791c" -dependencies = [ - "actix-macros 0.1.3", - "actix-rt 1.1.1", - "actix-server 1.0.4", - "actix-service 1.0.6", - "log", - "socket2 0.3.19", -] - -[[package]] -name = "actix-threadpool" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d209f04d002854b9afd3743032a27b066158817965bf5d036824d19ac2cc0e30" -dependencies = [ - "derive_more", - "futures-channel", - "lazy_static", - "log", - "num_cpus", - "parking_lot 0.11.2", - "threadpool", -] - -[[package]] -name = "actix-tls" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24789b7d7361cf5503a504ebe1c10806896f61e96eca9a7350e23001aca715fb" -dependencies = [ - "actix-codec 0.3.0", - "actix-service 1.0.6", - "actix-utils 2.0.0", - "futures-util", -] - -[[package]] -name = "actix-utils" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9022dec56632d1d7979e59af14f0597a28a830a9c1c7fec8b2327eb9f16b5a" -dependencies = [ - "actix-codec 0.3.0", - "actix-rt 1.1.1", - "actix-service 1.0.6", - "bitflags 1.3.2", - "bytes 0.5.6", - "either", - "futures-channel", - "futures-sink", - "futures-util", - "log", - "pin-project 0.4.30", - "slab", + "pin-project-lite", ] [[package]] @@ -363,46 +153,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" dependencies = [ "local-waker", - "pin-project-lite 0.2.13", -] - -[[package]] -name = "actix-web" -version = "3.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6534a126df581caf443ba2751cab42092c89b3f1d06a9d829b1e17edfe3e277" -dependencies = [ - "actix-codec 0.3.0", - "actix-http 2.2.2", - "actix-macros 0.1.3", - "actix-router 0.2.7", - "actix-rt 1.1.1", - "actix-server 1.0.4", - "actix-service 1.0.6", - "actix-testing", - "actix-threadpool", - "actix-tls", - "actix-utils 2.0.0", - "actix-web-codegen 0.4.0", - "awc", - "bytes 0.5.6", - "derive_more", - "encoding_rs", - "futures-channel", - "futures-core", - "futures-util", - "fxhash", - "log", - "mime", - "pin-project 1.1.3", - "regex", - "serde", - "serde_json", - "serde_urlencoded", - "socket2 0.3.19", - "time 0.2.27", - "tinyvec", - "url", + "pin-project-lite", ] [[package]] @@ -411,30 +162,30 @@ version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e4a5b5e29603ca8c94a77c65cf874718ceb60292c5a5c3e5f4ace041af462b9" dependencies = [ - "actix-codec 0.5.1", - "actix-http 3.4.0", - "actix-macros 0.2.4", - "actix-router 0.5.1", - "actix-rt 2.9.0", - "actix-server 2.3.0", - "actix-service 2.0.2", - "actix-utils 3.0.1", - "actix-web-codegen 4.2.2", + "actix-codec", + "actix-http", + "actix-macros", + "actix-router", + "actix-rt", + "actix-server", + "actix-service", + "actix-utils", + "actix-web-codegen", "ahash 0.8.6", - "bytes 1.5.0", + "bytes", "bytestring", - "cfg-if 1.0.0", - "cookie 0.16.2", + "cfg-if", + "cookie", "derive_more", "encoding_rs", "futures-core", "futures-util", - "itoa 1.0.9", - "language-tags 0.3.2", + "itoa", + "language-tags", "log", "mime", "once_cell", - "pin-project-lite 0.2.13", + "pin-project-lite", "regex", "serde", "serde_json", @@ -445,24 +196,13 @@ dependencies = [ "url", ] -[[package]] -name = "actix-web-codegen" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad26f77093333e0e7c6ffe54ebe3582d908a104e448723eec6d43d08b07143fb" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "actix-web-codegen" version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb1f50ebbb30eca122b188319a4398b3f7bb4a8cdf50ecfb73bfc6a3c3ce54f5" dependencies = [ - "actix-router 0.5.1", + "actix-router", "proc-macro2", "quote", "syn 2.0.39", @@ -474,13 +214,13 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d613edf08a42ccc6864c941d30fe14e1b676a77d16f1dbadc1174d065a0a775" dependencies = [ - "actix-utils 3.0.1", - "actix-web 4.4.0", + "actix-utils", + "actix-web", "base64 0.21.5", "futures-core", "futures-util", "log", - "pin-project-lite 0.2.13", + "pin-project-lite", ] [[package]] @@ -515,7 +255,7 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "const-random", "getrandom 0.2.11", "once_cell", @@ -701,7 +441,7 @@ dependencies = [ "event-listener 4.0.0", "event-listener-strategy", "futures-core", - "pin-project-lite 0.2.13", + "pin-project-lite", ] [[package]] @@ -752,7 +492,7 @@ checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" dependencies = [ "async-lock 2.8.0", "autocfg", - "cfg-if 1.0.0", + "cfg-if", "concurrent-queue", "futures-lite 1.13.0", "log", @@ -771,7 +511,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6d3b15875ba253d1110c740755e246537483f152fa334f91abd7fe84c88b3ff" dependencies = [ "async-lock 3.1.2", - "cfg-if 1.0.0", + "cfg-if", "concurrent-queue", "futures-io", "futures-lite 2.0.1", @@ -800,7 +540,7 @@ checksum = "dea8b3453dd7cc96711834b75400d671b73e3656975fa68d9f277163b7f7e316" dependencies = [ "event-listener 4.0.0", "event-listener-strategy", - "pin-project-lite 0.2.13", + "pin-project-lite", ] [[package]] @@ -815,32 +555,6 @@ dependencies = [ "reactor-trait", ] -[[package]] -name = "async-std" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" -dependencies = [ - "async-channel 1.9.0", - "async-global-executor", - "async-io 1.13.0", - "async-lock 2.8.0", - "crossbeam-utils", - "futures-channel", - "futures-core", - "futures-io", - "futures-lite 1.13.0", - "gloo-timers", - "kv-log-macro", - "log", - "memchr", - "once_cell", - "pin-project-lite 0.2.13", - "pin-utils", - "slab", - "wasm-bindgen-futures", -] - [[package]] name = "async-task" version = "4.5.0" @@ -879,30 +593,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" -[[package]] -name = "awc" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b381e490e7b0cfc37ebc54079b0413d8093ef43d14a4e4747083f7fa47a9e691" -dependencies = [ - "actix-codec 0.3.0", - "actix-http 2.2.2", - "actix-rt 1.1.1", - "actix-service 1.0.6", - "base64 0.13.1", - "bytes 0.5.6", - "cfg-if 1.0.0", - "derive_more", - "futures-core", - "log", - "mime", - "percent-encoding", - "rand 0.7.3", - "serde", - "serde_json", - "serde_urlencoded", -] - [[package]] name = "backtrace" version = "0.3.69" @@ -911,19 +601,13 @@ checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", - "cfg-if 1.0.0", + "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", ] -[[package]] -name = "base-x" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" - [[package]] name = "base64" version = "0.13.1" @@ -948,15 +632,6 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", -] - [[package]] name = "block-buffer" version = "0.10.4" @@ -1030,12 +705,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" -[[package]] -name = "bytes" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" - [[package]] name = "bytes" version = "1.5.0" @@ -1048,7 +717,7 @@ version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74d80203ea6b29df88012294f62733de21cfeab47f17b41af3a38bc30a03ee72" dependencies = [ - "bytes 1.5.0", + "bytes", ] [[package]] @@ -1077,7 +746,7 @@ checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" dependencies = [ "camino", "cargo-platform", - "semver 1.0.20", + "semver", "serde", "serde_json", ] @@ -1088,7 +757,6 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53fd06051bc34aa7ee753647dbd36506fa9f84026993d9871e65e0ee71ac3632" dependencies = [ - "async-std", "async-trait", "fixedbitset", "getrandom 0.2.11", @@ -1101,6 +769,7 @@ dependencies = [ "ritelinked", "serde", "thiserror", + "tokio", ] [[package]] @@ -1122,12 +791,6 @@ dependencies = [ "libc", ] -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -1254,29 +917,12 @@ dependencies = [ "tiny-keccak", ] -[[package]] -name = "const_fn" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935" - [[package]] name = "convert_case" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" -[[package]] -name = "cookie" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951" -dependencies = [ - "percent-encoding", - "time 0.2.27", - "version_check", -] - [[package]] name = "cookie" version = "0.16.2" @@ -1294,12 +940,6 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396de984970346b0d9e93d1415082923c679e5ae5c3ee3dcbd104f5610af126b" -[[package]] -name = "copyless" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2df960f5d869b2dd8532793fde43eb5427cceb126c929747a26823ab0eeb536" - [[package]] name = "core-foundation" version = "0.9.3" @@ -1346,7 +986,7 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -1355,7 +995,7 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", ] @@ -1365,7 +1005,7 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", ] @@ -1375,7 +1015,7 @@ version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -1435,7 +1075,7 @@ version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "hashbrown 0.14.2", "lock_api", "once_cell", @@ -1452,7 +1092,7 @@ dependencies = [ "deadpool-runtime", "num_cpus", "retain_mut", - "tokio 1.34.0", + "tokio", ] [[package]] @@ -1464,7 +1104,7 @@ dependencies = [ "async-trait", "deadpool-runtime", "num_cpus", - "tokio 1.34.0", + "tokio", ] [[package]] @@ -1484,7 +1124,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63dfa964fe2a66f3fde91fc70b267fe193d822c7e603e2a675a49a7f46ad3f49" dependencies = [ - "tokio 1.34.0", + "tokio", ] [[package]] @@ -1536,7 +1176,7 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "rustc_version 0.4.0", + "rustc_version", "syn 1.0.109", ] @@ -1549,22 +1189,13 @@ dependencies = [ "cipher", ] -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.4", + "block-buffer", "crypto-common", "subtle", ] @@ -1586,15 +1217,9 @@ checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" dependencies = [ "libc", "redox_users", - "winapi 0.3.9", + "winapi", ] -[[package]] -name = "discard" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" - [[package]] name = "dlv-list" version = "0.3.0" @@ -1640,19 +1265,7 @@ version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "enum-as-inner" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "570d109b813e904becc80d8d5da38376818a143348413f7149f1340fe04754d4" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 1.0.109", + "cfg-if", ] [[package]] @@ -1694,7 +1307,7 @@ checksum = "770d968249b5d99410d61f5bf89057f3199a077a04d087092f58e7d10692baae" dependencies = [ "concurrent-queue", "parking", - "pin-project-lite 0.2.13", + "pin-project-lite", ] [[package]] @@ -1704,7 +1317,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" dependencies = [ "event-listener 4.0.0", - "pin-project-lite 0.2.13", + "pin-project-lite", ] [[package]] @@ -1761,7 +1374,7 @@ checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" dependencies = [ "futures-core", "futures-sink", - "pin-project 1.1.3", + "pin-project", "spin 0.9.8", ] @@ -1804,22 +1417,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -dependencies = [ - "bitflags 1.3.2", - "fuchsia-zircon-sys", -] - -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" - [[package]] name = "futures" version = "0.3.29" @@ -1890,7 +1487,7 @@ dependencies = [ "futures-io", "memchr", "parking", - "pin-project-lite 0.2.13", + "pin-project-lite", "waker-fn", ] @@ -1905,7 +1502,7 @@ dependencies = [ "futures-io", "memchr", "parking", - "pin-project-lite 0.2.13", + "pin-project-lite", ] [[package]] @@ -1950,20 +1547,11 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.13", + "pin-project-lite", "pin-utils", "slab", ] -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -1981,7 +1569,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" dependencies = [ "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -1990,7 +1578,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi 0.9.0+wasi-snapshot-preview1", ] @@ -2001,7 +1589,7 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", @@ -2020,45 +1608,13 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" -[[package]] -name = "gloo-timers" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "h2" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e4728fd124914ad25e99e3d15a9361a879f6620f63cb56bbb08f95abb97a535" -dependencies = [ - "bytes 0.5.6", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap 1.9.3", - "slab", - "tokio 0.2.25", - "tokio-util 0.3.1", - "tracing", - "tracing-futures", -] - [[package]] name = "h2" version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" dependencies = [ - "bytes 1.5.0", + "bytes", "fnv", "futures-core", "futures-sink", @@ -2066,8 +1622,8 @@ dependencies = [ "http", "indexmap 2.1.0", "slab", - "tokio 1.34.0", - "tokio-util 0.7.10", + "tokio", + "tokio-util", "tracing", ] @@ -2144,18 +1700,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.7", -] - -[[package]] -name = "hostname" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" -dependencies = [ - "libc", - "match_cfg", - "winapi 0.3.9", + "digest", ] [[package]] @@ -2164,9 +1709,9 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ - "bytes 1.5.0", + "bytes", "fnv", - "itoa 1.0.9", + "itoa", ] [[package]] @@ -2175,9 +1720,9 @@ version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ - "bytes 1.5.0", + "bytes", "http", - "pin-project-lite 0.2.13", + "pin-project-lite", ] [[package]] @@ -2192,7 +1737,7 @@ dependencies = [ "futures-lite 1.13.0", "http", "infer", - "pin-project-lite 0.2.13", + "pin-project-lite", "rand 0.7.3", "serde", "serde_json", @@ -2219,19 +1764,19 @@ version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ - "bytes 1.5.0", + "bytes", "futures-channel", "futures-core", "futures-util", - "h2 0.3.22", + "h2", "http", "http-body", "httparse", "httpdate", - "itoa 1.0.9", - "pin-project-lite 0.2.13", + "itoa", + "pin-project-lite", "socket2 0.4.10", - "tokio 1.34.0", + "tokio", "tower-service", "tracing", "want", @@ -2243,10 +1788,10 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ - "bytes 1.5.0", + "bytes", "hyper", "native-tls", - "tokio 1.34.0", + "tokio", "tokio-native-tls", ] @@ -2279,17 +1824,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -[[package]] -name = "idna" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "idna" version = "0.5.0" @@ -2344,7 +1878,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -2358,27 +1892,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "iovec" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -dependencies = [ - "libc", -] - -[[package]] -name = "ipconfig" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7e2f18aece9709094573a9f24f483c4f65caa4298e2f7ae1b71cc65d853fad7" -dependencies = [ - "socket2 0.3.19", - "widestring", - "winapi 0.3.9", - "winreg 0.6.2", -] - [[package]] name = "ipnet" version = "2.9.0" @@ -2403,12 +1916,6 @@ dependencies = [ "either", ] -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - [[package]] name = "itoa" version = "1.0.9" @@ -2444,31 +1951,6 @@ dependencies = [ "serde", ] -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] - -[[package]] -name = "kv-log-macro" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" -dependencies = [ - "log", -] - -[[package]] -name = "language-tags" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" - [[package]] name = "language-tags" version = "0.3.2" @@ -2571,24 +2053,6 @@ name = "log" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" -dependencies = [ - "value-bag", -] - -[[package]] -name = "lru-cache" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" -dependencies = [ - "linked-hash-map", -] - -[[package]] -name = "match_cfg" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" [[package]] name = "matchers" @@ -2596,14 +2060,8 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "regex-automata 0.1.10", -] - -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + "regex-automata 0.1.10", +] [[package]] name = "md-5" @@ -2611,8 +2069,8 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ - "cfg-if 1.0.0", - "digest 0.10.7", + "cfg-if", + "digest", ] [[package]] @@ -2657,25 +2115,6 @@ dependencies = [ "adler", ] -[[package]] -name = "mio" -version = "0.6.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" -dependencies = [ - "cfg-if 0.1.10", - "fuchsia-zircon", - "fuchsia-zircon-sys", - "iovec", - "kernel32-sys", - "libc", - "log", - "miow", - "net2", - "slab", - "winapi 0.2.8", -] - [[package]] name = "mio" version = "0.8.9" @@ -2688,29 +2127,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "mio-uds" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" -dependencies = [ - "iovec", - "libc", - "mio 0.6.23", -] - -[[package]] -name = "miow" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" -dependencies = [ - "kernel32-sys", - "net2", - "winapi 0.2.8", - "ws2_32-sys", -] - [[package]] name = "mutually_exclusive_features" version = "0.0.3" @@ -2735,17 +2151,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "net2" -version = "0.2.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b13b648036a2339d06de780866fbdfda0dde886de7b3af2ddeba8b14f4ee34ac" -dependencies = [ - "cfg-if 0.1.10", - "libc", - "winapi 0.3.9", -] - [[package]] name = "nom" version = "7.1.3" @@ -2763,7 +2168,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" dependencies = [ "overload", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -2800,12 +2205,6 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - [[package]] name = "openssl" version = "0.10.60" @@ -2813,7 +2212,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800" dependencies = [ "bitflags 2.4.1", - "cfg-if 1.0.0", + "cfg-if", "foreign-types", "libc", "once_cell", @@ -2879,7 +2278,7 @@ dependencies = [ "hmac", "lazy_static", "rc2", - "sha1 0.10.6", + "sha1", "yasna", ] @@ -2916,12 +2315,12 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "instant", "libc", "redox_syscall 0.2.16", "smallvec", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -2930,7 +2329,7 @@ version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall 0.4.1", "smallvec", @@ -3010,33 +2409,13 @@ dependencies = [ "indexmap 2.1.0", ] -[[package]] -name = "pin-project" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ef0f924a5ee7ea9cbcea77529dba45f8a9ba9f622419fe3386ca581a3ae9d5a" -dependencies = [ - "pin-project-internal 0.4.30", -] - [[package]] name = "pin-project" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" dependencies = [ - "pin-project-internal 1.1.3", -] - -[[package]] -name = "pin-project-internal" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "851c8d0ce9bebe43790dedfc86614c23494ac9f423dd618d3a61fc693eafe61e" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "pin-project-internal", ] [[package]] @@ -3050,12 +2429,6 @@ dependencies = [ "syn 2.0.39", ] -[[package]] -name = "pin-project-lite" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" - [[package]] name = "pin-project-lite" version = "0.2.13" @@ -3105,11 +2478,11 @@ checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" dependencies = [ "autocfg", "bitflags 1.3.2", - "cfg-if 1.0.0", + "cfg-if", "concurrent-queue", "libc", "log", - "pin-project-lite 0.2.13", + "pin-project-lite", "windows-sys 0.48.0", ] @@ -3119,9 +2492,9 @@ version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf63fa624ab313c11656b4cda960bfc46c410187ad493c41f6ba2d8c1e991c9e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "concurrent-queue", - "pin-project-lite 0.2.13", + "pin-project-lite", "rustix 0.38.25", "tracing", "windows-sys 0.52.0", @@ -3163,12 +2536,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - [[package]] name = "proc-macro2" version = "1.0.70" @@ -3189,12 +2556,6 @@ dependencies = [ "unicase", ] -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - [[package]] name = "quote" version = "1.0.33" @@ -3375,11 +2736,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" dependencies = [ "base64 0.21.5", - "bytes 1.5.0", + "bytes", "encoding_rs", "futures-core", "futures-util", - "h2 0.3.22", + "h2", "http", "http-body", "hyper", @@ -3391,29 +2752,19 @@ dependencies = [ "native-tls", "once_cell", "percent-encoding", - "pin-project-lite 0.2.13", + "pin-project-lite", "serde", "serde_json", "serde_urlencoded", "system-configuration", - "tokio 1.34.0", + "tokio", "tokio-native-tls", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "winreg 0.50.0", -] - -[[package]] -name = "resolv-conf" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" -dependencies = [ - "hostname", - "quick-error", + "winreg", ] [[package]] @@ -3462,7 +2813,7 @@ dependencies = [ "spin 0.5.2", "untrusted 0.7.1", "web-sys", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -3506,7 +2857,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "ordered-multimap", ] @@ -3516,22 +2867,13 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver 0.9.0", -] - [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.20", + "semver", ] [[package]] @@ -3691,15 +3033,6 @@ dependencies = [ "libc", ] -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - [[package]] name = "semver" version = "1.0.20" @@ -3709,12 +3042,6 @@ dependencies = [ "serde", ] -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - [[package]] name = "serde" version = "1.0.193" @@ -3741,7 +3068,7 @@ version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ - "itoa 1.0.9", + "itoa", "ryu", "serde", ] @@ -3752,7 +3079,7 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335" dependencies = [ - "itoa 1.0.9", + "itoa", "serde", ] @@ -3774,7 +3101,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 1.0.9", + "itoa", "ryu", "serde", ] @@ -3830,60 +3157,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cc7a1570e38322cfe4154732e5110f887ea57e22b76f4bfd32b5bdd3368666c" dependencies = [ "indexmap 2.1.0", - "itoa 1.0.9", + "itoa", "ryu", "serde", "unsafe-libyaml", ] -[[package]] -name = "sha-1" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", -] - -[[package]] -name = "sha1" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" -dependencies = [ - "sha1_smol", -] - [[package]] name = "sha1" version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", - "digest 0.10.7", + "digest", ] -[[package]] -name = "sha1_smol" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" - [[package]] name = "sha2" version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", - "digest 0.10.7", + "digest", ] [[package]] @@ -3949,17 +3248,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "socket2" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "winapi 0.3.9", -] - [[package]] name = "socket2" version = "0.4.10" @@ -3967,7 +3255,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -4027,7 +3315,7 @@ dependencies = [ "base64 0.13.1", "bitflags 1.3.2", "byteorder", - "bytes 1.5.0", + "bytes", "chrono", "crc", "crossbeam-queue", @@ -4044,7 +3332,7 @@ dependencies = [ "hkdf", "hmac", "indexmap 1.9.3", - "itoa 1.0.9", + "itoa", "libc", "log", "md-5", @@ -4057,7 +3345,7 @@ dependencies = [ "rustls-pemfile", "serde", "serde_json", - "sha1 0.10.6", + "sha1", "sha2", "smallvec", "sqlformat", @@ -4100,7 +3388,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "804d3f245f894e61b1e6263c84b23ca675d96753b5abfd5cc8597d86806e8024" dependencies = [ "once_cell", - "tokio 1.34.0", + "tokio", "tokio-rustls", ] @@ -4110,8 +3398,8 @@ version = "0.1.0" dependencies = [ "actix-casbin-auth", "actix-cors", - "actix-http 3.4.0", - "actix-web 4.4.0", + "actix-http", + "actix-web", "actix-web-httpauth", "chrono", "clap", @@ -4138,7 +3426,7 @@ dependencies = [ "sha2", "sqlx", "thiserror", - "tokio 1.34.0", + "tokio", "tokio-stream", "tracing", "tracing-actix-web", @@ -4149,70 +3437,12 @@ dependencies = [ "wiremock", ] -[[package]] -name = "standback" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" -dependencies = [ - "version_check", -] - [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "stdweb" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" -dependencies = [ - "discard", - "rustc_version 0.2.3", - "stdweb-derive", - "stdweb-internal-macros", - "stdweb-internal-runtime", - "wasm-bindgen", -] - -[[package]] -name = "stdweb-derive" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "serde_derive", - "syn 1.0.109", -] - -[[package]] -name = "stdweb-internal-macros" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" -dependencies = [ - "base-x", - "proc-macro2", - "quote", - "serde", - "serde_derive", - "serde_json", - "sha1 0.6.1", - "syn 1.0.109", -] - -[[package]] -name = "stdweb-internal-runtime" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" - [[package]] name = "stringprep" version = "0.1.4" @@ -4291,7 +3521,7 @@ version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4da30af7998f51ee1aa48ab24276fe303a697b004e31ff542b192c088d5630a5" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "p12", "rustls-connector", "rustls-pemfile", @@ -4303,7 +3533,7 @@ version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "fastrand 2.0.1", "redox_syscall 0.4.1", "rustix 0.38.25", @@ -4336,19 +3566,10 @@ version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "once_cell", ] -[[package]] -name = "threadpool" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" -dependencies = [ - "num_cpus", -] - [[package]] name = "time" version = "0.1.45" @@ -4357,22 +3578,7 @@ checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" dependencies = [ "libc", "wasi 0.10.0+wasi-snapshot-preview1", - "winapi 0.3.9", -] - -[[package]] -name = "time" -version = "0.2.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" -dependencies = [ - "const_fn", - "libc", - "standback", - "stdweb", - "time-macros 0.1.1", - "version_check", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -4382,11 +3588,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" dependencies = [ "deranged", - "itoa 1.0.9", + "itoa", "powerfmt", "serde", "time-core", - "time-macros 0.2.15", + "time-macros", ] [[package]] @@ -4395,16 +3601,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" -[[package]] -name = "time-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" -dependencies = [ - "proc-macro-hack", - "time-macros-impl", -] - [[package]] name = "time-macros" version = "0.2.15" @@ -4414,19 +3610,6 @@ dependencies = [ "time-core", ] -[[package]] -name = "time-macros-impl" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" -dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "standback", - "syn 1.0.109", -] - [[package]] name = "tiny-keccak" version = "2.0.2" @@ -4451,26 +3634,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" -[[package]] -name = "tokio" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092" -dependencies = [ - "bytes 0.5.6", - "futures-core", - "iovec", - "lazy_static", - "libc", - "memchr", - "mio 0.6.23", - "mio-uds", - "pin-project-lite 0.1.12", - "signal-hook-registry", - "slab", - "winapi 0.3.9", -] - [[package]] name = "tokio" version = "1.34.0" @@ -4478,12 +3641,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ "backtrace", - "bytes 1.5.0", + "bytes", "libc", - "mio 0.8.9", + "mio", "num_cpus", "parking_lot 0.12.1", - "pin-project-lite 0.2.13", + "pin-project-lite", "signal-hook-registry", "socket2 0.5.5", "tokio-macros", @@ -4498,7 +3661,7 @@ checksum = "802ccf58e108fe16561f35348fabe15ff38218968f033d587e399a84937533cc" dependencies = [ "async-trait", "executor-trait", - "tokio 1.34.0", + "tokio", ] [[package]] @@ -4519,7 +3682,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" dependencies = [ "native-tls", - "tokio 1.34.0", + "tokio", ] [[package]] @@ -4529,7 +3692,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" dependencies = [ "rustls 0.20.9", - "tokio 1.34.0", + "tokio", "webpki", ] @@ -4540,22 +3703,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ "futures-core", - "pin-project-lite 0.2.13", - "tokio 1.34.0", -] - -[[package]] -name = "tokio-util" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" -dependencies = [ - "bytes 0.5.6", - "futures-core", - "futures-sink", - "log", - "pin-project-lite 0.1.12", - "tokio 0.2.25", + "pin-project-lite", + "tokio", ] [[package]] @@ -4564,11 +3713,11 @@ version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ - "bytes 1.5.0", + "bytes", "futures-core", "futures-sink", - "pin-project-lite 0.2.13", - "tokio 1.34.0", + "pin-project-lite", + "tokio", "tracing", ] @@ -4594,7 +3743,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "log", - "pin-project-lite 0.2.13", + "pin-project-lite", "tracing-attributes", "tracing-core", ] @@ -4605,9 +3754,9 @@ version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fe0d5feac3f4ca21ba33496bcb1ccab58cca6412b1405ae80f0581541e0ca78" dependencies = [ - "actix-web 4.4.0", + "actix-web", "mutually_exclusive_features", - "pin-project 1.1.3", + "pin-project", "tracing", "uuid", ] @@ -4651,16 +3800,6 @@ dependencies = [ "valuable", ] -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project 1.1.3", - "tracing", -] - [[package]] name = "tracing-log" version = "0.1.4" @@ -4707,45 +3846,6 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3" -[[package]] -name = "trust-dns-proto" -version = "0.19.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cad71a0c0d68ab9941d2fb6e82f8fb2e86d9945b94e1661dd0aaea2b88215a9" -dependencies = [ - "async-trait", - "cfg-if 1.0.0", - "enum-as-inner", - "futures", - "idna 0.2.3", - "lazy_static", - "log", - "rand 0.7.3", - "smallvec", - "thiserror", - "tokio 0.2.25", - "url", -] - -[[package]] -name = "trust-dns-resolver" -version = "0.19.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "710f593b371175db53a26d0b38ed2978fafb9e9e8d3868b1acd753ea18df0ceb" -dependencies = [ - "cfg-if 0.1.10", - "futures", - "ipconfig", - "lazy_static", - "log", - "lru-cache", - "resolv-conf", - "smallvec", - "thiserror", - "tokio 0.2.25", - "trust-dns-proto", -] - [[package]] name = "try-lock" version = "0.2.4" @@ -4831,7 +3931,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", - "idna 0.5.0", + "idna", "percent-encoding", "serde", ] @@ -4858,12 +3958,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" -[[package]] -name = "value-bag" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cdbaf5e132e593e9fc1de6a15bbec912395b11fb9719e061cf64f804524c503" - [[package]] name = "vcpkg" version = "0.2.15" @@ -4925,7 +4019,7 @@ version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "wasm-bindgen-macro", ] @@ -4950,7 +4044,7 @@ version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "wasm-bindgen", "web-sys", @@ -5024,18 +4118,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "widestring" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c" - -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" - [[package]] name = "winapi" version = "0.3.9" @@ -5046,12 +4128,6 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu", ] -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" - [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -5064,7 +4140,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -5214,22 +4290,13 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" -[[package]] -name = "winreg" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" -dependencies = [ - "winapi 0.3.9", -] - [[package]] name = "winreg" version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "windows-sys 0.48.0", ] @@ -5252,17 +4319,7 @@ dependencies = [ "regex", "serde", "serde_json", - "tokio 1.34.0", -] - -[[package]] -name = "ws2_32-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -dependencies = [ - "winapi 0.2.8", - "winapi-build", + "tokio", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 024d61b..abf15fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,7 +55,7 @@ clap = { version = "4.4.8", features = ["derive"] } serde_path_to_error = "0.1.14" deadpool-lapin = "0.11.0" docker-compose-types = "0.7.0" -actix-casbin-auth = "0.4.4" +actix-casbin-auth = { git = "https://github.com/casbin-rs/actix-casbin-auth.git"} [dependencies.sqlx] version = "0.6.3" diff --git a/rbac/rbac_with_pattern_model.conf b/rbac/rbac_with_pattern_model.conf new file mode 100644 index 0000000..44507a6 --- /dev/null +++ b/rbac/rbac_with_pattern_model.conf @@ -0,0 +1,15 @@ +[request_definition] +r = sub, obj, act + +[policy_definition] +p = sub, obj, act + +[role_definition] +g = _, _ +g2 = _, _ + +[policy_effect] +e = some(where (p.eft == allow)) + +[matchers] +m = g(r.sub, p.sub) && g2(r.obj, p.obj) && regexMatch(r.act, p.act) diff --git a/rbac/rbac_with_pattern_policy.csv b/rbac/rbac_with_pattern_policy.csv new file mode 100644 index 0000000..ea5b1a6 --- /dev/null +++ b/rbac/rbac_with_pattern_policy.csv @@ -0,0 +1,10 @@ +p, petru, /testcasbin, GET +p, alice, /pen/1, GET +p, alice, /pen2/1, GET +p, book_admin, book_group, GET +p, pen_admin, pen_group, GET + +g, alice, book_admin +g, bob, pen_admin +g2, /book/:id, book_group +g2, /pen/:id, pen_group diff --git a/src/middleware/trydirect.rs b/src/middleware/trydirect.rs index c079635..33c54a7 100644 --- a/src/middleware/trydirect.rs +++ b/src/middleware/trydirect.rs @@ -20,6 +20,13 @@ pub async fn bearer_guard( req: ServiceRequest, credentials: BearerAuth) -> Resu return Err((JsonResponse::::build().unauthorized("user already logged"), req)); } + let vals = actix_casbin_auth::CasbinVals { //todo + subject: String::from("alice"), + domain: Some("/pen/1".to_string()), + }; + let result = req.extensions_mut().insert(vals); //todo + tracing::error!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA {}", result.is_some()); //todo + Ok(req) } diff --git a/src/routes/test/casbin.rs b/src/routes/test/casbin.rs new file mode 100644 index 0000000..77e1ec5 --- /dev/null +++ b/src/routes/test/casbin.rs @@ -0,0 +1,8 @@ +use actix_web::{get, Responder, Result}; +use crate::helpers::JsonResponse; + +#[tracing::instrument(name = "Test casbin.")] +#[get("")] +pub async fn handler() -> Result { + Ok(JsonResponse::::build().ok("success")) +} diff --git a/src/routes/test/deploy.rs b/src/routes/test/deploy.rs index 4f36a3a..f123417 100644 --- a/src/routes/test/deploy.rs +++ b/src/routes/test/deploy.rs @@ -1,15 +1,8 @@ use crate::models::Client; use actix_web::{post, web, Responder, Result}; -use serde::Serialize; use std::sync::Arc; use crate::helpers::JsonResponse; -#[derive(Serialize)] -struct DeployResponse { - status: String, - client: Arc, -} - #[tracing::instrument(name = "Test deploy.")] #[post("/deploy")] pub async fn handler(client: web::ReqData>) -> Result { diff --git a/src/routes/test/mod.rs b/src/routes/test/mod.rs index 40149b1..2b55b42 100644 --- a/src/routes/test/mod.rs +++ b/src/routes/test/mod.rs @@ -1 +1,2 @@ pub mod deploy; +pub mod casbin; diff --git a/src/startup.rs b/src/startup.rs index b510af6..f00d0d8 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -11,6 +11,11 @@ use sqlx::{Pool, Postgres}; use std::net::TcpListener; use tracing_actix_web::TracingLogger; +use actix_casbin_auth::casbin::{DefaultModel, FileAdapter};//, Result}; +use actix_casbin_auth::CasbinService; +use actix_casbin_auth::casbin::function_map::key_match2; +use actix_casbin_auth::casbin::CoreApi; + pub async fn run( listener: TcpListener, pg_pool: Pool, @@ -22,6 +27,22 @@ pub async fn run( let mq_manager = helpers::MqManager::try_new(settings.amqp.connection_string())?; let mq_manager = web::Data::new(mq_manager); + //casbin + let m = DefaultModel::from_file("rbac/rbac_with_pattern_model.conf") + .await + .unwrap(); + let a = FileAdapter::new("rbac/rbac_with_pattern_policy.csv"); //You can also use diesel-adapter or sqlx-adapter + + let casbin_middleware = CasbinService::new(m, a).await.unwrap(); //todo + + casbin_middleware + .write() + .await + .get_role_manager() + .write() + //.unwrap() + .matching_fn(Some(key_match2), None); + let server = HttpServer::new(move || { App::new() .wrap(TracingLogger::default()) @@ -39,10 +60,20 @@ pub async fn run( ) .service( web::scope("/test") + .wrap(casbin_middleware.clone()) .wrap(crate::middleware::client::Guard::new()) .wrap(Cors::permissive()) .service(crate::routes::test::deploy::handler), ) + .service( + web::scope("/pen/1") + .wrap(casbin_middleware.clone()) //todo + .wrap(HttpAuthentication::bearer( + crate::middleware::trydirect::bearer_guard, + )) + .wrap(Cors::permissive()) + .service(crate::routes::test::casbin::handler), + ) .service( web::scope("/rating") .wrap(HttpAuthentication::bearer( From 1833e8fafee6010c2846d8712692c2e4d9fb9864 Mon Sep 17 00:00:00 2001 From: vsilent Date: Wed, 24 Jan 2024 15:12:19 +0200 Subject: [PATCH 152/284] test fixes --- src/forms/stack.rs | 43 +++++++------- src/helpers/dockerhub.rs | 32 +++++----- src/helpers/mod.rs | 2 +- src/helpers/stack/builder.rs | 44 ++++++++++---- src/helpers/stack/mod.rs | 2 +- tests/dockerhub.rs | 110 ++++++++++++++++------------------- 6 files changed, 125 insertions(+), 108 deletions(-) diff --git a/src/forms/stack.rs b/src/forms/stack.rs index 07674fa..135d0d0 100644 --- a/src/forms/stack.rs +++ b/src/forms/stack.rs @@ -3,7 +3,7 @@ use serde_json::Value; use serde_valid::Validate; use std::fmt; use regex::Regex; -use crate::helpers::dockerhub::{DockerHub, DockerHubCreds, DockerHubToken}; +use crate::helpers::dockerhub::DockerHub; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Role { @@ -102,7 +102,7 @@ impl fmt::Display for DockerImage { impl DockerImage { #[tracing::instrument(name = "is_active")] - async fn is_active(&self) -> Result { + pub async fn is_active(&self) -> Result { DockerHub::from(self).is_active().await } } @@ -170,23 +170,24 @@ impl StackForm { } } - if let Some(service) = &self.custom.service { - for app in service { - if !app.app.docker_image.is_active().await? { - is_active = false; - break; - } - } - } - - if let Some(features) = &self.custom.feature { - for app in features { - if !app.app.docker_image.is_active().await? { - is_active = false; - break; - } - } - } + // temporarily disabled + // if let Some(service) = &self.custom.service { + // for app in service { + // if !app.app.docker_image.is_active().await? { + // is_active = false; + // break; + // } + // } + // } + // + // if let Some(features) = &self.custom.feature { + // for app in features { + // if !app.app.docker_image.is_active().await? { + // is_active = false; + // break; + // } + // } + // } Ok(is_active) } } @@ -350,8 +351,8 @@ pub struct Environment { #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Volume { - pub(crate) host_path: Option, - pub(crate) container_path: Option, + pub host_path: Option, + pub container_path: Option, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] diff --git a/src/helpers/dockerhub.rs b/src/helpers/dockerhub.rs index e93783a..a4af31c 100644 --- a/src/helpers/dockerhub.rs +++ b/src/helpers/dockerhub.rs @@ -52,17 +52,17 @@ struct Tag { } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] struct TagResult { - count: i64, - next: Value, - previous: Value, + pub count: Option, + next: Option, + previous: Option, results: Vec } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct RepoResults { - pub count: i64, - pub next: Value, - pub previous: Value, + pub count: Option, + pub next: Option, + pub previous: Option, pub results: Vec, } @@ -85,7 +85,7 @@ pub struct RepoResult { } #[derive(Default, Debug, Clone, PartialEq, Serialize, Validate)] -pub(crate) struct DockerHub<'a> { +pub struct DockerHub<'a> { pub(crate) creds: DockerHubCreds<'a>, pub(crate) repos: String, pub(crate) image: String, @@ -123,10 +123,10 @@ impl<'a> DockerHub<'a> { })? .json::() .await - .map_err(|err| format!("{}", err)) + .map_err(|err| format!("Error on getting results:: {}", err)) .map(|repositories| { tracing::debug!("Get public image repositories response {:?}", repositories); - if repositories.count > 0 { + if repositories.count.unwrap_or(0) > 0 { // let's find at least one active tag let active = repositories.results .into_iter() @@ -159,7 +159,7 @@ impl<'a> DockerHub<'a> { }) .map(|tags| { tracing::debug!("Validate private image response {:?}", tags); - if tags.count > 0 { + if tags.count.unwrap_or(0) > 0 { // let's find at least one active tag let active = tags.results .into_iter() @@ -174,10 +174,16 @@ impl<'a> DockerHub<'a> { // if namespace/user is not set change endpoint and return a different response if self.creds.username.is_empty() { - return self.lookup_public_repo().await; + match self.lookup_public_repo().await { + Ok(result) => Ok(result), + Err(_e) => Ok(false) + } + } else{ + match self.lookup_private_repo().await { + Ok(result) => Ok(result), + Err(_e) => Ok(false) + } } - return self.lookup_private_repo().await; - } pub async fn set_token(&self, mut client: RequestBuilder) -> Result { diff --git a/src/helpers/mod.rs b/src/helpers/mod.rs index 3fe765f..e02a2c7 100644 --- a/src/helpers/mod.rs +++ b/src/helpers/mod.rs @@ -1,6 +1,6 @@ pub mod client; pub(crate) mod json; -pub(crate) mod stack; +pub mod stack; pub use json::*; pub(crate) mod compressor; pub mod dockerhub; diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 501d22e..1d7868a 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -5,7 +5,7 @@ use crate::helpers::stack::dctypes::{Compose, Port, Ports, PublishedPort, Servic ComposeNetworks, MapOrEmpty, ComposeNetworkSettingDetails, NetworkSettings}; use serde_yaml; -use crate::forms::{StackForm, stack, App, Volume, Web}; +use crate::forms::{StackForm, stack, App, Volume}; use crate::models::stack::Stack; #[derive(Clone, Debug)] struct Config {} @@ -36,16 +36,23 @@ pub struct DcBuilder { } impl TryInto for Volume { + // service volumes type Error = String; fn try_into(self) -> Result { let source = self.host_path.clone(); let target = self.container_path.clone(); tracing::debug!("Volume conversion result: source: {:?} target: {:?}", source, target); + let _type = if is_named_docker_volume(source.as_ref().unwrap()) { + "volume" + } else { + "bind" + }; + Ok(AdvancedVolumes { - source: source, + source, target: target.unwrap_or("".to_string()), - _type: "".to_string(), + _type: _type.to_string(), read_only: false, bind: None, volume: None, @@ -216,7 +223,28 @@ impl Into>> for stack::ComposeNetwo } } +impl Into for Volume { + fn into(self) -> ComposeVolume { + // let's create a symlink to /var/docker/volumes in project docroot + let mut driver_opts = IndexMap::default(); + let host_path = self.host_path.unwrap(); + driver_opts.insert(String::from("type"), Some(SingleValue::String("none".to_string()))); + driver_opts.insert(String::from("o"), Some(SingleValue::String("bind".to_string()))); + // @todo move to config stack docroot on host + let path = format!("/root/stack/{}", &host_path); + driver_opts.insert(String::from("device"), Some(SingleValue::String(path))); + + ComposeVolume { + driver: Some(String::from("local")), + driver_opts: driver_opts, + external: None, + labels: Default::default(), + name: Some(host_path) + } + } +} +#[tracing::instrument(name = "extract_named_volumes")] pub fn extract_named_volumes(app: App) -> IndexMap> { let mut named_volumes = IndexMap::default(); @@ -232,18 +260,12 @@ pub fn extract_named_volumes(app: App) -> IndexMap>>(); named_volumes.extend(volumes); - // tracing::debug!("Named volumes: {:?}", named_volumes); + tracing::debug!("Named volumes: {:?}", named_volumes); named_volumes } diff --git a/src/helpers/stack/mod.rs b/src/helpers/stack/mod.rs index 7da2d2e..6f09fdb 100644 --- a/src/helpers/stack/mod.rs +++ b/src/helpers/stack/mod.rs @@ -1,2 +1,2 @@ pub(crate) mod builder; -pub(crate) mod dctypes; \ No newline at end of file +pub mod dctypes; \ No newline at end of file diff --git a/tests/dockerhub.rs b/tests/dockerhub.rs index e13fe55..f109582 100644 --- a/tests/dockerhub.rs +++ b/tests/dockerhub.rs @@ -2,11 +2,13 @@ // use std::collections::HashMap; use std::env; mod common; -use stacker::helpers::dockerhub::{login, docker_image_exists}; +use stacker::forms::stack::DockerImage; +use stacker::helpers::stack::dctypes::{ComposeVolume, SingleValue}; +use serde_yaml; +use stacker::forms::Volume; const DOCKER_USERNAME: &str = "trydirect"; -const DOCKER_PASSWORD: &str = "dckr_pat_NyQoqqA2VFtBtCuZRp8YcjbuFkU"; - +const DOCKER_PASSWORD: &str = "*******"; // Unit Test // #[test] @@ -54,7 +56,7 @@ const DOCKER_PASSWORD: &str = "dckr_pat_NyQoqqA2VFtBtCuZRp8YcjbuFkU"; // } #[tokio::test] -async fn test_docker_hub_login() { +async fn test_docker_hub_successful_login() { common::spawn_app().await; // server // let username = env::var("TEST_DOCKER_USERNAME") @@ -62,78 +64,64 @@ async fn test_docker_hub_login() { // // let password= env::var("TEST_DOCKER_PASSWORD") // .expect("password environment variable is not set"); - let result = login( - DOCKER_USERNAME.as_ref(), - DOCKER_PASSWORD.as_ref() - ).await; - let token = result.unwrap().token; - - let exists: bool = match token { - Some(tok) => { - let exists = docker_image_exists(DOCKER_USERNAME, "nginx", tok).await; - match exists { - Ok(_) => true, - Err(err) => { - println!("{:?}", err); - false - } - } - } - _ => false, + let di = DockerImage { + dockerhub_user: Some(String::from("trydirect")), + dockerhub_name: Some(String::from("nginx-waf")), + dockerhub_image: None, + dockerhub_password: Some(String::from(DOCKER_PASSWORD)) }; - - assert_eq!(exists, true); + assert_eq!(di.is_active().await.unwrap(), true); } #[tokio::test] async fn test_docker_private_exists() { common::spawn_app().await; // server - let result = login( - DOCKER_USERNAME.as_ref(), DOCKER_PASSWORD.as_ref() - ).await; - let token = result.unwrap().token; - - let exists: bool = match token { - Some(tok) => { - let exists = docker_image_exists(DOCKER_USERNAME, "nginx-waf", tok).await; - match exists { - Ok(_) => true, - Err(err) => { - println!("{:?}", err); - false - } - } - } - _ => false, + let di = DockerImage { + dockerhub_user: Some(String::from("trydirect")), + dockerhub_name: Some(String::from("nginx-waf")), + dockerhub_image: None, + dockerhub_password: Some(String::from(DOCKER_PASSWORD)) }; - - assert_eq!(exists, true); + assert_eq!(di.is_active().await.unwrap(), true); } +#[tokio::test] +async fn test_public_repo_is_accessible() { + + common::spawn_app().await; // server + let di = DockerImage { + dockerhub_user: Some(String::from("")), + dockerhub_name: Some(String::from("nginx")), + dockerhub_image: None, + dockerhub_password: Some(String::from("")) + }; + assert_eq!(di.is_active().await.unwrap(), true); +} #[tokio::test] async fn test_docker_non_existent_repo() { common::spawn_app().await; // server - let result= login( - DOCKER_USERNAME.as_ref(), DOCKER_PASSWORD.as_ref() - ).await; - let token = result.unwrap().token; + let di = DockerImage { + dockerhub_user: Some(String::from("trydirect")), + dockerhub_name: Some(String::from("nonexistent")), + dockerhub_image: None, + dockerhub_password: Some(String::from("")) + }; + assert_eq!(di.is_active().await.unwrap(), false); +} - // println!("{:?}", token); - let exists: bool = match token { - Some(tok) => { - let exists = docker_image_exists(DOCKER_USERNAME, "nonexistent", tok).await; - match exists { - Ok(_) => true, - Err(err) => { - println!("{:?}", err); - false - } - } - } - _ => false, +#[tokio::test] +async fn test_docker_named_volume() { + let volume = Volume { + host_path: Some("flask-data".to_owned()), + container_path: Some("/var/www/flaskdata".to_owned()), }; - assert_eq!(exists, false); + let cv:ComposeVolume = volume.into(); + println!("ComposeVolume: {:?}", cv); + println!("{:?}", cv.driver_opts); + assert_eq!(Some("flask-data".to_string()), cv.name); + assert_eq!(&Some(SingleValue::String("/root/stack/flask-data".to_string())), cv.driver_opts.get("device").unwrap()); + assert_eq!(&Some(SingleValue::String("none".to_string())), cv.driver_opts.get("type").unwrap()); } From 3286ae59e77699569ff0c29a9bdfc47a8320bc17 Mon Sep 17 00:00:00 2001 From: vsilent Date: Wed, 24 Jan 2024 19:47:40 +0200 Subject: [PATCH 153/284] restart policy fix --- src/forms/stack.rs | 3 ++- src/helpers/stack/builder.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/forms/stack.rs b/src/forms/stack.rs index 135d0d0..fe04381 100644 --- a/src/forms/stack.rs +++ b/src/forms/stack.rs @@ -327,7 +327,8 @@ pub struct App { pub repo_dir: Option, pub url_app: Option, pub url_git: Option, - pub restart: Option, + #[validate(enumerate("always", "no", "unless-stopped", "on-failure"))] + pub restart: String, pub volumes: Option>, #[serde(flatten)] pub environment: Environment, diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 1d7868a..23d1bd9 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -170,7 +170,7 @@ impl TryIntoService for App { service.networks = networks; service.ports = Ports::Long(ports); - service.restart = Some("always".to_owned()); + service.restart = Some(self.restart.clone()); service.volumes = Volumes::Advanced(volumes); service.environment = Environment::KvPair(envs); From 1045db8762a93a51a2d385e57ee043d0b1690857 Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 27 Jan 2024 23:18:22 +0200 Subject: [PATCH 154/284] issue-auth casbin.1 --- Cargo.lock | 642 ++++++++++++++++-------------- Cargo.toml | 3 +- rbac/rbac_with_pattern_model.conf | 9 +- rbac/rbac_with_pattern_policy.csv | 16 +- src/middleware/trydirect.rs | 2 +- src/startup.rs | 3 +- 6 files changed, 347 insertions(+), 328 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 35a4403..c4ceaf8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,7 +5,7 @@ version = 3 [[package]] name = "actix-casbin-auth" version = "0.4.4" -source = "git+https://github.com/casbin-rs/actix-casbin-auth.git#5f8550953a29460d18029fb50785773d6957d717" +source = "git+https://github.com/smart--petea/actix-casbin-auth.git?branch=dirty-master#795c1209e4dea6078a787ccf7a882bd5d1148be7" dependencies = [ "actix-service", "actix-web", @@ -33,9 +33,9 @@ dependencies = [ [[package]] name = "actix-cors" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b340e9cfa5b08690aae90fb61beb44e9b06f44fe3d0f93781aaa58cfba86245e" +checksum = "0346d8c1f762b41b458ed3145eea914966bb9ad20b9be0d6d463b20d45586370" dependencies = [ "actix-utils", "actix-web", @@ -48,17 +48,17 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.4.0" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92ef85799cba03f76e4f7c10f533e66d87c9a7e7055f3391f09000ad8351bc9" +checksum = "129d4c88e98860e1758c5de288d1632b07970a16d59bdf7b8d66053d582bb71f" dependencies = [ "actix-codec", "actix-rt", "actix-service", "actix-utils", - "ahash 0.8.6", - "base64 0.21.5", - "bitflags 2.4.1", + "ahash 0.8.7", + "base64 0.21.7", + "bitflags 2.4.2", "brotli", "bytes", "bytestring", @@ -92,14 +92,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] name = "actix-router" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66ff4d247d2b160861fa2866457e85706833527840e4133f8f49aa423a38799" +checksum = "d22475596539443685426b6bdadb926ad0ecaefdfc5fb05e5e3441f15463c511" dependencies = [ "bytestring", "http", @@ -158,9 +158,9 @@ dependencies = [ [[package]] name = "actix-web" -version = "4.4.0" +version = "4.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4a5b5e29603ca8c94a77c65cf874718ceb60292c5a5c3e5f4ace041af462b9" +checksum = "e43428f3bf11dee6d166b00ec2df4e3aa8cc1606aaa0b7433c146852e2f4e03b" dependencies = [ "actix-codec", "actix-http", @@ -171,7 +171,7 @@ dependencies = [ "actix-service", "actix-utils", "actix-web-codegen", - "ahash 0.8.6", + "ahash 0.8.7", "bytes", "bytestring", "cfg-if", @@ -192,7 +192,7 @@ dependencies = [ "serde_urlencoded", "smallvec", "socket2 0.5.5", - "time 0.3.30", + "time 0.3.31", "url", ] @@ -205,7 +205,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -216,7 +216,7 @@ checksum = "1d613edf08a42ccc6864c941d30fe14e1b676a77d16f1dbadc1174d065a0a775" dependencies = [ "actix-utils", "actix-web", - "base64 0.21.5", + "base64 0.21.7", "futures-core", "futures-util", "log", @@ -244,20 +244,20 @@ version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.12", "once_cell", "version_check", ] [[package]] name = "ahash" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" +checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" dependencies = [ "cfg-if", "const-random", - "getrandom 0.2.11", + "getrandom 0.2.12", "once_cell", "version_check", "zerocopy", @@ -358,9 +358,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.4" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" +checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" dependencies = [ "anstyle", "anstyle-parse", @@ -378,37 +378,37 @@ checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" [[package]] name = "anstyle-parse" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.1" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" dependencies = [ "anstyle", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "anyhow" -version = "1.0.75" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" [[package]] name = "assert-json-diff" @@ -438,7 +438,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ca33f4bc4ed1babef42cad36cc1f51fa88be00420404e5b1e80ab1b18f7678c" dependencies = [ "concurrent-queue", - "event-listener 4.0.0", + "event-listener 4.0.3", "event-listener-strategy", "futures-core", "pin-project-lite", @@ -450,26 +450,26 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17ae5ebefcc48e7452b4987947920dac9450be1110cadf34d1b8c116bdbaf97c" dependencies = [ - "async-lock 3.1.2", + "async-lock 3.3.0", "async-task", "concurrent-queue", "fastrand 2.0.1", - "futures-lite 2.0.1", + "futures-lite 2.2.0", "slab", ] [[package]] name = "async-global-executor" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4353121d5644cdf2beb5726ab752e79a8db1ebb52031770ec47db31d245526" +checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ "async-channel 2.1.1", "async-executor", - "async-io 2.2.1", - "async-lock 3.1.2", + "async-io 2.3.0", + "async-lock 3.3.0", "blocking", - "futures-lite 2.0.1", + "futures-lite 2.2.0", "once_cell", ] @@ -506,18 +506,18 @@ dependencies = [ [[package]] name = "async-io" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6d3b15875ba253d1110c740755e246537483f152fa334f91abd7fe84c88b3ff" +checksum = "fb41eb19024a91746eba0773aa5e16036045bbf45733766661099e182ea6a744" dependencies = [ - "async-lock 3.1.2", + "async-lock 3.3.0", "cfg-if", "concurrent-queue", "futures-io", - "futures-lite 2.0.1", + "futures-lite 2.2.0", "parking", - "polling 3.3.1", - "rustix 0.38.25", + "polling 3.3.2", + "rustix 0.38.30", "slab", "tracing", "windows-sys 0.52.0", @@ -534,11 +534,11 @@ dependencies = [ [[package]] name = "async-lock" -version = "3.1.2" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea8b3453dd7cc96711834b75400d671b73e3656975fa68d9f277163b7f7e316" +checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" dependencies = [ - "event-listener 4.0.0", + "event-listener 4.0.3", "event-listener-strategy", "pin-project-lite", ] @@ -557,19 +557,19 @@ dependencies = [ [[package]] name = "async-task" -version = "4.5.0" +version = "4.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4eb2cdb97421e01129ccb49169d8279ed21e829929144f4a22a6e54ac549ca1" +checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799" [[package]] name = "async-trait" -version = "0.1.74" +version = "0.1.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -616,9 +616,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.5" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "bitflags" @@ -628,9 +628,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" [[package]] name = "block-buffer" @@ -657,11 +657,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118" dependencies = [ "async-channel 2.1.1", - "async-lock 3.1.2", + "async-lock 3.3.0", "async-task", "fastrand 2.0.1", "futures-io", - "futures-lite 2.0.1", + "futures-lite 2.2.0", "piper", "tracing", ] @@ -759,7 +759,7 @@ checksum = "53fd06051bc34aa7ee753647dbd36506fa9f84026993d9871e65e0ee71ac3632" dependencies = [ "async-trait", "fixedbitset", - "getrandom 0.2.11", + "getrandom 0.2.12", "mini-moka", "once_cell", "parking_lot 0.12.1", @@ -825,9 +825,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.8" +version = "4.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64" +checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" dependencies = [ "clap_builder", "clap_derive", @@ -835,9 +835,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.8" +version = "4.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc" +checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" dependencies = [ "anstream", "anstyle", @@ -854,7 +854,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -871,9 +871,9 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "concurrent-queue" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f057a694a54f12365049b0958a1685bb52d567f5593b355fbf685838e873d400" +checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" dependencies = [ "crossbeam-utils", ] @@ -912,7 +912,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.12", "once_cell", "tiny-keccak", ] @@ -930,7 +930,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" dependencies = [ "percent-encoding", - "time 0.3.30", + "time 0.3.31", "version_check", ] @@ -942,9 +942,9 @@ checksum = "396de984970346b0d9e93d1415082923c679e5ae5c3ee3dcbd104f5610af126b" [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -952,15 +952,15 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "cpufeatures" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] @@ -991,32 +991,27 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.8" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-queue" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crunchy" @@ -1076,7 +1071,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", - "hashbrown 0.14.2", + "hashbrown 0.14.3", "lock_api", "once_cell", "parking_lot_core 0.9.9", @@ -1129,9 +1124,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.9" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", ] @@ -1142,7 +1137,16 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" dependencies = [ - "derive_builder_macro", + "derive_builder_macro 0.12.0", +] + +[[package]] +name = "derive_builder" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "660047478bc508c0fde22c868991eec0c40a63e48d610befef466d48e2bee574" +dependencies = [ + "derive_builder_macro 0.13.0", ] [[package]] @@ -1157,13 +1161,35 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_builder_core" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b217e6dd1011a54d12f3b920a411b5abd44b1716ecfe94f5f2f2f7b52e08ab7" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "derive_builder_macro" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" dependencies = [ - "derive_builder_core", + "derive_builder_core 0.12.0", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_macro" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5f77d7e20ac9153428f7ca14a88aba652adfc7a0ef0a06d654386310ef663b" +dependencies = [ + "derive_builder_core 0.13.0", "syn 1.0.109", ] @@ -1234,11 +1260,11 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "docker-compose-types" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608ffe949fbffae4034bdde4bfa224238736ecc9e1a362997245c7282f49fa60" +checksum = "6e366950e7785fe0e404901a2b4e5c09ebd6656767f0c2167e34c5068ce0cc2d" dependencies = [ - "derive_builder", + "derive_builder 0.13.0", "indexmap 2.1.0", "serde", "serde_yaml", @@ -1276,12 +1302,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -1301,9 +1327,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" -version = "4.0.0" +version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "770d968249b5d99410d61f5bf89057f3199a077a04d087092f58e7d10692baae" +checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" dependencies = [ "concurrent-queue", "parking", @@ -1316,7 +1342,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" dependencies = [ - "event-listener 4.0.0", + "event-listener 4.0.3", "pin-project-lite", ] @@ -1419,9 +1445,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -1434,9 +1460,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -1444,15 +1470,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -1472,9 +1498,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-lite" @@ -1493,40 +1519,39 @@ dependencies = [ [[package]] name = "futures-lite" -version = "2.0.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3831c2651acb5177cbd83943f3d9c8912c5ad03c76afcc0e9511ba568ec5ebb" +checksum = "445ba825b27408685aaecefd65178908c36c6e96aaf6d8599419d46e624192ba" dependencies = [ "fastrand 2.0.1", "futures-core", "futures-io", - "memchr", "parking", "pin-project-lite", ] [[package]] name = "futures-macro" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] name = "futures-sink" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-timer" @@ -1536,9 +1561,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", @@ -1585,9 +1610,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "js-sys", @@ -1610,9 +1635,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "h2" -version = "0.3.22" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" +checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" dependencies = [ "bytes", "fnv", @@ -1647,11 +1672,11 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.7", "allocator-api2", ] @@ -1661,7 +1686,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.14.2", + "hashbrown 0.14.3", ] [[package]] @@ -1675,9 +1700,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" [[package]] name = "hex" @@ -1687,9 +1712,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hkdf" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ "hmac", ] @@ -1716,9 +1741,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", @@ -1760,9 +1785,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.27" +version = "0.14.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" dependencies = [ "bytes", "futures-channel", @@ -1775,7 +1800,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.10", + "socket2 0.5.5", "tokio", "tower-service", "tracing", @@ -1797,9 +1822,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.58" +version = "0.1.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1852,7 +1877,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown 0.14.2", + "hashbrown 0.14.3", "serde", ] @@ -1909,18 +1934,18 @@ dependencies = [ [[package]] name = "itertools" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "jobserver" @@ -1933,9 +1958,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.65" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" +checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" dependencies = [ "wasm-bindgen", ] @@ -1988,9 +2013,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.150" +version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" [[package]] name = "libredox" @@ -1998,7 +2023,7 @@ version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "libc", "redox_syscall 0.4.1", ] @@ -2017,9 +2042,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.11" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "local-channel" @@ -2075,9 +2100,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "mime" @@ -2117,9 +2142,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "log", @@ -2192,26 +2217,26 @@ dependencies = [ [[package]] name = "object" -version = "0.32.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" -version = "0.10.60" +version = "0.10.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800" +checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "cfg-if", "foreign-types", "libc", @@ -2228,7 +2253,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -2239,9 +2264,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.96" +version = "0.9.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f" +checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae" dependencies = [ "cc", "libc", @@ -2274,7 +2299,7 @@ dependencies = [ "cbc", "cipher", "des", - "getrandom 0.2.11", + "getrandom 0.2.12", "hmac", "lazy_static", "rc2", @@ -2356,9 +2381,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5" +checksum = "1f200d8d83c44a45b21764d1916299752ca035d15ecd46faca3e9a2a2bf6ad06" dependencies = [ "memchr", "thiserror", @@ -2367,9 +2392,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81d78524685f5ef2a3b3bd1cafbc9fcabb036253d9b1463e726a91cd16e2dfc2" +checksum = "bcd6ab1236bbdb3a49027e920e693192ebfe8913f6d60e294de57463a493cfde" dependencies = [ "pest", "pest_generator", @@ -2377,22 +2402,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68bd1206e71118b5356dae5ddc61c8b11e28b09ef6a31acbd15ea48a28e0c227" +checksum = "2a31940305ffc96863a735bef7c7994a00b325a7138fdbc5bda0f1a0476d3275" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] name = "pest_meta" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c747191d4ad9e4a4ab9c8798f1e82a39affe7ef9648390b7e5548d18e099de6" +checksum = "a7ff62f5259e53b78d1af898941cdcdccfae7385cf7d793a6e55de5d05bb4b7d" dependencies = [ "once_cell", "pest", @@ -2411,22 +2436,22 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -2466,9 +2491,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.27" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" [[package]] name = "polling" @@ -2488,14 +2513,14 @@ dependencies = [ [[package]] name = "polling" -version = "3.3.1" +version = "3.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf63fa624ab313c11656b4cda960bfc46c410187ad493c41f6ba2d8c1e991c9e" +checksum = "545c980a3880efd47b2e262f6a4bb6daad6555cf3367aa9c4e52895f69537a41" dependencies = [ "cfg-if", "concurrent-queue", "pin-project-lite", - "rustix 0.38.25", + "rustix 0.38.30", "tracing", "windows-sys 0.52.0", ] @@ -2538,29 +2563,29 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] [[package]] name = "pulldown-cmark" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998" +checksum = "b16a41fe73d9f20da4dae1440a2c4f23db602db9b4699b9b694f007c0a84f67d" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.2", "memchr", "unicase", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -2624,7 +2649,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.12", ] [[package]] @@ -2680,20 +2705,20 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.12", "libredox", "thiserror", ] [[package]] name = "regex" -version = "1.10.2" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.3", + "regex-automata 0.4.5", "regex-syntax 0.8.2", ] @@ -2708,9 +2733,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" dependencies = [ "aho-corasick", "memchr", @@ -2731,11 +2756,11 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.22" +version = "0.11.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" dependencies = [ - "base64 0.21.5", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", @@ -2779,8 +2804,8 @@ version = "1.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3625f343d89990133d013e39c46e350915178cf94f1bec9f49b0cbef98a3e3c" dependencies = [ - "ahash 0.8.6", - "bitflags 2.4.1", + "ahash 0.8.7", + "bitflags 2.4.2", "instant", "num-traits", "once_cell", @@ -2798,7 +2823,7 @@ checksum = "853977598f084a492323fe2f7896b4100a86284ee8473612de60021ea341310f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -2818,12 +2843,12 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.5" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" dependencies = [ "cc", - "getrandom 0.2.11", + "getrandom 0.2.12", "libc", "spin 0.9.8", "untrusted 0.9.0", @@ -2892,15 +2917,15 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.25" +version = "0.38.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" +checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "errno", "libc", - "linux-raw-sys 0.4.11", - "windows-sys 0.48.0", + "linux-raw-sys 0.4.13", + "windows-sys 0.52.0", ] [[package]] @@ -2917,12 +2942,12 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.9" +version = "0.21.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ "log", - "ring 0.17.5", + "ring 0.17.7", "rustls-webpki", "sct", ] @@ -2934,7 +2959,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25da151615461c7347114b1ad1a7458b4cdebc69cb220cd140cd5cb324b1dd37" dependencies = [ "log", - "rustls 0.21.9", + "rustls 0.21.10", "rustls-native-certs", "rustls-webpki", ] @@ -2957,7 +2982,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64 0.21.5", + "base64 0.21.7", ] [[package]] @@ -2966,15 +2991,15 @@ version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.17.5", + "ring 0.17.7", "untrusted 0.9.0", ] [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "same-file" @@ -2987,11 +3012,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -3006,7 +3031,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.17.5", + "ring 0.17.7", "untrusted 0.9.0", ] @@ -3035,38 +3060,38 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.193" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "4d1bd37ce2324cf3bf85e5a25f96eb4baf0d5aa6eba43e7ae8958870c4ec48ed" dependencies = [ "itoa", "ryu", @@ -3075,9 +3100,9 @@ dependencies = [ [[package]] name = "serde_path_to_error" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335" +checksum = "ebd154a240de39fdebcf5775d2675c204d7c13cf39a4c697be6493c8e734337c" dependencies = [ "itoa", "serde", @@ -3152,9 +3177,9 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.27" +version = "0.9.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cc7a1570e38322cfe4154732e5110f887ea57e22b76f4bfd32b5bdd3368666c" +checksum = "b1bf28c79a99f70ee1f1d83d10c875d2e70618417fda01ad1785e027579d9d38" dependencies = [ "indexmap 2.1.0", "itoa", @@ -3229,9 +3254,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.2" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" dependencies = [ "serde", ] @@ -3285,11 +3310,11 @@ dependencies = [ [[package]] name = "sqlformat" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b7b278788e7be4d0d29c0f39497a0eef3fba6bbc8e70d8bf7fde46edeaa9e85" +checksum = "ce81b7bd7c4493975347ef60d8c7e8b742d4694f4c49f93e0a12ea263938176c" dependencies = [ - "itertools 0.11.0", + "itertools 0.12.0", "nom", "unicode_categories", ] @@ -3405,7 +3430,7 @@ dependencies = [ "clap", "config", "deadpool-lapin", - "derive_builder", + "derive_builder 0.12.0", "docker-compose-types", "futures", "futures-lite 1.13.0", @@ -3479,9 +3504,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -3529,35 +3554,35 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.8.1" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" dependencies = [ "cfg-if", "fastrand 2.0.1", "redox_syscall 0.4.1", - "rustix 0.38.25", - "windows-sys 0.48.0", + "rustix 0.38.30", + "windows-sys 0.52.0", ] [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -3583,9 +3608,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" dependencies = [ "deranged", "itoa", @@ -3603,9 +3628,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" dependencies = [ "time-core", ] @@ -3636,9 +3661,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.34.0" +version = "1.35.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" +checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" dependencies = [ "backtrace", "bytes", @@ -3672,7 +3697,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -3769,7 +3794,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -3778,12 +3803,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5c266b9ac83dedf0e0385ad78514949e6d89491269e7065bee51d2bb8ec7373" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.7", "gethostname", "log", "serde", "serde_json", - "time 0.3.30", + "time 0.3.31", "tracing", "tracing-core", "tracing-log 0.1.4", @@ -3848,9 +3873,9 @@ checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3" [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" @@ -3875,9 +3900,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" @@ -3908,9 +3933,9 @@ checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" [[package]] name = "unsafe-libyaml" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa" +checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" [[package]] name = "untrusted" @@ -3944,11 +3969,11 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" +checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.12", "serde", ] @@ -4015,9 +4040,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.88" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" +checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -4025,24 +4050,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.88" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" +checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.38" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" +checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461" dependencies = [ "cfg-if", "js-sys", @@ -4052,9 +4077,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.88" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" +checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4062,28 +4087,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.88" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" +checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.88" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" +checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" [[package]] name = "web-sys" -version = "0.3.65" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" +checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" dependencies = [ "js-sys", "wasm-bindgen", @@ -4095,7 +4120,7 @@ version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" dependencies = [ - "ring 0.17.5", + "ring 0.17.7", "untrusted 0.9.0", ] @@ -4151,11 +4176,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.51.1" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.48.5", + "windows-targets 0.52.0", ] [[package]] @@ -4308,7 +4333,7 @@ checksum = "13a3a53eaf34f390dd30d7b1b078287dd05df2aa2e21a589ccb80f5c7253c2e9" dependencies = [ "assert-json-diff", "async-trait", - "base64 0.21.5", + "base64 0.21.7", "deadpool 0.9.5", "futures", "futures-timer", @@ -4339,40 +4364,39 @@ checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" [[package]] name = "zerocopy" -version = "0.7.26" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97e415490559a91254a2979b4829267a57d2fcd741a98eee8b722fb57289aa0" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.26" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] name = "zstd" -version = "0.12.4" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" +checksum = "bffb3309596d527cfcba7dfc6ed6052f1d39dfbd7c867aa2e865e4a449c10110" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "6.0.6" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" +checksum = "43747c7422e2924c11144d5229878b98180ef8b06cca4ab5af37afc8a8d8ea3e" dependencies = [ - "libc", "zstd-sys", ] diff --git a/Cargo.toml b/Cargo.toml index abf15fc..33c4e35 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,7 +55,8 @@ clap = { version = "4.4.8", features = ["derive"] } serde_path_to_error = "0.1.14" deadpool-lapin = "0.11.0" docker-compose-types = "0.7.0" -actix-casbin-auth = { git = "https://github.com/casbin-rs/actix-casbin-auth.git"} +#actix-casbin-auth = { git = "https://github.com/casbin-rs/actix-casbin-auth.git"} +actix-casbin-auth = { git = "https://github.com/smart--petea/actix-casbin-auth.git", branch = "dirty-master"} [dependencies.sqlx] version = "0.6.3" diff --git a/rbac/rbac_with_pattern_model.conf b/rbac/rbac_with_pattern_model.conf index 44507a6..5d04715 100644 --- a/rbac/rbac_with_pattern_model.conf +++ b/rbac/rbac_with_pattern_model.conf @@ -1,15 +1,14 @@ [request_definition] -r = sub, obj, act +r = sub, dom, obj, act [policy_definition] -p = sub, obj, act +p = sub, dom, obj, act [role_definition] -g = _, _ -g2 = _, _ +g = _, _, _ [policy_effect] e = some(where (p.eft == allow)) [matchers] -m = g(r.sub, p.sub) && g2(r.obj, p.obj) && regexMatch(r.act, p.act) +m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && regexMatch(r.act, p.act) diff --git a/rbac/rbac_with_pattern_policy.csv b/rbac/rbac_with_pattern_policy.csv index ea5b1a6..7526184 100644 --- a/rbac/rbac_with_pattern_policy.csv +++ b/rbac/rbac_with_pattern_policy.csv @@ -1,10 +1,6 @@ -p, petru, /testcasbin, GET -p, alice, /pen/1, GET -p, alice, /pen2/1, GET -p, book_admin, book_group, GET -p, pen_admin, pen_group, GET - -g, alice, book_admin -g, bob, pen_admin -g2, /book/:id, book_group -g2, /pen/:id, pen_group +p, admin, domain1, /pen/1, GET +p, admin, domain1, /pen/2, GET +p, admin, domain2, /book/1, GET +p, admin, domain2, /book/2, GET +g, alice, admin, domain1 +g, bob, admin, domain2 diff --git a/src/middleware/trydirect.rs b/src/middleware/trydirect.rs index 33c54a7..0afea4d 100644 --- a/src/middleware/trydirect.rs +++ b/src/middleware/trydirect.rs @@ -22,7 +22,7 @@ pub async fn bearer_guard( req: ServiceRequest, credentials: BearerAuth) -> Resu let vals = actix_casbin_auth::CasbinVals { //todo subject: String::from("alice"), - domain: Some("/pen/1".to_string()), + domain: Some("domain1".to_string()), }; let result = req.extensions_mut().insert(vals); //todo tracing::error!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA {}", result.is_some()); //todo diff --git a/src/startup.rs b/src/startup.rs index f00d0d8..91a0113 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -33,7 +33,7 @@ pub async fn run( .unwrap(); let a = FileAdapter::new("rbac/rbac_with_pattern_policy.csv"); //You can also use diesel-adapter or sqlx-adapter - let casbin_middleware = CasbinService::new(m, a).await.unwrap(); //todo + let mut casbin_middleware = CasbinService::new(m, a).await.unwrap(); //todo casbin_middleware .write() @@ -60,7 +60,6 @@ pub async fn run( ) .service( web::scope("/test") - .wrap(casbin_middleware.clone()) .wrap(crate::middleware::client::Guard::new()) .wrap(Cors::permissive()) .service(crate::routes::test::deploy::handler), From a7b5f1acd04c99d0c7eb2492e1440538006c31d0 Mon Sep 17 00:00:00 2001 From: petru Date: Sun, 28 Jan 2024 10:05:44 +0200 Subject: [PATCH 155/284] issue-auth access_manager --- src/middleware/access_control.rs | 5 ----- src/middleware/access_manager.rs | 25 +++++++++++++++++++++++ src/middleware/mod.rs | 2 +- src/startup.rs | 34 ++++++++------------------------ 4 files changed, 34 insertions(+), 32 deletions(-) delete mode 100644 src/middleware/access_control.rs create mode 100644 src/middleware/access_manager.rs diff --git a/src/middleware/access_control.rs b/src/middleware/access_control.rs deleted file mode 100644 index 80e4881..0000000 --- a/src/middleware/access_control.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub struct AccessControl{} - -impl AccessControl { - -} diff --git a/src/middleware/access_manager.rs b/src/middleware/access_manager.rs new file mode 100644 index 0000000..04c2b60 --- /dev/null +++ b/src/middleware/access_manager.rs @@ -0,0 +1,25 @@ +use actix_casbin_auth::casbin::{DefaultModel, FileAdapter};//, Result}; +use actix_casbin_auth::CasbinService; +use actix_casbin_auth::casbin::function_map::key_match2; +use actix_casbin_auth::casbin::CoreApi; +use std::io::{Error, ErrorKind}; + +pub async fn try_new() -> Result { + let m = DefaultModel::from_file("rbac/rbac_with_pattern_model.conf") + .await + .map_err(|err| Error::new(ErrorKind::Other, format!("{err:?}")))?; + let a = FileAdapter::new("rbac/rbac_with_pattern_policy.csv"); + + let mut casbin_service = CasbinService::new(m, a) + .await + .map_err(|err| Error::new(ErrorKind::Other, format!("{err:?}")))?; + + casbin_service + .write() + .await + .get_role_manager() + .write() + .matching_fn(Some(key_match2), None); + + Ok(casbin_service) +} diff --git a/src/middleware/mod.rs b/src/middleware/mod.rs index 66bc6dc..59debf1 100644 --- a/src/middleware/mod.rs +++ b/src/middleware/mod.rs @@ -1,3 +1,3 @@ pub mod client; pub mod trydirect; -pub mod access_control; +pub mod access_manager; diff --git a/src/startup.rs b/src/startup.rs index 91a0113..8c872f3 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -6,16 +6,12 @@ use actix_web::{ web::{self}, App, HttpServer, }; +use crate::middleware; use actix_web_httpauth::middleware::HttpAuthentication; use sqlx::{Pool, Postgres}; use std::net::TcpListener; use tracing_actix_web::TracingLogger; -use actix_casbin_auth::casbin::{DefaultModel, FileAdapter};//, Result}; -use actix_casbin_auth::CasbinService; -use actix_casbin_auth::casbin::function_map::key_match2; -use actix_casbin_auth::casbin::CoreApi; - pub async fn run( listener: TcpListener, pg_pool: Pool, @@ -27,21 +23,7 @@ pub async fn run( let mq_manager = helpers::MqManager::try_new(settings.amqp.connection_string())?; let mq_manager = web::Data::new(mq_manager); - //casbin - let m = DefaultModel::from_file("rbac/rbac_with_pattern_model.conf") - .await - .unwrap(); - let a = FileAdapter::new("rbac/rbac_with_pattern_policy.csv"); //You can also use diesel-adapter or sqlx-adapter - - let mut casbin_middleware = CasbinService::new(m, a).await.unwrap(); //todo - - casbin_middleware - .write() - .await - .get_role_manager() - .write() - //.unwrap() - .matching_fn(Some(key_match2), None); + let access_control_manager = middleware::access_manager::try_new().await?; let server = HttpServer::new(move || { App::new() @@ -50,7 +32,7 @@ pub async fn run( .service( web::scope("/client") .wrap(HttpAuthentication::bearer( - crate::middleware::trydirect::bearer_guard, + middleware::trydirect::bearer_guard, )) .wrap(Cors::permissive()) .service(crate::routes::client::add_handler) @@ -60,15 +42,15 @@ pub async fn run( ) .service( web::scope("/test") - .wrap(crate::middleware::client::Guard::new()) + .wrap(middleware::client::Guard::new()) .wrap(Cors::permissive()) .service(crate::routes::test::deploy::handler), ) .service( web::scope("/pen/1") - .wrap(casbin_middleware.clone()) //todo + .wrap(access_control_manager.clone()) .wrap(HttpAuthentication::bearer( - crate::middleware::trydirect::bearer_guard, + middleware::trydirect::bearer_guard, )) .wrap(Cors::permissive()) .service(crate::routes::test::casbin::handler), @@ -76,7 +58,7 @@ pub async fn run( .service( web::scope("/rating") .wrap(HttpAuthentication::bearer( - crate::middleware::trydirect::bearer_guard, + middleware::trydirect::bearer_guard, )) .wrap(Cors::permissive()) .service(crate::routes::rating::add_handler) @@ -86,7 +68,7 @@ pub async fn run( .service( web::scope("/stack") .wrap(HttpAuthentication::bearer( - crate::middleware::trydirect::bearer_guard, + middleware::trydirect::bearer_guard, )) .wrap(Cors::permissive()) .service(crate::routes::stack::deploy::add) From 94fbd7b02f1a62de30f84884802b70939a50a73a Mon Sep 17 00:00:00 2001 From: petru Date: Sun, 28 Jan 2024 20:00:01 +0200 Subject: [PATCH 156/284] issue-auth casbin_rule migration --- Cargo.toml | 1 + .../20230905145525_creating_stack_tables.down.sql | 1 - .../20230917162549_creating_test_product.down.sql | 2 +- .../20230917162549_creating_test_product.up.sql | 2 +- migrations/20231028161917_client.up.sql | 2 +- migrations/20240128174529_casbin_rule.down.sql | 2 ++ migrations/20240128174529_casbin_rule.up.sql | 12 ++++++++++++ 7 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 migrations/20240128174529_casbin_rule.down.sql create mode 100644 migrations/20240128174529_casbin_rule.up.sql diff --git a/Cargo.toml b/Cargo.toml index 33c4e35..894ba66 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,7 @@ tokio-stream = "0.1.14" actix-http = "3.4.0" hmac = "0.12.1" sha2 = "0.10.8" +sqlx-adapter = { version = "0.4.2", default-features = false, features = ["postgres", "runtime-tokio-native-tls"]} # dctypes derive_builder = "0.12.0" diff --git a/migrations/20230905145525_creating_stack_tables.down.sql b/migrations/20230905145525_creating_stack_tables.down.sql index 203a95a..2f2a6e4 100644 --- a/migrations/20230905145525_creating_stack_tables.down.sql +++ b/migrations/20230905145525_creating_stack_tables.down.sql @@ -1,3 +1,2 @@ -- Add down migration script here - DROP TABLE user_stack; diff --git a/migrations/20230917162549_creating_test_product.down.sql b/migrations/20230917162549_creating_test_product.down.sql index f9f6339..eafea95 100644 --- a/migrations/20230917162549_creating_test_product.down.sql +++ b/migrations/20230917162549_creating_test_product.down.sql @@ -1 +1 @@ -delete from product where id=1; +DELETE FROM product WHERE id=1; diff --git a/migrations/20230917162549_creating_test_product.up.sql b/migrations/20230917162549_creating_test_product.up.sql index 7a1d8d6..9aae3c5 100644 --- a/migrations/20230917162549_creating_test_product.up.sql +++ b/migrations/20230917162549_creating_test_product.up.sql @@ -1 +1 @@ -INSERT INTO public.product (id, obj_id, obj_type, created_at, updated_at) VALUES(1, 1, 'Application', '2023-09-17 10:30:02.579', '2023-09-17 10:30:02.579'); \ No newline at end of file +INSERT INTO product (id, obj_id, obj_type, created_at, updated_at) VALUES(1, 1, 'Application', '2023-09-17 10:30:02.579', '2023-09-17 10:30:02.579'); diff --git a/migrations/20231028161917_client.up.sql b/migrations/20231028161917_client.up.sql index fcb9065..e0470c3 100644 --- a/migrations/20231028161917_client.up.sql +++ b/migrations/20231028161917_client.up.sql @@ -1,5 +1,5 @@ -- Add up migration script here -CREATE TABLE public.client ( +CREATE TABLE client ( id serial4 NOT NULL, user_id varchar(50) NOT NULL, secret varchar(255), diff --git a/migrations/20240128174529_casbin_rule.down.sql b/migrations/20240128174529_casbin_rule.down.sql new file mode 100644 index 0000000..ef4c417 --- /dev/null +++ b/migrations/20240128174529_casbin_rule.down.sql @@ -0,0 +1,2 @@ +-- Add down migration script here +DROP TABLE casbin_rule; diff --git a/migrations/20240128174529_casbin_rule.up.sql b/migrations/20240128174529_casbin_rule.up.sql new file mode 100644 index 0000000..15b9914 --- /dev/null +++ b/migrations/20240128174529_casbin_rule.up.sql @@ -0,0 +1,12 @@ +-- Add up migration script here +CREATE TABLE casbin_rule ( + id SERIAL PRIMARY KEY, + ptype VARCHAR NOT NULL, + v0 VARCHAR NOT NULL, + v1 VARCHAR NOT NULL, + v2 VARCHAR NOT NULL, + v3 VARCHAR NOT NULL, + v4 VARCHAR NOT NULL, + v5 VARCHAR NOT NULL, + CONSTRAINT unique_key_sqlx_adapter UNIQUE(ptype, v0, v1, v2, v3, v4, v5) +) From 7348383e97e2cc765a4f338067054fb5a7127b10 Mon Sep 17 00:00:00 2001 From: petru Date: Mon, 29 Jan 2024 17:51:54 +0200 Subject: [PATCH 157/284] issue-auth casbin adapter --- Cargo.lock | 50 ++++++++++++++++++++++---------- Cargo.toml | 3 +- src/middleware/access_manager.rs | 19 ++++++++---- src/startup.rs | 2 +- 4 files changed, 50 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c4ceaf8..f844c9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -466,7 +466,7 @@ checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ "async-channel 2.1.1", "async-executor", - "async-io 2.3.0", + "async-io 2.3.1", "async-lock 3.3.0", "blocking", "futures-lite 2.2.0", @@ -506,9 +506,9 @@ dependencies = [ [[package]] name = "async-io" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb41eb19024a91746eba0773aa5e16036045bbf45733766661099e182ea6a744" +checksum = "8f97ab0c5b00a7cdbe5a371b9a782ee7be1316095885c8a4ea1daf490eb0ef65" dependencies = [ "async-lock 3.3.0", "cfg-if", @@ -1265,11 +1265,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e366950e7785fe0e404901a2b4e5c09ebd6656767f0c2167e34c5068ce0cc2d" dependencies = [ "derive_builder 0.13.0", - "indexmap 2.1.0", + "indexmap 2.2.1", "serde", "serde_yaml", ] +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + [[package]] name = "dotenvy" version = "0.15.7" @@ -1645,7 +1651,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 2.1.0", + "indexmap 2.2.1", "slab", "tokio", "tokio-util", @@ -1872,9 +1878,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.1.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "433de089bd45971eecf4668ee0ee8f4cec17db4f8bd8f7bc3197a6ce37aa7d9b" dependencies = [ "equivalent", "hashbrown 0.14.3", @@ -2431,7 +2437,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.1.0", + "indexmap 2.2.1", ] [[package]] @@ -2572,9 +2578,9 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.9.4" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16a41fe73d9f20da4dae1440a2c4f23db602db9b4699b9b694f007c0a84f67d" +checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" dependencies = [ "bitflags 2.4.2", "memchr", @@ -3089,9 +3095,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.112" +version = "1.0.113" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d1bd37ce2324cf3bf85e5a25f96eb4baf0d5aa6eba43e7ae8958870c4ec48ed" +checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" dependencies = [ "itoa", "ryu", @@ -3177,11 +3183,11 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.30" +version = "0.9.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1bf28c79a99f70ee1f1d83d10c875d2e70618417fda01ad1785e027579d9d38" +checksum = "adf8a49373e98a4c5f0ceb5d05aa7c648d75f63774981ed95b7c7443bbd50c6e" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.1", "itoa", "ryu", "serde", @@ -3329,6 +3335,17 @@ dependencies = [ "sqlx-macros", ] +[[package]] +name = "sqlx-adapter" +version = "0.4.2" +source = "git+https://github.com/smart--petea/sqlx-adapter.git?branch=dirty-master#5f7cabbde494098a1b460f26c4b74fcbcf2d5857" +dependencies = [ + "async-trait", + "casbin", + "dotenv", + "sqlx", +] + [[package]] name = "sqlx-core" version = "0.6.3" @@ -3437,7 +3454,7 @@ dependencies = [ "futures-util", "glob", "hmac", - "indexmap 2.1.0", + "indexmap 2.2.1", "lapin", "rand 0.8.5", "regex", @@ -3450,6 +3467,7 @@ dependencies = [ "serde_yaml", "sha2", "sqlx", + "sqlx-adapter", "thiserror", "tokio", "tokio-stream", diff --git a/Cargo.toml b/Cargo.toml index 894ba66..8942098 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,8 @@ tokio-stream = "0.1.14" actix-http = "3.4.0" hmac = "0.12.1" sha2 = "0.10.8" -sqlx-adapter = { version = "0.4.2", default-features = false, features = ["postgres", "runtime-tokio-native-tls"]} +#sqlx-adapter = { version = "0.4.2", default-features = false, features = ["postgres", "runtime-tokio-native-tls"]} +sqlx-adapter = { git="https://github.com/smart--petea/sqlx-adapter.git", branch="dirty-master", default-features = false, features = ["postgres"]} # dctypes derive_builder = "0.12.0" diff --git a/src/middleware/access_manager.rs b/src/middleware/access_manager.rs index 04c2b60..82301cd 100644 --- a/src/middleware/access_manager.rs +++ b/src/middleware/access_manager.rs @@ -1,14 +1,21 @@ -use actix_casbin_auth::casbin::{DefaultModel, FileAdapter};//, Result}; -use actix_casbin_auth::CasbinService; -use actix_casbin_auth::casbin::function_map::key_match2; -use actix_casbin_auth::casbin::CoreApi; +use actix_casbin_auth::{ + CasbinService, + casbin::{ + DefaultModel, + CoreApi, + function_map::key_match2 + } +}; use std::io::{Error, ErrorKind}; +use sqlx_adapter::SqlxAdapter; -pub async fn try_new() -> Result { +pub async fn try_new(db_connection_address: String) -> Result { let m = DefaultModel::from_file("rbac/rbac_with_pattern_model.conf") .await .map_err(|err| Error::new(ErrorKind::Other, format!("{err:?}")))?; - let a = FileAdapter::new("rbac/rbac_with_pattern_policy.csv"); + let a = SqlxAdapter::new(db_connection_address, 8) + .await + .map_err(|err| Error::new(ErrorKind::Other, format!("{err:?}")))?; let mut casbin_service = CasbinService::new(m, a) .await diff --git a/src/startup.rs b/src/startup.rs index 8c872f3..3548192 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -23,7 +23,7 @@ pub async fn run( let mq_manager = helpers::MqManager::try_new(settings.amqp.connection_string())?; let mq_manager = web::Data::new(mq_manager); - let access_control_manager = middleware::access_manager::try_new().await?; + let access_control_manager = middleware::access_manager::try_new(settings.database.connection_string()).await?; let server = HttpServer::new(move || { App::new() From 30fa18beaef6bb7321fc4ed9b187cef2766c9e1c Mon Sep 17 00:00:00 2001 From: vsilent Date: Tue, 30 Jan 2024 09:37:29 +0200 Subject: [PATCH 158/284] stack form fields change, network id is added, replace net name with net id for every service --- src/forms/stack.rs | 45 +++++++++++++++-- src/helpers/stack/builder.rs | 54 ++++++++++++--------- tests/custom-stack-payload-no-networks.json | 2 + tests/custom.json | 0 4 files changed, 73 insertions(+), 28 deletions(-) create mode 100644 tests/custom-stack-payload-no-networks.json create mode 100644 tests/custom.json diff --git a/src/forms/stack.rs b/src/forms/stack.rs index fe04381..ddab46c 100644 --- a/src/forms/stack.rs +++ b/src/forms/stack.rs @@ -2,8 +2,10 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use serde_valid::Validate; use std::fmt; +use indexmap::IndexMap; use regex::Regex; use crate::helpers::dockerhub::DockerHub; +use crate::helpers::stack::dctypes::SingleValue; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Role { @@ -268,10 +270,6 @@ pub struct Custom { pub networks: ComposeNetworks, // all networks } -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Network { - name: String, -} #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct App { @@ -367,9 +365,46 @@ pub struct ServiceNetworks { pub network: Option>, } +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct NetworkDriver { + // not implemented +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct Network { + pub(crate) id: String, + pub(crate) attachable: Option, + pub(crate) driver: Option, + pub(crate) driver_opts: Option, + pub(crate) enable_ipv6: Option, + pub(crate) internal: Option, + pub(crate) external: Option, + pub(crate) ipam: Option, + pub(crate) labels: Option, + pub(crate) name: String, +} + +impl Default for Network { + fn default() -> Self { + // The case when we need at least one external network to be preconfigured + Network { + id: "default_network".to_string(), + attachable: None, + driver: None, + driver_opts: Default::default(), + enable_ipv6: None, + internal: None, + external: Some(true), + ipam: None, + labels: None, + name: "default_network".to_string(), + } + } +} + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct ComposeNetworks { - pub networks: Option>, + pub networks: Option>, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 23d1bd9..28c74f5 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -5,7 +5,7 @@ use crate::helpers::stack::dctypes::{Compose, Port, Ports, PublishedPort, Servic ComposeNetworks, MapOrEmpty, ComposeNetworkSettingDetails, NetworkSettings}; use serde_yaml; -use crate::forms::{StackForm, stack, App, Volume}; +use crate::forms::{StackForm, stack, App, Volume, Network, NetworkDriver}; use crate::models::stack::Stack; #[derive(Clone, Debug)] struct Config {} @@ -101,12 +101,10 @@ impl TryInto for stack::Port { impl TryInto for stack::ServiceNetworks { type Error = (); fn try_into(self) -> Result { - let mut default_networks = vec!["default_network".to_string()]; + let mut default_networks = vec![]; let nets = match self.network { Some(mut _nets) => { - if !_nets.contains(&"default_network".to_string()) { _nets.append(&mut default_networks); - } _nets } None => { @@ -178,18 +176,42 @@ impl TryIntoService for App { } } +impl Into>> for NetworkDriver { + fn into(self) -> IndexMap> { + IndexMap::new() + } +} + +impl Into for Network { + + fn into(self) -> NetworkSettings { + + NetworkSettings { + attachable: self.attachable.unwrap_or(false), + driver: self.driver.clone(), + driver_opts: self.driver_opts.unwrap_or_default().into(), // @todo + enable_ipv6: self.enable_ipv6.unwrap_or(false), + internal: self.internal.unwrap_or(false), + external: Some(ComposeNetwork::Bool(self.external.unwrap_or(false))), + ipam: None, // @todo + labels: Default::default(), + name: Some(self.name.clone()), + } + } +} impl Into>> for stack::ComposeNetworks { fn into(self) -> IndexMap> { - let mut default_network = vec!["default_network".to_string()]; + // let mut default_networks = vec![Network::default()]; + let mut default_networks = vec![]; let networks = match self.networks { None => { - default_network + default_networks } Some(mut nets) => { - if !nets.contains(&"default_network".to_string()) { - nets.append(&mut default_network); + if !nets.is_empty() { + nets.append(&mut default_networks); } nets } @@ -198,21 +220,7 @@ impl Into>> for stack::ComposeNetwo let networks = networks .into_iter() .map(|net| { - (net, - MapOrEmpty::Map( - NetworkSettings { - attachable: false, - driver: None, - driver_opts: Default::default(), - enable_ipv6: false, - internal: false, - // external: None, - external: Some(ComposeNetwork::Bool(true)), - ipam: None, - labels: Default::default(), - name: Some("default_network".to_string()), - } - )) + (net.name.clone(), MapOrEmpty::Map(net.into())) } ) .collect::>(); diff --git a/tests/custom-stack-payload-no-networks.json b/tests/custom-stack-payload-no-networks.json new file mode 100644 index 0000000..2ec622b --- /dev/null +++ b/tests/custom-stack-payload-no-networks.json @@ -0,0 +1,2 @@ +{"commonDomain":"","domainList":{},"region":"fsn1","zone":null,"server":"cx11","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":[],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":false,"disk_type":"pd-standart","cloud_token":"****************************","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"networks":[{ + "name": "default_network"}, {"name":"mynetwork"}],"web":[{"name":"MyApp","code":"myapp","domain":"myapp.com","shared_ports":[{"host_port":"","container_port":"8080"}],"versions":[],"custom":true,"type":"web","network":["default_network", "mynetwork"],"restart":"no","timestamp":"2024-01-15T09:47:46.580Z","_id":"lreqrvv81ifrmng39","dockerhub_user":"","dockerhub_name":"nginx", "dockerhub_password":"", "dockerhub_image": "None", "environment":[{"key":"SOMEENVVAR1","value":"SOMEENVVAR_VALUE1"},{"key":"SOMEENVVAR2","value":"SOMEENVVAR_VALUE2"}],"volumes":[]}],"feature":[],"service":[],"servers_count":3,"project_git_url":"info@optimum-web.com","project_name":"Sample2024","custom_stack_code":"sample2024"}} \ No newline at end of file diff --git a/tests/custom.json b/tests/custom.json new file mode 100644 index 0000000..e69de29 From 87db191240caab99cab94e93ae724b3cdd1250ad Mon Sep 17 00:00:00 2001 From: petru Date: Tue, 30 Jan 2024 18:13:18 +0200 Subject: [PATCH 159/284] issue-auth casbin --- access_control.conf.dist | 14 ++++++++++++++ rbac/rbac_with_pattern_model.conf | 14 -------------- rbac/rbac_with_pattern_policy.csv | 6 ------ src/middleware/access_manager.rs | 2 +- src/middleware/trydirect.rs | 9 +++++---- 5 files changed, 20 insertions(+), 25 deletions(-) create mode 100644 access_control.conf.dist delete mode 100644 rbac/rbac_with_pattern_model.conf delete mode 100644 rbac/rbac_with_pattern_policy.csv diff --git a/access_control.conf.dist b/access_control.conf.dist new file mode 100644 index 0000000..459a15f --- /dev/null +++ b/access_control.conf.dist @@ -0,0 +1,14 @@ +[request_definition] +r = sub, obj, act + +[policy_definition] +p = sub, obj, act + +[role_definition] +g = _, _ + +[policy_effect] +e = some(where (p.eft == allow)) + +[matchers] +m = g(r.sub, p.sub) && r.obj == p.obj && regexMatch(r.act, p.act) diff --git a/rbac/rbac_with_pattern_model.conf b/rbac/rbac_with_pattern_model.conf deleted file mode 100644 index 5d04715..0000000 --- a/rbac/rbac_with_pattern_model.conf +++ /dev/null @@ -1,14 +0,0 @@ -[request_definition] -r = sub, dom, obj, act - -[policy_definition] -p = sub, dom, obj, act - -[role_definition] -g = _, _, _ - -[policy_effect] -e = some(where (p.eft == allow)) - -[matchers] -m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && regexMatch(r.act, p.act) diff --git a/rbac/rbac_with_pattern_policy.csv b/rbac/rbac_with_pattern_policy.csv deleted file mode 100644 index 7526184..0000000 --- a/rbac/rbac_with_pattern_policy.csv +++ /dev/null @@ -1,6 +0,0 @@ -p, admin, domain1, /pen/1, GET -p, admin, domain1, /pen/2, GET -p, admin, domain2, /book/1, GET -p, admin, domain2, /book/2, GET -g, alice, admin, domain1 -g, bob, admin, domain2 diff --git a/src/middleware/access_manager.rs b/src/middleware/access_manager.rs index 82301cd..4760114 100644 --- a/src/middleware/access_manager.rs +++ b/src/middleware/access_manager.rs @@ -10,7 +10,7 @@ use std::io::{Error, ErrorKind}; use sqlx_adapter::SqlxAdapter; pub async fn try_new(db_connection_address: String) -> Result { - let m = DefaultModel::from_file("rbac/rbac_with_pattern_model.conf") + let m = DefaultModel::from_file("access_control.conf") .await .map_err(|err| Error::new(ErrorKind::Other, format!("{err:?}")))?; let a = SqlxAdapter::new(db_connection_address, 8) diff --git a/src/middleware/trydirect.rs b/src/middleware/trydirect.rs index 0afea4d..1c61049 100644 --- a/src/middleware/trydirect.rs +++ b/src/middleware/trydirect.rs @@ -20,12 +20,13 @@ pub async fn bearer_guard( req: ServiceRequest, credentials: BearerAuth) -> Resu return Err((JsonResponse::::build().unauthorized("user already logged"), req)); } - let vals = actix_casbin_auth::CasbinVals { //todo + let accesscontrol_vals = actix_casbin_auth::CasbinVals { subject: String::from("alice"), - domain: Some("domain1".to_string()), + domain: None, }; - let result = req.extensions_mut().insert(vals); //todo - tracing::error!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA {}", result.is_some()); //todo + if req.extensions_mut().insert(accesscontrol_vals).is_some() { + return Err((JsonResponse::::build().unauthorized("sth wrong with access control"), req)); + } Ok(req) } From 8e67dca8d1d4704cb503bf54f2913fedd2bcc064 Mon Sep 17 00:00:00 2001 From: vsilent Date: Thu, 1 Feb 2024 12:08:46 +0200 Subject: [PATCH 160/284] default_network is already created by an ansible role on TD side and is always external=True --- src/helpers/stack/builder.rs | 54 ++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 28c74f5..1466fe1 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -5,6 +5,7 @@ use crate::helpers::stack::dctypes::{Compose, Port, Ports, PublishedPort, Servic ComposeNetworks, MapOrEmpty, ComposeNetworkSettingDetails, NetworkSettings}; use serde_yaml; +use tracing::Value; use crate::forms::{StackForm, stack, App, Volume, Network, NetworkDriver}; use crate::models::stack::Stack; #[derive(Clone, Debug)] @@ -186,14 +187,18 @@ impl Into for Network { fn into(self) -> NetworkSettings { + // default_network is always external=true + let is_default = self.name == String::from("default_network"); + let external = is_default || self.external.unwrap_or(false); + NetworkSettings { attachable: self.attachable.unwrap_or(false), driver: self.driver.clone(), driver_opts: self.driver_opts.unwrap_or_default().into(), // @todo enable_ipv6: self.enable_ipv6.unwrap_or(false), internal: self.internal.unwrap_or(false), - external: Some(ComposeNetwork::Bool(self.external.unwrap_or(false))), - ipam: None, // @todo + external: Some(ComposeNetwork::Bool(external)), + ipam: None, // @todo labels: Default::default(), name: Some(self.name.clone()), } @@ -278,6 +283,34 @@ pub fn extract_named_volumes(app: App) -> IndexMap) -> Option { + + for n in networks.into_iter() { + if id == &n.id { + tracing::debug!("matches: {:?}", n.name); + return Some(n.name.clone()); + } + } + None +} + +pub fn replace_id_with_name(service_networks: Networks, all_networks: &Vec) -> Vec { + + match service_networks { + Networks::Simple(nets) => { + nets + .iter() + .map(|id| { + if let Some(name) = matches_network_by_id(&id, all_networks) { + name + } else { "".to_string() } + }) + .collect::>() + }, + _ => vec![] + } +} + impl DcBuilder { pub fn new(stack: Stack) -> Self { @@ -299,15 +332,23 @@ impl DcBuilder { match _stack { Ok(apps) => { + let all_networks = &apps.custom.networks.networks.clone().unwrap_or(vec![]); + for app_type in &apps.custom.web { - let service = app_type.app.try_into_service(); + let mut service = app_type.app.try_into_service(); + let service_networks = service.networks.clone(); + let networks = replace_id_with_name(service_networks, all_networks); + service.networks = Networks::Simple(networks); services.insert(app_type.app.code.clone().to_owned(), Some(service)); named_volumes.extend(extract_named_volumes(app_type.app.clone())); } if let Some(srvs) = apps.custom.service { for app_type in srvs { - let service = app_type.app.try_into_service(); + let mut service = app_type.app.try_into_service(); + let service_networks = service.networks.clone(); + let networks = replace_id_with_name(service_networks, all_networks); + service.networks = Networks::Simple(networks); services.insert(app_type.app.code.clone().to_owned(), Some(service)); named_volumes.extend(extract_named_volumes(app_type.app.clone())); } @@ -315,7 +356,10 @@ impl DcBuilder { if let Some(features) = apps.custom.feature { for app_type in features { - let service = app_type.app.try_into_service(); + let mut service = app_type.app.try_into_service(); + let service_networks = service.networks.clone(); + let networks = replace_id_with_name(service_networks, all_networks); + service.networks = Networks::Simple(networks); services.insert(app_type.app.code.clone().to_owned(), Some(service)); named_volumes.extend(extract_named_volumes(app_type.app.clone())); } From 5e150d3f63a5a97ebfa5b818f7d2f1b3df404b09 Mon Sep 17 00:00:00 2001 From: vsilent Date: Sun, 4 Feb 2024 09:06:03 +0200 Subject: [PATCH 161/284] tests json sample data --- tests/custom-stack-payload-no-networks.json | 3 +-- tests/custom.json | 1 + tests/dockerhub.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/custom-stack-payload-no-networks.json b/tests/custom-stack-payload-no-networks.json index 2ec622b..2f81246 100644 --- a/tests/custom-stack-payload-no-networks.json +++ b/tests/custom-stack-payload-no-networks.json @@ -1,2 +1 @@ -{"commonDomain":"","domainList":{},"region":"fsn1","zone":null,"server":"cx11","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":[],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":false,"disk_type":"pd-standart","cloud_token":"****************************","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"networks":[{ - "name": "default_network"}, {"name":"mynetwork"}],"web":[{"name":"MyApp","code":"myapp","domain":"myapp.com","shared_ports":[{"host_port":"","container_port":"8080"}],"versions":[],"custom":true,"type":"web","network":["default_network", "mynetwork"],"restart":"no","timestamp":"2024-01-15T09:47:46.580Z","_id":"lreqrvv81ifrmng39","dockerhub_user":"","dockerhub_name":"nginx", "dockerhub_password":"", "dockerhub_image": "None", "environment":[{"key":"SOMEENVVAR1","value":"SOMEENVVAR_VALUE1"},{"key":"SOMEENVVAR2","value":"SOMEENVVAR_VALUE2"}],"volumes":[]}],"feature":[],"service":[],"servers_count":3,"project_git_url":"info@optimum-web.com","project_name":"Sample2024","custom_stack_code":"sample2024"}} \ No newline at end of file +{"commonDomain":"","domainList":{},"region":"fsn1","zone":null,"server":"cx11","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":[],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":false,"disk_type":"pd-standart","cloud_token":"****************************","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"web":[{"name":"MyApp","code":"myapp","domain":"myapp.com","shared_ports":[{"host_port":"","container_port":"8080"}],"versions":[],"custom":true,"type":"web","network":null,"restart":"no","timestamp":"2024-01-15T09:47:46.580Z","_id":"lreqrvv81ifrmng39","dockerhub_user":"","dockerhub_name":"nginx", "dockerhub_password":"", "dockerhub_image": "None", "environment":[{"key":"SOMEENVVAR1","value":"SOMEENVVAR_VALUE1"},{"key":"SOMEENVVAR2","value":"SOMEENVVAR_VALUE2"}],"volumes":[]}],"feature":[],"service":[],"servers_count":3,"project_git_url":"info@optimum-web.com","project_name":"Sample2024-1","custom_stack_code":"sample2024-1"}} \ No newline at end of file diff --git a/tests/custom.json b/tests/custom.json index e69de29..952b1f9 100644 --- a/tests/custom.json +++ b/tests/custom.json @@ -0,0 +1 @@ +{"commonDomain":"","domainList":{},"region":"fsn1","zone":null,"server":"cx11","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":[],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":true,"disk_type":"pd-standart","cloud_token":"*********","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"networks":[{"name":"default_network","id":"ls005v9r2xn6l3d2s"},{"name":"lkhlkjhlkjh","id":"ls025c5f1ld1u2tnn"},{"name":"samples","id":"ls007dio3aq1uh6ad"}],"web":[{"name":"samplecom","code":"samplecom","domain":"sample.com","shared_ports":[{"host_port":"80","container_port":"8080"}],"versions":[],"custom":true,"type":"web","network":["ls005v9r2xn6l3d2s","ls025c5f1ld1u2tnn","ls007dio3aq1uh6ad"],"restart":"always","timestamp":"2024-01-30T06:53:55.713Z","_id":"ls0063cx3h9cks1ue","dockerhub_name":"nginx"}],"feature":[],"service":[{"_etag":null,"_id":"ls086eg8szwxxcph","_created":"2020-06-19T13:07:24.228389","_updated":"2024-01-23T11:43:30.452364","name":"PostgreSQL","code":"postgres","role":["postgres"],"type":"service","default":null,"popularity":null,"descr":null,"ports":{"private":["5432"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":{"light":{"width":576,"height":594,"image":"fd23f54c-e250-4228-8d56-7e5d93ffb925.svg"},"dark":{}},"category_id":null,"parent_app_id":null,"full_description":null,"description":null,"plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"postgres","form":null,"requirements":null,"docker_image_is_internal":true,"category":[null],"group":[{"_etag":null,"_id":12,"_created":null,"_updated":null,"name":"Database","code":"database"}],"versions":[{"_id":458,"name":"15","version":"15","update_status":"published","tag":"15"},{"_id":288,"name":"10.22","version":"10.22","update_status":"published","tag":"10.22"},{"_id":303,"name":"13.8","version":"13.8","update_status":"published","tag":"13.8"},{"_id":266,"name":"11","version":"11","update_status":"published","tag":"11"},{"_id":267,"name":"12.12","version":"12.12","update_status":"published","tag":"12.12"},{"_id":38,"name":"14.5","version":"14.5","update_status":"published","tag":"14.5"},{"_id":596,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"}],"links":[],"shared_ports":[{"host_port":"","container_port":"5432"}],"version":{"_id":596,"name":"Postgres","version":"15.1","update_status":"published","tag":"15.1"},"network":["ls025c5f1ld1u2tnn","ls007dio3aq1uh6ad"],"restart":"always","timestamp":"2024-01-30T10:38:07.016Z","domain":""}],"servers_count":3,"project_name":"sampletest","custom_stack_code":"sampletest"}} \ No newline at end of file diff --git a/tests/dockerhub.rs b/tests/dockerhub.rs index f109582..200b665 100644 --- a/tests/dockerhub.rs +++ b/tests/dockerhub.rs @@ -8,7 +8,7 @@ use serde_yaml; use stacker::forms::Volume; const DOCKER_USERNAME: &str = "trydirect"; -const DOCKER_PASSWORD: &str = "*******"; +const DOCKER_PASSWORD: &str = "***************"; // Unit Test // #[test] From 2994b0481093f75211b64bd39a1b7ba6f3f2e66c Mon Sep 17 00:00:00 2001 From: vsilent Date: Sun, 4 Feb 2024 09:06:19 +0200 Subject: [PATCH 162/284] tests json sample data --- tests/custom-stack-payload.json | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tests/custom-stack-payload.json diff --git a/tests/custom-stack-payload.json b/tests/custom-stack-payload.json new file mode 100644 index 0000000..2ec622b --- /dev/null +++ b/tests/custom-stack-payload.json @@ -0,0 +1,2 @@ +{"commonDomain":"","domainList":{},"region":"fsn1","zone":null,"server":"cx11","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":[],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":false,"disk_type":"pd-standart","cloud_token":"****************************","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"networks":[{ + "name": "default_network"}, {"name":"mynetwork"}],"web":[{"name":"MyApp","code":"myapp","domain":"myapp.com","shared_ports":[{"host_port":"","container_port":"8080"}],"versions":[],"custom":true,"type":"web","network":["default_network", "mynetwork"],"restart":"no","timestamp":"2024-01-15T09:47:46.580Z","_id":"lreqrvv81ifrmng39","dockerhub_user":"","dockerhub_name":"nginx", "dockerhub_password":"", "dockerhub_image": "None", "environment":[{"key":"SOMEENVVAR1","value":"SOMEENVVAR_VALUE1"},{"key":"SOMEENVVAR2","value":"SOMEENVVAR_VALUE2"}],"volumes":[]}],"feature":[],"service":[],"servers_count":3,"project_git_url":"info@optimum-web.com","project_name":"Sample2024","custom_stack_code":"sample2024"}} \ No newline at end of file From 05f0aefcd65dcee0c38c4ff1cd7eb9f9eccdd969 Mon Sep 17 00:00:00 2001 From: vsilent Date: Sun, 4 Feb 2024 10:12:51 +0200 Subject: [PATCH 163/284] local merge --- .gitignore | 1 + Cargo.lock | 22 ++++++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 32da6d8..eb15c24 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ target .idea/ files +access_control.conf \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index f844c9c..7dc72c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -753,9 +753,9 @@ dependencies = [ [[package]] name = "casbin" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fd06051bc34aa7ee753647dbd36506fa9f84026993d9871e65e0ee71ac3632" +checksum = "b71063d3ee2f5ecc89229ccade0f3f8fb413b5e3978124a38b611216f91dd7c9" dependencies = [ "async-trait", "fixedbitset", @@ -2806,9 +2806,9 @@ checksum = "4389f1d5789befaf6029ebd9f7dac4af7f7e3d61b69d4f30e2ac02b57e7712b0" [[package]] name = "rhai" -version = "1.16.3" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3625f343d89990133d013e39c46e350915178cf94f1bec9f49b0cbef98a3e3c" +checksum = "f6273372244d04a8a4b0bec080ea1e710403e88c5d9d83f9808b2bfa64f0982a" dependencies = [ "ahash 0.8.7", "bitflags 2.4.2", @@ -2819,13 +2819,14 @@ dependencies = [ "serde", "smallvec", "smartstring", + "thin-vec", ] [[package]] name = "rhai_codegen" -version = "1.6.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "853977598f084a492323fe2f7896b4100a86284ee8473612de60021ea341310f" +checksum = "9db7f8dc4c9d48183a17ce550574c42995252b82d267eaca3fcd1b979159856c" dependencies = [ "proc-macro2", "quote", @@ -3583,6 +3584,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "thin-vec" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b" +dependencies = [ + "serde", +] + [[package]] name = "thiserror" version = "1.0.56" From 769f5a3aff6b7689ebf88ba43a474b47dca4a47d Mon Sep 17 00:00:00 2001 From: petru Date: Mon, 5 Feb 2024 17:58:30 +0200 Subject: [PATCH 164/284] 30-access-policies app domain --- Cargo.lock | 138 +++++++++++++++++++++--------------- access_control.conf.dist | 8 +-- src/middleware/client.rs | 8 +++ src/middleware/trydirect.rs | 2 +- src/startup.rs | 1 + 5 files changed, 96 insertions(+), 61 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f844c9c..1dc15f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,7 +5,7 @@ version = 3 [[package]] name = "actix-casbin-auth" version = "0.4.4" -source = "git+https://github.com/smart--petea/actix-casbin-auth.git?branch=dirty-master#795c1209e4dea6078a787ccf7a882bd5d1148be7" +source = "git+https://github.com/smart--petea/actix-casbin-auth.git?branch=dirty-master#5b76cc4e0df68ccee02c563b947a788ab1cb5193" dependencies = [ "actix-service", "actix-web", @@ -16,11 +16,11 @@ dependencies = [ [[package]] name = "actix-codec" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8" +checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.2", "bytes", "futures-core", "futures-sink", @@ -48,9 +48,9 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.5.1" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "129d4c88e98860e1758c5de288d1632b07970a16d59bdf7b8d66053d582bb71f" +checksum = "d223b13fd481fc0d1f83bb12659ae774d9e3601814c68a0bc539731698cca743" dependencies = [ "actix-codec", "actix-rt", @@ -158,9 +158,9 @@ dependencies = [ [[package]] name = "actix-web" -version = "4.4.1" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e43428f3bf11dee6d166b00ec2df4e3aa8cc1606aaa0b7433c146852e2f4e03b" +checksum = "43a6556ddebb638c2358714d853257ed226ece6023ef9364f23f0c70737ea984" dependencies = [ "actix-codec", "actix-http", @@ -192,7 +192,7 @@ dependencies = [ "serde_urlencoded", "smallvec", "socket2 0.5.5", - "time 0.3.31", + "time 0.3.34", "url", ] @@ -372,9 +372,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" +checksum = "2faccea4cc4ab4a667ce676a30e8ec13922a692c99bb8f5b11f1502c72e04220" [[package]] name = "anstyle-parse" @@ -517,7 +517,7 @@ dependencies = [ "futures-lite 2.2.0", "parking", "polling 3.3.2", - "rustix 0.38.30", + "rustix 0.38.31", "slab", "tracing", "windows-sys 0.52.0", @@ -753,9 +753,9 @@ dependencies = [ [[package]] name = "casbin" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fd06051bc34aa7ee753647dbd36506fa9f84026993d9871e65e0ee71ac3632" +checksum = "b71063d3ee2f5ecc89229ccade0f3f8fb413b5e3978124a38b611216f91dd7c9" dependencies = [ "async-trait", "fixedbitset", @@ -930,7 +930,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" dependencies = [ "percent-encoding", - "time 0.3.31", + "time 0.3.34", "version_check", ] @@ -1265,7 +1265,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e366950e7785fe0e404901a2b4e5c09ebd6656767f0c2167e34c5068ce0cc2d" dependencies = [ "derive_builder 0.13.0", - "indexmap 2.2.1", + "indexmap 2.2.2", "serde", "serde_yaml", ] @@ -1651,7 +1651,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 2.2.1", + "indexmap 2.2.2", "slab", "tokio", "tokio-util", @@ -1828,9 +1828,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.59" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1878,9 +1878,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433de089bd45971eecf4668ee0ee8f4cec17db4f8bd8f7bc3197a6ce37aa7d9b" +checksum = "824b2ae422412366ba479e8111fd301f7b5faece8149317bb81925979a53f520" dependencies = [ "equivalent", "hashbrown 0.14.3", @@ -1940,9 +1940,9 @@ dependencies = [ [[package]] name = "itertools" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ "either", ] @@ -2019,9 +2019,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.152" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libredox" @@ -2139,9 +2139,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", ] @@ -2202,6 +2202,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-traits" version = "0.2.17" @@ -2387,9 +2393,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.6" +version = "2.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f200d8d83c44a45b21764d1916299752ca035d15ecd46faca3e9a2a2bf6ad06" +checksum = "219c0dcc30b6a27553f9cc242972b67f75b60eb0db71f0b5462f38b058c41546" dependencies = [ "memchr", "thiserror", @@ -2398,9 +2404,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.6" +version = "2.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcd6ab1236bbdb3a49027e920e693192ebfe8913f6d60e294de57463a493cfde" +checksum = "22e1288dbd7786462961e69bfd4df7848c1e37e8b74303dbdab82c3a9cdd2809" dependencies = [ "pest", "pest_generator", @@ -2408,9 +2414,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.6" +version = "2.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a31940305ffc96863a735bef7c7994a00b325a7138fdbc5bda0f1a0476d3275" +checksum = "1381c29a877c6d34b8c176e734f35d7f7f5b3adaefe940cb4d1bb7af94678e2e" dependencies = [ "pest", "pest_meta", @@ -2421,9 +2427,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.7.6" +version = "2.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7ff62f5259e53b78d1af898941cdcdccfae7385cf7d793a6e55de5d05bb4b7d" +checksum = "d0934d6907f148c22a3acbda520c7eed243ad7487a30f51f6ce52b58b7077a8a" dependencies = [ "once_cell", "pest", @@ -2437,7 +2443,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.2.1", + "indexmap 2.2.2", ] [[package]] @@ -2526,7 +2532,7 @@ dependencies = [ "cfg-if", "concurrent-queue", "pin-project-lite", - "rustix 0.38.30", + "rustix 0.38.31", "tracing", "windows-sys 0.52.0", ] @@ -2762,9 +2768,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.23" +version = "0.11.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" +checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" dependencies = [ "base64 0.21.7", "bytes", @@ -2784,9 +2790,11 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", + "sync_wrapper", "system-configuration", "tokio", "tokio-native-tls", @@ -2806,9 +2814,9 @@ checksum = "4389f1d5789befaf6029ebd9f7dac4af7f7e3d61b69d4f30e2ac02b57e7712b0" [[package]] name = "rhai" -version = "1.16.3" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3625f343d89990133d013e39c46e350915178cf94f1bec9f49b0cbef98a3e3c" +checksum = "f6273372244d04a8a4b0bec080ea1e710403e88c5d9d83f9808b2bfa64f0982a" dependencies = [ "ahash 0.8.7", "bitflags 2.4.2", @@ -2819,13 +2827,14 @@ dependencies = [ "serde", "smallvec", "smartstring", + "thin-vec", ] [[package]] name = "rhai_codegen" -version = "1.6.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "853977598f084a492323fe2f7896b4100a86284ee8473612de60021ea341310f" +checksum = "9db7f8dc4c9d48183a17ce550574c42995252b82d267eaca3fcd1b979159856c" dependencies = [ "proc-macro2", "quote", @@ -2923,9 +2932,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.30" +version = "0.38.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" dependencies = [ "bitflags 2.4.2", "errno", @@ -3187,7 +3196,7 @@ version = "0.9.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adf8a49373e98a4c5f0ceb5d05aa7c648d75f63774981ed95b7c7443bbd50c6e" dependencies = [ - "indexmap 2.2.1", + "indexmap 2.2.2", "itoa", "ryu", "serde", @@ -3320,7 +3329,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce81b7bd7c4493975347ef60d8c7e8b742d4694f4c49f93e0a12ea263938176c" dependencies = [ - "itertools 0.12.0", + "itertools 0.12.1", "nom", "unicode_categories", ] @@ -3454,7 +3463,7 @@ dependencies = [ "futures-util", "glob", "hmac", - "indexmap 2.2.1", + "indexmap 2.2.2", "lapin", "rand 0.8.5", "regex", @@ -3531,6 +3540,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "system-configuration" version = "0.5.1" @@ -3579,10 +3594,19 @@ dependencies = [ "cfg-if", "fastrand 2.0.1", "redox_syscall 0.4.1", - "rustix 0.38.30", + "rustix 0.38.31", "windows-sys 0.52.0", ] +[[package]] +name = "thin-vec" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b" +dependencies = [ + "serde", +] + [[package]] name = "thiserror" version = "1.0.56" @@ -3626,12 +3650,13 @@ dependencies = [ [[package]] name = "time" -version = "0.3.31" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" dependencies = [ "deranged", "itoa", + "num-conv", "powerfmt", "serde", "time-core", @@ -3646,10 +3671,11 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" +checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" dependencies = [ + "num-conv", "time-core", ] @@ -3679,9 +3705,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.35.1" +version = "1.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" dependencies = [ "backtrace", "bytes", @@ -3826,7 +3852,7 @@ dependencies = [ "log", "serde", "serde_json", - "time 0.3.31", + "time 0.3.34", "tracing", "tracing-core", "tracing-log 0.1.4", diff --git a/access_control.conf.dist b/access_control.conf.dist index 459a15f..5d04715 100644 --- a/access_control.conf.dist +++ b/access_control.conf.dist @@ -1,14 +1,14 @@ [request_definition] -r = sub, obj, act +r = sub, dom, obj, act [policy_definition] -p = sub, obj, act +p = sub, dom, obj, act [role_definition] -g = _, _ +g = _, _, _ [policy_effect] e = some(where (p.eft == allow)) [matchers] -m = g(r.sub, p.sub) && r.obj == p.obj && regexMatch(r.act, p.act) +m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && regexMatch(r.act, p.act) diff --git a/src/middleware/client.rs b/src/middleware/client.rs index a6915d5..def95b0 100644 --- a/src/middleware/client.rs +++ b/src/middleware/client.rs @@ -96,6 +96,14 @@ where None => {} } + let accesscontrol_vals = actix_casbin_auth::CasbinVals { + subject: client_id.to_string(), + domain: Some(String::from("app")), + }; + if req.extensions_mut().insert(accesscontrol_vals).is_some() { + return Err("sth wrong with access control".to_string()); + } + Ok(req) } .then(|req| async move { diff --git a/src/middleware/trydirect.rs b/src/middleware/trydirect.rs index 1c61049..c070379 100644 --- a/src/middleware/trydirect.rs +++ b/src/middleware/trydirect.rs @@ -22,7 +22,7 @@ pub async fn bearer_guard( req: ServiceRequest, credentials: BearerAuth) -> Resu let accesscontrol_vals = actix_casbin_auth::CasbinVals { subject: String::from("alice"), - domain: None, + domain: Some(String::from("human")), }; if req.extensions_mut().insert(accesscontrol_vals).is_some() { return Err((JsonResponse::::build().unauthorized("sth wrong with access control"), req)); diff --git a/src/startup.rs b/src/startup.rs index 3548192..1c43fc7 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -42,6 +42,7 @@ pub async fn run( ) .service( web::scope("/test") + .wrap(access_control_manager.clone()) .wrap(middleware::client::Guard::new()) .wrap(Cors::permissive()) .service(crate::routes::test::deploy::handler), From 4d39ea5300f704044156bd3d277d0d6cff7710c3 Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 10 Feb 2024 20:00:14 +0200 Subject: [PATCH 165/284] 30-access-policies sqlx-adapter. new version --- Cargo.lock | 343 +++++++++++++++++++++++++++++++++++++++++++---------- Cargo.toml | 3 +- 2 files changed, 281 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1dc15f9..269e579 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -372,9 +372,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2faccea4cc4ab4a667ce676a30e8ec13922a692c99bb8f5b11f1502c72e04220" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" [[package]] name = "anstyle-parse" @@ -433,13 +433,13 @@ dependencies = [ [[package]] name = "async-channel" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ca33f4bc4ed1babef42cad36cc1f51fa88be00420404e5b1e80ab1b18f7678c" +checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3" dependencies = [ "concurrent-queue", - "event-listener 4.0.3", - "event-listener-strategy", + "event-listener 5.0.0", + "event-listener-strategy 0.5.0", "futures-core", "pin-project-lite", ] @@ -464,7 +464,7 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ - "async-channel 2.1.1", + "async-channel 2.2.0", "async-executor", "async-io 2.3.1", "async-lock 3.3.0", @@ -516,7 +516,7 @@ dependencies = [ "futures-io", "futures-lite 2.2.0", "parking", - "polling 3.3.2", + "polling 3.4.0", "rustix 0.38.31", "slab", "tracing", @@ -539,7 +539,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" dependencies = [ "event-listener 4.0.3", - "event-listener-strategy", + "event-listener-strategy 0.4.0", "pin-project-lite", ] @@ -581,12 +581,31 @@ dependencies = [ "num-traits", ] +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + [[package]] name = "atomic-waker" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[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 = "autocfg" version = "1.1.0" @@ -656,7 +675,7 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118" dependencies = [ - "async-channel 2.1.1", + "async-channel 2.2.0", "async-lock 3.3.0", "async-task", "fastrand 2.0.1", @@ -731,9 +750,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceed8ef69d8518a5dda55c07425450b58a4e1946f4951eab6d7191ee86c2443d" +checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f" dependencies = [ "serde", ] @@ -825,9 +844,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.18" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f" dependencies = [ "clap_builder", "clap_derive", @@ -835,21 +854,21 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.18" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99" dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim", + "strsim 0.11.0", ] [[package]] name = "clap_derive" -version = "4.4.7" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" dependencies = [ "heck", "proc-macro2", @@ -859,9 +878,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "colorchoice" @@ -1049,7 +1068,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.10.0", "syn 1.0.109", ] @@ -1284,9 +1303,9 @@ checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" [[package]] name = "either" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" dependencies = [ "serde", ] @@ -1325,6 +1344,17 @@ dependencies = [ "version_check", ] +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] + [[package]] name = "event-listener" version = "2.5.3" @@ -1342,6 +1372,17 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "event-listener" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b72557800024fabbaa2449dd4bf24e37b93702d457a4d4f2b0dd1f0f039f20c1" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + [[package]] name = "event-listener-strategy" version = "0.4.0" @@ -1352,6 +1393,16 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "event-listener-strategy" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feedafcaa9b749175d5ac357452a9d41ea2911da598fde46ce1fe02c37751291" +dependencies = [ + "event-listener 5.0.0", + "pin-project-lite", +] + [[package]] name = "executor-trait" version = "2.1.0" @@ -1502,6 +1553,17 @@ dependencies = [ "parking_lot 0.11.2", ] +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot 0.12.1", +] + [[package]] name = "futures-io" version = "0.3.30" @@ -1706,9 +1768,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" +checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3" [[package]] name = "hex" @@ -1734,6 +1796,15 @@ dependencies = [ "digest", ] +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "http" version = "0.2.11" @@ -1955,18 +2026,18 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "jobserver" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.67" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" +checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" dependencies = [ "wasm-bindgen", ] @@ -2182,6 +2253,17 @@ dependencies = [ "tempfile", ] +[[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 = "nom" version = "7.1.3" @@ -2210,9 +2292,9 @@ checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", ] @@ -2525,9 +2607,9 @@ dependencies = [ [[package]] name = "polling" -version = "3.3.2" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "545c980a3880efd47b2e262f6a4bb6daad6555cf3367aa9c4e52895f69537a41" +checksum = "30054e72317ab98eddd8561db0f6524df3367636884b7b21b703e4b280a84a14" dependencies = [ "cfg-if", "concurrent-queue", @@ -3176,7 +3258,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "strsim", + "strsim 0.10.0", "syn 1.0.109", ] @@ -3340,19 +3422,31 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8de3b03a925878ed54a954f621e64bf55a3c1bd29652d0d1a17830405350188" dependencies = [ - "sqlx-core", - "sqlx-macros", + "sqlx-core 0.6.3", + "sqlx-macros 0.6.3", +] + +[[package]] +name = "sqlx" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dba03c279da73694ef99763320dea58b51095dfe87d001b1d4b5fe78ba8763cf" +dependencies = [ + "sqlx-core 0.7.3", + "sqlx-macros 0.7.3", + "sqlx-postgres", ] [[package]] name = "sqlx-adapter" -version = "0.4.2" -source = "git+https://github.com/smart--petea/sqlx-adapter.git?branch=dirty-master#5f7cabbde494098a1b460f26c4b74fcbcf2d5857" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e39a25e18b8f9cd4f61b1653be67260d28dcd31b0bd8d3a08ed3ecbe2afa3b84" dependencies = [ "async-trait", "casbin", "dotenv", - "sqlx", + "sqlx 0.7.3", ] [[package]] @@ -3362,7 +3456,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa8241483a83a3f33aa5fff7e7d9def398ff9990b2752b6c6112b83c6d246029" dependencies = [ "ahash 0.7.7", - "atoi", + "atoi 1.0.0", "base64 0.13.1", "bitflags 1.3.2", "byteorder", @@ -3376,7 +3470,7 @@ dependencies = [ "event-listener 2.5.3", "futures-channel", "futures-core", - "futures-intrusive", + "futures-intrusive 0.4.2", "futures-util", "hashlink", "hex", @@ -3410,6 +3504,47 @@ dependencies = [ "whoami", ] +[[package]] +name = "sqlx-core" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd" +dependencies = [ + "ahash 0.8.7", + "atoi 2.0.0", + "byteorder", + "bytes", + "crc", + "crossbeam-queue", + "dotenvy", + "either", + "event-listener 2.5.3", + "futures-channel", + "futures-core", + "futures-intrusive 0.5.0", + "futures-io", + "futures-util", + "hashlink", + "hex", + "indexmap 2.2.2", + "log", + "memchr", + "native-tls", + "once_cell", + "paste", + "percent-encoding", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlformat", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "url", +] + [[package]] name = "sqlx-macros" version = "0.6.3" @@ -3426,12 +3561,89 @@ dependencies = [ "serde", "serde_json", "sha2", - "sqlx-core", + "sqlx-core 0.6.3", "sqlx-rt", "syn 1.0.109", "url", ] +[[package]] +name = "sqlx-macros" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89961c00dc4d7dffb7aee214964b065072bff69e36ddb9e2c107541f75e4f2a5" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core 0.7.3", + "sqlx-macros-core", + "syn 1.0.109", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0bd4519486723648186a08785143599760f7cc81c52334a55d6a83ea1e20841" +dependencies = [ + "atomic-write-file", + "dotenvy", + "either", + "heck", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2", + "sqlx-core 0.7.3", + "sqlx-postgres", + "syn 1.0.109", + "tempfile", + "tokio", + "url", +] + +[[package]] +name = "sqlx-postgres" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24" +dependencies = [ + "atoi 2.0.0", + "base64 0.21.7", + "bitflags 2.4.2", + "byteorder", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "rand 0.8.5", + "serde", + "serde_json", + "sha1", + "sha2", + "smallvec", + "sqlx-core 0.7.3", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + [[package]] name = "sqlx-rt" version = "0.6.3" @@ -3475,7 +3687,7 @@ dependencies = [ "serde_valid", "serde_yaml", "sha2", - "sqlx", + "sqlx 0.6.3", "sqlx-adapter", "thiserror", "tokio", @@ -3512,6 +3724,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strsim" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" + [[package]] name = "subtle" version = "2.5.0" @@ -3587,13 +3805,12 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.9.0" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" dependencies = [ "cfg-if", "fastrand 2.0.1", - "redox_syscall 0.4.1", "rustix 0.38.31", "windows-sys 0.52.0", ] @@ -3965,9 +4182,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode_categories" @@ -4084,9 +4301,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" +checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -4094,9 +4311,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" +checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" dependencies = [ "bumpalo", "log", @@ -4109,9 +4326,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461" +checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97" dependencies = [ "cfg-if", "js-sys", @@ -4121,9 +4338,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" +checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4131,9 +4348,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" +checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" dependencies = [ "proc-macro2", "quote", @@ -4144,15 +4361,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" +checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" [[package]] name = "web-sys" -version = "0.3.67" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" +checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index 8942098..20a127c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,8 +44,7 @@ tokio-stream = "0.1.14" actix-http = "3.4.0" hmac = "0.12.1" sha2 = "0.10.8" -#sqlx-adapter = { version = "0.4.2", default-features = false, features = ["postgres", "runtime-tokio-native-tls"]} -sqlx-adapter = { git="https://github.com/smart--petea/sqlx-adapter.git", branch="dirty-master", default-features = false, features = ["postgres"]} +sqlx-adapter = { version = "1.0.0", default-features = false, features = ["postgres", "runtime-tokio-native-tls"]} # dctypes derive_builder = "0.12.0" From c53bcb79f77e353633730294dfb1c4b0efca9960 Mon Sep 17 00:00:00 2001 From: petru Date: Wed, 14 Feb 2024 18:18:35 +0200 Subject: [PATCH 166/284] 30-access-policies --- access_control.conf.dist | 8 ++++---- src/forms/mod.rs | 1 + src/forms/user.rs | 4 +++- src/middleware/client.rs | 2 +- src/middleware/trydirect.rs | 16 +++++++++------- src/startup.rs | 9 ++++++++- 6 files changed, 26 insertions(+), 14 deletions(-) diff --git a/access_control.conf.dist b/access_control.conf.dist index 5d04715..f164af1 100644 --- a/access_control.conf.dist +++ b/access_control.conf.dist @@ -1,14 +1,14 @@ [request_definition] -r = sub, dom, obj, act +r = sub, obj, act [policy_definition] -p = sub, dom, obj, act +p = sub, obj, act [role_definition] -g = _, _, _ +g = _, _ [policy_effect] e = some(where (p.eft == allow)) [matchers] -m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && regexMatch(r.act, p.act) +m = g(r.sub, p.sub) && keyMatch2(r.obj, p.obj) && r.act == p.act diff --git a/src/forms/mod.rs b/src/forms/mod.rs index 9647ea6..273c2a0 100644 --- a/src/forms/mod.rs +++ b/src/forms/mod.rs @@ -3,3 +3,4 @@ pub mod stack; pub mod user; pub use rating::*; +pub use user::UserForm; diff --git a/src/forms/user.rs b/src/forms/user.rs index 8ff0b4c..0fd0024 100644 --- a/src/forms/user.rs +++ b/src/forms/user.rs @@ -10,6 +10,8 @@ pub struct UserForm { pub user: User, } +//todo deref for UserForm. userForm.id, userForm.first_name + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] #[serde(rename_all = "camelCase")] pub struct User { @@ -139,4 +141,4 @@ impl TryInto for UserForm { }) } -} \ No newline at end of file +} diff --git a/src/middleware/client.rs b/src/middleware/client.rs index def95b0..7345223 100644 --- a/src/middleware/client.rs +++ b/src/middleware/client.rs @@ -98,7 +98,7 @@ where let accesscontrol_vals = actix_casbin_auth::CasbinVals { subject: client_id.to_string(), - domain: Some(String::from("app")), + domain: None, }; if req.extensions_mut().insert(accesscontrol_vals).is_some() { return Err("sth wrong with access control".to_string()); diff --git a/src/middleware/trydirect.rs b/src/middleware/trydirect.rs index c070379..e9ce5eb 100644 --- a/src/middleware/trydirect.rs +++ b/src/middleware/trydirect.rs @@ -1,4 +1,6 @@ -use crate::{models, configuration::Settings, forms::user::UserForm, helpers::JsonResponse}; +use crate::{configuration::Settings, helpers::JsonResponse}; +use crate::models; +use crate::forms; use actix_web::{web, dev::ServiceRequest, Error, HttpMessage}; use actix_web_httpauth::extractors::bearer::BearerAuth; use futures::future::{FutureExt}; @@ -12,20 +14,20 @@ pub async fn bearer_guard( req: ServiceRequest, credentials: BearerAuth) -> Resu let user = match fetch_user(settings.auth_url.as_str(), token).await { Ok(user) => user, Err(err) => { - return Err((JsonResponse::::build().unauthorized(err), req)); + return Err((JsonResponse::::build().unauthorized(err), req)); //todo anonymous } }; if req.extensions_mut().insert(Arc::new(user)).is_some() { - return Err((JsonResponse::::build().unauthorized("user already logged"), req)); + return Err((JsonResponse::::build().unauthorized("user already logged"), req)); //todo 500 internal error } let accesscontrol_vals = actix_casbin_auth::CasbinVals { - subject: String::from("alice"), - domain: Some(String::from("human")), + subject: String::from("alice"), //todo username or anonymous + domain: None, }; if req.extensions_mut().insert(accesscontrol_vals).is_some() { - return Err((JsonResponse::::build().unauthorized("sth wrong with access control"), req)); + return Err((JsonResponse::::build().unauthorized("sth wrong with access control"), req)); //todo 500 internal error } Ok(req) @@ -47,7 +49,7 @@ async fn fetch_user(auth_url: &str, token: &str) -> Result } resp - .json::() + .json::() .await .map_err(|_err| "can't parse the response body".to_string())? .try_into() diff --git a/src/startup.rs b/src/startup.rs index 1c43fc7..45f1464 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -28,7 +28,14 @@ pub async fn run( let server = HttpServer::new(move || { App::new() .wrap(TracingLogger::default()) - .service(web::scope("/health_check").service(crate::routes::health_check)) + .service( + web::scope("/health_check") + .wrap(HttpAuthentication::bearer( + middleware::trydirect::bearer_guard, + )) + .wrap(Cors::permissive()) + .service(crate::routes::health_check) + ) .service( web::scope("/client") .wrap(HttpAuthentication::bearer( From ff82dbf72bbae09dfc0229f4721e3743f591b39c Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 17 Feb 2024 08:03:05 +0200 Subject: [PATCH 167/284] 30-access-policies replace crate::routes::xxx with routes::xx --- src/startup.rs | 70 +++++++++++++++++++------------------------------- 1 file changed, 26 insertions(+), 44 deletions(-) diff --git a/src/startup.rs b/src/startup.rs index 45f1464..447f2dd 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -1,5 +1,6 @@ use crate::configuration::Settings; use crate::helpers; +use crate::routes; use actix_cors::Cors; use actix_web::dev::Server; use actix_web::{ @@ -28,64 +29,45 @@ pub async fn run( let server = HttpServer::new(move || { App::new() .wrap(TracingLogger::default()) - .service( - web::scope("/health_check") - .wrap(HttpAuthentication::bearer( + /* + .wrap(middleware::client::Guard::new()) + .wrap(HttpAuthentication::bearer( middleware::trydirect::bearer_guard, - )) - .wrap(Cors::permissive()) - .service(crate::routes::health_check) + )) + */ + .wrap(access_control_manager.clone()) + .wrap(Cors::permissive()) + .service( + web::scope("/health_check").service(routes::health_check) ) .service( web::scope("/client") - .wrap(HttpAuthentication::bearer( - middleware::trydirect::bearer_guard, - )) - .wrap(Cors::permissive()) - .service(crate::routes::client::add_handler) - .service(crate::routes::client::update_handler) - .service(crate::routes::client::enable_handler) - .service(crate::routes::client::disable_handler), + .service(routes::client::add_handler) + .service(routes::client::update_handler) + .service(routes::client::enable_handler) + .service(routes::client::disable_handler), ) .service( - web::scope("/test") - .wrap(access_control_manager.clone()) - .wrap(middleware::client::Guard::new()) - .wrap(Cors::permissive()) - .service(crate::routes::test::deploy::handler), + web::scope("/test").service(routes::test::deploy::handler), ) .service( - web::scope("/pen/1") - .wrap(access_control_manager.clone()) - .wrap(HttpAuthentication::bearer( - middleware::trydirect::bearer_guard, - )) - .wrap(Cors::permissive()) - .service(crate::routes::test::casbin::handler), + web::scope("/pen/1").service(routes::test::casbin::handler), ) .service( web::scope("/rating") - .wrap(HttpAuthentication::bearer( - middleware::trydirect::bearer_guard, - )) - .wrap(Cors::permissive()) - .service(crate::routes::rating::add_handler) - .service(crate::routes::rating::get_handler) - .service(crate::routes::rating::list_handler), + .service(routes::rating::add_handler) + .service(routes::rating::get_handler) + .service(routes::rating::list_handler), ) .service( web::scope("/stack") - .wrap(HttpAuthentication::bearer( - middleware::trydirect::bearer_guard, - )) - .wrap(Cors::permissive()) - .service(crate::routes::stack::deploy::add) - .service(crate::routes::stack::compose::add) - .service(crate::routes::stack::compose::admin) - .service(crate::routes::stack::get::item) - .service(crate::routes::stack::get::list) - .service(crate::routes::stack::add::add) - .service(crate::routes::stack::update::update), + .service(routes::stack::deploy::add) + .service(routes::stack::compose::add) + .service(routes::stack::compose::admin) + .service(routes::stack::get::item) + .service(routes::stack::get::list) + .service(routes::stack::add::add) + .service(routes::stack::update::update), ) .app_data(pg_pool.clone()) .app_data(mq_manager.clone()) From 7e575c699252a2afbe35c0e7037b8d2c7248483c Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 17 Feb 2024 08:12:46 +0200 Subject: [PATCH 168/284] 30-access-policies authorization manager --- .../{access_manager.rs => authorization_manager.rs} | 0 src/middleware/mod.rs | 2 +- src/startup.rs | 4 ++-- 3 files changed, 3 insertions(+), 3 deletions(-) rename src/middleware/{access_manager.rs => authorization_manager.rs} (100%) diff --git a/src/middleware/access_manager.rs b/src/middleware/authorization_manager.rs similarity index 100% rename from src/middleware/access_manager.rs rename to src/middleware/authorization_manager.rs diff --git a/src/middleware/mod.rs b/src/middleware/mod.rs index 59debf1..97bbd74 100644 --- a/src/middleware/mod.rs +++ b/src/middleware/mod.rs @@ -1,3 +1,3 @@ pub mod client; pub mod trydirect; -pub mod access_manager; +pub mod authorization_manager; diff --git a/src/startup.rs b/src/startup.rs index 447f2dd..9df9ab2 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -24,7 +24,7 @@ pub async fn run( let mq_manager = helpers::MqManager::try_new(settings.amqp.connection_string())?; let mq_manager = web::Data::new(mq_manager); - let access_control_manager = middleware::access_manager::try_new(settings.database.connection_string()).await?; + let authorization_manager = middleware::authorization_manager::try_new(settings.database.connection_string()).await?; let server = HttpServer::new(move || { App::new() @@ -35,7 +35,7 @@ pub async fn run( middleware::trydirect::bearer_guard, )) */ - .wrap(access_control_manager.clone()) + .wrap(authorization_manager.clone()) .wrap(Cors::permissive()) .service( web::scope("/health_check").service(routes::health_check) From eae011695cb9e64d8ece1442f1c2e4c2738ca362 Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 17 Feb 2024 08:25:13 +0200 Subject: [PATCH 169/284] 30-access-polices - Authorization/Authentication manager --- .../{client.rs => authentication/mod.rs} | 16 +++++----- src/middleware/authorization_manager.rs | 32 ------------------- src/middleware/mod.rs | 4 +-- src/startup.rs | 11 ++----- 4 files changed, 13 insertions(+), 50 deletions(-) rename src/middleware/{client.rs => authentication/mod.rs} (94%) delete mode 100644 src/middleware/authorization_manager.rs diff --git a/src/middleware/client.rs b/src/middleware/authentication/mod.rs similarity index 94% rename from src/middleware/client.rs rename to src/middleware/authentication/mod.rs index 7345223..81adf90 100644 --- a/src/middleware/client.rs +++ b/src/middleware/authentication/mod.rs @@ -22,15 +22,15 @@ use actix_web::{ }; use sqlx::{Pool, Postgres}; -pub struct Guard {} +pub struct Manager {} -impl Guard { +impl Manager { pub fn new() -> Self { Self {} } } -impl Transform for Guard +impl Transform for Manager where S: Service, Error = Error> + 'static, S::Future: 'static, @@ -39,21 +39,21 @@ where type Response = ServiceResponse; type Error = Error; type InitError = (); - type Transform = GuardMiddleware; + type Transform = ManagerMiddleware; type Future = Ready>; fn new_transform(&self, service: S) -> Self::Future { - ready(Ok(GuardMiddleware { + ready(Ok(ManagerMiddleware { service: Arc::new(Mutex::new(service)), })) } } -pub struct GuardMiddleware { +pub struct ManagerMiddleware { service: Arc>, } -impl Service for GuardMiddleware +impl Service for ManagerMiddleware where S: Service, Error = Error> + 'static, S::Future: 'static, @@ -66,7 +66,7 @@ where fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll> { self.service .try_lock() - .expect("GuardMiddleware was called allready") + .expect("Authentication ManagerMiddleware was called allready") .poll_ready(ctx) } diff --git a/src/middleware/authorization_manager.rs b/src/middleware/authorization_manager.rs deleted file mode 100644 index 4760114..0000000 --- a/src/middleware/authorization_manager.rs +++ /dev/null @@ -1,32 +0,0 @@ -use actix_casbin_auth::{ - CasbinService, - casbin::{ - DefaultModel, - CoreApi, - function_map::key_match2 - } -}; -use std::io::{Error, ErrorKind}; -use sqlx_adapter::SqlxAdapter; - -pub async fn try_new(db_connection_address: String) -> Result { - let m = DefaultModel::from_file("access_control.conf") - .await - .map_err(|err| Error::new(ErrorKind::Other, format!("{err:?}")))?; - let a = SqlxAdapter::new(db_connection_address, 8) - .await - .map_err(|err| Error::new(ErrorKind::Other, format!("{err:?}")))?; - - let mut casbin_service = CasbinService::new(m, a) - .await - .map_err(|err| Error::new(ErrorKind::Other, format!("{err:?}")))?; - - casbin_service - .write() - .await - .get_role_manager() - .write() - .matching_fn(Some(key_match2), None); - - Ok(casbin_service) -} diff --git a/src/middleware/mod.rs b/src/middleware/mod.rs index 97bbd74..5efc32e 100644 --- a/src/middleware/mod.rs +++ b/src/middleware/mod.rs @@ -1,3 +1,3 @@ -pub mod client; +pub mod authentication; pub mod trydirect; -pub mod authorization_manager; +pub mod authorization; diff --git a/src/startup.rs b/src/startup.rs index 9df9ab2..83b8548 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -24,18 +24,13 @@ pub async fn run( let mq_manager = helpers::MqManager::try_new(settings.amqp.connection_string())?; let mq_manager = web::Data::new(mq_manager); - let authorization_manager = middleware::authorization_manager::try_new(settings.database.connection_string()).await?; + let authorization = middleware::authorization::try_new(settings.database.connection_string()).await?; let server = HttpServer::new(move || { App::new() .wrap(TracingLogger::default()) - /* - .wrap(middleware::client::Guard::new()) - .wrap(HttpAuthentication::bearer( - middleware::trydirect::bearer_guard, - )) - */ - .wrap(authorization_manager.clone()) + .wrap(middleware::authentication::Manager::new()) + .wrap(authorization.clone()) .wrap(Cors::permissive()) .service( web::scope("/health_check").service(routes::health_check) From e4ad08ab5ed81d94094de3c7a24672769384b44b Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 17 Feb 2024 08:43:02 +0200 Subject: [PATCH 170/284] 30-access-policies get_header --- src/middleware/authentication/mod.rs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/middleware/authentication/mod.rs b/src/middleware/authentication/mod.rs index 81adf90..c2a1450 100644 --- a/src/middleware/authentication/mod.rs +++ b/src/middleware/authentication/mod.rs @@ -73,8 +73,8 @@ where fn call(&self, mut req: ServiceRequest) -> Self::Future { let service = self.service.clone(); async move { - let client_id: i32 = get_header(&req, "stacker-id")?; - let header_hash: String = get_header(&req, "stacker-hash")?; + let client_id: i32 = get_header(&req, "stacker-id")?.unwrap(); //todo + let header_hash: String = get_header(&req, "stacker-hash")?.unwrap(); //todo let db_pool = req.app_data::>>().unwrap().get_ref(); let client: Client = db_fetch_client(db_pool, client_id).await?; @@ -121,25 +121,28 @@ where } } -fn get_header(req: &ServiceRequest, header_name: &'static str) -> Result +fn get_header(req: &ServiceRequest, header_name: &'static str) -> Result, String> where T: FromStr, { let header_value = req .headers() - .get(HeaderName::from_static(header_name)) - .ok_or(format!("header {header_name} not found"))?; + .get(HeaderName::from_static(header_name)); - let header_value: &str = header_value - .to_str() - .map_err(|_| format!("header {header_name} can't be converted to string"))?; + if header_value.is_none() { + return Ok(None); + } header_value + .unwrap() + .to_str() + .map_err(|_| format!("header {header_name} can't be converted to string"))? .parse::() .map_err(|_| format!("header {header_name} has wrong type")) + .map(|v| Some(v)) } -async fn db_fetch_client(db_pool: &Pool, client_id: i32) -> Result { +async fn db_fetch_client(db_pool: &Pool, client_id: i32) -> Result { //todo let query_span = tracing::info_span!("Fetching the client by ID"); sqlx::query_as!( @@ -162,7 +165,7 @@ async fn db_fetch_client(db_pool: &Pool, client_id: i32) -> Result Result { - let content_length: usize = get_header(req, CONTENT_LENGTH.as_str())?; + let content_length: usize = get_header(req, CONTENT_LENGTH.as_str())?.unwrap(); //todo let mut body = BytesMut::with_capacity(content_length); let mut payload = req.take_payload(); while let Some(chunk) = payload.next().await { From be13d2a572a0a43a07af931fb127bc46d4f58d82 Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 17 Feb 2024 17:38:08 +0200 Subject: [PATCH 171/284] 30-access-policies app authorization --- src/middleware/authentication/mod.rs | 83 ++++++++++++++++++---------- src/startup.rs | 2 +- 2 files changed, 54 insertions(+), 31 deletions(-) diff --git a/src/middleware/authentication/mod.rs b/src/middleware/authentication/mod.rs index c2a1450..4a1851e 100644 --- a/src/middleware/authentication/mod.rs +++ b/src/middleware/authentication/mod.rs @@ -73,40 +73,25 @@ where fn call(&self, mut req: ServiceRequest) -> Self::Future { let service = self.service.clone(); async move { - let client_id: i32 = get_header(&req, "stacker-id")?.unwrap(); //todo - let header_hash: String = get_header(&req, "stacker-hash")?.unwrap(); //todo - - let db_pool = req.app_data::>>().unwrap().get_ref(); - let client: Client = db_fetch_client(db_pool, client_id).await?; - if client.secret.is_none() { - return Err("client is not active".to_string()); - } - - let client_secret = client.secret.as_ref().unwrap().as_bytes(); - let body_hash = compute_body_hash(&mut req, client_secret).await?; - if header_hash != body_hash { - return Err("hash is wrong".to_string()); - } - - match req.extensions_mut().insert(Arc::new(client)) { - Some(_) => { - tracing::error!("client middleware already called once"); - return Err("".to_string()); + let authorization = get_header::(&req, "authorization")?; + let client_id = get_header::(&req, "stacker-id")?; + if authorization.is_some() { + //try_authorize_bearer(); //todo + } else if client_id.is_some() { + try_authorize_id_hash(&mut req, client_id.unwrap()).await?; + } else { + let accesscontrol_vals = actix_casbin_auth::CasbinVals { + subject: "anonym".to_string(), + domain: None, + }; + if req.extensions_mut().insert(accesscontrol_vals).is_some() { + return Err("sth wrong with access control".to_string()); } - None => {} - } - - let accesscontrol_vals = actix_casbin_auth::CasbinVals { - subject: client_id.to_string(), - domain: None, - }; - if req.extensions_mut().insert(accesscontrol_vals).is_some() { - return Err("sth wrong with access control".to_string()); } Ok(req) } - .then(|req| async move { + .then(|req: Result| async move { match req { Ok(req) => { let service = service.lock().await; @@ -165,7 +150,7 @@ async fn db_fetch_client(db_pool: &Pool, client_id: i32) -> Result Result { - let content_length: usize = get_header(req, CONTENT_LENGTH.as_str())?.unwrap(); //todo + let content_length: usize = get_header(req, CONTENT_LENGTH.as_str())?.unwrap(); let mut body = BytesMut::with_capacity(content_length); let mut payload = req.take_payload(); while let Some(chunk) = payload.next().await { @@ -188,3 +173,41 @@ async fn compute_body_hash(req: &mut ServiceRequest, client_secret: &[u8]) -> Re Ok(format!("{:x}", mac.finalize().into_bytes())) } + +async fn try_authorize_id_hash(req: &mut ServiceRequest, client_id: i32) -> Result<(), String> { + let header_hash = get_header::(&req, "stacker-hash")?; + if header_hash.is_none() { + return Err("stacker-hash header is not set".to_string()); + } //todo + let header_hash = header_hash.unwrap(); + + let db_pool = req.app_data::>>().unwrap().get_ref(); + let client: Client = db_fetch_client(db_pool, client_id).await?; + if client.secret.is_none() { + return Err("client is not active".to_string()); + } + + let client_secret = client.secret.as_ref().unwrap().as_bytes(); + let body_hash = compute_body_hash(req, client_secret).await?; + if header_hash != body_hash { + return Err("hash is wrong".to_string()); + } + + match req.extensions_mut().insert(Arc::new(client)) { + Some(_) => { + tracing::error!("client middleware already called once"); + return Err("".to_string()); + } + None => {} + } + + let accesscontrol_vals = actix_casbin_auth::CasbinVals { + subject: client_id.to_string(), + domain: None, + }; + if req.extensions_mut().insert(accesscontrol_vals).is_some() { + return Err("sth wrong with access control".to_string()); + } + + Ok(()) +} diff --git a/src/startup.rs b/src/startup.rs index 83b8548..279044e 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -29,8 +29,8 @@ pub async fn run( let server = HttpServer::new(move || { App::new() .wrap(TracingLogger::default()) - .wrap(middleware::authentication::Manager::new()) .wrap(authorization.clone()) + .wrap(middleware::authentication::Manager::new()) .wrap(Cors::permissive()) .service( web::scope("/health_check").service(routes::health_check) From be1cb818a35f8743bbddde63dfcb833809441455 Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 17 Feb 2024 17:56:54 +0200 Subject: [PATCH 172/284] 30-access-policies two authentication managers in one bowl --- src/middleware/authentication/mod.rs | 99 ++++++++++++++++++++++------ src/middleware/mod.rs | 1 - src/middleware/trydirect.rs | 56 ---------------- 3 files changed, 79 insertions(+), 77 deletions(-) delete mode 100644 src/middleware/trydirect.rs diff --git a/src/middleware/authentication/mod.rs b/src/middleware/authentication/mod.rs index 4a1851e..1b79f1c 100644 --- a/src/middleware/authentication/mod.rs +++ b/src/middleware/authentication/mod.rs @@ -1,24 +1,34 @@ -use crate::helpers::JsonResponse; -use crate::models::Client; +use crate::{ + helpers::JsonResponse, + models, + forms, + configuration::Settings, +}; use actix_http::header::CONTENT_LENGTH; -use actix_web::web::BytesMut; -use actix_web::HttpMessage; -use futures::future::{FutureExt, LocalBoxFuture}; -use futures::lock::Mutex; -use futures::task::{Context, Poll}; -use futures::StreamExt; +use futures::{ + future::{FutureExt, LocalBoxFuture}, + lock::Mutex, + task::{Context, Poll}, + StreamExt, +}; use hmac::{Hmac, Mac}; use sha2::Sha256; -use std::future::{ready, Ready}; -use std::str::FromStr; -use std::sync::Arc; +use std::{ + future::{ready, Ready}, + str::FromStr, + sync::Arc, +}; use tracing::Instrument; - -use actix_web::{ - dev::{Service, ServiceRequest, ServiceResponse, Transform}, +use actix_web::{}; +use reqwest::header::{ACCEPT, CONTENT_TYPE}; +use actix_web::{ + web::BytesMut, + HttpMessage, + web, + Error, + dev::{ServiceRequest, Service, ServiceResponse, Transform}, error::ErrorBadRequest, http::header::HeaderName, - web, Error, }; use sqlx::{Pool, Postgres}; @@ -76,7 +86,7 @@ where let authorization = get_header::(&req, "authorization")?; let client_id = get_header::(&req, "stacker-id")?; if authorization.is_some() { - //try_authorize_bearer(); //todo + try_authorize_bearer(&mut req, authorization.unwrap()).await?; } else if client_id.is_some() { try_authorize_id_hash(&mut req, client_id.unwrap()).await?; } else { @@ -98,7 +108,7 @@ where service.call(req).await } Err(msg) => Err(ErrorBadRequest( - JsonResponse::::build().set_msg(msg).to_string(), + JsonResponse::::build().set_msg(msg).to_string(), )), } }) @@ -127,11 +137,11 @@ where .map(|v| Some(v)) } -async fn db_fetch_client(db_pool: &Pool, client_id: i32) -> Result { //todo +async fn db_fetch_client(db_pool: &Pool, client_id: i32) -> Result { //todo let query_span = tracing::info_span!("Fetching the client by ID"); sqlx::query_as!( - Client, + models::Client, r#"SELECT id, user_id, secret FROM client c WHERE c.id = $1"#, client_id, ) @@ -174,6 +184,7 @@ async fn compute_body_hash(req: &mut ServiceRequest, client_secret: &[u8]) -> Re Ok(format!("{:x}", mac.finalize().into_bytes())) } +#[tracing::instrument(name = "try authorize. stacker-id header")] async fn try_authorize_id_hash(req: &mut ServiceRequest, client_id: i32) -> Result<(), String> { let header_hash = get_header::(&req, "stacker-hash")?; if header_hash.is_none() { @@ -182,7 +193,7 @@ async fn try_authorize_id_hash(req: &mut ServiceRequest, client_id: i32) -> Resu let header_hash = header_hash.unwrap(); let db_pool = req.app_data::>>().unwrap().get_ref(); - let client: Client = db_fetch_client(db_pool, client_id).await?; + let client: models::Client = db_fetch_client(db_pool, client_id).await?; if client.secret.is_none() { return Err("client is not active".to_string()); } @@ -211,3 +222,51 @@ async fn try_authorize_id_hash(req: &mut ServiceRequest, client_id: i32) -> Resu Ok(()) } + +#[tracing::instrument(name = "try authorize. Authorization header")] +async fn try_authorize_bearer(req: &mut ServiceRequest, authorization: String) -> Result<(), String> { + let settings = req.app_data::>().unwrap(); + let token = "abc"; //todo + let user = match fetch_user(settings.auth_url.as_str(), token).await { + Ok(user) => user, + Err(err) => { + return Err(format!("{}", err)); + } + }; //todo . process the err + + if req.extensions_mut().insert(Arc::new(user)).is_some() { + return Err("user already logged".to_string()); + } + + let accesscontrol_vals = actix_casbin_auth::CasbinVals { + subject: String::from("alice"), //todo username or anonymous + domain: None, + }; + if req.extensions_mut().insert(accesscontrol_vals).is_some() { + return Err("sth wrong with access control".to_string()); + } + + Ok(()) +} + +async fn fetch_user(auth_url: &str, token: &str) -> Result { + let client = reqwest::Client::new(); + let resp = client + .get(auth_url) + .bearer_auth(token) + .header(CONTENT_TYPE, "application/json") + .header(ACCEPT, "application/json") + .send() + .await + .map_err(|_err| "no resp from auth server".to_string())?; + + if !resp.status().is_success() { + return Err("401 Unauthorized".to_string()); + } + + resp + .json::() + .await + .map_err(|_err| "can't parse the response body".to_string())? + .try_into() +} diff --git a/src/middleware/mod.rs b/src/middleware/mod.rs index 5efc32e..6d34250 100644 --- a/src/middleware/mod.rs +++ b/src/middleware/mod.rs @@ -1,3 +1,2 @@ pub mod authentication; -pub mod trydirect; pub mod authorization; diff --git a/src/middleware/trydirect.rs b/src/middleware/trydirect.rs deleted file mode 100644 index e9ce5eb..0000000 --- a/src/middleware/trydirect.rs +++ /dev/null @@ -1,56 +0,0 @@ -use crate::{configuration::Settings, helpers::JsonResponse}; -use crate::models; -use crate::forms; -use actix_web::{web, dev::ServiceRequest, Error, HttpMessage}; -use actix_web_httpauth::extractors::bearer::BearerAuth; -use futures::future::{FutureExt}; -use reqwest::header::{ACCEPT, CONTENT_TYPE}; -use std::sync::Arc; - -#[tracing::instrument(name = "TryDirect bearer guard.")] -pub async fn bearer_guard( req: ServiceRequest, credentials: BearerAuth) -> Result { - let settings = req.app_data::>().unwrap(); - let token = credentials.token(); - let user = match fetch_user(settings.auth_url.as_str(), token).await { - Ok(user) => user, - Err(err) => { - return Err((JsonResponse::::build().unauthorized(err), req)); //todo anonymous - } - }; - - if req.extensions_mut().insert(Arc::new(user)).is_some() { - return Err((JsonResponse::::build().unauthorized("user already logged"), req)); //todo 500 internal error - } - - let accesscontrol_vals = actix_casbin_auth::CasbinVals { - subject: String::from("alice"), //todo username or anonymous - domain: None, - }; - if req.extensions_mut().insert(accesscontrol_vals).is_some() { - return Err((JsonResponse::::build().unauthorized("sth wrong with access control"), req)); //todo 500 internal error - } - - Ok(req) -} - -async fn fetch_user(auth_url: &str, token: &str) -> Result { - let client = reqwest::Client::new(); - let resp = client - .get(auth_url) - .bearer_auth(token) - .header(CONTENT_TYPE, "application/json") - .header(ACCEPT, "application/json") - .send() - .await - .map_err(|_err| "no resp from auth server".to_string())?; - - if !resp.status().is_success() { - return Err("401 Unauthorized".to_string()); - } - - resp - .json::() - .await - .map_err(|_err| "can't parse the response body".to_string())? - .try_into() -} From f0e3df50bfe94d296bde4a827cb231080ccb477c Mon Sep 17 00:00:00 2001 From: petru Date: Sun, 18 Feb 2024 08:25:30 +0200 Subject: [PATCH 173/284] 30-access-policies authorization.rs --- src/middleware/authorization.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/middleware/authorization.rs diff --git a/src/middleware/authorization.rs b/src/middleware/authorization.rs new file mode 100644 index 0000000..4760114 --- /dev/null +++ b/src/middleware/authorization.rs @@ -0,0 +1,32 @@ +use actix_casbin_auth::{ + CasbinService, + casbin::{ + DefaultModel, + CoreApi, + function_map::key_match2 + } +}; +use std::io::{Error, ErrorKind}; +use sqlx_adapter::SqlxAdapter; + +pub async fn try_new(db_connection_address: String) -> Result { + let m = DefaultModel::from_file("access_control.conf") + .await + .map_err(|err| Error::new(ErrorKind::Other, format!("{err:?}")))?; + let a = SqlxAdapter::new(db_connection_address, 8) + .await + .map_err(|err| Error::new(ErrorKind::Other, format!("{err:?}")))?; + + let mut casbin_service = CasbinService::new(m, a) + .await + .map_err(|err| Error::new(ErrorKind::Other, format!("{err:?}")))?; + + casbin_service + .write() + .await + .get_role_manager() + .write() + .matching_fn(Some(key_match2), None); + + Ok(casbin_service) +} From 626baec4f5f098ad59d83cbd99e5d67342606c15 Mon Sep 17 00:00:00 2001 From: petru Date: Sun, 18 Feb 2024 08:51:31 +0200 Subject: [PATCH 174/284] 30-access-policies --- src/middleware/authentication/manager.rs | 37 ++++++++ .../authentication/manager_middleware.rs | 58 ++++++++++++ src/middleware/authentication/mod.rs | 91 ++----------------- 3 files changed, 102 insertions(+), 84 deletions(-) create mode 100644 src/middleware/authentication/manager.rs create mode 100644 src/middleware/authentication/manager_middleware.rs diff --git a/src/middleware/authentication/manager.rs b/src/middleware/authentication/manager.rs new file mode 100644 index 0000000..2b8e09d --- /dev/null +++ b/src/middleware/authentication/manager.rs @@ -0,0 +1,37 @@ +use crate::middleware::authentication::*; + +use std::sync::Arc; +use std::future::{ready, Ready}; +use futures::lock::Mutex; + +use actix_web::{ + Error, + dev::{Service, ServiceRequest, ServiceResponse, Transform}, +}; + +pub struct Manager {} + +impl Manager { + pub fn new() -> Self { + Self {} + } +} + +impl Transform for Manager +where + S: Service, Error = Error> + 'static, + S::Future: 'static, + B: 'static, +{ + type Response = ServiceResponse; + type Error = Error; + type InitError = (); + type Transform = ManagerMiddleware; + type Future = Ready>; + + fn new_transform(&self, service: S) -> Self::Future { + ready(Ok(ManagerMiddleware { + service: Arc::new(Mutex::new(service)), + })) + } +} diff --git a/src/middleware/authentication/manager_middleware.rs b/src/middleware/authentication/manager_middleware.rs new file mode 100644 index 0000000..67ecbf7 --- /dev/null +++ b/src/middleware/authentication/manager_middleware.rs @@ -0,0 +1,58 @@ +use crate::middleware::authentication::*; + +pub struct ManagerMiddleware { + pub service: Arc>, +} + +impl Service for ManagerMiddleware +where + S: Service, Error = Error> + 'static, + S::Future: 'static, + B: 'static, +{ + type Response = ServiceResponse; + type Error = S::Error; + type Future = LocalBoxFuture<'static, Result, Error>>; + + fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll> { + self.service + .try_lock() + .expect("Authentication ManagerMiddleware was called allready") + .poll_ready(ctx) + } + + fn call(&self, mut req: ServiceRequest) -> Self::Future { + let service = self.service.clone(); + async move { + let authorization = get_header::(&req, "authorization")?; + let client_id = get_header::(&req, "stacker-id")?; + if authorization.is_some() { + try_authorize_bearer(&mut req, authorization.unwrap()).await?; + } else if client_id.is_some() { + try_authorize_id_hash(&mut req, client_id.unwrap()).await?; + } else { + let accesscontrol_vals = actix_casbin_auth::CasbinVals { + subject: "anonym".to_string(), + domain: None, + }; + if req.extensions_mut().insert(accesscontrol_vals).is_some() { + return Err("sth wrong with access control".to_string()); + } + } + + Ok(req) + } + .then(|req: Result| async move { + match req { + Ok(req) => { + let service = service.lock().await; + service.call(req).await + } + Err(msg) => Err(ErrorBadRequest( + JsonResponse::::build().set_msg(msg).to_string(), + )), + } + }) + .boxed_local() + } +} diff --git a/src/middleware/authentication/mod.rs b/src/middleware/authentication/mod.rs index 1b79f1c..36986c5 100644 --- a/src/middleware/authentication/mod.rs +++ b/src/middleware/authentication/mod.rs @@ -1,3 +1,9 @@ +mod manager; +mod manager_middleware; + +pub use manager::*; +pub use manager_middleware::*; + use crate::{ helpers::JsonResponse, models, @@ -32,90 +38,6 @@ use actix_web::{ }; use sqlx::{Pool, Postgres}; -pub struct Manager {} - -impl Manager { - pub fn new() -> Self { - Self {} - } -} - -impl Transform for Manager -where - S: Service, Error = Error> + 'static, - S::Future: 'static, - B: 'static, -{ - type Response = ServiceResponse; - type Error = Error; - type InitError = (); - type Transform = ManagerMiddleware; - type Future = Ready>; - - fn new_transform(&self, service: S) -> Self::Future { - ready(Ok(ManagerMiddleware { - service: Arc::new(Mutex::new(service)), - })) - } -} - -pub struct ManagerMiddleware { - service: Arc>, -} - -impl Service for ManagerMiddleware -where - S: Service, Error = Error> + 'static, - S::Future: 'static, - B: 'static, -{ - type Response = ServiceResponse; - type Error = S::Error; - type Future = LocalBoxFuture<'static, Result, Error>>; - - fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll> { - self.service - .try_lock() - .expect("Authentication ManagerMiddleware was called allready") - .poll_ready(ctx) - } - - fn call(&self, mut req: ServiceRequest) -> Self::Future { - let service = self.service.clone(); - async move { - let authorization = get_header::(&req, "authorization")?; - let client_id = get_header::(&req, "stacker-id")?; - if authorization.is_some() { - try_authorize_bearer(&mut req, authorization.unwrap()).await?; - } else if client_id.is_some() { - try_authorize_id_hash(&mut req, client_id.unwrap()).await?; - } else { - let accesscontrol_vals = actix_casbin_auth::CasbinVals { - subject: "anonym".to_string(), - domain: None, - }; - if req.extensions_mut().insert(accesscontrol_vals).is_some() { - return Err("sth wrong with access control".to_string()); - } - } - - Ok(req) - } - .then(|req: Result| async move { - match req { - Ok(req) => { - let service = service.lock().await; - service.call(req).await - } - Err(msg) => Err(ErrorBadRequest( - JsonResponse::::build().set_msg(msg).to_string(), - )), - } - }) - .boxed_local() - } -} - fn get_header(req: &ServiceRequest, header_name: &'static str) -> Result, String> where T: FromStr, @@ -270,3 +192,4 @@ async fn fetch_user(auth_url: &str, token: &str) -> Result .map_err(|_err| "can't parse the response body".to_string())? .try_into() } + From 1820776afe98d894731ee4779d19d622252a58b3 Mon Sep 17 00:00:00 2001 From: petru Date: Mon, 19 Feb 2024 17:59:02 +0200 Subject: [PATCH 175/284] 30-access-policies refactor --- src/middleware/authentication/getheader.rs | 24 +++ .../authentication/manager_middleware.rs | 20 +- .../authentication/method/f_hmac.rs | 102 +++++++++ .../authentication/method/f_oauth.rs | 60 ++++++ src/middleware/authentication/method/mod.rs | 5 + src/middleware/authentication/mod.rs | 193 +----------------- 6 files changed, 207 insertions(+), 197 deletions(-) create mode 100644 src/middleware/authentication/getheader.rs create mode 100644 src/middleware/authentication/method/f_hmac.rs create mode 100644 src/middleware/authentication/method/f_oauth.rs create mode 100644 src/middleware/authentication/method/mod.rs diff --git a/src/middleware/authentication/getheader.rs b/src/middleware/authentication/getheader.rs new file mode 100644 index 0000000..d810400 --- /dev/null +++ b/src/middleware/authentication/getheader.rs @@ -0,0 +1,24 @@ +use actix_web::{ http::header::HeaderName, dev::ServiceRequest}; +use std::str::FromStr; + +pub fn get_header(req: &ServiceRequest, header_name: &'static str) -> Result, String> +where + T: FromStr, +{ + let header_value = req + .headers() + .get(HeaderName::from_static(header_name)); + + if header_value.is_none() { + return Ok(None); + } + + header_value + .unwrap() + .to_str() + .map_err(|_| format!("header {header_name} can't be converted to string"))? + .parse::() + .map_err(|_| format!("header {header_name} has wrong type")) + .map(|v| Some(v)) +} + diff --git a/src/middleware/authentication/manager_middleware.rs b/src/middleware/authentication/manager_middleware.rs index 67ecbf7..8faa9db 100644 --- a/src/middleware/authentication/manager_middleware.rs +++ b/src/middleware/authentication/manager_middleware.rs @@ -1,4 +1,9 @@ use crate::middleware::authentication::*; +use actix_web::{error::ErrorBadRequest, HttpMessage, Error, dev::{ServiceRequest, ServiceResponse, Service}}; +use crate::helpers::JsonResponse; +use futures::{task::{Poll, Context}, future::{FutureExt, LocalBoxFuture}, lock::Mutex}; +use crate::models; +use std::sync::Arc; pub struct ManagerMiddleware { pub service: Arc>, @@ -24,13 +29,14 @@ where fn call(&self, mut req: ServiceRequest) -> Self::Future { let service = self.service.clone(); async move { - let authorization = get_header::(&req, "authorization")?; - let client_id = get_header::(&req, "stacker-id")?; - if authorization.is_some() { - try_authorize_bearer(&mut req, authorization.unwrap()).await?; - } else if client_id.is_some() { - try_authorize_id_hash(&mut req, client_id.unwrap()).await?; - } else { + /* + method::try_oauth(&mut req).await? + || method::try_hmac(&mut req).await? + || method::anonym(&mut req); //todo + */ + + if (!(method::try_oauth(&mut req).await? || method::try_hmac(&mut req).await?)) + { let accesscontrol_vals = actix_casbin_auth::CasbinVals { subject: "anonym".to_string(), domain: None, diff --git a/src/middleware/authentication/method/f_hmac.rs b/src/middleware/authentication/method/f_hmac.rs new file mode 100644 index 0000000..998a237 --- /dev/null +++ b/src/middleware/authentication/method/f_hmac.rs @@ -0,0 +1,102 @@ +use hmac::{Hmac, Mac}; +use sha2::Sha256; +use sqlx::{Pool, Postgres}; +use tracing::Instrument; +use std::sync::Arc; +use crate::models; +use actix_web::{web, dev::ServiceRequest, HttpMessage}; +use crate::middleware::authentication::get_header; //todo move to helpers +use actix_http::header::CONTENT_LENGTH; +use futures::StreamExt; + +async fn db_fetch_client(db_pool: &Pool, client_id: i32) -> Result { //todo + let query_span = tracing::info_span!("Fetching the client by ID"); + + sqlx::query_as!( + models::Client, + r#"SELECT id, user_id, secret FROM client c WHERE c.id = $1"#, + client_id, + ) + .fetch_one(db_pool) + .instrument(query_span) + .await + .map_err(|err| { + match err { + sqlx::Error::RowNotFound => "the client is not found".to_string(), + e => { + tracing::error!("Failed to execute fetch query: {:?}", e); + String::new() + } + } + }) +} + +async fn compute_body_hash(req: &mut ServiceRequest, client_secret: &[u8]) -> Result { + let content_length: usize = get_header(req, CONTENT_LENGTH.as_str())?.unwrap(); + let mut body = web::BytesMut::with_capacity(content_length); + let mut payload = req.take_payload(); + while let Some(chunk) = payload.next().await { + body.extend_from_slice(&chunk.expect("can't unwrap the chunk")); + } + + let mut mac = + match Hmac::::new_from_slice(client_secret) { + Ok(mac) => mac, + Err(err) => { + tracing::error!("error generating hmac {err:?}"); + return Err("".to_string()); + } + }; + + mac.update(body.as_ref()); + let (_, mut payload) = actix_http::h1::Payload::create(true); + payload.unread_data(body.into()); + req.set_payload(payload.into()); + + Ok(format!("{:x}", mac.finalize().into_bytes())) +} + +#[tracing::instrument(name = "try authorize. stacker-id header")] +pub async fn try_hmac(req: &mut ServiceRequest) -> Result { + let client_id = get_header::(&req, "stacker-id")?; + if client_id.is_none() { + return Ok(false); + } + let client_id = client_id.unwrap(); + + let header_hash = get_header::(&req, "stacker-hash")?; + if header_hash.is_none() { + return Err("stacker-hash header is not set".to_string()); + } //todo + let header_hash = header_hash.unwrap(); + + let db_pool = req.app_data::>>().unwrap().get_ref(); + let client: models::Client = db_fetch_client(db_pool, client_id).await?; + if client.secret.is_none() { + return Err("client is not active".to_string()); + } + + let client_secret = client.secret.as_ref().unwrap().as_bytes(); + let body_hash = compute_body_hash(req, client_secret).await?; + if header_hash != body_hash { + return Err("hash is wrong".to_string()); + } + + match req.extensions_mut().insert(Arc::new(client)) { + Some(_) => { + tracing::error!("client middleware already called once"); + return Err("".to_string()); + } + None => {} + } + + let accesscontrol_vals = actix_casbin_auth::CasbinVals { + subject: client_id.to_string(), + domain: None, + }; + if req.extensions_mut().insert(accesscontrol_vals).is_some() { + return Err("sth wrong with access control".to_string()); + } + + Ok(true) +} diff --git a/src/middleware/authentication/method/f_oauth.rs b/src/middleware/authentication/method/f_oauth.rs new file mode 100644 index 0000000..02b2024 --- /dev/null +++ b/src/middleware/authentication/method/f_oauth.rs @@ -0,0 +1,60 @@ +use crate::middleware::authentication::get_header; +use actix_web::{web, dev::{ServiceRequest}, HttpMessage}; +use crate::configuration::Settings; +use crate::models; +use crate::forms; +use reqwest::header::{ACCEPT, CONTENT_TYPE}; +use std::sync::Arc; + +#[tracing::instrument(name = "try authorize. Authorization header")] +pub async fn try_oauth(req: &mut ServiceRequest) -> Result { + let authentication = get_header::(&req, "authorization")?; //todo + if authentication.is_none() { + return Ok(false); + } + + let settings = req.app_data::>().unwrap(); + let token = "abc"; //todo + let user = match fetch_user(settings.auth_url.as_str(), token).await { + Ok(user) => user, + Err(err) => { + return Err(format!("{}", err)); + } + }; //todo . process the err + + if req.extensions_mut().insert(Arc::new(user)).is_some() { + return Err("user already logged".to_string()); + } + + let accesscontrol_vals = actix_casbin_auth::CasbinVals { + subject: String::from("alice"), //todo username or anonymous + domain: None, + }; + if req.extensions_mut().insert(accesscontrol_vals).is_some() { + return Err("sth wrong with access control".to_string()); + } + + Ok(true) +} + +async fn fetch_user(auth_url: &str, token: &str) -> Result { + let client = reqwest::Client::new(); + let resp = client + .get(auth_url) + .bearer_auth(token) + .header(CONTENT_TYPE, "application/json") + .header(ACCEPT, "application/json") + .send() + .await + .map_err(|_err| "no resp from auth server".to_string())?; + + if !resp.status().is_success() { + return Err("401 Unauthorized".to_string()); + } + + resp + .json::() + .await + .map_err(|_err| "can't parse the response body".to_string())? + .try_into() +} diff --git a/src/middleware/authentication/method/mod.rs b/src/middleware/authentication/method/mod.rs new file mode 100644 index 0000000..5d82a31 --- /dev/null +++ b/src/middleware/authentication/method/mod.rs @@ -0,0 +1,5 @@ +mod f_oauth; +mod f_hmac; + +pub use f_oauth::try_oauth; +pub use f_hmac::try_hmac; diff --git a/src/middleware/authentication/mod.rs b/src/middleware/authentication/mod.rs index 36986c5..5338d6d 100644 --- a/src/middleware/authentication/mod.rs +++ b/src/middleware/authentication/mod.rs @@ -1,195 +1,8 @@ +mod getheader; mod manager; mod manager_middleware; +mod method; +pub use getheader::*; pub use manager::*; pub use manager_middleware::*; - -use crate::{ - helpers::JsonResponse, - models, - forms, - configuration::Settings, -}; -use actix_http::header::CONTENT_LENGTH; -use futures::{ - future::{FutureExt, LocalBoxFuture}, - lock::Mutex, - task::{Context, Poll}, - StreamExt, -}; -use hmac::{Hmac, Mac}; -use sha2::Sha256; -use std::{ - future::{ready, Ready}, - str::FromStr, - sync::Arc, -}; -use tracing::Instrument; -use actix_web::{}; -use reqwest::header::{ACCEPT, CONTENT_TYPE}; -use actix_web::{ - web::BytesMut, - HttpMessage, - web, - Error, - dev::{ServiceRequest, Service, ServiceResponse, Transform}, - error::ErrorBadRequest, - http::header::HeaderName, -}; -use sqlx::{Pool, Postgres}; - -fn get_header(req: &ServiceRequest, header_name: &'static str) -> Result, String> -where - T: FromStr, -{ - let header_value = req - .headers() - .get(HeaderName::from_static(header_name)); - - if header_value.is_none() { - return Ok(None); - } - - header_value - .unwrap() - .to_str() - .map_err(|_| format!("header {header_name} can't be converted to string"))? - .parse::() - .map_err(|_| format!("header {header_name} has wrong type")) - .map(|v| Some(v)) -} - -async fn db_fetch_client(db_pool: &Pool, client_id: i32) -> Result { //todo - let query_span = tracing::info_span!("Fetching the client by ID"); - - sqlx::query_as!( - models::Client, - r#"SELECT id, user_id, secret FROM client c WHERE c.id = $1"#, - client_id, - ) - .fetch_one(db_pool) - .instrument(query_span) - .await - .map_err(|err| { - match err { - sqlx::Error::RowNotFound => "the client is not found".to_string(), - e => { - tracing::error!("Failed to execute fetch query: {:?}", e); - String::new() - } - } - }) -} - -async fn compute_body_hash(req: &mut ServiceRequest, client_secret: &[u8]) -> Result { - let content_length: usize = get_header(req, CONTENT_LENGTH.as_str())?.unwrap(); - let mut body = BytesMut::with_capacity(content_length); - let mut payload = req.take_payload(); - while let Some(chunk) = payload.next().await { - body.extend_from_slice(&chunk.expect("can't unwrap the chunk")); - } - - let mut mac = - match Hmac::::new_from_slice(client_secret) { - Ok(mac) => mac, - Err(err) => { - tracing::error!("error generating hmac {err:?}"); - return Err("".to_string()); - } - }; - - mac.update(body.as_ref()); - let (_, mut payload) = actix_http::h1::Payload::create(true); - payload.unread_data(body.into()); - req.set_payload(payload.into()); - - Ok(format!("{:x}", mac.finalize().into_bytes())) -} - -#[tracing::instrument(name = "try authorize. stacker-id header")] -async fn try_authorize_id_hash(req: &mut ServiceRequest, client_id: i32) -> Result<(), String> { - let header_hash = get_header::(&req, "stacker-hash")?; - if header_hash.is_none() { - return Err("stacker-hash header is not set".to_string()); - } //todo - let header_hash = header_hash.unwrap(); - - let db_pool = req.app_data::>>().unwrap().get_ref(); - let client: models::Client = db_fetch_client(db_pool, client_id).await?; - if client.secret.is_none() { - return Err("client is not active".to_string()); - } - - let client_secret = client.secret.as_ref().unwrap().as_bytes(); - let body_hash = compute_body_hash(req, client_secret).await?; - if header_hash != body_hash { - return Err("hash is wrong".to_string()); - } - - match req.extensions_mut().insert(Arc::new(client)) { - Some(_) => { - tracing::error!("client middleware already called once"); - return Err("".to_string()); - } - None => {} - } - - let accesscontrol_vals = actix_casbin_auth::CasbinVals { - subject: client_id.to_string(), - domain: None, - }; - if req.extensions_mut().insert(accesscontrol_vals).is_some() { - return Err("sth wrong with access control".to_string()); - } - - Ok(()) -} - -#[tracing::instrument(name = "try authorize. Authorization header")] -async fn try_authorize_bearer(req: &mut ServiceRequest, authorization: String) -> Result<(), String> { - let settings = req.app_data::>().unwrap(); - let token = "abc"; //todo - let user = match fetch_user(settings.auth_url.as_str(), token).await { - Ok(user) => user, - Err(err) => { - return Err(format!("{}", err)); - } - }; //todo . process the err - - if req.extensions_mut().insert(Arc::new(user)).is_some() { - return Err("user already logged".to_string()); - } - - let accesscontrol_vals = actix_casbin_auth::CasbinVals { - subject: String::from("alice"), //todo username or anonymous - domain: None, - }; - if req.extensions_mut().insert(accesscontrol_vals).is_some() { - return Err("sth wrong with access control".to_string()); - } - - Ok(()) -} - -async fn fetch_user(auth_url: &str, token: &str) -> Result { - let client = reqwest::Client::new(); - let resp = client - .get(auth_url) - .bearer_auth(token) - .header(CONTENT_TYPE, "application/json") - .header(ACCEPT, "application/json") - .send() - .await - .map_err(|_err| "no resp from auth server".to_string())?; - - if !resp.status().is_success() { - return Err("401 Unauthorized".to_string()); - } - - resp - .json::() - .await - .map_err(|_err| "can't parse the response body".to_string())? - .try_into() -} - From 5330ad931ecc37b056539d50ab12447cae404f66 Mon Sep 17 00:00:00 2001 From: petru Date: Tue, 20 Feb 2024 07:40:33 +0200 Subject: [PATCH 176/284] 30-access-policies anonym logic separated --- .../authentication/manager_middleware.rs | 15 +-------------- src/middleware/authentication/method/f_anonym.rs | 15 +++++++++++++++ src/middleware/authentication/method/f_hmac.rs | 2 +- src/middleware/authentication/method/f_oauth.rs | 2 +- src/middleware/authentication/method/mod.rs | 2 ++ 5 files changed, 20 insertions(+), 16 deletions(-) create mode 100644 src/middleware/authentication/method/f_anonym.rs diff --git a/src/middleware/authentication/manager_middleware.rs b/src/middleware/authentication/manager_middleware.rs index 8faa9db..0a72c8d 100644 --- a/src/middleware/authentication/manager_middleware.rs +++ b/src/middleware/authentication/manager_middleware.rs @@ -29,22 +29,9 @@ where fn call(&self, mut req: ServiceRequest) -> Self::Future { let service = self.service.clone(); async move { - /* method::try_oauth(&mut req).await? || method::try_hmac(&mut req).await? - || method::anonym(&mut req); //todo - */ - - if (!(method::try_oauth(&mut req).await? || method::try_hmac(&mut req).await?)) - { - let accesscontrol_vals = actix_casbin_auth::CasbinVals { - subject: "anonym".to_string(), - domain: None, - }; - if req.extensions_mut().insert(accesscontrol_vals).is_some() { - return Err("sth wrong with access control".to_string()); - } - } + || method::anonym(&mut req)?; Ok(req) } diff --git a/src/middleware/authentication/method/f_anonym.rs b/src/middleware/authentication/method/f_anonym.rs new file mode 100644 index 0000000..fa7c288 --- /dev/null +++ b/src/middleware/authentication/method/f_anonym.rs @@ -0,0 +1,15 @@ +use actix_web::dev::ServiceRequest; +use actix_web::HttpMessage; + +#[tracing::instrument(name = "authenticate as anonym")] +pub fn anonym(req: &mut ServiceRequest) -> Result { + let accesscontrol_vals = actix_casbin_auth::CasbinVals { + subject: "anonym".to_string(), + domain: None, + }; + if req.extensions_mut().insert(accesscontrol_vals).is_some() { + return Err("sth wrong with access control".to_string()); + } + + Ok(true) +} diff --git a/src/middleware/authentication/method/f_hmac.rs b/src/middleware/authentication/method/f_hmac.rs index 998a237..e385f8f 100644 --- a/src/middleware/authentication/method/f_hmac.rs +++ b/src/middleware/authentication/method/f_hmac.rs @@ -56,7 +56,7 @@ async fn compute_body_hash(req: &mut ServiceRequest, client_secret: &[u8]) -> Re Ok(format!("{:x}", mac.finalize().into_bytes())) } -#[tracing::instrument(name = "try authorize. stacker-id header")] +#[tracing::instrument(name = "try authenticate via hmac")] pub async fn try_hmac(req: &mut ServiceRequest) -> Result { let client_id = get_header::(&req, "stacker-id")?; if client_id.is_none() { diff --git a/src/middleware/authentication/method/f_oauth.rs b/src/middleware/authentication/method/f_oauth.rs index 02b2024..5566f49 100644 --- a/src/middleware/authentication/method/f_oauth.rs +++ b/src/middleware/authentication/method/f_oauth.rs @@ -6,7 +6,7 @@ use crate::forms; use reqwest::header::{ACCEPT, CONTENT_TYPE}; use std::sync::Arc; -#[tracing::instrument(name = "try authorize. Authorization header")] +#[tracing::instrument(name = "try authenticate via bearer")] pub async fn try_oauth(req: &mut ServiceRequest) -> Result { let authentication = get_header::(&req, "authorization")?; //todo if authentication.is_none() { diff --git a/src/middleware/authentication/method/mod.rs b/src/middleware/authentication/method/mod.rs index 5d82a31..3d55881 100644 --- a/src/middleware/authentication/method/mod.rs +++ b/src/middleware/authentication/method/mod.rs @@ -1,5 +1,7 @@ mod f_oauth; +mod f_anonym; mod f_hmac; pub use f_oauth::try_oauth; +pub use f_anonym::anonym; pub use f_hmac::try_hmac; From 44c28efbe555b35bfe6976947aa0cc68412322e0 Mon Sep 17 00:00:00 2001 From: petru Date: Tue, 20 Feb 2024 17:18:04 +0200 Subject: [PATCH 177/284] 30-access-policies removed http authentication --- Cargo.lock | 219 ++++++++---------- Cargo.toml | 1 - .../authentication/manager_middleware.rs | 2 +- .../authentication/method/f_oauth.rs | 1 + src/startup.rs | 1 - 5 files changed, 104 insertions(+), 120 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 269e579..da5e64e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -56,7 +56,7 @@ dependencies = [ "actix-rt", "actix-service", "actix-utils", - "ahash 0.8.7", + "ahash 0.8.9", "base64 0.21.7", "bitflags 2.4.2", "brotli", @@ -92,7 +92,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -171,7 +171,7 @@ dependencies = [ "actix-service", "actix-utils", "actix-web-codegen", - "ahash 0.8.7", + "ahash 0.8.9", "bytes", "bytestring", "cfg-if", @@ -205,22 +205,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.48", -] - -[[package]] -name = "actix-web-httpauth" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d613edf08a42ccc6864c941d30fe14e1b676a77d16f1dbadc1174d065a0a775" -dependencies = [ - "actix-utils", - "actix-web", - "base64 0.21.7", - "futures-core", - "futures-util", - "log", - "pin-project-lite", + "syn 2.0.50", ] [[package]] @@ -240,9 +225,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ "getrandom 0.2.12", "once_cell", @@ -251,9 +236,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.7" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" +checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f" dependencies = [ "cfg-if", "const-random", @@ -358,9 +343,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.11" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +checksum = "96b09b5178381e0874812a9b157f7fe84982617e48f71f4e3235482775e5b540" dependencies = [ "anstyle", "anstyle-parse", @@ -406,9 +391,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" [[package]] name = "assert-json-diff" @@ -438,7 +423,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3" dependencies = [ "concurrent-queue", - "event-listener 5.0.0", + "event-listener 5.1.0", "event-listener-strategy 0.5.0", "futures-core", "pin-project-lite", @@ -516,7 +501,7 @@ dependencies = [ "futures-io", "futures-lite 2.2.0", "parking", - "polling 3.4.0", + "polling 3.5.0", "rustix 0.38.31", "slab", "tracing", @@ -569,7 +554,7 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -708,9 +693,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "d32a994c2b3ca201d9b263612a374263f05e7adde37c4707f693dcd375076d1f" [[package]] name = "bytecount" @@ -844,9 +829,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.0" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f" +checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da" dependencies = [ "clap_builder", "clap_derive", @@ -854,9 +839,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.0" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99" +checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb" dependencies = [ "anstream", "anstyle", @@ -873,7 +858,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -1001,9 +986,9 @@ checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" dependencies = [ "cfg-if", ] @@ -1161,11 +1146,11 @@ dependencies = [ [[package]] name = "derive_builder" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "660047478bc508c0fde22c868991eec0c40a63e48d610befef466d48e2bee574" +checksum = "8f59169f400d8087f238c5c0c7db6a28af18681717f3b623227d92f397e938c7" dependencies = [ - "derive_builder_macro 0.13.0", + "derive_builder_macro 0.13.1", ] [[package]] @@ -1182,9 +1167,9 @@ dependencies = [ [[package]] name = "derive_builder_core" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b217e6dd1011a54d12f3b920a411b5abd44b1716ecfe94f5f2f2f7b52e08ab7" +checksum = "a4ec317cc3e7ef0928b0ca6e4a634a4d6c001672ae210438cf114a83e56b018d" dependencies = [ "darling", "proc-macro2", @@ -1204,11 +1189,11 @@ dependencies = [ [[package]] name = "derive_builder_macro" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5f77d7e20ac9153428f7ca14a88aba652adfc7a0ef0a06d654386310ef663b" +checksum = "870368c3fb35b8031abb378861d4460f573b92238ec2152c927a21f77e3e0127" dependencies = [ - "derive_builder_core 0.13.0", + "derive_builder_core 0.13.1", "syn 1.0.109", ] @@ -1283,8 +1268,8 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e366950e7785fe0e404901a2b4e5c09ebd6656767f0c2167e34c5068ce0cc2d" dependencies = [ - "derive_builder 0.13.0", - "indexmap 2.2.2", + "derive_builder 0.13.1", + "indexmap 2.2.3", "serde", "serde_yaml", ] @@ -1374,9 +1359,9 @@ dependencies = [ [[package]] name = "event-listener" -version = "5.0.0" +version = "5.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b72557800024fabbaa2449dd4bf24e37b93702d457a4d4f2b0dd1f0f039f20c1" +checksum = "b7ad6fd685ce13acd6d9541a30f6db6567a7a24c9ffd4ba2955d29e3f22c8b27" dependencies = [ "concurrent-queue", "parking", @@ -1399,7 +1384,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "feedafcaa9b749175d5ac357452a9d41ea2911da598fde46ce1fe02c37751291" dependencies = [ - "event-listener 5.0.0", + "event-listener 5.1.0", "pin-project-lite", ] @@ -1606,7 +1591,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -1713,7 +1698,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 2.2.2", + "indexmap 2.2.3", "slab", "tokio", "tokio-util", @@ -1726,7 +1711,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" dependencies = [ - "ahash 0.7.7", + "ahash 0.7.8", ] [[package]] @@ -1735,7 +1720,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.7", + "ahash 0.7.8", ] [[package]] @@ -1744,7 +1729,7 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ - "ahash 0.8.7", + "ahash 0.8.9", "allocator-api2", ] @@ -1768,9 +1753,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3" +checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd" [[package]] name = "hex" @@ -1949,9 +1934,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824b2ae422412366ba479e8111fd301f7b5faece8149317bb81925979a53f520" +checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" dependencies = [ "equivalent", "hashbrown 0.14.3", @@ -2326,9 +2311,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" -version = "0.10.63" +version = "0.10.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8" +checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" dependencies = [ "bitflags 2.4.2", "cfg-if", @@ -2347,7 +2332,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -2358,9 +2343,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.99" +version = "0.9.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae" +checksum = "ae94056a791d0e1217d18b6cbdccb02c61e3054fc69893607f4067e3bb0b1fd1" dependencies = [ "cc", "libc", @@ -2504,7 +2489,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -2525,7 +2510,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.2.2", + "indexmap 2.2.3", ] [[package]] @@ -2545,7 +2530,7 @@ checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -2585,9 +2570,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "polling" @@ -2607,9 +2592,9 @@ dependencies = [ [[package]] name = "polling" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30054e72317ab98eddd8561db0f6524df3367636884b7b21b703e4b280a84a14" +checksum = "24f040dee2588b4963afb4e420540439d126f73fdacf4a9c486a96d840bac3c9" dependencies = [ "cfg-if", "concurrent-queue", @@ -2900,7 +2885,7 @@ version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6273372244d04a8a4b0bec080ea1e710403e88c5d9d83f9808b2bfa64f0982a" dependencies = [ - "ahash 0.8.7", + "ahash 0.8.9", "bitflags 2.4.2", "instant", "num-traits", @@ -2920,7 +2905,7 @@ checksum = "9db7f8dc4c9d48183a17ce550574c42995252b82d267eaca3fcd1b979159856c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -2940,16 +2925,17 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", + "cfg-if", "getrandom 0.2.12", "libc", "spin 0.9.8", "untrusted 0.9.0", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2958,7 +2944,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98f2771d255fd99f0294f13249fecd0cae6e074f86b4197ec1f1689d537b44d3" dependencies = [ - "ahash 0.7.7", + "ahash 0.7.8", "hashbrown 0.11.2", ] @@ -3044,7 +3030,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ "log", - "ring 0.17.7", + "ring 0.17.8", "rustls-webpki", "sct", ] @@ -3088,15 +3074,15 @@ version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.17.7", + "ring 0.17.8", "untrusted 0.9.0", ] [[package]] name = "ryu" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "same-file" @@ -3128,7 +3114,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.17.7", + "ring 0.17.8", "untrusted 0.9.0", ] @@ -3157,38 +3143,38 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] name = "serde_json" -version = "1.0.113" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", @@ -3274,11 +3260,11 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.31" +version = "0.9.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adf8a49373e98a4c5f0ceb5d05aa7c648d75f63774981ed95b7c7443bbd50c6e" +checksum = "8fd075d994154d4a774f95b51fb96bdc2832b0ea48425c92546073816cda1f2f" dependencies = [ - "indexmap 2.2.2", + "indexmap 2.2.3", "itoa", "ryu", "serde", @@ -3439,9 +3425,9 @@ dependencies = [ [[package]] name = "sqlx-adapter" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e39a25e18b8f9cd4f61b1653be67260d28dcd31b0bd8d3a08ed3ecbe2afa3b84" +checksum = "24fe30f13db95ad25c9b7480d9a3c8b1fabe42a9ebd670428fa56a7173281eaa" dependencies = [ "async-trait", "casbin", @@ -3455,7 +3441,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa8241483a83a3f33aa5fff7e7d9def398ff9990b2752b6c6112b83c6d246029" dependencies = [ - "ahash 0.7.7", + "ahash 0.7.8", "atoi 1.0.0", "base64 0.13.1", "bitflags 1.3.2", @@ -3510,7 +3496,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd" dependencies = [ - "ahash 0.8.7", + "ahash 0.8.9", "atoi 2.0.0", "byteorder", "bytes", @@ -3526,7 +3512,7 @@ dependencies = [ "futures-util", "hashlink", "hex", - "indexmap 2.2.2", + "indexmap 2.2.3", "log", "memchr", "native-tls", @@ -3663,7 +3649,6 @@ dependencies = [ "actix-cors", "actix-http", "actix-web", - "actix-web-httpauth", "chrono", "clap", "config", @@ -3675,7 +3660,7 @@ dependencies = [ "futures-util", "glob", "hmac", - "indexmap 2.2.2", + "indexmap 2.2.3", "lapin", "rand 0.8.5", "regex", @@ -3749,9 +3734,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb" dependencies = [ "proc-macro2", "quote", @@ -3826,22 +3811,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -3958,7 +3943,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -4055,7 +4040,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -4064,7 +4049,7 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5c266b9ac83dedf0e0385ad78514949e6d89491269e7065bee51d2bb8ec7373" dependencies = [ - "ahash 0.8.7", + "ahash 0.8.9", "gethostname", "log", "serde", @@ -4320,7 +4305,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", "wasm-bindgen-shared", ] @@ -4354,7 +4339,7 @@ checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4381,7 +4366,7 @@ version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" dependencies = [ - "ring 0.17.7", + "ring 0.17.8", "untrusted 0.9.0", ] @@ -4640,7 +4625,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 20a127c..56ef812 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,6 @@ thiserror = "1.0" serde_valid = "0.16.3" serde_json = { version = "1.0.105", features = [] } serde_derive = "1.0.188" -actix-web-httpauth = "0.8.1" actix-cors = "0.6.4" tracing-actix-web = "0.7.7" regex = "1.10.2" diff --git a/src/middleware/authentication/manager_middleware.rs b/src/middleware/authentication/manager_middleware.rs index 0a72c8d..7b9dc6b 100644 --- a/src/middleware/authentication/manager_middleware.rs +++ b/src/middleware/authentication/manager_middleware.rs @@ -29,7 +29,7 @@ where fn call(&self, mut req: ServiceRequest) -> Self::Future { let service = self.service.clone(); async move { - method::try_oauth(&mut req).await? + let _ = method::try_oauth(&mut req).await? || method::try_hmac(&mut req).await? || method::anonym(&mut req)?; diff --git a/src/middleware/authentication/method/f_oauth.rs b/src/middleware/authentication/method/f_oauth.rs index 5566f49..5befe35 100644 --- a/src/middleware/authentication/method/f_oauth.rs +++ b/src/middleware/authentication/method/f_oauth.rs @@ -9,6 +9,7 @@ use std::sync::Arc; #[tracing::instrument(name = "try authenticate via bearer")] pub async fn try_oauth(req: &mut ServiceRequest) -> Result { let authentication = get_header::(&req, "authorization")?; //todo + println!("{authentication:?}"); if authentication.is_none() { return Ok(false); } diff --git a/src/startup.rs b/src/startup.rs index 279044e..5e57dc8 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -8,7 +8,6 @@ use actix_web::{ App, HttpServer, }; use crate::middleware; -use actix_web_httpauth::middleware::HttpAuthentication; use sqlx::{Pool, Postgres}; use std::net::TcpListener; use tracing_actix_web::TracingLogger; From 0e5901da64a4987dee929a45d5d93a874b6dcb3c Mon Sep 17 00:00:00 2001 From: petru Date: Tue, 20 Feb 2024 18:30:50 +0200 Subject: [PATCH 178/284] 30-access-policies Bearer token extract logic --- .../authentication/method/f_oauth.rs | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/middleware/authentication/method/f_oauth.rs b/src/middleware/authentication/method/f_oauth.rs index 5befe35..2b8ccb8 100644 --- a/src/middleware/authentication/method/f_oauth.rs +++ b/src/middleware/authentication/method/f_oauth.rs @@ -6,17 +6,30 @@ use crate::forms; use reqwest::header::{ACCEPT, CONTENT_TYPE}; use std::sync::Arc; +fn try_extract_token(authentication: String) -> Result { + let mut authentication_parts = authentication.splitn(2, ' '); + match authentication_parts.next() { + Some("Bearer") => {} + _ => return Err("Bearer missing scheme".to_string()) + } + let token = authentication_parts.next(); + if token.is_none() { + return Err("Empty bearer token".to_string()); + } + + Ok(token.unwrap().into()) +} + #[tracing::instrument(name = "try authenticate via bearer")] pub async fn try_oauth(req: &mut ServiceRequest) -> Result { - let authentication = get_header::(&req, "authorization")?; //todo - println!("{authentication:?}"); + let authentication = get_header::(&req, "authorization")?; if authentication.is_none() { return Ok(false); } + let token = try_extract_token(authentication.unwrap())?; let settings = req.app_data::>().unwrap(); - let token = "abc"; //todo - let user = match fetch_user(settings.auth_url.as_str(), token).await { + let user = match fetch_user(settings.auth_url.as_str(), &token).await { Ok(user) => user, Err(err) => { return Err(format!("{}", err)); From 35815f61cccae763bfce7221661fabde219b98a1 Mon Sep 17 00:00:00 2001 From: petru Date: Wed, 21 Feb 2024 16:36:36 +0200 Subject: [PATCH 179/284] 30-access-policies user_fetch improved --- .../authentication/method/f_oauth.rs | 18 ++++++++---------- src/routes/client/disable.rs | 2 ++ src/routes/client/enable.rs | 2 ++ src/routes/client/update.rs | 2 ++ 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/middleware/authentication/method/f_oauth.rs b/src/middleware/authentication/method/f_oauth.rs index 2b8ccb8..efe215c 100644 --- a/src/middleware/authentication/method/f_oauth.rs +++ b/src/middleware/authentication/method/f_oauth.rs @@ -29,21 +29,19 @@ pub async fn try_oauth(req: &mut ServiceRequest) -> Result { let token = try_extract_token(authentication.unwrap())?; let settings = req.app_data::>().unwrap(); - let user = match fetch_user(settings.auth_url.as_str(), &token).await { - Ok(user) => user, - Err(err) => { - return Err(format!("{}", err)); - } - }; //todo . process the err + let user = fetch_user(settings.auth_url.as_str(), &token) + .await + .map_err(|err| format!("{err}"))?; + + let accesscontrol_vals = actix_casbin_auth::CasbinVals { + subject: user.id.clone(), + domain: None, + }; if req.extensions_mut().insert(Arc::new(user)).is_some() { return Err("user already logged".to_string()); } - let accesscontrol_vals = actix_casbin_auth::CasbinVals { - subject: String::from("alice"), //todo username or anonymous - domain: None, - }; if req.extensions_mut().insert(accesscontrol_vals).is_some() { return Err("sth wrong with access control".to_string()); } diff --git a/src/routes/client/disable.rs b/src/routes/client/disable.rs index 70d2a1c..3c46fa6 100644 --- a/src/routes/client/disable.rs +++ b/src/routes/client/disable.rs @@ -15,6 +15,8 @@ pub async fn disable_handler( pg_pool: web::Data, path: web::Path<(i32,)>, ) -> Result { + //todo. the owner + //todo. add admin endpoint let client_id = path.0; let mut client = db::client::fetch(pg_pool.get_ref(), client_id) .await diff --git a/src/routes/client/enable.rs b/src/routes/client/enable.rs index c87fc44..ca36451 100644 --- a/src/routes/client/enable.rs +++ b/src/routes/client/enable.rs @@ -16,6 +16,8 @@ pub async fn enable_handler( pg_pool: web::Data, path: web::Path<(i32,)>, ) -> Result { + //todo the owner + //todo add admin endpoint let client_id = path.0; let mut client = db::client::fetch(pg_pool.get_ref(), client_id) .await diff --git a/src/routes/client/update.rs b/src/routes/client/update.rs index 5f19de5..fe8db12 100644 --- a/src/routes/client/update.rs +++ b/src/routes/client/update.rs @@ -15,6 +15,8 @@ pub async fn update_handler( pg_pool: web::Data, path: web::Path<(i32,)>, ) -> Result { + //todo owner + //todo admin endpoint let client_id = path.0; let mut client = db::client::fetch(pg_pool.get_ref(), client_id) .await From e7661b2608f6afc3e19b9c36b30964ea0910b38f Mon Sep 17 00:00:00 2001 From: vsilent Date: Sat, 24 Feb 2024 21:22:45 +0200 Subject: [PATCH 180/284] refactoring 70% --- src/forms/stack/app.rs | 37 +++++++++++------------------ src/forms/stack/compose_networks.rs | 2 ++ src/forms/stack/custom.rs | 6 ++--- src/forms/stack/docker_image.rs | 21 +++++++++++++--- src/forms/stack/network.rs | 31 ------------------------ src/forms/stack/service_networks.rs | 8 +++---- src/forms/stack/volume.rs | 5 ++-- src/forms/stack1.rs | 14 ----------- src/helpers/stack/builder.rs | 4 ++-- src/main.rs | 1 - src/routes/stack/update.rs | 2 +- tests/custom-stack-payload.json | 3 +-- 12 files changed, 48 insertions(+), 86 deletions(-) diff --git a/src/forms/stack/app.rs b/src/forms/stack/app.rs index a46374e..6b548a1 100644 --- a/src/forms/stack/app.rs +++ b/src/forms/stack/app.rs @@ -5,7 +5,7 @@ use serde_json::Value; use serde::{Deserialize, Serialize}; use serde_valid::Validate; use crate::forms::stack::network::Network; -use crate::forms::stack::replace_id_with_name; +use crate::forms::stack::{DockerImage, replace_id_with_name}; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct App { @@ -95,35 +95,21 @@ impl App { tracing::debug!("Named volumes: {:?}", named_volumes); named_volumes } -} - -impl AsRef for App { - fn as_ref(&self) -> &forms::stack::DockerImage { - &self.docker_image - } -} -impl TryFrom<&App> for dctypes::Service { - type Error = String; - fn try_from(args:(&App, Vec)) -> Result { - let (app, all_networks) = args; + pub(crate) fn try_into_service(&self, all_networks: &Vec) -> Result { let mut service = dctypes::Service { - image: Some(app.docker_image.to_string()), + image: Some(self.docker_image.to_string()), ..Default::default() }; - let networks = dctypes::Networks::try_from(&app.network).unwrap_or_default(); + let networks = dctypes::Networks::try_from(&self.network).unwrap_or_default(); - // @todo refactoring all_networks and - // let networks = replace_id_with_name(service_networks, all_networks); - // service.networks = Networks::Simple(networks); - - let networks = replace_id_with_name(networks, &all_networks); + let networks = replace_id_with_name(networks, all_networks); service.networks = dctypes::Networks::Simple(networks); - let ports: Vec = match &app.ports { + let ports: Vec = match &self.ports { Some(ports) => { let mut collector = vec![]; for port in ports { @@ -134,7 +120,7 @@ impl TryFrom<&App> for dctypes::Service { None => vec![] }; - let volumes: Vec = match &app.volumes { + let volumes: Vec = match &self.volumes { Some(volumes) => { let mut collector = vec![]; for volume in volumes { @@ -147,7 +133,7 @@ impl TryFrom<&App> for dctypes::Service { }; let mut envs = IndexMap::new(); - for item in app.environment.environment.clone().unwrap_or_default() { + for item in self.environment.environment.clone().unwrap_or_default() { let items = item .into_iter() .map(|(k, v)| (k, Some(dctypes::SingleValue::String(v.clone())))) @@ -156,7 +142,6 @@ impl TryFrom<&App> for dctypes::Service { envs.extend(items); } - service.networks = networks; service.ports = dctypes::Ports::Long(ports); service.restart = Some("always".to_owned()); service.volumes = volumes; @@ -165,3 +150,9 @@ impl TryFrom<&App> for dctypes::Service { Ok(service) } } + +impl AsRef for App { + fn as_ref(&self) -> &forms::stack::DockerImage { + &self.docker_image + } +} diff --git a/src/forms/stack/compose_networks.rs b/src/forms/stack/compose_networks.rs index 0b229ab..afbd6f8 100644 --- a/src/forms/stack/compose_networks.rs +++ b/src/forms/stack/compose_networks.rs @@ -1,6 +1,7 @@ use serde::{Deserialize, Serialize}; use docker_compose_types as dctypes; use indexmap::IndexMap; +use crate::forms::stack; use crate::forms::stack::network::Network; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -38,3 +39,4 @@ impl Into>> for C networks } } + diff --git a/src/forms/stack/custom.rs b/src/forms/stack/custom.rs index 007e0af..872e34e 100644 --- a/src/forms/stack/custom.rs +++ b/src/forms/stack/custom.rs @@ -68,20 +68,20 @@ impl Custom { let all_networks = self.networks.networks.clone().unwrap_or(vec![]); for app_type in &self.web { - let service = dctypes::Service::try_from((&app_type.app, &all_networks))?; + let service = app_type.app.try_into_service(&all_networks)?; services.insert(app_type.app.code.clone().to_owned(), Some(service)); } if let Some(srvs) = &self.service { for app_type in srvs { - let service = dctypes::Service::try_from((&app_type.app, &all_networks))?; + let service = app_type.app.try_into_service(&all_networks)?; services.insert(app_type.app.code.clone().to_owned(), Some(service)); } } if let Some(features) = &self.feature { for app_type in features { - let service = dctypes::Service::try_from((&app_type.app, &all_networks))?; + let service = app_type.app.try_into_service(&all_networks)?; services.insert(app_type.app.code.clone().to_owned(), Some(service)); } } diff --git a/src/forms/stack/docker_image.rs b/src/forms/stack/docker_image.rs index b36a099..85a335a 100644 --- a/src/forms/stack/docker_image.rs +++ b/src/forms/stack/docker_image.rs @@ -1,18 +1,25 @@ use serde::{Deserialize, Serialize}; use serde_valid::Validate; use std::fmt; +use crate::helpers::dockerhub::DockerHub; + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct DockerImage { - #[validate(min_length = 3)] + // #[validate(min_length = 3)] #[validate(max_length = 50)] + // @todo conditional check, if not empty + // #[validate(pattern = r"^[a-z0-9]+([-_.][a-z0-9]+)*$")] pub dockerhub_user: Option, - #[validate(min_length = 3)] + // #[validate(min_length = 3)] #[validate(max_length = 50)] + // @todo conditional check, if not empty + // #[validate(pattern = r"^[a-z0-9]+([-_.][a-z0-9]+)*$")] pub dockerhub_name: Option, - #[validate(min_length = 3)] + // #[validate(min_length = 3)] #[validate(max_length = 100)] pub dockerhub_image: Option, + pub dockerhub_password: Option, } impl fmt::Display for DockerImage { @@ -32,3 +39,11 @@ impl fmt::Display for DockerImage { ) } } +impl DockerImage { + #[tracing::instrument(name = "is_active")] + pub async fn is_active(&self) -> Result { + DockerHub::from(self).is_active().await + } +} + + diff --git a/src/forms/stack/network.rs b/src/forms/stack/network.rs index 5f3b8ba..a05fd54 100644 --- a/src/forms/stack/network.rs +++ b/src/forms/stack/network.rs @@ -60,34 +60,3 @@ impl Into for Network { } } } -impl Into>> for stack::ComposeNetworks { - fn into(self) -> IndexMap> { - - // let mut default_networks = vec![Network::default()]; - let mut default_networks = vec![]; - - let networks = match self.networks { - None => { - default_networks - } - Some(mut nets) => { - if !nets.is_empty() { - nets.append(&mut default_networks); - } - nets - } - }; - - let networks = networks - .into_iter() - .map(|net| { - (net.name.clone(), dctypes::MapOrEmpty::Map(net.into())) - } - ) - .collect::>(); - - tracing::debug!("networks collected {:?}", &networks); - - networks - } -} diff --git a/src/forms/stack/service_networks.rs b/src/forms/stack/service_networks.rs index f1b8267..97763e6 100644 --- a/src/forms/stack/service_networks.rs +++ b/src/forms/stack/service_networks.rs @@ -11,15 +11,15 @@ impl TryFrom<&ServiceNetworks> for dctypes::Networks { fn try_from(service_networks: &ServiceNetworks) -> Result { let mut default_networks = vec![]; - let nets = match service_networks.network.as_ref() { + let nets = match service_networks.network.as_ref() { Some(mut _nets) => { _nets.append(&mut default_networks); - _nets - } + _nets.clone() + } None => { default_networks } }; - Ok(dctypes::Networks::Simple(result)) + Ok(dctypes::Networks::Simple(nets.into())) } } diff --git a/src/forms/stack/volume.rs b/src/forms/stack/volume.rs index faa7089..ab4d3f8 100644 --- a/src/forms/stack/volume.rs +++ b/src/forms/stack/volume.rs @@ -50,11 +50,12 @@ impl TryInto for &Volume { } } -impl Into for Volume { +impl Into for &Volume { fn into(self) -> dctypes::ComposeVolume { // let's create a symlink to /var/docker/volumes in project docroot let mut driver_opts = IndexMap::default(); - let host_path = self.host_path.unwrap(); + let host_path = self.host_path.clone().unwrap_or_else(String::default); + // @todo check if host_path is required argument driver_opts.insert(String::from("type"), Some(dctypes::SingleValue::String("none".to_string()))); driver_opts.insert(String::from("o"), Some(dctypes::SingleValue::String("bind".to_string()))); // @todo move to config stack docroot on host diff --git a/src/forms/stack1.rs b/src/forms/stack1.rs index d63764b..888b42f 100644 --- a/src/forms/stack1.rs +++ b/src/forms/stack1.rs @@ -4,7 +4,6 @@ use serde_valid::Validate; use std::fmt; use indexmap::IndexMap; use regex::Regex; -use crate::helpers::dockerhub::DockerHub; use crate::helpers::stack::dctypes::SingleValue; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] @@ -102,19 +101,6 @@ impl fmt::Display for DockerImage { } -impl DockerImage { - #[tracing::instrument(name = "is_active")] - pub async fn is_active(&self) -> Result { - DockerHub::from(self).is_active().await - } -} - - -impl AsRef for App { - fn as_ref(&self) -> &DockerImage { - &self.docker_image - } -} #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct StackForm { diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 404f9e9..1539a9a 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -31,8 +31,8 @@ impl DcBuilder { // <<<<<<< HEAD let apps = forms::stack::Stack::try_from(&self.stack)?; - let services = apps.custom.services()?; - let named_volumes = apps.custom.named_volumes()?; + let services = apps.custom.services()?; + let named_volumes = apps.custom.named_volumes()?; // let all_networks = &apps.custom.networks.networks.clone().unwrap_or(vec![]); let networks = apps.custom.networks.clone(); diff --git a/src/main.rs b/src/main.rs index 86d9ba0..8132f58 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,6 @@ use stacker::startup::run; use stacker::telemetry::{get_subscriber, init_subscriber}; use std::net::TcpListener; - #[actix_web::main] async fn main() -> std::io::Result<()> { let subscriber = get_subscriber("stacker".into(), "info".into()); diff --git a/src/routes/stack/update.rs b/src/routes/stack/update.rs index 23123ae..ba4d728 100644 --- a/src/routes/stack/update.rs +++ b/src/routes/stack/update.rs @@ -41,7 +41,7 @@ pub async fn update( return Err(JsonResponse::::build().bad_request("Can not access docker image")); } - let body: Value = serde_json::to_value::(form.into_inner()) + let body: Value = serde_json::to_value::(form_inner) .map_err(|err| JsonResponse::::build().bad_request(format!("{err}")) )?; diff --git a/tests/custom-stack-payload.json b/tests/custom-stack-payload.json index 2ec622b..ab48715 100644 --- a/tests/custom-stack-payload.json +++ b/tests/custom-stack-payload.json @@ -1,2 +1 @@ -{"commonDomain":"","domainList":{},"region":"fsn1","zone":null,"server":"cx11","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":[],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":false,"disk_type":"pd-standart","cloud_token":"****************************","provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-monthly","custom":{"networks":[{ - "name": "default_network"}, {"name":"mynetwork"}],"web":[{"name":"MyApp","code":"myapp","domain":"myapp.com","shared_ports":[{"host_port":"","container_port":"8080"}],"versions":[],"custom":true,"type":"web","network":["default_network", "mynetwork"],"restart":"no","timestamp":"2024-01-15T09:47:46.580Z","_id":"lreqrvv81ifrmng39","dockerhub_user":"","dockerhub_name":"nginx", "dockerhub_password":"", "dockerhub_image": "None", "environment":[{"key":"SOMEENVVAR1","value":"SOMEENVVAR_VALUE1"},{"key":"SOMEENVVAR2","value":"SOMEENVVAR_VALUE2"}],"volumes":[]}],"feature":[],"service":[],"servers_count":3,"project_git_url":"info@optimum-web.com","project_name":"Sample2024","custom_stack_code":"sample2024"}} \ No newline at end of file +{"commonDomain":"","domainList":{},"region":"","zone":null,"server":"cx11","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":[],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":true,"disk_type":"pd-standart","cloud_token":"*******************","cloud_key":"*********","cloud_secret":"****************","disk_size":40,"provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-annually","custom":{"networks":[{"name":"default_network","id":"lsnd2ttg3ivhw3db5"}],"web":[{"_etag":null,"_id":"lsq2tdff3c0acf2lj","_created":"2023-04-28T09:46:19.470502","_updated":"2024-02-09T13:44:36.854036","name":"PostgREST","code":"postgrest","role":["postgrest"],"type":"web","default":false,"popularity":null,"descr":null,"ports":{"public":["3000","8080"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":null,"category_id":null,"parent_app_id":null,"full_description":null,"description":null,"plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"postgrest","form":null,"requirements":null,"docker_image_is_internal":true,"custom_preset":{"volumes":[],"environment":[{"key":"PGRST_OPENAPI_SERVER_PROXY_URI","value":"http://DOMAIN_NAME:3000"},{"key":"PGRST_DB_ANON_ROLE","value":"anon"},{"key":"PGRST_DB_SCHEMA","value":"public"},{"key":"PGHOST","value":"postgresql_host"},{"key":"PGPORT","value":"5432"},{"key":"PGUSER","value":"user"},{"key":"PGDATABASE","value":"database"},{"key":"PGPASSWORD ","value":"password"}],"shared_ports":[{"host_port":"3000","container_port":"3000"}],"restart":"always"},"category":[null],"group":[],"versions":[{"_id":556,"name":"Postgrest","version":"latest","update_status":"published","tag":"latest"}],"links":[{"url":"https://postgrest.org","title":"Vendor","type":"vendor","follow":false},{"repo_owner":"PostgREST","repo_name":"postgrest","type":"github","follow":false}],"version":{"_id":556,"name":"Postgrest","version":"latest","update_status":"published","tag":"latest"},"network":["lsnd2ttg3ivhw3db5"],"restart":"always","timestamp":"2024-02-17T12:50:01.659Z","volumes":[],"environment":[{"key":"PGRST_OPENAPI_SERVER_PROXY_URI","value":"http://DOMAIN_NAME:3000"},{"key":"PGRST_DB_ANON_ROLE","value":"anon"},{"key":"PGRST_DB_SCHEMA","value":"public"},{"key":"PGHOST","value":"postgresql_host"},{"key":"PGPORT","value":"5432"},{"key":"PGUSER","value":"user"},{"key":"PGDATABASE","value":"database"},{"key":"PGPASSWORD ","value":"password"}],"shared_ports":[{"host_port":"3000","container_port":"3000"}],"domain":"","dockerhub_name":"postgrest"}],"feature":[],"service":[],"servers_count":3,"project_name":"Databases","custom_stack_code":"databases"}} \ No newline at end of file From f2fa00efbea302ed43d31926840da032b671306c Mon Sep 17 00:00:00 2001 From: vsilent Date: Sat, 24 Feb 2024 23:07:55 +0200 Subject: [PATCH 181/284] refactoring ~75%, code compiles --- src/forms/stack/service_networks.rs | 6 ++-- src/helpers/stack/builder.rs | 50 +---------------------------- 2 files changed, 3 insertions(+), 53 deletions(-) diff --git a/src/forms/stack/service_networks.rs b/src/forms/stack/service_networks.rs index 97763e6..03f5f45 100644 --- a/src/forms/stack/service_networks.rs +++ b/src/forms/stack/service_networks.rs @@ -10,14 +10,12 @@ impl TryFrom<&ServiceNetworks> for dctypes::Networks { type Error = (); fn try_from(service_networks: &ServiceNetworks) -> Result { - let mut default_networks = vec![]; let nets = match service_networks.network.as_ref() { - Some(mut _nets) => { - _nets.append(&mut default_networks); + Some(_nets) => { _nets.clone() } None => { - default_networks + vec![] } }; Ok(dctypes::Networks::Simple(nets.into())) diff --git a/src/helpers/stack/builder.rs b/src/helpers/stack/builder.rs index 1539a9a..e17d364 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/stack/builder.rs @@ -29,8 +29,7 @@ impl DcBuilder { ..Default::default() }; -// <<<<<<< HEAD - let apps = forms::stack::Stack::try_from(&self.stack)?; + let apps = forms::stack::Stack::try_from(&self.stack)?; let services = apps.custom.services()?; let named_volumes = apps.custom.named_volumes()?; @@ -40,53 +39,6 @@ impl DcBuilder { if !named_volumes.is_empty() { compose_content.volumes = dctypes::TopLevelVolumes(named_volumes); -// ======= -// match _stack { -// Ok(apps) => { -// -// for app_type in &apps.custom.web { -// let mut service = app_type.app.try_into_service(); -// let service_networks = service.networks.clone(); -// let networks = replace_id_with_name(service_networks, all_networks); -// service.networks = Networks::Simple(networks); -// services.insert(app_type.app.code.clone().to_owned(), Some(service)); -// named_volumes.extend(extract_named_volumes(app_type.app.clone())); -// } -// -// if let Some(srvs) = apps.custom.service { -// for app_type in srvs { -// let mut service = app_type.app.try_into_service(); -// let service_networks = service.networks.clone(); -// let networks = replace_id_with_name(service_networks, all_networks); -// service.networks = Networks::Simple(networks); -// services.insert(app_type.app.code.clone().to_owned(), Some(service)); -// named_volumes.extend(extract_named_volumes(app_type.app.clone())); -// } -// } -// -// if let Some(features) = apps.custom.feature { -// for app_type in features { -// let mut service = app_type.app.try_into_service(); -// let service_networks = service.networks.clone(); -// let networks = replace_id_with_name(service_networks, all_networks); -// service.networks = Networks::Simple(networks); -// services.insert(app_type.app.code.clone().to_owned(), Some(service)); -// named_volumes.extend(extract_named_volumes(app_type.app.clone())); -// } -// } -// -// let networks = apps.custom.networks.clone(); -// compose_content.networks = ComposeNetworks(networks.into()); -// -// if !named_volumes.is_empty() { -// compose_content.volumes = TopLevelVolumes(named_volumes); -// } -// -// } -// Err(e) => { -// tracing::debug!("Unpack stack form error {:?}", e); -// } -// >>>>>>> issue-16 } tracing::debug!("services {:?}", &services); From 1cc25627aba9c6131e52a4ae100224aa48610b3c Mon Sep 17 00:00:00 2001 From: vsilent Date: Sun, 25 Feb 2024 08:52:44 +0200 Subject: [PATCH 182/284] delete extra file --- src/forms/stack/service_networks.rs | 35 +++ src/forms/stack1.rs | 423 ---------------------------- 2 files changed, 35 insertions(+), 423 deletions(-) delete mode 100644 src/forms/stack1.rs diff --git a/src/forms/stack/service_networks.rs b/src/forms/stack/service_networks.rs index 03f5f45..17b51c5 100644 --- a/src/forms/stack/service_networks.rs +++ b/src/forms/stack/service_networks.rs @@ -21,3 +21,38 @@ impl TryFrom<&ServiceNetworks> for dctypes::Networks { Ok(dctypes::Networks::Simple(nets.into())) } } + +// IndexMap +// +// impl Into>> for stack::ComposeNetworks { +// fn into(self) -> IndexMap> { +// +// // let mut default_networks = vec![Network::default()]; +// let mut default_networks = vec![]; +// +// let networks = match self.networks { +// None => { +// default_networks +// } +// Some(mut nets) => { +// if !nets.is_empty() { +// nets.append(&mut default_networks); +// } +// nets +// } +// }; +// +// let networks = networks +// .into_iter() +// .map(|net| { +// (net.name.clone(), MapOrEmpty::Map(net.into())) +// } +// ) +// .collect::>(); +// +// tracing::debug!("networks collected {:?}", &networks); +// +// networks +// } +// } + diff --git a/src/forms/stack1.rs b/src/forms/stack1.rs deleted file mode 100644 index 888b42f..0000000 --- a/src/forms/stack1.rs +++ /dev/null @@ -1,423 +0,0 @@ -use serde::{Deserialize, Serialize}; -use serde_json::Value; -use serde_valid::Validate; -use std::fmt; -use indexmap::IndexMap; -use regex::Regex; -use crate::helpers::stack::dctypes::SingleValue; - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Role { - pub role: Option>, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Requirements { - #[validate(min_length = 1)] - #[validate(max_length = 10)] - #[validate(pattern = r"^\d+\.?[0-9]+$")] - pub cpu: Option, - #[validate(min_length = 1)] - #[validate(max_length = 10)] - #[validate(pattern = r"^\d+G$")] - #[serde(rename = "disk_size")] - pub disk_size: Option, - #[serde(rename = "ram_size")] - #[validate(min_length = 1)] - #[validate(max_length = 10)] - #[validate(pattern = r"^\d+G$")] - pub ram_size: Option, -} - -fn validate_non_empty(v: &Option) -> Result<(), serde_valid::validation::Error> { - if v.is_none() { - return Ok(()); - } - - if let Some(value) = v { - if value.is_empty() { - return Ok(()); - } - - // #[validate(pattern = r"^\d{2,6}$")] - let re = Regex::new(r"^\d{2,6}$").unwrap(); - - if !re.is_match(value.as_str()) { - return Err(serde_valid::validation::Error::Custom("Port is not valid.".to_owned())); - } - } - - Ok(()) -} - -#[derive(Validate)] -struct Data { - val: i32, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Port { - #[validate(custom(|v| validate_non_empty(v)))] - pub host_port: Option, - #[validate(pattern = r"^\d{2,6}$")] - pub container_port: String, - #[validate(enumerate("tcp", "udp"))] - pub protocol: Option, -} - - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct DockerImage { - // #[validate(min_length = 3)] - #[validate(max_length = 50)] - // @todo conditional check, if not empty - // #[validate(pattern = r"^[a-z0-9]+([-_.][a-z0-9]+)*$")] - pub dockerhub_user: Option, - // #[validate(min_length = 3)] - #[validate(max_length = 50)] - // @todo conditional check, if not empty - // #[validate(pattern = r"^[a-z0-9]+([-_.][a-z0-9]+)*$")] - pub dockerhub_name: Option, - // #[validate(min_length = 3)] - #[validate(max_length = 100)] - pub dockerhub_image: Option, - pub dockerhub_password: Option, -} - -impl fmt::Display for DockerImage { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let dh_image = self.dockerhub_image.as_ref().map(String::as_str).unwrap_or(""); - let dh_nmspc = self.dockerhub_user.as_ref().map(String::as_str).unwrap_or(""); - let dh_name = self.dockerhub_name.as_ref().map(String::as_str).unwrap_or(""); - - write!( - f, - "{}{}{}", - if !dh_nmspc.is_empty() { format!("{}/", dh_nmspc) } else { String::new() }, - if !dh_name.is_empty() { dh_name } else { dh_image }, - if !dh_name.contains(":") && dh_image.is_empty() { ":latest".to_string() } else { String::new() }, - ) - } -} - - - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct StackForm { - #[validate(max_length = 255)] - #[serde(rename = "commonDomain")] - pub common_domain: Option, - pub domain_list: Option, - #[validate(min_length = 2)] - #[validate(max_length = 255)] - pub stack_code: Option, - #[validate(min_length = 2)] - #[validate(max_length = 50)] - pub region: String, - #[validate(min_length = 2)] - #[validate(max_length = 50)] - pub zone: Option, - #[validate(min_length = 2)] - #[validate(max_length = 50)] - pub server: String, - #[validate(min_length = 2)] - #[validate(max_length = 50)] - pub os: String, - #[validate(min_length = 3)] - #[validate(max_length = 50)] - pub ssl: String, - pub vars: Option>, - pub integrated_features: Option>, - pub extended_features: Option>, - pub subscriptions: Option>, - pub form_app: Option>, - #[validate(min_length = 3)] - #[validate(max_length = 50)] - pub disk_type: Option, - pub save_token: bool, - #[validate(min_length = 10)] - #[validate(max_length = 255)] - pub cloud_token: String, - #[validate(min_length = 2)] - #[validate(max_length = 50)] - pub provider: String, - #[validate(min_length = 3)] - #[validate(max_length = 50)] - pub selected_plan: String, - #[validate] - pub custom: Custom, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -#[serde(rename_all = "snake_case")] -pub struct StackPayload { - pub(crate) id: Option, - pub(crate) user_token: Option, - pub(crate) user_email: Option, - #[serde(rename = "commonDomain")] - pub common_domain: String, - pub domain_list: Option, - pub region: String, - pub zone: Option, - pub server: String, - pub os: String, - pub ssl: String, - pub vars: Option>, - #[serde(rename = "integrated_features")] - pub integrated_features: Option>, - #[serde(rename = "extended_features")] - pub extended_features: Option>, - pub subscriptions: Option>, - pub form_app: Option>, - pub disk_type: Option, - #[serde(rename = "save_token")] - pub save_token: bool, - #[serde(rename = "cloud_token")] - pub cloud_token: String, - pub provider: String, - pub stack_code: String, - #[serde(rename = "selected_plan")] - pub selected_plan: String, - pub custom: Custom, - pub docker_compose: Option>, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct DomainList {} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct Var {} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Price { - pub value: f64, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Custom { - #[validate] - pub web: Vec, - #[validate] - pub feature: Option>, - #[validate] - pub service: Option>, - #[validate(minimum = 0)] - #[validate(maximum = 10)] - pub servers_count: u32, - #[validate(min_length = 3)] - #[validate(max_length = 50)] - pub custom_stack_code: String, - #[validate(min_length = 3)] - #[validate(max_length = 255)] - pub project_git_url: Option, - pub custom_stack_category: Option>, - pub custom_stack_short_description: Option, - pub custom_stack_description: Option, - #[validate(min_length = 3)] - #[validate(max_length = 255)] - pub project_name: String, - pub project_overview: Option, - pub project_description: Option, - #[serde(flatten)] - pub networks: ComposeNetworks, // all networks -} - - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct App { - #[serde(rename = "_etag")] - #[validate(min_length = 3)] - #[validate(max_length = 255)] - pub etag: Option, - #[serde(rename = "_id")] - pub id: String, - #[serde(rename = "_created")] - pub created: Option, - #[serde(rename = "_updated")] - pub updated: Option, - #[validate(min_length = 3)] - #[validate(max_length = 50)] - pub name: String, - #[validate(min_length = 3)] - #[validate(max_length = 50)] - pub code: String, - #[validate(min_length = 3)] - #[validate(max_length = 50)] - #[serde(rename = "type")] - pub type_field: String, - #[serde(flatten)] - pub role: Role, - pub default: Option, - pub versions: Option>, - #[serde(flatten)] - #[validate] - pub docker_image: DockerImage, - #[serde(flatten)] - #[validate] - pub requirements: Requirements, - #[validate(minimum = 1)] - pub popularity: Option, - pub commercial: Option, - pub subscription: Option, - pub autodeploy: Option, - pub suggested: Option, - pub dependency: Option, - pub avoid_render: Option, - pub price: Option, - pub icon: Option, - pub domain: Option, - pub category_id: Option, - pub parent_app_id: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub descr: Option, - pub full_description: Option, - pub description: Option, - pub plan_type: Option, - pub ansible_var: Option, - pub repo_dir: Option, - pub url_app: Option, - pub url_git: Option, - #[validate(enumerate("always", "no", "unless-stopped", "on-failure"))] - pub restart: String, - pub volumes: Option>, - #[serde(flatten)] - pub environment: Environment, - #[serde(flatten)] - pub network: ServiceNetworks, - #[validate] - pub shared_ports: Option>, -} - - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct EnvVar { - pub(crate) key: String, - pub(crate) value: String, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Environment { - pub(crate) environment: Option>, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Volume { - pub host_path: Option, - pub container_path: Option, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Volumes { - volumes: Vec, -} - -// pub(crate) type Networks = Option>; -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct ServiceNetworks { - pub network: Option>, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct NetworkDriver { - // not implemented -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Network { - pub(crate) id: String, - pub(crate) attachable: Option, - pub(crate) driver: Option, - pub(crate) driver_opts: Option, - pub(crate) enable_ipv6: Option, - pub(crate) internal: Option, - pub(crate) external: Option, - pub(crate) ipam: Option, - pub(crate) labels: Option, - pub(crate) name: String, -} - -impl Default for Network { - fn default() -> Self { - // The case when we need at least one external network to be preconfigured - Network { - id: "default_network".to_string(), - attachable: None, - driver: None, - driver_opts: Default::default(), - enable_ipv6: None, - internal: None, - external: Some(true), - ipam: None, - labels: None, - name: "default_network".to_string(), - } - } -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct ComposeNetworks { - pub networks: Option>, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Web { - #[serde(flatten)] - #[validate] - pub app: App, - pub custom: Option, - pub main: Option, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Feature { - #[serde(flatten)] - #[validate] - pub app: App, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Service { - #[serde(flatten)] - #[validate] - pub(crate) app: App, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Icon { - pub light: IconLight, - pub dark: IconDark, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct IconLight { - pub width: i64, - pub height: i64, - pub image: String, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct IconDark {} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Version { - #[serde(rename = "_etag")] - pub etag: Option, - #[serde(rename = "_id")] - pub id: u32, - #[serde(rename = "_created")] - pub created: Option, - #[serde(rename = "_updated")] - pub updated: Option, - pub app_id: Option, - pub name: String, - #[validate(min_length = 3)] - #[validate(max_length = 20)] - pub version: String, - #[serde(rename = "update_status")] - pub update_status: Option, - #[validate(min_length = 3)] - #[validate(max_length = 20)] - pub tag: String, -} From 6cd46bcfa8da62f8ce397d6c99d929336e013727 Mon Sep 17 00:00:00 2001 From: vsilent Date: Sun, 25 Feb 2024 09:33:44 +0200 Subject: [PATCH 183/284] new fixes from issue-16 --- src/forms/stack/app.rs | 19 +- src/forms/stack/custom.rs | 3 + src/forms/stack/environment.rs | 9 +- src/forms/stack/payload.rs | 9 +- src/forms/stack/port.rs | 10 +- src/forms/stack/requirements.rs | 6 +- src/forms/stack1.rs | 462 ++++++++++++++++++++++++++++++++ src/helpers/json.rs | 4 + src/routes/stack/add.rs | 13 +- src/routes/stack/deploy.rs | 6 +- src/routes/stack/update.rs | 4 +- src/routes/test/deploy.rs | 7 + 12 files changed, 522 insertions(+), 30 deletions(-) create mode 100644 src/forms/stack1.rs diff --git a/src/forms/stack/app.rs b/src/forms/stack/app.rs index 6b548a1..1eedd6b 100644 --- a/src/forms/stack/app.rs +++ b/src/forms/stack/app.rs @@ -14,7 +14,7 @@ pub struct App { #[validate(max_length = 255)] pub etag: Option, #[serde(rename = "_id")] - pub id: u32, + pub id: String, #[serde(rename = "_created")] pub created: Option, #[serde(rename = "_updated")] @@ -34,8 +34,10 @@ pub struct App { pub default: Option, pub versions: Option>, #[serde(flatten)] - pub docker_image: forms::stack::DockerImage, + #[validate] + pub docker_image: DockerImage, #[serde(flatten)] + #[validate] pub requirements: forms::stack::Requirements, #[validate(minimum = 1)] pub popularity: Option, @@ -59,18 +61,15 @@ pub struct App { pub repo_dir: Option, pub url_app: Option, pub url_git: Option, - pub restart: Option, + #[validate(enumerate("always", "no", "unless-stopped", "on-failure"))] + pub restart: String, pub volumes: Option>, #[serde(flatten)] pub environment: forms::stack::Environment, #[serde(flatten)] pub network: forms::stack::ServiceNetworks, - // #[serde(flatten)] - // pub ports: Ports, - #[serde(rename(deserialize = "sharedPorts"))] - #[serde(rename(serialize = "shared_ports"))] - #[serde(alias = "shared_ports")] - pub ports: Option>, + #[validate] + pub shared_ports: Option>, } impl App { @@ -109,7 +108,7 @@ impl App { let networks = replace_id_with_name(networks, all_networks); service.networks = dctypes::Networks::Simple(networks); - let ports: Vec = match &self.ports { + let ports: Vec = match &self.shared_ports { Some(ports) => { let mut collector = vec![]; for port in ports { diff --git a/src/forms/stack/custom.rs b/src/forms/stack/custom.rs index 872e34e..b127a12 100644 --- a/src/forms/stack/custom.rs +++ b/src/forms/stack/custom.rs @@ -8,8 +8,11 @@ use crate::forms::stack::Network; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Custom { + #[validate] pub web: Vec, + #[validate] pub feature: Option>, + #[validate] pub service: Option>, #[validate(minimum = 0)] #[validate(maximum = 10)] diff --git a/src/forms/stack/environment.rs b/src/forms/stack/environment.rs index 9b6e88d..071d159 100644 --- a/src/forms/stack/environment.rs +++ b/src/forms/stack/environment.rs @@ -1,7 +1,12 @@ use serde::{Deserialize, Serialize}; -use std::collections::HashMap; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Environment { - pub(crate) environment: Option>>, + pub(crate) environment: Option>, } +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct EnvVar { + pub(crate) key: String, + pub(crate) value: String, +} + diff --git a/src/forms/stack/payload.rs b/src/forms/stack/payload.rs index 70be841..ddcd927 100644 --- a/src/forms/stack/payload.rs +++ b/src/forms/stack/payload.rs @@ -27,15 +27,16 @@ pub struct Payload { pub subscriptions: Option>, pub form_app: Option>, pub disk_type: Option, - #[serde(rename = "save_token")] pub save_token: bool, - #[serde(rename = "cloud_token")] - pub cloud_token: String, + pub cloud_token: Option, + pub cloud_key: Option, + pub cloud_secret: Option, pub provider: String, pub stack_code: String, #[serde(rename = "selected_plan")] pub selected_plan: String, - pub custom: forms::stack::Custom, + pub custom: Custom, + pub docker_compose: Option>, } impl TryFrom<&models::Stack> for Payload { diff --git a/src/forms/stack/port.rs b/src/forms/stack/port.rs index a6e77d2..0251d90 100644 --- a/src/forms/stack/port.rs +++ b/src/forms/stack/port.rs @@ -1,12 +1,18 @@ use serde::{Deserialize, Serialize}; use docker_compose_types as dctypes; +use serde_valid::Validate; -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Port { + #[validate(custom(|v| validate_non_empty(v)))] pub host_port: Option, - pub container_port: Option, + #[validate(pattern = r"^\d{2,6}+$")] + pub container_port: String, + #[validate(enumerate("tcp", "udp"))] + pub protocol: Option, } + // impl Default for Port{ // fn default() -> Self { // Port { diff --git a/src/forms/stack/requirements.rs b/src/forms/stack/requirements.rs index 02e6891..402f80d 100644 --- a/src/forms/stack/requirements.rs +++ b/src/forms/stack/requirements.rs @@ -5,16 +5,16 @@ use serde_valid::Validate; pub struct Requirements { #[validate(min_length = 1)] #[validate(max_length = 10)] - #[validate(pattern = r"^\d+\.?[0-9]+$")] + #[validate(pattern = r"^[0-9]*\.?[0-9]+$")] pub cpu: Option, #[validate(min_length = 1)] #[validate(max_length = 10)] - #[validate(pattern = r"^\d+G$")] + #[validate(pattern = r"^[0-9]*\.?[0-9]+Gb?$")] #[serde(rename = "disk_size")] pub disk_size: Option, #[serde(rename = "ram_size")] #[validate(min_length = 1)] #[validate(max_length = 10)] - #[validate(pattern = r"^\d+G$")] + #[validate(pattern = r"^[0-9]*\.?[0-9]+Gb?$")] pub ram_size: Option, } diff --git a/src/forms/stack1.rs b/src/forms/stack1.rs new file mode 100644 index 0000000..22555fe --- /dev/null +++ b/src/forms/stack1.rs @@ -0,0 +1,462 @@ +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use serde_valid::Validate; +use std::fmt; +use indexmap::IndexMap; +use regex::Regex; +use crate::helpers::dockerhub::DockerHub; +use crate::helpers::stack::dctypes::SingleValue; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct Role { + pub role: Option>, +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct Requirements { + #[validate(min_length = 1)] + #[validate(max_length = 10)] + #[validate(pattern = r"^[0-9]*\.?[0-9]+$")] + pub cpu: Option, + #[validate(min_length = 1)] + #[validate(max_length = 10)] + #[validate(pattern = r"^[0-9]*\.?[0-9]+Gb?$")] + #[serde(rename = "disk_size")] + pub disk_size: Option, + #[serde(rename = "ram_size")] + #[validate(min_length = 1)] + #[validate(max_length = 10)] + #[validate(pattern = r"^[0-9]*\.?[0-9]+Gb?$")] + pub ram_size: Option, +} + +fn validate_non_empty(v: &Option) -> Result<(), serde_valid::validation::Error> { + if v.is_none() { + return Ok(()); + } + + if let Some(value) = v { + if value.is_empty() { + return Ok(()); + } + + // #[validate(pattern = r"^\d{2,6}+$")] + let re = Regex::new(r"^\d{2,6}+$").unwrap(); + + if !re.is_match(value.as_str()) { + return Err(serde_valid::validation::Error::Custom("Port is not valid.".to_owned())); + } + } + + Ok(()) +} + +#[derive(Validate)] +struct Data { + val: i32, +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct Port { + #[validate(custom(|v| validate_non_empty(v)))] + pub host_port: Option, + #[validate(pattern = r"^\d{2,6}+$")] + pub container_port: String, + #[validate(enumerate("tcp", "udp"))] + pub protocol: Option, +} + + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct DockerImage { + // #[validate(min_length = 3)] + #[validate(max_length = 50)] + // @todo conditional check, if not empty + // #[validate(pattern = r"^[a-z0-9]+([-_.][a-z0-9]+)*$")] + pub dockerhub_user: Option, + // #[validate(min_length = 3)] + #[validate(max_length = 50)] + // @todo conditional check, if not empty + // #[validate(pattern = r"^[a-z0-9]+([-_.][a-z0-9]+)*$")] + pub dockerhub_name: Option, + // #[validate(min_length = 3)] + #[validate(max_length = 100)] + pub dockerhub_image: Option, + pub dockerhub_password: Option, +} + +impl fmt::Display for DockerImage { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let dh_image = self.dockerhub_image.as_ref().map(String::as_str).unwrap_or(""); + let dh_nmspc = self.dockerhub_user.as_ref().map(String::as_str).unwrap_or(""); + let dh_name = self.dockerhub_name.as_ref().map(String::as_str).unwrap_or(""); + + write!( + f, + "{}{}{}", + if !dh_nmspc.is_empty() { format!("{}/", dh_nmspc) } else { String::new() }, + if !dh_name.is_empty() { dh_name } else { dh_image }, + if !dh_name.contains(":") && dh_image.is_empty() { ":latest".to_string() } else { String::new() }, + ) + } +} + + +impl DockerImage { + #[tracing::instrument(name = "is_active")] + pub async fn is_active(&self) -> Result { + DockerHub::from(self).is_active().await + } +} + + +impl AsRef for App { + fn as_ref(&self) -> &DockerImage { + &self.docker_image + } +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct StackForm { + #[validate(max_length = 255)] + #[serde(rename = "commonDomain")] + pub common_domain: Option, + pub domain_list: Option, + #[validate(min_length = 2)] + #[validate(max_length = 255)] + pub stack_code: Option, + #[validate(min_length = 2)] + #[validate(max_length = 50)] + pub region: String, + #[validate(min_length = 1)] + #[validate(max_length = 50)] + pub zone: Option, + #[validate(min_length = 2)] + #[validate(max_length = 50)] + pub server: String, + #[validate(min_length = 2)] + #[validate(max_length = 50)] + pub os: String, + #[validate(min_length = 3)] + #[validate(max_length = 50)] + pub ssl: String, + pub vars: Option>, + pub integrated_features: Option>, + pub extended_features: Option>, + pub subscriptions: Option>, + pub form_app: Option>, + #[validate(min_length = 3)] + #[validate(max_length = 50)] + pub disk_type: Option, + pub save_token: bool, + #[validate(max_length = 255)] + pub cloud_token: Option, + #[validate(max_length = 255)] + pub cloud_key: Option, + #[validate(max_length = 255)] + pub cloud_secret: Option, + #[validate(min_length = 2)] + #[validate(max_length = 50)] + pub provider: String, + #[validate(min_length = 3)] + #[validate(max_length = 50)] + pub selected_plan: String, + #[validate] + pub custom: Custom, +} + +impl StackForm { + pub async fn is_readable_docker_image(&self) -> Result { + let mut is_active = true; + for app in &self.custom.web { + if !app.app.docker_image.is_active().await? { + is_active = false; + break; + } + } + + // temporarily disabled + // if let Some(service) = &self.custom.service { + // for app in service { + // if !app.app.docker_image.is_active().await? { + // is_active = false; + // break; + // } + // } + // } + // + // if let Some(features) = &self.custom.feature { + // for app in features { + // if !app.app.docker_image.is_active().await? { + // is_active = false; + // break; + // } + // } + // } + Ok(is_active) + } +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +#[serde(rename_all = "snake_case")] +pub struct StackPayload { + pub(crate) id: Option, + pub(crate) user_token: Option, + pub(crate) user_email: Option, + #[serde(rename = "commonDomain")] + pub common_domain: String, + pub domain_list: Option, + pub region: String, + pub zone: Option, + pub server: String, + pub os: String, + pub ssl: String, + pub vars: Option>, + #[serde(rename = "integrated_features")] + pub integrated_features: Option>, + #[serde(rename = "extended_features")] + pub extended_features: Option>, + pub subscriptions: Option>, + pub form_app: Option>, + pub disk_type: Option, + pub save_token: bool, + pub cloud_token: Option, + pub cloud_key: Option, + pub cloud_secret: Option, + pub provider: String, + pub stack_code: String, + #[serde(rename = "selected_plan")] + pub selected_plan: String, + pub custom: Custom, + pub docker_compose: Option>, +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct DomainList {} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Var {} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Price { + pub value: f64, +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct Custom { + #[validate] + pub web: Vec, + #[validate] + pub feature: Option>, + #[validate] + pub service: Option>, + #[validate(minimum = 0)] + #[validate(maximum = 10)] + pub servers_count: u32, + #[validate(min_length = 3)] + #[validate(max_length = 50)] + pub custom_stack_code: String, + #[validate(min_length = 3)] + #[validate(max_length = 255)] + pub project_git_url: Option, + pub custom_stack_category: Option>, + pub custom_stack_short_description: Option, + pub custom_stack_description: Option, + #[validate(min_length = 3)] + #[validate(max_length = 255)] + pub project_name: String, + pub project_overview: Option, + pub project_description: Option, + #[serde(flatten)] + pub networks: ComposeNetworks, // all networks +} + + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct App { + #[serde(rename = "_etag")] + #[validate(min_length = 3)] + #[validate(max_length = 255)] + pub etag: Option, + #[serde(rename = "_id")] + pub id: String, + #[serde(rename = "_created")] + pub created: Option, + #[serde(rename = "_updated")] + pub updated: Option, + #[validate(min_length = 3)] + #[validate(max_length = 50)] + pub name: String, + #[validate(min_length = 3)] + #[validate(max_length = 50)] + pub code: String, + #[validate(min_length = 3)] + #[validate(max_length = 50)] + #[serde(rename = "type")] + pub type_field: String, + #[serde(flatten)] + pub role: Role, + pub default: Option, + pub versions: Option>, + #[serde(flatten)] + #[validate] + pub docker_image: DockerImage, + #[serde(flatten)] + #[validate] + pub requirements: Requirements, + #[validate(minimum = 1)] + pub popularity: Option, + pub commercial: Option, + pub subscription: Option, + pub autodeploy: Option, + pub suggested: Option, + pub dependency: Option, + pub avoid_render: Option, + pub price: Option, + pub icon: Option, + pub domain: Option, + pub category_id: Option, + pub parent_app_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub descr: Option, + pub full_description: Option, + pub description: Option, + pub plan_type: Option, + pub ansible_var: Option, + pub repo_dir: Option, + pub url_app: Option, + pub url_git: Option, + #[validate(enumerate("always", "no", "unless-stopped", "on-failure"))] + pub restart: String, + pub volumes: Option>, + #[serde(flatten)] + pub environment: Environment, + #[serde(flatten)] + pub network: ServiceNetworks, + #[validate] + pub shared_ports: Option>, +} + + + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Volume { + pub host_path: Option, + pub container_path: Option, +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Volumes { + volumes: Vec, +} + +// pub(crate) type Networks = Option>; +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ServiceNetworks { + pub network: Option>, +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct NetworkDriver { + // not implemented +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct Network { + pub(crate) id: String, + pub(crate) attachable: Option, + pub(crate) driver: Option, + pub(crate) driver_opts: Option, + pub(crate) enable_ipv6: Option, + pub(crate) internal: Option, + pub(crate) external: Option, + pub(crate) ipam: Option, + pub(crate) labels: Option, + pub(crate) name: String, +} + +impl Default for Network { + fn default() -> Self { + // The case when we need at least one external network to be preconfigured + Network { + id: "default_network".to_string(), + attachable: None, + driver: None, + driver_opts: Default::default(), + enable_ipv6: None, + internal: None, + external: Some(true), + ipam: None, + labels: None, + name: "default_network".to_string(), + } + } +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ComposeNetworks { + pub networks: Option>, +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct Web { + #[serde(flatten)] + #[validate] + pub app: App, + pub custom: Option, + pub main: Option, +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct Feature { + #[serde(flatten)] + #[validate] + pub app: App, +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct Service { + #[serde(flatten)] + #[validate] + pub(crate) app: App, +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Icon { + pub light: IconLight, + pub dark: IconDark, +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct IconLight { + pub width: i64, + pub height: i64, + pub image: String, +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct IconDark {} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct Version { + #[serde(rename = "_etag")] + pub etag: Option, + #[serde(rename = "_id")] + pub id: u32, + #[serde(rename = "_created")] + pub created: Option, + #[serde(rename = "_updated")] + pub updated: Option, + pub app_id: Option, + pub name: String, + #[validate(min_length = 3)] + #[validate(max_length = 20)] + pub version: String, + #[serde(rename = "update_status")] + pub update_status: Option, + #[validate(min_length = 3)] + #[validate(max_length = 20)] + pub tag: String, +} diff --git a/src/helpers/json.rs b/src/helpers/json.rs index 952d768..ee209c1 100644 --- a/src/helpers/json.rs +++ b/src/helpers/json.rs @@ -74,6 +74,10 @@ where ErrorBadRequest(self.set_msg(msg).to_string()) } + pub(crate) fn form_error(self, msg: String) -> Error { + ErrorBadRequest(msg) + } + pub(crate) fn not_found>(self, msg: I) -> Error { ErrorNotFound(self.set_msg(msg).to_string()) } diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs index 653c7ad..712ca5a 100644 --- a/src/routes/stack/add.rs +++ b/src/routes/stack/add.rs @@ -25,7 +25,7 @@ pub async fn add( let form = body_into_form(body).await?; let stack_name = form.custom.custom_stack_code.clone(); - check_if_stack_exists(pg_pool.get_ref(), &stack_name).await?; + stack_exists(pg_pool.get_ref(), &stack_name).await?; let body: Value = serde_json::to_value::(form) .or(serde_json::to_value::(forms::stack::Stack::default())) @@ -40,8 +40,9 @@ pub async fn add( }) } -async fn check_if_stack_exists(pg_pool: &PgPool, stack_name: &String) -> Result<(), Error> { - db::stack::fetch_one_by_name(pg_pool, stack_name) + +async fn stack_exists(pool: &PgPool, stack_name: &String) -> Result<(), Error> { + db::stack::fetch_one_by_name(pool, stack_name) .await .map_err(|_| { JsonResponse::::build().internal_server_error("Internal Server Error") @@ -65,11 +66,11 @@ async fn body_into_form(body: Bytes) -> Result { }) .and_then(|form: forms::stack::Stack| { if !form.validate().is_ok() { - let errors = form.validate().unwrap_err(); - let err_msg = format!("Invalid data received {:?}", &errors.to_string()); + let errors = form.validate().unwrap_err().to_string(); + let err_msg = format!("Invalid data received {:?}", &errors); tracing::debug!(err_msg); - return Err(JsonResponse::::build().bad_request(errors.to_string())); + return Err(JsonResponse::::build().form_error(errors)); } Ok(form) diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs index 71d459f..e372853 100644 --- a/src/routes/stack/deploy.rs +++ b/src/routes/stack/deploy.rs @@ -8,6 +8,8 @@ use actix_web::{post, web, web::Data, Responder, Result}; use lapin::publisher_confirm::Confirmation; use sqlx::PgPool; use std::sync::Arc; +use crate::helpers::compressor::compress; + #[tracing::instrument(name = "Deploy for every user. Admin endpoint")] #[post("/{id}/deploy")] @@ -29,7 +31,7 @@ pub async fn add( let id = stack.id.clone(); let dc = DcBuilder::new(stack); - dc.build().map_err(|err| { + let fc = dc.build().map_err(|err| { JsonResponse::::build().internal_server_error(err) })?; @@ -37,6 +39,8 @@ pub async fn add( .map_err(|err| JsonResponse::::build().bad_request(err))?; stack_data.user_token = Some(user.id.clone()); stack_data.user_email = Some(user.email.clone()); + let compressed = fc.unwrap_or("".to_string()); + stack_data.docker_compose = Some(compress(compressed.as_str())); mq_manager .publish_and_confirm( diff --git a/src/routes/stack/update.rs b/src/routes/stack/update.rs index ba4d728..46ad014 100644 --- a/src/routes/stack/update.rs +++ b/src/routes/stack/update.rs @@ -24,7 +24,7 @@ pub async fn update( .map_err(|err| JsonResponse::::build().internal_server_error(err)) .and_then(|stack| match stack { Some(stack) => Ok(stack), - None => Err(JsonResponse::::build().not_found("not found")), + None => Err(JsonResponse::::build().not_found("Object not found")), })?; let stack_name = form.custom.custom_stack_code.clone(); @@ -32,7 +32,7 @@ pub async fn update( let user_id = user.id.clone(); if let Err(errors) = form.validate() { - return Err(JsonResponse::::build().bad_request(errors.to_string())); + return Err(JsonResponse::::build().form_error(errors.unwrap_err().to_string())); } let form_inner = form.into_inner(); diff --git a/src/routes/test/deploy.rs b/src/routes/test/deploy.rs index f123417..4f36a3a 100644 --- a/src/routes/test/deploy.rs +++ b/src/routes/test/deploy.rs @@ -1,8 +1,15 @@ use crate::models::Client; use actix_web::{post, web, Responder, Result}; +use serde::Serialize; use std::sync::Arc; use crate::helpers::JsonResponse; +#[derive(Serialize)] +struct DeployResponse { + status: String, + client: Arc, +} + #[tracing::instrument(name = "Test deploy.")] #[post("/deploy")] pub async fn handler(client: web::ReqData>) -> Result { From b5574055984e144fe3cafbe24072fa5602c1da1b Mon Sep 17 00:00:00 2001 From: vsilent Date: Sun, 25 Feb 2024 09:46:04 +0200 Subject: [PATCH 184/284] brotli compressor from issue-16 --- Cargo.lock | 1 + Cargo.toml | 1 + src/forms/stack/payload.rs | 2 +- src/helpers/compressor.rs | 20 ++++++++++++++++++++ src/helpers/mod.rs | 2 ++ src/routes/stack/deploy.rs | 4 ++-- src/routes/stack/update.rs | 2 +- 7 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 src/helpers/compressor.rs diff --git a/Cargo.lock b/Cargo.lock index df244b2..0ea5e67 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3442,6 +3442,7 @@ dependencies = [ "actix-http", "actix-web", "actix-web-httpauth", + "brotli", "chrono", "clap", "config", diff --git a/Cargo.toml b/Cargo.toml index 4642533..f817a30 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,6 +54,7 @@ serde_yaml = "0.9" lapin = { version = "2.3.1", features = ["serde_json"] } futures-lite = "1.13.0" clap = { version = "4.4.8", features = ["derive"] } +brotli = "3.4.0" serde_path_to_error = "0.1.14" deadpool-lapin = "0.11.0" docker-compose-types = "0.7.0" diff --git a/src/forms/stack/payload.rs b/src/forms/stack/payload.rs index ddcd927..f89b3c6 100644 --- a/src/forms/stack/payload.rs +++ b/src/forms/stack/payload.rs @@ -35,7 +35,7 @@ pub struct Payload { pub stack_code: String, #[serde(rename = "selected_plan")] pub selected_plan: String, - pub custom: Custom, + pub custom: forms::stack::Custom, pub docker_compose: Option>, } diff --git a/src/helpers/compressor.rs b/src/helpers/compressor.rs new file mode 100644 index 0000000..624747d --- /dev/null +++ b/src/helpers/compressor.rs @@ -0,0 +1,20 @@ +use brotli::{CompressorWriter, Decompressor}; +use std::io::{Read, Write}; + +pub fn compress(input: &str) -> Vec { + let mut compressed = Vec::new(); + let mut compressor = CompressorWriter::new( + &mut compressed, 4096, 11, 22 + ); + compressor.write_all(input.as_bytes()).unwrap(); + compressor.flush().unwrap(); + drop(compressor); + compressed +} + +pub fn decompress(input: &[u8]) -> String { + let mut decompressed = String::new(); + let mut decompressor = Decompressor::new(input, 4096); + decompressor.read_to_string(&mut decompressed).unwrap(); + decompressed +} \ No newline at end of file diff --git a/src/helpers/mod.rs b/src/helpers/mod.rs index ad70535..17f75f1 100644 --- a/src/helpers/mod.rs +++ b/src/helpers/mod.rs @@ -6,4 +6,6 @@ pub(crate) mod stack; pub use json::*; pub use mq_manager::MqManager; pub mod dockerhub; +pub(crate) mod compressor; + pub use dockerhub::*; diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs index e372853..a2bf869 100644 --- a/src/routes/stack/deploy.rs +++ b/src/routes/stack/deploy.rs @@ -39,8 +39,8 @@ pub async fn add( .map_err(|err| JsonResponse::::build().bad_request(err))?; stack_data.user_token = Some(user.id.clone()); stack_data.user_email = Some(user.email.clone()); - let compressed = fc.unwrap_or("".to_string()); - stack_data.docker_compose = Some(compress(compressed.as_str())); + // let compressed = fc.unwrap_or("".to_string()); + stack_data.docker_compose = Some(compress(fc.as_str())); mq_manager .publish_and_confirm( diff --git a/src/routes/stack/update.rs b/src/routes/stack/update.rs index 46ad014..ef11d82 100644 --- a/src/routes/stack/update.rs +++ b/src/routes/stack/update.rs @@ -32,7 +32,7 @@ pub async fn update( let user_id = user.id.clone(); if let Err(errors) = form.validate() { - return Err(JsonResponse::::build().form_error(errors.unwrap_err().to_string())); + return Err(JsonResponse::::build().form_error(errors.to_string())); } let form_inner = form.into_inner(); From c9b25fc9b70d471c2be116073d5b5fbc7b086400 Mon Sep 17 00:00:00 2001 From: vsilent Date: Sun, 25 Feb 2024 09:54:32 +0200 Subject: [PATCH 185/284] validate --- src/forms/stack/app.rs | 5 +++-- src/forms/stack/custom.rs | 3 +-- src/forms/stack/web.rs | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/forms/stack/app.rs b/src/forms/stack/app.rs index 1eedd6b..93529a3 100644 --- a/src/forms/stack/app.rs +++ b/src/forms/stack/app.rs @@ -132,15 +132,16 @@ impl App { }; let mut envs = IndexMap::new(); - for item in self.environment.environment.clone().unwrap_or_default() { + for item in self.environment.environment.clone() { let items = item .into_iter() - .map(|(k, v)| (k, Some(dctypes::SingleValue::String(v.clone())))) + .map(|env_var| (env_var.key, Some(dctypes::SingleValue::String(env_var.value.clone())))) .collect::>(); envs.extend(items); } + service.ports = dctypes::Ports::Long(ports); service.restart = Some("always".to_owned()); service.volumes = volumes; diff --git a/src/forms/stack/custom.rs b/src/forms/stack/custom.rs index b127a12..4e6bd87 100644 --- a/src/forms/stack/custom.rs +++ b/src/forms/stack/custom.rs @@ -1,10 +1,9 @@ use serde::{Deserialize, Serialize}; -use serde_json::Value; -use serde_valid::Validate; use crate::forms; use indexmap::IndexMap; use docker_compose_types as dctypes; use crate::forms::stack::Network; +use serde_valid::Validate; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Custom { diff --git a/src/forms/stack/web.rs b/src/forms/stack/web.rs index 776ea0a..4bef9bd 100644 --- a/src/forms/stack/web.rs +++ b/src/forms/stack/web.rs @@ -1,7 +1,8 @@ use serde::{Deserialize, Serialize}; +use serde_valid::Validate; use crate::forms::stack::*; -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Web { #[serde(flatten)] pub app: App, From bca14b99c46f7d22f833bee6b40a0335e74ab0fa Mon Sep 17 00:00:00 2001 From: vsilent Date: Sun, 25 Feb 2024 09:56:59 +0200 Subject: [PATCH 186/284] validate --- src/forms/stack/feature.rs | 3 +- src/forms/stack1.rs | 462 ------------------------------------- 2 files changed, 2 insertions(+), 463 deletions(-) delete mode 100644 src/forms/stack1.rs diff --git a/src/forms/stack/feature.rs b/src/forms/stack/feature.rs index 8e5908c..147aa03 100644 --- a/src/forms/stack/feature.rs +++ b/src/forms/stack/feature.rs @@ -1,7 +1,8 @@ use serde::{Deserialize, Serialize}; +use serde_valid::Validate; use crate::forms::stack::*; -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Feature { // #[serde(rename(deserialize = "sharedPorts"))] // #[serde(rename(serialize = "shared_ports"))] diff --git a/src/forms/stack1.rs b/src/forms/stack1.rs deleted file mode 100644 index 22555fe..0000000 --- a/src/forms/stack1.rs +++ /dev/null @@ -1,462 +0,0 @@ -use serde::{Deserialize, Serialize}; -use serde_json::Value; -use serde_valid::Validate; -use std::fmt; -use indexmap::IndexMap; -use regex::Regex; -use crate::helpers::dockerhub::DockerHub; -use crate::helpers::stack::dctypes::SingleValue; - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Role { - pub role: Option>, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Requirements { - #[validate(min_length = 1)] - #[validate(max_length = 10)] - #[validate(pattern = r"^[0-9]*\.?[0-9]+$")] - pub cpu: Option, - #[validate(min_length = 1)] - #[validate(max_length = 10)] - #[validate(pattern = r"^[0-9]*\.?[0-9]+Gb?$")] - #[serde(rename = "disk_size")] - pub disk_size: Option, - #[serde(rename = "ram_size")] - #[validate(min_length = 1)] - #[validate(max_length = 10)] - #[validate(pattern = r"^[0-9]*\.?[0-9]+Gb?$")] - pub ram_size: Option, -} - -fn validate_non_empty(v: &Option) -> Result<(), serde_valid::validation::Error> { - if v.is_none() { - return Ok(()); - } - - if let Some(value) = v { - if value.is_empty() { - return Ok(()); - } - - // #[validate(pattern = r"^\d{2,6}+$")] - let re = Regex::new(r"^\d{2,6}+$").unwrap(); - - if !re.is_match(value.as_str()) { - return Err(serde_valid::validation::Error::Custom("Port is not valid.".to_owned())); - } - } - - Ok(()) -} - -#[derive(Validate)] -struct Data { - val: i32, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Port { - #[validate(custom(|v| validate_non_empty(v)))] - pub host_port: Option, - #[validate(pattern = r"^\d{2,6}+$")] - pub container_port: String, - #[validate(enumerate("tcp", "udp"))] - pub protocol: Option, -} - - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct DockerImage { - // #[validate(min_length = 3)] - #[validate(max_length = 50)] - // @todo conditional check, if not empty - // #[validate(pattern = r"^[a-z0-9]+([-_.][a-z0-9]+)*$")] - pub dockerhub_user: Option, - // #[validate(min_length = 3)] - #[validate(max_length = 50)] - // @todo conditional check, if not empty - // #[validate(pattern = r"^[a-z0-9]+([-_.][a-z0-9]+)*$")] - pub dockerhub_name: Option, - // #[validate(min_length = 3)] - #[validate(max_length = 100)] - pub dockerhub_image: Option, - pub dockerhub_password: Option, -} - -impl fmt::Display for DockerImage { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let dh_image = self.dockerhub_image.as_ref().map(String::as_str).unwrap_or(""); - let dh_nmspc = self.dockerhub_user.as_ref().map(String::as_str).unwrap_or(""); - let dh_name = self.dockerhub_name.as_ref().map(String::as_str).unwrap_or(""); - - write!( - f, - "{}{}{}", - if !dh_nmspc.is_empty() { format!("{}/", dh_nmspc) } else { String::new() }, - if !dh_name.is_empty() { dh_name } else { dh_image }, - if !dh_name.contains(":") && dh_image.is_empty() { ":latest".to_string() } else { String::new() }, - ) - } -} - - -impl DockerImage { - #[tracing::instrument(name = "is_active")] - pub async fn is_active(&self) -> Result { - DockerHub::from(self).is_active().await - } -} - - -impl AsRef for App { - fn as_ref(&self) -> &DockerImage { - &self.docker_image - } -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct StackForm { - #[validate(max_length = 255)] - #[serde(rename = "commonDomain")] - pub common_domain: Option, - pub domain_list: Option, - #[validate(min_length = 2)] - #[validate(max_length = 255)] - pub stack_code: Option, - #[validate(min_length = 2)] - #[validate(max_length = 50)] - pub region: String, - #[validate(min_length = 1)] - #[validate(max_length = 50)] - pub zone: Option, - #[validate(min_length = 2)] - #[validate(max_length = 50)] - pub server: String, - #[validate(min_length = 2)] - #[validate(max_length = 50)] - pub os: String, - #[validate(min_length = 3)] - #[validate(max_length = 50)] - pub ssl: String, - pub vars: Option>, - pub integrated_features: Option>, - pub extended_features: Option>, - pub subscriptions: Option>, - pub form_app: Option>, - #[validate(min_length = 3)] - #[validate(max_length = 50)] - pub disk_type: Option, - pub save_token: bool, - #[validate(max_length = 255)] - pub cloud_token: Option, - #[validate(max_length = 255)] - pub cloud_key: Option, - #[validate(max_length = 255)] - pub cloud_secret: Option, - #[validate(min_length = 2)] - #[validate(max_length = 50)] - pub provider: String, - #[validate(min_length = 3)] - #[validate(max_length = 50)] - pub selected_plan: String, - #[validate] - pub custom: Custom, -} - -impl StackForm { - pub async fn is_readable_docker_image(&self) -> Result { - let mut is_active = true; - for app in &self.custom.web { - if !app.app.docker_image.is_active().await? { - is_active = false; - break; - } - } - - // temporarily disabled - // if let Some(service) = &self.custom.service { - // for app in service { - // if !app.app.docker_image.is_active().await? { - // is_active = false; - // break; - // } - // } - // } - // - // if let Some(features) = &self.custom.feature { - // for app in features { - // if !app.app.docker_image.is_active().await? { - // is_active = false; - // break; - // } - // } - // } - Ok(is_active) - } -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -#[serde(rename_all = "snake_case")] -pub struct StackPayload { - pub(crate) id: Option, - pub(crate) user_token: Option, - pub(crate) user_email: Option, - #[serde(rename = "commonDomain")] - pub common_domain: String, - pub domain_list: Option, - pub region: String, - pub zone: Option, - pub server: String, - pub os: String, - pub ssl: String, - pub vars: Option>, - #[serde(rename = "integrated_features")] - pub integrated_features: Option>, - #[serde(rename = "extended_features")] - pub extended_features: Option>, - pub subscriptions: Option>, - pub form_app: Option>, - pub disk_type: Option, - pub save_token: bool, - pub cloud_token: Option, - pub cloud_key: Option, - pub cloud_secret: Option, - pub provider: String, - pub stack_code: String, - #[serde(rename = "selected_plan")] - pub selected_plan: String, - pub custom: Custom, - pub docker_compose: Option>, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct DomainList {} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct Var {} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Price { - pub value: f64, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Custom { - #[validate] - pub web: Vec, - #[validate] - pub feature: Option>, - #[validate] - pub service: Option>, - #[validate(minimum = 0)] - #[validate(maximum = 10)] - pub servers_count: u32, - #[validate(min_length = 3)] - #[validate(max_length = 50)] - pub custom_stack_code: String, - #[validate(min_length = 3)] - #[validate(max_length = 255)] - pub project_git_url: Option, - pub custom_stack_category: Option>, - pub custom_stack_short_description: Option, - pub custom_stack_description: Option, - #[validate(min_length = 3)] - #[validate(max_length = 255)] - pub project_name: String, - pub project_overview: Option, - pub project_description: Option, - #[serde(flatten)] - pub networks: ComposeNetworks, // all networks -} - - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct App { - #[serde(rename = "_etag")] - #[validate(min_length = 3)] - #[validate(max_length = 255)] - pub etag: Option, - #[serde(rename = "_id")] - pub id: String, - #[serde(rename = "_created")] - pub created: Option, - #[serde(rename = "_updated")] - pub updated: Option, - #[validate(min_length = 3)] - #[validate(max_length = 50)] - pub name: String, - #[validate(min_length = 3)] - #[validate(max_length = 50)] - pub code: String, - #[validate(min_length = 3)] - #[validate(max_length = 50)] - #[serde(rename = "type")] - pub type_field: String, - #[serde(flatten)] - pub role: Role, - pub default: Option, - pub versions: Option>, - #[serde(flatten)] - #[validate] - pub docker_image: DockerImage, - #[serde(flatten)] - #[validate] - pub requirements: Requirements, - #[validate(minimum = 1)] - pub popularity: Option, - pub commercial: Option, - pub subscription: Option, - pub autodeploy: Option, - pub suggested: Option, - pub dependency: Option, - pub avoid_render: Option, - pub price: Option, - pub icon: Option, - pub domain: Option, - pub category_id: Option, - pub parent_app_id: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub descr: Option, - pub full_description: Option, - pub description: Option, - pub plan_type: Option, - pub ansible_var: Option, - pub repo_dir: Option, - pub url_app: Option, - pub url_git: Option, - #[validate(enumerate("always", "no", "unless-stopped", "on-failure"))] - pub restart: String, - pub volumes: Option>, - #[serde(flatten)] - pub environment: Environment, - #[serde(flatten)] - pub network: ServiceNetworks, - #[validate] - pub shared_ports: Option>, -} - - - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Volume { - pub host_path: Option, - pub container_path: Option, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Volumes { - volumes: Vec, -} - -// pub(crate) type Networks = Option>; -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct ServiceNetworks { - pub network: Option>, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct NetworkDriver { - // not implemented -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Network { - pub(crate) id: String, - pub(crate) attachable: Option, - pub(crate) driver: Option, - pub(crate) driver_opts: Option, - pub(crate) enable_ipv6: Option, - pub(crate) internal: Option, - pub(crate) external: Option, - pub(crate) ipam: Option, - pub(crate) labels: Option, - pub(crate) name: String, -} - -impl Default for Network { - fn default() -> Self { - // The case when we need at least one external network to be preconfigured - Network { - id: "default_network".to_string(), - attachable: None, - driver: None, - driver_opts: Default::default(), - enable_ipv6: None, - internal: None, - external: Some(true), - ipam: None, - labels: None, - name: "default_network".to_string(), - } - } -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct ComposeNetworks { - pub networks: Option>, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Web { - #[serde(flatten)] - #[validate] - pub app: App, - pub custom: Option, - pub main: Option, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Feature { - #[serde(flatten)] - #[validate] - pub app: App, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Service { - #[serde(flatten)] - #[validate] - pub(crate) app: App, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Icon { - pub light: IconLight, - pub dark: IconDark, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct IconLight { - pub width: i64, - pub height: i64, - pub image: String, -} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct IconDark {} - -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Version { - #[serde(rename = "_etag")] - pub etag: Option, - #[serde(rename = "_id")] - pub id: u32, - #[serde(rename = "_created")] - pub created: Option, - #[serde(rename = "_updated")] - pub updated: Option, - pub app_id: Option, - pub name: String, - #[validate(min_length = 3)] - #[validate(max_length = 20)] - pub version: String, - #[serde(rename = "update_status")] - pub update_status: Option, - #[validate(min_length = 3)] - #[validate(max_length = 20)] - pub tag: String, -} From de24ab9a7cd1ed94ebd6ea72e81b65bb93d3c013 Mon Sep 17 00:00:00 2001 From: vsilent Date: Sun, 25 Feb 2024 09:59:20 +0200 Subject: [PATCH 187/284] validate_non_empty added --- src/forms/stack/port.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/forms/stack/port.rs b/src/forms/stack/port.rs index 0251d90..5fa5c38 100644 --- a/src/forms/stack/port.rs +++ b/src/forms/stack/port.rs @@ -1,5 +1,6 @@ use serde::{Deserialize, Serialize}; use docker_compose_types as dctypes; +use regex::Regex; use serde_valid::Validate; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] @@ -12,6 +13,27 @@ pub struct Port { pub protocol: Option, } +fn validate_non_empty(v: &Option) -> Result<(), serde_valid::validation::Error> { + if v.is_none() { + return Ok(()); + } + + if let Some(value) = v { + if value.is_empty() { + return Ok(()); + } + + let re = Regex::new(r"^\d{2,6}$").unwrap(); + + if !re.is_match(value.as_str()) { + return Err(serde_valid::validation::Error::Custom("Port is not valid.".to_owned())); + } + } + + Ok(()) +} + + // impl Default for Port{ // fn default() -> Self { From 5bfda15fffc746a90d51bda4aac4a974ddb9cd12 Mon Sep 17 00:00:00 2001 From: vsilent Date: Sun, 25 Feb 2024 10:06:48 +0200 Subject: [PATCH 188/284] TryInto fix --- src/forms/stack/port.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/forms/stack/port.rs b/src/forms/stack/port.rs index 5fa5c38..4da0c49 100644 --- a/src/forms/stack/port.rs +++ b/src/forms/stack/port.rs @@ -50,11 +50,10 @@ fn validate_non_empty(v: &Option) -> Result<(), serde_valid::validation: impl TryInto for &Port { type Error = String; fn try_into(self) -> Result { - let cp = self - .container_port - .as_ref() - .map_or(Ok(0u16), |s| s.parse::()) - .map_err(|_| "Could not parse container port".to_string())?; + let cp = self.container_port + .clone() + .parse::() + .map_err(|err| "Could not parse container port".to_string() )?; let hp = match self.host_port.clone() { Some(hp) => { From 40cfee23f3ba03b1b8f62bd11a05cc55108e5abd Mon Sep 17 00:00:00 2001 From: vsilent Date: Sun, 25 Feb 2024 18:14:53 +0200 Subject: [PATCH 189/284] field main is removed --- src/forms/stack/web.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/forms/stack/web.rs b/src/forms/stack/web.rs index 4bef9bd..87e70cf 100644 --- a/src/forms/stack/web.rs +++ b/src/forms/stack/web.rs @@ -7,5 +7,4 @@ pub struct Web { #[serde(flatten)] pub app: App, pub custom: Option, - pub main: bool, } From 4f31021953a0dec292902f9b1d3acdbb5f57918b Mon Sep 17 00:00:00 2001 From: vsilent Date: Wed, 28 Feb 2024 10:17:35 +0200 Subject: [PATCH 190/284] DockerImage fmt logic from issue-16 --- src/forms/rating.rs | 6 +-- src/forms/stack/docker_image.rs | 17 ++++---- src/helpers/dockerhub.rs | 71 ++++++++++++++------------------- 3 files changed, 41 insertions(+), 53 deletions(-) diff --git a/src/forms/rating.rs b/src/forms/rating.rs index d7a4bd7..04b9b6b 100644 --- a/src/forms/rating.rs +++ b/src/forms/rating.rs @@ -15,12 +15,12 @@ pub struct Rating { impl Into for Rating { fn into(self) -> models::Rating { - let mut rating = models::Rating::default(); + let mut rating = models::Rating::default(); rating.obj_id = self.obj_id; rating.category = self.category.into(); //todo change the type of category field to the RateCategory - rating.hidden = Some(false); + rating.hidden = Some(false); rating.rate = Some(self.rate); - rating.comment = self.comment; + rating.comment = self.comment; rating } diff --git a/src/forms/stack/docker_image.rs b/src/forms/stack/docker_image.rs index 85a335a..e9737d0 100644 --- a/src/forms/stack/docker_image.rs +++ b/src/forms/stack/docker_image.rs @@ -24,21 +24,20 @@ pub struct DockerImage { impl fmt::Display for DockerImage { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let tag = "latest"; + let dh_image = self.dockerhub_image.as_ref().map(String::as_str).unwrap_or(""); + let dh_nmspc = self.dockerhub_user.as_ref().map(String::as_str).unwrap_or(""); + let dh_name = self.dockerhub_name.as_ref().map(String::as_str).unwrap_or(""); - let dim = self.dockerhub_image.clone().unwrap_or("".to_string()); write!( f, - "{}/{}:{}", - self.dockerhub_user - .clone() - .unwrap_or("trydirect".to_string()) - .clone(), - self.dockerhub_name.clone().unwrap_or(dim), - tag + "{}{}{}", + if !dh_nmspc.is_empty() { format!("{}/", dh_nmspc) } else { String::new() }, + if !dh_name.is_empty() { dh_name } else { dh_image }, + if !dh_name.contains(":") && dh_image.is_empty() { ":latest".to_string() } else { String::new() }, ) } } + impl DockerImage { #[tracing::instrument(name = "is_active")] pub async fn is_active(&self) -> Result { diff --git a/src/helpers/dockerhub.rs b/src/helpers/dockerhub.rs index a4af31c..e3f1720 100644 --- a/src/helpers/dockerhub.rs +++ b/src/helpers/dockerhub.rs @@ -1,19 +1,18 @@ +use crate::forms::stack::DockerImage; use reqwest::RequestBuilder; use serde_derive::{Deserialize, Serialize}; -use serde_valid::Validate; use serde_json::Value; -use crate::forms::stack::DockerImage; - +use serde_valid::Validate; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct DockerHubToken { - pub token: Option + pub token: Option, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct DockerHubCreds<'a> { pub(crate) username: &'a str, - pub(crate) password: &'a str + pub(crate) password: &'a str, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] @@ -48,14 +47,14 @@ struct Tag { tag_last_pulled: Option, tag_last_pushed: Option, tag_status: String, - v2: bool + v2: bool, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] struct TagResult { pub count: Option, next: Option, previous: Option, - results: Vec + results: Vec, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] @@ -92,7 +91,6 @@ pub struct DockerHub<'a> { } impl<'a> DockerHub<'a> { - pub async fn login(&'a self) -> Result { let endpoint = "https://hub.docker.com/v2/users/login"; @@ -128,9 +126,10 @@ impl<'a> DockerHub<'a> { tracing::debug!("Get public image repositories response {:?}", repositories); if repositories.count.unwrap_or(0) > 0 { // let's find at least one active tag - let active = repositories.results + let active = repositories + .results .into_iter() - .any(|mut repo| repo.status == 1 ); + .any(|repo| repo.status == 1); active } else { false @@ -139,9 +138,10 @@ impl<'a> DockerHub<'a> { } pub async fn lookup_private_repo(&self) -> Result { - let url = format!("https://hub.docker.com/v2/namespaces/{}/repositories/{}/tags", - &self.creds.username, - &self.repos); + let url = format!( + "https://hub.docker.com/v2/namespaces/{}/repositories/{}/tags", + &self.creds.username, &self.repos + ); tracing::debug!("Validate image {:?}", url); let client = reqwest::Client::new() .get(url) @@ -161,9 +161,10 @@ impl<'a> DockerHub<'a> { tracing::debug!("Validate private image response {:?}", tags); if tags.count.unwrap_or(0) > 0 { // let's find at least one active tag - let active = tags.results + let active = tags + .results .into_iter() - .any(|tag| tag.tag_status.contains("active") ); + .any(|tag| tag.tag_status.contains("active")); active } else { false @@ -171,66 +172,54 @@ impl<'a> DockerHub<'a> { }) } pub async fn is_active(&'a self) -> Result { - // if namespace/user is not set change endpoint and return a different response if self.creds.username.is_empty() { match self.lookup_public_repo().await { - Ok(result) => Ok(result), - Err(_e) => Ok(false) + Ok(result) => Ok(result), + Err(_e) => Ok(false), } - } else{ + } else { match self.lookup_private_repo().await { Ok(result) => Ok(result), - Err(_e) => Ok(false) + Err(_e) => Ok(false), } } } pub async fn set_token(&self, mut client: RequestBuilder) -> Result { - if self.creds.password.is_empty() { tracing::debug!("Password is empty. Image should be public"); return Ok(client); - } else{ - + } else { } tracing::debug!("Password is set. Login.."); let token = self.login().await?; match token.token { - None => { - Ok(client) - }, - Some(token) => { - Ok(client.bearer_auth(token)) - } + None => Ok(client), + Some(token) => Ok(client.bearer_auth(token)), } } } -impl<'a> From <&'a DockerImage> for DockerHub<'a> { - +impl<'a> From<&'a DockerImage> for DockerHub<'a> { fn from(image: &'a DockerImage) -> Self { let username = match image.dockerhub_user { - Some(ref username) => { - username - }, - None => "" + Some(ref username) => username, + None => "", }; let password = match image.dockerhub_password { - Some(ref password) => { - password - }, - None => "" + Some(ref password) => password, + None => "", }; DockerHub { creds: DockerHubCreds { username: username, - password: password + password: password, }, repos: image.dockerhub_name.clone().unwrap_or("".to_string()), image: format!("{}", image), } } -} \ No newline at end of file +} From 441549c0d7ba931713b9ef364ba1e648325f4246 Mon Sep 17 00:00:00 2001 From: vsilent Date: Wed, 28 Feb 2024 13:00:43 +0200 Subject: [PATCH 191/284] custom role for any custom stack --- docker-compose.yml | 2 +- src/forms/stack/feature.rs | 1 + src/forms/stack/service.rs | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 9a66dde..467836e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,7 @@ volumes: services: stacker: - image: trydirect/stacker:0.0.6 + image: trydirect/stacker:0.0.7 build: . container_name: stacker restart: always diff --git a/src/forms/stack/feature.rs b/src/forms/stack/feature.rs index 147aa03..b6d0cbc 100644 --- a/src/forms/stack/feature.rs +++ b/src/forms/stack/feature.rs @@ -10,4 +10,5 @@ pub struct Feature { // pub shared_ports: Option>, #[serde(flatten)] pub app: App, + pub custom: Option, } diff --git a/src/forms/stack/service.rs b/src/forms/stack/service.rs index 1470233..5aea4a8 100644 --- a/src/forms/stack/service.rs +++ b/src/forms/stack/service.rs @@ -10,4 +10,5 @@ pub struct Service { // pub shared_ports: Option>, #[serde(flatten)] pub(crate) app: App, + pub custom: Option, } From 046425cb5d3315bebbcc24634b43597ab972f8b4 Mon Sep 17 00:00:00 2001 From: petru Date: Wed, 28 Feb 2024 17:09:36 +0200 Subject: [PATCH 192/284] 30-access-policies --- src/routes/client/enable.rs | 5 +++-- src/startup.rs | 6 ++++++ tests/middleware_trydirect.rs | 4 ---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/routes/client/enable.rs b/src/routes/client/enable.rs index ca36451..c390a4e 100644 --- a/src/routes/client/enable.rs +++ b/src/routes/client/enable.rs @@ -1,6 +1,6 @@ use crate::configuration::Settings; use crate::db; -use crate::helpers::client; +use crate::helpers; use crate::helpers::JsonResponse; use crate::models; use actix_web::{put, web, Responder, Result}; @@ -16,6 +16,7 @@ pub async fn enable_handler( pg_pool: web::Data, path: web::Path<(i32,)>, ) -> Result { + println!("user.id {}", user.id); //todo the owner //todo add admin endpoint let client_id = path.0; @@ -28,7 +29,7 @@ pub async fn enable_handler( return Err(JsonResponse::::build().bad_request("client is already active")); } - client.secret = client::generate_secret(pg_pool.get_ref(), 255) + client.secret = helpers::client::generate_secret(pg_pool.get_ref(), 255) .await .map(|secret| Some(secret)) .map_err(|err| JsonResponse::::build().bad_request(err))?; diff --git a/src/startup.rs b/src/startup.rs index 5e57dc8..5f0b30b 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -41,6 +41,12 @@ pub async fn run( .service(routes::client::enable_handler) .service(routes::client::disable_handler), ) + /* + .service( + web::scope("/admin/client") + .service(routes::client::admin_enable_handler) + ) + */ .service( web::scope("/test").service(routes::test::deploy::handler), ) diff --git a/tests/middleware_trydirect.rs b/tests/middleware_trydirect.rs index 0590618..4937781 100644 --- a/tests/middleware_trydirect.rs +++ b/tests/middleware_trydirect.rs @@ -22,8 +22,4 @@ async fn middleware_trydirect_works() { assert!(response.status().is_success()); assert_eq!(Some(0), response.content_length()); - - - //todo header stacker-id not found - // } From 5a510846c1e445a125115fdcdb736255b3dd06bc Mon Sep 17 00:00:00 2001 From: vsilent Date: Thu, 29 Feb 2024 14:30:39 +0200 Subject: [PATCH 193/284] refactoring. renamed user_stack with project, cloud and server endpoins --- README.md | 10 +- ...230903063840_creating_rating_tables.up.sql | 2 +- ...30905145525_creating_stack_tables.down.sql | 2 +- ...0230905145525_creating_stack_tables.up.sql | 9 +- ...240228125751_creating_deployments.down.sql | 2 + ...20240228125751_creating_deployments.up.sql | 14 ++ .../20240229072555_creating_cloud.down.sql | 2 + .../20240229072555_creating_cloud.up.sql | 14 ++ ...reating_user_stack_cloud_relation.down.sql | 2 + ..._creating_user_stack_cloud_relation.up.sql | 3 + ...40229080559_creating_cloud_server.down.sql | 3 + ...0240229080559_creating_cloud_server.up.sql | 22 ++ ...eating_user_stack_server_relation.down.sql | 2 + ...creating_user_stack_server_relation.up.sql | 2 + src/db/cloud.rs | 120 +++++++++++ src/db/deployment.rs | 68 ++++++ src/db/mod.rs | 5 +- src/db/project.rs | 194 ++++++++++++++++++ src/db/server.rs | 152 ++++++++++++++ src/db/stack.rs | 140 ------------- src/forms/cloud.rs | 34 +++ src/forms/mod.rs | 4 +- src/forms/{stack => project}/app.rs | 26 +-- .../{stack => project}/compose_networks.rs | 4 +- src/forms/{stack => project}/custom.rs | 16 +- src/forms/{stack => project}/docker_image.rs | 0 src/forms/{stack => project}/domain_list.rs | 0 src/forms/{stack => project}/environment.rs | 0 src/forms/{stack => project}/feature.rs | 2 +- src/forms/{stack => project}/form.rs | 39 +--- src/forms/{stack => project}/icon.rs | 2 +- src/forms/{stack => project}/icon_dark.rs | 0 src/forms/{stack => project}/icon_light.rs | 0 src/forms/{stack => project}/mod.rs | 0 src/forms/{stack => project}/network.rs | 4 +- .../{stack => project}/network_driver.rs | 0 src/forms/{stack => project}/payload.rs | 32 ++- src/forms/{stack => project}/port.rs | 0 src/forms/{stack => project}/price.rs | 0 src/forms/{stack => project}/requirements.rs | 0 src/forms/{stack => project}/role.rs | 0 src/forms/{stack => project}/service.rs | 2 +- .../{stack => project}/service_networks.rs | 2 +- src/forms/{stack => project}/var.rs | 0 src/forms/{stack => project}/version.rs | 0 src/forms/{stack => project}/volume.rs | 4 +- src/forms/{stack => project}/volumes.rs | 2 +- src/forms/{stack => project}/web.rs | 2 +- src/forms/server.rs | 36 ++++ src/helpers/dockerhub.rs | 2 +- src/helpers/mod.rs | 2 +- src/helpers/{stack => project}/builder.rs | 14 +- .../{stack => project}/builder_config.rs | 0 .../dctypes/advanced_build_step.rs | 2 +- .../dctypes/advanced_network_settings.rs | 0 .../dctypes/advanced_networks.rs | 2 +- .../{stack => project}/dctypes/build_args.rs | 0 .../{stack => project}/dctypes/build_step.rs | 2 +- .../{stack => project}/dctypes/compose.rs | 2 +- .../dctypes/compose_file.rs | 2 +- .../dctypes/compose_network.rs | 2 +- .../compose_network_setting_details.rs | 0 .../dctypes/compose_networks.rs | 2 +- .../dctypes/compose_volume.rs | 5 +- .../dctypes/depends_condition.rs | 0 .../dctypes/depends_on_options.rs | 2 +- .../{stack => project}/dctypes/env_file.rs | 0 .../{stack => project}/dctypes/environment.rs | 2 +- .../{stack => project}/dctypes/extension.rs | 2 +- .../dctypes/extension_parse_error.rs | 0 .../dctypes/external_network_setting_bool.rs | 0 .../dctypes/external_volume.rs | 0 .../{stack => project}/dctypes/ipam.rs | 2 +- .../{stack => project}/dctypes/ipam_config.rs | 0 .../{stack => project}/dctypes/labels.rs | 0 .../dctypes/logging_parameters.rs | 2 +- src/helpers/{stack => project}/dctypes/mod.rs | 2 +- .../dctypes/network_settings.rs | 2 +- .../{stack => project}/dctypes/networks.rs | 2 +- .../{stack => project}/dctypes/port.rs | 4 +- .../{stack => project}/dctypes/ports.rs | 2 +- .../dctypes/published_port.rs | 0 .../{stack => project}/dctypes/service.rs | 2 +- .../{stack => project}/dctypes/services.rs | 2 +- .../dctypes/single_service.rs | 2 +- .../{stack => project}/dctypes/sys_ctls.rs | 2 +- .../{stack => project}/dctypes/tmpfs.rs | 0 .../dctypes/top_level_volumes.rs | 2 +- .../{stack => project}/dctypes/ulimit.rs | 0 .../{stack => project}/dctypes/ulimits.rs | 2 +- src/helpers/{stack => project}/mod.rs | 0 src/models/cloud.rs | 15 ++ src/models/deployment.rs | 38 ++++ src/models/mod.rs | 10 +- src/models/product.rs | 6 +- src/models/{stack.rs => project.rs} | 14 +- src/models/ratecategory.rs | 2 +- src/models/server.rs | 28 +++ src/routes/cloud/add.rs | 50 +++++ src/routes/cloud/get.rs | 46 +++++ src/routes/cloud/mod.rs | 7 + .../{stack/service.rs => cloud/update.rs} | 0 src/routes/mod.rs | 7 +- src/routes/project/add.rs | 78 +++++++ src/routes/{stack => project}/compose.rs | 34 +-- src/routes/project/delete.rs | 33 +++ src/routes/project/deploy.rs | 79 +++++++ src/routes/project/get.rs | 47 +++++ src/routes/{stack => project}/mod.rs | 1 + .../stack.rs => routes/project/service.rs} | 0 src/routes/project/update.rs | 65 ++++++ src/routes/server/add.rs | 50 +++++ src/routes/server/get.rs | 46 +++++ src/routes/server/mod.rs | 5 + src/routes/stack/add.rs | 78 ------- src/routes/stack/deploy.rs | 58 ------ src/routes/stack/get.rs | 48 ----- src/routes/stack/update.rs | 65 ------ src/services/mod.rs | 2 +- src/services/project.rs | 0 src/services/rating.rs | 6 +- src/startup.rs | 36 +++- tests/dockerhub.rs | 18 +- tests/model_user_stack.rs | 18 +- 124 files changed, 1458 insertions(+), 582 deletions(-) create mode 100644 migrations/20240228125751_creating_deployments.down.sql create mode 100644 migrations/20240228125751_creating_deployments.up.sql create mode 100644 migrations/20240229072555_creating_cloud.down.sql create mode 100644 migrations/20240229072555_creating_cloud.up.sql create mode 100644 migrations/20240229075843_creating_user_stack_cloud_relation.down.sql create mode 100644 migrations/20240229075843_creating_user_stack_cloud_relation.up.sql create mode 100644 migrations/20240229080559_creating_cloud_server.down.sql create mode 100644 migrations/20240229080559_creating_cloud_server.up.sql create mode 100644 migrations/20240229083517_creating_user_stack_server_relation.down.sql create mode 100644 migrations/20240229083517_creating_user_stack_server_relation.up.sql create mode 100644 src/db/cloud.rs create mode 100644 src/db/deployment.rs create mode 100644 src/db/project.rs create mode 100644 src/db/server.rs delete mode 100644 src/db/stack.rs create mode 100644 src/forms/cloud.rs rename src/forms/{stack => project}/app.rs (87%) rename src/forms/{stack => project}/compose_networks.rs (94%) rename src/forms/{stack => project}/custom.rs (90%) rename src/forms/{stack => project}/docker_image.rs (100%) rename src/forms/{stack => project}/domain_list.rs (100%) rename src/forms/{stack => project}/environment.rs (100%) rename src/forms/{stack => project}/feature.rs (93%) rename src/forms/{stack => project}/form.rs (63%) rename src/forms/{stack => project}/icon.rs (85%) rename src/forms/{stack => project}/icon_dark.rs (100%) rename src/forms/{stack => project}/icon_light.rs (100%) rename src/forms/{stack => project}/mod.rs (100%) rename src/forms/{stack => project}/network.rs (96%) rename src/forms/{stack => project}/network_driver.rs (100%) rename src/forms/{stack => project}/payload.rs (55%) rename src/forms/{stack => project}/port.rs (100%) rename src/forms/{stack => project}/price.rs (100%) rename src/forms/{stack => project}/requirements.rs (100%) rename src/forms/{stack => project}/role.rs (100%) rename src/forms/{stack => project}/service.rs (93%) rename src/forms/{stack => project}/service_networks.rs (98%) rename src/forms/{stack => project}/var.rs (100%) rename src/forms/{stack => project}/version.rs (100%) rename src/forms/{stack => project}/volume.rs (95%) rename src/forms/{stack => project}/volumes.rs (83%) rename src/forms/{stack => project}/web.rs (88%) create mode 100644 src/forms/server.rs rename src/helpers/{stack => project}/builder.rs (81%) rename src/helpers/{stack => project}/builder_config.rs (100%) rename src/helpers/{stack => project}/dctypes/advanced_build_step.rs (95%) rename src/helpers/{stack => project}/dctypes/advanced_network_settings.rs (100%) rename src/helpers/{stack => project}/dctypes/advanced_networks.rs (92%) rename src/helpers/{stack => project}/dctypes/build_args.rs (100%) rename src/helpers/{stack => project}/dctypes/build_step.rs (84%) rename src/helpers/{stack => project}/dctypes/compose.rs (96%) rename src/helpers/{stack => project}/dctypes/compose_file.rs (92%) rename src/helpers/{stack => project}/dctypes/compose_network.rs (83%) rename src/helpers/{stack => project}/dctypes/compose_network_setting_details.rs (100%) rename src/helpers/{stack => project}/dctypes/compose_networks.rs (93%) rename src/helpers/{stack => project}/dctypes/compose_volume.rs (79%) rename src/helpers/{stack => project}/dctypes/depends_condition.rs (100%) rename src/helpers/{stack => project}/dctypes/depends_on_options.rs (95%) rename src/helpers/{stack => project}/dctypes/env_file.rs (100%) rename src/helpers/{stack => project}/dctypes/environment.rs (94%) rename src/helpers/{stack => project}/dctypes/extension.rs (94%) rename src/helpers/{stack => project}/dctypes/extension_parse_error.rs (100%) rename src/helpers/{stack => project}/dctypes/external_network_setting_bool.rs (100%) rename src/helpers/{stack => project}/dctypes/external_volume.rs (100%) rename src/helpers/{stack => project}/dctypes/ipam.rs (89%) rename src/helpers/{stack => project}/dctypes/ipam_config.rs (100%) rename src/helpers/{stack => project}/dctypes/labels.rs (100%) rename src/helpers/{stack => project}/dctypes/logging_parameters.rs (93%) rename src/helpers/{stack => project}/dctypes/mod.rs (99%) rename src/helpers/{stack => project}/dctypes/network_settings.rs (96%) rename src/helpers/{stack => project}/dctypes/networks.rs (92%) rename src/helpers/{stack => project}/dctypes/port.rs (94%) rename src/helpers/{stack => project}/dctypes/ports.rs (92%) rename src/helpers/{stack => project}/dctypes/published_port.rs (100%) rename src/helpers/{stack => project}/dctypes/service.rs (99%) rename src/helpers/{stack => project}/dctypes/services.rs (93%) rename src/helpers/{stack => project}/dctypes/single_service.rs (81%) rename src/helpers/{stack => project}/dctypes/sys_ctls.rs (94%) rename src/helpers/{stack => project}/dctypes/tmpfs.rs (100%) rename src/helpers/{stack => project}/dctypes/top_level_volumes.rs (93%) rename src/helpers/{stack => project}/dctypes/ulimit.rs (100%) rename src/helpers/{stack => project}/dctypes/ulimits.rs (93%) rename src/helpers/{stack => project}/mod.rs (100%) create mode 100644 src/models/cloud.rs create mode 100644 src/models/deployment.rs rename src/models/{stack.rs => project.rs} (79%) create mode 100644 src/models/server.rs create mode 100644 src/routes/cloud/add.rs create mode 100644 src/routes/cloud/get.rs create mode 100644 src/routes/cloud/mod.rs rename src/routes/{stack/service.rs => cloud/update.rs} (100%) create mode 100644 src/routes/project/add.rs rename src/routes/{stack => project}/compose.rs (50%) create mode 100644 src/routes/project/delete.rs create mode 100644 src/routes/project/deploy.rs create mode 100644 src/routes/project/get.rs rename src/routes/{stack => project}/mod.rs (92%) rename src/{services/stack.rs => routes/project/service.rs} (100%) create mode 100644 src/routes/project/update.rs create mode 100644 src/routes/server/add.rs create mode 100644 src/routes/server/get.rs create mode 100644 src/routes/server/mod.rs delete mode 100644 src/routes/stack/add.rs delete mode 100644 src/routes/stack/deploy.rs delete mode 100644 src/routes/stack/get.rs delete mode 100644 src/routes/stack/update.rs create mode 100644 src/services/project.rs diff --git a/README.md b/README.md index 53879ed..09f466f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Stacker - is an application that helps users to create custom IT solutions based on dockerized open -source apps and user's custom applications docker containers. Users can build their own stack of applications, and +source apps and user's custom applications docker containers. Users can build their own project of applications, and deploy the final result to their favorite clouds using TryDirect API. Application development will include: @@ -36,9 +36,9 @@ Stacker (API) - Serves API clients Authentication made through TryDirect OAuth, here we have only client Database (Read only) Logging/Tracing (Files) / Quickwit for future -/stack (WebUI, as a result we have a JSON) -/stack/deploy -> sends deploy command to TryDirect Install service -/stack/deploy/status - get installation progress (rabbitmq client), +/project (WebUI, as a result we have a JSON) +/project/deploy -> sends deploy command to TryDirect Install service +/project/deploy/status - get installation progress (rabbitmq client), #### TODO Find out how to get user's token for queue @@ -76,7 +76,7 @@ sqlx migrate revert #### Deploy ``` -curl -X POST -H "Content-Type: application/json" -d @custom-stack-payload-2.json http://127.0.0.1:8000/stack +curl -X POST -H "Content-Type: application/json" -d @custom-stack-payload-2.json http://127.0.0.1:8000/project ``` diff --git a/migrations/20230903063840_creating_rating_tables.up.sql b/migrations/20230903063840_creating_rating_tables.up.sql index 2842270..156c722 100644 --- a/migrations/20230903063840_creating_rating_tables.up.sql +++ b/migrations/20230903063840_creating_rating_tables.up.sql @@ -3,7 +3,7 @@ CREATE TYPE rate_category AS ENUM ( 'application', 'cloud', - 'stack', + 'project', 'deploymentSpeed', 'documentation', 'design', diff --git a/migrations/20230905145525_creating_stack_tables.down.sql b/migrations/20230905145525_creating_stack_tables.down.sql index 2f2a6e4..7f367df 100644 --- a/migrations/20230905145525_creating_stack_tables.down.sql +++ b/migrations/20230905145525_creating_stack_tables.down.sql @@ -1,2 +1,2 @@ -- Add down migration script here -DROP TABLE user_stack; +DROP TABLE project; diff --git a/migrations/20230905145525_creating_stack_tables.up.sql b/migrations/20230905145525_creating_stack_tables.up.sql index b20b2cd..333b27f 100644 --- a/migrations/20230905145525_creating_stack_tables.up.sql +++ b/migrations/20230905145525_creating_stack_tables.up.sql @@ -1,4 +1,4 @@ -CREATE TABLE user_stack ( +CREATE TABLE project ( id serial4 NOT NULL, stack_id uuid NOT NULL, user_id VARCHAR(50) NOT NULL, @@ -6,8 +6,9 @@ CREATE TABLE user_stack ( body JSON NOT NULL, created_at timestamptz NOT NULL, updated_at timestamptz NOT NULL, - CONSTRAINT user_stack_pkey PRIMARY KEY (id) + CONSTRAINT project_pkey PRIMARY KEY (id) ); -CREATE INDEX idx_stack_id ON user_stack(stack_id); -CREATE INDEX idx_stack_user_id ON user_stack(user_id); \ No newline at end of file +CREATE INDEX idx_project_stack_id ON project(stack_id); +CREATE INDEX idx_project_user_id ON project(user_id); +CREATE INDEX idx_project_name ON project(name); diff --git a/migrations/20240228125751_creating_deployments.down.sql b/migrations/20240228125751_creating_deployments.down.sql new file mode 100644 index 0000000..228cc13 --- /dev/null +++ b/migrations/20240228125751_creating_deployments.down.sql @@ -0,0 +1,2 @@ +-- Add up migration script here +DROP table deployment; \ No newline at end of file diff --git a/migrations/20240228125751_creating_deployments.up.sql b/migrations/20240228125751_creating_deployments.up.sql new file mode 100644 index 0000000..7a06d3b --- /dev/null +++ b/migrations/20240228125751_creating_deployments.up.sql @@ -0,0 +1,14 @@ +-- Add up migration script here +CREATE TABLE deployment ( + id serial4 NOT NULL, + project_id integer NOT NULL, + body JSON NOT NULL, + deleted BOOLEAN DEFAULT FALSE, + status VARCHAR(32) NOT NULL, + created_at timestamptz NOT NULL, + updated_at timestamptz NOT NULL, + CONSTRAINT fk_project FOREIGN KEY(project_id) REFERENCES project(id), + CONSTRAINT deployment_pkey PRIMARY KEY (id) +); + +CREATE INDEX idx_deployment_project_id ON deployment(project_id); diff --git a/migrations/20240229072555_creating_cloud.down.sql b/migrations/20240229072555_creating_cloud.down.sql new file mode 100644 index 0000000..2a04e92 --- /dev/null +++ b/migrations/20240229072555_creating_cloud.down.sql @@ -0,0 +1,2 @@ +-- Add down migration script here +DROP table cloud; diff --git a/migrations/20240229072555_creating_cloud.up.sql b/migrations/20240229072555_creating_cloud.up.sql new file mode 100644 index 0000000..c842d3f --- /dev/null +++ b/migrations/20240229072555_creating_cloud.up.sql @@ -0,0 +1,14 @@ +CREATE TABLE cloud ( + id serial4 NOT NULL, + user_id VARCHAR(50) NOT NULL, + provider VARCHAR(50) NOT NULL, + cloud_token VARCHAR(255) , + cloud_key VARCHAR(255), + cloud_secret VARCHAR(255), + save_token BOOLEAN DEFAULT FALSE, + created_at timestamptz NOT NULL, + updated_at timestamptz NOT NULL, + CONSTRAINT user_cloud_pkey PRIMARY KEY (id) +); + +CREATE INDEX idx_deployment_user_cloud_user_id ON cloud(user_id); \ No newline at end of file diff --git a/migrations/20240229075843_creating_user_stack_cloud_relation.down.sql b/migrations/20240229075843_creating_user_stack_cloud_relation.down.sql new file mode 100644 index 0000000..02d2fe5 --- /dev/null +++ b/migrations/20240229075843_creating_user_stack_cloud_relation.down.sql @@ -0,0 +1,2 @@ +-- Add down migration script here +ALTER table project DROP COLUMN cloud_id; \ No newline at end of file diff --git a/migrations/20240229075843_creating_user_stack_cloud_relation.up.sql b/migrations/20240229075843_creating_user_stack_cloud_relation.up.sql new file mode 100644 index 0000000..5f65c66 --- /dev/null +++ b/migrations/20240229075843_creating_user_stack_cloud_relation.up.sql @@ -0,0 +1,3 @@ +-- Add up migration script here +ALTER table project ADD COLUMN cloud_id INT CONSTRAINT project_cloud_id REFERENCES cloud(id) ON UPDATE CASCADE ON DELETE CASCADE; + diff --git a/migrations/20240229080559_creating_cloud_server.down.sql b/migrations/20240229080559_creating_cloud_server.down.sql new file mode 100644 index 0000000..f0fa982 --- /dev/null +++ b/migrations/20240229080559_creating_cloud_server.down.sql @@ -0,0 +1,3 @@ +DROP INDEX idx_server_user_id; +DROP INDEX idx_server_cloud_id; +DROP table server; diff --git a/migrations/20240229080559_creating_cloud_server.up.sql b/migrations/20240229080559_creating_cloud_server.up.sql new file mode 100644 index 0000000..091fb8f --- /dev/null +++ b/migrations/20240229080559_creating_cloud_server.up.sql @@ -0,0 +1,22 @@ +-- Add up migration script here + +CREATE TABLE server ( + id serial4 NOT NULL, + user_id VARCHAR(50) NOT NULL, + cloud_id integer NOT NULL, + project_id integer NOT NULL, + region VARCHAR(50) NOT NULL, + zone VARCHAR(50), + server VARCHAR(255) NOT NULL, + os VARCHAR(100) NOT NULL, + disk_type VARCHAR(100), + created_at timestamptz NOT NULL, + updated_at timestamptz NOT NULL, + CONSTRAINT user_server_pkey PRIMARY KEY (id), + CONSTRAINT fk_server FOREIGN KEY(cloud_id) REFERENCES cloud(id), + CONSTRAINT fk_server_project FOREIGN KEY(project_id) REFERENCES project(id) +); + +CREATE INDEX idx_server_user_id ON server(user_id); +CREATE INDEX idx_server_cloud_id ON server(cloud_id); +CREATE INDEX idx_server_project_id ON server(project_id); diff --git a/migrations/20240229083517_creating_user_stack_server_relation.down.sql b/migrations/20240229083517_creating_user_stack_server_relation.down.sql new file mode 100644 index 0000000..c410fff --- /dev/null +++ b/migrations/20240229083517_creating_user_stack_server_relation.down.sql @@ -0,0 +1,2 @@ +-- Add down migration script here +ALTER table server DROP COLUMN project_id; diff --git a/migrations/20240229083517_creating_user_stack_server_relation.up.sql b/migrations/20240229083517_creating_user_stack_server_relation.up.sql new file mode 100644 index 0000000..ab021b1 --- /dev/null +++ b/migrations/20240229083517_creating_user_stack_server_relation.up.sql @@ -0,0 +1,2 @@ +-- Add up migration script here +ALTER table server ADD COLUMN project_id integer CONSTRAINT project_id REFERENCES project(id) ON UPDATE CASCADE ON DELETE CASCADE; diff --git a/src/db/cloud.rs b/src/db/cloud.rs new file mode 100644 index 0000000..0385434 --- /dev/null +++ b/src/db/cloud.rs @@ -0,0 +1,120 @@ +use crate::models; +use sqlx::PgPool; +use tracing::Instrument; + +pub async fn fetch(pool: &PgPool, id: i32) -> Result, String> { + tracing::info!("Fetch cloud {}", id); + sqlx::query_as!( + models::Cloud, + r#"SELECT * FROM cloud WHERE id=$1 LIMIT 1 "#, id + ) + .fetch_one(pool) + .await + .map(|cloud| Some(cloud)) + .or_else(|err| match err { + sqlx::Error::RowNotFound => Ok(None), + e => { + tracing::error!("Failed to fetch cloud, error: {:?}", e); + Err("Could not fetch data".to_string()) + } + }) +} + +pub async fn fetch_by_user(pool: &PgPool, user_id: &str) -> Result, String> { + let query_span = tracing::info_span!("Fetch clouds by user id."); + sqlx::query_as!( + models::Cloud, + r#" + SELECT + * + FROM cloud + WHERE user_id=$1 + "#, + user_id + ) + .fetch_all(pool) + .instrument(query_span) + .await + .map_err(|err| { + tracing::error!("Failed to fetch cloud, error: {:?}", err); + "".to_string() + }) +} + + +pub async fn insert(pool: &PgPool, mut cloud: models::Cloud) -> Result { + let query_span = tracing::info_span!("Saving user's cloud data into the database"); + sqlx::query!( + r#" + INSERT INTO cloud ( + user_id, + provider, + cloud_token, + cloud_key, + cloud_secret, + save_token, + created_at, + updated_at) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8) + RETURNING id; + "#, + cloud.user_id, + cloud.provider, + cloud.cloud_token, + cloud.cloud_key, + cloud.cloud_secret, + cloud.save_token, + cloud.created_at, + cloud.updated_at, + ) + .fetch_one(pool) + .instrument(query_span) + .await + .map(move |result| { + cloud.id = result.id; + cloud + }) + .map_err(|e| { + tracing::error!("Failed to execute query: {:?}", e); + "Failed to insert".to_string() + }) +} + +pub async fn update(pool: &PgPool, mut cloud: models::Cloud) -> Result { + let query_span = tracing::info_span!("Updating user cloud"); + sqlx::query_as!( + models::Cloud, + r#" + UPDATE cloud + SET + user_id=$2, + provider=$3, + cloud_token=$4, + cloud_key=$5, + cloud_secret=$6, + created_at=$7, + updated_at=NOW() at time zone 'utc' + WHERE id = $1 + RETURNING * + "#, + cloud.id, + cloud.user_id, + cloud.provider, + cloud.cloud_token, + cloud.cloud_key, + cloud.cloud_secret, + cloud.created_at, + ) + .fetch_one(pool) + .instrument(query_span) + .await + .map(|result|{ + tracing::info!("Cloud info {} have been saved", cloud.id); + cloud.updated_at = result.updated_at; + cloud + }) + .map_err(|err| { + tracing::error!("Failed to execute query: {:?}", err); + "".to_string() + }) +} diff --git a/src/db/deployment.rs b/src/db/deployment.rs new file mode 100644 index 0000000..1a22f02 --- /dev/null +++ b/src/db/deployment.rs @@ -0,0 +1,68 @@ +use crate::models; +use sqlx::PgPool; +use tracing::Instrument; + +pub async fn insert(pool: &PgPool, mut deployment: models::Deployment) -> Result { + let query_span = tracing::info_span!("Saving new deployment into the database"); + sqlx::query!( + r#" + INSERT INTO deployment (project_id, deleted, status, body, created_at, updated_at) + VALUES ($1, $2, $3, $4, $5, $6) + RETURNING id; + "#, + deployment.project_id, + deployment.deleted, + deployment.status, + deployment.body, + deployment.created_at, + deployment.updated_at, + ) + .fetch_one(pool) + .instrument(query_span) + .await + .map(move |result| { + deployment.id = result.id; + deployment + }) + .map_err(|e| { + tracing::error!("Failed to execute query: {:?}", e); + "Failed to insert".to_string() + }) +} + +// pub async fn update(pool: &PgPool, mut deployment: models::Deployment) -> Result { +// let query_span = tracing::info_span!("Updating user deployment into the database"); +// sqlx::query_as!( +// models::Deployment, +// r#" +// UPDATE deployment +// SET +// project_id=$2, +// deleted=$3, +// status=$4, +// body=$5, +// created_at=$6, +// updated_at=NOW() at time zone 'utc' +// WHERE id = $1 +// RETURNING * +// "#, +// deployment.id, +// deployment.project_id, +// deployment.deleted, +// deployment.status, +// deployment.body, +// deployment.created_at, +// ) +// .fetch_one(pool) +// .instrument(query_span) +// .await +// .map(|result|{ +// tracing::info!("Deployment {} have been saved to database", deployment.id); +// deployment.updated_at = result.updated_at; +// deployment +// }) +// .map_err(|err| { +// tracing::error!("Failed to execute query: {:?}", err); +// "".to_string() +// }) +// } diff --git a/src/db/mod.rs b/src/db/mod.rs index a4fe3ae..3585327 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -1,4 +1,7 @@ pub mod client; pub mod product; pub mod rating; -pub mod stack; +pub mod project; +pub(crate) mod deployment; +pub(crate) mod cloud; +pub(crate) mod server; diff --git a/src/db/project.rs b/src/db/project.rs new file mode 100644 index 0000000..99a5d92 --- /dev/null +++ b/src/db/project.rs @@ -0,0 +1,194 @@ +use crate::models; +use sqlx::PgPool; +use sqlx::postgres::PgRow; +use tracing::Instrument; + +pub async fn fetch(pool: &PgPool, id: i32) -> Result, String> { + tracing::info!("Fetch project {}", id); + sqlx::query_as!( + models::Project, + r#" + SELECT + * + FROM project + WHERE id=$1 + LIMIT 1 + "#, + id + ) + .fetch_one(pool) + .await + .map(|project| Some(project)) + .or_else(|err| match err { + sqlx::Error::RowNotFound => Ok(None), + e => { + tracing::error!("Failed to fetch project, error: {:?}", e); + Err("Could not fetch data".to_string()) + } + }) +} + +pub async fn fetch_by_user(pool: &PgPool, user_id: &str) -> Result, String> { + let query_span = tracing::info_span!("Fetch projects by user id."); + sqlx::query_as!( + models::Project, + r#" + SELECT + * + FROM project + WHERE user_id=$1 + "#, + user_id + ) + .fetch_all(pool) + .instrument(query_span) + .await + .map_err(|err| { + tracing::error!("Failed to fetch project, error: {:?}", err); + "".to_string() + }) +} + +pub async fn fetch_one_by_name(pool: &PgPool, name: &str) -> Result, String> { + let query_span = tracing::info_span!("Fetch one project by name."); + sqlx::query_as!( + models::Project, + r#" + SELECT + * + FROM project + WHERE name=$1 + LIMIT 1 + "#, + name + ) + .fetch_one(pool) + .instrument(query_span) + .await + .map(|project| Some(project)) + .or_else(|err| match err { + sqlx::Error::RowNotFound => Ok(None), + err => { + tracing::error!("Failed to fetch one project by name, error: {:?}", err); + Err("".to_string()) + } + }) +} + +pub async fn insert(pool: &PgPool, mut project: models::Project) -> Result { + let query_span = tracing::info_span!("Saving new project into the database"); + sqlx::query!( + r#" + INSERT INTO project (stack_id, user_id, name, body, created_at, updated_at, cloud_id) + VALUES ($1, $2, $3, $4, $5, $6, $7) + RETURNING id; + "#, + project.stack_id, + project.user_id, + project.name, + project.body, + project.created_at, + project.updated_at, + project.cloud_id, + ) + .fetch_one(pool) + .instrument(query_span) + .await + .map(move |result| { + project.id = result.id; + project + }) + .map_err(|e| { + tracing::error!("Failed to execute query: {:?}", e); + "Failed to insert".to_string() + }) +} + +pub async fn update(pool: &PgPool, mut project: models::Project) -> Result { + let query_span = tracing::info_span!("Updating project"); + sqlx::query_as!( + models::Project, + r#" + UPDATE project + SET + stack_id=$2, + user_id=$3, + cloud_id=$4, + name=$5, + body=$6, + created_at=$7, + updated_at=NOW() at time zone 'utc' + WHERE id = $1 + RETURNING * + "#, + project.id, + project.stack_id, + project.user_id, + project.cloud_id, + project.name, + project.body, + project.created_at, + ) + .fetch_one(pool) + .instrument(query_span) + .await + .map(|result|{ + tracing::info!("Project {} have been saved to database", project.id); + project.updated_at = result.updated_at; + project + }) + .map_err(|err| { + tracing::error!("Failed to execute query: {:?}", err); + "".to_string() + }) +} + +pub async fn delete(pool: &PgPool, id: i32) -> Result, String> { + tracing::info!("Delete project {}", id); + let mut tx = pool.begin().await + .map(|result| result) + .map_err(|err| { + tracing::error!("Failed to execute query: {:?}", err); + "".to_string() + }).unwrap(); + + // delete records from deployment + // delete records from server + sqlx::query("DELETE FROM deployment where project_id=?") + .bind(id) + .execute(&mut *tx) + .await + .map(|result| result) + .map_err(|err| { + tracing::error!("Failed to execute query: {:?}", err); + "".to_string() + }).unwrap(); + + sqlx::query("DELETE FROM server where project_id=?") + .bind(id) + .execute(&mut *tx) + .await + .map(|result| result) + .map_err(|err| { + tracing::error!("Failed to execute query: {:?}", err); + "".to_string() + }).unwrap(); + + sqlx::query("DELETE FROM project where id=?") + .bind(id) + .execute(&mut *tx) + .await + .map(|result| result) + .map_err(|err| { + tracing::error!("Failed to execute query: {:?}", err); + "".to_string() + }).unwrap(); + + tx.commit().await; + + // tracing::error!("Failed to delete project, error: {:?}", e); + // Err("Could not fetch data".to_string()) + + Ok(None) +} + diff --git a/src/db/server.rs b/src/db/server.rs new file mode 100644 index 0000000..c471cf7 --- /dev/null +++ b/src/db/server.rs @@ -0,0 +1,152 @@ +use crate::models; +use sqlx::PgPool; +use tracing::Instrument; + +pub async fn fetch(pool: &PgPool, id: i32) -> Result, String> { + tracing::info!("Fetch server {}", id); + sqlx::query_as!( + models::Server, + r#"SELECT * FROM server WHERE id=$1 LIMIT 1 "#, id + ) + .fetch_one(pool) + .await + .map(|server| Some(server)) + .or_else(|err| match err { + sqlx::Error::RowNotFound => Ok(None), + e => { + tracing::error!("Failed to fetch server, error: {:?}", e); + Err("Could not fetch data".to_string()) + } + }) +} + +pub async fn fetch_by_user(pool: &PgPool, user_id: &str) -> Result, String> { + let query_span = tracing::info_span!("Fetch servers by user id."); + sqlx::query_as!( + models::Server, + r#" + SELECT + * + FROM server + WHERE user_id=$1 + "#, + user_id + ) + .fetch_all(pool) + .instrument(query_span) + .await + .map_err(|err| { + tracing::error!("Failed to fetch server, error: {:?}", err); + "".to_string() + }) +} + + +pub async fn fetch_by_project(pool: &PgPool, project_id: i32) -> Result, String> { + let query_span = tracing::info_span!("Fetch servers by project/project id."); + sqlx::query_as!( + models::Server, + r#" + SELECT + * + FROM server + WHERE project_id=$1 + "#, + project_id + ) + .fetch_all(pool) + .instrument(query_span) + .await + .map_err(|err| { + tracing::error!("Failed to fetch servers, error: {:?}", err); + "".to_string() + }) +} + + +pub async fn insert(pool: &PgPool, mut server: models::Server) -> Result { + let query_span = tracing::info_span!("Saving user's server data into the database"); + sqlx::query!( + r#" + INSERT INTO server ( + user_id, + cloud_id, + project_id, + region, + zone, + server, + os, + disk_type, + created_at, + updated_at) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) + RETURNING id; + "#, + server.user_id, + server.cloud_id, + server.project_id, + server.region, + server.zone, + server.server, + server.os, + server.disk_type, + server.created_at, + server.updated_at, + ) + .fetch_one(pool) + .instrument(query_span) + .await + .map(move |result| { + server.id = result.id; + server + }) + .map_err(|e| { + tracing::error!("Failed to execute query: {:?}", e); + "Failed to insert".to_string() + }) +} + +pub async fn update(pool: &PgPool, mut server: models::Server) -> Result { + let query_span = tracing::info_span!("Updating user server"); + sqlx::query_as!( + models::Server, + r#" + UPDATE server + SET + user_id=$2, + cloud_id=$3, + project_id=$4, + region=$5, + zone=$6, + server=$7, + os=$8, + disk_type=$9, + created_at=$10, + updated_at=NOW() at time zone 'utc' + WHERE id = $1 + RETURNING * + "#, + server.id, + server.user_id, + server.cloud_id, + server.project_id, + server.region, + server.zone, + server.server, + server.os, + server.disk_type, + server.created_at, + ) + .fetch_one(pool) + .instrument(query_span) + .await + .map(|result|{ + tracing::info!("Server info {} have been saved", server.id); + server.updated_at = result.updated_at; + server + }) + .map_err(|err| { + tracing::error!("Failed to execute query: {:?}", err); + "".to_string() + }) +} diff --git a/src/db/stack.rs b/src/db/stack.rs deleted file mode 100644 index def7a36..0000000 --- a/src/db/stack.rs +++ /dev/null @@ -1,140 +0,0 @@ -use crate::models; -use sqlx::PgPool; -use tracing::Instrument; - -pub async fn fetch(pool: &PgPool, id: i32) -> Result, String> { - tracing::info!("Fecth stack {}", id); - sqlx::query_as!( - models::Stack, - r#" - SELECT - * - FROM user_stack - WHERE id=$1 - LIMIT 1 - "#, - id - ) - .fetch_one(pool) - .await - .map(|stack| Some(stack)) - .or_else(|err| match err { - sqlx::Error::RowNotFound => Ok(None), - e => { - tracing::error!("Failed to fetch stack, error: {:?}", e); - Err("Could not fetch data".to_string()) - } - }) -} - -pub async fn fetch_by_user(pool: &PgPool, user_id: &str) -> Result, String> { - let query_span = tracing::info_span!("Fetch stacks by user id."); - sqlx::query_as!( - models::Stack, - r#" - SELECT - * - FROM user_stack - WHERE user_id=$1 - "#, - user_id - ) - .fetch_all(pool) - .instrument(query_span) - .await - .map_err(|err| { - tracing::error!("Failed to fetch stack, error: {:?}", err); - "".to_string() - }) -} - -pub async fn fetch_one_by_name(pool: &PgPool, name: &str) -> Result, String> { - let query_span = tracing::info_span!("Fetch one stack by name."); - sqlx::query_as!( - models::Stack, - r#" - SELECT - * - FROM user_stack - WHERE name=$1 - LIMIT 1 - "#, - name - ) - .fetch_one(pool) - .instrument(query_span) - .await - .map(|stack| Some(stack)) - .or_else(|err| match err { - sqlx::Error::RowNotFound => Ok(None), - err => { - tracing::error!("Failed to fetch one stack by name, error: {:?}", err); - Err("".to_string()) - } - }) -} - -pub async fn insert(pool: &PgPool, mut stack: models::Stack) -> Result { - let query_span = tracing::info_span!("Saving new stack into the database"); - sqlx::query!( - r#" - INSERT INTO user_stack (stack_id, user_id, name, body, created_at, updated_at) - VALUES ($1, $2, $3, $4, $5, $6) - RETURNING id; - "#, - stack.stack_id, - stack.user_id, - stack.name, - stack.body, - stack.created_at, - stack.updated_at, - ) - .fetch_one(pool) - .instrument(query_span) - .await - .map(move |result| { - stack.id = result.id; - stack - }) - .map_err(|e| { - tracing::error!("Failed to execute query: {:?}", e); - "Failed to insert".to_string() - }) -} - -pub async fn update(pool: &PgPool, mut stack: models::Stack) -> Result { - let query_span = tracing::info_span!("Updating user stack into the database"); - sqlx::query_as!( - models::Stack, - r#" - UPDATE user_stack - SET - stack_id=$2, - user_id=$3, - name=$4, - body=$5, - created_at=$6, - updated_at=NOW() at time zone 'utc' - WHERE id = $1 - RETURNING * - "#, - stack.id, - stack.stack_id, - stack.user_id, - stack.name, - stack.body, - stack.created_at, - ) - .fetch_one(pool) - .instrument(query_span) - .await - .map(|result|{ - tracing::info!("Stack {} have been saved to database", stack.id); - stack.updated_at = result.updated_at; - stack - }) - .map_err(|err| { - tracing::error!("Failed to execute query: {:?}", err); - "".to_string() - }) -} diff --git a/src/forms/cloud.rs b/src/forms/cloud.rs new file mode 100644 index 0000000..e742952 --- /dev/null +++ b/src/forms/cloud.rs @@ -0,0 +1,34 @@ +use crate::models; +use serde::{Deserialize, Serialize}; +use serde_valid::Validate; +use chrono::{DateTime, Utc}; + +#[derive(Serialize, Deserialize, Debug, Validate)] +pub struct Cloud { + pub id: i32, + pub user_id: String, + #[validate(min_length = 2)] + #[validate(max_length = 50)] + pub provider: String, + pub cloud_token: Option, + pub cloud_key: Option, + pub cloud_secret: Option, + pub save_token: Option, + pub created_at: DateTime, + pub updated_at: DateTime, +} + +impl Into for Cloud { + fn into(self) -> models::Cloud { + let mut cloud = models::Cloud::default(); + cloud.user_id = self.user_id; + cloud.provider = self.provider; + cloud.cloud_token = Some(String::from("")); + cloud.cloud_key = Some(String::from("")); + cloud.cloud_secret = Some(String::from("")); + cloud.created_at = Utc::now(); + cloud.updated_at = Utc::now(); + + cloud + } +} diff --git a/src/forms/mod.rs b/src/forms/mod.rs index 9647ea6..f152263 100644 --- a/src/forms/mod.rs +++ b/src/forms/mod.rs @@ -1,5 +1,7 @@ mod rating; -pub mod stack; +pub mod project; pub mod user; +pub(crate) mod cloud; +pub(crate) mod server; pub use rating::*; diff --git a/src/forms/stack/app.rs b/src/forms/project/app.rs similarity index 87% rename from src/forms/stack/app.rs rename to src/forms/project/app.rs index 93529a3..64598e6 100644 --- a/src/forms/stack/app.rs +++ b/src/forms/project/app.rs @@ -4,8 +4,8 @@ use indexmap::IndexMap; use serde_json::Value; use serde::{Deserialize, Serialize}; use serde_valid::Validate; -use crate::forms::stack::network::Network; -use crate::forms::stack::{DockerImage, replace_id_with_name}; +use crate::forms::project::network::Network; +use crate::forms::project::{DockerImage, replace_id_with_name}; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct App { @@ -30,15 +30,15 @@ pub struct App { #[serde(rename = "type")] pub type_field: String, #[serde(flatten)] - pub role: forms::stack::Role, + pub role: forms::project::Role, pub default: Option, - pub versions: Option>, + pub versions: Option>, #[serde(flatten)] #[validate] pub docker_image: DockerImage, #[serde(flatten)] #[validate] - pub requirements: forms::stack::Requirements, + pub requirements: forms::project::Requirements, #[validate(minimum = 1)] pub popularity: Option, pub commercial: Option, @@ -47,8 +47,8 @@ pub struct App { pub suggested: Option, pub dependency: Option, pub avoid_render: Option, - pub price: Option, - pub icon: Option, + pub price: Option, + pub icon: Option, pub domain: Option, pub category_id: Option, pub parent_app_id: Option, @@ -63,13 +63,13 @@ pub struct App { pub url_git: Option, #[validate(enumerate("always", "no", "unless-stopped", "on-failure"))] pub restart: String, - pub volumes: Option>, + pub volumes: Option>, #[serde(flatten)] - pub environment: forms::stack::Environment, + pub environment: forms::project::Environment, #[serde(flatten)] - pub network: forms::stack::ServiceNetworks, + pub network: forms::project::ServiceNetworks, #[validate] - pub shared_ports: Option>, + pub shared_ports: Option>, } impl App { @@ -151,8 +151,8 @@ impl App { } } -impl AsRef for App { - fn as_ref(&self) -> &forms::stack::DockerImage { +impl AsRef for App { + fn as_ref(&self) -> &forms::project::DockerImage { &self.docker_image } } diff --git a/src/forms/stack/compose_networks.rs b/src/forms/project/compose_networks.rs similarity index 94% rename from src/forms/stack/compose_networks.rs rename to src/forms/project/compose_networks.rs index afbd6f8..bb45a36 100644 --- a/src/forms/stack/compose_networks.rs +++ b/src/forms/project/compose_networks.rs @@ -1,8 +1,8 @@ use serde::{Deserialize, Serialize}; use docker_compose_types as dctypes; use indexmap::IndexMap; -use crate::forms::stack; -use crate::forms::stack::network::Network; +use crate::forms::project; +use crate::forms::project::network::Network; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct ComposeNetworks { diff --git a/src/forms/stack/custom.rs b/src/forms/project/custom.rs similarity index 90% rename from src/forms/stack/custom.rs rename to src/forms/project/custom.rs index 4e6bd87..8be69cc 100644 --- a/src/forms/stack/custom.rs +++ b/src/forms/project/custom.rs @@ -2,17 +2,17 @@ use serde::{Deserialize, Serialize}; use crate::forms; use indexmap::IndexMap; use docker_compose_types as dctypes; -use crate::forms::stack::Network; +use crate::forms::project::Network; use serde_valid::Validate; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Custom { #[validate] - pub web: Vec, + pub web: Vec, #[validate] - pub feature: Option>, + pub feature: Option>, #[validate] - pub service: Option>, + pub service: Option>, #[validate(minimum = 0)] #[validate(maximum = 10)] pub servers_count: u32, @@ -25,13 +25,13 @@ pub struct Custom { pub custom_stack_category: Option>, pub custom_stack_short_description: Option, pub custom_stack_description: Option, - #[validate(min_length = 3)] - #[validate(max_length = 255)] - pub project_name: String, + // #[validate(min_length = 3)] + // #[validate(max_length = 255)] + pub project_name: Option, pub project_overview: Option, pub project_description: Option, #[serde(flatten)] - pub networks: forms::stack::ComposeNetworks, // all networks + pub networks: forms::project::ComposeNetworks, // all networks } diff --git a/src/forms/stack/docker_image.rs b/src/forms/project/docker_image.rs similarity index 100% rename from src/forms/stack/docker_image.rs rename to src/forms/project/docker_image.rs diff --git a/src/forms/stack/domain_list.rs b/src/forms/project/domain_list.rs similarity index 100% rename from src/forms/stack/domain_list.rs rename to src/forms/project/domain_list.rs diff --git a/src/forms/stack/environment.rs b/src/forms/project/environment.rs similarity index 100% rename from src/forms/stack/environment.rs rename to src/forms/project/environment.rs diff --git a/src/forms/stack/feature.rs b/src/forms/project/feature.rs similarity index 93% rename from src/forms/stack/feature.rs rename to src/forms/project/feature.rs index b6d0cbc..d540572 100644 --- a/src/forms/stack/feature.rs +++ b/src/forms/project/feature.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; use serde_valid::Validate; -use crate::forms::stack::*; +use crate::forms::project::*; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Feature { diff --git a/src/forms/stack/form.rs b/src/forms/project/form.rs similarity index 63% rename from src/forms/stack/form.rs rename to src/forms/project/form.rs index 3a9d8b7..2ae56bd 100644 --- a/src/forms/stack/form.rs +++ b/src/forms/project/form.rs @@ -6,61 +6,40 @@ use std::fmt; use crate::models; use crate::forms; + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Stack { +pub struct ProjectForm { // #[validate(min_length=2)] // #[validate(max_length=255)] #[serde(rename = "commonDomain")] pub common_domain: Option, - pub domain_list: Option, + pub domain_list: Option, #[validate(min_length = 2)] #[validate(max_length = 255)] pub stack_code: Option, - #[validate(min_length = 2)] - #[validate(max_length = 50)] - pub region: String, - #[validate(min_length = 2)] - #[validate(max_length = 50)] - pub zone: Option, - #[validate(min_length = 2)] - #[validate(max_length = 50)] - pub server: String, - #[validate(min_length = 2)] - #[validate(max_length = 50)] - pub os: String, #[validate(min_length = 3)] #[validate(max_length = 50)] pub ssl: String, - pub vars: Option>, + pub vars: Option>, pub integrated_features: Option>, pub extended_features: Option>, pub subscriptions: Option>, pub form_app: Option>, #[validate(min_length = 3)] #[validate(max_length = 50)] - pub disk_type: Option, - pub save_token: bool, - #[validate(min_length = 10)] - #[validate(max_length = 255)] - pub cloud_token: String, - #[validate(min_length = 2)] - #[validate(max_length = 50)] - pub provider: String, - #[validate(min_length = 3)] - #[validate(max_length = 50)] pub selected_plan: String, - pub custom: forms::stack::Custom, + pub custom: forms::project::Custom, } -impl TryFrom<&models::Stack> for Stack { +impl TryFrom<&models::Project> for ProjectForm { type Error = String; - fn try_from(stack: &models::Stack) -> Result { - serde_json::from_value::(stack.body.clone()).map_err(|err| format!("{:?}", err)) + fn try_from(project: &models::Project) -> Result { + serde_json::from_value::(project.body.clone()).map_err(|err| format!("{:?}", err)) } } -impl Stack { +impl ProjectForm { pub async fn is_readable_docker_image(&self) -> Result { let mut is_active = true; for app in &self.custom.web { diff --git a/src/forms/stack/icon.rs b/src/forms/project/icon.rs similarity index 85% rename from src/forms/stack/icon.rs rename to src/forms/project/icon.rs index 0bcae01..2f1c83c 100644 --- a/src/forms/stack/icon.rs +++ b/src/forms/project/icon.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use crate::forms::stack::*; +use crate::forms::project::*; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Icon { diff --git a/src/forms/stack/icon_dark.rs b/src/forms/project/icon_dark.rs similarity index 100% rename from src/forms/stack/icon_dark.rs rename to src/forms/project/icon_dark.rs diff --git a/src/forms/stack/icon_light.rs b/src/forms/project/icon_light.rs similarity index 100% rename from src/forms/stack/icon_light.rs rename to src/forms/project/icon_light.rs diff --git a/src/forms/stack/mod.rs b/src/forms/project/mod.rs similarity index 100% rename from src/forms/stack/mod.rs rename to src/forms/project/mod.rs diff --git a/src/forms/stack/network.rs b/src/forms/project/network.rs similarity index 96% rename from src/forms/stack/network.rs rename to src/forms/project/network.rs index a05fd54..9b848ff 100644 --- a/src/forms/stack/network.rs +++ b/src/forms/project/network.rs @@ -1,9 +1,9 @@ use serde::{Deserialize, Serialize}; use serde_valid::Validate; -use crate::forms::stack; +use crate::forms::project; use docker_compose_types as dctypes; use indexmap::IndexMap; -use crate::forms::stack::NetworkDriver; +use crate::forms::project::NetworkDriver; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] diff --git a/src/forms/stack/network_driver.rs b/src/forms/project/network_driver.rs similarity index 100% rename from src/forms/stack/network_driver.rs rename to src/forms/project/network_driver.rs diff --git a/src/forms/stack/payload.rs b/src/forms/project/payload.rs similarity index 55% rename from src/forms/stack/payload.rs rename to src/forms/project/payload.rs index f89b3c6..70800fe 100644 --- a/src/forms/stack/payload.rs +++ b/src/forms/project/payload.rs @@ -13,13 +13,11 @@ pub struct Payload { pub(crate) user_email: Option, #[serde(rename = "commonDomain")] pub common_domain: String, - pub domain_list: Option, - pub region: String, - pub zone: Option, - pub server: String, - pub os: String, + pub domain_list: Option, + #[serde(flatten)] + pub server: models::Server, pub ssl: String, - pub vars: Option>, + pub vars: Option>, #[serde(rename = "integrated_features")] pub integrated_features: Option>, #[serde(rename = "extended_features")] @@ -27,29 +25,25 @@ pub struct Payload { pub subscriptions: Option>, pub form_app: Option>, pub disk_type: Option, - pub save_token: bool, - pub cloud_token: Option, - pub cloud_key: Option, - pub cloud_secret: Option, - pub provider: String, + #[serde(flatten)] + pub cloud: models::Cloud, pub stack_code: String, - #[serde(rename = "selected_plan")] pub selected_plan: String, - pub custom: forms::stack::Custom, + pub custom: forms::project::Custom, pub docker_compose: Option>, } -impl TryFrom<&models::Stack> for Payload { +impl TryFrom<&models::Project> for Payload { type Error = String; - fn try_from(stack: &models::Stack) -> Result { - let mut stack_data = serde_json::from_value::(stack.body.clone()).map_err(|err| { + fn try_from(project: &models::Project) -> Result { + let mut project_data = serde_json::from_value::(project.body.clone()).map_err(|err| { format!("{:?}", err) })?; - stack_data.id = Some(stack.id.clone()); - stack_data.stack_code = stack_data.custom.custom_stack_code.clone(); + project_data.id = Some(project.id.clone()); + project_data.stack_code = project_data.custom.custom_stack_code.clone(); - Ok(stack_data) + Ok(project_data) } } diff --git a/src/forms/stack/port.rs b/src/forms/project/port.rs similarity index 100% rename from src/forms/stack/port.rs rename to src/forms/project/port.rs diff --git a/src/forms/stack/price.rs b/src/forms/project/price.rs similarity index 100% rename from src/forms/stack/price.rs rename to src/forms/project/price.rs diff --git a/src/forms/stack/requirements.rs b/src/forms/project/requirements.rs similarity index 100% rename from src/forms/stack/requirements.rs rename to src/forms/project/requirements.rs diff --git a/src/forms/stack/role.rs b/src/forms/project/role.rs similarity index 100% rename from src/forms/stack/role.rs rename to src/forms/project/role.rs diff --git a/src/forms/stack/service.rs b/src/forms/project/service.rs similarity index 93% rename from src/forms/stack/service.rs rename to src/forms/project/service.rs index 5aea4a8..706e0be 100644 --- a/src/forms/stack/service.rs +++ b/src/forms/project/service.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; use serde_valid::Validate; -use crate::forms::stack::*; +use crate::forms::project::*; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Service { diff --git a/src/forms/stack/service_networks.rs b/src/forms/project/service_networks.rs similarity index 98% rename from src/forms/stack/service_networks.rs rename to src/forms/project/service_networks.rs index 17b51c5..39f03b0 100644 --- a/src/forms/stack/service_networks.rs +++ b/src/forms/project/service_networks.rs @@ -24,7 +24,7 @@ impl TryFrom<&ServiceNetworks> for dctypes::Networks { // IndexMap // -// impl Into>> for stack::ComposeNetworks { +// impl Into>> for project::ComposeNetworks { // fn into(self) -> IndexMap> { // // // let mut default_networks = vec![Network::default()]; diff --git a/src/forms/stack/var.rs b/src/forms/project/var.rs similarity index 100% rename from src/forms/stack/var.rs rename to src/forms/project/var.rs diff --git a/src/forms/stack/version.rs b/src/forms/project/version.rs similarity index 100% rename from src/forms/stack/version.rs rename to src/forms/project/version.rs diff --git a/src/forms/stack/volume.rs b/src/forms/project/volume.rs similarity index 95% rename from src/forms/stack/volume.rs rename to src/forms/project/volume.rs index ab4d3f8..b4bfaed 100644 --- a/src/forms/stack/volume.rs +++ b/src/forms/project/volume.rs @@ -58,8 +58,8 @@ impl Into for &Volume { // @todo check if host_path is required argument driver_opts.insert(String::from("type"), Some(dctypes::SingleValue::String("none".to_string()))); driver_opts.insert(String::from("o"), Some(dctypes::SingleValue::String("bind".to_string()))); - // @todo move to config stack docroot on host - let path = format!("/root/stack/{}", &host_path); + // @todo move to config project docroot on host + let path = format!("/root/project/{}", &host_path); driver_opts.insert(String::from("device"), Some(dctypes::SingleValue::String(path))); dctypes::ComposeVolume { diff --git a/src/forms/stack/volumes.rs b/src/forms/project/volumes.rs similarity index 83% rename from src/forms/stack/volumes.rs rename to src/forms/project/volumes.rs index 39ec33e..27548a7 100644 --- a/src/forms/stack/volumes.rs +++ b/src/forms/project/volumes.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use crate::forms::stack::*; +use crate::forms::project::*; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Volumes { diff --git a/src/forms/stack/web.rs b/src/forms/project/web.rs similarity index 88% rename from src/forms/stack/web.rs rename to src/forms/project/web.rs index 87e70cf..2d80cd5 100644 --- a/src/forms/stack/web.rs +++ b/src/forms/project/web.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; use serde_valid::Validate; -use crate::forms::stack::*; +use crate::forms::project::*; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Web { diff --git a/src/forms/server.rs b/src/forms/server.rs new file mode 100644 index 0000000..7b2672b --- /dev/null +++ b/src/forms/server.rs @@ -0,0 +1,36 @@ +use crate::models; +use serde::{Deserialize, Serialize}; +use serde_valid::Validate; +use chrono::{DateTime, Utc}; + +#[derive(Serialize, Deserialize, Debug, Validate)] +pub struct Server { + pub id: i32, + pub user_id: String, + pub cloud_id: i32, + pub project_id: i32, + pub region: String, + pub zone: Option, + pub server: String, + pub os: String, + pub disk_type: Option, + pub created_at: DateTime, + pub updated_at: DateTime, +} + +impl Into for Server { + fn into(self) -> models::Server { + let mut server = models::Server::default(); + server.user_id = self.user_id; + server.cloud_id = self.cloud_id; + server.project_id = self.project_id; + server.region = String::from(""); + server.zone = Some(String::from("")); + server.server = String::from(""); + server.os = String::from(""); + server.created_at = Utc::now(); + server.updated_at = Utc::now(); + + server + } +} diff --git a/src/helpers/dockerhub.rs b/src/helpers/dockerhub.rs index e3f1720..d5e4ad6 100644 --- a/src/helpers/dockerhub.rs +++ b/src/helpers/dockerhub.rs @@ -1,4 +1,4 @@ -use crate::forms::stack::DockerImage; +use crate::forms::project::DockerImage; use reqwest::RequestBuilder; use serde_derive::{Deserialize, Serialize}; use serde_json::Value; diff --git a/src/helpers/mod.rs b/src/helpers/mod.rs index 17f75f1..74f975b 100644 --- a/src/helpers/mod.rs +++ b/src/helpers/mod.rs @@ -1,7 +1,7 @@ pub mod client; pub(crate) mod json; mod mq_manager; -pub(crate) mod stack; +pub mod project; pub use json::*; pub use mq_manager::MqManager; diff --git a/src/helpers/stack/builder.rs b/src/helpers/project/builder.rs similarity index 81% rename from src/helpers/stack/builder.rs rename to src/helpers/project/builder.rs index e17d364..b5b0e42 100644 --- a/src/helpers/stack/builder.rs +++ b/src/helpers/project/builder.rs @@ -2,7 +2,7 @@ use crate::forms; use docker_compose_types as dctypes; use crate::models; use serde_yaml; -use crate::helpers::stack::*; +use crate::helpers::project::*; use tracing::Value; @@ -10,26 +10,26 @@ use tracing::Value; #[derive(Clone, Debug)] pub struct DcBuilder { config: Config, - pub(crate) stack: models::Stack, + pub(crate) project: models::Project, } impl DcBuilder { - pub fn new(stack: models::Stack) -> Self { + pub fn new(project: models::Project) -> Self { DcBuilder { config: Config::default(), - stack, + project, } } - #[tracing::instrument(name = "building stack")] + #[tracing::instrument(name = "building project")] pub fn build(&self) -> Result { let mut compose_content = dctypes::Compose { version: Some("3.8".to_string()), ..Default::default() }; - let apps = forms::stack::Stack::try_from(&self.stack)?; + let apps = forms::project::ProjectForm::try_from(&self.project)?; let services = apps.custom.services()?; let named_volumes = apps.custom.named_volumes()?; @@ -44,7 +44,7 @@ impl DcBuilder { tracing::debug!("services {:?}", &services); compose_content.services = dctypes::Services(services); - let fname = format!("./files/{}.yml", self.stack.stack_id); + let fname = format!("./files/{}.yml", self.project.stack_id); tracing::debug!("Saving docker compose to file {:?}", fname); let target_file = std::path::Path::new(fname.as_str()); let serialized = serde_yaml::to_string(&compose_content) diff --git a/src/helpers/stack/builder_config.rs b/src/helpers/project/builder_config.rs similarity index 100% rename from src/helpers/stack/builder_config.rs rename to src/helpers/project/builder_config.rs diff --git a/src/helpers/stack/dctypes/advanced_build_step.rs b/src/helpers/project/dctypes/advanced_build_step.rs similarity index 95% rename from src/helpers/stack/dctypes/advanced_build_step.rs rename to src/helpers/project/dctypes/advanced_build_step.rs index c0e6e06..41f2f0c 100644 --- a/src/helpers/stack/dctypes/advanced_build_step.rs +++ b/src/helpers/project/dctypes/advanced_build_step.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use crate::helpers::stack::dctypes::*; +use crate::helpers::project::dctypes::*; #[derive(Builder, Clone, Debug, Deserialize, Serialize, Eq, PartialEq, Default)] #[serde(deny_unknown_fields)] diff --git a/src/helpers/stack/dctypes/advanced_network_settings.rs b/src/helpers/project/dctypes/advanced_network_settings.rs similarity index 100% rename from src/helpers/stack/dctypes/advanced_network_settings.rs rename to src/helpers/project/dctypes/advanced_network_settings.rs diff --git a/src/helpers/stack/dctypes/advanced_networks.rs b/src/helpers/project/dctypes/advanced_networks.rs similarity index 92% rename from src/helpers/stack/dctypes/advanced_networks.rs rename to src/helpers/project/dctypes/advanced_networks.rs index d26aba1..2b4f0b0 100644 --- a/src/helpers/stack/dctypes/advanced_networks.rs +++ b/src/helpers/project/dctypes/advanced_networks.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use indexmap::IndexMap; #[cfg(not(feature = "indexmap"))] use std::collections::HashMap; -use crate::helpers::stack::dctypes::*; +use crate::helpers::project::dctypes::*; #[cfg(feature = "indexmap")] #[derive(Clone, Default, Debug, Serialize, Deserialize, Eq, PartialEq)] diff --git a/src/helpers/stack/dctypes/build_args.rs b/src/helpers/project/dctypes/build_args.rs similarity index 100% rename from src/helpers/stack/dctypes/build_args.rs rename to src/helpers/project/dctypes/build_args.rs diff --git a/src/helpers/stack/dctypes/build_step.rs b/src/helpers/project/dctypes/build_step.rs similarity index 84% rename from src/helpers/stack/dctypes/build_step.rs rename to src/helpers/project/dctypes/build_step.rs index 25a468d..3c1fc49 100644 --- a/src/helpers/stack/dctypes/build_step.rs +++ b/src/helpers/project/dctypes/build_step.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use crate::helpers::stack::dctypes; +use crate::helpers::project::dctypes; #[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] #[serde(untagged)] diff --git a/src/helpers/stack/dctypes/compose.rs b/src/helpers/project/dctypes/compose.rs similarity index 96% rename from src/helpers/stack/dctypes/compose.rs rename to src/helpers/project/dctypes/compose.rs index 46d43c2..4bee50a 100644 --- a/src/helpers/stack/dctypes/compose.rs +++ b/src/helpers/project/dctypes/compose.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use crate::helpers::stack::dctypes::*; +use crate::helpers::project::dctypes::*; #[cfg(feature = "indexmap")] use indexmap::IndexMap; use serde_yaml::Value; diff --git a/src/helpers/stack/dctypes/compose_file.rs b/src/helpers/project/dctypes/compose_file.rs similarity index 92% rename from src/helpers/stack/dctypes/compose_file.rs rename to src/helpers/project/dctypes/compose_file.rs index 1131f67..79abe91 100644 --- a/src/helpers/stack/dctypes/compose_file.rs +++ b/src/helpers/project/dctypes/compose_file.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use crate::helpers::stack::dctypes; +use crate::helpers::project::dctypes; #[cfg(feature = "indexmap")] use indexmap::IndexMap; diff --git a/src/helpers/stack/dctypes/compose_network.rs b/src/helpers/project/dctypes/compose_network.rs similarity index 83% rename from src/helpers/stack/dctypes/compose_network.rs rename to src/helpers/project/dctypes/compose_network.rs index da36434..56d3de1 100644 --- a/src/helpers/stack/dctypes/compose_network.rs +++ b/src/helpers/project/dctypes/compose_network.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use crate::helpers::stack::dctypes::*; +use crate::helpers::project::dctypes::*; #[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] #[serde(untagged)] diff --git a/src/helpers/stack/dctypes/compose_network_setting_details.rs b/src/helpers/project/dctypes/compose_network_setting_details.rs similarity index 100% rename from src/helpers/stack/dctypes/compose_network_setting_details.rs rename to src/helpers/project/dctypes/compose_network_setting_details.rs diff --git a/src/helpers/stack/dctypes/compose_networks.rs b/src/helpers/project/dctypes/compose_networks.rs similarity index 93% rename from src/helpers/stack/dctypes/compose_networks.rs rename to src/helpers/project/dctypes/compose_networks.rs index f1374f0..da6aae1 100644 --- a/src/helpers/stack/dctypes/compose_networks.rs +++ b/src/helpers/project/dctypes/compose_networks.rs @@ -3,7 +3,7 @@ use indexmap::IndexMap; #[cfg(not(feature = "indexmap"))] use std::collections::HashMap; use serde::{Deserialize, Serialize}; -use crate::helpers::stack::dctypes::*; +use crate::helpers::project::dctypes::*; #[cfg(feature = "indexmap")] #[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] diff --git a/src/helpers/stack/dctypes/compose_volume.rs b/src/helpers/project/dctypes/compose_volume.rs similarity index 79% rename from src/helpers/stack/dctypes/compose_volume.rs rename to src/helpers/project/dctypes/compose_volume.rs index 4d40b23..644b67c 100644 --- a/src/helpers/stack/dctypes/compose_volume.rs +++ b/src/helpers/project/dctypes/compose_volume.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use crate::helpers::stack::dctypes::*; +use crate::helpers::project::dctypes::*; #[cfg(feature = "indexmap")] use indexmap::IndexMap; #[cfg(not(feature = "indexmap"))] @@ -12,9 +12,6 @@ pub struct ComposeVolume { #[cfg(feature = "indexmap")] #[serde(default, skip_serializing_if = "IndexMap::is_empty")] pub driver_opts: IndexMap>, - #[cfg(not(feature = "indexmap"))] - #[serde(default, skip_serializing_if = "HashMap::is_empty")] - pub driver_opts: HashMap>, #[serde(skip_serializing_if = "Option::is_none")] pub external: Option, #[serde(default, skip_serializing_if = "Labels::is_empty")] diff --git a/src/helpers/stack/dctypes/depends_condition.rs b/src/helpers/project/dctypes/depends_condition.rs similarity index 100% rename from src/helpers/stack/dctypes/depends_condition.rs rename to src/helpers/project/dctypes/depends_condition.rs diff --git a/src/helpers/stack/dctypes/depends_on_options.rs b/src/helpers/project/dctypes/depends_on_options.rs similarity index 95% rename from src/helpers/stack/dctypes/depends_on_options.rs rename to src/helpers/project/dctypes/depends_on_options.rs index 6e12300..fbf7911 100644 --- a/src/helpers/stack/dctypes/depends_on_options.rs +++ b/src/helpers/project/dctypes/depends_on_options.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "indexmap")] use indexmap::IndexMap; -use crate::helpers::stack::dctypes; +use crate::helpers::project::dctypes; #[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] #[serde(untagged)] diff --git a/src/helpers/stack/dctypes/env_file.rs b/src/helpers/project/dctypes/env_file.rs similarity index 100% rename from src/helpers/stack/dctypes/env_file.rs rename to src/helpers/project/dctypes/env_file.rs diff --git a/src/helpers/stack/dctypes/environment.rs b/src/helpers/project/dctypes/environment.rs similarity index 94% rename from src/helpers/stack/dctypes/environment.rs rename to src/helpers/project/dctypes/environment.rs index 3afafed..a04f992 100644 --- a/src/helpers/stack/dctypes/environment.rs +++ b/src/helpers/project/dctypes/environment.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use serde_yaml::Value; #[cfg(feature = "indexmap")] use indexmap::IndexMap; -use crate::helpers::stack::dctypes; +use crate::helpers::project::dctypes; #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[serde(untagged)] diff --git a/src/helpers/stack/dctypes/extension.rs b/src/helpers/project/dctypes/extension.rs similarity index 94% rename from src/helpers/stack/dctypes/extension.rs rename to src/helpers/project/dctypes/extension.rs index f70871c..1c0b412 100644 --- a/src/helpers/stack/dctypes/extension.rs +++ b/src/helpers/project/dctypes/extension.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use crate::helpers::stack::dctypes; +use crate::helpers::project::dctypes; use std::str::FromStr; #[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash, Default, Ord, PartialOrd)] diff --git a/src/helpers/stack/dctypes/extension_parse_error.rs b/src/helpers/project/dctypes/extension_parse_error.rs similarity index 100% rename from src/helpers/stack/dctypes/extension_parse_error.rs rename to src/helpers/project/dctypes/extension_parse_error.rs diff --git a/src/helpers/stack/dctypes/external_network_setting_bool.rs b/src/helpers/project/dctypes/external_network_setting_bool.rs similarity index 100% rename from src/helpers/stack/dctypes/external_network_setting_bool.rs rename to src/helpers/project/dctypes/external_network_setting_bool.rs diff --git a/src/helpers/stack/dctypes/external_volume.rs b/src/helpers/project/dctypes/external_volume.rs similarity index 100% rename from src/helpers/stack/dctypes/external_volume.rs rename to src/helpers/project/dctypes/external_volume.rs diff --git a/src/helpers/stack/dctypes/ipam.rs b/src/helpers/project/dctypes/ipam.rs similarity index 89% rename from src/helpers/stack/dctypes/ipam.rs rename to src/helpers/project/dctypes/ipam.rs index 592c2a6..99e8b1f 100644 --- a/src/helpers/stack/dctypes/ipam.rs +++ b/src/helpers/project/dctypes/ipam.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use crate::helpers::stack::dctypes::*; +use crate::helpers::project::dctypes::*; #[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] #[serde(deny_unknown_fields)] diff --git a/src/helpers/stack/dctypes/ipam_config.rs b/src/helpers/project/dctypes/ipam_config.rs similarity index 100% rename from src/helpers/stack/dctypes/ipam_config.rs rename to src/helpers/project/dctypes/ipam_config.rs diff --git a/src/helpers/stack/dctypes/labels.rs b/src/helpers/project/dctypes/labels.rs similarity index 100% rename from src/helpers/stack/dctypes/labels.rs rename to src/helpers/project/dctypes/labels.rs diff --git a/src/helpers/stack/dctypes/logging_parameters.rs b/src/helpers/project/dctypes/logging_parameters.rs similarity index 93% rename from src/helpers/stack/dctypes/logging_parameters.rs rename to src/helpers/project/dctypes/logging_parameters.rs index bae66fc..a0068c7 100644 --- a/src/helpers/stack/dctypes/logging_parameters.rs +++ b/src/helpers/project/dctypes/logging_parameters.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "indexmap")] use indexmap::IndexMap; -use crate::helpers::stack::dctypes; +use crate::helpers::project::dctypes; #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct LoggingParameters { diff --git a/src/helpers/stack/dctypes/mod.rs b/src/helpers/project/dctypes/mod.rs similarity index 99% rename from src/helpers/stack/dctypes/mod.rs rename to src/helpers/project/dctypes/mod.rs index 66bda09..093c7f1 100644 --- a/src/helpers/stack/dctypes/mod.rs +++ b/src/helpers/project/dctypes/mod.rs @@ -72,7 +72,7 @@ pub use network_settings::*; pub use ipam::*; pub use ipam_config::*; -use crate::helpers::stack::dctypes; +use crate::helpers::project::dctypes; use derive_builder::*; #[cfg(feature = "indexmap")] diff --git a/src/helpers/stack/dctypes/network_settings.rs b/src/helpers/project/dctypes/network_settings.rs similarity index 96% rename from src/helpers/stack/dctypes/network_settings.rs rename to src/helpers/project/dctypes/network_settings.rs index 9c45bc1..72b27b2 100644 --- a/src/helpers/stack/dctypes/network_settings.rs +++ b/src/helpers/project/dctypes/network_settings.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use crate::helpers::stack::dctypes::*; +use crate::helpers::project::dctypes::*; #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)] #[serde(deny_unknown_fields)] diff --git a/src/helpers/stack/dctypes/networks.rs b/src/helpers/project/dctypes/networks.rs similarity index 92% rename from src/helpers/stack/dctypes/networks.rs rename to src/helpers/project/dctypes/networks.rs index bbcfdb1..751554f 100644 --- a/src/helpers/stack/dctypes/networks.rs +++ b/src/helpers/project/dctypes/networks.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use crate::helpers::stack::dctypes; +use crate::helpers::project::dctypes; #[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] #[serde(untagged)] diff --git a/src/helpers/stack/dctypes/port.rs b/src/helpers/project/dctypes/port.rs similarity index 94% rename from src/helpers/stack/dctypes/port.rs rename to src/helpers/project/dctypes/port.rs index 2555758..fc437ef 100644 --- a/src/helpers/stack/dctypes/port.rs +++ b/src/helpers/project/dctypes/port.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use crate::helpers::stack::dctypes; +use crate::helpers::project::dctypes; use crate::forms; #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] @@ -27,7 +27,7 @@ impl Default for Port { } } -impl TryInto for &forms::stack::Port { +impl TryInto for &forms::project::Port { type Error = String; fn try_into(self) -> Result { let cp = self diff --git a/src/helpers/stack/dctypes/ports.rs b/src/helpers/project/dctypes/ports.rs similarity index 92% rename from src/helpers/stack/dctypes/ports.rs rename to src/helpers/project/dctypes/ports.rs index bdcc6a8..3c61494 100644 --- a/src/helpers/stack/dctypes/ports.rs +++ b/src/helpers/project/dctypes/ports.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use crate::helpers::stack::dctypes; +use crate::helpers::project::dctypes; #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[serde(untagged)] diff --git a/src/helpers/stack/dctypes/published_port.rs b/src/helpers/project/dctypes/published_port.rs similarity index 100% rename from src/helpers/stack/dctypes/published_port.rs rename to src/helpers/project/dctypes/published_port.rs diff --git a/src/helpers/stack/dctypes/service.rs b/src/helpers/project/dctypes/service.rs similarity index 99% rename from src/helpers/stack/dctypes/service.rs rename to src/helpers/project/dctypes/service.rs index 4cebefc..e288632 100644 --- a/src/helpers/stack/dctypes/service.rs +++ b/src/helpers/project/dctypes/service.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "indexmap")] use indexmap::IndexMap; -use crate::helpers::stack::dctypes; +use crate::helpers::project::dctypes; use serde_json::Value; use derive_builder::*; diff --git a/src/helpers/stack/dctypes/services.rs b/src/helpers/project/dctypes/services.rs similarity index 93% rename from src/helpers/stack/dctypes/services.rs rename to src/helpers/project/dctypes/services.rs index b41ff10..949437e 100644 --- a/src/helpers/stack/dctypes/services.rs +++ b/src/helpers/project/dctypes/services.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use indexmap::IndexMap; #[cfg(not(feature = "indexmap"))] use std::collections::HashMap; -use crate::helpers::stack::dctypes; +use crate::helpers::project::dctypes; #[cfg(feature = "indexmap")] #[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] diff --git a/src/helpers/stack/dctypes/single_service.rs b/src/helpers/project/dctypes/single_service.rs similarity index 81% rename from src/helpers/stack/dctypes/single_service.rs rename to src/helpers/project/dctypes/single_service.rs index 489a306..19031c5 100644 --- a/src/helpers/stack/dctypes/single_service.rs +++ b/src/helpers/project/dctypes/single_service.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use crate::helpers::stack::dctypes; +use crate::helpers::project::dctypes; #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)] pub struct SingleService { diff --git a/src/helpers/stack/dctypes/sys_ctls.rs b/src/helpers/project/dctypes/sys_ctls.rs similarity index 94% rename from src/helpers/stack/dctypes/sys_ctls.rs rename to src/helpers/project/dctypes/sys_ctls.rs index 45d0a7c..4abbb24 100644 --- a/src/helpers/stack/dctypes/sys_ctls.rs +++ b/src/helpers/project/dctypes/sys_ctls.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use crate::helpers::stack::dctypes; +use crate::helpers::project::dctypes; #[cfg(feature = "indexmap")] use indexmap::IndexMap; diff --git a/src/helpers/stack/dctypes/tmpfs.rs b/src/helpers/project/dctypes/tmpfs.rs similarity index 100% rename from src/helpers/stack/dctypes/tmpfs.rs rename to src/helpers/project/dctypes/tmpfs.rs diff --git a/src/helpers/stack/dctypes/top_level_volumes.rs b/src/helpers/project/dctypes/top_level_volumes.rs similarity index 93% rename from src/helpers/stack/dctypes/top_level_volumes.rs rename to src/helpers/project/dctypes/top_level_volumes.rs index 7216953..304d531 100644 --- a/src/helpers/stack/dctypes/top_level_volumes.rs +++ b/src/helpers/project/dctypes/top_level_volumes.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use indexmap::IndexMap; #[cfg(not(feature = "indexmap"))] use std::collections::HashMap; -use crate::helpers::stack::dctypes::*; +use crate::helpers::project::dctypes::*; #[cfg(feature = "indexmap")] #[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] diff --git a/src/helpers/stack/dctypes/ulimit.rs b/src/helpers/project/dctypes/ulimit.rs similarity index 100% rename from src/helpers/stack/dctypes/ulimit.rs rename to src/helpers/project/dctypes/ulimit.rs diff --git a/src/helpers/stack/dctypes/ulimits.rs b/src/helpers/project/dctypes/ulimits.rs similarity index 93% rename from src/helpers/stack/dctypes/ulimits.rs rename to src/helpers/project/dctypes/ulimits.rs index 721eaf9..2cfe4f5 100644 --- a/src/helpers/stack/dctypes/ulimits.rs +++ b/src/helpers/project/dctypes/ulimits.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use indexmap::IndexMap; #[cfg(not(feature = "indexmap"))] use std::collections::HashMap; -use crate::helpers::stack::dctypes; +use crate::helpers::project::dctypes; #[cfg(feature = "indexmap")] #[derive(Clone, Default, Debug, Serialize, Deserialize, Eq, PartialEq)] diff --git a/src/helpers/stack/mod.rs b/src/helpers/project/mod.rs similarity index 100% rename from src/helpers/stack/mod.rs rename to src/helpers/project/mod.rs diff --git a/src/models/cloud.rs b/src/models/cloud.rs new file mode 100644 index 0000000..308950d --- /dev/null +++ b/src/models/cloud.rs @@ -0,0 +1,15 @@ +use chrono::{DateTime, Utc}; +use serde_derive::{Deserialize, Serialize}; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Cloud { + pub id: i32, + pub user_id: String, + pub provider: String, + pub cloud_token: Option, + pub cloud_key: Option, + pub cloud_secret: Option, + pub save_token: Option, + pub created_at: DateTime, + pub updated_at: DateTime, +} diff --git a/src/models/deployment.rs b/src/models/deployment.rs new file mode 100644 index 0000000..3aea4e6 --- /dev/null +++ b/src/models/deployment.rs @@ -0,0 +1,38 @@ +use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +// Store user deployment attempts for a specific project +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct Deployment { + pub id: i32, // id - is a unique identifier for the app project + pub project_id: i32, // external project ID + pub deleted: bool, + pub status: String, + pub body: Value, //json type + pub created_at: DateTime, + pub updated_at: DateTime, +} + +impl Deployment { + pub fn new(project_id: i32, status: String, body: Value) -> Self { + Self { + id: 0, + project_id, + deleted: false, + status, + body, + created_at: Utc::now(), + updated_at: Utc::now(), + } + } +} + +impl Default for Deployment { + fn default() -> Self { + Deployment { + status: "pending".to_string(), + ..Default::default() + } + } +} diff --git a/src/models/mod.rs b/src/models/mod.rs index a17ea32..03de8ab 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -3,13 +3,19 @@ mod product; mod ratecategory; mod rules; pub mod rating; -pub mod stack; +pub mod project; pub mod user; +mod deployment; +mod cloud; +mod server; pub use client::*; pub use rating::*; -pub use stack::*; +pub use project::*; pub use user::*; pub use product::*; pub use ratecategory::*; pub use rules::*; +pub use deployment::*; +pub use cloud::*; +pub use server::*; diff --git a/src/models/product.rs b/src/models/product.rs index 992818d..8fde4f3 100644 --- a/src/models/product.rs +++ b/src/models/product.rs @@ -2,15 +2,15 @@ use chrono::{DateTime, Utc}; pub struct Product { // Product - is an external object that we want to store in the database, - // that can be a stack or an app in the stack. feature, service, web app etc. + // that can be a project or an app in the project. feature, service, web app etc. // id - is a unique identifier for the product // user_id - is a unique identifier for the user // rating - is a rating of the product - // product type stack & app, + // product type project & app, // id is generated based on the product type and external obj_id pub id: i32, //primary key, for better data management pub obj_id: i32, // external product ID db, no autoincrement, example: 100 - pub obj_type: String, // stack | app, unique index + pub obj_type: String, // project | app, unique index pub created_at: DateTime, pub updated_at: DateTime, } diff --git a/src/models/stack.rs b/src/models/project.rs similarity index 79% rename from src/models/stack.rs rename to src/models/project.rs index a808f13..35661eb 100644 --- a/src/models/stack.rs +++ b/src/models/project.rs @@ -4,9 +4,10 @@ use serde_json::Value; use uuid::Uuid; #[derive(Debug, Serialize, Deserialize, Clone)] -pub struct Stack { - pub id: i32, // id - is a unique identifier for the app stack - pub stack_id: Uuid, // external stack ID +pub struct Project { + pub id: i32, // id - is a unique identifier for the app project + pub cloud_id: Option, // cloud assigned to a project + pub stack_id: Uuid, // external project ID pub user_id: String, // external unique identifier for the user pub name: String, // pub body: sqlx::types::Json, @@ -15,11 +16,12 @@ pub struct Stack { pub updated_at: DateTime, } -impl Stack { +impl Project { pub fn new(user_id: String, name: String, body: Value) -> Self { Self { id: 0, stack_id: Uuid::new_v4(), + cloud_id: None, user_id: user_id, name: name, body: body, @@ -29,9 +31,9 @@ impl Stack { } } -impl Default for Stack { +impl Default for Project { fn default() -> Self { - Stack { + Project { user_id: "".to_string(), name: "".to_string(), ..Default::default() diff --git a/src/models/ratecategory.rs b/src/models/ratecategory.rs index 8228ae0..352bedb 100644 --- a/src/models/ratecategory.rs +++ b/src/models/ratecategory.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; pub enum RateCategory { Application, // app, feature, extension Cloud, // is user satisfied working with this cloud - Stack, // app stack + Project, // app project DeploymentSpeed, Documentation, Design, diff --git a/src/models/server.rs b/src/models/server.rs new file mode 100644 index 0000000..6098d68 --- /dev/null +++ b/src/models/server.rs @@ -0,0 +1,28 @@ +use chrono::{DateTime, Utc}; +use serde_derive::{Deserialize, Serialize}; +use serde_valid::Validate; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct Server { + pub id: i32, + pub user_id: String, + pub cloud_id: i32, + pub project_id: i32, + #[validate(min_length = 2)] + #[validate(max_length = 50)] + pub region: String, + #[validate(min_length = 2)] + #[validate(max_length = 50)] + pub zone: Option, + #[validate(min_length = 2)] + #[validate(max_length = 50)] + pub server: String, + #[validate(min_length = 2)] + #[validate(max_length = 50)] + pub os: String, + #[validate(min_length = 3)] + #[validate(max_length = 50)] + pub disk_type: Option, + pub created_at: DateTime, + pub updated_at: DateTime, +} diff --git a/src/routes/cloud/add.rs b/src/routes/cloud/add.rs new file mode 100644 index 0000000..4923cad --- /dev/null +++ b/src/routes/cloud/add.rs @@ -0,0 +1,50 @@ +use crate::forms; +use crate::helpers::JsonResponse; +use crate::models; +use crate::db; +use actix_web::{post, web, Responder, Result}; +use sqlx::PgPool; +use tracing::Instrument; +use std::sync::Arc; +use serde_valid::Validate; + +// workflow +// add, update, list, get(user_id), ACL, +// ACL - access to func for a user +// ACL - access to objects for a user + +#[tracing::instrument(name = "Add cloud.")] +#[post("")] +pub async fn add( + user: web::ReqData>, + form: web::Json, + pg_pool: web::Data, +) -> Result { + + if !form.validate().is_ok() { + let errors = form.validate().unwrap_err().to_string(); + let err_msg = format!("Invalid data received {:?}", &errors); + tracing::debug!(err_msg); + + return Err(JsonResponse::::build().form_error(errors)); + } + + let cloud = db::cloud::fetch(pg_pool.get_ref(), form.id) + .await + .map_err(|_msg| JsonResponse::::build().internal_server_error(_msg))? + .ok_or_else(|| JsonResponse::::build().not_found("not found"))? + ; + + tracing::debug!("Cloud record is found ? {:?}", cloud); + + let mut cloud: models::Cloud = form.into_inner().into(); + cloud.user_id = user.id.clone(); + + db::cloud::insert(pg_pool.get_ref(), cloud) + .await + .map(|cloud| JsonResponse::build() + .set_item(cloud) + .ok("success")) + .map_err(|_err| JsonResponse::::build() + .internal_server_error("Failed to insert")) +} diff --git a/src/routes/cloud/get.rs b/src/routes/cloud/get.rs new file mode 100644 index 0000000..62f2a47 --- /dev/null +++ b/src/routes/cloud/get.rs @@ -0,0 +1,46 @@ +use std::sync::Arc; +use crate::db; +use crate::helpers::JsonResponse; +use crate::models; +use actix_web::{get, web, Responder, Result}; +use sqlx::PgPool; +use tracing::Instrument; + +// workflow +// add, update, list, get(user_id), ACL, +// ACL - access to func for a user +// ACL - access to objects for a user + +#[tracing::instrument(name = "Get cloud.")] +#[get("/{id}")] +pub async fn item( + path: web::Path<(i32,)>, + pg_pool: web::Data, +) -> Result { + let id = path.0; + let cloud = db::cloud::fetch(pg_pool.get_ref(), id) + .await + .map_err(|_err| JsonResponse::::build() + .internal_server_error("")) + .and_then(|cloud| { + match cloud { + Some(cloud) => { Ok(cloud) }, + None => Err(JsonResponse::::build().not_found("object not found")) + } + })?; + + Ok(JsonResponse::build().set_item(cloud).ok("OK")) +} + +#[tracing::instrument(name = "Get all clouds.")] +#[get("")] +pub async fn list( + path: web::Path<()>, + user: web::ReqData>, + pg_pool: web::Data, +) -> Result { + db::cloud::fetch_by_user(pg_pool.get_ref(), user.id.as_ref()) + .await + .map(|clouds| JsonResponse::build().set_list(clouds).ok("OK")) + .map_err(|_err| JsonResponse::::build().internal_server_error("")) +} diff --git a/src/routes/cloud/mod.rs b/src/routes/cloud/mod.rs new file mode 100644 index 0000000..a489a06 --- /dev/null +++ b/src/routes/cloud/mod.rs @@ -0,0 +1,7 @@ +pub mod add; +pub mod get; +pub mod update; + +pub use add::*; +pub use get::*; +pub use update::*; diff --git a/src/routes/stack/service.rs b/src/routes/cloud/update.rs similarity index 100% rename from src/routes/stack/service.rs rename to src/routes/cloud/update.rs diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 0d6e99e..647742a 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -4,5 +4,8 @@ pub(crate) mod rating; pub(crate) mod test; pub use health_checks::*; -pub(crate) mod stack; -pub use stack::*; +pub(crate) mod project; +pub(crate) mod cloud; +pub(crate) mod server; + +pub use project::*; diff --git a/src/routes/project/add.rs b/src/routes/project/add.rs new file mode 100644 index 0000000..e3d1b07 --- /dev/null +++ b/src/routes/project/add.rs @@ -0,0 +1,78 @@ +use crate::db; +use crate::forms; +use crate::helpers::JsonResponse; +use crate::models; +use actix_web::Error; +use actix_web::{ + post, web, + web::{Bytes, Data}, + Responder, Result, +}; +use serde_json::Value; +use serde_valid::Validate; +use sqlx::PgPool; +use std::str; +use std::sync::Arc; + +#[tracing::instrument(name = "Add project.")] +#[post("")] +pub async fn add( + body: Bytes, + user: web::ReqData>, + pg_pool: Data, +) -> Result { + // @todo ACL + let form = body_into_form(body).await?; + let project_name = form.custom.custom_stack_code.clone(); + + project_exists(pg_pool.get_ref(), &project_name).await?; + + let body: Value = serde_json::to_value::(form) + .or(serde_json::to_value::(forms::project::ProjectForm::default())) + .unwrap(); + + let project = models::Project::new(user.id.clone(), project_name, body); + db::project::insert(pg_pool.get_ref(), project) + .await + .map(|project| JsonResponse::build().set_item(project).ok("Ok")) + .map_err(|_| { + JsonResponse::::build().internal_server_error("Internal Server Error") + }) +} + + +async fn project_exists(pool: &PgPool, project_name: &String) -> Result<(), Error> { + db::project::fetch_one_by_name(pool, project_name) + .await + .map_err(|_| { + JsonResponse::::build().internal_server_error("Internal Server Error") + }) + .and_then(|project| match project { + Some(_) => Err(JsonResponse::::build() + .conflict("Project with that name already exists")), + None => Ok(()), + }) +} + +async fn body_into_form(body: Bytes) -> Result { + let body_bytes = actix_web::body::to_bytes(body).await.unwrap(); + let body_str = str::from_utf8(&body_bytes) + .map_err(|err| JsonResponse::::build().internal_server_error(err.to_string()))?; + let deserializer = &mut serde_json::Deserializer::from_str(body_str); + serde_path_to_error::deserialize(deserializer) + .map_err(|err| { + let msg = format!("{}:{:?}", err.path().to_string(), err); + JsonResponse::::build().bad_request(msg) + }) + .and_then(|form: forms::project::ProjectForm| { + if !form.validate().is_ok() { + let errors = form.validate().unwrap_err().to_string(); + let err_msg = format!("Invalid data received {:?}", &errors); + tracing::debug!(err_msg); + + return Err(JsonResponse::::build().form_error(errors)); + } + + Ok(form) + }) +} diff --git a/src/routes/stack/compose.rs b/src/routes/project/compose.rs similarity index 50% rename from src/routes/stack/compose.rs rename to src/routes/project/compose.rs index 7c926b5..d0ea432 100644 --- a/src/routes/stack/compose.rs +++ b/src/routes/project/compose.rs @@ -1,5 +1,5 @@ use crate::db; -use crate::helpers::stack::builder::DcBuilder; +use crate::helpers::project::builder::DcBuilder; use crate::helpers::JsonResponse; use crate::models; use actix_web::{get, web, web::Data, Responder, Result}; @@ -14,21 +14,21 @@ pub async fn add( pg_pool: Data, ) -> Result { let id = path.0; - let stack = db::stack::fetch(pg_pool.get_ref(), id) + let project = db::project::fetch(pg_pool.get_ref(), id) .await - .map_err(|err| JsonResponse::::build().internal_server_error(err)) - .and_then(|stack| match stack { - Some(stack) if stack.user_id != user.id => { - Err(JsonResponse::::build().not_found("not found")) + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .and_then(|project| match project { + Some(project) if project.user_id != user.id => { + Err(JsonResponse::::build().not_found("not found")) } - Some(stack) => Ok(stack), - None => Err(JsonResponse::::build().not_found("not found")), + Some(project) => Ok(project), + None => Err(JsonResponse::::build().not_found("not found")), })?; - DcBuilder::new(stack) + DcBuilder::new(project) .build() .map_err(|err| { - JsonResponse::::build().internal_server_error(err) + JsonResponse::::build().internal_server_error(err) }) .map(|fc| JsonResponse::build().set_id(id).set_item(fc).ok("Success")) } @@ -42,18 +42,18 @@ pub async fn admin( ) -> Result { /// Admin function for generating compose file for specified user let id = path.0; - let stack = db::stack::fetch(pg_pool.get_ref(), id) + let project = db::project::fetch(pg_pool.get_ref(), id) .await - .map_err(|err| JsonResponse::::build().internal_server_error(err)) - .and_then(|stack| match stack { - Some(stack) => Ok(stack), - None => Err(JsonResponse::::build().not_found("not found")), + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .and_then(|project| match project { + Some(project) => Ok(project), + None => Err(JsonResponse::::build().not_found("not found")), })?; - DcBuilder::new(stack) + DcBuilder::new(project) .build() .map_err(|err| { - JsonResponse::::build().internal_server_error(err) + JsonResponse::::build().internal_server_error(err) }) .map(|fc| JsonResponse::build().set_id(id).set_item(fc).ok("Success")) } diff --git a/src/routes/project/delete.rs b/src/routes/project/delete.rs new file mode 100644 index 0000000..fb4ff33 --- /dev/null +++ b/src/routes/project/delete.rs @@ -0,0 +1,33 @@ +use crate::db; +use crate::helpers::JsonResponse; +use crate::models; +use actix_web::{delete, web, Responder, Result}; +use sqlx::PgPool; +use std::sync::Arc; +use tracing::Instrument; + +#[tracing::instrument(name = "Get logged user project.")] +#[delete("/{id}")] +pub async fn item( + user: web::ReqData>, + path: web::Path<(i32,)>, + pg_pool: web::Data, +) -> Result { + /// Get project apps of logged user only + let (id,) = path.into_inner(); + + db::project::fetch(pg_pool.get_ref(), id) + .await + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .and_then(|project| match project { + Some(project) if project.user_id != user.id => { + Err(JsonResponse::::build().not_found("not found")) + } + Some(project) => { + db::project::delete(pg_pool.get_ref(), id); + Ok(JsonResponse::build().set_item(Some(project)).ok("Deleted")) + }, + None => Err(JsonResponse::::build().not_found("not found")), + }) + +} diff --git a/src/routes/project/deploy.rs b/src/routes/project/deploy.rs new file mode 100644 index 0000000..265957a --- /dev/null +++ b/src/routes/project/deploy.rs @@ -0,0 +1,79 @@ +use crate::configuration::Settings; +use crate::db; +use crate::forms; +use crate::helpers::project::builder::DcBuilder; +use crate::helpers::{JsonResponse, MqManager}; +use crate::models; +use actix_web::{post, web, web::Data, Responder, Result}; +use sqlx::PgPool; +use std::sync::Arc; +use crate::helpers::compressor::compress; + + + +#[tracing::instrument(name = "Deploy for every user. Admin endpoint")] +#[post("/{id}/deploy")] +pub async fn add( + user: web::ReqData>, + path: web::Path<(i32,)>, + pg_pool: Data, + mq_manager: Data, + sets: Data, +) -> Result { + let id = path.0; + let project = db::project::fetch(pg_pool.get_ref(), id) + .await + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .and_then(|project| match project { + Some(project) => Ok(project), + None => Err(JsonResponse::::build().not_found("not found")), + })?; + + let id = project.id.clone(); + let dc = DcBuilder::new(project); + let fc = dc.build().map_err(|err| { + JsonResponse::::build().internal_server_error(err) + })?; + + let mut project_data = forms::project::Payload::try_from(&dc.project) + .map_err(|err| JsonResponse::::build().bad_request(err))?; + project_data.user_token = Some(user.id.clone()); + project_data.user_email = Some(user.email.clone()); + // let compressed = fc.unwrap_or("".to_string()); + project_data.docker_compose = Some(compress(fc.as_str())); + + // project_data.cloud = + // project_data.server = + + let project_id = dc.project.id.clone(); + let json_request = dc.project.body.clone(); + let deployment = models::Deployment::new( + project_id, + String::from("pending"), + json_request + ); + + let result = db::deployment::insert(pg_pool.get_ref(), deployment) + .await + .map(|deployment| deployment) + .map_err(|_| { + JsonResponse::::build().internal_server_error("Internal Server Error") + }); + + tracing::debug!("Save deployment result: {:?}", result); + + mq_manager + .publish_and_confirm( + "install".to_string(), + "install.start.tfa.all.all".to_string(), + &project_data, + ) + .await + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .map(|_| { + JsonResponse::::build() + .set_id(id) + .ok("Success") + }) + +} diff --git a/src/routes/project/get.rs b/src/routes/project/get.rs new file mode 100644 index 0000000..3cd7fc3 --- /dev/null +++ b/src/routes/project/get.rs @@ -0,0 +1,47 @@ +use crate::db; +use crate::helpers::JsonResponse; +use crate::models; +use actix_web::{get, web, Responder, Result}; +use sqlx::PgPool; +use std::sync::Arc; +use tracing::Instrument; + +#[tracing::instrument(name = "Get logged user project.")] +#[get("/{id}")] +pub async fn item( + user: web::ReqData>, + path: web::Path<(i32,)>, + pg_pool: web::Data, +) -> Result { + /// Get project apps of logged user only + let (id,) = path.into_inner(); + + db::project::fetch(pg_pool.get_ref(), id) + .await + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .and_then(|project| match project { + Some(project) if project.user_id != user.id => { + Err(JsonResponse::::build().not_found("not found")) + } + Some(project) => Ok(JsonResponse::build().set_item(Some(project)).ok("OK")), + None => Err(JsonResponse::::build().not_found("not found")), + }) +} + +#[tracing::instrument(name = "Get user's project list.")] +#[get("/user/{id}")] +pub async fn list( + user: web::ReqData>, + path: web::Path<(String,)>, + pg_pool: web::Data, +) -> Result { + /// This is admin endpoint, used by a client app, client app is confidential + /// it should return projects by user id + /// in order to pass validation at external deployment service + let user_id = path.into_inner().0; + + db::project::fetch_by_user(pg_pool.get_ref(), &user_id) + .await + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .map(|projects| JsonResponse::build().set_list(projects).ok("OK")) +} diff --git a/src/routes/stack/mod.rs b/src/routes/project/mod.rs similarity index 92% rename from src/routes/stack/mod.rs rename to src/routes/project/mod.rs index 27c8061..2d41c67 100644 --- a/src/routes/stack/mod.rs +++ b/src/routes/project/mod.rs @@ -3,6 +3,7 @@ pub mod deploy; pub mod get; pub mod update; pub(crate) mod compose; +mod delete; pub use add::*; pub use update::*; diff --git a/src/services/stack.rs b/src/routes/project/service.rs similarity index 100% rename from src/services/stack.rs rename to src/routes/project/service.rs diff --git a/src/routes/project/update.rs b/src/routes/project/update.rs new file mode 100644 index 0000000..5a8dac6 --- /dev/null +++ b/src/routes/project/update.rs @@ -0,0 +1,65 @@ +use crate::forms; +use crate::helpers::JsonResponse; +use crate::models; +use crate::db; +use actix_web::{web, web::Data, Responder, Result, post}; +use serde_json::Value; +use serde_valid::Validate; +use sqlx::PgPool; +use std::sync::Arc; +use tracing::Instrument; +use uuid::Uuid; + +#[tracing::instrument(name = "Update project.")] +#[post("/{id}")] +pub async fn update( + path: web::Path<(i32,)>, + form: web::Json, + user: web::ReqData>, + pg_pool: Data, +) -> Result { + let id = path.0; + let mut project = db::project::fetch(pg_pool.get_ref(), id) + .await + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .and_then(|project| match project { + Some(project) => Ok(project), + None => Err(JsonResponse::::build().not_found("Object not found")), + })?; + + let project_name = form.custom.custom_stack_code.clone(); + tracing::debug!("form data: {:?}", form); + let user_id = user.id.clone(); + + if let Err(errors) = form.validate() { + return Err(JsonResponse::::build().form_error(errors.to_string())); + } + + let form_inner = form.into_inner(); + + if !form_inner.is_readable_docker_image().await.is_ok() { + return Err(JsonResponse::::build().bad_request("Can not access docker image")); + } + + let body: Value = serde_json::to_value::(form_inner) + .map_err(|err| + JsonResponse::::build().bad_request(format!("{err}")) + )?; + + project.stack_id = Uuid::new_v4(); + project.user_id = user_id; + project.name = project_name; + project.body = body; + + db::project::update(pg_pool.get_ref(), project) + .await + .map(|project| { + JsonResponse::::build() + .set_item(project) + .ok("success") + }) + .map_err(|err| { + tracing::error!("Failed to execute query: {:?}", err); + JsonResponse::::build().internal_server_error("") + }) +} diff --git a/src/routes/server/add.rs b/src/routes/server/add.rs new file mode 100644 index 0000000..6dbd2d0 --- /dev/null +++ b/src/routes/server/add.rs @@ -0,0 +1,50 @@ +use crate::forms; +use crate::helpers::JsonResponse; +use crate::models; +use crate::db; +use actix_web::{post, web, Responder, Result}; +use sqlx::PgPool; +use tracing::Instrument; +use std::sync::Arc; +use serde_valid::Validate; + +// workflow +// add, update, list, get(user_id), ACL, +// ACL - access to func for a user +// ACL - access to objects for a user + +#[tracing::instrument(name = "Add server.")] +#[post("")] +pub async fn add( + user: web::ReqData>, + form: web::Json, + pg_pool: web::Data, +) -> Result { + + if !form.validate().is_ok() { + let errors = form.validate().unwrap_err().to_string(); + let err_msg = format!("Invalid data received {:?}", &errors); + tracing::debug!(err_msg); + + return Err(JsonResponse::::build().form_error(errors)); + } + + let server = db::server::fetch(pg_pool.get_ref(), form.id) + .await + .map_err(|_msg| JsonResponse::::build().internal_server_error(_msg))? + .ok_or_else(|| JsonResponse::::build().not_found("not found"))? + ; + + tracing::debug!("Server record is found ? {:?}", server); + + let mut server: models::Server = form.into_inner().into(); + server.user_id = user.id.clone(); + + db::server::insert(pg_pool.get_ref(), server) + .await + .map(|server| JsonResponse::build() + .set_item(server) + .ok("success")) + .map_err(|_err| JsonResponse::::build() + .internal_server_error("Failed to insert")) +} diff --git a/src/routes/server/get.rs b/src/routes/server/get.rs new file mode 100644 index 0000000..23bac5b --- /dev/null +++ b/src/routes/server/get.rs @@ -0,0 +1,46 @@ +use std::sync::Arc; +use crate::db; +use crate::helpers::JsonResponse; +use crate::models; +use actix_web::{get, web, Responder, Result}; +use sqlx::PgPool; +use tracing::Instrument; + +// workflow +// add, update, list, get(user_id), ACL, +// ACL - access to func for a user +// ACL - access to objects for a user + +#[tracing::instrument(name = "Get server.")] +#[get("/{id}")] +pub async fn item( + path: web::Path<(i32,)>, + pg_pool: web::Data, +) -> Result { + let id = path.0; + let server = db::server::fetch(pg_pool.get_ref(), id) + .await + .map_err(|_err| JsonResponse::::build() + .internal_server_error("")) + .and_then(|server| { + match server { + Some(server) => { Ok(server) }, + None => Err(JsonResponse::::build().not_found("object not found")) + } + })?; + + Ok(JsonResponse::build().set_item(server).ok("OK")) +} + +#[tracing::instrument(name = "Get all servers.")] +#[get("")] +pub async fn list( + path: web::Path<()>, + user: web::ReqData>, + pg_pool: web::Data, +) -> Result { + db::server::fetch_by_user(pg_pool.get_ref(), user.id.as_ref()) + .await + .map(|server| JsonResponse::build().set_list(server).ok("OK")) + .map_err(|_err| JsonResponse::::build().internal_server_error("")) +} diff --git a/src/routes/server/mod.rs b/src/routes/server/mod.rs new file mode 100644 index 0000000..d3122a3 --- /dev/null +++ b/src/routes/server/mod.rs @@ -0,0 +1,5 @@ +pub mod add; +pub(crate) mod get; + +pub use add::*; +pub use get::*; diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs deleted file mode 100644 index 712ca5a..0000000 --- a/src/routes/stack/add.rs +++ /dev/null @@ -1,78 +0,0 @@ -use crate::db; -use crate::forms; -use crate::helpers::JsonResponse; -use crate::models; -use actix_web::Error; -use actix_web::{ - post, web, - web::{Bytes, Data}, - Responder, Result, -}; -use serde_json::Value; -use serde_valid::Validate; -use sqlx::PgPool; -use std::str; -use std::sync::Arc; - -#[tracing::instrument(name = "Add stack.")] -#[post("")] -pub async fn add( - body: Bytes, - user: web::ReqData>, - pg_pool: Data, -) -> Result { - // @todo ACL - let form = body_into_form(body).await?; - let stack_name = form.custom.custom_stack_code.clone(); - - stack_exists(pg_pool.get_ref(), &stack_name).await?; - - let body: Value = serde_json::to_value::(form) - .or(serde_json::to_value::(forms::stack::Stack::default())) - .unwrap(); - - let stack = models::Stack::new(user.id.clone(), stack_name, body); - db::stack::insert(pg_pool.get_ref(), stack) - .await - .map(|stack| JsonResponse::build().set_item(stack).ok("Ok")) - .map_err(|_| { - JsonResponse::::build().internal_server_error("Internal Server Error") - }) -} - - -async fn stack_exists(pool: &PgPool, stack_name: &String) -> Result<(), Error> { - db::stack::fetch_one_by_name(pool, stack_name) - .await - .map_err(|_| { - JsonResponse::::build().internal_server_error("Internal Server Error") - }) - .and_then(|stack| match stack { - Some(_) => Err(JsonResponse::::build() - .conflict("Stack with that name already exists")), - None => Ok(()), - }) -} - -async fn body_into_form(body: Bytes) -> Result { - let body_bytes = actix_web::body::to_bytes(body).await.unwrap(); - let body_str = str::from_utf8(&body_bytes) - .map_err(|err| JsonResponse::::build().internal_server_error(err.to_string()))?; - let deserializer = &mut serde_json::Deserializer::from_str(body_str); - serde_path_to_error::deserialize(deserializer) - .map_err(|err| { - let msg = format!("{}:{:?}", err.path().to_string(), err); - JsonResponse::::build().bad_request(msg) - }) - .and_then(|form: forms::stack::Stack| { - if !form.validate().is_ok() { - let errors = form.validate().unwrap_err().to_string(); - let err_msg = format!("Invalid data received {:?}", &errors); - tracing::debug!(err_msg); - - return Err(JsonResponse::::build().form_error(errors)); - } - - Ok(form) - }) -} diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs deleted file mode 100644 index a2bf869..0000000 --- a/src/routes/stack/deploy.rs +++ /dev/null @@ -1,58 +0,0 @@ -use crate::configuration::Settings; -use crate::db; -use crate::forms; -use crate::helpers::stack::builder::DcBuilder; -use crate::helpers::{JsonResponse, MqManager}; -use crate::models; -use actix_web::{post, web, web::Data, Responder, Result}; -use lapin::publisher_confirm::Confirmation; -use sqlx::PgPool; -use std::sync::Arc; -use crate::helpers::compressor::compress; - - -#[tracing::instrument(name = "Deploy for every user. Admin endpoint")] -#[post("/{id}/deploy")] -pub async fn add( - user: web::ReqData>, - path: web::Path<(i32,)>, - pg_pool: Data, - mq_manager: Data, - sets: Data, -) -> Result { - let id = path.0; - let stack = db::stack::fetch(pg_pool.get_ref(), id) - .await - .map_err(|err| JsonResponse::::build().internal_server_error(err)) - .and_then(|stack| match stack { - Some(stack) => Ok(stack), - None => Err(JsonResponse::::build().not_found("not found")), - })?; - - let id = stack.id.clone(); - let dc = DcBuilder::new(stack); - let fc = dc.build().map_err(|err| { - JsonResponse::::build().internal_server_error(err) - })?; - - let mut stack_data = forms::stack::Payload::try_from(&dc.stack) - .map_err(|err| JsonResponse::::build().bad_request(err))?; - stack_data.user_token = Some(user.id.clone()); - stack_data.user_email = Some(user.email.clone()); - // let compressed = fc.unwrap_or("".to_string()); - stack_data.docker_compose = Some(compress(fc.as_str())); - - mq_manager - .publish_and_confirm( - "install".to_string(), - "install.start.tfa.all.all".to_string(), - &stack_data, - ) - .await - .map_err(|err| JsonResponse::::build().internal_server_error(err)) - .map(|_| { - JsonResponse::::build() - .set_id(id) - .ok("Success") - }) -} diff --git a/src/routes/stack/get.rs b/src/routes/stack/get.rs deleted file mode 100644 index ccb9c9d..0000000 --- a/src/routes/stack/get.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::db; -use crate::helpers::JsonResponse; -use crate::models; -use actix_web::{get, web, Responder, Result}; -use sqlx::PgPool; -use std::convert::From; -use std::sync::Arc; -use tracing::Instrument; - -#[tracing::instrument(name = "Get logged user stack.")] -#[get("/{id}")] -pub async fn item( - user: web::ReqData>, - path: web::Path<(i32,)>, - pg_pool: web::Data, -) -> Result { - /// Get stack apps of logged user only - let (id,) = path.into_inner(); - - db::stack::fetch(pg_pool.get_ref(), id) - .await - .map_err(|err| JsonResponse::::build().internal_server_error(err)) - .and_then(|stack| match stack { - Some(stack) if stack.user_id != user.id => { - Err(JsonResponse::::build().not_found("not found")) - } - Some(stack) => Ok(JsonResponse::build().set_item(Some(stack)).ok("OK")), - None => Err(JsonResponse::::build().not_found("not found")), - }) -} - -#[tracing::instrument(name = "Get user's stack list.")] -#[get("/user/{id}")] -pub async fn list( - user: web::ReqData>, - path: web::Path<(String,)>, - pg_pool: web::Data, -) -> Result { - /// This is admin endpoint, used by a client app, client app is confidential - /// it should return stacks by user id - /// in order to pass validation at external deployment service - let user_id = path.into_inner().0; - - db::stack::fetch_by_user(pg_pool.get_ref(), &user_id) - .await - .map_err(|err| JsonResponse::::build().internal_server_error(err)) - .map(|stacks| JsonResponse::build().set_list(stacks).ok("OK")) -} diff --git a/src/routes/stack/update.rs b/src/routes/stack/update.rs deleted file mode 100644 index ef11d82..0000000 --- a/src/routes/stack/update.rs +++ /dev/null @@ -1,65 +0,0 @@ -use crate::forms; -use crate::helpers::JsonResponse; -use crate::models; -use crate::db; -use actix_web::{web, web::Data, Responder, Result, post}; -use serde_json::Value; -use serde_valid::Validate; -use sqlx::PgPool; -use std::sync::Arc; -use tracing::Instrument; -use uuid::Uuid; - -#[tracing::instrument(name = "Update stack.")] -#[post("/{id}")] -pub async fn update( - path: web::Path<(i32,)>, - form: web::Json, - user: web::ReqData>, - pg_pool: Data, -) -> Result { - let id = path.0; - let mut stack = db::stack::fetch(pg_pool.get_ref(), id) - .await - .map_err(|err| JsonResponse::::build().internal_server_error(err)) - .and_then(|stack| match stack { - Some(stack) => Ok(stack), - None => Err(JsonResponse::::build().not_found("Object not found")), - })?; - - let stack_name = form.custom.custom_stack_code.clone(); - tracing::debug!("form data: {:?}", form); - let user_id = user.id.clone(); - - if let Err(errors) = form.validate() { - return Err(JsonResponse::::build().form_error(errors.to_string())); - } - - let form_inner = form.into_inner(); - - if !form_inner.is_readable_docker_image().await.is_ok() { - return Err(JsonResponse::::build().bad_request("Can not access docker image")); - } - - let body: Value = serde_json::to_value::(form_inner) - .map_err(|err| - JsonResponse::::build().bad_request(format!("{err}")) - )?; - - stack.stack_id = Uuid::new_v4(); - stack.user_id = user_id; - stack.name = stack_name; - stack.body = body; - - db::stack::update(pg_pool.get_ref(), stack) - .await - .map(|stack| { - JsonResponse::::build() - .set_item(stack) - .ok("success") - }) - .map_err(|err| { - tracing::error!("Failed to execute query: {:?}", err); - JsonResponse::::build().internal_server_error("") - }) -} diff --git a/src/services/mod.rs b/src/services/mod.rs index f61186f..94b4efc 100644 --- a/src/services/mod.rs +++ b/src/services/mod.rs @@ -1,2 +1,2 @@ -pub mod stack; +pub mod project; mod rating; \ No newline at end of file diff --git a/src/services/project.rs b/src/services/project.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/services/rating.rs b/src/services/rating.rs index 8222221..837be7b 100644 --- a/src/services/rating.rs +++ b/src/services/rating.rs @@ -1,6 +1,6 @@ -use crate::models::rating::Rating; -use tracing::Instrument; -use tracing_subscriber::fmt::format; +// use crate::models::rating::Rating; +// use tracing::Instrument; +// use tracing_subscriber::fmt::format; // impl Rating { // pub async fn filter_by(query_string: &str, pool: PgPool) -> Result<()> { diff --git a/src/startup.rs b/src/startup.rs index 3548192..e489cb9 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -66,18 +66,38 @@ pub async fn run( .service(crate::routes::rating::list_handler), ) .service( - web::scope("/stack") + web::scope("/project") .wrap(HttpAuthentication::bearer( middleware::trydirect::bearer_guard, )) .wrap(Cors::permissive()) - .service(crate::routes::stack::deploy::add) - .service(crate::routes::stack::compose::add) - .service(crate::routes::stack::compose::admin) - .service(crate::routes::stack::get::item) - .service(crate::routes::stack::get::list) - .service(crate::routes::stack::add::add) - .service(crate::routes::stack::update::update), + .service(crate::routes::project::deploy::add) + .service(crate::routes::project::compose::add) + .service(crate::routes::project::compose::admin) + .service(crate::routes::project::get::item) + .service(crate::routes::project::get::list) + .service(crate::routes::project::add::add) + .service(crate::routes::project::update::update), + ) + .service( + web::scope("/cloud") + .wrap(HttpAuthentication::bearer( + middleware::trydirect::bearer_guard, + )) + .wrap(Cors::permissive()) + .service(crate::routes::cloud::get::item) + .service(crate::routes::cloud::get::list) + .service(crate::routes::cloud::add::add) + ) + .service( + web::scope("/server") + .wrap(HttpAuthentication::bearer( + middleware::trydirect::bearer_guard, + )) + .wrap(Cors::permissive()) + .service(crate::routes::server::get::item) + .service(crate::routes::server::get::list) + .service(crate::routes::server::add::add) ) .app_data(pg_pool.clone()) .app_data(mq_manager.clone()) diff --git a/tests/dockerhub.rs b/tests/dockerhub.rs index 200b665..4134309 100644 --- a/tests/dockerhub.rs +++ b/tests/dockerhub.rs @@ -2,8 +2,8 @@ // use std::collections::HashMap; use std::env; mod common; -use stacker::forms::stack::DockerImage; -use stacker::helpers::stack::dctypes::{ComposeVolume, SingleValue}; +use stacker::forms::project::DockerImage; +use stacker::helpers::project::dctypes::{ComposeVolume, SingleValue}; use serde_yaml; use stacker::forms::Volume; @@ -12,7 +12,7 @@ const DOCKER_PASSWORD: &str = "***************"; // Unit Test // #[test] -// fn test_deserialize_user_stack_web() { +// fn test_deserialize_project_web() { // // let body_str = fs::read_to_string("./tests/web-item.json").unwrap(); // // let form:serde_json::Value = serde_json::from_str(&body_str).unwrap(); @@ -24,17 +24,17 @@ const DOCKER_PASSWORD: &str = "***************"; // // } // // Err(_err) => { // // let msg = format!("Invalid data. {:?}", _err); -// // return JsonResponse::::build().bad_request(msg); +// // return JsonResponse::::build().bad_request(msg); // // } // // }; // // // // assert_eq!(result, 12); // } // #[test] -// fn test_deserialize_user_stack() { +// fn test_deserialize_project() { // -// let body_str = fs::read_to_string("./tests/custom-stack-payload-11.json").unwrap(); -// let form = serde_json::from_str::(&body_str).unwrap(); +// let body_str = fs::read_to_string("./tests/custom-project-payload-11.json").unwrap(); +// let form = serde_json::from_str::(&body_str).unwrap(); // println!("{:?}", form); // // @todo assert required data // @@ -44,7 +44,7 @@ const DOCKER_PASSWORD: &str = "***************"; // // } // // Err(_err) => { // // let msg = format!("Invalid data. {:?}", _err); -// // return JsonResponse::::build().bad_request(msg); +// // return JsonResponse::::build().bad_request(msg); // // } // // }; // // @@ -122,6 +122,6 @@ async fn test_docker_named_volume() { println!("ComposeVolume: {:?}", cv); println!("{:?}", cv.driver_opts); assert_eq!(Some("flask-data".to_string()), cv.name); - assert_eq!(&Some(SingleValue::String("/root/stack/flask-data".to_string())), cv.driver_opts.get("device").unwrap()); + assert_eq!(&Some(SingleValue::String("/root/project/flask-data".to_string())), cv.driver_opts.get("device").unwrap()); assert_eq!(&Some(SingleValue::String("none".to_string())), cv.driver_opts.get("type").unwrap()); } diff --git a/tests/model_user_stack.rs b/tests/model_user_stack.rs index 88a005b..e5fd40d 100644 --- a/tests/model_user_stack.rs +++ b/tests/model_user_stack.rs @@ -1,13 +1,13 @@ -use stacker::forms::stack::StackForm; -use stacker::forms::stack::DockerImage; -use stacker::forms::stack::App; +use stacker::forms::project::ProjectForm; +use stacker::forms::project::DockerImage; +use stacker::forms::project::App; use std::fs; use std::collections::HashMap; // Unit Test // #[test] -// fn test_deserialize_user_stack_web() { +// fn test_deserialize_project_web() { // // let body_str = fs::read_to_string("./tests/web-item.json").unwrap(); // // let form:serde_json::Value = serde_json::from_str(&body_str).unwrap(); @@ -19,17 +19,17 @@ use std::collections::HashMap; // // } // // Err(_err) => { // // let msg = format!("Invalid data. {:?}", _err); -// // return JsonResponse::::build().bad_request(msg); +// // return JsonResponse::::build().bad_request(msg); // // } // // }; // // // // assert_eq!(result, 12); // } #[test] -fn test_deserialize_user_stack() { +fn test_deserialize_project() { - let body_str = fs::read_to_string("./tests/custom-stack-payload-11.json").unwrap(); - let form = serde_json::from_str::(&body_str).unwrap(); + let body_str = fs::read_to_string("./tests/custom-project-payload-11.json").unwrap(); + let form = serde_json::from_str::(&body_str).unwrap(); println!("{:?}", form); // @todo assert required data @@ -39,7 +39,7 @@ fn test_deserialize_user_stack() { // } // Err(_err) => { // let msg = format!("Invalid data. {:?}", _err); - // return JsonResponse::::build().bad_request(msg); + // return JsonResponse::::build().bad_request(msg); // } // }; // From 0b5f0507e37e62434a6d230d5a17b1b2644bd562 Mon Sep 17 00:00:00 2001 From: vsilent Date: Thu, 29 Feb 2024 15:43:13 +0200 Subject: [PATCH 194/284] fix Dockerfile, add casbin config, delete dctypes files use requirement --- Dockerfile | 1 + docker/local/configuration.yaml | 2 + .../project/dctypes/advanced_build_step.rs | 23 -- .../dctypes/advanced_network_settings.rs | 12 - .../project/dctypes/advanced_networks.rs | 13 - src/helpers/project/dctypes/build_args.rs | 16 - src/helpers/project/dctypes/build_step.rs | 9 - src/helpers/project/dctypes/compose.rs | 25 -- src/helpers/project/dctypes/compose_file.rs | 18 - .../project/dctypes/compose_network.rs | 9 - .../compose_network_setting_details.rs | 7 - .../project/dctypes/compose_networks.rs | 19 - src/helpers/project/dctypes/compose_volume.rs | 22 -- .../project/dctypes/depends_condition.rs | 6 - .../project/dctypes/depends_on_options.rs | 30 -- src/helpers/project/dctypes/env_file.rs | 9 - src/helpers/project/dctypes/environment.rs | 30 -- src/helpers/project/dctypes/extension.rs | 28 -- .../project/dctypes/extension_parse_error.rs | 15 - .../dctypes/external_network_setting_bool.rs | 5 - .../project/dctypes/external_volume.rs | 8 - src/helpers/project/dctypes/ipam.rs | 12 - src/helpers/project/dctypes/ipam_config.rs | 9 - src/helpers/project/dctypes/labels.rs | 31 -- .../project/dctypes/logging_parameters.rs | 15 - src/helpers/project/dctypes/mod.rs | 326 ------------------ .../project/dctypes/network_settings.rs | 29 -- src/helpers/project/dctypes/networks.rs | 24 -- src/helpers/project/dctypes/port.rs | 53 --- src/helpers/project/dctypes/ports.rs | 25 -- src/helpers/project/dctypes/published_port.rs | 8 - src/helpers/project/dctypes/service.rs | 120 ------- src/helpers/project/dctypes/services.rs | 19 - src/helpers/project/dctypes/single_service.rs | 8 - src/helpers/project/dctypes/sys_ctls.rs | 30 -- src/helpers/project/dctypes/tmpfs.rs | 9 - .../project/dctypes/top_level_volumes.rs | 19 - src/helpers/project/dctypes/ulimit.rs | 8 - src/helpers/project/dctypes/ulimits.rs | 20 -- .../{model_user_stack.rs => model_project.rs} | 0 40 files changed, 3 insertions(+), 1069 deletions(-) delete mode 100644 src/helpers/project/dctypes/advanced_build_step.rs delete mode 100644 src/helpers/project/dctypes/advanced_network_settings.rs delete mode 100644 src/helpers/project/dctypes/advanced_networks.rs delete mode 100644 src/helpers/project/dctypes/build_args.rs delete mode 100644 src/helpers/project/dctypes/build_step.rs delete mode 100644 src/helpers/project/dctypes/compose.rs delete mode 100644 src/helpers/project/dctypes/compose_file.rs delete mode 100644 src/helpers/project/dctypes/compose_network.rs delete mode 100644 src/helpers/project/dctypes/compose_network_setting_details.rs delete mode 100644 src/helpers/project/dctypes/compose_networks.rs delete mode 100644 src/helpers/project/dctypes/compose_volume.rs delete mode 100644 src/helpers/project/dctypes/depends_condition.rs delete mode 100644 src/helpers/project/dctypes/depends_on_options.rs delete mode 100644 src/helpers/project/dctypes/env_file.rs delete mode 100644 src/helpers/project/dctypes/environment.rs delete mode 100644 src/helpers/project/dctypes/extension.rs delete mode 100644 src/helpers/project/dctypes/extension_parse_error.rs delete mode 100644 src/helpers/project/dctypes/external_network_setting_bool.rs delete mode 100644 src/helpers/project/dctypes/external_volume.rs delete mode 100644 src/helpers/project/dctypes/ipam.rs delete mode 100644 src/helpers/project/dctypes/ipam_config.rs delete mode 100644 src/helpers/project/dctypes/labels.rs delete mode 100644 src/helpers/project/dctypes/logging_parameters.rs delete mode 100644 src/helpers/project/dctypes/mod.rs delete mode 100644 src/helpers/project/dctypes/network_settings.rs delete mode 100644 src/helpers/project/dctypes/networks.rs delete mode 100644 src/helpers/project/dctypes/port.rs delete mode 100644 src/helpers/project/dctypes/ports.rs delete mode 100644 src/helpers/project/dctypes/published_port.rs delete mode 100644 src/helpers/project/dctypes/service.rs delete mode 100644 src/helpers/project/dctypes/services.rs delete mode 100644 src/helpers/project/dctypes/single_service.rs delete mode 100644 src/helpers/project/dctypes/sys_ctls.rs delete mode 100644 src/helpers/project/dctypes/tmpfs.rs delete mode 100644 src/helpers/project/dctypes/top_level_volumes.rs delete mode 100644 src/helpers/project/dctypes/ulimit.rs delete mode 100644 src/helpers/project/dctypes/ulimits.rs rename tests/{model_user_stack.rs => model_project.rs} (100%) diff --git a/Dockerfile b/Dockerfile index c068fc2..34fa4b0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -54,6 +54,7 @@ COPY --from=builder /app/target/release/server . COPY --from=builder /app/.env . COPY --from=builder /app/configuration.yaml . COPY --from=builder /usr/local/cargo/bin/sqlx sqlx +COPY ./access_control.conf.dist /app EXPOSE 8000 diff --git a/docker/local/configuration.yaml b/docker/local/configuration.yaml index a0bb4c0..750f1cb 100644 --- a/docker/local/configuration.yaml +++ b/docker/local/configuration.yaml @@ -1,6 +1,8 @@ app_host: 0.0.0.0 app_port: 8000 auth_url: https://dev.try.direct/server/user/oauth_server/api/me +max_clients_number: 2 + database: host: 172.17.0.2 port: 5432 diff --git a/src/helpers/project/dctypes/advanced_build_step.rs b/src/helpers/project/dctypes/advanced_build_step.rs deleted file mode 100644 index 41f2f0c..0000000 --- a/src/helpers/project/dctypes/advanced_build_step.rs +++ /dev/null @@ -1,23 +0,0 @@ -use serde::{Deserialize, Serialize}; -use crate::helpers::project::dctypes::*; - -#[derive(Builder, Clone, Debug, Deserialize, Serialize, Eq, PartialEq, Default)] -#[serde(deny_unknown_fields)] -#[builder(setter(into), default)] -pub struct AdvancedBuildStep { - pub context: String, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub dockerfile: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub args: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub shm_size: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub target: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub network: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub cache_from: Vec, - #[serde(default, skip_serializing_if = "Labels::is_empty")] - pub labels: Labels, -} diff --git a/src/helpers/project/dctypes/advanced_network_settings.rs b/src/helpers/project/dctypes/advanced_network_settings.rs deleted file mode 100644 index 730c9cb..0000000 --- a/src/helpers/project/dctypes/advanced_network_settings.rs +++ /dev/null @@ -1,12 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, Default, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(deny_unknown_fields)] -pub struct AdvancedNetworkSettings { - #[serde(skip_serializing_if = "Option::is_none")] - pub ipv4_address: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub ipv6_address: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub aliases: Vec, -} diff --git a/src/helpers/project/dctypes/advanced_networks.rs b/src/helpers/project/dctypes/advanced_networks.rs deleted file mode 100644 index 2b4f0b0..0000000 --- a/src/helpers/project/dctypes/advanced_networks.rs +++ /dev/null @@ -1,13 +0,0 @@ -use serde::{Deserialize, Serialize}; -#[cfg(feature = "indexmap")] -use indexmap::IndexMap; -#[cfg(not(feature = "indexmap"))] -use std::collections::HashMap; -use crate::helpers::project::dctypes::*; - -#[cfg(feature = "indexmap")] -#[derive(Clone, Default, Debug, Serialize, Deserialize, Eq, PartialEq)] -pub struct AdvancedNetworks(pub IndexMap>); -#[cfg(not(feature = "indexmap"))] -#[derive(Clone, Default, Debug, Serialize, Deserialize, Eq, PartialEq)] -pub struct AdvancedNetworks(pub HashMap>); diff --git a/src/helpers/project/dctypes/build_args.rs b/src/helpers/project/dctypes/build_args.rs deleted file mode 100644 index 8f62966..0000000 --- a/src/helpers/project/dctypes/build_args.rs +++ /dev/null @@ -1,16 +0,0 @@ -use serde::{Deserialize, Serialize}; -#[cfg(feature = "indexmap")] -use indexmap::IndexMap; -#[cfg(not(feature = "indexmap"))] -use std::collections::HashMap; - -#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] -#[serde(untagged)] -pub enum BuildArgs { - Simple(String), - List(Vec), - #[cfg(feature = "indexmap")] - KvPair(IndexMap), - #[cfg(not(feature = "indexmap"))] - KvPair(HashMap), -} diff --git a/src/helpers/project/dctypes/build_step.rs b/src/helpers/project/dctypes/build_step.rs deleted file mode 100644 index 3c1fc49..0000000 --- a/src/helpers/project/dctypes/build_step.rs +++ /dev/null @@ -1,9 +0,0 @@ -use serde::{Deserialize, Serialize}; -use crate::helpers::project::dctypes; - -#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] -#[serde(untagged)] -pub enum BuildStep { - Simple(String), - Advanced(dctypes::AdvancedBuildStep), -} diff --git a/src/helpers/project/dctypes/compose.rs b/src/helpers/project/dctypes/compose.rs deleted file mode 100644 index 4bee50a..0000000 --- a/src/helpers/project/dctypes/compose.rs +++ /dev/null @@ -1,25 +0,0 @@ -use serde::{Deserialize, Serialize}; -use crate::helpers::project::dctypes::*; -#[cfg(feature = "indexmap")] -use indexmap::IndexMap; -use serde_yaml::Value; - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)] -pub struct Compose { - #[serde(skip_serializing_if = "Option::is_none")] - pub version: Option, - #[serde(default, skip_serializing_if = "Services::is_empty")] - pub services: Services, - #[serde(default, skip_serializing_if = "TopLevelVolumes::is_empty")] - pub volumes: TopLevelVolumes, - #[serde(default, skip_serializing_if = "ComposeNetworks::is_empty")] - pub networks: ComposeNetworks, - #[serde(skip_serializing_if = "Option::is_none")] - pub service: Option, - #[cfg(feature = "indexmap")] - #[serde(flatten, skip_serializing_if = "IndexMap::is_empty")] - pub extensions: IndexMap, - #[cfg(not(feature = "indexmap"))] - #[serde(flatten, skip_serializing_if = "HashMap::is_empty")] - pub extensions: HashMap, -} diff --git a/src/helpers/project/dctypes/compose_file.rs b/src/helpers/project/dctypes/compose_file.rs deleted file mode 100644 index 79abe91..0000000 --- a/src/helpers/project/dctypes/compose_file.rs +++ /dev/null @@ -1,18 +0,0 @@ -use serde::{Deserialize, Serialize}; -use crate::helpers::project::dctypes; - -#[cfg(feature = "indexmap")] -use indexmap::IndexMap; - -#[allow(clippy::large_enum_variant)] -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -#[serde(untagged)] -pub enum ComposeFile { - V2Plus(dctypes::Compose), - #[cfg(feature = "indexmap")] - V1(IndexMap), - #[cfg(not(feature = "indexmap"))] - V1(HashMap), - Single(dctypes::SingleService), -} - diff --git a/src/helpers/project/dctypes/compose_network.rs b/src/helpers/project/dctypes/compose_network.rs deleted file mode 100644 index 56d3de1..0000000 --- a/src/helpers/project/dctypes/compose_network.rs +++ /dev/null @@ -1,9 +0,0 @@ -use serde::{Deserialize, Serialize}; -use crate::helpers::project::dctypes::*; - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(untagged)] -pub enum ComposeNetwork { - Detailed(ComposeNetworkSettingDetails), - Bool(bool), -} diff --git a/src/helpers/project/dctypes/compose_network_setting_details.rs b/src/helpers/project/dctypes/compose_network_setting_details.rs deleted file mode 100644 index 59d0348..0000000 --- a/src/helpers/project/dctypes/compose_network_setting_details.rs +++ /dev/null @@ -1,7 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(deny_unknown_fields)] -pub struct ComposeNetworkSettingDetails { - pub name: String, -} diff --git a/src/helpers/project/dctypes/compose_networks.rs b/src/helpers/project/dctypes/compose_networks.rs deleted file mode 100644 index da6aae1..0000000 --- a/src/helpers/project/dctypes/compose_networks.rs +++ /dev/null @@ -1,19 +0,0 @@ -#[cfg(feature = "indexmap")] -use indexmap::IndexMap; -#[cfg(not(feature = "indexmap"))] -use std::collections::HashMap; -use serde::{Deserialize, Serialize}; -use crate::helpers::project::dctypes::*; - -#[cfg(feature = "indexmap")] -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] -pub struct ComposeNetworks(pub IndexMap>); -#[cfg(not(feature = "indexmap"))] -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] -pub struct ComposeNetworks(pub HashMap>); - -impl ComposeNetworks { - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } -} diff --git a/src/helpers/project/dctypes/compose_volume.rs b/src/helpers/project/dctypes/compose_volume.rs deleted file mode 100644 index 644b67c..0000000 --- a/src/helpers/project/dctypes/compose_volume.rs +++ /dev/null @@ -1,22 +0,0 @@ -use serde::{Deserialize, Serialize}; -use crate::helpers::project::dctypes::*; -#[cfg(feature = "indexmap")] -use indexmap::IndexMap; -#[cfg(not(feature = "indexmap"))] -use std::collections::HashMap; - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -pub struct ComposeVolume { - #[serde(skip_serializing_if = "Option::is_none")] - pub driver: Option, - #[cfg(feature = "indexmap")] - #[serde(default, skip_serializing_if = "IndexMap::is_empty")] - pub driver_opts: IndexMap>, - #[serde(skip_serializing_if = "Option::is_none")] - pub external: Option, - #[serde(default, skip_serializing_if = "Labels::is_empty")] - pub labels: Labels, - #[serde(skip_serializing_if = "Option::is_none")] - pub name: Option, -} - diff --git a/src/helpers/project/dctypes/depends_condition.rs b/src/helpers/project/dctypes/depends_condition.rs deleted file mode 100644 index 863c7b5..0000000 --- a/src/helpers/project/dctypes/depends_condition.rs +++ /dev/null @@ -1,6 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -pub struct DependsCondition { - pub condition: String, -} diff --git a/src/helpers/project/dctypes/depends_on_options.rs b/src/helpers/project/dctypes/depends_on_options.rs deleted file mode 100644 index fbf7911..0000000 --- a/src/helpers/project/dctypes/depends_on_options.rs +++ /dev/null @@ -1,30 +0,0 @@ -use serde::{Deserialize, Serialize}; -#[cfg(feature = "indexmap")] -use indexmap::IndexMap; -use crate::helpers::project::dctypes; - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] -#[serde(untagged)] -pub enum DependsOnOptions { - Simple(Vec), - #[cfg(feature = "indexmap")] - Conditional(IndexMap), - #[cfg(not(feature = "indexmap"))] - Conditional(HashMap), -} - -impl Default for DependsOnOptions { - fn default() -> Self { - Self::Simple(Vec::new()) - } -} - -impl DependsOnOptions { - pub fn is_empty(&self) -> bool { - match self { - Self::Simple(v) => v.is_empty(), - Self::Conditional(m) => m.is_empty(), - } - } -} - diff --git a/src/helpers/project/dctypes/env_file.rs b/src/helpers/project/dctypes/env_file.rs deleted file mode 100644 index 643d6b9..0000000 --- a/src/helpers/project/dctypes/env_file.rs +++ /dev/null @@ -1,9 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(untagged)] -pub enum EnvFile { - Simple(String), - List(Vec), -} - diff --git a/src/helpers/project/dctypes/environment.rs b/src/helpers/project/dctypes/environment.rs deleted file mode 100644 index a04f992..0000000 --- a/src/helpers/project/dctypes/environment.rs +++ /dev/null @@ -1,30 +0,0 @@ -use serde::{Deserialize, Serialize}; -use serde_yaml::Value; -#[cfg(feature = "indexmap")] -use indexmap::IndexMap; -use crate::helpers::project::dctypes; - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -#[serde(untagged)] -pub enum Environment { - List(Vec), - #[cfg(feature = "indexmap")] - KvPair(IndexMap>), - #[cfg(not(feature = "indexmap"))] - KvPair(HashMap>), -} - -impl Default for Environment { - fn default() -> Self { - Self::List(Vec::new()) - } -} - -impl Environment { - pub fn is_empty(&self) -> bool { - match self { - Self::List(v) => v.is_empty(), - Self::KvPair(m) => m.is_empty(), - } - } -} diff --git a/src/helpers/project/dctypes/extension.rs b/src/helpers/project/dctypes/extension.rs deleted file mode 100644 index 1c0b412..0000000 --- a/src/helpers/project/dctypes/extension.rs +++ /dev/null @@ -1,28 +0,0 @@ -use serde::{Deserialize, Serialize}; -use crate::helpers::project::dctypes; -use std::str::FromStr; - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash, Default, Ord, PartialOrd)] -#[serde(try_from = "String")] -pub struct Extension(String); - -impl FromStr for Extension { - type Err = dctypes::ExtensionParseError; - - fn from_str(s: &str) -> Result { - let owned = s.to_owned(); - Extension::try_from(owned) - } -} - -impl TryFrom for Extension { - type Error = dctypes::ExtensionParseError; - - fn try_from(s: String) -> Result { - if s.starts_with("x-") { - Ok(Self(s)) - } else { - Err(dctypes::ExtensionParseError(s)) - } - } -} diff --git a/src/helpers/project/dctypes/extension_parse_error.rs b/src/helpers/project/dctypes/extension_parse_error.rs deleted file mode 100644 index 9fcec51..0000000 --- a/src/helpers/project/dctypes/extension_parse_error.rs +++ /dev/null @@ -1,15 +0,0 @@ -use std::fmt; - -/// The result of a failed TryFrom conversion for [`Extension`] -/// -/// Contains the string that was being converted -#[derive(Clone, Debug, Eq, PartialEq, Hash)] -pub struct ExtensionParseError(pub String); - -impl fmt::Display for ExtensionParseError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "unknown attribute {:?}, extensions must start with 'x-' (see https://docs.docker.com/compose/compose-file/#extension)", self.0) - } -} - -impl std::error::Error for ExtensionParseError {} diff --git a/src/helpers/project/dctypes/external_network_setting_bool.rs b/src/helpers/project/dctypes/external_network_setting_bool.rs deleted file mode 100644 index 1d1ad3d..0000000 --- a/src/helpers/project/dctypes/external_network_setting_bool.rs +++ /dev/null @@ -1,5 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(deny_unknown_fields)] -pub struct ExternalNetworkSettingBool(bool); diff --git a/src/helpers/project/dctypes/external_volume.rs b/src/helpers/project/dctypes/external_volume.rs deleted file mode 100644 index ba03e26..0000000 --- a/src/helpers/project/dctypes/external_volume.rs +++ /dev/null @@ -1,8 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -#[serde(untagged)] -pub enum ExternalVolume { - Bool(bool), - Name { name: String }, -} diff --git a/src/helpers/project/dctypes/ipam.rs b/src/helpers/project/dctypes/ipam.rs deleted file mode 100644 index 99e8b1f..0000000 --- a/src/helpers/project/dctypes/ipam.rs +++ /dev/null @@ -1,12 +0,0 @@ -use serde::{Deserialize, Serialize}; -use crate::helpers::project::dctypes::*; - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(deny_unknown_fields)] -pub struct Ipam { - #[serde(skip_serializing_if = "Option::is_none")] - pub driver: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub config: Vec, -} - diff --git a/src/helpers/project/dctypes/ipam_config.rs b/src/helpers/project/dctypes/ipam_config.rs deleted file mode 100644 index f40c2f5..0000000 --- a/src/helpers/project/dctypes/ipam_config.rs +++ /dev/null @@ -1,9 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(deny_unknown_fields)] -pub struct IpamConfig { - pub subnet: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub gateway: Option, -} diff --git a/src/helpers/project/dctypes/labels.rs b/src/helpers/project/dctypes/labels.rs deleted file mode 100644 index e4296af..0000000 --- a/src/helpers/project/dctypes/labels.rs +++ /dev/null @@ -1,31 +0,0 @@ -use serde::{Deserialize, Serialize}; -#[cfg(feature = "indexmap")] -use indexmap::IndexMap; -#[cfg(not(feature = "indexmap"))] -use std::collections::HashMap; - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] -#[serde(untagged)] -pub enum Labels { - List(Vec), - #[cfg(feature = "indexmap")] - Map(IndexMap), - #[cfg(not(feature = "indexmap"))] - Map(HashMap), -} - -impl Default for Labels { - fn default() -> Self { - Self::List(Vec::new()) - } -} - -impl Labels { - pub fn is_empty(&self) -> bool { - match self { - Self::List(v) => v.is_empty(), - Self::Map(m) => m.is_empty(), - } - } -} - diff --git a/src/helpers/project/dctypes/logging_parameters.rs b/src/helpers/project/dctypes/logging_parameters.rs deleted file mode 100644 index a0068c7..0000000 --- a/src/helpers/project/dctypes/logging_parameters.rs +++ /dev/null @@ -1,15 +0,0 @@ -use serde::{Deserialize, Serialize}; -#[cfg(feature = "indexmap")] -use indexmap::IndexMap; -use crate::helpers::project::dctypes; - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -pub struct LoggingParameters { - pub driver: String, - #[cfg(feature = "indexmap")] - #[serde(skip_serializing_if = "Option::is_none")] - pub options: Option>, - #[cfg(not(feature = "indexmap"))] - #[serde(skip_serializing_if = "Option::is_none")] - pub options: Option>, -} diff --git a/src/helpers/project/dctypes/mod.rs b/src/helpers/project/dctypes/mod.rs deleted file mode 100644 index 093c7f1..0000000 --- a/src/helpers/project/dctypes/mod.rs +++ /dev/null @@ -1,326 +0,0 @@ -mod port; -mod published_port; -mod compose_file; -mod single_service; -mod service; -mod sys_ctls; -mod compose; -mod env_file; -mod depends_on_options; -mod depends_condition; -mod logging_parameters; -mod ports; -mod environment; -mod extension; -mod extension_parse_error; -mod services; -mod labels; -mod tmpfs; -mod ulimit; -mod ulimits; -mod networks; -mod build_step; -mod advanced_build_step; -mod build_args; -mod advanced_networks; -mod advanced_network_settings; -mod top_level_volumes; -mod compose_volume; -mod external_volume; -mod compose_network; -mod compose_networks; -mod compose_network_setting_details; -mod external_network_setting_bool; -mod network_settings; -mod ipam; -mod ipam_config; - -pub use port::*; -pub use published_port::*; -pub use compose_file::*; -pub use single_service::*; -pub use service::*; -pub use sys_ctls::*; -pub use compose::*; -pub use env_file::*; -pub use depends_on_options::*; -pub use depends_condition::*; -pub use logging_parameters::*; -pub use ports::*; -pub use environment::*; -pub use extension::*; -pub use extension_parse_error::*; -pub use services::*; -pub use labels::*; -pub use tmpfs::*; -pub use ulimit::*; -pub use ulimits::*; -pub use networks::*; -pub use build_step::*; -pub use advanced_build_step::*; -pub use build_args::*; -pub use advanced_networks::*; -pub use advanced_network_settings::*; -pub use top_level_volumes::*; -pub use compose_volume::*; -pub use external_volume::*; -pub use compose_networks::*; -pub use compose_network::*; -pub use compose_network_setting_details::*; -pub use external_network_setting_bool::*; -pub use network_settings::*; -pub use ipam::*; -pub use ipam_config::*; - -use crate::helpers::project::dctypes; - -use derive_builder::*; -#[cfg(feature = "indexmap")] -use indexmap::IndexMap; -use serde::{Deserialize, Serialize}; -use serde_yaml::Value; -#[cfg(not(feature = "indexmap"))] -use std::collections::HashMap; -use std::convert::TryFrom; -use std::fmt; - - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)] -#[serde(deny_unknown_fields)] -pub struct Deploy { - #[serde(skip_serializing_if = "Option::is_none")] - pub mode: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub replicas: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub labels: Vec, - #[serde(skip_serializing_if = "Option::is_none")] - pub update_config: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub resources: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub restart_policy: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub placement: Option, -} - -fn is_zero(val: &i64) -> bool { - *val == 0 -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(deny_unknown_fields)] -pub struct Healthcheck { - #[serde(skip_serializing_if = "Option::is_none")] - pub test: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub interval: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub timeout: Option, - #[serde(default, skip_serializing_if = "is_zero")] - pub retries: i64, - #[serde(skip_serializing_if = "Option::is_none")] - pub start_period: Option, - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub disable: bool, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(untagged)] -pub enum HealthcheckTest { - Single(String), - Multiple(Vec), -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash, Default)] -#[serde(deny_unknown_fields)] -pub struct Limits { - #[serde(skip_serializing_if = "Option::is_none")] - pub cpus: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub memory: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash, Default)] -#[serde(deny_unknown_fields)] -pub struct Placement { - #[serde(skip_serializing_if = "Vec::is_empty", default)] - pub constraints: Vec, - #[serde(skip_serializing_if = "Vec::is_empty", default)] - pub preferences: Vec, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(deny_unknown_fields)] -pub struct Preferences { - pub spread: String, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash, Default)] -#[serde(deny_unknown_fields)] -pub struct Resources { - pub limits: Option, - pub reservations: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash, Default)] -#[serde(deny_unknown_fields)] -pub struct RestartPolicy { - #[serde(skip_serializing_if = "Option::is_none")] - pub condition: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub delay: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub max_attempts: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub window: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)] -#[serde(deny_unknown_fields)] -pub struct UpdateConfig { - #[serde(skip_serializing_if = "Option::is_none")] - pub parallelism: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub delay: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub failure_action: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub monitor: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub max_failure_ratio: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(untagged)] -pub enum Volumes { - Simple(Vec), - Advanced(Vec), -} - -impl Default for Volumes { - fn default() -> Self { - Self::Simple(Vec::new()) - } -} - -impl Volumes { - pub fn is_empty(&self) -> bool { - match self { - Self::Simple(v) => v.is_empty(), - Self::Advanced(v) => v.is_empty(), - } - } -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(deny_unknown_fields)] -pub struct AdvancedVolumes { - #[serde(skip_serializing_if = "Option::is_none")] - pub source: Option, - pub target: String, - #[serde(rename = "type")] - pub _type: String, - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub read_only: bool, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub bind: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub volume: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub tmpfs: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash, Default)] -#[serde(deny_unknown_fields)] -pub struct Bind { - pub propagation: String, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash, Default)] -#[serde(deny_unknown_fields)] -pub struct Volume { - pub nocopy: bool, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash, Default)] -#[serde(deny_unknown_fields)] -pub struct TmpfsSettings { - pub size: u64, -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(untagged)] -pub enum Command { - Simple(String), - Args(Vec), -} - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] -#[serde(untagged)] -pub enum Entrypoint { - Simple(String), - List(Vec), -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, PartialOrd)] -#[serde(untagged)] -pub enum SingleValue { - String(String), - Bool(bool), - Unsigned(u64), - Signed(i64), - Float(f64), -} - -impl fmt::Display for SingleValue { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::String(s) => f.write_str(s), - Self::Bool(b) => write!(f, "{b}"), - Self::Unsigned(u) => write!(f, "{u}"), - Self::Signed(i) => write!(f, "{i}"), - Self::Float(fl) => write!(f, "{fl}"), - } - } -} - -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Hash)] -#[serde(untagged)] -pub enum MapOrEmpty { - Map(T), - Empty, -} - -impl Default for MapOrEmpty { - fn default() -> Self { - Self::Empty - } -} - -impl From> for Option { - fn from(value: MapOrEmpty) -> Self { - match value { - MapOrEmpty::Map(t) => Some(t), - MapOrEmpty::Empty => None, - } - } -} - -impl Serialize for MapOrEmpty - where - T: Serialize, -{ - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - match self { - Self::Map(t) => t.serialize(serializer), - Self::Empty => { - use serde::ser::SerializeMap; - serializer.serialize_map(None)?.end() - } - } - } -} diff --git a/src/helpers/project/dctypes/network_settings.rs b/src/helpers/project/dctypes/network_settings.rs deleted file mode 100644 index 72b27b2..0000000 --- a/src/helpers/project/dctypes/network_settings.rs +++ /dev/null @@ -1,29 +0,0 @@ -use serde::{Deserialize, Serialize}; -use crate::helpers::project::dctypes::*; - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)] -#[serde(deny_unknown_fields)] -pub struct NetworkSettings { - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub attachable: bool, - #[serde(skip_serializing_if = "Option::is_none")] - pub driver: Option, - #[cfg(feature = "indexmap")] - #[serde(default, skip_serializing_if = "IndexMap::is_empty")] - pub driver_opts: IndexMap>, - #[cfg(not(feature = "indexmap"))] - #[serde(default, skip_serializing_if = "HashMap::is_empty")] - pub driver_opts: HashMap>, - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub enable_ipv6: bool, - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub internal: bool, - #[serde(skip_serializing_if = "Option::is_none")] - pub external: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub ipam: Option, - #[serde(default, skip_serializing_if = "Labels::is_empty")] - pub labels: Labels, - #[serde(skip_serializing_if = "Option::is_none")] - pub name: Option, -} diff --git a/src/helpers/project/dctypes/networks.rs b/src/helpers/project/dctypes/networks.rs deleted file mode 100644 index 751554f..0000000 --- a/src/helpers/project/dctypes/networks.rs +++ /dev/null @@ -1,24 +0,0 @@ -use serde::{Deserialize, Serialize}; -use crate::helpers::project::dctypes; - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] -#[serde(untagged)] -pub enum Networks { - Simple(Vec), - Advanced(dctypes::AdvancedNetworks), -} - -impl Default for Networks { - fn default() -> Self { - Self::Simple(Vec::new()) - } -} - -impl Networks { - pub fn is_empty(&self) -> bool { - match self { - Self::Simple(n) => n.is_empty(), - Self::Advanced(n) => n.0.is_empty(), - } - } -} diff --git a/src/helpers/project/dctypes/port.rs b/src/helpers/project/dctypes/port.rs deleted file mode 100644 index fc437ef..0000000 --- a/src/helpers/project/dctypes/port.rs +++ /dev/null @@ -1,53 +0,0 @@ -use serde::{Deserialize, Serialize}; -use crate::helpers::project::dctypes; -use crate::forms; - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -pub struct Port { - pub target: u16, - #[serde(skip_serializing_if = "Option::is_none")] - pub host_ip: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub published: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub protocol: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub mode: Option, -} - -impl Default for Port { - fn default() -> Self { - Port { - target: 80, - host_ip: None, - published: None, - protocol: None, - mode: None, - } - } -} - -impl TryInto for &forms::project::Port { - type Error = String; - fn try_into(self) -> Result { - let cp = self - .container_port - .as_ref() - .map_or(Ok(0u16), |s| s.parse::()) - .map_err(|_| "Could not parse port".to_string())?; - - let hp = self - .host_port - .as_ref() - .map_or(Ok(0u16), |s| s.parse::()) - .map_err(|_| "Could not parse port".to_string())?; - - Ok(Port { - target: cp, - host_ip: None, - published: Some(dctypes::PublishedPort::Single(hp)), - protocol: None, - mode: None, - }) - } -} diff --git a/src/helpers/project/dctypes/ports.rs b/src/helpers/project/dctypes/ports.rs deleted file mode 100644 index 3c61494..0000000 --- a/src/helpers/project/dctypes/ports.rs +++ /dev/null @@ -1,25 +0,0 @@ -use serde::{Deserialize, Serialize}; -use crate::helpers::project::dctypes; - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -#[serde(untagged)] -pub enum Ports { - Short(Vec), - Long(Vec), -} - -impl Default for Ports { - fn default() -> Self { - Self::Short(Vec::default()) - } -} - -impl Ports { - pub fn is_empty(&self) -> bool { - match self { - Self::Short(v) => v.is_empty(), - Self::Long(v) => v.is_empty(), - } - } -} - diff --git a/src/helpers/project/dctypes/published_port.rs b/src/helpers/project/dctypes/published_port.rs deleted file mode 100644 index 57a24ab..0000000 --- a/src/helpers/project/dctypes/published_port.rs +++ /dev/null @@ -1,8 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -#[serde(untagged)] -pub enum PublishedPort { - Single(u16), - Range(String), -} diff --git a/src/helpers/project/dctypes/service.rs b/src/helpers/project/dctypes/service.rs deleted file mode 100644 index e288632..0000000 --- a/src/helpers/project/dctypes/service.rs +++ /dev/null @@ -1,120 +0,0 @@ -use serde::{Deserialize, Serialize}; -#[cfg(feature = "indexmap")] -use indexmap::IndexMap; -use crate::helpers::project::dctypes; -use serde_json::Value; -use derive_builder::*; - -#[derive(Builder, Clone, Debug, Deserialize, Serialize, PartialEq, Default)] -#[builder(setter(into), default)] -pub struct Service { - #[serde(skip_serializing_if = "Option::is_none")] - pub hostname: Option, - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub privileged: bool, - #[serde(skip_serializing_if = "Option::is_none")] - pub healthcheck: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub deploy: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub image: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub container_name: Option, - #[serde(skip_serializing_if = "Option::is_none", rename = "build")] - pub build_: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub pid: Option, - #[serde(default, skip_serializing_if = "dctypes::Ports::is_empty")] - pub ports: dctypes::Ports, - #[serde(default, skip_serializing_if = "dctypes::Environment::is_empty")] - pub environment: dctypes::Environment, - #[serde(skip_serializing_if = "Option::is_none")] - pub network_mode: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub devices: Vec, - #[serde(skip_serializing_if = "Option::is_none")] - pub restart: Option, - #[serde(default, skip_serializing_if = "dctypes::Labels::is_empty")] - pub labels: dctypes::Labels, - #[serde(skip_serializing_if = "Option::is_none")] - pub tmpfs: Option, - #[serde(default, skip_serializing_if = "dctypes::Ulimits::is_empty")] - pub ulimits: dctypes::Ulimits, - #[serde(default, skip_serializing_if = "dctypes::Volumes::is_empty")] - pub volumes: dctypes::Volumes, - #[serde(default, skip_serializing_if = "dctypes::Networks::is_empty")] - pub networks: dctypes::Networks, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub cap_add: Vec, - #[serde(default, skip_serializing_if = "dctypes::DependsOnOptions::is_empty")] - pub depends_on: dctypes::DependsOnOptions, - #[serde(skip_serializing_if = "Option::is_none")] - pub command: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub entrypoint: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub env_file: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub stop_grace_period: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub profiles: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub links: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub dns: Vec, - #[serde(skip_serializing_if = "Option::is_none")] - pub ipc: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub net: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub stop_signal: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub user: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub working_dir: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub expose: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub volumes_from: Vec, - #[cfg(feature = "indexmap")] - #[serde(default, skip_serializing_if = "IndexMap::is_empty")] - pub extends: IndexMap, - #[cfg(not(feature = "indexmap"))] - #[serde(default, skip_serializing_if = "HashMap::is_empty")] - pub extends: HashMap, - #[serde(skip_serializing_if = "Option::is_none")] - pub logging: Option, - #[serde(default, skip_serializing_if = "dctypes::is_zero")] - pub scale: i64, - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub init: bool, - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub stdin_open: bool, - #[serde(skip_serializing_if = "Option::is_none")] - pub shm_size: Option, - #[cfg(feature = "indexmap")] - #[serde(flatten, skip_serializing_if = "IndexMap::is_empty")] - pub extensions: IndexMap, - #[cfg(not(feature = "indexmap"))] - #[serde(flatten, skip_serializing_if = "HashMap::is_empty")] - pub extensions: HashMap, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub extra_hosts: Vec, - #[serde(default, skip_serializing_if = "std::ops::Not::not")] - pub tty: bool, - #[serde(default, skip_serializing_if = "dctypes::SysCtls::is_empty")] - pub sysctls: dctypes::SysCtls, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub security_opt: Vec, -} - -impl Service { - pub fn image(&self) -> &str { - self.image.as_deref().unwrap_or_default() - } - - pub fn network_mode(&self) -> &str { - self.network_mode.as_deref().unwrap_or_default() - } -} - diff --git a/src/helpers/project/dctypes/services.rs b/src/helpers/project/dctypes/services.rs deleted file mode 100644 index 949437e..0000000 --- a/src/helpers/project/dctypes/services.rs +++ /dev/null @@ -1,19 +0,0 @@ -use serde::{Deserialize, Serialize}; -#[cfg(feature = "indexmap")] -use indexmap::IndexMap; -#[cfg(not(feature = "indexmap"))] -use std::collections::HashMap; -use crate::helpers::project::dctypes; - -#[cfg(feature = "indexmap")] -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] -pub struct Services(pub IndexMap>); -#[cfg(not(feature = "indexmap"))] -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] -pub struct Services(pub HashMap>); - -impl Services { - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } -} diff --git a/src/helpers/project/dctypes/single_service.rs b/src/helpers/project/dctypes/single_service.rs deleted file mode 100644 index 19031c5..0000000 --- a/src/helpers/project/dctypes/single_service.rs +++ /dev/null @@ -1,8 +0,0 @@ -use serde::{Deserialize, Serialize}; -use crate::helpers::project::dctypes; - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)] -pub struct SingleService { - pub service: dctypes::Service, -} - diff --git a/src/helpers/project/dctypes/sys_ctls.rs b/src/helpers/project/dctypes/sys_ctls.rs deleted file mode 100644 index 4abbb24..0000000 --- a/src/helpers/project/dctypes/sys_ctls.rs +++ /dev/null @@ -1,30 +0,0 @@ -use serde::{Deserialize, Serialize}; -use crate::helpers::project::dctypes; -#[cfg(feature = "indexmap")] -use indexmap::IndexMap; - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -#[serde(untagged)] -pub enum SysCtls { - List(Vec), - #[cfg(feature = "indexmap")] - Map(IndexMap>), - #[cfg(not(feature = "indexmap"))] - Map(HashMap>), -} - -impl Default for SysCtls { - fn default() -> Self { - Self::List(Vec::new()) - } -} - -impl SysCtls { - pub fn is_empty(&self) -> bool { - match self { - Self::List(v) => v.is_empty(), - Self::Map(m) => m.is_empty(), - } - } -} - diff --git a/src/helpers/project/dctypes/tmpfs.rs b/src/helpers/project/dctypes/tmpfs.rs deleted file mode 100644 index 1bea9b6..0000000 --- a/src/helpers/project/dctypes/tmpfs.rs +++ /dev/null @@ -1,9 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] -#[serde(untagged)] -pub enum Tmpfs { - Simple(String), - List(Vec), -} - diff --git a/src/helpers/project/dctypes/top_level_volumes.rs b/src/helpers/project/dctypes/top_level_volumes.rs deleted file mode 100644 index 304d531..0000000 --- a/src/helpers/project/dctypes/top_level_volumes.rs +++ /dev/null @@ -1,19 +0,0 @@ -use serde::{Deserialize, Serialize}; -#[cfg(feature = "indexmap")] -use indexmap::IndexMap; -#[cfg(not(feature = "indexmap"))] -use std::collections::HashMap; -use crate::helpers::project::dctypes::*; - -#[cfg(feature = "indexmap")] -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] -pub struct TopLevelVolumes(pub IndexMap>); -#[cfg(not(feature = "indexmap"))] -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] -pub struct TopLevelVolumes(pub HashMap>); - -impl TopLevelVolumes { - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } -} diff --git a/src/helpers/project/dctypes/ulimit.rs b/src/helpers/project/dctypes/ulimit.rs deleted file mode 100644 index 6589931..0000000 --- a/src/helpers/project/dctypes/ulimit.rs +++ /dev/null @@ -1,8 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] -#[serde(untagged)] -pub enum Ulimit { - Single(i64), - SoftHard { soft: i64, hard: i64 }, -} diff --git a/src/helpers/project/dctypes/ulimits.rs b/src/helpers/project/dctypes/ulimits.rs deleted file mode 100644 index 2cfe4f5..0000000 --- a/src/helpers/project/dctypes/ulimits.rs +++ /dev/null @@ -1,20 +0,0 @@ -use serde::{Deserialize, Serialize}; -#[cfg(feature = "indexmap")] -use indexmap::IndexMap; -#[cfg(not(feature = "indexmap"))] -use std::collections::HashMap; -use crate::helpers::project::dctypes; - -#[cfg(feature = "indexmap")] -#[derive(Clone, Default, Debug, Serialize, Deserialize, Eq, PartialEq)] -pub struct Ulimits(pub IndexMap); -#[cfg(not(feature = "indexmap"))] -#[derive(Clone, Default, Debug, Serialize, Deserialize, Eq, PartialEq)] -pub struct Ulimits(pub HashMap); - -impl Ulimits { - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } -} - diff --git a/tests/model_user_stack.rs b/tests/model_project.rs similarity index 100% rename from tests/model_user_stack.rs rename to tests/model_project.rs From 96c84b6474cce4680cc60df873bb4b20b0a896c9 Mon Sep 17 00:00:00 2001 From: vsilent Date: Thu, 29 Feb 2024 17:07:56 +0200 Subject: [PATCH 195/284] form updates --- docker-compose.yml | 1 + docker/dev/docker-compose.yml | 3 ++- src/forms/cloud.rs | 3 --- src/forms/project/volume.rs | 4 ++-- src/forms/server.rs | 3 --- src/routes/cloud/add.rs | 8 -------- src/routes/server/add.rs | 8 -------- tests/cloud.rs | 0 tests/{ => mock_data}/app.json | 0 .../{ => mock_data}/custom-stack-payload-no-networks.json | 0 tests/{ => mock_data}/custom-stack-payload.json | 0 tests/{ => mock_data}/custom.json | 0 tests/{ => mock_data}/web-item.json | 0 13 files changed, 5 insertions(+), 25 deletions(-) create mode 100644 tests/cloud.rs rename tests/{ => mock_data}/app.json (100%) rename tests/{ => mock_data}/custom-stack-payload-no-networks.json (100%) rename tests/{ => mock_data}/custom-stack-payload.json (100%) rename tests/{ => mock_data}/custom.json (100%) rename tests/{ => mock_data}/web-item.json (100%) diff --git a/docker-compose.yml b/docker-compose.yml index 467836e..e9aee75 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,6 +15,7 @@ services: volumes: - ./files:/app/files - ./docker/local/configuration.yaml:/app/configuration.yaml + - ./access_control.conf:/app/access_control.conf - ./migrations:/app/migrations - ./docker/local/.env:/app/.env ports: diff --git a/docker/dev/docker-compose.yml b/docker/dev/docker-compose.yml index c1a022b..6bf8eb5 100644 --- a/docker/dev/docker-compose.yml +++ b/docker/dev/docker-compose.yml @@ -13,13 +13,14 @@ networks: services: stacker: - image: trydirect/stacker:0.0.5 + image: trydirect/stacker:0.0.7 build: . container_name: stacker restart: always volumes: - ./stacker/files:/app/files - ./configuration.yaml:/app/configuration.yaml + - ./access_control.conf:/app/access_control.conf - ./migrations:/app/migrations - ./.env:/app/.env ports: diff --git a/src/forms/cloud.rs b/src/forms/cloud.rs index e742952..e0fafd9 100644 --- a/src/forms/cloud.rs +++ b/src/forms/cloud.rs @@ -5,7 +5,6 @@ use chrono::{DateTime, Utc}; #[derive(Serialize, Deserialize, Debug, Validate)] pub struct Cloud { - pub id: i32, pub user_id: String, #[validate(min_length = 2)] #[validate(max_length = 50)] @@ -14,8 +13,6 @@ pub struct Cloud { pub cloud_key: Option, pub cloud_secret: Option, pub save_token: Option, - pub created_at: DateTime, - pub updated_at: DateTime, } impl Into for Cloud { diff --git a/src/forms/project/volume.rs b/src/forms/project/volume.rs index b4bfaed..2b30a59 100644 --- a/src/forms/project/volume.rs +++ b/src/forms/project/volume.rs @@ -4,8 +4,8 @@ use indexmap::IndexMap; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Volume { - pub(crate) host_path: Option, - pub(crate) container_path: Option, + pub host_path: Option, + pub container_path: Option, } impl Volume { diff --git a/src/forms/server.rs b/src/forms/server.rs index 7b2672b..edfe827 100644 --- a/src/forms/server.rs +++ b/src/forms/server.rs @@ -5,7 +5,6 @@ use chrono::{DateTime, Utc}; #[derive(Serialize, Deserialize, Debug, Validate)] pub struct Server { - pub id: i32, pub user_id: String, pub cloud_id: i32, pub project_id: i32, @@ -14,8 +13,6 @@ pub struct Server { pub server: String, pub os: String, pub disk_type: Option, - pub created_at: DateTime, - pub updated_at: DateTime, } impl Into for Server { diff --git a/src/routes/cloud/add.rs b/src/routes/cloud/add.rs index 4923cad..cb57209 100644 --- a/src/routes/cloud/add.rs +++ b/src/routes/cloud/add.rs @@ -29,14 +29,6 @@ pub async fn add( return Err(JsonResponse::::build().form_error(errors)); } - let cloud = db::cloud::fetch(pg_pool.get_ref(), form.id) - .await - .map_err(|_msg| JsonResponse::::build().internal_server_error(_msg))? - .ok_or_else(|| JsonResponse::::build().not_found("not found"))? - ; - - tracing::debug!("Cloud record is found ? {:?}", cloud); - let mut cloud: models::Cloud = form.into_inner().into(); cloud.user_id = user.id.clone(); diff --git a/src/routes/server/add.rs b/src/routes/server/add.rs index 6dbd2d0..278f4e9 100644 --- a/src/routes/server/add.rs +++ b/src/routes/server/add.rs @@ -29,14 +29,6 @@ pub async fn add( return Err(JsonResponse::::build().form_error(errors)); } - let server = db::server::fetch(pg_pool.get_ref(), form.id) - .await - .map_err(|_msg| JsonResponse::::build().internal_server_error(_msg))? - .ok_or_else(|| JsonResponse::::build().not_found("not found"))? - ; - - tracing::debug!("Server record is found ? {:?}", server); - let mut server: models::Server = form.into_inner().into(); server.user_id = user.id.clone(); diff --git a/tests/cloud.rs b/tests/cloud.rs new file mode 100644 index 0000000..e69de29 diff --git a/tests/app.json b/tests/mock_data/app.json similarity index 100% rename from tests/app.json rename to tests/mock_data/app.json diff --git a/tests/custom-stack-payload-no-networks.json b/tests/mock_data/custom-stack-payload-no-networks.json similarity index 100% rename from tests/custom-stack-payload-no-networks.json rename to tests/mock_data/custom-stack-payload-no-networks.json diff --git a/tests/custom-stack-payload.json b/tests/mock_data/custom-stack-payload.json similarity index 100% rename from tests/custom-stack-payload.json rename to tests/mock_data/custom-stack-payload.json diff --git a/tests/custom.json b/tests/mock_data/custom.json similarity index 100% rename from tests/custom.json rename to tests/mock_data/custom.json diff --git a/tests/web-item.json b/tests/mock_data/web-item.json similarity index 100% rename from tests/web-item.json rename to tests/mock_data/web-item.json From 10d727518b6959737c94618dbff0179ab178b7dd Mon Sep 17 00:00:00 2001 From: vsilent Date: Fri, 1 Mar 2024 13:57:02 +0200 Subject: [PATCH 196/284] form field refactoring, servers_count removed --- ...0230905145525_creating_stack_tables.up.sql | 2 +- ...0240229080559_creating_cloud_server.up.sql | 2 +- ...eating_user_stack_server_relation.down.sql | 2 - ...creating_user_stack_server_relation.up.sql | 2 - src/db/project.rs | 72 +++++++++---------- src/forms/project/custom.rs | 3 - src/forms/project/form.rs | 38 +++++----- src/forms/project/payload.rs | 1 - src/models/project.rs | 1 + src/routes/project/add.rs | 17 +---- src/routes/project/delete.rs | 43 +++++++---- src/routes/project/deploy.rs | 32 ++++++++- src/routes/project/mod.rs | 2 +- src/routes/project/update.rs | 2 +- src/startup.rs | 5 +- tests/cloud.rs | 48 +++++++++++++ tests/dockerhub.rs | 6 +- 17 files changed, 169 insertions(+), 109 deletions(-) delete mode 100644 migrations/20240229083517_creating_user_stack_server_relation.down.sql delete mode 100644 migrations/20240229083517_creating_user_stack_server_relation.up.sql diff --git a/migrations/20230905145525_creating_stack_tables.up.sql b/migrations/20230905145525_creating_stack_tables.up.sql index 333b27f..6ae6433 100644 --- a/migrations/20230905145525_creating_stack_tables.up.sql +++ b/migrations/20230905145525_creating_stack_tables.up.sql @@ -2,7 +2,7 @@ CREATE TABLE project ( id serial4 NOT NULL, stack_id uuid NOT NULL, user_id VARCHAR(50) NOT NULL, - name TEXT NOT NULL UNIQUE, + name TEXT, body JSON NOT NULL, created_at timestamptz NOT NULL, updated_at timestamptz NOT NULL, diff --git a/migrations/20240229080559_creating_cloud_server.up.sql b/migrations/20240229080559_creating_cloud_server.up.sql index 091fb8f..e4ed91b 100644 --- a/migrations/20240229080559_creating_cloud_server.up.sql +++ b/migrations/20240229080559_creating_cloud_server.up.sql @@ -14,7 +14,7 @@ CREATE TABLE server ( updated_at timestamptz NOT NULL, CONSTRAINT user_server_pkey PRIMARY KEY (id), CONSTRAINT fk_server FOREIGN KEY(cloud_id) REFERENCES cloud(id), - CONSTRAINT fk_server_project FOREIGN KEY(project_id) REFERENCES project(id) + CONSTRAINT fk_server_project FOREIGN KEY(project_id) REFERENCES project(id) ON UPDATE CASCADE ON DELETE CASCADE ); CREATE INDEX idx_server_user_id ON server(user_id); diff --git a/migrations/20240229083517_creating_user_stack_server_relation.down.sql b/migrations/20240229083517_creating_user_stack_server_relation.down.sql deleted file mode 100644 index c410fff..0000000 --- a/migrations/20240229083517_creating_user_stack_server_relation.down.sql +++ /dev/null @@ -1,2 +0,0 @@ --- Add down migration script here -ALTER table server DROP COLUMN project_id; diff --git a/migrations/20240229083517_creating_user_stack_server_relation.up.sql b/migrations/20240229083517_creating_user_stack_server_relation.up.sql deleted file mode 100644 index ab021b1..0000000 --- a/migrations/20240229083517_creating_user_stack_server_relation.up.sql +++ /dev/null @@ -1,2 +0,0 @@ --- Add up migration script here -ALTER table server ADD COLUMN project_id integer CONSTRAINT project_id REFERENCES project(id) ON UPDATE CASCADE ON DELETE CASCADE; diff --git a/src/db/project.rs b/src/db/project.rs index 99a5d92..8104b06 100644 --- a/src/db/project.rs +++ b/src/db/project.rs @@ -143,52 +143,44 @@ pub async fn update(pool: &PgPool, mut project: models::Project) -> Result Result, String> { +pub async fn delete(pool: &PgPool, id: i32) -> Result { tracing::info!("Delete project {}", id); - let mut tx = pool.begin().await - .map(|result| result) - .map_err(|err| { - tracing::error!("Failed to execute query: {:?}", err); - "".to_string() - }).unwrap(); + let mut tx = match pool.begin().await { + Ok(result) => result, + Err(err) => { + tracing::error!("Failed to begin transaction: {:?}", err); + return Err("".to_string()); + } + }; - // delete records from deployment - // delete records from server - sqlx::query("DELETE FROM deployment where project_id=?") - .bind(id) - .execute(&mut *tx) - .await - .map(|result| result) - .map_err(|err| { - tracing::error!("Failed to execute query: {:?}", err); - "".to_string() - }).unwrap(); + // Combine delete queries into a single query + let delete_query = " + DELETE FROM deployment WHERE project_id = $1; + DELETE FROM server WHERE project_id = $1; + DELETE FROM project WHERE id = $1; + "; - sqlx::query("DELETE FROM server where project_id=?") + match sqlx::query(delete_query) .bind(id) - .execute(&mut *tx) + .execute(&mut tx) .await - .map(|result| result) .map_err(|err| { - tracing::error!("Failed to execute query: {:?}", err); - "".to_string() - }).unwrap(); - - sqlx::query("DELETE FROM project where id=?") - .bind(id) - .execute(&mut *tx) - .await - .map(|result| result) - .map_err(|err| { - tracing::error!("Failed to execute query: {:?}", err); - "".to_string() - }).unwrap(); - - tx.commit().await; - - // tracing::error!("Failed to delete project, error: {:?}", e); - // Err("Could not fetch data".to_string()) + println!("{:?}", err) + }) + { + Ok(_) => { + tx.commit().await.map_err(|err| { + tracing::error!("Failed to commit transaction: {:?}", err); + false + }); + Ok(true) + } + Err(err) => { + tx.rollback().await.map_err(|err| println!("{:?}", err)); + Ok(false) + } + } + // Ok(true) - Ok(None) } diff --git a/src/forms/project/custom.rs b/src/forms/project/custom.rs index 8be69cc..0a4eac7 100644 --- a/src/forms/project/custom.rs +++ b/src/forms/project/custom.rs @@ -13,9 +13,6 @@ pub struct Custom { pub feature: Option>, #[validate] pub service: Option>, - #[validate(minimum = 0)] - #[validate(maximum = 10)] - pub servers_count: u32, #[validate(min_length = 3)] #[validate(max_length = 50)] pub custom_stack_code: String, diff --git a/src/forms/project/form.rs b/src/forms/project/form.rs index 2ae56bd..4321f33 100644 --- a/src/forms/project/form.rs +++ b/src/forms/project/form.rs @@ -25,9 +25,6 @@ pub struct ProjectForm { pub extended_features: Option>, pub subscriptions: Option>, pub form_app: Option>, - #[validate(min_length = 3)] - #[validate(max_length = 50)] - pub selected_plan: String, pub custom: forms::project::Custom, } @@ -49,24 +46,23 @@ impl ProjectForm { } } - // temporarily disabled - // if let Some(service) = &self.custom.service { - // for app in service { - // if !app.app.docker_image.is_active().await? { - // is_active = false; - // break; - // } - // } - // } - // - // if let Some(features) = &self.custom.feature { - // for app in features { - // if !app.app.docker_image.is_active().await? { - // is_active = false; - // break; - // } - // } - // } + if let Some(service) = &self.custom.service { + for app in service { + if !app.app.docker_image.is_active().await? { + is_active = false; + break; + } + } + } + + if let Some(features) = &self.custom.feature { + for app in features { + if !app.app.docker_image.is_active().await? { + is_active = false; + break; + } + } + } Ok(is_active) } } diff --git a/src/forms/project/payload.rs b/src/forms/project/payload.rs index 70800fe..70e8f60 100644 --- a/src/forms/project/payload.rs +++ b/src/forms/project/payload.rs @@ -28,7 +28,6 @@ pub struct Payload { #[serde(flatten)] pub cloud: models::Cloud, pub stack_code: String, - pub selected_plan: String, pub custom: forms::project::Custom, pub docker_compose: Option>, } diff --git a/src/models/project.rs b/src/models/project.rs index 35661eb..06d2905 100644 --- a/src/models/project.rs +++ b/src/models/project.rs @@ -2,6 +2,7 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_json::Value; use uuid::Uuid; +use crate::db; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Project { diff --git a/src/routes/project/add.rs b/src/routes/project/add.rs index e3d1b07..05fb6cf 100644 --- a/src/routes/project/add.rs +++ b/src/routes/project/add.rs @@ -16,7 +16,7 @@ use std::sync::Arc; #[tracing::instrument(name = "Add project.")] #[post("")] -pub async fn add( +pub async fn item( body: Bytes, user: web::ReqData>, pg_pool: Data, @@ -25,8 +25,6 @@ pub async fn add( let form = body_into_form(body).await?; let project_name = form.custom.custom_stack_code.clone(); - project_exists(pg_pool.get_ref(), &project_name).await?; - let body: Value = serde_json::to_value::(form) .or(serde_json::to_value::(forms::project::ProjectForm::default())) .unwrap(); @@ -41,19 +39,6 @@ pub async fn add( } -async fn project_exists(pool: &PgPool, project_name: &String) -> Result<(), Error> { - db::project::fetch_one_by_name(pool, project_name) - .await - .map_err(|_| { - JsonResponse::::build().internal_server_error("Internal Server Error") - }) - .and_then(|project| match project { - Some(_) => Err(JsonResponse::::build() - .conflict("Project with that name already exists")), - None => Ok(()), - }) -} - async fn body_into_form(body: Bytes) -> Result { let body_bytes = actix_web::body::to_bytes(body).await.unwrap(); let body_str = str::from_utf8(&body_bytes) diff --git a/src/routes/project/delete.rs b/src/routes/project/delete.rs index fb4ff33..16cc579 100644 --- a/src/routes/project/delete.rs +++ b/src/routes/project/delete.rs @@ -1,12 +1,13 @@ -use crate::db; use crate::helpers::JsonResponse; use crate::models; use actix_web::{delete, web, Responder, Result}; use sqlx::PgPool; use std::sync::Arc; use tracing::Instrument; +use crate::db; +use crate::models::Project; -#[tracing::instrument(name = "Get logged user project.")] +#[tracing::instrument(name = "Delete project of a user.")] #[delete("/{id}")] pub async fn item( user: web::ReqData>, @@ -16,18 +17,32 @@ pub async fn item( /// Get project apps of logged user only let (id,) = path.into_inner(); - db::project::fetch(pg_pool.get_ref(), id) - .await + let project = db::project::fetch(pg_pool.get_ref(), id).await .map_err(|err| JsonResponse::::build().internal_server_error(err)) - .and_then(|project| match project { - Some(project) if project.user_id != user.id => { - Err(JsonResponse::::build().not_found("not found")) - } - Some(project) => { - db::project::delete(pg_pool.get_ref(), id); - Ok(JsonResponse::build().set_item(Some(project)).ok("Deleted")) - }, - None => Err(JsonResponse::::build().not_found("not found")), - }) + .map(|project| { project }).unwrap(); + // + // match project { + // Some(project) if project.user_id != user.id => { + // Err(JsonResponse::::build().not_found("not found")) + // } + // Some(project) => { + // + // match db::project::delete(pg_pool.get_ref(), id) + // .await + // .map_err(|e| println!("{:?}", e)) + // { + // Ok(true) => { + // Ok(JsonResponse::build().set_item(Some(project)).ok("Deleted")) + // } + // _ => { + // Err(JsonResponse::::build().bad_request("Could not delete")) + // } + // } + // }, + // None => Err(JsonResponse::::build().not_found("not found")), + // } + // }) + + Ok(JsonResponse::::build().ok("Deleted")) } diff --git a/src/routes/project/deploy.rs b/src/routes/project/deploy.rs index 265957a..f3144f0 100644 --- a/src/routes/project/deploy.rs +++ b/src/routes/project/deploy.rs @@ -42,8 +42,36 @@ pub async fn add( // let compressed = fc.unwrap_or("".to_string()); project_data.docker_compose = Some(compress(fc.as_str())); - // project_data.cloud = - // project_data.server = + if let Some(cloud_id) = dc.project.cloud_id { + project_data.cloud = match db::cloud::fetch(pg_pool.get_ref(), cloud_id).await { + Ok(cloud) => { + match cloud { + Some(cloud) => cloud, + None => { + return Err(JsonResponse::::build().not_found("No cloud configured")); + } + } + } + Err(e) => { + return Err(JsonResponse::::build().not_found("No cloud configured")); + } + }; + + project_data.server = match db::server::fetch_by_project(pg_pool.get_ref(), dc.project.id.clone()).await { + Ok(server) => { + // for now we support only one type of servers + // if let Some(server) = server.into_iter().nth(0) { + // server + // } + server.into_iter().nth(0).unwrap() // @todo refactoring is required + } + Err(err) => { + return Err(JsonResponse::::build().not_found("No servers configured")); + } + } + } else { + return Err(JsonResponse::::build().not_found("No cloud provider configured")); + } let project_id = dc.project.id.clone(); let json_request = dc.project.body.clone(); diff --git a/src/routes/project/mod.rs b/src/routes/project/mod.rs index 2d41c67..6d66205 100644 --- a/src/routes/project/mod.rs +++ b/src/routes/project/mod.rs @@ -3,7 +3,7 @@ pub mod deploy; pub mod get; pub mod update; pub(crate) mod compose; -mod delete; +pub(crate) mod delete; pub use add::*; pub use update::*; diff --git a/src/routes/project/update.rs b/src/routes/project/update.rs index 5a8dac6..e20d909 100644 --- a/src/routes/project/update.rs +++ b/src/routes/project/update.rs @@ -12,7 +12,7 @@ use uuid::Uuid; #[tracing::instrument(name = "Update project.")] #[post("/{id}")] -pub async fn update( +pub async fn item( path: web::Path<(i32,)>, form: web::Json, user: web::ReqData>, diff --git a/src/startup.rs b/src/startup.rs index e489cb9..3c8165c 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -76,8 +76,9 @@ pub async fn run( .service(crate::routes::project::compose::admin) .service(crate::routes::project::get::item) .service(crate::routes::project::get::list) - .service(crate::routes::project::add::add) - .service(crate::routes::project::update::update), + .service(crate::routes::project::add::item) + .service(crate::routes::project::update::item) + .service(crate::routes::project::delete::item), ) .service( web::scope("/cloud") diff --git a/tests/cloud.rs b/tests/cloud.rs index e69de29..c3fd2d3 100644 --- a/tests/cloud.rs +++ b/tests/cloud.rs @@ -0,0 +1,48 @@ +mod common; + +// test me: cargo t --test cloud -- --nocapture --show-output +#[tokio::test] +async fn list() { + + let app = common::spawn_app().await; // server + let client = reqwest::Client::new(); // client + + let response = client + .get(&format!("{}/cloud", &app.address)) + .send() + .await + .expect("Failed to execute request."); + + assert!(response.status().is_success()); + assert_eq!(Some(0), response.content_length()); +} + +// test me: cargo t --test cloud add_cloud -- --nocapture --show-output +#[tokio::test] +async fn add_cloud() { + + let app = common::spawn_app().await; // server + let client = reqwest::Client::new(); // client + + let data = r#" + { + "user_id": "fake_user_id", + "provider": "htz", + "cloud_token": "", + "cloud_key": "", + "cloud_secret": "", + "save_token": true + } + "#; + + let response = client + .post(&format!("{}/cloud", &app.address)) + .json(data) + .send() + .await + .expect("Failed to execute request."); + + println!("response: {}", response.status()); + assert!(response.status().is_success()); + assert_eq!(Some(0), response.content_length()); +} diff --git a/tests/dockerhub.rs b/tests/dockerhub.rs index 4134309..25b30e2 100644 --- a/tests/dockerhub.rs +++ b/tests/dockerhub.rs @@ -1,11 +1,13 @@ // use std::fs; // use std::collections::HashMap; use std::env; +use docker_compose_types::{ComposeVolume, SingleValue}; + mod common; use stacker::forms::project::DockerImage; -use stacker::helpers::project::dctypes::{ComposeVolume, SingleValue}; +// use stacker::helpers::project::dctypes::{ComposeVolume, SingleValue}; use serde_yaml; -use stacker::forms::Volume; +use stacker::forms::project::Volume; const DOCKER_USERNAME: &str = "trydirect"; const DOCKER_PASSWORD: &str = "***************"; From 47eac8fcf274bf1cb973797177c8354e671fd402 Mon Sep 17 00:00:00 2001 From: petru Date: Fri, 1 Mar 2024 16:54:41 +0200 Subject: [PATCH 197/284] 30-access-policies admin enable client --- src/routes/client/enable.rs | 30 ++++++++++++++++++++++++++---- src/startup.rs | 2 -- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/routes/client/enable.rs b/src/routes/client/enable.rs index c390a4e..7976411 100644 --- a/src/routes/client/enable.rs +++ b/src/routes/client/enable.rs @@ -8,7 +8,7 @@ use sqlx::PgPool; use std::sync::Arc; use tracing::Instrument; -#[tracing::instrument(name = "Enable client.")] +#[tracing::instrument(name = "User enable client.")] #[put("/{id}/enable")] pub async fn enable_handler( user: web::ReqData>, @@ -16,15 +16,37 @@ pub async fn enable_handler( pg_pool: web::Data, path: web::Path<(i32,)>, ) -> Result { - println!("user.id {}", user.id); - //todo the owner - //todo add admin endpoint let client_id = path.0; let mut client = db::client::fetch(pg_pool.get_ref(), client_id) .await .map_err(|msg| JsonResponse::::build().internal_server_error(msg))? .ok_or_else(|| JsonResponse::::build().not_found("not found"))?; + if client.user_id != user.id { + return Err(JsonResponse::::build().bad_request("client is not the owner")); + } + + enable_client(pg_pool, client).await +} + +#[tracing::instrument(name = "Admin enable client.")] +#[put("/{id}/enable")] +pub async fn admin_enable_handler( + user: web::ReqData>, + settings: web::Data, + pg_pool: web::Data, + path: web::Path<(i32,)>, +) -> Result { + let client_id = path.0; + let mut client = db::client::fetch(pg_pool.get_ref(), client_id) + .await + .map_err(|msg| JsonResponse::::build().internal_server_error(msg))? + .ok_or_else(|| JsonResponse::::build().not_found("not found"))?; + + enable_client(pg_pool, client).await +} + +async fn enable_client(pg_pool: web::Data, mut client: models::Client) -> Result { if client.secret.is_some() { return Err(JsonResponse::::build().bad_request("client is already active")); } diff --git a/src/startup.rs b/src/startup.rs index 5f0b30b..7e3786d 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -41,12 +41,10 @@ pub async fn run( .service(routes::client::enable_handler) .service(routes::client::disable_handler), ) - /* .service( web::scope("/admin/client") .service(routes::client::admin_enable_handler) ) - */ .service( web::scope("/test").service(routes::test::deploy::handler), ) From b9e6284ff791af65470eed20bcecf65ed8acfb20 Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 2 Mar 2024 16:36:36 +0200 Subject: [PATCH 198/284] 30-access-policies client admin --- src/routes/client/disable.rs | 31 +++++++++++++++++++++++++++---- src/routes/client/enable.rs | 10 +++++----- src/routes/client/update.rs | 33 ++++++++++++++++++++++++++++----- src/startup.rs | 2 ++ 4 files changed, 62 insertions(+), 14 deletions(-) diff --git a/src/routes/client/disable.rs b/src/routes/client/disable.rs index 3c46fa6..892d388 100644 --- a/src/routes/client/disable.rs +++ b/src/routes/client/disable.rs @@ -7,7 +7,7 @@ use sqlx::PgPool; use std::sync::Arc; use tracing::Instrument; -#[tracing::instrument(name = "Disable client.")] +#[tracing::instrument(name = "User disable client.")] #[put("/{id}/disable")] pub async fn disable_handler( user: web::ReqData>, @@ -15,20 +15,43 @@ pub async fn disable_handler( pg_pool: web::Data, path: web::Path<(i32,)>, ) -> Result { - //todo. the owner - //todo. add admin endpoint let client_id = path.0; let mut client = db::client::fetch(pg_pool.get_ref(), client_id) .await .map_err(|msg| JsonResponse::::build().internal_server_error(msg))? .ok_or_else(|| JsonResponse::::build().not_found("not found"))?; + if client.user_id != user.id { + return Err(JsonResponse::::build().bad_request("client is not the owner")); + } + + disable_client(pg_pool.get_ref(), client).await +} + +#[tracing::instrument(name = "Admin disable client.")] +#[put("/{id}/disable")] +pub async fn admin_disable_handler( + user: web::ReqData>, + settings: web::Data, + pg_pool: web::Data, + path: web::Path<(i32,)>, +) -> Result { + let client_id = path.0; + let mut client = db::client::fetch(pg_pool.get_ref(), client_id) + .await + .map_err(|msg| JsonResponse::::build().internal_server_error(msg))? + .ok_or_else(|| JsonResponse::::build().not_found("not found"))?; + + disable_client(pg_pool.get_ref(), client).await +} + +async fn disable_client(pg_pool: &PgPool, mut client: models::Client) -> Result { if client.secret.is_none() { return Err(JsonResponse::::build().bad_request("client is not active")); } client.secret = None; - db::client::update(pg_pool.get_ref(), client) + db::client::update(pg_pool, client) .await .map(|client| JsonResponse::build().set_item(client).ok("success")) .map_err(|msg| JsonResponse::::build().bad_request(msg)) diff --git a/src/routes/client/enable.rs b/src/routes/client/enable.rs index 7976411..5fb3c64 100644 --- a/src/routes/client/enable.rs +++ b/src/routes/client/enable.rs @@ -26,7 +26,7 @@ pub async fn enable_handler( return Err(JsonResponse::::build().bad_request("client is not the owner")); } - enable_client(pg_pool, client).await + enable_client(pg_pool.get_ref(), client).await } #[tracing::instrument(name = "Admin enable client.")] @@ -43,20 +43,20 @@ pub async fn admin_enable_handler( .map_err(|msg| JsonResponse::::build().internal_server_error(msg))? .ok_or_else(|| JsonResponse::::build().not_found("not found"))?; - enable_client(pg_pool, client).await + enable_client(pg_pool.get_ref(), client).await } -async fn enable_client(pg_pool: web::Data, mut client: models::Client) -> Result { +async fn enable_client(pg_pool: &PgPool, mut client: models::Client) -> Result { if client.secret.is_some() { return Err(JsonResponse::::build().bad_request("client is already active")); } - client.secret = helpers::client::generate_secret(pg_pool.get_ref(), 255) + client.secret = helpers::client::generate_secret(pg_pool, 255) .await .map(|secret| Some(secret)) .map_err(|err| JsonResponse::::build().bad_request(err))?; - db::client::update(pg_pool.get_ref(), client) + db::client::update(pg_pool, client) .await .map(|client| JsonResponse::build().set_item(client).ok("success")) .map_err(|err| JsonResponse::::build().bad_request(err)) diff --git a/src/routes/client/update.rs b/src/routes/client/update.rs index fe8db12..506fd53 100644 --- a/src/routes/client/update.rs +++ b/src/routes/client/update.rs @@ -7,7 +7,7 @@ use sqlx::PgPool; use std::sync::Arc; use tracing::Instrument; -#[tracing::instrument(name = "Update client.")] +#[tracing::instrument(name = "User update client.")] #[put("/{id}")] pub async fn update_handler( user: web::ReqData>, @@ -15,24 +15,47 @@ pub async fn update_handler( pg_pool: web::Data, path: web::Path<(i32,)>, ) -> Result { - //todo owner - //todo admin endpoint let client_id = path.0; let mut client = db::client::fetch(pg_pool.get_ref(), client_id) .await .map_err(|msg| JsonResponse::::build().internal_server_error(msg))? .ok_or_else(|| JsonResponse::::build().not_found("not found"))?; + if client.user_id != user.id { + return Err(JsonResponse::::build().bad_request("client is not the owner")); + } + + update_client(pg_pool.get_ref(), client).await +} + +#[tracing::instrument(name = "Admin update client.")] +#[put("/{id}")] +pub async fn admin_update_handler( + user: web::ReqData>, + settings: web::Data, + pg_pool: web::Data, + path: web::Path<(i32,)>, +) -> Result { + let client_id = path.0; + let mut client = db::client::fetch(pg_pool.get_ref(), client_id) + .await + .map_err(|msg| JsonResponse::::build().internal_server_error(msg))? + .ok_or_else(|| JsonResponse::::build().not_found("not found"))?; + + update_client(pg_pool.get_ref(), client).await +} + +async fn update_client(pg_pool: &PgPool, mut client: models::Client) -> Result { if client.secret.is_none() { return Err(JsonResponse::::build().bad_request("client is not active")); } - client.secret = client::generate_secret(pg_pool.get_ref(), 255) + client.secret = client::generate_secret(pg_pool, 255) .await .map(|s| Some(s)) .map_err(|msg| JsonResponse::::build().bad_request(msg))?; - db::client::update(pg_pool.get_ref(), client) + db::client::update(pg_pool, client) .await .map(|client| { JsonResponse::::build() diff --git a/src/startup.rs b/src/startup.rs index 7e3786d..22d071f 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -44,6 +44,8 @@ pub async fn run( .service( web::scope("/admin/client") .service(routes::client::admin_enable_handler) + .service(routes::client::admin_update_handler) + .service(routes::client::admin_disable_handler), ) .service( web::scope("/test").service(routes::test::deploy::handler), From de85d4b694ba6569a28fde0e818e615bcbe9b0ca Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 2 Mar 2024 17:19:31 +0200 Subject: [PATCH 199/284] 30-access-policies removed src/routes/stack/service.rs --- src/routes/stack/service.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/routes/stack/service.rs diff --git a/src/routes/stack/service.rs b/src/routes/stack/service.rs deleted file mode 100644 index e69de29..0000000 From 618c30ea735c267a85d6173d63b203a1f02373ab Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 2 Mar 2024 17:39:46 +0200 Subject: [PATCH 200/284] 30-access-policies owner logic for POST /stack/:id --- src/routes/stack/update.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/routes/stack/update.rs b/src/routes/stack/update.rs index ef11d82..72a0b44 100644 --- a/src/routes/stack/update.rs +++ b/src/routes/stack/update.rs @@ -27,11 +27,15 @@ pub async fn update( None => Err(JsonResponse::::build().not_found("Object not found")), })?; + if stack.user_id != user.id { + return Err(JsonResponse::::build().bad_request("client is not the owner")); + } + let stack_name = form.custom.custom_stack_code.clone(); tracing::debug!("form data: {:?}", form); let user_id = user.id.clone(); - if let Err(errors) = form.validate() { + if let Err(errors) = form.validate() { return Err(JsonResponse::::build().form_error(errors.to_string())); } From b599b98af9d5a7e5840239b270b3ff43846d4eb1 Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 2 Mar 2024 17:59:49 +0200 Subject: [PATCH 201/284] 30-access-policies admin, GET /stack/:id --- src/routes/stack/get.rs | 19 +++++++++++++++++++ src/startup.rs | 4 ++++ 2 files changed, 23 insertions(+) diff --git a/src/routes/stack/get.rs b/src/routes/stack/get.rs index ccb9c9d..d6b2e27 100644 --- a/src/routes/stack/get.rs +++ b/src/routes/stack/get.rs @@ -29,6 +29,25 @@ pub async fn item( }) } +#[tracing::instrument(name = "Get logged user stack.")] +#[get("/{id}")] +pub async fn admin_item( + user: web::ReqData>, + path: web::Path<(i32,)>, + pg_pool: web::Data, +) -> Result { + /// Get stack apps of logged user only + let (id,) = path.into_inner(); + + db::stack::fetch(pg_pool.get_ref(), id) + .await + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .and_then(|stack| match stack { + Some(stack) => Ok(JsonResponse::build().set_item(Some(stack)).ok("OK")), + None => Err(JsonResponse::::build().not_found("not found")), + }) +} + #[tracing::instrument(name = "Get user's stack list.")] #[get("/user/{id}")] pub async fn list( diff --git a/src/startup.rs b/src/startup.rs index 22d071f..c59aff8 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -69,6 +69,10 @@ pub async fn run( .service(routes::stack::add::add) .service(routes::stack::update::update), ) + .service( + web::scope("/admin/stack") + .service(routes::stack::get::admin_item) + ) .app_data(pg_pool.clone()) .app_data(mq_manager.clone()) .app_data(settings.clone()) From 15b890b61436ce190a41f1a52bab6ad88e74a990 Mon Sep 17 00:00:00 2001 From: petru Date: Sun, 3 Mar 2024 08:33:17 +0200 Subject: [PATCH 202/284] 30-access-policies GET /stack, GET /admin/stack/user/:id --- src/routes/stack/get.rs | 25 ++++++++++++++++++++----- src/startup.rs | 1 + 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/routes/stack/get.rs b/src/routes/stack/get.rs index d6b2e27..132a665 100644 --- a/src/routes/stack/get.rs +++ b/src/routes/stack/get.rs @@ -7,7 +7,22 @@ use std::convert::From; use std::sync::Arc; use tracing::Instrument; -#[tracing::instrument(name = "Get logged user stack.")] +#[tracing::instrument(name = "User get user's stack list.")] +#[get("")] +pub async fn list( + user: web::ReqData>, + pg_pool: web::Data, +) -> Result { + /// This is admin endpoint, used by a client app, client app is confidential + /// it should return stacks by user id + /// in order to pass validation at external deployment service + db::stack::fetch_by_user(pg_pool.get_ref(), &user.id) + .await + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .map(|stacks| JsonResponse::build().set_list(stacks).ok("OK")) +} + +#[tracing::instrument(name = "User get logged user stack.")] #[get("/{id}")] pub async fn item( user: web::ReqData>, @@ -29,7 +44,7 @@ pub async fn item( }) } -#[tracing::instrument(name = "Get logged user stack.")] +#[tracing::instrument(name = "Admin get logged user stack.")] #[get("/{id}")] pub async fn admin_item( user: web::ReqData>, @@ -48,10 +63,10 @@ pub async fn admin_item( }) } -#[tracing::instrument(name = "Get user's stack list.")] +#[tracing::instrument(name = "User get user's stack list.")] #[get("/user/{id}")] -pub async fn list( - user: web::ReqData>, +pub async fn admin_list( + admin: web::ReqData>, path: web::Path<(String,)>, pg_pool: web::Data, ) -> Result { diff --git a/src/startup.rs b/src/startup.rs index c59aff8..b805266 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -72,6 +72,7 @@ pub async fn run( .service( web::scope("/admin/stack") .service(routes::stack::get::admin_item) + .service(routes::stack::get::admin_list) ) .app_data(pg_pool.clone()) .app_data(mq_manager.clone()) From 9f92af23c35300c69b5b7b1b27dc3355a23cfc87 Mon Sep 17 00:00:00 2001 From: vsilent Date: Mon, 4 Mar 2024 10:27:41 +0200 Subject: [PATCH 203/284] delete action for project/cloud/server, require review and optimization (duplicates etc) --- ...g_original_request_column_project.down.sql | 2 + ...ing_original_request_column_project.up.sql | 1 + src/db/cloud.rs | 36 +++++++++++++ src/db/project.rs | 18 ++++--- src/db/server.rs | 36 +++++++++++++ src/forms/project/form.rs | 2 +- src/models/project.rs | 11 ++-- src/routes/cloud/delete.rs | 51 ++++++++++++++++++ src/routes/cloud/mod.rs | 2 + src/routes/project/add.rs | 21 ++++++-- src/routes/project/delete.rs | 53 ++++++++++--------- src/routes/server/delete.rs | 50 +++++++++++++++++ src/routes/server/mod.rs | 2 + 13 files changed, 243 insertions(+), 42 deletions(-) create mode 100644 migrations/20240302081015_creating_original_request_column_project.down.sql create mode 100644 migrations/20240302081015_creating_original_request_column_project.up.sql create mode 100644 src/routes/cloud/delete.rs create mode 100644 src/routes/server/delete.rs diff --git a/migrations/20240302081015_creating_original_request_column_project.down.sql b/migrations/20240302081015_creating_original_request_column_project.down.sql new file mode 100644 index 0000000..93549b5 --- /dev/null +++ b/migrations/20240302081015_creating_original_request_column_project.down.sql @@ -0,0 +1,2 @@ +-- Add down migration script here +ALTER table project DROP COLUMN request_json; diff --git a/migrations/20240302081015_creating_original_request_column_project.up.sql b/migrations/20240302081015_creating_original_request_column_project.up.sql new file mode 100644 index 0000000..2c1ba74 --- /dev/null +++ b/migrations/20240302081015_creating_original_request_column_project.up.sql @@ -0,0 +1 @@ +ALTER table project ADD COLUMN request_json JSON NOT NULL DEFAULT '{}'; \ No newline at end of file diff --git a/src/db/cloud.rs b/src/db/cloud.rs index 0385434..d1b332f 100644 --- a/src/db/cloud.rs +++ b/src/db/cloud.rs @@ -118,3 +118,39 @@ pub async fn update(pool: &PgPool, mut cloud: models::Cloud) -> Result Result { + tracing::info!("Delete cloud {}", id); + let mut tx = match pool.begin().await { + Ok(result) => result, + Err(err) => { + tracing::error!("Failed to begin transaction: {:?}", err); + return Err("".to_string()); + } + }; + + let delete_query = " DELETE FROM cloud WHERE id = $1; "; + + match sqlx::query(delete_query) + .bind(id) + .execute(&mut tx) + .await + .map_err(|err| { + println!("{:?}", err) + }) + { + Ok(_) => { + tx.commit().await.map_err(|err| { + tracing::error!("Failed to commit transaction: {:?}", err); + false + }); + Ok(true) + } + Err(err) => { + tx.rollback().await.map_err(|err| println!("{:?}", err)); + Ok(false) + } + } + +} diff --git a/src/db/project.rs b/src/db/project.rs index 8104b06..210a718 100644 --- a/src/db/project.rs +++ b/src/db/project.rs @@ -1,6 +1,5 @@ use crate::models; use sqlx::PgPool; -use sqlx::postgres::PgRow; use tracing::Instrument; pub async fn fetch(pool: &PgPool, id: i32) -> Result, String> { @@ -79,8 +78,8 @@ pub async fn insert(pool: &PgPool, mut project: models::Project) -> Result Result Result Result Result Result { tracing::info!("Delete project {}", id); let mut tx = match pool.begin().await { @@ -155,8 +158,8 @@ pub async fn delete(pool: &PgPool, id: i32) -> Result { // Combine delete queries into a single query let delete_query = " - DELETE FROM deployment WHERE project_id = $1; - DELETE FROM server WHERE project_id = $1; + --DELETE FROM deployment WHERE project_id = $1; // on delete cascade + --DELETE FROM server WHERE project_id = $1; // on delete cascade DELETE FROM project WHERE id = $1; "; @@ -179,8 +182,7 @@ pub async fn delete(pool: &PgPool, id: i32) -> Result { tx.rollback().await.map_err(|err| println!("{:?}", err)); Ok(false) } + // todo, when empty commit() } - // Ok(true) - } diff --git a/src/db/server.rs b/src/db/server.rs index c471cf7..10a0ea6 100644 --- a/src/db/server.rs +++ b/src/db/server.rs @@ -150,3 +150,39 @@ pub async fn update(pool: &PgPool, mut server: models::Server) -> Result Result { + tracing::info!("Delete server {}", id); + let mut tx = match pool.begin().await { + Ok(result) => result, + Err(err) => { + tracing::error!("Failed to begin transaction: {:?}", err); + return Err("".to_string()); + } + }; + + let delete_query = " DELETE FROM server WHERE id = $1; "; + + match sqlx::query(delete_query) + .bind(id) + .execute(&mut tx) + .await + .map_err(|err| { + println!("{:?}", err) + }) + { + Ok(_) => { + tx.commit().await.map_err(|err| { + tracing::error!("Failed to commit transaction: {:?}", err); + false + }); + Ok(true) + } + Err(err) => { + tx.rollback().await.map_err(|err| println!("{:?}", err)); + Ok(false) + } + } + +} diff --git a/src/forms/project/form.rs b/src/forms/project/form.rs index 4321f33..d29233f 100644 --- a/src/forms/project/form.rs +++ b/src/forms/project/form.rs @@ -25,7 +25,7 @@ pub struct ProjectForm { pub extended_features: Option>, pub subscriptions: Option>, pub form_app: Option>, - pub custom: forms::project::Custom, + pub custom: forms::project::Custom } impl TryFrom<&models::Project> for ProjectForm { diff --git a/src/models/project.rs b/src/models/project.rs index 06d2905..1f33df8 100644 --- a/src/models/project.rs +++ b/src/models/project.rs @@ -2,7 +2,6 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_json::Value; use uuid::Uuid; -use crate::db; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Project { @@ -13,19 +12,21 @@ pub struct Project { pub name: String, // pub body: sqlx::types::Json, pub body: Value, //json type + pub request_json: Value, pub created_at: DateTime, pub updated_at: DateTime, } impl Project { - pub fn new(user_id: String, name: String, body: Value) -> Self { + pub fn new(user_id: String, name: String, body: Value, request_json: Value) -> Self { Self { id: 0, stack_id: Uuid::new_v4(), cloud_id: None, - user_id: user_id, - name: name, - body: body, + user_id, + name, + body, + request_json, created_at: Utc::now(), updated_at: Utc::now(), } diff --git a/src/routes/cloud/delete.rs b/src/routes/cloud/delete.rs new file mode 100644 index 0000000..b69aec4 --- /dev/null +++ b/src/routes/cloud/delete.rs @@ -0,0 +1,51 @@ +use crate::helpers::JsonResponse; +use crate::models; +use actix_web::{delete, web, Responder, Result}; +use sqlx::PgPool; +use std::sync::Arc; +use futures_util::FutureExt; +use tracing::Instrument; +use crate::db; +use crate::models::Cloud; + +#[tracing::instrument(name = "Delete cloud record of a user.")] +#[delete("/{id}")] +pub async fn item( + user: web::ReqData>, + path: web::Path<(i32,)>, + pg_pool: web::Data, +) -> Result { + /// Get cloud apps of logged user only + let (id,) = path.into_inner(); + + let cloud = db::cloud::fetch(pg_pool.get_ref(), id) + .await + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .and_then(|cloud| { + match cloud { + Some(cloud) if cloud.user_id != user.id => { + Err(JsonResponse::::build().bad_request("Delete is forbidden")) + } + Some(cloud) => { + Ok(cloud) + }, + None => Err(JsonResponse::::build().not_found("")) + } + })?; + + db::cloud::delete(pg_pool.get_ref(), cloud.id) + .await + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .and_then(|result| { + match result + { + true => { + Ok(JsonResponse::::build().ok("Deleted")) + } + _ => { + Err(JsonResponse::::build().bad_request("Could not delete")) + } + } + }) + +} diff --git a/src/routes/cloud/mod.rs b/src/routes/cloud/mod.rs index a489a06..bc35158 100644 --- a/src/routes/cloud/mod.rs +++ b/src/routes/cloud/mod.rs @@ -1,7 +1,9 @@ pub mod add; pub mod get; pub mod update; +mod delete; pub use add::*; pub use get::*; pub use update::*; +pub use delete::*; diff --git a/src/routes/project/add.rs b/src/routes/project/add.rs index 05fb6cf..963e07e 100644 --- a/src/routes/project/add.rs +++ b/src/routes/project/add.rs @@ -13,6 +13,7 @@ use serde_valid::Validate; use sqlx::PgPool; use std::str; use std::sync::Arc; +use std::str::FromStr; #[tracing::instrument(name = "Add project.")] #[post("")] @@ -22,14 +23,27 @@ pub async fn item( pg_pool: Data, ) -> Result { // @todo ACL - let form = body_into_form(body).await?; + let form = body_into_form(body.clone()).await?; let project_name = form.custom.custom_stack_code.clone(); + //let request_json = Some(serde_json::Value::from_str(r#"{"somefield": "somevalue"}"#).unwrap()); + // let request_json = form.request_json.clone(); + let body_bytes = actix_web::body::to_bytes(body).await.unwrap(); + let body_str = str::from_utf8(&body_bytes) + .map_err(|err| JsonResponse::::build().internal_server_error(err.to_string()))?; + let request_json = Value::from_str(body_str).unwrap(); + tracing::debug!("Request json: {:?}", request_json); + let body: Value = serde_json::to_value::(form) .or(serde_json::to_value::(forms::project::ProjectForm::default())) .unwrap(); - let project = models::Project::new(user.id.clone(), project_name, body); + let project = models::Project::new( + user.id.clone(), + project_name, + body, + request_json + ); db::project::insert(pg_pool.get_ref(), project) .await .map(|project| JsonResponse::build().set_item(project).ok("Ok")) @@ -49,7 +63,7 @@ async fn body_into_form(body: Bytes) -> Result::build().bad_request(msg) }) - .and_then(|form: forms::project::ProjectForm| { + .and_then(|mut form: forms::project::ProjectForm| { if !form.validate().is_ok() { let errors = form.validate().unwrap_err().to_string(); let err_msg = format!("Invalid data received {:?}", &errors); @@ -61,3 +75,4 @@ async fn body_into_form(body: Bytes) -> Result::build().internal_server_error(err)) - .map(|project| { project }).unwrap(); - // - // match project { - // Some(project) if project.user_id != user.id => { - // Err(JsonResponse::::build().not_found("not found")) - // } - // Some(project) => { - // - // match db::project::delete(pg_pool.get_ref(), id) - // .await - // .map_err(|e| println!("{:?}", e)) - // { - // Ok(true) => { - // Ok(JsonResponse::build().set_item(Some(project)).ok("Deleted")) - // } - // _ => { - // Err(JsonResponse::::build().bad_request("Could not delete")) - // } - // } - // }, - // None => Err(JsonResponse::::build().not_found("not found")), - // } - // }) + .and_then(|project| { + match project { + Some(project) if project.user_id != user.id => { + Err(JsonResponse::::build().bad_request("Delete is forbidden")) + } + Some(project) => { + Ok(project) + }, + None => Err(JsonResponse::::build().not_found("")) + } + })?; + db::project::delete(pg_pool.get_ref(), project.id) + .await + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .and_then(|result| { + match result + { + true => { + Ok(JsonResponse::::build().ok("Deleted")) + } + _ => { + Err(JsonResponse::::build().bad_request("Could not delete")) + } + } + }) - Ok(JsonResponse::::build().ok("Deleted")) } diff --git a/src/routes/server/delete.rs b/src/routes/server/delete.rs new file mode 100644 index 0000000..cd9a824 --- /dev/null +++ b/src/routes/server/delete.rs @@ -0,0 +1,50 @@ +use crate::helpers::JsonResponse; +use crate::models; +use actix_web::{delete, web, Responder, Result}; +use sqlx::PgPool; +use std::sync::Arc; +use tracing::Instrument; +use crate::db; +use crate::models::Server; + +#[tracing::instrument(name = "Delete user's server.")] +#[delete("/{id}")] +pub async fn item( + user: web::ReqData>, + path: web::Path<(i32,)>, + pg_pool: web::Data, +) -> Result { + /// Get server apps of logged user only + let (id,) = path.into_inner(); + + let server = db::server::fetch(pg_pool.get_ref(), id) + .await + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .and_then(|server| { + match server { + Some(server) if server.user_id != user.id => { + Err(JsonResponse::::build().bad_request("Delete is forbidden")) + } + Some(server) => { + Ok(server) + }, + None => Err(JsonResponse::::build().not_found("")) + } + })?; + + db::server::delete(pg_pool.get_ref(), server.id) + .await + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .and_then(|result| { + match result + { + true => { + Ok(JsonResponse::::build().ok("Item deleted")) + } + _ => { + Err(JsonResponse::::build().bad_request("Could not delete")) + } + } + }) + +} diff --git a/src/routes/server/mod.rs b/src/routes/server/mod.rs index d3122a3..5f3597b 100644 --- a/src/routes/server/mod.rs +++ b/src/routes/server/mod.rs @@ -1,5 +1,7 @@ pub mod add; pub(crate) mod get; +mod delete; pub use add::*; pub use get::*; +pub use delete::*; From aca9fdc0880c56ec884df21addc5f43012a56123 Mon Sep 17 00:00:00 2001 From: vsilent Date: Mon, 4 Mar 2024 13:11:50 +0200 Subject: [PATCH 204/284] form fields fix for server/cloud --- src/db/cloud.rs | 4 +++- src/forms/cloud.rs | 7 ++++--- src/forms/server.rs | 9 +++++---- src/routes/cloud/mod.rs | 2 +- src/routes/server/mod.rs | 2 +- src/startup.rs | 2 ++ tests/mock_data/cloud.json | 8 ++++++++ tests/mock_data/project.json | 7 +++++++ tests/mock_data/server-update.json | 14 ++++++++++++++ tests/mock_data/server.json | 13 +++++++++++++ 10 files changed, 58 insertions(+), 10 deletions(-) create mode 100644 tests/mock_data/cloud.json create mode 100644 tests/mock_data/project.json create mode 100644 tests/mock_data/server-update.json create mode 100644 tests/mock_data/server.json diff --git a/src/db/cloud.rs b/src/db/cloud.rs index d1b332f..51c3f24 100644 --- a/src/db/cloud.rs +++ b/src/db/cloud.rs @@ -92,7 +92,8 @@ pub async fn update(pool: &PgPool, mut cloud: models::Cloud) -> Result Result for Cloud { let mut cloud = models::Cloud::default(); cloud.user_id = self.user_id; cloud.provider = self.provider; - cloud.cloud_token = Some(String::from("")); - cloud.cloud_key = Some(String::from("")); - cloud.cloud_secret = Some(String::from("")); + cloud.cloud_token = self.cloud_token; + cloud.cloud_key = self.cloud_key; + cloud.cloud_secret = self.cloud_secret; + cloud.save_token = self.save_token; cloud.created_at = Utc::now(); cloud.updated_at = Utc::now(); diff --git a/src/forms/server.rs b/src/forms/server.rs index edfe827..cc69c6d 100644 --- a/src/forms/server.rs +++ b/src/forms/server.rs @@ -21,10 +21,11 @@ impl Into for Server { server.user_id = self.user_id; server.cloud_id = self.cloud_id; server.project_id = self.project_id; - server.region = String::from(""); - server.zone = Some(String::from("")); - server.server = String::from(""); - server.os = String::from(""); + server.disk_type = self.disk_type; + server.region = self.region; + server.server = self.server; + server.zone = self.zone; + server.os = self.os; server.created_at = Utc::now(); server.updated_at = Utc::now(); diff --git a/src/routes/cloud/mod.rs b/src/routes/cloud/mod.rs index bc35158..bc45c2a 100644 --- a/src/routes/cloud/mod.rs +++ b/src/routes/cloud/mod.rs @@ -1,7 +1,7 @@ pub mod add; pub mod get; pub mod update; -mod delete; +pub(crate) mod delete; pub use add::*; pub use get::*; diff --git a/src/routes/server/mod.rs b/src/routes/server/mod.rs index 5f3597b..551560f 100644 --- a/src/routes/server/mod.rs +++ b/src/routes/server/mod.rs @@ -1,6 +1,6 @@ pub mod add; pub(crate) mod get; -mod delete; +pub(crate) mod delete; pub use add::*; pub use get::*; diff --git a/src/startup.rs b/src/startup.rs index 3c8165c..bcd1428 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -89,6 +89,7 @@ pub async fn run( .service(crate::routes::cloud::get::item) .service(crate::routes::cloud::get::list) .service(crate::routes::cloud::add::add) + .service(crate::routes::cloud::delete::item), ) .service( web::scope("/server") @@ -99,6 +100,7 @@ pub async fn run( .service(crate::routes::server::get::item) .service(crate::routes::server::get::list) .service(crate::routes::server::add::add) + .service(crate::routes::server::delete::item), ) .app_data(pg_pool.clone()) .app_data(mq_manager.clone()) diff --git a/tests/mock_data/cloud.json b/tests/mock_data/cloud.json new file mode 100644 index 0000000..9e680c9 --- /dev/null +++ b/tests/mock_data/cloud.json @@ -0,0 +1,8 @@ +{ + "user_id": "hy181TZa4DaabUZWklsrxw", + "provider": "htz", + "cloud_token": "cloud_token_here", + "cloud_key": "cloud_token_here", + "cloud_secret": "cloud_secret_here", + "save_token": true +} diff --git a/tests/mock_data/project.json b/tests/mock_data/project.json new file mode 100644 index 0000000..9ff62aa --- /dev/null +++ b/tests/mock_data/project.json @@ -0,0 +1,7 @@ +{ + "stack_id": "9239ea1d-8306-4493-aae1-fcc00de76241", + "user_id": "hy181TZa4DaabUZWklsrxw", + "name": "sample", + "body": "{}", + "cloud_id": 1 +} \ No newline at end of file diff --git a/tests/mock_data/server-update.json b/tests/mock_data/server-update.json new file mode 100644 index 0000000..4ad2173 --- /dev/null +++ b/tests/mock_data/server-update.json @@ -0,0 +1,14 @@ +{ + "id": 1, + "user_id": "hy181TZa4DaabUZWklsrxw", + "cloud_id": 1, + "region": "fra-1", + "zone": "a", + "server": "server-1", + "os": "3408230498203948234", + "disk_type": "samples", + "created_at": "", + "updated_at": "", + "project_id": 1 +} + diff --git a/tests/mock_data/server.json b/tests/mock_data/server.json new file mode 100644 index 0000000..cec56c9 --- /dev/null +++ b/tests/mock_data/server.json @@ -0,0 +1,13 @@ +{ + "user_id": "hy181TZa4DaabUZWklsrxw", + "cloud_id": 3, + "region": "fra-1", + "zone": "a", + "server": "server-1", + "os": "3408230498203948234", + "disk_type": "samples", + "created_at": "", + "updated_at": "", + "project_id":4 +} + From 98b5a7dda7a4247101dcb7072c6d34a1afe71fb3 Mon Sep 17 00:00:00 2001 From: petru Date: Mon, 4 Mar 2024 17:24:01 +0200 Subject: [PATCH 205/284] 30-access-policies /stack/:id/deploy --- src/routes/client/disable.rs | 14 ++++++++------ src/routes/stack/deploy.rs | 1 + src/routes/stack/update.rs | 5 +---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/routes/client/disable.rs b/src/routes/client/disable.rs index 892d388..08a310c 100644 --- a/src/routes/client/disable.rs +++ b/src/routes/client/disable.rs @@ -18,12 +18,14 @@ pub async fn disable_handler( let client_id = path.0; let mut client = db::client::fetch(pg_pool.get_ref(), client_id) .await - .map_err(|msg| JsonResponse::::build().internal_server_error(msg))? - .ok_or_else(|| JsonResponse::::build().not_found("not found"))?; - - if client.user_id != user.id { - return Err(JsonResponse::::build().bad_request("client is not the owner")); - } + .map_err(|msg| JsonResponse::::build().internal_server_error(msg)) + .and_then( |client| { + match client { + Some(client) if client.user_id != user.id => Err(JsonResponse::::build().bad_request("client is not the owner")), + Some(client) => Ok(client), + None => Err(JsonResponse::::build().not_found("not found")) + } + })?; disable_client(pg_pool.get_ref(), client).await } diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs index a2bf869..2120c16 100644 --- a/src/routes/stack/deploy.rs +++ b/src/routes/stack/deploy.rs @@ -25,6 +25,7 @@ pub async fn add( .await .map_err(|err| JsonResponse::::build().internal_server_error(err)) .and_then(|stack| match stack { + Some(stack) if stack.user_id != user.id => Err(JsonResponse::::build().bad_request("client is not the owner")), Some(stack) => Ok(stack), None => Err(JsonResponse::::build().not_found("not found")), })?; diff --git a/src/routes/stack/update.rs b/src/routes/stack/update.rs index 72a0b44..c2eae71 100644 --- a/src/routes/stack/update.rs +++ b/src/routes/stack/update.rs @@ -23,14 +23,11 @@ pub async fn update( .await .map_err(|err| JsonResponse::::build().internal_server_error(err)) .and_then(|stack| match stack { + Some(stack) if stack.user_id != user.id => Err(JsonResponse::::build().bad_request("client is not the owner")), Some(stack) => Ok(stack), None => Err(JsonResponse::::build().not_found("Object not found")), })?; - if stack.user_id != user.id { - return Err(JsonResponse::::build().bad_request("client is not the owner")); - } - let stack_name = form.custom.custom_stack_code.clone(); tracing::debug!("form data: {:?}", form); let user_id = user.id.clone(); From 4c152e9ebde4268543d4ae252de513761a3d91a5 Mon Sep 17 00:00:00 2001 From: vsilent Date: Mon, 4 Mar 2024 18:15:09 +0200 Subject: [PATCH 206/284] cloud update testing --- src/forms/cloud.rs | 2 +- src/forms/server.rs | 2 +- src/routes/cloud/update.rs | 55 ++++++++++++++++++++++ src/routes/project/add.rs | 1 + src/routes/project/update.rs | 13 +++-- src/routes/server/add.rs | 40 +++++++++++++++- src/startup.rs | 2 + tests/mock_data/cloud-update.json | 8 ++++ tests/mock_data/server-update-invalid.json | 14 ++++++ 9 files changed, 126 insertions(+), 11 deletions(-) create mode 100644 tests/mock_data/cloud-update.json create mode 100644 tests/mock_data/server-update-invalid.json diff --git a/src/forms/cloud.rs b/src/forms/cloud.rs index cbde8b0..357edd2 100644 --- a/src/forms/cloud.rs +++ b/src/forms/cloud.rs @@ -24,7 +24,7 @@ impl Into for Cloud { cloud.cloud_key = self.cloud_key; cloud.cloud_secret = self.cloud_secret; cloud.save_token = self.save_token; - cloud.created_at = Utc::now(); + // cloud.created_at = Utc::now(); cloud.updated_at = Utc::now(); cloud diff --git a/src/forms/server.rs b/src/forms/server.rs index cc69c6d..fac003f 100644 --- a/src/forms/server.rs +++ b/src/forms/server.rs @@ -2,7 +2,7 @@ use crate::models; use serde::{Deserialize, Serialize}; use serde_valid::Validate; use chrono::{DateTime, Utc}; - +use crate::db; #[derive(Serialize, Deserialize, Debug, Validate)] pub struct Server { pub user_id: String, diff --git a/src/routes/cloud/update.rs b/src/routes/cloud/update.rs index e69de29..d4fd238 100644 --- a/src/routes/cloud/update.rs +++ b/src/routes/cloud/update.rs @@ -0,0 +1,55 @@ +use crate::forms; +use crate::helpers::JsonResponse; +use crate::models; +use crate::db; +use actix_web::{web, web::Data, Responder, Result, post, put}; +use serde_valid::Validate; +use sqlx::PgPool; +use std::sync::Arc; +use tracing::Instrument; + +#[tracing::instrument(name = "Update cloud.")] +#[put("/{id}")] +pub async fn item( + path: web::Path<(i32,)>, + form: web::Json, + user: web::ReqData>, + pg_pool: Data, +) -> Result { + + let id = path.0; + let mut cloud_row = db::cloud::fetch(pg_pool.get_ref(), id) + .await + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .and_then(|cloud| match cloud { + Some(cloud) if cloud.user_id != user.id => { + Err(JsonResponse::::build().bad_request("Cloud not found")) + } + Some(cloud) => Ok(cloud), + None => Err(JsonResponse::::build().not_found("Cloud not found")), + })?; + + if let Err(errors) = form.validate() { + return Err(JsonResponse::::build().form_error(errors.to_string())); + } + + let mut cloud:models::Cloud = form.into_inner().into(); + cloud.id = cloud_row.id; + cloud.user_id = user.id.clone(); + // exclude + // cloud.created_at + + tracing::debug!("Updating cloud {:?}", cloud); + + db::cloud::update(pg_pool.get_ref(), cloud) + .await + .map(|cloud| { + JsonResponse::::build() + .set_item(cloud) + .ok("success") + }) + .map_err(|err| { + tracing::error!("Failed to execute query: {:?}", err); + JsonResponse::::build().internal_server_error("Could not update") + }) +} diff --git a/src/routes/project/add.rs b/src/routes/project/add.rs index 963e07e..729285c 100644 --- a/src/routes/project/add.rs +++ b/src/routes/project/add.rs @@ -44,6 +44,7 @@ pub async fn item( body, request_json ); + db::project::insert(pg_pool.get_ref(), project) .await .map(|project| JsonResponse::build().set_item(project).ok("Ok")) diff --git a/src/routes/project/update.rs b/src/routes/project/update.rs index e20d909..f59d45a 100644 --- a/src/routes/project/update.rs +++ b/src/routes/project/update.rs @@ -23,18 +23,19 @@ pub async fn item( .await .map_err(|err| JsonResponse::::build().internal_server_error(err)) .and_then(|project| match project { + Some(project) if project.user_id != user.id => { + Err(JsonResponse::::build().bad_request("Project not found")) + } Some(project) => Ok(project), - None => Err(JsonResponse::::build().not_found("Object not found")), + None => Err(JsonResponse::::build().not_found("Project not found")), })?; - let project_name = form.custom.custom_stack_code.clone(); tracing::debug!("form data: {:?}", form); - let user_id = user.id.clone(); - if let Err(errors) = form.validate() { return Err(JsonResponse::::build().form_error(errors.to_string())); } + let project_name = form.custom.custom_stack_code.clone(); let form_inner = form.into_inner(); if !form_inner.is_readable_docker_image().await.is_ok() { @@ -44,10 +45,8 @@ pub async fn item( let body: Value = serde_json::to_value::(form_inner) .map_err(|err| JsonResponse::::build().bad_request(format!("{err}")) - )?; + )?; - project.stack_id = Uuid::new_v4(); - project.user_id = user_id; project.name = project_name; project.body = body; diff --git a/src/routes/server/add.rs b/src/routes/server/add.rs index 278f4e9..e625df5 100644 --- a/src/routes/server/add.rs +++ b/src/routes/server/add.rs @@ -29,6 +29,35 @@ pub async fn add( return Err(JsonResponse::::build().form_error(errors)); } + db::cloud::fetch(pg_pool.get_ref(), form.cloud_id) + .await + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .and_then(|cloud| { + match cloud { + Some(cloud) if cloud.user_id != user.id => { + Err(JsonResponse::::build().bad_request("Cloud not found")) + } + Some(cloud) => { + Ok(cloud) + }, + None => Err(JsonResponse::::build().not_found("Cloud not found")) + } + })?; + + db::project::fetch(pg_pool.get_ref(), form.project_id) + .await + .map_err(|_err| JsonResponse::::build() + .bad_request("Invalid project")) + .and_then(|project| { + match project { + Some(project) if project.user_id != user.id => { + Err(JsonResponse::::build().bad_request("Project not found")) + } + Some(project) => { Ok(project) }, + None => Err(JsonResponse::::build().not_found("Project not found")) + } + })?; + let mut server: models::Server = form.into_inner().into(); server.user_id = user.id.clone(); @@ -37,6 +66,13 @@ pub async fn add( .map(|server| JsonResponse::build() .set_item(server) .ok("success")) - .map_err(|_err| JsonResponse::::build() - .internal_server_error("Failed to insert")) + .map_err(|err| + match err { + // sqlx::error::ErrorKind::ForeignKeyViolation => { + // return JsonResponse::::build().bad_request("Failed to insert"); + // } + _ => { + return JsonResponse::::build().internal_server_error("Failed to insert"); + } + }) } diff --git a/src/startup.rs b/src/startup.rs index bcd1428..06ada2a 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -89,6 +89,7 @@ pub async fn run( .service(crate::routes::cloud::get::item) .service(crate::routes::cloud::get::list) .service(crate::routes::cloud::add::add) + .service(crate::routes::cloud::update::item) .service(crate::routes::cloud::delete::item), ) .service( @@ -100,6 +101,7 @@ pub async fn run( .service(crate::routes::server::get::item) .service(crate::routes::server::get::list) .service(crate::routes::server::add::add) + // .service(crate::routes::server::update::item) .service(crate::routes::server::delete::item), ) .app_data(pg_pool.clone()) diff --git a/tests/mock_data/cloud-update.json b/tests/mock_data/cloud-update.json new file mode 100644 index 0000000..d436baa --- /dev/null +++ b/tests/mock_data/cloud-update.json @@ -0,0 +1,8 @@ +{ + "user_id": "hy181TZa4DaabUZWklsrxw", + "provider": "htz", + "cloud_token": "cloud_token_updates", + "cloud_key": "cloud_token_updates", + "cloud_secret": "cloud_secret_updates", + "save_token": false +} diff --git a/tests/mock_data/server-update-invalid.json b/tests/mock_data/server-update-invalid.json new file mode 100644 index 0000000..5110345 --- /dev/null +++ b/tests/mock_data/server-update-invalid.json @@ -0,0 +1,14 @@ +{ + "id": 1, + "user_id": "hy181TZa4DaabUZWklsrxw", + "cloud_id": 100000, + "region": "fra-1", + "zone": "a", + "server": "server-1", + "os": "3408230498203948234", + "disk_type": "samples", + "created_at": "", + "updated_at": "", + "project_id": 100000 +} + From 4cc54713087ed64479dac82715d1ed1480ed48e5 Mon Sep 17 00:00:00 2001 From: vsilent Date: Wed, 6 Mar 2024 12:19:53 +0200 Subject: [PATCH 207/284] project update fix, request_json updates, body_into_form moved to form --- src/db/client.rs | 2 +- src/db/deployment.rs | 2 +- src/db/project.rs | 2 +- src/forms/cloud.rs | 2 +- src/forms/project/form.rs | 28 ++++++++++++++++++++++++++-- src/forms/project/mod.rs | 2 +- src/forms/rating.rs | 2 +- src/routes/project/add.rs | 32 ++------------------------------ src/routes/project/update.rs | 32 ++++++++++++++++++++++---------- src/routes/server/add.rs | 3 ++- 10 files changed, 58 insertions(+), 49 deletions(-) diff --git a/src/db/client.rs b/src/db/client.rs index b8307a7..8f13d9a 100644 --- a/src/db/client.rs +++ b/src/db/client.rs @@ -19,7 +19,7 @@ pub async fn update(pool: &PgPool, client: models::Client) -> Result Result // .instrument(query_span) // .await // .map(|result|{ -// tracing::info!("Deployment {} have been saved to database", deployment.id); +// tracing::info!("Deployment {} has been saved to database", deployment.id); // deployment.updated_at = result.updated_at; // deployment // }) diff --git a/src/db/project.rs b/src/db/project.rs index 210a718..fdeb663 100644 --- a/src/db/project.rs +++ b/src/db/project.rs @@ -135,7 +135,7 @@ pub async fn update(pool: &PgPool, mut project: models::Project) -> Result for Cloud { cloud.cloud_key = self.cloud_key; cloud.cloud_secret = self.cloud_secret; cloud.save_token = self.save_token; - // cloud.created_at = Utc::now(); + cloud.created_at = Utc::now(); cloud.updated_at = Utc::now(); cloud diff --git a/src/forms/project/form.rs b/src/forms/project/form.rs index d29233f..73f0eb2 100644 --- a/src/forms/project/form.rs +++ b/src/forms/project/form.rs @@ -1,10 +1,12 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use serde_valid::Validate; -use std::collections::HashMap; -use std::fmt; +use actix_web::Error; +use actix_web::web::Bytes; use crate::models; use crate::forms; +use crate::helpers::JsonResponse; +use std::str; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] @@ -67,3 +69,25 @@ impl ProjectForm { } } +pub(crate) async fn body_into_form(body: Bytes) -> actix_web::Result { + let body_bytes = actix_web::body::to_bytes(body).await.unwrap(); + let body_str = str::from_utf8(&body_bytes) + .map_err(|err| JsonResponse::::build().internal_server_error(err.to_string()))?; + let deserializer = &mut serde_json::Deserializer::from_str(body_str); + serde_path_to_error::deserialize(deserializer) + .map_err(|err| { + let msg = format!("{}:{:?}", err.path().to_string(), err); + JsonResponse::::build().bad_request(msg) + }) + .and_then(|mut form: forms::project::ProjectForm| { + if !form.validate().is_ok() { + let errors = form.validate().unwrap_err().to_string(); + let err_msg = format!("Invalid data received {:?}", &errors); + tracing::debug!(err_msg); + + return Err(JsonResponse::::build().form_error(errors)); + } + + Ok(form) + }) +} diff --git a/src/forms/project/mod.rs b/src/forms/project/mod.rs index 29799fb..b0463a9 100644 --- a/src/forms/project/mod.rs +++ b/src/forms/project/mod.rs @@ -1,6 +1,6 @@ mod app; mod custom; -mod form; +pub(crate) mod form; mod port; mod payload; mod volumes; diff --git a/src/forms/rating.rs b/src/forms/rating.rs index 04b9b6b..e3f8281 100644 --- a/src/forms/rating.rs +++ b/src/forms/rating.rs @@ -17,7 +17,7 @@ impl Into for Rating { fn into(self) -> models::Rating { let mut rating = models::Rating::default(); rating.obj_id = self.obj_id; - rating.category = self.category.into(); //todo change the type of category field to the RateCategory + rating.category = self.category.into(); rating.hidden = Some(false); rating.rate = Some(self.rate); rating.comment = self.comment; diff --git a/src/routes/project/add.rs b/src/routes/project/add.rs index 729285c..e1b84bc 100644 --- a/src/routes/project/add.rs +++ b/src/routes/project/add.rs @@ -2,18 +2,16 @@ use crate::db; use crate::forms; use crate::helpers::JsonResponse; use crate::models; -use actix_web::Error; use actix_web::{ post, web, web::{Bytes, Data}, Responder, Result, }; use serde_json::Value; -use serde_valid::Validate; use sqlx::PgPool; -use std::str; use std::sync::Arc; use std::str::FromStr; +use std::str; #[tracing::instrument(name = "Add project.")] #[post("")] @@ -23,11 +21,9 @@ pub async fn item( pg_pool: Data, ) -> Result { // @todo ACL - let form = body_into_form(body.clone()).await?; + let form = forms::project::form::body_into_form(body.clone()).await?; let project_name = form.custom.custom_stack_code.clone(); - //let request_json = Some(serde_json::Value::from_str(r#"{"somefield": "somevalue"}"#).unwrap()); - // let request_json = form.request_json.clone(); let body_bytes = actix_web::body::to_bytes(body).await.unwrap(); let body_str = str::from_utf8(&body_bytes) .map_err(|err| JsonResponse::::build().internal_server_error(err.to_string()))?; @@ -53,27 +49,3 @@ pub async fn item( }) } - -async fn body_into_form(body: Bytes) -> Result { - let body_bytes = actix_web::body::to_bytes(body).await.unwrap(); - let body_str = str::from_utf8(&body_bytes) - .map_err(|err| JsonResponse::::build().internal_server_error(err.to_string()))?; - let deserializer = &mut serde_json::Deserializer::from_str(body_str); - serde_path_to_error::deserialize(deserializer) - .map_err(|err| { - let msg = format!("{}:{:?}", err.path().to_string(), err); - JsonResponse::::build().bad_request(msg) - }) - .and_then(|mut form: forms::project::ProjectForm| { - if !form.validate().is_ok() { - let errors = form.validate().unwrap_err().to_string(); - let err_msg = format!("Invalid data received {:?}", &errors); - tracing::debug!(err_msg); - - return Err(JsonResponse::::build().form_error(errors)); - } - - Ok(form) - }) -} - diff --git a/src/routes/project/update.rs b/src/routes/project/update.rs index f59d45a..ecd72b1 100644 --- a/src/routes/project/update.rs +++ b/src/routes/project/update.rs @@ -1,20 +1,22 @@ +use std::str::FromStr; use crate::forms; use crate::helpers::JsonResponse; use crate::models; use crate::db; -use actix_web::{web, web::Data, Responder, Result, post}; +use actix_web::{web, web::Data, Responder, Result, put}; use serde_json::Value; use serde_valid::Validate; use sqlx::PgPool; use std::sync::Arc; +use actix_web::web::Bytes; use tracing::Instrument; -use uuid::Uuid; +use std::str; #[tracing::instrument(name = "Update project.")] -#[post("/{id}")] +#[put("/{id}")] pub async fn item( path: web::Path<(i32,)>, - form: web::Json, + body: Bytes, user: web::ReqData>, pg_pool: Data, ) -> Result { @@ -30,25 +32,35 @@ pub async fn item( None => Err(JsonResponse::::build().not_found("Project not found")), })?; + let body_bytes = actix_web::body::to_bytes(body.clone()).await.unwrap(); + let body_str = str::from_utf8(&body_bytes) + .map_err(|err| JsonResponse::::build().internal_server_error(err.to_string()))?; + let request_json = Value::from_str(body_str)?; + tracing::debug!("Request json: {:?}", request_json); + + // @todo ACL + let form = forms::project::form::body_into_form(body.clone()).await?; tracing::debug!("form data: {:?}", form); + if let Err(errors) = form.validate() { return Err(JsonResponse::::build().form_error(errors.to_string())); } let project_name = form.custom.custom_stack_code.clone(); - let form_inner = form.into_inner(); - if !form_inner.is_readable_docker_image().await.is_ok() { + if !form.is_readable_docker_image().await.is_ok() { return Err(JsonResponse::::build().bad_request("Can not access docker image")); } - let body: Value = serde_json::to_value::(form_inner) - .map_err(|err| - JsonResponse::::build().bad_request(format!("{err}")) - )?; + let body: Value = serde_json::to_value::(form) + .or(serde_json::to_value::(forms::project::ProjectForm::default())) + .unwrap(); + project.name = project_name; project.body = body; + project.request_json = request_json; + db::project::update(pg_pool.get_ref(), project) .await diff --git a/src/routes/server/add.rs b/src/routes/server/add.rs index e625df5..020f55b 100644 --- a/src/routes/server/add.rs +++ b/src/routes/server/add.rs @@ -68,8 +68,9 @@ pub async fn add( .ok("success")) .map_err(|err| match err { + // sqlx::error::DatabaseError::kind() // sqlx::error::ErrorKind::ForeignKeyViolation => { - // return JsonResponse::::build().bad_request("Failed to insert"); + // return JsonResponse::::build().bad_request(""); // } _ => { return JsonResponse::::build().internal_server_error("Failed to insert"); From b46620a251c85923968371b0b0f334f0940363ba Mon Sep 17 00:00:00 2001 From: vsilent Date: Wed, 6 Mar 2024 13:24:05 +0200 Subject: [PATCH 208/284] icon attrs --- src/forms/project/icon_dark.rs | 6 +++++- src/forms/project/icon_light.rs | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/forms/project/icon_dark.rs b/src/forms/project/icon_dark.rs index 73c543e..d488f6a 100644 --- a/src/forms/project/icon_dark.rs +++ b/src/forms/project/icon_dark.rs @@ -1,4 +1,8 @@ use serde::{Deserialize, Serialize}; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct IconDark {} +pub struct IconDark { + width: Option, + height: Option, + image: Option +} diff --git a/src/forms/project/icon_light.rs b/src/forms/project/icon_light.rs index 8e9e4b8..90b2c6a 100644 --- a/src/forms/project/icon_light.rs +++ b/src/forms/project/icon_light.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct IconLight { - pub width: i64, - pub height: i64, - pub image: String, + pub width: Option, + pub height: Option, + pub image: Option, } From 5fad9d93c22f597b56762d11e898fed520e35aff Mon Sep 17 00:00:00 2001 From: petru Date: Fri, 8 Mar 2024 08:57:39 +0200 Subject: [PATCH 209/284] 30-access-polices working on the general JsonConfig --- src/startup.rs | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/startup.rs b/src/startup.rs index b805266..1047bea 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -4,8 +4,13 @@ use crate::routes; use actix_cors::Cors; use actix_web::dev::Server; use actix_web::{ - web::{self}, - App, HttpServer, + error, + web, + App, + HttpServer, + HttpResponse, + FromRequest, + rt, }; use crate::middleware; use sqlx::{Pool, Postgres}; @@ -24,6 +29,26 @@ pub async fn run( let mq_manager = web::Data::new(mq_manager); let authorization = middleware::authorization::try_new(settings.database.connection_string()).await?; + let json_cfg = web::JsonConfig::default() + .error_handler(|err, req| { + let bytes = web::Bytes::from_request(req, &mut actix_web::dev::Payload::None); + let rt = rt::Runtime::new().unwrap(); + let handle = rt.spawn(async move { + let bytes: web::Bytes = bytes.await.unwrap(); + }); + + rt.block_on(handle).unwrap(); //todo 1. get the result of bytes. + //todo 2. transform line, column into index + //todo 3. transform index in the start of json till the + //error occured + + match err { + error::JsonPayloadError::Deserialize(ref err) => println!("deserialize {err:?} {err}"), + _ => println!("sth else {err:?}") + } + + error::InternalError::from_response(err, HttpResponse::Conflict().into()).into() + }); let server = HttpServer::new(move || { App::new() @@ -74,6 +99,7 @@ pub async fn run( .service(routes::stack::get::admin_item) .service(routes::stack::get::admin_list) ) + .app_data(json_cfg.clone()) .app_data(pg_pool.clone()) .app_data(mq_manager.clone()) .app_data(settings.clone()) From 810bb6a0b4492122624e6969632393c9d995d4aa Mon Sep 17 00:00:00 2001 From: petru Date: Sun, 10 Mar 2024 02:10:32 +0200 Subject: [PATCH 210/284] 30-access-polices json errors --- src/routes/test/casbin.rs | 8 ----- src/routes/test/json_explain.rs | 37 +++++++++++++++++++++++ src/routes/test/mod.rs | 2 +- src/startup.rs | 53 +++++++++++++++++---------------- 4 files changed, 65 insertions(+), 35 deletions(-) delete mode 100644 src/routes/test/casbin.rs create mode 100644 src/routes/test/json_explain.rs diff --git a/src/routes/test/casbin.rs b/src/routes/test/casbin.rs deleted file mode 100644 index 77e1ec5..0000000 --- a/src/routes/test/casbin.rs +++ /dev/null @@ -1,8 +0,0 @@ -use actix_web::{get, Responder, Result}; -use crate::helpers::JsonResponse; - -#[tracing::instrument(name = "Test casbin.")] -#[get("")] -pub async fn handler() -> Result { - Ok(JsonResponse::::build().ok("success")) -} diff --git a/src/routes/test/json_explain.rs b/src/routes/test/json_explain.rs new file mode 100644 index 0000000..734a59a --- /dev/null +++ b/src/routes/test/json_explain.rs @@ -0,0 +1,37 @@ +use actix_web::{post, web, HttpResponse, Result, http::header::ContentType}; + +#[tracing::instrument(name = "Json explain")] +#[post("/json/explain/{line}/{column}")] +pub async fn handler(path: web::Path<(usize, usize,)>, body: web::Bytes) -> HttpResponse { + let line = path.0; + let column = path.1; + + let index = line_column_to_index(body.as_ref(), line, column); + let body = String::from_utf8(body.as_ref()[..index].to_vec()).unwrap(); //todo unwrap + + HttpResponse::Ok() + .content_type(ContentType::plaintext()) + .body(body) +} + +fn line_column_to_index(u8slice: &[u8], line: usize, column: usize) -> usize { + let mut l = 1; + let mut c = 0; + let mut i = 0; + for ch in u8slice { + i += 1; + match ch { + b'\n' => { + l += 1; + c = 0; + } + _ => { + c += 1; + } + } + if line == l && c == column { + break; + } + } + return i; +} diff --git a/src/routes/test/mod.rs b/src/routes/test/mod.rs index 2b55b42..9c49066 100644 --- a/src/routes/test/mod.rs +++ b/src/routes/test/mod.rs @@ -1,2 +1,2 @@ pub mod deploy; -pub mod casbin; +pub mod json_explain; diff --git a/src/startup.rs b/src/startup.rs index 1047bea..37892a3 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -29,27 +29,6 @@ pub async fn run( let mq_manager = web::Data::new(mq_manager); let authorization = middleware::authorization::try_new(settings.database.connection_string()).await?; - let json_cfg = web::JsonConfig::default() - .error_handler(|err, req| { - let bytes = web::Bytes::from_request(req, &mut actix_web::dev::Payload::None); - let rt = rt::Runtime::new().unwrap(); - let handle = rt.spawn(async move { - let bytes: web::Bytes = bytes.await.unwrap(); - }); - - rt.block_on(handle).unwrap(); //todo 1. get the result of bytes. - //todo 2. transform line, column into index - //todo 3. transform index in the start of json till the - //error occured - - match err { - error::JsonPayloadError::Deserialize(ref err) => println!("deserialize {err:?} {err}"), - _ => println!("sth else {err:?}") - } - - error::InternalError::from_response(err, HttpResponse::Conflict().into()).into() - }); - let server = HttpServer::new(move || { App::new() .wrap(TracingLogger::default()) @@ -73,10 +52,9 @@ pub async fn run( .service(routes::client::admin_disable_handler), ) .service( - web::scope("/test").service(routes::test::deploy::handler), - ) - .service( - web::scope("/pen/1").service(routes::test::casbin::handler), + web::scope("/test") + .service(routes::test::deploy::handler) + .service(routes::test::json_explain::handler), ) .service( web::scope("/rating") @@ -99,7 +77,6 @@ pub async fn run( .service(routes::stack::get::admin_item) .service(routes::stack::get::admin_list) ) - .app_data(json_cfg.clone()) .app_data(pg_pool.clone()) .app_data(mq_manager.clone()) .app_data(settings.clone()) @@ -109,3 +86,27 @@ pub async fn run( Ok(server) } + +fn line_column_to_index(u8slice: &[u8], line: usize, column: usize) -> usize { + let mut l = 1; + let mut c = 0; + let mut i = 0; + for ch in u8slice { + i += 1; + match ch { + b'\n' => { + l += 1; + c = 0; + } + _ => { + c += 1; + } + } + + if line == l && c == column { + break; + } + } + + return i; +} From a83071a7292816a9843cbf772a44cb13ba937017 Mon Sep 17 00:00:00 2001 From: petru Date: Mon, 11 Mar 2024 16:56:22 +0200 Subject: [PATCH 211/284] 30-access-policies json message for errors --- src/startup.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/startup.rs b/src/startup.rs index 37892a3..2240565 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -2,8 +2,9 @@ use crate::configuration::Settings; use crate::helpers; use crate::routes; use actix_cors::Cors; -use actix_web::dev::Server; use actix_web::{ + dev::Server, + http, error, web, App, @@ -29,6 +30,14 @@ pub async fn run( let mq_manager = web::Data::new(mq_manager); let authorization = middleware::authorization::try_new(settings.database.connection_string()).await?; + let json_config = web::JsonConfig::default() + .error_handler(|err, req| { + let msg: String = match err { + error::JsonPayloadError::Deserialize(err) => format!("{{\"kind\":\"deserialize\",\"line\":{}, \"column\":{}, \"msg\":\"{}\"}}", err.line(), err.column(), err), + _ => format!("{{\"kind\":\"other\",\"msg\":\"{}\"}}", err) + }; + error::InternalError::new(msg, http::StatusCode::BAD_REQUEST).into() + }); let server = HttpServer::new(move || { App::new() .wrap(TracingLogger::default()) @@ -77,6 +86,7 @@ pub async fn run( .service(routes::stack::get::admin_item) .service(routes::stack::get::admin_list) ) + .app_data(json_config.clone()) .app_data(pg_pool.clone()) .app_data(mq_manager.clone()) .app_data(settings.clone()) From b402c83e9bb7c7faaea976ed9aaebf19774662af Mon Sep 17 00:00:00 2001 From: petru Date: Mon, 11 Mar 2024 17:22:02 +0200 Subject: [PATCH 212/284] 30-access-policies json debug command. sketch --- src/console/commands/debug/json.rs | 23 +++++++++++++++++++++++ src/console/commands/debug/mod.rs | 3 +++ src/console/commands/mod.rs | 1 + src/console/main.rs | 22 ++++++++++++++++++++-- 4 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 src/console/commands/debug/json.rs create mode 100644 src/console/commands/debug/mod.rs diff --git a/src/console/commands/debug/json.rs b/src/console/commands/debug/json.rs new file mode 100644 index 0000000..63d90f5 --- /dev/null +++ b/src/console/commands/debug/json.rs @@ -0,0 +1,23 @@ +use crate::configuration::get_configuration; +use actix_web::rt; +use actix_web::web; +use sqlx::PgPool; + +pub struct JsonCommand { + line: usize, + column: usize, + payload: String +} + +impl JsonCommand { + pub fn new(line: usize, column: usize, payload: String) -> Self { + Self { line, column, payload } + } +} + +impl crate::console::commands::CallableTrait for JsonCommand { + fn call(&self) -> Result<(), Box> { + println!("line={} column={} payload={}", self.line, self.column, self.payload); + Ok(()) + } +} diff --git a/src/console/commands/debug/mod.rs b/src/console/commands/debug/mod.rs new file mode 100644 index 0000000..5f50076 --- /dev/null +++ b/src/console/commands/debug/mod.rs @@ -0,0 +1,3 @@ +mod json; + +pub use json::*; diff --git a/src/console/commands/mod.rs b/src/console/commands/mod.rs index 2cf75be..0b8d17a 100644 --- a/src/console/commands/mod.rs +++ b/src/console/commands/mod.rs @@ -1,4 +1,5 @@ pub mod appclient; +pub mod debug; mod callable; pub use callable::*; diff --git a/src/console/main.rs b/src/console/main.rs index 0921128..5d5b168 100644 --- a/src/console/main.rs +++ b/src/console/main.rs @@ -12,6 +12,10 @@ enum Commands { #[command(subcommand)] command: AppClientCommands, }, + Debug { + #[command(subcommand)] + command: DebugCommands, + }, } #[derive(Debug, Subcommand)] @@ -22,8 +26,17 @@ enum AppClientCommands { }, } -//todo add documentation about how to add a new command -//todo the helper from console should have a nicer display +#[derive(Debug, Subcommand)] +enum DebugCommands { + Json { + #[arg(long)] + line: usize, + #[arg(long)] + column: usize, + #[arg(long)] + payload: String, + }, +} fn main() -> Result<(), Box> { let cli = Cli::parse(); @@ -38,6 +51,11 @@ fn get_command(cli: Cli) -> Result match command { + DebugCommands::Json { line, column, payload } => Ok(Box::new( + stacker::console::commands::debug::JsonCommand::new(line, column, payload), + )), + }, _ => Err("command does not match".to_string()), } } From 2cf6a7599c63b825f6e0b32c3fccb82431126981 Mon Sep 17 00:00:00 2001 From: vsilent Date: Tue, 12 Mar 2024 16:58:54 +0200 Subject: [PATCH 213/284] payload fix for deploy command --- ...0230905145525_creating_stack_tables.up.sql | 2 +- ...7113718_alter_cloud_alter_project.down.sql | 3 + ...307113718_alter_cloud_alter_project.up.sql | 3 + src/db/cloud.rs | 24 +++--- src/db/project.rs | 17 ++-- src/db/server.rs | 15 +++- src/forms/cloud.rs | 19 ++++- src/forms/mod.rs | 2 + src/forms/project/payload.rs | 12 +-- src/forms/server.rs | 22 ++++- src/helpers/project/builder.rs | 4 +- src/models/cloud.rs | 1 + src/models/project.rs | 2 - src/routes/cloud/update.rs | 2 - src/routes/project/deploy.rs | 81 ++++++++++--------- src/routes/server/add.rs | 4 - src/routes/server/mod.rs | 4 +- src/routes/server/update.rs | 57 +++++++++++++ src/startup.rs | 2 +- tests/mock_data/project-update.json | 6 ++ 20 files changed, 198 insertions(+), 84 deletions(-) create mode 100644 migrations/20240307113718_alter_cloud_alter_project.down.sql create mode 100644 migrations/20240307113718_alter_cloud_alter_project.up.sql create mode 100644 src/routes/server/update.rs create mode 100644 tests/mock_data/project-update.json diff --git a/migrations/20230905145525_creating_stack_tables.up.sql b/migrations/20230905145525_creating_stack_tables.up.sql index 6ae6433..c002beb 100644 --- a/migrations/20230905145525_creating_stack_tables.up.sql +++ b/migrations/20230905145525_creating_stack_tables.up.sql @@ -2,7 +2,7 @@ CREATE TABLE project ( id serial4 NOT NULL, stack_id uuid NOT NULL, user_id VARCHAR(50) NOT NULL, - name TEXT, + name TEXT NOT NULL, body JSON NOT NULL, created_at timestamptz NOT NULL, updated_at timestamptz NOT NULL, diff --git a/migrations/20240307113718_alter_cloud_alter_project.down.sql b/migrations/20240307113718_alter_cloud_alter_project.down.sql new file mode 100644 index 0000000..06f51ab --- /dev/null +++ b/migrations/20240307113718_alter_cloud_alter_project.down.sql @@ -0,0 +1,3 @@ +-- Add down migration script here +ALTER table project ADD COLUMN cloud_id INT CONSTRAINT project_cloud_id REFERENCES cloud(id) ON UPDATE CASCADE ON DELETE CASCADE; +ALTER table cloud DROP COLUMN project_id; \ No newline at end of file diff --git a/migrations/20240307113718_alter_cloud_alter_project.up.sql b/migrations/20240307113718_alter_cloud_alter_project.up.sql new file mode 100644 index 0000000..554a24a --- /dev/null +++ b/migrations/20240307113718_alter_cloud_alter_project.up.sql @@ -0,0 +1,3 @@ +-- Add up migration script here +ALTER table project DROP COLUMN cloud_id; +ALTER table cloud ADD COLUMN project_id INT CONSTRAINT cloud_project_id REFERENCES project(id) ON UPDATE CASCADE ON DELETE CASCADE; diff --git a/src/db/cloud.rs b/src/db/cloud.rs index 51c3f24..07f5285 100644 --- a/src/db/cloud.rs +++ b/src/db/cloud.rs @@ -48,6 +48,7 @@ pub async fn insert(pool: &PgPool, mut cloud: models::Cloud) -> Result Result Result Result { }) { Ok(_) => { - tx.commit().await.map_err(|err| { + let _ = tx.commit().await.map_err(|err| { tracing::error!("Failed to commit transaction: {:?}", err); false }); Ok(true) } Err(err) => { - tx.rollback().await.map_err(|err| println!("{:?}", err)); + let _ = tx.rollback().await.map_err(|err| println!("{:?}", err)); Ok(false) } } diff --git a/src/db/project.rs b/src/db/project.rs index fdeb663..d1f469f 100644 --- a/src/db/project.rs +++ b/src/db/project.rs @@ -78,8 +78,8 @@ pub async fn insert(pool: &PgPool, mut project: models::Project) -> Result Result Result Result Result { + // return JsonResponse::::build().bad_request(""); + // } + // _ => { + // return JsonResponse::::build().internal_server_error("Failed to insert"); + // } + // }) tracing::error!("Failed to execute query: {:?}", e); "Failed to insert".to_string() }) @@ -121,7 +130,6 @@ pub async fn update(pool: &PgPool, mut server: models::Server) -> Result Result Result { }) { Ok(_) => { - tx.commit().await.map_err(|err| { + let _ = tx.commit().await.map_err(|err| { tracing::error!("Failed to commit transaction: {:?}", err); false }); Ok(true) } Err(err) => { - tx.rollback().await.map_err(|err| println!("{:?}", err)); + let _ = tx.rollback().await.map_err(|err| println!("{:?}", err)); Ok(false) } } diff --git a/src/forms/cloud.rs b/src/forms/cloud.rs index cbde8b0..9af0b4a 100644 --- a/src/forms/cloud.rs +++ b/src/forms/cloud.rs @@ -3,9 +3,10 @@ use serde::{Deserialize, Serialize}; use serde_valid::Validate; use chrono::{DateTime, Utc}; -#[derive(Serialize, Deserialize, Debug, Validate)] +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Cloud { pub user_id: String, + pub project_id: Option, #[validate(min_length = 2)] #[validate(max_length = 50)] pub provider: String, @@ -19,6 +20,7 @@ impl Into for Cloud { fn into(self) -> models::Cloud { let mut cloud = models::Cloud::default(); cloud.user_id = self.user_id; + cloud.project_id = self.project_id; cloud.provider = self.provider; cloud.cloud_token = self.cloud_token; cloud.cloud_key = self.cloud_key; @@ -30,3 +32,18 @@ impl Into for Cloud { cloud } } + +impl Into for models::Cloud { + fn into(self) -> Cloud { + let mut form = Cloud::default(); + form.user_id = self.user_id; + form.project_id = self.project_id; + form.provider = self.provider; + form.cloud_token = self.cloud_token; + form.cloud_key = self.cloud_key; + form.cloud_secret = self.cloud_secret; + form.save_token = self.save_token; + + form + } +} diff --git a/src/forms/mod.rs b/src/forms/mod.rs index f152263..f5fcc9c 100644 --- a/src/forms/mod.rs +++ b/src/forms/mod.rs @@ -5,3 +5,5 @@ pub(crate) mod cloud; pub(crate) mod server; pub use rating::*; +pub use cloud::*; +pub use server::*; diff --git a/src/forms/project/payload.rs b/src/forms/project/payload.rs index 70e8f60..aee8a4c 100644 --- a/src/forms/project/payload.rs +++ b/src/forms/project/payload.rs @@ -15,7 +15,7 @@ pub struct Payload { pub common_domain: String, pub domain_list: Option, #[serde(flatten)] - pub server: models::Server, + pub server: Option, pub ssl: String, pub vars: Option>, #[serde(rename = "integrated_features")] @@ -26,7 +26,7 @@ pub struct Payload { pub form_app: Option>, pub disk_type: Option, #[serde(flatten)] - pub cloud: models::Cloud, + pub cloud: Option, pub stack_code: String, pub custom: forms::project::Custom, pub docker_compose: Option>, @@ -36,9 +36,11 @@ impl TryFrom<&models::Project> for Payload { type Error = String; fn try_from(project: &models::Project) -> Result { - let mut project_data = serde_json::from_value::(project.body.clone()).map_err(|err| { - format!("{:?}", err) - })?; + // tracing::debug!("project body: {:?}", project.body.clone()); + let mut project_data = serde_json::from_value::(project.body.clone()) + .map_err(|err| { + format!("{:?}", err) + })?; project_data.id = Some(project.id.clone()); project_data.stack_code = project_data.custom.custom_stack_code.clone(); diff --git a/src/forms/server.rs b/src/forms/server.rs index fac003f..d66cde0 100644 --- a/src/forms/server.rs +++ b/src/forms/server.rs @@ -2,8 +2,9 @@ use crate::models; use serde::{Deserialize, Serialize}; use serde_valid::Validate; use chrono::{DateTime, Utc}; -use crate::db; -#[derive(Serialize, Deserialize, Debug, Validate)] +use crate::forms; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Server { pub user_id: String, pub cloud_id: i32, @@ -32,3 +33,20 @@ impl Into for Server { server } } + +impl Into for models::Server { + + fn into(self) -> Server { + let mut form = Server::default(); + form.user_id = self.user_id; + form.cloud_id = self.cloud_id; + form.project_id = self.project_id; + form.disk_type = self.disk_type; + form.region = self.region; + form.server = self.server; + form.zone = self.zone; + form.os = self.os; + + form + } +} diff --git a/src/helpers/project/builder.rs b/src/helpers/project/builder.rs index b5b0e42..7112fe3 100644 --- a/src/helpers/project/builder.rs +++ b/src/helpers/project/builder.rs @@ -30,9 +30,12 @@ impl DcBuilder { }; let apps = forms::project::ProjectForm::try_from(&self.project)?; + tracing::debug!("apps {:?}", &apps); let services = apps.custom.services()?; + tracing::debug!("services {:?}", &services); let named_volumes = apps.custom.named_volumes()?; + tracing::debug!("named volumes {:?}", &named_volumes); // let all_networks = &apps.custom.networks.networks.clone().unwrap_or(vec![]); let networks = apps.custom.networks.clone(); compose_content.networks = dctypes::ComposeNetworks(networks.into()); @@ -41,7 +44,6 @@ impl DcBuilder { compose_content.volumes = dctypes::TopLevelVolumes(named_volumes); } - tracing::debug!("services {:?}", &services); compose_content.services = dctypes::Services(services); let fname = format!("./files/{}.yml", self.project.stack_id); diff --git a/src/models/cloud.rs b/src/models/cloud.rs index 308950d..91b494c 100644 --- a/src/models/cloud.rs +++ b/src/models/cloud.rs @@ -5,6 +5,7 @@ use serde_derive::{Deserialize, Serialize}; pub struct Cloud { pub id: i32, pub user_id: String, + pub project_id: Option, pub provider: String, pub cloud_token: Option, pub cloud_key: Option, diff --git a/src/models/project.rs b/src/models/project.rs index 1f33df8..7742267 100644 --- a/src/models/project.rs +++ b/src/models/project.rs @@ -6,7 +6,6 @@ use uuid::Uuid; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Project { pub id: i32, // id - is a unique identifier for the app project - pub cloud_id: Option, // cloud assigned to a project pub stack_id: Uuid, // external project ID pub user_id: String, // external unique identifier for the user pub name: String, @@ -22,7 +21,6 @@ impl Project { Self { id: 0, stack_id: Uuid::new_v4(), - cloud_id: None, user_id, name, body, diff --git a/src/routes/cloud/update.rs b/src/routes/cloud/update.rs index d4fd238..2a69237 100644 --- a/src/routes/cloud/update.rs +++ b/src/routes/cloud/update.rs @@ -36,8 +36,6 @@ pub async fn item( let mut cloud:models::Cloud = form.into_inner().into(); cloud.id = cloud_row.id; cloud.user_id = user.id.clone(); - // exclude - // cloud.created_at tracing::debug!("Updating cloud {:?}", cloud); diff --git a/src/routes/project/deploy.rs b/src/routes/project/deploy.rs index f3144f0..6bbb4cd 100644 --- a/src/routes/project/deploy.rs +++ b/src/routes/project/deploy.rs @@ -12,15 +12,19 @@ use crate::helpers::compressor::compress; #[tracing::instrument(name = "Deploy for every user. Admin endpoint")] -#[post("/{id}/deploy")] -pub async fn add( +#[post("/{id}/deploy/{cloud_id}")] +pub async fn item( user: web::ReqData>, - path: web::Path<(i32,)>, + path: web::Path<(i32, i32)>, pg_pool: Data, mq_manager: Data, sets: Data, ) -> Result { let id = path.0; + let cloud_id = path.1; + //let cloud_id = Some(1); + tracing::debug!("User {:?} is deploying project: {} to cloud: {} ", user, id, cloud_id); + let project = db::project::fetch(pg_pool.get_ref(), id) .await .map_err(|err| JsonResponse::::build().internal_server_error(err)) @@ -35,43 +39,43 @@ pub async fn add( JsonResponse::::build().internal_server_error(err) })?; - let mut project_data = forms::project::Payload::try_from(&dc.project) - .map_err(|err| JsonResponse::::build().bad_request(err))?; - project_data.user_token = Some(user.id.clone()); - project_data.user_email = Some(user.email.clone()); - // let compressed = fc.unwrap_or("".to_string()); - project_data.docker_compose = Some(compress(fc.as_str())); - - if let Some(cloud_id) = dc.project.cloud_id { - project_data.cloud = match db::cloud::fetch(pg_pool.get_ref(), cloud_id).await { - Ok(cloud) => { - match cloud { - Some(cloud) => cloud, - None => { - return Err(JsonResponse::::build().not_found("No cloud configured")); - } + let cloud = match db::cloud::fetch(pg_pool.get_ref(), cloud_id).await { + Ok(cloud) => { + match cloud { + Some(cloud) => cloud, + None => { + return Err(JsonResponse::::build().not_found("No cloud configured")); } } - Err(e) => { - return Err(JsonResponse::::build().not_found("No cloud configured")); - } - }; + } + Err(e) => { + return Err(JsonResponse::::build().not_found("No cloud configured")); + } + }; - project_data.server = match db::server::fetch_by_project(pg_pool.get_ref(), dc.project.id.clone()).await { - Ok(server) => { - // for now we support only one type of servers - // if let Some(server) = server.into_iter().nth(0) { - // server - // } - server.into_iter().nth(0).unwrap() // @todo refactoring is required - } - Err(err) => { - return Err(JsonResponse::::build().not_found("No servers configured")); - } + let server = match db::server::fetch_by_project(pg_pool.get_ref(), dc.project.id.clone()).await { + Ok(server) => { + // for now we support only one type of servers + // if let Some(server) = server.into_iter().nth(0) { + // server + // } + server.into_iter().nth(0).unwrap() // @todo refactoring is required } - } else { - return Err(JsonResponse::::build().not_found("No cloud provider configured")); - } + Err(err) => { + return Err(JsonResponse::::build().not_found("No servers configured")); + } + }; + + // let mut payload = forms::project::Payload::default(); + let mut payload = forms::project::Payload::try_from(&dc.project) + .map_err(|err| JsonResponse::::build().bad_request(err))?; + payload.server = Some(server.into()); + payload.cloud = Some(cloud.into()); + payload.user_token = Some(user.id.clone()); + payload.user_email = Some(user.email.clone()); + // let compressed = fc.unwrap_or("".to_string()); + payload.docker_compose = Some(compress(fc.as_str())); + let project_id = dc.project.id.clone(); let json_request = dc.project.body.clone(); @@ -89,12 +93,13 @@ pub async fn add( }); tracing::debug!("Save deployment result: {:?}", result); + tracing::debug!("Send project data <<<<<<<<<<<>>>>>>>>>>>>>>>>{:?}", payload); mq_manager - .publish_and_confirm( + .publish( "install".to_string(), "install.start.tfa.all.all".to_string(), - &project_data, + &payload, ) .await .map_err(|err| JsonResponse::::build().internal_server_error(err)) diff --git a/src/routes/server/add.rs b/src/routes/server/add.rs index 020f55b..96ea390 100644 --- a/src/routes/server/add.rs +++ b/src/routes/server/add.rs @@ -68,10 +68,6 @@ pub async fn add( .ok("success")) .map_err(|err| match err { - // sqlx::error::DatabaseError::kind() - // sqlx::error::ErrorKind::ForeignKeyViolation => { - // return JsonResponse::::build().bad_request(""); - // } _ => { return JsonResponse::::build().internal_server_error("Failed to insert"); } diff --git a/src/routes/server/mod.rs b/src/routes/server/mod.rs index 551560f..319c89f 100644 --- a/src/routes/server/mod.rs +++ b/src/routes/server/mod.rs @@ -1,7 +1,9 @@ pub mod add; pub(crate) mod get; pub(crate) mod delete; +mod update; -pub use add::*; pub use get::*; +pub use add::*; +pub use update::*; pub use delete::*; diff --git a/src/routes/server/update.rs b/src/routes/server/update.rs new file mode 100644 index 0000000..b708778 --- /dev/null +++ b/src/routes/server/update.rs @@ -0,0 +1,57 @@ +use crate::forms; +use crate::helpers::JsonResponse; +use crate::models; +use crate::db; +use actix_web::{web, web::Data, Responder, Result, post, put}; +use serde_valid::Validate; +use sqlx::PgPool; +use std::sync::Arc; +use tracing::Instrument; + +#[tracing::instrument(name = "Update server.")] +#[put("/{id}")] +pub async fn item( + path: web::Path<(i32,)>, + form: web::Json, + user: web::ReqData>, + pg_pool: Data, +) -> Result { + + let id = path.0; + let mut server_row = db::server::fetch(pg_pool.get_ref(), id) + .await + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .and_then(|server| match server { + Some(server) if server.user_id != user.id => { + Err(JsonResponse::::build().bad_request("Server not found")) + } + Some(server) => Ok(server), + None => Err(JsonResponse::::build().not_found("Server not found")), + })?; + + if let Err(errors) = form.validate() { + return Err(JsonResponse::::build().form_error(errors.to_string())); + } + + let mut server:models::Server = form.into_inner().into(); + server.id = server_row.id; + server.cloud_id = server_row.cloud_id; + server.project_id = server_row.project_id; + server.user_id = user.id.clone(); + // exclude + // server.created_at + + tracing::debug!("Updating server {:?}", server); + + db::server::update(pg_pool.get_ref(), server) + .await + .map(|server| { + JsonResponse::::build() + .set_item(server) + .ok("success") + }) + .map_err(|err| { + tracing::error!("Failed to execute query: {:?}", err); + JsonResponse::::build().internal_server_error("Could not update server") + }) +} diff --git a/src/startup.rs b/src/startup.rs index 06ada2a..612d321 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -71,7 +71,7 @@ pub async fn run( middleware::trydirect::bearer_guard, )) .wrap(Cors::permissive()) - .service(crate::routes::project::deploy::add) + .service(crate::routes::project::deploy::item) .service(crate::routes::project::compose::add) .service(crate::routes::project::compose::admin) .service(crate::routes::project::get::item) diff --git a/tests/mock_data/project-update.json b/tests/mock_data/project-update.json new file mode 100644 index 0000000..4c0e7c7 --- /dev/null +++ b/tests/mock_data/project-update.json @@ -0,0 +1,6 @@ +{ + "stack_id": "9239ea1d-8306-4493-aae1-fcc00de76241", + "user_id": "hy181TZa4DaabUZWklsrxw", + "name": "sample", + "body": "{}" +} \ No newline at end of file From d708f82787398988755d13c49a3b13786ee6ffcc Mon Sep 17 00:00:00 2001 From: petru Date: Wed, 13 Mar 2024 16:50:37 +0200 Subject: [PATCH 214/284] 30-access-policies read payload from file --- src/console/commands/debug/json.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/console/commands/debug/json.rs b/src/console/commands/debug/json.rs index 63d90f5..544b1b5 100644 --- a/src/console/commands/debug/json.rs +++ b/src/console/commands/debug/json.rs @@ -17,7 +17,8 @@ impl JsonCommand { impl crate::console::commands::CallableTrait for JsonCommand { fn call(&self) -> Result<(), Box> { - println!("line={} column={} payload={}", self.line, self.column, self.payload); + let payload = std::fs::read_to_string(&self.payload)?; + println!("line={} column={} payload={}", self.line, self.column, payload); Ok(()) } } From fd47bfc7a292e908046386038b43a5653bd9ce3e Mon Sep 17 00:00:00 2001 From: petru Date: Fri, 15 Mar 2024 16:56:31 +0200 Subject: [PATCH 215/284] 30-access-policies - json debug command --- src/console/commands/debug/json.rs | 33 ++++++++++++++++++++++---- src/routes/test/json_explain.rs | 37 ------------------------------ src/routes/test/mod.rs | 1 - src/startup.rs | 1 - 4 files changed, 28 insertions(+), 44 deletions(-) delete mode 100644 src/routes/test/json_explain.rs diff --git a/src/console/commands/debug/json.rs b/src/console/commands/debug/json.rs index 544b1b5..047faf0 100644 --- a/src/console/commands/debug/json.rs +++ b/src/console/commands/debug/json.rs @@ -1,7 +1,5 @@ use crate::configuration::get_configuration; -use actix_web::rt; -use actix_web::web; -use sqlx::PgPool; +use actix_web::{rt, post, web, HttpResponse, Result, http::header::ContentType}; pub struct JsonCommand { line: usize, @@ -17,8 +15,33 @@ impl JsonCommand { impl crate::console::commands::CallableTrait for JsonCommand { fn call(&self) -> Result<(), Box> { - let payload = std::fs::read_to_string(&self.payload)?; - println!("line={} column={} payload={}", self.line, self.column, payload); + let payload: String = std::fs::read_to_string(&self.payload)?; + let index = line_column_to_index(payload.as_ref(), self.line, self.column); + let prefix = String::from_utf8(>::as_ref(&payload)[..index].to_vec()).unwrap(); + + println!("{}", prefix); Ok(()) } } + +fn line_column_to_index(u8slice: &[u8], line: usize, column: usize) -> usize { + let mut l = 1; + let mut c = 0; + let mut i = 0; + for ch in u8slice { + i += 1; + match ch { + b'\n' => { + l += 1; + c = 0; + } + _ => { + c += 1; + } + } + if line == l && c == column { + break; + } + } + return i; +} diff --git a/src/routes/test/json_explain.rs b/src/routes/test/json_explain.rs deleted file mode 100644 index 734a59a..0000000 --- a/src/routes/test/json_explain.rs +++ /dev/null @@ -1,37 +0,0 @@ -use actix_web::{post, web, HttpResponse, Result, http::header::ContentType}; - -#[tracing::instrument(name = "Json explain")] -#[post("/json/explain/{line}/{column}")] -pub async fn handler(path: web::Path<(usize, usize,)>, body: web::Bytes) -> HttpResponse { - let line = path.0; - let column = path.1; - - let index = line_column_to_index(body.as_ref(), line, column); - let body = String::from_utf8(body.as_ref()[..index].to_vec()).unwrap(); //todo unwrap - - HttpResponse::Ok() - .content_type(ContentType::plaintext()) - .body(body) -} - -fn line_column_to_index(u8slice: &[u8], line: usize, column: usize) -> usize { - let mut l = 1; - let mut c = 0; - let mut i = 0; - for ch in u8slice { - i += 1; - match ch { - b'\n' => { - l += 1; - c = 0; - } - _ => { - c += 1; - } - } - if line == l && c == column { - break; - } - } - return i; -} diff --git a/src/routes/test/mod.rs b/src/routes/test/mod.rs index 9c49066..40149b1 100644 --- a/src/routes/test/mod.rs +++ b/src/routes/test/mod.rs @@ -1,2 +1 @@ pub mod deploy; -pub mod json_explain; diff --git a/src/startup.rs b/src/startup.rs index 2240565..46d0b5b 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -63,7 +63,6 @@ pub async fn run( .service( web::scope("/test") .service(routes::test::deploy::handler) - .service(routes::test::json_explain::handler), ) .service( web::scope("/rating") From d89fb335de32db02c9a8aa31294997de6346ba27 Mon Sep 17 00:00:00 2001 From: vsilent Date: Fri, 15 Mar 2024 17:10:23 +0200 Subject: [PATCH 216/284] deploy function re-factoring, rabbitmq listener non-functional yet --- ...43712_remove_cloud_id_from_server.down.sql | 3 + ...5143712_remove_cloud_id_from_server.up.sql | 2 + src/console/commands/mod.rs | 2 + src/console/commands/mq/listener.rs | 88 +++++++++++ src/console/commands/mq/mod.rs | 2 + src/console/main.rs | 15 ++ src/db/deployment.rs | 70 +++++---- src/db/server.rs | 18 +-- src/forms/cloud.rs | 8 +- src/forms/project/deploy.rs | 27 ++++ src/forms/project/form.rs | 16 -- src/forms/project/mod.rs | 2 + src/forms/project/payload.rs | 18 +-- src/forms/server.rs | 16 +- src/helpers/mod.rs | 4 +- src/helpers/mq_manager.rs | 79 ++++++++-- src/models/deployment.rs | 4 +- src/models/mod.rs | 2 +- src/models/server.rs | 1 - src/routes/cloud/update.rs | 2 +- src/routes/project/deploy.rs | 118 ++++++++++++++- src/routes/server/add.rs | 139 +++++++++--------- src/routes/server/mod.rs | 2 +- src/routes/server/update.rs | 1 - src/startup.rs | 4 +- tests/mock_data/deploy.json | 0 tests/mock_data/deploy2.json | 1 + 27 files changed, 452 insertions(+), 192 deletions(-) create mode 100644 migrations/20240315143712_remove_cloud_id_from_server.down.sql create mode 100644 migrations/20240315143712_remove_cloud_id_from_server.up.sql create mode 100644 src/console/commands/mq/listener.rs create mode 100644 src/console/commands/mq/mod.rs create mode 100644 src/forms/project/deploy.rs create mode 100644 tests/mock_data/deploy.json create mode 100644 tests/mock_data/deploy2.json diff --git a/migrations/20240315143712_remove_cloud_id_from_server.down.sql b/migrations/20240315143712_remove_cloud_id_from_server.down.sql new file mode 100644 index 0000000..72dd11e --- /dev/null +++ b/migrations/20240315143712_remove_cloud_id_from_server.down.sql @@ -0,0 +1,3 @@ +-- Add down migration script here +DROP INDEX idx_server_cloud_id; +alter table server ADD column cloud_id integer NOT NULL; diff --git a/migrations/20240315143712_remove_cloud_id_from_server.up.sql b/migrations/20240315143712_remove_cloud_id_from_server.up.sql new file mode 100644 index 0000000..be9027c --- /dev/null +++ b/migrations/20240315143712_remove_cloud_id_from_server.up.sql @@ -0,0 +1,2 @@ +-- Add up migration script here +alter table server drop column cloud_id; diff --git a/src/console/commands/mod.rs b/src/console/commands/mod.rs index 2cf75be..585347d 100644 --- a/src/console/commands/mod.rs +++ b/src/console/commands/mod.rs @@ -1,4 +1,6 @@ pub mod appclient; mod callable; +pub mod mq; pub use callable::*; +pub use mq::*; diff --git a/src/console/commands/mq/listener.rs b/src/console/commands/mq/listener.rs new file mode 100644 index 0000000..75cae06 --- /dev/null +++ b/src/console/commands/mq/listener.rs @@ -0,0 +1,88 @@ +use crate::configuration::get_configuration; +use actix_web::rt; +use actix_web::web; +use lapin::{Channel, Queue}; +use lapin::options::{BasicAckOptions, BasicConsumeOptions}; +use lapin::types::FieldTable; +use sqlx::PgPool; +use db::deployment; +use crate::{db, helpers}; +use crate::helpers::mq_manager; +use crate::helpers::mq_manager::MqManager; + +pub struct ListenCommand { +} + +impl ListenCommand { + pub fn new() -> Self { + Self {} + } +} + +impl crate::console::commands::CallableTrait for ListenCommand { + + fn call(&self) -> Result<(), Box> { + rt::System::new().block_on(async { + let settings = get_configuration().expect("Failed to read configuration."); + let db_pool = PgPool::connect(&settings.database.connection_string()) + .await + .expect("Failed to connect to database."); + + let db_pool = web::Data::new(db_pool); + + let mq_manager = MqManager::try_new(settings.amqp.connection_string())?; + let consumer_channel= mq_manager + .consume( + "install_progress", + "install_progress_*******" + ) + .await?; + + + let consumer = consumer_channel + .basic_consume( + "install_progress", + "console_listener", + BasicConsumeOptions::default(), + FieldTable::default(), + ) + .await + .expect("Basic consume"); + + // .map_err(|err| format!("Error {:?}", err)); + + tracing::info!("will consume"); + // if let Ok(consumer) = consumer { + // while let Some(delivery) = consumer.next().await { + // let delivery = delivery.expect("error in consumer"); + // delivery.ack(BasicAckOptions::default()).await.expect("ack"); + // } + // } + + // while let Some(delivery) = consumer.next().await { + // tracing::debug!(message=?delivery, "received message"); + // if let Ok(delivery) = delivery { + // delivery + // .ack(BasicAckOptions::default()) + // .await + // .expect("basic_ack"); + // } + // } + + + // on_complete() + // let deployment = crate::models::deployment::Deployment { + // id: 0, + // project_id: 0, + // deleted: false, + // status: "".to_string(), + // body: Default::default(), + // created_at: Default::default(), + // updated_at: Default::default(), + // }; + // deployment::update(db_pool.get_ref(), deployment).await?; + + Ok(()) + }) + } +} diff --git a/src/console/commands/mq/mod.rs b/src/console/commands/mq/mod.rs new file mode 100644 index 0000000..0d4c7ef --- /dev/null +++ b/src/console/commands/mq/mod.rs @@ -0,0 +1,2 @@ +mod listener; +pub use listener::*; \ No newline at end of file diff --git a/src/console/main.rs b/src/console/main.rs index 0921128..752e10a 100644 --- a/src/console/main.rs +++ b/src/console/main.rs @@ -12,6 +12,10 @@ enum Commands { #[command(subcommand)] command: AppClientCommands, }, + MQ { + #[command(subcommand)] + command: AppMqCommands, + } } #[derive(Debug, Subcommand)] @@ -22,6 +26,12 @@ enum AppClientCommands { }, } +#[derive(Debug, Subcommand)] +enum AppMqCommands { + Listen { + }, +} + //todo add documentation about how to add a new command //todo the helper from console should have a nicer display @@ -38,6 +48,11 @@ fn get_command(cli: Cli) -> Result match command { + AppMqCommands::Listen {} => Ok(Box::new( + stacker::console::commands::mq::ListenCommand::new(), + )), + }, _ => Err("command does not match".to_string()), } } diff --git a/src/db/deployment.rs b/src/db/deployment.rs index 1bfb3b3..11e7a2e 100644 --- a/src/db/deployment.rs +++ b/src/db/deployment.rs @@ -30,39 +30,37 @@ pub async fn insert(pool: &PgPool, mut deployment: models::Deployment) -> Result }) } -// pub async fn update(pool: &PgPool, mut deployment: models::Deployment) -> Result { -// let query_span = tracing::info_span!("Updating user deployment into the database"); -// sqlx::query_as!( -// models::Deployment, -// r#" -// UPDATE deployment -// SET -// project_id=$2, -// deleted=$3, -// status=$4, -// body=$5, -// created_at=$6, -// updated_at=NOW() at time zone 'utc' -// WHERE id = $1 -// RETURNING * -// "#, -// deployment.id, -// deployment.project_id, -// deployment.deleted, -// deployment.status, -// deployment.body, -// deployment.created_at, -// ) -// .fetch_one(pool) -// .instrument(query_span) -// .await -// .map(|result|{ -// tracing::info!("Deployment {} has been saved to database", deployment.id); -// deployment.updated_at = result.updated_at; -// deployment -// }) -// .map_err(|err| { -// tracing::error!("Failed to execute query: {:?}", err); -// "".to_string() -// }) -// } +pub async fn update(pool: &PgPool, mut deployment: models::Deployment) -> Result { + let query_span = tracing::info_span!("Updating user deployment into the database"); + sqlx::query_as!( + models::Deployment, + r#" + UPDATE deployment + SET + project_id=$2, + deleted=$3, + status=$4, + body=$5, + updated_at=NOW() at time zone 'utc' + WHERE id = $1 + RETURNING * + "#, + deployment.id, + deployment.project_id, + deployment.deleted, + deployment.status, + deployment.body, + ) + .fetch_one(pool) + .instrument(query_span) + .await + .map(|result|{ + tracing::info!("Deployment {} has been updated", deployment.id); + deployment.updated_at = result.updated_at; + deployment + }) + .map_err(|err| { + tracing::error!("Failed to execute query: {:?}", err); + "".to_string() + }) +} diff --git a/src/db/server.rs b/src/db/server.rs index 6a0aa64..86f147b 100644 --- a/src/db/server.rs +++ b/src/db/server.rs @@ -70,7 +70,6 @@ pub async fn insert(pool: &PgPool, mut server: models::Server) -> Result Result Result, #[validate(min_length = 2)] #[validate(max_length = 50)] @@ -19,15 +18,11 @@ pub struct Cloud { impl Into for Cloud { fn into(self) -> models::Cloud { let mut cloud = models::Cloud::default(); - cloud.user_id = self.user_id; - cloud.project_id = self.project_id; cloud.provider = self.provider; cloud.cloud_token = self.cloud_token; cloud.cloud_key = self.cloud_key; cloud.cloud_secret = self.cloud_secret; cloud.save_token = self.save_token; - cloud.created_at = Utc::now(); - cloud.updated_at = Utc::now(); cloud } @@ -36,7 +31,6 @@ impl Into for Cloud { impl Into for models::Cloud { fn into(self) -> Cloud { let mut form = Cloud::default(); - form.user_id = self.user_id; form.project_id = self.project_id; form.provider = self.provider; form.cloud_token = self.cloud_token; diff --git a/src/forms/project/deploy.rs b/src/forms/project/deploy.rs new file mode 100644 index 0000000..ae4c5e8 --- /dev/null +++ b/src/forms/project/deploy.rs @@ -0,0 +1,27 @@ +use serde_derive::{Deserialize, Serialize}; +use serde_json::Value; +use serde_valid::Validate; +use crate::forms; +use crate::forms::{Cloud, Server}; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct Deploy { + #[validate] + pub(crate) stack: Stack, + #[validate] + pub(crate) server: Server, + #[validate] + pub(crate) cloud: Cloud +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct Stack { + #[validate(min_length = 2)] + #[validate(max_length = 255)] + pub stack_code: Option, + pub vars: Option>, + pub integrated_features: Option>, + pub extended_features: Option>, + pub subscriptions: Option>, + pub form_app: Option>, +} \ No newline at end of file diff --git a/src/forms/project/form.rs b/src/forms/project/form.rs index 73f0eb2..d2498cf 100644 --- a/src/forms/project/form.rs +++ b/src/forms/project/form.rs @@ -11,22 +11,6 @@ use std::str; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct ProjectForm { - // #[validate(min_length=2)] - // #[validate(max_length=255)] - #[serde(rename = "commonDomain")] - pub common_domain: Option, - pub domain_list: Option, - #[validate(min_length = 2)] - #[validate(max_length = 255)] - pub stack_code: Option, - #[validate(min_length = 3)] - #[validate(max_length = 50)] - pub ssl: String, - pub vars: Option>, - pub integrated_features: Option>, - pub extended_features: Option>, - pub subscriptions: Option>, - pub form_app: Option>, pub custom: forms::project::Custom } diff --git a/src/forms/project/mod.rs b/src/forms/project/mod.rs index b0463a9..d83fecc 100644 --- a/src/forms/project/mod.rs +++ b/src/forms/project/mod.rs @@ -24,6 +24,7 @@ mod icon_dark; mod version; mod network_driver; +mod deploy; pub use app::*; pub use custom::*; @@ -50,3 +51,4 @@ pub use icon::*; pub use icon_light::*; pub use icon_dark::*; pub use version::*; +pub use deploy::*; \ No newline at end of file diff --git a/src/forms/project/payload.rs b/src/forms/project/payload.rs index aee8a4c..7108a1f 100644 --- a/src/forms/project/payload.rs +++ b/src/forms/project/payload.rs @@ -11,23 +11,12 @@ pub struct Payload { pub(crate) id: Option, pub(crate) user_token: Option, pub(crate) user_email: Option, - #[serde(rename = "commonDomain")] - pub common_domain: String, - pub domain_list: Option, + #[serde(flatten)] + pub cloud: Option, #[serde(flatten)] pub server: Option, - pub ssl: String, - pub vars: Option>, - #[serde(rename = "integrated_features")] - pub integrated_features: Option>, - #[serde(rename = "extended_features")] - pub extended_features: Option>, - pub subscriptions: Option>, - pub form_app: Option>, - pub disk_type: Option, #[serde(flatten)] - pub cloud: Option, - pub stack_code: String, + pub stack: forms::project::Stack, pub custom: forms::project::Custom, pub docker_compose: Option>, } @@ -43,7 +32,6 @@ impl TryFrom<&models::Project> for Payload { })?; project_data.id = Some(project.id.clone()); - project_data.stack_code = project_data.custom.custom_stack_code.clone(); Ok(project_data) } diff --git a/src/forms/server.rs b/src/forms/server.rs index d66cde0..1e55a89 100644 --- a/src/forms/server.rs +++ b/src/forms/server.rs @@ -1,14 +1,12 @@ use crate::models; use serde::{Deserialize, Serialize}; use serde_valid::Validate; -use chrono::{DateTime, Utc}; -use crate::forms; +use chrono::{Utc}; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Server { - pub user_id: String, - pub cloud_id: i32, - pub project_id: i32, + // pub cloud_id: i32, + // pub project_id: i32, pub region: String, pub zone: Option, pub server: String, @@ -19,9 +17,6 @@ pub struct Server { impl Into for Server { fn into(self) -> models::Server { let mut server = models::Server::default(); - server.user_id = self.user_id; - server.cloud_id = self.cloud_id; - server.project_id = self.project_id; server.disk_type = self.disk_type; server.region = self.region; server.server = self.server; @@ -38,9 +33,8 @@ impl Into for models::Server { fn into(self) -> Server { let mut form = Server::default(); - form.user_id = self.user_id; - form.cloud_id = self.cloud_id; - form.project_id = self.project_id; + // form.cloud_id = self.cloud_id; + // form.project_id = self.project_id; form.disk_type = self.disk_type; form.region = self.region; form.server = self.server; diff --git a/src/helpers/mod.rs b/src/helpers/mod.rs index 74f975b..0640df8 100644 --- a/src/helpers/mod.rs +++ b/src/helpers/mod.rs @@ -1,10 +1,10 @@ pub mod client; pub(crate) mod json; -mod mq_manager; +pub mod mq_manager; pub mod project; pub use json::*; -pub use mq_manager::MqManager; +pub use mq_manager::*; pub mod dockerhub; pub(crate) mod compressor; diff --git a/src/helpers/mq_manager.rs b/src/helpers/mq_manager.rs index 5b058ea..a7eb5e5 100644 --- a/src/helpers/mq_manager.rs +++ b/src/helpers/mq_manager.rs @@ -1,9 +1,8 @@ +use actix_web::web; use deadpool_lapin::{Config, CreatePoolError, Object, Pool, Runtime}; -use lapin::{ - options::*, - publisher_confirm::{Confirmation, PublisherConfirm}, - BasicProperties, Channel, -}; +use lapin::{options::*, publisher_confirm::{Confirmation, PublisherConfirm}, BasicProperties, Channel, ExchangeKind, Queue}; +use lapin::types::AMQPType::ShortString; +use lapin::types::{AMQPValue, FieldTable}; use serde::ser::Serialize; #[derive(Debug)] @@ -33,8 +32,9 @@ impl MqManager { async fn get_connection(&self) -> Result { self.pool.get().await.map_err(|err| { - tracing::error!("getting connection from pool {:?}", err); - format!("getting connection from pool {:?}", err) + let msg = format!("getting connection from pool {:?}", err); + tracing::error!(msg); + msg }) } @@ -44,8 +44,9 @@ impl MqManager { .create_channel() .await .map_err(|err| { - tracing::error!("creating RabbitMQ channel {:?}", err); - format!("creating RabbitMQ channel {:?}", err) + let msg = format!("creating RabbitMQ channel {:?}", err); + tracing::error!(msg); + msg }) } @@ -85,15 +86,67 @@ impl MqManager { .await? .await .map_err(|err| { - tracing::error!("confirming the publication {:?}", err); - format!("confirming the publication {:?}", err) + let msg = format!("confirming the publication {:?}", err); + tracing::error!(msg); + msg + }) .and_then(|confirm| match confirm { Confirmation::NotRequested => { - tracing::error!("confirmation is NotRequested"); - Err(format!("confirmation is NotRequested")) + let msg = format!("confirmation is NotRequested"); + tracing::error!(msg); + Err(msg) } _ => Ok(()), }) } + + pub async fn consume( + &self, + exchange_name: &str, + routing_key: &str, + ) -> Result { + + let mut args = FieldTable::default(); + args.insert("x-expires".into(), AMQPValue::LongUInt(180000)); + let channel = self.create_channel().await?; + + channel + .exchange_declare( + exchange_name, + ExchangeKind::Topic, + ExchangeDeclareOptions { + passive: false, + durable: false, + auto_delete: true, + internal: false, + nowait: false, + }, + args + ) + .await + .expect("Exchange declare failed"); + + let queue = channel.queue_declare( + routing_key, + QueueDeclareOptions::default(), + Default::default(), + ) + .await + .expect("Queue declare failed"); + + let _ = channel + .queue_bind( + queue.name().as_str(), + exchange_name, + routing_key, + QueueBindOptions::default(), + FieldTable::default(), + ) + .await + .map_err(|err| format!("error {:?}", err)); + + let channel = self.create_channel().await?; + Ok(channel) + } } diff --git a/src/models/deployment.rs b/src/models/deployment.rs index 3aea4e6..bfdd72b 100644 --- a/src/models/deployment.rs +++ b/src/models/deployment.rs @@ -7,7 +7,7 @@ use serde_json::Value; pub struct Deployment { pub id: i32, // id - is a unique identifier for the app project pub project_id: i32, // external project ID - pub deleted: bool, + pub deleted: Option, pub status: String, pub body: Value, //json type pub created_at: DateTime, @@ -19,7 +19,7 @@ impl Deployment { Self { id: 0, project_id, - deleted: false, + deleted: Some(false), status, body, created_at: Utc::now(), diff --git a/src/models/mod.rs b/src/models/mod.rs index 03de8ab..c1c375b 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -5,7 +5,7 @@ mod rules; pub mod rating; pub mod project; pub mod user; -mod deployment; +pub(crate) mod deployment; mod cloud; mod server; diff --git a/src/models/server.rs b/src/models/server.rs index 6098d68..3827fcf 100644 --- a/src/models/server.rs +++ b/src/models/server.rs @@ -6,7 +6,6 @@ use serde_valid::Validate; pub struct Server { pub id: i32, pub user_id: String, - pub cloud_id: i32, pub project_id: i32, #[validate(min_length = 2)] #[validate(max_length = 50)] diff --git a/src/routes/cloud/update.rs b/src/routes/cloud/update.rs index 2a69237..3e2e564 100644 --- a/src/routes/cloud/update.rs +++ b/src/routes/cloud/update.rs @@ -18,7 +18,7 @@ pub async fn item( ) -> Result { let id = path.0; - let mut cloud_row = db::cloud::fetch(pg_pool.get_ref(), id) + let cloud_row = db::cloud::fetch(pg_pool.get_ref(), id) .await .map_err(|err| JsonResponse::::build().internal_server_error(err)) .and_then(|cloud| match cloud { diff --git a/src/routes/project/deploy.rs b/src/routes/project/deploy.rs index 6bbb4cd..a1261ab 100644 --- a/src/routes/project/deploy.rs +++ b/src/routes/project/deploy.rs @@ -7,13 +7,125 @@ use crate::models; use actix_web::{post, web, web::Data, Responder, Result}; use sqlx::PgPool; use std::sync::Arc; +use serde_valid::Validate; use crate::helpers::compressor::compress; -#[tracing::instrument(name = "Deploy for every user. Admin endpoint")] -#[post("/{id}/deploy/{cloud_id}")] +#[tracing::instrument(name = "Deploy for every user")] +#[post("/{id}/deploy")] pub async fn item( + user: web::ReqData>, + path: web::Path<(i32,)>, + form: web::Json, + pg_pool: Data, + mq_manager: Data, + sets: Data, +) -> Result { + let id = path.0; + tracing::debug!("User {:?} is deploying project: {}", user, id); + + if !form.validate().is_ok() { + let errors = form.validate().unwrap_err().to_string(); + let err_msg = format!("Invalid form data received {:?}", &errors); + tracing::debug!(err_msg); + + return Err(JsonResponse::::build().form_error(errors)); + } + + // Validate project + let project = db::project::fetch(pg_pool.get_ref(), id) + .await + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .and_then(|project| match project { + Some(project) => Ok(project), + None => Err(JsonResponse::::build().not_found("not found")), + })?; + + // Build compose + let id = project.id.clone(); + let dc = DcBuilder::new(project); + let fc = dc.build().map_err(|err| { + JsonResponse::::build().internal_server_error(err) + })?; + + + // Save cloud credentials if requested + let mut cloud_creds: models::Cloud = form.cloud.clone().into(); + cloud_creds.project_id = Some(id.clone()); + cloud_creds.user_id = user.id.clone(); + + if let Some(save_token) = cloud_creds.save_token { + if save_token { + db::cloud::insert(pg_pool.get_ref(), cloud_creds.clone()) + .await + .map(|cloud| cloud) + .map_err(|_| { + JsonResponse::::build().internal_server_error("Internal Server Error") + })?; + } + } + + // Save server type and region + let mut server: models::Server = form.server.clone().into(); + server.user_id = user.id.clone(); + server.project_id = id.clone(); + let server = db::server::insert(pg_pool.get_ref(), server) + .await + .map(|server| server) + .map_err(|_| { + JsonResponse::::build().internal_server_error("Internal Server Error") + })?; + + // Build Payload for the 3-d party service through RabbitMQ + let mut payload = forms::project::Payload::try_from(&dc.project) + .map_err(|err| JsonResponse::::build().bad_request(err))?; + + payload.server = Some(server.into()); + payload.cloud = Some(cloud_creds.into()); + payload.stack = form.stack.clone().into(); + payload.user_token = Some(user.id.clone()); + payload.user_email = Some(user.email.clone()); + payload.docker_compose = Some(compress(fc.as_str())); + + // Store deployment attempts into deployment table in db + let project_id = dc.project.id.clone(); + let json_request = dc.project.body.clone(); + let deployment = models::Deployment::new( + project_id, + String::from("pending"), + json_request + ); + + let result = db::deployment::insert(pg_pool.get_ref(), deployment) + .await + .map(|deployment| deployment) + .map_err(|_| { + JsonResponse::::build().internal_server_error("Internal Server Error") + }); + + tracing::debug!("Save deployment result: {:?}", result); + tracing::debug!("Send project data <<<<<<<<<<<>>>>>>>>>>>>>>>>{:?}", payload); + + // Send Payload + mq_manager + .publish( + "install".to_string(), + "install.start.tfa.all.all".to_string(), + &payload, + ) + .await + .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .map(|_| { + JsonResponse::::build() + .set_id(id) + .ok("Success") + }) + +} +#[tracing::instrument(name = "Deploy, when cloud token is saved")] +#[post("/{id}/deploy/{cloud_id}")] +pub async fn saved_item( user: web::ReqData>, path: web::Path<(i32, i32)>, pg_pool: Data, @@ -30,7 +142,7 @@ pub async fn item( .map_err(|err| JsonResponse::::build().internal_server_error(err)) .and_then(|project| match project { Some(project) => Ok(project), - None => Err(JsonResponse::::build().not_found("not found")), + None => Err(JsonResponse::::build().not_found("Project not found")), })?; let id = project.id.clone(); diff --git a/src/routes/server/add.rs b/src/routes/server/add.rs index 96ea390..5a8970c 100644 --- a/src/routes/server/add.rs +++ b/src/routes/server/add.rs @@ -1,75 +1,76 @@ -use crate::forms; -use crate::helpers::JsonResponse; -use crate::models; -use crate::db; -use actix_web::{post, web, Responder, Result}; -use sqlx::PgPool; -use tracing::Instrument; -use std::sync::Arc; -use serde_valid::Validate; +// use crate::forms; +// use crate::helpers::JsonResponse; +// use crate::models; +// use crate::db; +// use actix_web::{post, web, Responder, Result}; +// use sqlx::PgPool; +// use tracing::Instrument; +// use std::sync::Arc; +// use serde_valid::Validate; // workflow // add, update, list, get(user_id), ACL, // ACL - access to func for a user // ACL - access to objects for a user -#[tracing::instrument(name = "Add server.")] -#[post("")] -pub async fn add( - user: web::ReqData>, - form: web::Json, - pg_pool: web::Data, -) -> Result { - - if !form.validate().is_ok() { - let errors = form.validate().unwrap_err().to_string(); - let err_msg = format!("Invalid data received {:?}", &errors); - tracing::debug!(err_msg); - - return Err(JsonResponse::::build().form_error(errors)); - } - - db::cloud::fetch(pg_pool.get_ref(), form.cloud_id) - .await - .map_err(|err| JsonResponse::::build().internal_server_error(err)) - .and_then(|cloud| { - match cloud { - Some(cloud) if cloud.user_id != user.id => { - Err(JsonResponse::::build().bad_request("Cloud not found")) - } - Some(cloud) => { - Ok(cloud) - }, - None => Err(JsonResponse::::build().not_found("Cloud not found")) - } - })?; - - db::project::fetch(pg_pool.get_ref(), form.project_id) - .await - .map_err(|_err| JsonResponse::::build() - .bad_request("Invalid project")) - .and_then(|project| { - match project { - Some(project) if project.user_id != user.id => { - Err(JsonResponse::::build().bad_request("Project not found")) - } - Some(project) => { Ok(project) }, - None => Err(JsonResponse::::build().not_found("Project not found")) - } - })?; - - let mut server: models::Server = form.into_inner().into(); - server.user_id = user.id.clone(); - - db::server::insert(pg_pool.get_ref(), server) - .await - .map(|server| JsonResponse::build() - .set_item(server) - .ok("success")) - .map_err(|err| - match err { - _ => { - return JsonResponse::::build().internal_server_error("Failed to insert"); - } - }) -} +// #[tracing::instrument(name = "Add server.")] +// #[post("")] +// pub async fn add( +// user: web::ReqData>, +// form: web::Json, +// pg_pool: web::Data, +// ) -> Result { +// // +// // if !form.validate().is_ok() { +// // let errors = form.validate().unwrap_err().to_string(); +// // let err_msg = format!("Invalid data received {:?}", &errors); +// // tracing::debug!(err_msg); +// // +// // return Err(JsonResponse::::build().form_error(errors)); +// // } +// // +// // +// // db::cloud::fetch(pg_pool.get_ref(), form.cloud_id) +// // .await +// // .map_err(|err| JsonResponse::::build().internal_server_error(err)) +// // .and_then(|cloud| { +// // match cloud { +// // Some(cloud) if cloud.user_id != user.id => { +// // Err(JsonResponse::::build().bad_request("Cloud not found")) +// // } +// // Some(cloud) => { +// // Ok(cloud) +// // }, +// // None => Err(JsonResponse::::build().not_found("Cloud not found")) +// // } +// // })?; +// // +// // db::project::fetch(pg_pool.get_ref(), form.project_id) +// // .await +// // .map_err(|_err| JsonResponse::::build() +// // .bad_request("Invalid project")) +// // .and_then(|project| { +// // match project { +// // Some(project) if project.user_id != user.id => { +// // Err(JsonResponse::::build().bad_request("Project not found")) +// // } +// // Some(project) => { Ok(project) }, +// // None => Err(JsonResponse::::build().not_found("Project not found")) +// // } +// // })?; +// // +// // let mut server: models::Server = form.into_inner().into(); +// // server.user_id = user.id.clone(); +// // +// // db::server::insert(pg_pool.get_ref(), server) +// // .await +// // .map(|server| JsonResponse::build() +// // .set_item(server) +// // .ok("success")) +// // .map_err(|err| +// // match err { +// // _ => { +// // return JsonResponse::::build().internal_server_error("Failed to insert"); +// // } +// // }) +// } diff --git a/src/routes/server/mod.rs b/src/routes/server/mod.rs index 319c89f..af796d2 100644 --- a/src/routes/server/mod.rs +++ b/src/routes/server/mod.rs @@ -1,7 +1,7 @@ pub mod add; pub(crate) mod get; pub(crate) mod delete; -mod update; +pub(crate) mod update; pub use get::*; pub use add::*; diff --git a/src/routes/server/update.rs b/src/routes/server/update.rs index b708778..6220869 100644 --- a/src/routes/server/update.rs +++ b/src/routes/server/update.rs @@ -35,7 +35,6 @@ pub async fn item( let mut server:models::Server = form.into_inner().into(); server.id = server_row.id; - server.cloud_id = server_row.cloud_id; server.project_id = server_row.project_id; server.user_id = user.id.clone(); // exclude diff --git a/src/startup.rs b/src/startup.rs index 612d321..2c7c4ba 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -100,8 +100,8 @@ pub async fn run( .wrap(Cors::permissive()) .service(crate::routes::server::get::item) .service(crate::routes::server::get::list) - .service(crate::routes::server::add::add) - // .service(crate::routes::server::update::item) + // .service(crate::routes::server::add::add) + .service(crate::routes::server::update::item) .service(crate::routes::server::delete::item), ) .app_data(pg_pool.clone()) diff --git a/tests/mock_data/deploy.json b/tests/mock_data/deploy.json new file mode 100644 index 0000000..e69de29 diff --git a/tests/mock_data/deploy2.json b/tests/mock_data/deploy2.json new file mode 100644 index 0000000..ed30b57 --- /dev/null +++ b/tests/mock_data/deploy2.json @@ -0,0 +1 @@ +{"cloud":{"save_token":false,"cloud_token":"4CVzsUUjW3ecn3djvXVC9HZI27QK3jNONRWyMB57c4p45Mp9m0rFUR95LwbYv1ov","provider":"htz"},"server":{"region":"fsn1","zone":null,"server":"cx11","os":"ubuntu-20.04","disk_type":"pd-standart","servers_count":3},"stack":{"vars":[],"integrated_features":[],"extended_features":[],"subscriptions":[],"form_app":[]}} From 0cf61053068bf4115fdd9a45ac0b0b4d35311075 Mon Sep 17 00:00:00 2001 From: vsilent Date: Sun, 17 Mar 2024 09:33:35 +0200 Subject: [PATCH 217/284] mq listener, added futures_lite::stream::StraemExt --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/console/commands/mq/listener.rs | 11 ++++++----- src/helpers/mq_manager.rs | 4 ++-- tests/mock_data/cloud-update.json | 1 + tests/mock_data/cloud.json | 1 + tests/mock_data/deploy.json | 1 + tests/mock_data/deploy2.json | 2 +- tests/mock_data/project-update.json | 3 ++- tests/mock_data/project.json | 3 +-- tests/mock_data/server-update.json | 4 ++-- tests/mock_data/server.json | 6 +++--- 12 files changed, 22 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0ea5e67..1f08eb2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3450,7 +3450,7 @@ dependencies = [ "derive_builder 0.12.0", "docker-compose-types", "futures", - "futures-lite 1.13.0", + "futures-lite 2.2.0", "futures-util", "glob", "hmac", diff --git a/Cargo.toml b/Cargo.toml index f817a30..b7daae6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,7 +52,7 @@ derive_builder = "0.12.0" indexmap = { version = "2.0.0", features = ["serde"], optional = true } serde_yaml = "0.9" lapin = { version = "2.3.1", features = ["serde_json"] } -futures-lite = "1.13.0" +futures-lite = "2.2.0" clap = { version = "4.4.8", features = ["derive"] } brotli = "3.4.0" serde_path_to_error = "0.1.14" diff --git a/src/console/commands/mq/listener.rs b/src/console/commands/mq/listener.rs index 75cae06..cfe329a 100644 --- a/src/console/commands/mq/listener.rs +++ b/src/console/commands/mq/listener.rs @@ -9,6 +9,7 @@ use db::deployment; use crate::{db, helpers}; use crate::helpers::mq_manager; use crate::helpers::mq_manager::MqManager; +use futures_lite::stream::StreamExt; pub struct ListenCommand { } @@ -39,7 +40,7 @@ impl crate::console::commands::CallableTrait for ListenCommand { .await?; - let consumer = consumer_channel + let mut consumer = consumer_channel .basic_consume( "install_progress", "console_listener", @@ -53,10 +54,10 @@ impl crate::console::commands::CallableTrait for ListenCommand { tracing::info!("will consume"); // if let Ok(consumer) = consumer { - // while let Some(delivery) = consumer.next().await { - // let delivery = delivery.expect("error in consumer"); - // delivery.ack(BasicAckOptions::default()).await.expect("ack"); - // } + while let Some(delivery) = consumer.next().await { + let delivery = delivery.expect("error in consumer"); + delivery.ack(BasicAckOptions::default()).await.expect("ack"); + } // } // while let Some(delivery) = consumer.next().await { diff --git a/src/helpers/mq_manager.rs b/src/helpers/mq_manager.rs index a7eb5e5..c265825 100644 --- a/src/helpers/mq_manager.rs +++ b/src/helpers/mq_manager.rs @@ -117,8 +117,8 @@ impl MqManager { ExchangeKind::Topic, ExchangeDeclareOptions { passive: false, - durable: false, - auto_delete: true, + durable: true, + auto_delete: false, internal: false, nowait: false, }, diff --git a/tests/mock_data/cloud-update.json b/tests/mock_data/cloud-update.json index d436baa..72967ad 100644 --- a/tests/mock_data/cloud-update.json +++ b/tests/mock_data/cloud-update.json @@ -1,5 +1,6 @@ { "user_id": "hy181TZa4DaabUZWklsrxw", + "project_id": 1, "provider": "htz", "cloud_token": "cloud_token_updates", "cloud_key": "cloud_token_updates", diff --git a/tests/mock_data/cloud.json b/tests/mock_data/cloud.json index 9e680c9..04f7412 100644 --- a/tests/mock_data/cloud.json +++ b/tests/mock_data/cloud.json @@ -1,5 +1,6 @@ { "user_id": "hy181TZa4DaabUZWklsrxw", + "project_id": 1, "provider": "htz", "cloud_token": "cloud_token_here", "cloud_key": "cloud_token_here", diff --git a/tests/mock_data/deploy.json b/tests/mock_data/deploy.json index e69de29..6917d31 100644 --- a/tests/mock_data/deploy.json +++ b/tests/mock_data/deploy.json @@ -0,0 +1 @@ +{"project":{"networks":[{"id":"ltoi393j2i4iit2pz","name":"default_network"}],"web":[{"_created":"2023-05-10T09:57:23.773552","_etag":null,"_id":"ltoi3u3515z6nwsk1","_updated":"2024-02-27T15:10:40.107999","ansible_var":null,"autodeploy":null,"avoid_render":null,"category":[null],"category_id":null,"code":"openresty","commercial":null,"cpu":"0.0","custom_preset":{"dockerhub_name":"openresty","dockerhub_user":"openresty","environment":[],"restart":"always","shared_ports":[],"volumes":[]},"default":true,"dependency":null,"descr":null,"description":"

a dynamic web platform built on NGINX and LuaJIT. Learn more

","disk_size":null,"docker_image_is_internal":true,"dockerhub_image":"openresty","dockerhub_name":"openresty","dockerhub_user":"openresty","domain":"","environment":[],"form":null,"full_description":null,"group":[],"icon":{"dark":{},"light":{"height":150,"image":"12140d93-350c-4fb8-b3d2-e350f3943b0b.svg","width":147}},"links":[{"follow":false,"title":"Openresty","type":"vendor","url":"https://openresty.org/"},{"follow":false,"repo_name":"openresty","repo_owner":"openresty","type":"github"}],"name":"OpenResty","network":["ltoi393j2i4iit2pz"],"parent_app_id":null,"plan_type":null,"popularity":null,"ports":{"public":["80","443"]},"price":null,"ram_size":null,"repo_dir":null,"requirements":null,"restart":"always","role":null,"shared_ports":[{"host_port":"80","container_port":"80"}],"subscription":null,"suggested":null,"timestamp":"2024-03-12T15:02:14.033Z","type":"web","version":{"_id":586,"name":"1.15.8.3","tag":"1.15.8.3","update_status":"published","version":"1.15.8.3"},"versions":[{"_id":586,"name":"1.15.8.3","tag":"1.15.8.3","update_status":"published","version":"1.15.8.3"}],"volumes":[]}],"feature":[],"service":[],"custom_stack_category":null,"custom_stack_code":"project-1","custom_stack_description":null,"custom_stack_short_description":null,"project_description":null,"project_git_url":null,"project_name":"Project 1","project_overview":null},"cloud":{"provider": "htz","save_token":true,"cloud_token":"*****"},"server":{"region":"fsn1","zone":null,"server":"cx11","os":"ubuntu-20.04","disk_type":"pd-standart","servers_count":3},"stack":{"commonDomain":"","domainList":{},"ssl":"letsencrypt","vars":[],"integrated_features":[],"extended_features":[],"subscriptions":[],"form_app":[]}} \ No newline at end of file diff --git a/tests/mock_data/deploy2.json b/tests/mock_data/deploy2.json index ed30b57..4bf3857 100644 --- a/tests/mock_data/deploy2.json +++ b/tests/mock_data/deploy2.json @@ -1 +1 @@ -{"cloud":{"save_token":false,"cloud_token":"4CVzsUUjW3ecn3djvXVC9HZI27QK3jNONRWyMB57c4p45Mp9m0rFUR95LwbYv1ov","provider":"htz"},"server":{"region":"fsn1","zone":null,"server":"cx11","os":"ubuntu-20.04","disk_type":"pd-standart","servers_count":3},"stack":{"vars":[],"integrated_features":[],"extended_features":[],"subscriptions":[],"form_app":[]}} +{"cloud":{"save_token":false,"cloud_token":"****","provider":"htz"},"server":{"region":"fsn1","zone":null,"server":"cx11","os":"ubuntu-20.04","disk_type":"pd-standart","servers_count":3},"stack":{"vars":[],"integrated_features":[],"extended_features":[],"subscriptions":[],"form_app":[]}} diff --git a/tests/mock_data/project-update.json b/tests/mock_data/project-update.json index 4c0e7c7..f13f68b 100644 --- a/tests/mock_data/project-update.json +++ b/tests/mock_data/project-update.json @@ -1,6 +1,7 @@ { + "id": 1, "stack_id": "9239ea1d-8306-4493-aae1-fcc00de76241", "user_id": "hy181TZa4DaabUZWklsrxw", "name": "sample", - "body": "{}" + "body": "{\"key\": \"val\"}" } \ No newline at end of file diff --git a/tests/mock_data/project.json b/tests/mock_data/project.json index 9ff62aa..4c0e7c7 100644 --- a/tests/mock_data/project.json +++ b/tests/mock_data/project.json @@ -2,6 +2,5 @@ "stack_id": "9239ea1d-8306-4493-aae1-fcc00de76241", "user_id": "hy181TZa4DaabUZWklsrxw", "name": "sample", - "body": "{}", - "cloud_id": 1 + "body": "{}" } \ No newline at end of file diff --git a/tests/mock_data/server-update.json b/tests/mock_data/server-update.json index 4ad2173..b85eb42 100644 --- a/tests/mock_data/server-update.json +++ b/tests/mock_data/server-update.json @@ -1,6 +1,7 @@ { "id": 1, "user_id": "hy181TZa4DaabUZWklsrxw", + "project_id": 1, "cloud_id": 1, "region": "fra-1", "zone": "a", @@ -8,7 +9,6 @@ "os": "3408230498203948234", "disk_type": "samples", "created_at": "", - "updated_at": "", - "project_id": 1 + "updated_at": "" } diff --git a/tests/mock_data/server.json b/tests/mock_data/server.json index cec56c9..2d7d626 100644 --- a/tests/mock_data/server.json +++ b/tests/mock_data/server.json @@ -1,13 +1,13 @@ { "user_id": "hy181TZa4DaabUZWklsrxw", - "cloud_id": 3, + "project_id":1, + "cloud_id": 1, "region": "fra-1", "zone": "a", "server": "server-1", "os": "3408230498203948234", "disk_type": "samples", "created_at": "", - "updated_at": "", - "project_id":4 + "updated_at": "" } From 9450ef4802906e91ebe80d19c8be3644904bdc7c Mon Sep 17 00:00:00 2001 From: vsilent Date: Sun, 17 Mar 2024 10:32:50 +0200 Subject: [PATCH 218/284] slight refactoring, deref() for subforms --- src/forms/cloud.rs | 12 ++++++------ src/forms/server.rs | 12 ++++++------ src/routes/cloud/add.rs | 3 ++- src/routes/cloud/update.rs | 3 ++- src/routes/project/deploy.rs | 32 ++++++++++++++------------------ src/routes/server/update.rs | 3 ++- 6 files changed, 32 insertions(+), 33 deletions(-) diff --git a/src/forms/cloud.rs b/src/forms/cloud.rs index 138b298..472bdb7 100644 --- a/src/forms/cloud.rs +++ b/src/forms/cloud.rs @@ -15,14 +15,14 @@ pub struct Cloud { pub save_token: Option, } -impl Into for Cloud { +impl Into for &Cloud { fn into(self) -> models::Cloud { let mut cloud = models::Cloud::default(); - cloud.provider = self.provider; - cloud.cloud_token = self.cloud_token; - cloud.cloud_key = self.cloud_key; - cloud.cloud_secret = self.cloud_secret; - cloud.save_token = self.save_token; + cloud.provider = self.provider.clone(); + cloud.cloud_token = self.cloud_token.clone(); + cloud.cloud_key = self.cloud_key.clone(); + cloud.cloud_secret = self.cloud_secret.clone(); + cloud.save_token = self.save_token.clone(); cloud } diff --git a/src/forms/server.rs b/src/forms/server.rs index 1e55a89..cba997f 100644 --- a/src/forms/server.rs +++ b/src/forms/server.rs @@ -14,14 +14,14 @@ pub struct Server { pub disk_type: Option, } -impl Into for Server { +impl Into for &Server { fn into(self) -> models::Server { let mut server = models::Server::default(); - server.disk_type = self.disk_type; - server.region = self.region; - server.server = self.server; - server.zone = self.zone; - server.os = self.os; + server.disk_type = self.disk_type.clone(); + server.region = self.region.clone(); + server.server = self.server.clone(); + server.zone = self.zone.clone(); + server.os = self.os.clone(); server.created_at = Utc::now(); server.updated_at = Utc::now(); diff --git a/src/routes/cloud/add.rs b/src/routes/cloud/add.rs index cb57209..6178ff1 100644 --- a/src/routes/cloud/add.rs +++ b/src/routes/cloud/add.rs @@ -1,3 +1,4 @@ +use std::ops::Deref; use crate::forms; use crate::helpers::JsonResponse; use crate::models; @@ -29,7 +30,7 @@ pub async fn add( return Err(JsonResponse::::build().form_error(errors)); } - let mut cloud: models::Cloud = form.into_inner().into(); + let mut cloud: models::Cloud = form.deref().into(); cloud.user_id = user.id.clone(); db::cloud::insert(pg_pool.get_ref(), cloud) diff --git a/src/routes/cloud/update.rs b/src/routes/cloud/update.rs index 3e2e564..b48fd8b 100644 --- a/src/routes/cloud/update.rs +++ b/src/routes/cloud/update.rs @@ -7,6 +7,7 @@ use serde_valid::Validate; use sqlx::PgPool; use std::sync::Arc; use tracing::Instrument; +use std::ops::Deref; #[tracing::instrument(name = "Update cloud.")] #[put("/{id}")] @@ -33,7 +34,7 @@ pub async fn item( return Err(JsonResponse::::build().form_error(errors.to_string())); } - let mut cloud:models::Cloud = form.into_inner().into(); + let mut cloud:models::Cloud = form.deref().into(); cloud.id = cloud_row.id; cloud.user_id = user.id.clone(); diff --git a/src/routes/project/deploy.rs b/src/routes/project/deploy.rs index a1261ab..b0665d8 100644 --- a/src/routes/project/deploy.rs +++ b/src/routes/project/deploy.rs @@ -43,7 +43,7 @@ pub async fn item( })?; // Build compose - let id = project.id.clone(); + let id = project.id; let dc = DcBuilder::new(project); let fc = dc.build().map_err(|err| { JsonResponse::::build().internal_server_error(err) @@ -51,25 +51,23 @@ pub async fn item( // Save cloud credentials if requested - let mut cloud_creds: models::Cloud = form.cloud.clone().into(); - cloud_creds.project_id = Some(id.clone()); + let mut cloud_creds: models::Cloud = (&form.cloud).into(); + cloud_creds.project_id = Some(id); cloud_creds.user_id = user.id.clone(); - if let Some(save_token) = cloud_creds.save_token { - if save_token { - db::cloud::insert(pg_pool.get_ref(), cloud_creds.clone()) - .await - .map(|cloud| cloud) - .map_err(|_| { - JsonResponse::::build().internal_server_error("Internal Server Error") - })?; - } + if Some(true) == cloud_creds.save_token { + db::cloud::insert(pg_pool.get_ref(), cloud_creds.clone()) + .await + .map(|cloud| cloud) + .map_err(|_| { + JsonResponse::::build().internal_server_error("Internal Server Error") + })?; } // Save server type and region - let mut server: models::Server = form.server.clone().into(); + let mut server: models::Server = (&form.server).into(); server.user_id = user.id.clone(); - server.project_id = id.clone(); + server.project_id = id; let server = db::server::insert(pg_pool.get_ref(), server) .await .map(|server| server) @@ -89,10 +87,9 @@ pub async fn item( payload.docker_compose = Some(compress(fc.as_str())); // Store deployment attempts into deployment table in db - let project_id = dc.project.id.clone(); let json_request = dc.project.body.clone(); let deployment = models::Deployment::new( - project_id, + dc.project.id, String::from("pending"), json_request ); @@ -189,10 +186,9 @@ pub async fn saved_item( payload.docker_compose = Some(compress(fc.as_str())); - let project_id = dc.project.id.clone(); let json_request = dc.project.body.clone(); let deployment = models::Deployment::new( - project_id, + dc.project.id, String::from("pending"), json_request ); diff --git a/src/routes/server/update.rs b/src/routes/server/update.rs index 6220869..02c4b0e 100644 --- a/src/routes/server/update.rs +++ b/src/routes/server/update.rs @@ -7,6 +7,7 @@ use serde_valid::Validate; use sqlx::PgPool; use std::sync::Arc; use tracing::Instrument; +use std::ops::Deref; #[tracing::instrument(name = "Update server.")] #[put("/{id}")] @@ -33,7 +34,7 @@ pub async fn item( return Err(JsonResponse::::build().form_error(errors.to_string())); } - let mut server:models::Server = form.into_inner().into(); + let mut server:models::Server = form.deref().into(); server.id = server_row.id; server.project_id = server_row.project_id; server.user_id = user.id.clone(); From f665d5de1fed92de9425dbf5ee9bb53a69027980 Mon Sep 17 00:00:00 2001 From: vsilent Date: Wed, 20 Mar 2024 15:04:05 +0200 Subject: [PATCH 219/284] mq listener, read queue and update status --- Dockerfile | 3 +- docker-compose.yml | 16 ++++++ docker/dev/docker-compose.yml | 20 +++++++ src/console/commands/mq/listener.rs | 86 ++++++++++++++++++----------- src/console/main.rs | 3 +- src/db/deployment.rs | 26 +++++++++ src/helpers/mq_manager.rs | 19 ++++++- src/routes/project/deploy.rs | 1 - 8 files changed, 135 insertions(+), 39 deletions(-) diff --git a/Dockerfile b/Dockerfile index 34fa4b0..66222d1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -37,7 +37,7 @@ COPY ./src ./src # cargo build --release RUN apt-get update && apt-get install --no-install-recommends -y libssl-dev; \ - cargo build --release + cargo build --bin=console && cargo build --release #RUN ls -la /app/target/release/ >&2 @@ -51,6 +51,7 @@ RUN mkdir ./files && chmod 0777 ./files # copy binary and configuration files COPY --from=builder /app/target/release/server . +COPY --from=builder /app/target/release/console . COPY --from=builder /app/.env . COPY --from=builder /app/configuration.yaml . COPY --from=builder /usr/local/cargo/bin/sqlx sqlx diff --git a/docker-compose.yml b/docker-compose.yml index e9aee75..f87b3e2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,6 +29,22 @@ services: # stackerdb: # condition: service_healthy + stacker_queue: + image: trydirect/stacker:0.0.7 + container_name: stacker_queue + restart: always + volumes: + - ./configuration.yaml:/app/configuration.yaml + - ./.env:/app/.env + environment: + - RUST_LOG=debug + - RUST_BACKTRACE=1 + env_file: + - ./.env + depends_on: + stackerdb: + condition: service_healthy + entrypoint: /app/console mq listen # stackerdb: # container_name: stackerdb diff --git a/docker/dev/docker-compose.yml b/docker/dev/docker-compose.yml index 6bf8eb5..3577b14 100644 --- a/docker/dev/docker-compose.yml +++ b/docker/dev/docker-compose.yml @@ -37,6 +37,26 @@ services: - backend + stacker_queue: + image: trydirect/stacker:0.0.7 + container_name: stacker_queue + restart: always + volumes: + - ./configuration.yaml:/app/configuration.yaml + - ./.env:/app/.env + environment: + - RUST_LOG=debug + - RUST_BACKTRACE=1 + env_file: + - ./.env + depends_on: + stackerdb: + condition: service_healthy + entrypoint: /app/console mq listen + networks: + - backend + + stackerdb: container_name: stackerdb healthcheck: diff --git a/src/console/commands/mq/listener.rs b/src/console/commands/mq/listener.rs index cfe329a..501d199 100644 --- a/src/console/commands/mq/listener.rs +++ b/src/console/commands/mq/listener.rs @@ -1,19 +1,31 @@ use crate::configuration::get_configuration; use actix_web::rt; use actix_web::web; +use chrono::Utc; use lapin::{Channel, Queue}; use lapin::options::{BasicAckOptions, BasicConsumeOptions}; use lapin::types::FieldTable; use sqlx::PgPool; use db::deployment; -use crate::{db, helpers}; -use crate::helpers::mq_manager; +use crate::{db, forms, helpers}; +use crate::helpers::{JsonResponse, mq_manager}; use crate::helpers::mq_manager::MqManager; use futures_lite::stream::StreamExt; +use serde_derive::{Deserialize, Serialize}; +use crate::forms::project::ProjectForm; pub struct ListenCommand { } +#[derive(Serialize, Deserialize, Debug)] +struct ProgressMessage { + alert: i32, + id: String, + message: String, + status: String, + progress: String +} + impl ListenCommand { pub fn new() -> Self { Self {} @@ -31,18 +43,20 @@ impl crate::console::commands::CallableTrait for ListenCommand { let db_pool = web::Data::new(db_pool); + println!("Declare exchange"); let mq_manager = MqManager::try_new(settings.amqp.connection_string())?; let consumer_channel= mq_manager .consume( "install_progress", - "install_progress_*******" + "install.progress.#" ) .await?; + println!("Declare queue"); let mut consumer = consumer_channel .basic_consume( - "install_progress", + "#", "console_listener", BasicConsumeOptions::default(), FieldTable::default(), @@ -50,38 +64,46 @@ impl crate::console::commands::CallableTrait for ListenCommand { .await .expect("Basic consume"); - // .map_err(|err| format!("Error {:?}", err)); + println!("Waiting for messages .."); + while let Some(delivery) = consumer.next().await { + // println!("checking messages delivery {:?}", delivery); + let delivery = delivery.expect("error in consumer"); + let s:String = match String::from_utf8(delivery.data.to_owned()) { + //delivery.data is of type Vec + Ok(v) => v, + Err(e) => panic!("Invalid UTF-8 sequence: {}", e), + }; - tracing::info!("will consume"); - // if let Ok(consumer) = consumer { - while let Some(delivery) = consumer.next().await { - let delivery = delivery.expect("error in consumer"); - delivery.ack(BasicAckOptions::default()).await.expect("ack"); - } - // } + match serde_json::from_str::(&s) { + Ok(msg) => { + println!("message {:?}", msg); + // println!("id {:?}", msg.id); + // println!("status {:?}", msg.status); + delivery.ack(BasicAckOptions::default()).await.expect("ack"); - // while let Some(delivery) = consumer.next().await { - // tracing::debug!(message=?delivery, "received message"); - // if let Ok(delivery) = delivery { - // delivery - // .ack(BasicAckOptions::default()) - // .await - // .expect("basic_ack"); - // } - // } + if msg.status == "complete" { + let id = msg.id + .parse::() + .map_err(|err| "Could not parse deployment id".to_string() )?; + match crate::db::deployment::fetch( + db_pool.get_ref(), id + ) + .await? { - // on_complete() - // let deployment = crate::models::deployment::Deployment { - // id: 0, - // project_id: 0, - // deleted: false, - // status: "".to_string(), - // body: Default::default(), - // created_at: Default::default(), - // updated_at: Default::default(), - // }; - // deployment::update(db_pool.get_ref(), deployment).await?; + Some(mut row) => { + row.status = msg.status; + row.updated_at = Utc::now(); + deployment::update(db_pool.get_ref(), row).await?; + println!("deployment {} completed successfully", id); + } + None => println!("Deployment record not found in db") + } + } + } + Err(err) => { tracing::debug!("Invalid message format")} + } + } Ok(()) }) diff --git a/src/console/main.rs b/src/console/main.rs index 752e10a..f6bc804 100644 --- a/src/console/main.rs +++ b/src/console/main.rs @@ -52,7 +52,6 @@ fn get_command(cli: Cli) -> Result Ok(Box::new( stacker::console::commands::mq::ListenCommand::new(), )), - }, - _ => Err("command does not match".to_string()), + } } } diff --git a/src/db/deployment.rs b/src/db/deployment.rs index 11e7a2e..7f78f0c 100644 --- a/src/db/deployment.rs +++ b/src/db/deployment.rs @@ -2,6 +2,32 @@ use crate::models; use sqlx::PgPool; use tracing::Instrument; + +pub async fn fetch(pool: &PgPool, id: i32) -> Result, String> { + tracing::info!("Fetch deployment {}", id); + sqlx::query_as!( + models::Deployment, + r#" + SELECT + * + FROM deployment + WHERE id=$1 + LIMIT 1 + "#, + id + ) + .fetch_one(pool) + .await + .map(|deployment| Some(deployment)) + .or_else(|err| match err { + sqlx::Error::RowNotFound => Ok(None), + e => { + tracing::error!("Failed to fetch deployment, error: {:?}", e); + Err("Could not fetch data".to_string()) + } + }) +} + pub async fn insert(pool: &PgPool, mut deployment: models::Deployment) -> Result { let query_span = tracing::info_span!("Saving new deployment into the database"); sqlx::query!( diff --git a/src/helpers/mq_manager.rs b/src/helpers/mq_manager.rs index c265825..f30d238 100644 --- a/src/helpers/mq_manager.rs +++ b/src/helpers/mq_manager.rs @@ -4,6 +4,7 @@ use lapin::{options::*, publisher_confirm::{Confirmation, PublisherConfirm}, Bas use lapin::types::AMQPType::ShortString; use lapin::types::{AMQPValue, FieldTable}; use serde::ser::Serialize; +use serde_valid::validation::error::Format::Default; #[derive(Debug)] pub struct MqManager { @@ -127,10 +128,22 @@ impl MqManager { .await .expect("Exchange declare failed"); + let mut args = FieldTable::default(); + args.insert("x-expires".into(), AMQPValue::LongUInt(180000)); + let queue = channel.queue_declare( - routing_key, - QueueDeclareOptions::default(), - Default::default(), + // "install_progress_all", + "#", + // "install_progress_hy181TZa4DaabUZWklsrxw", + QueueDeclareOptions { + passive: false, + durable: false, + exclusive: false, + auto_delete: true, + nowait: false, + }, + // FieldTable::default(), + args, ) .await .expect("Queue declare failed"); diff --git a/src/routes/project/deploy.rs b/src/routes/project/deploy.rs index b0665d8..9844035 100644 --- a/src/routes/project/deploy.rs +++ b/src/routes/project/deploy.rs @@ -49,7 +49,6 @@ pub async fn item( JsonResponse::::build().internal_server_error(err) })?; - // Save cloud credentials if requested let mut cloud_creds: models::Cloud = (&form.cloud).into(); cloud_creds.project_id = Some(id); From d4d21b441d3aae4d232d34c88d67fb100bbe5773 Mon Sep 17 00:00:00 2001 From: vsilent Date: Wed, 20 Mar 2024 15:13:24 +0200 Subject: [PATCH 220/284] mq listener, read queue and update status --- Dockerfile | 3 +- access_control.conf.dist | 2 +- docker-compose.yml | 16 ++++++ docker/dev/docker-compose.yml | 20 +++++++ src/console/commands/mq/listener.rs | 86 ++++++++++++++++++----------- src/console/main.rs | 3 +- src/db/deployment.rs | 26 +++++++++ src/forms/cloud.rs | 12 ++-- src/forms/mod.rs | 1 + src/forms/server.rs | 12 ++-- src/forms/user.rs | 4 +- src/helpers/mq_manager.rs | 19 ++++++- src/routes/cloud/add.rs | 3 +- src/routes/cloud/update.rs | 3 +- src/routes/project/deploy.rs | 33 +++++------ src/routes/server/update.rs | 3 +- src/startup.rs | 1 - tests/middleware_trydirect.rs | 4 -- 18 files changed, 172 insertions(+), 79 deletions(-) diff --git a/Dockerfile b/Dockerfile index 34fa4b0..66222d1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -37,7 +37,7 @@ COPY ./src ./src # cargo build --release RUN apt-get update && apt-get install --no-install-recommends -y libssl-dev; \ - cargo build --release + cargo build --bin=console && cargo build --release #RUN ls -la /app/target/release/ >&2 @@ -51,6 +51,7 @@ RUN mkdir ./files && chmod 0777 ./files # copy binary and configuration files COPY --from=builder /app/target/release/server . +COPY --from=builder /app/target/release/console . COPY --from=builder /app/.env . COPY --from=builder /app/configuration.yaml . COPY --from=builder /usr/local/cargo/bin/sqlx sqlx diff --git a/access_control.conf.dist b/access_control.conf.dist index 459a15f..f164af1 100644 --- a/access_control.conf.dist +++ b/access_control.conf.dist @@ -11,4 +11,4 @@ g = _, _ e = some(where (p.eft == allow)) [matchers] -m = g(r.sub, p.sub) && r.obj == p.obj && regexMatch(r.act, p.act) +m = g(r.sub, p.sub) && keyMatch2(r.obj, p.obj) && r.act == p.act diff --git a/docker-compose.yml b/docker-compose.yml index e9aee75..f87b3e2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,6 +29,22 @@ services: # stackerdb: # condition: service_healthy + stacker_queue: + image: trydirect/stacker:0.0.7 + container_name: stacker_queue + restart: always + volumes: + - ./configuration.yaml:/app/configuration.yaml + - ./.env:/app/.env + environment: + - RUST_LOG=debug + - RUST_BACKTRACE=1 + env_file: + - ./.env + depends_on: + stackerdb: + condition: service_healthy + entrypoint: /app/console mq listen # stackerdb: # container_name: stackerdb diff --git a/docker/dev/docker-compose.yml b/docker/dev/docker-compose.yml index 6bf8eb5..3577b14 100644 --- a/docker/dev/docker-compose.yml +++ b/docker/dev/docker-compose.yml @@ -37,6 +37,26 @@ services: - backend + stacker_queue: + image: trydirect/stacker:0.0.7 + container_name: stacker_queue + restart: always + volumes: + - ./configuration.yaml:/app/configuration.yaml + - ./.env:/app/.env + environment: + - RUST_LOG=debug + - RUST_BACKTRACE=1 + env_file: + - ./.env + depends_on: + stackerdb: + condition: service_healthy + entrypoint: /app/console mq listen + networks: + - backend + + stackerdb: container_name: stackerdb healthcheck: diff --git a/src/console/commands/mq/listener.rs b/src/console/commands/mq/listener.rs index cfe329a..501d199 100644 --- a/src/console/commands/mq/listener.rs +++ b/src/console/commands/mq/listener.rs @@ -1,19 +1,31 @@ use crate::configuration::get_configuration; use actix_web::rt; use actix_web::web; +use chrono::Utc; use lapin::{Channel, Queue}; use lapin::options::{BasicAckOptions, BasicConsumeOptions}; use lapin::types::FieldTable; use sqlx::PgPool; use db::deployment; -use crate::{db, helpers}; -use crate::helpers::mq_manager; +use crate::{db, forms, helpers}; +use crate::helpers::{JsonResponse, mq_manager}; use crate::helpers::mq_manager::MqManager; use futures_lite::stream::StreamExt; +use serde_derive::{Deserialize, Serialize}; +use crate::forms::project::ProjectForm; pub struct ListenCommand { } +#[derive(Serialize, Deserialize, Debug)] +struct ProgressMessage { + alert: i32, + id: String, + message: String, + status: String, + progress: String +} + impl ListenCommand { pub fn new() -> Self { Self {} @@ -31,18 +43,20 @@ impl crate::console::commands::CallableTrait for ListenCommand { let db_pool = web::Data::new(db_pool); + println!("Declare exchange"); let mq_manager = MqManager::try_new(settings.amqp.connection_string())?; let consumer_channel= mq_manager .consume( "install_progress", - "install_progress_*******" + "install.progress.#" ) .await?; + println!("Declare queue"); let mut consumer = consumer_channel .basic_consume( - "install_progress", + "#", "console_listener", BasicConsumeOptions::default(), FieldTable::default(), @@ -50,38 +64,46 @@ impl crate::console::commands::CallableTrait for ListenCommand { .await .expect("Basic consume"); - // .map_err(|err| format!("Error {:?}", err)); + println!("Waiting for messages .."); + while let Some(delivery) = consumer.next().await { + // println!("checking messages delivery {:?}", delivery); + let delivery = delivery.expect("error in consumer"); + let s:String = match String::from_utf8(delivery.data.to_owned()) { + //delivery.data is of type Vec + Ok(v) => v, + Err(e) => panic!("Invalid UTF-8 sequence: {}", e), + }; - tracing::info!("will consume"); - // if let Ok(consumer) = consumer { - while let Some(delivery) = consumer.next().await { - let delivery = delivery.expect("error in consumer"); - delivery.ack(BasicAckOptions::default()).await.expect("ack"); - } - // } + match serde_json::from_str::(&s) { + Ok(msg) => { + println!("message {:?}", msg); + // println!("id {:?}", msg.id); + // println!("status {:?}", msg.status); + delivery.ack(BasicAckOptions::default()).await.expect("ack"); - // while let Some(delivery) = consumer.next().await { - // tracing::debug!(message=?delivery, "received message"); - // if let Ok(delivery) = delivery { - // delivery - // .ack(BasicAckOptions::default()) - // .await - // .expect("basic_ack"); - // } - // } + if msg.status == "complete" { + let id = msg.id + .parse::() + .map_err(|err| "Could not parse deployment id".to_string() )?; + match crate::db::deployment::fetch( + db_pool.get_ref(), id + ) + .await? { - // on_complete() - // let deployment = crate::models::deployment::Deployment { - // id: 0, - // project_id: 0, - // deleted: false, - // status: "".to_string(), - // body: Default::default(), - // created_at: Default::default(), - // updated_at: Default::default(), - // }; - // deployment::update(db_pool.get_ref(), deployment).await?; + Some(mut row) => { + row.status = msg.status; + row.updated_at = Utc::now(); + deployment::update(db_pool.get_ref(), row).await?; + println!("deployment {} completed successfully", id); + } + None => println!("Deployment record not found in db") + } + } + } + Err(err) => { tracing::debug!("Invalid message format")} + } + } Ok(()) }) diff --git a/src/console/main.rs b/src/console/main.rs index 752e10a..f6bc804 100644 --- a/src/console/main.rs +++ b/src/console/main.rs @@ -52,7 +52,6 @@ fn get_command(cli: Cli) -> Result Ok(Box::new( stacker::console::commands::mq::ListenCommand::new(), )), - }, - _ => Err("command does not match".to_string()), + } } } diff --git a/src/db/deployment.rs b/src/db/deployment.rs index 11e7a2e..7f78f0c 100644 --- a/src/db/deployment.rs +++ b/src/db/deployment.rs @@ -2,6 +2,32 @@ use crate::models; use sqlx::PgPool; use tracing::Instrument; + +pub async fn fetch(pool: &PgPool, id: i32) -> Result, String> { + tracing::info!("Fetch deployment {}", id); + sqlx::query_as!( + models::Deployment, + r#" + SELECT + * + FROM deployment + WHERE id=$1 + LIMIT 1 + "#, + id + ) + .fetch_one(pool) + .await + .map(|deployment| Some(deployment)) + .or_else(|err| match err { + sqlx::Error::RowNotFound => Ok(None), + e => { + tracing::error!("Failed to fetch deployment, error: {:?}", e); + Err("Could not fetch data".to_string()) + } + }) +} + pub async fn insert(pool: &PgPool, mut deployment: models::Deployment) -> Result { let query_span = tracing::info_span!("Saving new deployment into the database"); sqlx::query!( diff --git a/src/forms/cloud.rs b/src/forms/cloud.rs index 138b298..472bdb7 100644 --- a/src/forms/cloud.rs +++ b/src/forms/cloud.rs @@ -15,14 +15,14 @@ pub struct Cloud { pub save_token: Option, } -impl Into for Cloud { +impl Into for &Cloud { fn into(self) -> models::Cloud { let mut cloud = models::Cloud::default(); - cloud.provider = self.provider; - cloud.cloud_token = self.cloud_token; - cloud.cloud_key = self.cloud_key; - cloud.cloud_secret = self.cloud_secret; - cloud.save_token = self.save_token; + cloud.provider = self.provider.clone(); + cloud.cloud_token = self.cloud_token.clone(); + cloud.cloud_key = self.cloud_key.clone(); + cloud.cloud_secret = self.cloud_secret.clone(); + cloud.save_token = self.save_token.clone(); cloud } diff --git a/src/forms/mod.rs b/src/forms/mod.rs index f5fcc9c..0647181 100644 --- a/src/forms/mod.rs +++ b/src/forms/mod.rs @@ -7,3 +7,4 @@ pub(crate) mod server; pub use rating::*; pub use cloud::*; pub use server::*; +pub use user::UserForm; diff --git a/src/forms/server.rs b/src/forms/server.rs index 1e55a89..cba997f 100644 --- a/src/forms/server.rs +++ b/src/forms/server.rs @@ -14,14 +14,14 @@ pub struct Server { pub disk_type: Option, } -impl Into for Server { +impl Into for &Server { fn into(self) -> models::Server { let mut server = models::Server::default(); - server.disk_type = self.disk_type; - server.region = self.region; - server.server = self.server; - server.zone = self.zone; - server.os = self.os; + server.disk_type = self.disk_type.clone(); + server.region = self.region.clone(); + server.server = self.server.clone(); + server.zone = self.zone.clone(); + server.os = self.os.clone(); server.created_at = Utc::now(); server.updated_at = Utc::now(); diff --git a/src/forms/user.rs b/src/forms/user.rs index 8ff0b4c..0fd0024 100644 --- a/src/forms/user.rs +++ b/src/forms/user.rs @@ -10,6 +10,8 @@ pub struct UserForm { pub user: User, } +//todo deref for UserForm. userForm.id, userForm.first_name + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] #[serde(rename_all = "camelCase")] pub struct User { @@ -139,4 +141,4 @@ impl TryInto for UserForm { }) } -} \ No newline at end of file +} diff --git a/src/helpers/mq_manager.rs b/src/helpers/mq_manager.rs index c265825..f30d238 100644 --- a/src/helpers/mq_manager.rs +++ b/src/helpers/mq_manager.rs @@ -4,6 +4,7 @@ use lapin::{options::*, publisher_confirm::{Confirmation, PublisherConfirm}, Bas use lapin::types::AMQPType::ShortString; use lapin::types::{AMQPValue, FieldTable}; use serde::ser::Serialize; +use serde_valid::validation::error::Format::Default; #[derive(Debug)] pub struct MqManager { @@ -127,10 +128,22 @@ impl MqManager { .await .expect("Exchange declare failed"); + let mut args = FieldTable::default(); + args.insert("x-expires".into(), AMQPValue::LongUInt(180000)); + let queue = channel.queue_declare( - routing_key, - QueueDeclareOptions::default(), - Default::default(), + // "install_progress_all", + "#", + // "install_progress_hy181TZa4DaabUZWklsrxw", + QueueDeclareOptions { + passive: false, + durable: false, + exclusive: false, + auto_delete: true, + nowait: false, + }, + // FieldTable::default(), + args, ) .await .expect("Queue declare failed"); diff --git a/src/routes/cloud/add.rs b/src/routes/cloud/add.rs index cb57209..6178ff1 100644 --- a/src/routes/cloud/add.rs +++ b/src/routes/cloud/add.rs @@ -1,3 +1,4 @@ +use std::ops::Deref; use crate::forms; use crate::helpers::JsonResponse; use crate::models; @@ -29,7 +30,7 @@ pub async fn add( return Err(JsonResponse::::build().form_error(errors)); } - let mut cloud: models::Cloud = form.into_inner().into(); + let mut cloud: models::Cloud = form.deref().into(); cloud.user_id = user.id.clone(); db::cloud::insert(pg_pool.get_ref(), cloud) diff --git a/src/routes/cloud/update.rs b/src/routes/cloud/update.rs index 3e2e564..b48fd8b 100644 --- a/src/routes/cloud/update.rs +++ b/src/routes/cloud/update.rs @@ -7,6 +7,7 @@ use serde_valid::Validate; use sqlx::PgPool; use std::sync::Arc; use tracing::Instrument; +use std::ops::Deref; #[tracing::instrument(name = "Update cloud.")] #[put("/{id}")] @@ -33,7 +34,7 @@ pub async fn item( return Err(JsonResponse::::build().form_error(errors.to_string())); } - let mut cloud:models::Cloud = form.into_inner().into(); + let mut cloud:models::Cloud = form.deref().into(); cloud.id = cloud_row.id; cloud.user_id = user.id.clone(); diff --git a/src/routes/project/deploy.rs b/src/routes/project/deploy.rs index a1261ab..9844035 100644 --- a/src/routes/project/deploy.rs +++ b/src/routes/project/deploy.rs @@ -43,33 +43,30 @@ pub async fn item( })?; // Build compose - let id = project.id.clone(); + let id = project.id; let dc = DcBuilder::new(project); let fc = dc.build().map_err(|err| { JsonResponse::::build().internal_server_error(err) })?; - // Save cloud credentials if requested - let mut cloud_creds: models::Cloud = form.cloud.clone().into(); - cloud_creds.project_id = Some(id.clone()); + let mut cloud_creds: models::Cloud = (&form.cloud).into(); + cloud_creds.project_id = Some(id); cloud_creds.user_id = user.id.clone(); - if let Some(save_token) = cloud_creds.save_token { - if save_token { - db::cloud::insert(pg_pool.get_ref(), cloud_creds.clone()) - .await - .map(|cloud| cloud) - .map_err(|_| { - JsonResponse::::build().internal_server_error("Internal Server Error") - })?; - } + if Some(true) == cloud_creds.save_token { + db::cloud::insert(pg_pool.get_ref(), cloud_creds.clone()) + .await + .map(|cloud| cloud) + .map_err(|_| { + JsonResponse::::build().internal_server_error("Internal Server Error") + })?; } // Save server type and region - let mut server: models::Server = form.server.clone().into(); + let mut server: models::Server = (&form.server).into(); server.user_id = user.id.clone(); - server.project_id = id.clone(); + server.project_id = id; let server = db::server::insert(pg_pool.get_ref(), server) .await .map(|server| server) @@ -89,10 +86,9 @@ pub async fn item( payload.docker_compose = Some(compress(fc.as_str())); // Store deployment attempts into deployment table in db - let project_id = dc.project.id.clone(); let json_request = dc.project.body.clone(); let deployment = models::Deployment::new( - project_id, + dc.project.id, String::from("pending"), json_request ); @@ -189,10 +185,9 @@ pub async fn saved_item( payload.docker_compose = Some(compress(fc.as_str())); - let project_id = dc.project.id.clone(); let json_request = dc.project.body.clone(); let deployment = models::Deployment::new( - project_id, + dc.project.id, String::from("pending"), json_request ); diff --git a/src/routes/server/update.rs b/src/routes/server/update.rs index 6220869..02c4b0e 100644 --- a/src/routes/server/update.rs +++ b/src/routes/server/update.rs @@ -7,6 +7,7 @@ use serde_valid::Validate; use sqlx::PgPool; use std::sync::Arc; use tracing::Instrument; +use std::ops::Deref; #[tracing::instrument(name = "Update server.")] #[put("/{id}")] @@ -33,7 +34,7 @@ pub async fn item( return Err(JsonResponse::::build().form_error(errors.to_string())); } - let mut server:models::Server = form.into_inner().into(); + let mut server:models::Server = form.deref().into(); server.id = server_row.id; server.project_id = server_row.project_id; server.user_id = user.id.clone(); diff --git a/src/startup.rs b/src/startup.rs index 2c7c4ba..a95acfb 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -7,7 +7,6 @@ use actix_web::{ App, HttpServer, }; use crate::middleware; -use actix_web_httpauth::middleware::HttpAuthentication; use sqlx::{Pool, Postgres}; use std::net::TcpListener; use tracing_actix_web::TracingLogger; diff --git a/tests/middleware_trydirect.rs b/tests/middleware_trydirect.rs index 0590618..4937781 100644 --- a/tests/middleware_trydirect.rs +++ b/tests/middleware_trydirect.rs @@ -22,8 +22,4 @@ async fn middleware_trydirect_works() { assert!(response.status().is_success()); assert_eq!(Some(0), response.content_length()); - - - //todo header stacker-id not found - // } From dc6c54fffd04b58e2a6ec4ec3b7c8464be0f6dd2 Mon Sep 17 00:00:00 2001 From: vsilent Date: Wed, 20 Mar 2024 15:42:10 +0200 Subject: [PATCH 221/284] fix warnings --- docker-compose.yml | 32 ++++++++++++++++---------------- src/db/cloud.rs | 2 +- src/db/project.rs | 4 ++-- src/db/server.rs | 2 +- src/forms/project/form.rs | 2 +- src/helpers/dockerhub.rs | 6 +++--- src/routes/project/deploy.rs | 4 ++-- src/routes/server/update.rs | 2 +- src/startup.rs | 1 + 9 files changed, 28 insertions(+), 27 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index f87b3e2..eeb10eb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,22 +29,22 @@ services: # stackerdb: # condition: service_healthy - stacker_queue: - image: trydirect/stacker:0.0.7 - container_name: stacker_queue - restart: always - volumes: - - ./configuration.yaml:/app/configuration.yaml - - ./.env:/app/.env - environment: - - RUST_LOG=debug - - RUST_BACKTRACE=1 - env_file: - - ./.env - depends_on: - stackerdb: - condition: service_healthy - entrypoint: /app/console mq listen +# stacker_queue: +# image: trydirect/stacker:0.0.7 +# container_name: stacker_queue +# restart: always +# volumes: +# - ./configuration.yaml:/app/configuration.yaml +# - ./.env:/app/.env +# environment: +# - RUST_LOG=debug +# - RUST_BACKTRACE=1 +# env_file: +# - ./.env +# depends_on: +# stackerdb: +# condition: service_healthy +# entrypoint: /app/console mq listen # stackerdb: # container_name: stackerdb diff --git a/src/db/cloud.rs b/src/db/cloud.rs index 07f5285..a5e71c2 100644 --- a/src/db/cloud.rs +++ b/src/db/cloud.rs @@ -151,7 +151,7 @@ pub async fn delete(pool: &PgPool, id: i32) -> Result { }); Ok(true) } - Err(err) => { + Err(_err) => { let _ = tx.rollback().await.map_err(|err| println!("{:?}", err)); Ok(false) } diff --git a/src/db/project.rs b/src/db/project.rs index d1f469f..b7978e6 100644 --- a/src/db/project.rs +++ b/src/db/project.rs @@ -167,14 +167,14 @@ pub async fn delete(pool: &PgPool, id: i32) -> Result { }) { Ok(_) => { - tx.commit().await.map_err(|err| { + let _ = tx.commit().await.map_err(|err| { tracing::error!("Failed to commit transaction: {:?}", err); false }); Ok(true) } Err(err) => { - tx.rollback().await.map_err(|err| println!("{:?}", err)); + let _ = tx.rollback().await.map_err(|err| println!("{:?}", err)); Ok(false) } // todo, when empty commit() diff --git a/src/db/server.rs b/src/db/server.rs index 86f147b..75513a9 100644 --- a/src/db/server.rs +++ b/src/db/server.rs @@ -182,7 +182,7 @@ pub async fn delete(pool: &PgPool, id: i32) -> Result { }); Ok(true) } - Err(err) => { + Err(_err) => { let _ = tx.rollback().await.map_err(|err| println!("{:?}", err)); Ok(false) } diff --git a/src/forms/project/form.rs b/src/forms/project/form.rs index d2498cf..c122ffc 100644 --- a/src/forms/project/form.rs +++ b/src/forms/project/form.rs @@ -63,7 +63,7 @@ pub(crate) async fn body_into_form(body: Bytes) -> actix_web::Result::build().bad_request(msg) }) - .and_then(|mut form: forms::project::ProjectForm| { + .and_then(|form: forms::project::ProjectForm| { if !form.validate().is_ok() { let errors = form.validate().unwrap_err().to_string(); let err_msg = format!("Invalid data received {:?}", &errors); diff --git a/src/helpers/dockerhub.rs b/src/helpers/dockerhub.rs index d5e4ad6..d7771c7 100644 --- a/src/helpers/dockerhub.rs +++ b/src/helpers/dockerhub.rs @@ -111,7 +111,7 @@ impl<'a> DockerHub<'a> { let client = reqwest::Client::new() .get(url) .header("Accept", "application/json"); - let mut client = self.set_token(client).await?; + let client = self.set_token(client).await?; client .send() .await @@ -146,7 +146,7 @@ impl<'a> DockerHub<'a> { let client = reqwest::Client::new() .get(url) .header("Accept", "application/json"); - let mut client = self.set_token(client).await?; + let client = self.set_token(client).await?; client .send() .await @@ -186,7 +186,7 @@ impl<'a> DockerHub<'a> { } } - pub async fn set_token(&self, mut client: RequestBuilder) -> Result { + pub async fn set_token(&self, client: RequestBuilder) -> Result { if self.creds.password.is_empty() { tracing::debug!("Password is empty. Image should be public"); return Ok(client); diff --git a/src/routes/project/deploy.rs b/src/routes/project/deploy.rs index 9844035..f3d242a 100644 --- a/src/routes/project/deploy.rs +++ b/src/routes/project/deploy.rs @@ -156,7 +156,7 @@ pub async fn saved_item( } } } - Err(e) => { + Err(_e) => { return Err(JsonResponse::::build().not_found("No cloud configured")); } }; @@ -169,7 +169,7 @@ pub async fn saved_item( // } server.into_iter().nth(0).unwrap() // @todo refactoring is required } - Err(err) => { + Err(_e) => { return Err(JsonResponse::::build().not_found("No servers configured")); } }; diff --git a/src/routes/server/update.rs b/src/routes/server/update.rs index 02c4b0e..4f83d1e 100644 --- a/src/routes/server/update.rs +++ b/src/routes/server/update.rs @@ -19,7 +19,7 @@ pub async fn item( ) -> Result { let id = path.0; - let mut server_row = db::server::fetch(pg_pool.get_ref(), id) + let server_row = db::server::fetch(pg_pool.get_ref(), id) .await .map_err(|err| JsonResponse::::build().internal_server_error(err)) .and_then(|server| match server { diff --git a/src/startup.rs b/src/startup.rs index a95acfb..2c7c4ba 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -7,6 +7,7 @@ use actix_web::{ App, HttpServer, }; use crate::middleware; +use actix_web_httpauth::middleware::HttpAuthentication; use sqlx::{Pool, Postgres}; use std::net::TcpListener; use tracing_actix_web::TracingLogger; From 3e367ee3dfdc4259039c3ec8a6695141ed784eec Mon Sep 17 00:00:00 2001 From: vsilent Date: Wed, 20 Mar 2024 15:51:32 +0200 Subject: [PATCH 222/284] fix restart policy for service --- src/forms/project/app.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/forms/project/app.rs b/src/forms/project/app.rs index 64598e6..56a5da9 100644 --- a/src/forms/project/app.rs +++ b/src/forms/project/app.rs @@ -143,7 +143,7 @@ impl App { service.ports = dctypes::Ports::Long(ports); - service.restart = Some("always".to_owned()); + service.restart = Some(self.restart.clone()); service.volumes = volumes; service.environment = dctypes::Environment::KvPair(envs); From 858ab0e890f8073e4856135f7314d9a3d1c6d4d8 Mon Sep 17 00:00:00 2001 From: vsilent Date: Thu, 21 Mar 2024 11:52:25 +0200 Subject: [PATCH 223/284] import fixes --- src/console/commands/mq/listener.rs | 25 ++++++++++++++----------- src/db/project.rs | 2 +- src/forms/cloud.rs | 1 - src/forms/project/compose_networks.rs | 1 - src/forms/project/form.rs | 1 - src/forms/project/network.rs | 2 -- src/forms/project/payload.rs | 1 - src/forms/project/port.rs | 2 +- src/forms/user.rs | 1 - src/helpers/dockerhub.rs | 10 ++++++---- src/helpers/mq_manager.rs | 5 +---- src/helpers/project/builder.rs | 7 +++---- src/middleware/access_manager.rs | 2 +- src/middleware/trydirect.rs | 1 - src/models/deployment.rs | 7 ++++++- src/models/project.rs | 7 ++++++- src/routes/client/add.rs | 1 - src/routes/client/disable.rs | 1 - src/routes/client/enable.rs | 1 - src/routes/client/update.rs | 1 - src/routes/cloud/add.rs | 1 - src/routes/cloud/delete.rs | 4 +--- src/routes/cloud/get.rs | 1 - src/routes/cloud/mod.rs | 8 ++++---- src/routes/cloud/update.rs | 3 +-- src/routes/project/compose.rs | 2 +- src/routes/project/delete.rs | 4 +--- src/routes/project/get.rs | 9 ++++----- src/routes/project/mod.rs | 8 ++++---- src/routes/project/update.rs | 1 - src/routes/rating/add.rs | 1 - src/routes/rating/get.rs | 1 - src/routes/server/delete.rs | 3 +-- src/routes/server/get.rs | 2 +- src/routes/server/mod.rs | 8 ++++---- src/routes/server/update.rs | 3 +-- 36 files changed, 62 insertions(+), 76 deletions(-) diff --git a/src/console/commands/mq/listener.rs b/src/console/commands/mq/listener.rs index 501d199..a9e6c04 100644 --- a/src/console/commands/mq/listener.rs +++ b/src/console/commands/mq/listener.rs @@ -2,25 +2,24 @@ use crate::configuration::get_configuration; use actix_web::rt; use actix_web::web; use chrono::Utc; -use lapin::{Channel, Queue}; use lapin::options::{BasicAckOptions, BasicConsumeOptions}; use lapin::types::FieldTable; use sqlx::PgPool; use db::deployment; -use crate::{db, forms, helpers}; -use crate::helpers::{JsonResponse, mq_manager}; +use crate::db; use crate::helpers::mq_manager::MqManager; use futures_lite::stream::StreamExt; use serde_derive::{Deserialize, Serialize}; -use crate::forms::project::ProjectForm; +// use crate::forms::project::ProjectForm; pub struct ListenCommand { } #[derive(Serialize, Deserialize, Debug)] struct ProgressMessage { - alert: i32, id: String, + deploy_id: Option, + alert: i32, message: String, status: String, progress: String @@ -74,17 +73,19 @@ impl crate::console::commands::CallableTrait for ListenCommand { Err(e) => panic!("Invalid UTF-8 sequence: {}", e), }; + println!("incoming data {:?}", s); + let statuses = vec!["complete", "paused", "failed"]; match serde_json::from_str::(&s) { Ok(msg) => { - println!("message {:?}", msg); + println!("message {:?}", s); // println!("id {:?}", msg.id); // println!("status {:?}", msg.status); - delivery.ack(BasicAckOptions::default()).await.expect("ack"); - if msg.status == "complete" { - let id = msg.id + if statuses.contains(&(msg.status.as_str())) { + println!("Process on complete status"); + let id = msg.deploy_id.unwrap() .parse::() - .map_err(|err| "Could not parse deployment id".to_string() )?; + .map_err(|_err| "Could not parse deployment id".to_string() )?; match crate::db::deployment::fetch( db_pool.get_ref(), id @@ -101,8 +102,10 @@ impl crate::console::commands::CallableTrait for ListenCommand { } } } - Err(err) => { tracing::debug!("Invalid message format")} + Err(_err) => { tracing::debug!("Invalid message format {:?}", _err)} } + + delivery.ack(BasicAckOptions::default()).await.expect("ack"); } Ok(()) diff --git a/src/db/project.rs b/src/db/project.rs index b7978e6..0e8e24c 100644 --- a/src/db/project.rs +++ b/src/db/project.rs @@ -173,7 +173,7 @@ pub async fn delete(pool: &PgPool, id: i32) -> Result { }); Ok(true) } - Err(err) => { + Err(_err) => { let _ = tx.rollback().await.map_err(|err| println!("{:?}", err)); Ok(false) } diff --git a/src/forms/cloud.rs b/src/forms/cloud.rs index 472bdb7..ab040c3 100644 --- a/src/forms/cloud.rs +++ b/src/forms/cloud.rs @@ -1,7 +1,6 @@ use crate::models; use serde::{Deserialize, Serialize}; use serde_valid::Validate; -use chrono::Utc; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Cloud { diff --git a/src/forms/project/compose_networks.rs b/src/forms/project/compose_networks.rs index bb45a36..b38eb8f 100644 --- a/src/forms/project/compose_networks.rs +++ b/src/forms/project/compose_networks.rs @@ -1,7 +1,6 @@ use serde::{Deserialize, Serialize}; use docker_compose_types as dctypes; use indexmap::IndexMap; -use crate::forms::project; use crate::forms::project::network::Network; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] diff --git a/src/forms/project/form.rs b/src/forms/project/form.rs index c122ffc..3924c6c 100644 --- a/src/forms/project/form.rs +++ b/src/forms/project/form.rs @@ -1,5 +1,4 @@ use serde::{Deserialize, Serialize}; -use serde_json::Value; use serde_valid::Validate; use actix_web::Error; use actix_web::web::Bytes; diff --git a/src/forms/project/network.rs b/src/forms/project/network.rs index 9b848ff..2e0e183 100644 --- a/src/forms/project/network.rs +++ b/src/forms/project/network.rs @@ -1,8 +1,6 @@ use serde::{Deserialize, Serialize}; use serde_valid::Validate; -use crate::forms::project; use docker_compose_types as dctypes; -use indexmap::IndexMap; use crate::forms::project::NetworkDriver; diff --git a/src/forms/project/payload.rs b/src/forms/project/payload.rs index 7108a1f..bc8e8fb 100644 --- a/src/forms/project/payload.rs +++ b/src/forms/project/payload.rs @@ -1,7 +1,6 @@ use std::convert::TryFrom; use crate::models; use crate::forms; -use serde_json::Value; use serde::{Deserialize, Serialize}; use serde_valid::Validate; diff --git a/src/forms/project/port.rs b/src/forms/project/port.rs index 4da0c49..06c3020 100644 --- a/src/forms/project/port.rs +++ b/src/forms/project/port.rs @@ -53,7 +53,7 @@ impl TryInto for &Port { let cp = self.container_port .clone() .parse::() - .map_err(|err| "Could not parse container port".to_string() )?; + .map_err(|_err| "Could not parse container port".to_string() )?; let hp = match self.host_port.clone() { Some(hp) => { diff --git a/src/forms/user.rs b/src/forms/user.rs index 0fd0024..5a7fa48 100644 --- a/src/forms/user.rs +++ b/src/forms/user.rs @@ -1,7 +1,6 @@ use serde_derive::{Serialize, Deserialize}; use serde_json::Value; use serde_valid::{Validate}; -use tracing_subscriber::fmt::format; use crate::models::user::User as UserModel; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] diff --git a/src/helpers/dockerhub.rs b/src/helpers/dockerhub.rs index d7771c7..fa41df7 100644 --- a/src/helpers/dockerhub.rs +++ b/src/helpers/dockerhub.rs @@ -116,12 +116,12 @@ impl<'a> DockerHub<'a> { .send() .await .map_err(|err| { - tracing::debug!("Error response {:?}", err); + tracing::debug!("πŸŸ₯Error response {:?}", err); format!("{}", err) })? .json::() .await - .map_err(|err| format!("Error on getting results:: {}", err)) + .map_err(|err| format!("πŸŸ₯Error on getting results:: {}", err)) .map(|repositories| { tracing::debug!("Get public image repositories response {:?}", repositories); if repositories.count.unwrap_or(0) > 0 { @@ -130,6 +130,7 @@ impl<'a> DockerHub<'a> { .results .into_iter() .any(|repo| repo.status == 1); + tracing::debug!("βœ… Image is active"); active } else { false @@ -150,11 +151,11 @@ impl<'a> DockerHub<'a> { client .send() .await - .map_err(|err| format!("{}", err))? + .map_err(|err| format!("πŸŸ₯{}", err))? .json::() .await .map_err(|err| { - tracing::debug!("Error response {:?}", err); + tracing::debug!("πŸŸ₯Error response {:?}", err); format!("{}", err) }) .map(|tags| { @@ -165,6 +166,7 @@ impl<'a> DockerHub<'a> { .results .into_iter() .any(|tag| tag.tag_status.contains("active")); + tracing::debug!("βœ… Image is active"); active } else { false diff --git a/src/helpers/mq_manager.rs b/src/helpers/mq_manager.rs index f30d238..f205f1a 100644 --- a/src/helpers/mq_manager.rs +++ b/src/helpers/mq_manager.rs @@ -1,10 +1,7 @@ -use actix_web::web; use deadpool_lapin::{Config, CreatePoolError, Object, Pool, Runtime}; -use lapin::{options::*, publisher_confirm::{Confirmation, PublisherConfirm}, BasicProperties, Channel, ExchangeKind, Queue}; -use lapin::types::AMQPType::ShortString; +use lapin::{options::*, publisher_confirm::{Confirmation, PublisherConfirm}, BasicProperties, Channel, ExchangeKind}; use lapin::types::{AMQPValue, FieldTable}; use serde::ser::Serialize; -use serde_valid::validation::error::Format::Default; #[derive(Debug)] pub struct MqManager { diff --git a/src/helpers/project/builder.rs b/src/helpers/project/builder.rs index 7112fe3..9c2a33a 100644 --- a/src/helpers/project/builder.rs +++ b/src/helpers/project/builder.rs @@ -2,14 +2,13 @@ use crate::forms; use docker_compose_types as dctypes; use crate::models; use serde_yaml; -use crate::helpers::project::*; -use tracing::Value; +// use crate::helpers::project::*; /// A builder for constructing docker compose. #[derive(Clone, Debug)] pub struct DcBuilder { - config: Config, + // config: Config, pub(crate) project: models::Project, } @@ -17,7 +16,7 @@ pub struct DcBuilder { impl DcBuilder { pub fn new(project: models::Project) -> Self { DcBuilder { - config: Config::default(), + // config: Config::default(), project, } } diff --git a/src/middleware/access_manager.rs b/src/middleware/access_manager.rs index 4760114..f251e9d 100644 --- a/src/middleware/access_manager.rs +++ b/src/middleware/access_manager.rs @@ -17,7 +17,7 @@ pub async fn try_new(db_connection_address: String) -> Result Self { Deployment { + id: 0, + project_id: 0, + deleted: None, status: "pending".to_string(), - ..Default::default() + body: Default::default(), + created_at: Default::default(), + updated_at: Default::default(), } } } diff --git a/src/models/project.rs b/src/models/project.rs index 7742267..29b260b 100644 --- a/src/models/project.rs +++ b/src/models/project.rs @@ -34,9 +34,14 @@ impl Project { impl Default for Project { fn default() -> Self { Project { + id: 0, + stack_id: Default::default(), user_id: "".to_string(), name: "".to_string(), - ..Default::default() + body: Default::default(), + request_json: Default::default(), + created_at: Default::default(), + updated_at: Default::default(), } } } diff --git a/src/routes/client/add.rs b/src/routes/client/add.rs index 0b526d1..bddbb74 100644 --- a/src/routes/client/add.rs +++ b/src/routes/client/add.rs @@ -6,7 +6,6 @@ use crate::models; use actix_web::{post, web, Responder, Result}; use sqlx::PgPool; use std::sync::Arc; -use tracing::Instrument; #[tracing::instrument(name = "Add client.")] #[post("")] diff --git a/src/routes/client/disable.rs b/src/routes/client/disable.rs index 70d2a1c..eb4f43a 100644 --- a/src/routes/client/disable.rs +++ b/src/routes/client/disable.rs @@ -5,7 +5,6 @@ use crate::models; use actix_web::{put, web, Responder, Result}; use sqlx::PgPool; use std::sync::Arc; -use tracing::Instrument; #[tracing::instrument(name = "Disable client.")] #[put("/{id}/disable")] diff --git a/src/routes/client/enable.rs b/src/routes/client/enable.rs index c87fc44..200f080 100644 --- a/src/routes/client/enable.rs +++ b/src/routes/client/enable.rs @@ -6,7 +6,6 @@ use crate::models; use actix_web::{put, web, Responder, Result}; use sqlx::PgPool; use std::sync::Arc; -use tracing::Instrument; #[tracing::instrument(name = "Enable client.")] #[put("/{id}/enable")] diff --git a/src/routes/client/update.rs b/src/routes/client/update.rs index 5f19de5..243cfa8 100644 --- a/src/routes/client/update.rs +++ b/src/routes/client/update.rs @@ -5,7 +5,6 @@ use crate::{configuration::Settings, helpers::JsonResponse}; use actix_web::{put, web, Responder, Result}; use sqlx::PgPool; use std::sync::Arc; -use tracing::Instrument; #[tracing::instrument(name = "Update client.")] #[put("/{id}")] diff --git a/src/routes/cloud/add.rs b/src/routes/cloud/add.rs index 6178ff1..ca8e7b8 100644 --- a/src/routes/cloud/add.rs +++ b/src/routes/cloud/add.rs @@ -5,7 +5,6 @@ use crate::models; use crate::db; use actix_web::{post, web, Responder, Result}; use sqlx::PgPool; -use tracing::Instrument; use std::sync::Arc; use serde_valid::Validate; diff --git a/src/routes/cloud/delete.rs b/src/routes/cloud/delete.rs index b69aec4..94188c7 100644 --- a/src/routes/cloud/delete.rs +++ b/src/routes/cloud/delete.rs @@ -3,8 +3,6 @@ use crate::models; use actix_web::{delete, web, Responder, Result}; use sqlx::PgPool; use std::sync::Arc; -use futures_util::FutureExt; -use tracing::Instrument; use crate::db; use crate::models::Cloud; @@ -15,7 +13,7 @@ pub async fn item( path: web::Path<(i32,)>, pg_pool: web::Data, ) -> Result { - /// Get cloud apps of logged user only + // Get cloud apps of logged user only let (id,) = path.into_inner(); let cloud = db::cloud::fetch(pg_pool.get_ref(), id) diff --git a/src/routes/cloud/get.rs b/src/routes/cloud/get.rs index 62f2a47..23af867 100644 --- a/src/routes/cloud/get.rs +++ b/src/routes/cloud/get.rs @@ -4,7 +4,6 @@ use crate::helpers::JsonResponse; use crate::models; use actix_web::{get, web, Responder, Result}; use sqlx::PgPool; -use tracing::Instrument; // workflow // add, update, list, get(user_id), ACL, diff --git a/src/routes/cloud/mod.rs b/src/routes/cloud/mod.rs index bc45c2a..e4ea6c1 100644 --- a/src/routes/cloud/mod.rs +++ b/src/routes/cloud/mod.rs @@ -3,7 +3,7 @@ pub mod get; pub mod update; pub(crate) mod delete; -pub use add::*; -pub use get::*; -pub use update::*; -pub use delete::*; +// pub use add::*; +// pub use get::*; +// pub use update::*; +// pub use delete::*; diff --git a/src/routes/cloud/update.rs b/src/routes/cloud/update.rs index b48fd8b..bdc0a15 100644 --- a/src/routes/cloud/update.rs +++ b/src/routes/cloud/update.rs @@ -2,11 +2,10 @@ use crate::forms; use crate::helpers::JsonResponse; use crate::models; use crate::db; -use actix_web::{web, web::Data, Responder, Result, post, put}; +use actix_web::{web, web::Data, Responder, Result, put}; use serde_valid::Validate; use sqlx::PgPool; use std::sync::Arc; -use tracing::Instrument; use std::ops::Deref; #[tracing::instrument(name = "Update cloud.")] diff --git a/src/routes/project/compose.rs b/src/routes/project/compose.rs index d0ea432..de52ca0 100644 --- a/src/routes/project/compose.rs +++ b/src/routes/project/compose.rs @@ -40,7 +40,7 @@ pub async fn admin( path: web::Path<(i32,)>, pg_pool: Data, ) -> Result { - /// Admin function for generating compose file for specified user + // Admin function for generating compose file for specified user let id = path.0; let project = db::project::fetch(pg_pool.get_ref(), id) .await diff --git a/src/routes/project/delete.rs b/src/routes/project/delete.rs index c0e1b26..92c6d98 100644 --- a/src/routes/project/delete.rs +++ b/src/routes/project/delete.rs @@ -3,8 +3,6 @@ use crate::models; use actix_web::{delete, web, Responder, Result}; use sqlx::PgPool; use std::sync::Arc; -use futures_util::FutureExt; -use tracing::Instrument; use crate::db; use crate::models::Project; @@ -15,7 +13,7 @@ pub async fn item( path: web::Path<(i32,)>, pg_pool: web::Data, ) -> Result { - /// Get project apps of logged user only + // Get project apps of logged user only let (id,) = path.into_inner(); let project = db::project::fetch(pg_pool.get_ref(), id) diff --git a/src/routes/project/get.rs b/src/routes/project/get.rs index 3cd7fc3..e5d5a16 100644 --- a/src/routes/project/get.rs +++ b/src/routes/project/get.rs @@ -4,7 +4,6 @@ use crate::models; use actix_web::{get, web, Responder, Result}; use sqlx::PgPool; use std::sync::Arc; -use tracing::Instrument; #[tracing::instrument(name = "Get logged user project.")] #[get("/{id}")] @@ -13,7 +12,7 @@ pub async fn item( path: web::Path<(i32,)>, pg_pool: web::Data, ) -> Result { - /// Get project apps of logged user only + // Get project apps of logged user only let (id,) = path.into_inner(); db::project::fetch(pg_pool.get_ref(), id) @@ -35,9 +34,9 @@ pub async fn list( path: web::Path<(String,)>, pg_pool: web::Data, ) -> Result { - /// This is admin endpoint, used by a client app, client app is confidential - /// it should return projects by user id - /// in order to pass validation at external deployment service + // This is admin endpoint, used by a client app, client app is confidential + // it should return projects by user id + // in order to pass validation at external deployment service let user_id = path.into_inner().0; db::project::fetch_by_user(pg_pool.get_ref(), &user_id) diff --git a/src/routes/project/mod.rs b/src/routes/project/mod.rs index 6d66205..05f7de8 100644 --- a/src/routes/project/mod.rs +++ b/src/routes/project/mod.rs @@ -5,7 +5,7 @@ pub mod update; pub(crate) mod compose; pub(crate) mod delete; -pub use add::*; -pub use update::*; -pub use deploy::*; -pub use get::*; +pub use add::item; +// pub use update::*; +// pub use deploy::*; +// pub use get::*; diff --git a/src/routes/project/update.rs b/src/routes/project/update.rs index ecd72b1..4fc8568 100644 --- a/src/routes/project/update.rs +++ b/src/routes/project/update.rs @@ -9,7 +9,6 @@ use serde_valid::Validate; use sqlx::PgPool; use std::sync::Arc; use actix_web::web::Bytes; -use tracing::Instrument; use std::str; #[tracing::instrument(name = "Update project.")] diff --git a/src/routes/rating/add.rs b/src/routes/rating/add.rs index 74bc725..e91dbe6 100644 --- a/src/routes/rating/add.rs +++ b/src/routes/rating/add.rs @@ -4,7 +4,6 @@ use crate::models; use crate::db; use actix_web::{post, web, Responder, Result}; use sqlx::PgPool; -use tracing::Instrument; use std::sync::Arc; // workflow diff --git a/src/routes/rating/get.rs b/src/routes/rating/get.rs index 34ef6af..c34677d 100644 --- a/src/routes/rating/get.rs +++ b/src/routes/rating/get.rs @@ -3,7 +3,6 @@ use crate::helpers::JsonResponse; use crate::models; use actix_web::{get, web, Responder, Result}; use sqlx::PgPool; -use tracing::Instrument; // workflow // add, update, list, get(user_id), ACL, diff --git a/src/routes/server/delete.rs b/src/routes/server/delete.rs index cd9a824..35440ec 100644 --- a/src/routes/server/delete.rs +++ b/src/routes/server/delete.rs @@ -3,7 +3,6 @@ use crate::models; use actix_web::{delete, web, Responder, Result}; use sqlx::PgPool; use std::sync::Arc; -use tracing::Instrument; use crate::db; use crate::models::Server; @@ -14,7 +13,7 @@ pub async fn item( path: web::Path<(i32,)>, pg_pool: web::Data, ) -> Result { - /// Get server apps of logged user only + // Get server apps of logged user only let (id,) = path.into_inner(); let server = db::server::fetch(pg_pool.get_ref(), id) diff --git a/src/routes/server/get.rs b/src/routes/server/get.rs index 23bac5b..de33e8f 100644 --- a/src/routes/server/get.rs +++ b/src/routes/server/get.rs @@ -4,7 +4,7 @@ use crate::helpers::JsonResponse; use crate::models; use actix_web::{get, web, Responder, Result}; use sqlx::PgPool; -use tracing::Instrument; +// use tracing::Instrument; // workflow // add, update, list, get(user_id), ACL, diff --git a/src/routes/server/mod.rs b/src/routes/server/mod.rs index af796d2..8ef07d3 100644 --- a/src/routes/server/mod.rs +++ b/src/routes/server/mod.rs @@ -3,7 +3,7 @@ pub(crate) mod get; pub(crate) mod delete; pub(crate) mod update; -pub use get::*; -pub use add::*; -pub use update::*; -pub use delete::*; +// pub use get::*; +// pub use add::*; +// pub use update::*; +// pub use delete::*; diff --git a/src/routes/server/update.rs b/src/routes/server/update.rs index 4f83d1e..2be6aca 100644 --- a/src/routes/server/update.rs +++ b/src/routes/server/update.rs @@ -2,11 +2,10 @@ use crate::forms; use crate::helpers::JsonResponse; use crate::models; use crate::db; -use actix_web::{web, web::Data, Responder, Result, post, put}; +use actix_web::{web, web::Data, Responder, Result, put}; use serde_valid::Validate; use sqlx::PgPool; use std::sync::Arc; -use tracing::Instrument; use std::ops::Deref; #[tracing::instrument(name = "Update server.")] From d68bc5efa552cfc76d1d36ffceccb269c5adfdc4 Mon Sep 17 00:00:00 2001 From: petru Date: Thu, 21 Mar 2024 17:23:19 +0200 Subject: [PATCH 224/284] 30-access-policies --- src/routes/rating/get.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/routes/rating/get.rs b/src/routes/rating/get.rs index 34ef6af..7071dcc 100644 --- a/src/routes/rating/get.rs +++ b/src/routes/rating/get.rs @@ -5,11 +5,6 @@ use actix_web::{get, web, Responder, Result}; use sqlx::PgPool; use tracing::Instrument; -// workflow -// add, update, list, get(user_id), ACL, -// ACL - access to func for a user -// ACL - access to objects for a user - #[tracing::instrument(name = "Get rating.")] #[get("/{id}")] pub async fn get_handler( From 2f0507df0d1ad4032bb175c2f72d06af09322262 Mon Sep 17 00:00:00 2001 From: vsilent Date: Fri, 22 Mar 2024 14:24:01 +0200 Subject: [PATCH 225/284] reconfigure rabbitmq queue --- src/console/commands/mq/listener.rs | 37 ++++++++++++++++++----------- src/forms/project/payload.rs | 3 ++- src/helpers/compressor.rs | 7 ------ src/helpers/dockerhub.rs | 2 ++ src/helpers/mq_manager.rs | 14 ++++------- src/routes/project/deploy.rs | 11 +++++++-- src/startup.rs | 1 + 7 files changed, 42 insertions(+), 33 deletions(-) diff --git a/src/console/commands/mq/listener.rs b/src/console/commands/mq/listener.rs index a9e6c04..3e67a9c 100644 --- a/src/console/commands/mq/listener.rs +++ b/src/console/commands/mq/listener.rs @@ -10,7 +10,6 @@ use crate::db; use crate::helpers::mq_manager::MqManager; use futures_lite::stream::StreamExt; use serde_derive::{Deserialize, Serialize}; -// use crate::forms::project::ProjectForm; pub struct ListenCommand { } @@ -44,10 +43,13 @@ impl crate::console::commands::CallableTrait for ListenCommand { println!("Declare exchange"); let mq_manager = MqManager::try_new(settings.amqp.connection_string())?; + // let queue_name = "stacker_listener"; + let queue_name = "install_progress_m383emvfP9zQKs8lkgSU_Q"; let consumer_channel= mq_manager .consume( "install_progress", - "install.progress.#" + queue_name, + "install.progress.*.*.*" ) .await?; @@ -55,7 +57,7 @@ impl crate::console::commands::CallableTrait for ListenCommand { println!("Declare queue"); let mut consumer = consumer_channel .basic_consume( - "#", + queue_name, "console_listener", BasicConsumeOptions::default(), FieldTable::default(), @@ -73,32 +75,39 @@ impl crate::console::commands::CallableTrait for ListenCommand { Err(e) => panic!("Invalid UTF-8 sequence: {}", e), }; - println!("incoming data {:?}", s); - let statuses = vec!["complete", "paused", "failed"]; + let statuses = vec![ + "completed", + "paused", + "failed", + "in_progress", + "error", + "wait_resume", + "wait_start", + "confirmed" + ]; match serde_json::from_str::(&s) { Ok(msg) => { println!("message {:?}", s); - // println!("id {:?}", msg.id); - // println!("status {:?}", msg.status); - if statuses.contains(&(msg.status.as_str())) { - println!("Process on complete status"); + if statuses.contains(&(msg.status.as_ref())) && msg.deploy_id.is_some() { + println!("Update DB on status change .."); let id = msg.deploy_id.unwrap() .parse::() - .map_err(|_err| "Could not parse deployment id".to_string() )?; + .map_err(|_err| "Could not parse deployment id".to_string())?; - match crate::db::deployment::fetch( + match deployment::fetch( db_pool.get_ref(), id ) .await? { - Some(mut row) => { row.status = msg.status; row.updated_at = Utc::now(); + println!("Deployment {} updated with status {}", + &id, &row.status + ); deployment::update(db_pool.get_ref(), row).await?; - println!("deployment {} completed successfully", id); } - None => println!("Deployment record not found in db") + None => println!("Deployment record was not found in db") } } } diff --git a/src/forms/project/payload.rs b/src/forms/project/payload.rs index bc8e8fb..d7e84d4 100644 --- a/src/forms/project/payload.rs +++ b/src/forms/project/payload.rs @@ -8,6 +8,7 @@ use serde_valid::Validate; #[serde(rename_all = "snake_case")] pub struct Payload { pub(crate) id: Option, + pub(crate) project_id: Option, pub(crate) user_token: Option, pub(crate) user_email: Option, #[serde(flatten)] @@ -30,7 +31,7 @@ impl TryFrom<&models::Project> for Payload { format!("{:?}", err) })?; - project_data.id = Some(project.id.clone()); + project_data.project_id = Some(project.id); Ok(project_data) } diff --git a/src/helpers/compressor.rs b/src/helpers/compressor.rs index 624747d..c6e1258 100644 --- a/src/helpers/compressor.rs +++ b/src/helpers/compressor.rs @@ -10,11 +10,4 @@ pub fn compress(input: &str) -> Vec { compressor.flush().unwrap(); drop(compressor); compressed -} - -pub fn decompress(input: &[u8]) -> String { - let mut decompressed = String::new(); - let mut decompressor = Decompressor::new(input, 4096); - decompressor.read_to_string(&mut decompressed).unwrap(); - decompressed } \ No newline at end of file diff --git a/src/helpers/dockerhub.rs b/src/helpers/dockerhub.rs index fa41df7..81f4feb 100644 --- a/src/helpers/dockerhub.rs +++ b/src/helpers/dockerhub.rs @@ -133,6 +133,7 @@ impl<'a> DockerHub<'a> { tracing::debug!("βœ… Image is active"); active } else { + tracing::debug!("πŸŸ₯ Image tag is not active"); false } }) @@ -169,6 +170,7 @@ impl<'a> DockerHub<'a> { tracing::debug!("βœ… Image is active"); active } else { + tracing::debug!("πŸŸ₯ Image tag is not active"); false } }) diff --git a/src/helpers/mq_manager.rs b/src/helpers/mq_manager.rs index f205f1a..dfcda23 100644 --- a/src/helpers/mq_manager.rs +++ b/src/helpers/mq_manager.rs @@ -102,11 +102,10 @@ impl MqManager { pub async fn consume( &self, exchange_name: &str, + queue_name: &str, routing_key: &str, ) -> Result { - let mut args = FieldTable::default(); - args.insert("x-expires".into(), AMQPValue::LongUInt(180000)); let channel = self.create_channel().await?; channel @@ -120,18 +119,16 @@ impl MqManager { internal: false, nowait: false, }, - args + FieldTable::default() ) .await .expect("Exchange declare failed"); let mut args = FieldTable::default(); - args.insert("x-expires".into(), AMQPValue::LongUInt(180000)); + args.insert("x-expires".into(), AMQPValue::LongUInt(3600000)); let queue = channel.queue_declare( - // "install_progress_all", - "#", - // "install_progress_hy181TZa4DaabUZWklsrxw", + queue_name, QueueDeclareOptions { passive: false, durable: false, @@ -139,7 +136,6 @@ impl MqManager { auto_delete: true, nowait: false, }, - // FieldTable::default(), args, ) .await @@ -147,7 +143,7 @@ impl MqManager { let _ = channel .queue_bind( - queue.name().as_str(), + queue_name, exchange_name, routing_key, QueueBindOptions::default(), diff --git a/src/routes/project/deploy.rs b/src/routes/project/deploy.rs index f3d242a..0fa7030 100644 --- a/src/routes/project/deploy.rs +++ b/src/routes/project/deploy.rs @@ -95,7 +95,11 @@ pub async fn item( let result = db::deployment::insert(pg_pool.get_ref(), deployment) .await - .map(|deployment| deployment) + .map(|deployment| { + payload.id = Some(deployment.id); + deployment + } + ) .map_err(|_| { JsonResponse::::build().internal_server_error("Internal Server Error") }); @@ -194,7 +198,10 @@ pub async fn saved_item( let result = db::deployment::insert(pg_pool.get_ref(), deployment) .await - .map(|deployment| deployment) + .map(|deployment| { + payload.id = Some(deployment.id); + deployment + }) .map_err(|_| { JsonResponse::::build().internal_server_error("Internal Server Error") }); diff --git a/src/startup.rs b/src/startup.rs index 2c7c4ba..29d0c9b 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -72,6 +72,7 @@ pub async fn run( )) .wrap(Cors::permissive()) .service(crate::routes::project::deploy::item) + .service(crate::routes::project::deploy::saved_item) .service(crate::routes::project::compose::add) .service(crate::routes::project::compose::admin) .service(crate::routes::project::get::item) From b1295b8df088bf5d52d895674e65fab6302fbbab Mon Sep 17 00:00:00 2001 From: vsilent Date: Fri, 22 Mar 2024 21:45:09 +0200 Subject: [PATCH 226/284] docker image tag validation fix --- src/console/commands/mq/listener.rs | 5 +++-- src/forms/project/form.rs | 12 ++++-------- src/routes/cloud/delete.rs | 2 +- src/routes/project/deploy.rs | 8 ++++++-- src/routes/project/update.rs | 2 +- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/console/commands/mq/listener.rs b/src/console/commands/mq/listener.rs index 3e67a9c..5d4b0c7 100644 --- a/src/console/commands/mq/listener.rs +++ b/src/console/commands/mq/listener.rs @@ -43,8 +43,9 @@ impl crate::console::commands::CallableTrait for ListenCommand { println!("Declare exchange"); let mq_manager = MqManager::try_new(settings.amqp.connection_string())?; - // let queue_name = "stacker_listener"; - let queue_name = "install_progress_m383emvfP9zQKs8lkgSU_Q"; + let queue_name = "stacker_listener"; + // let queue_name = "install_progress_m383emvfP9zQKs8lkgSU_Q"; + // let queue_name = "install_progress_hy181TZa4DaabUZWklsrxw"; let consumer_channel= mq_manager .consume( "install_progress", diff --git a/src/forms/project/form.rs b/src/forms/project/form.rs index 3924c6c..840bfaa 100644 --- a/src/forms/project/form.rs +++ b/src/forms/project/form.rs @@ -23,19 +23,16 @@ impl TryFrom<&models::Project> for ProjectForm { impl ProjectForm { pub async fn is_readable_docker_image(&self) -> Result { - let mut is_active = true; for app in &self.custom.web { if !app.app.docker_image.is_active().await? { - is_active = false; - break; + return Ok(false); } } if let Some(service) = &self.custom.service { for app in service { if !app.app.docker_image.is_active().await? { - is_active = false; - break; + return Ok(false); } } } @@ -43,12 +40,11 @@ impl ProjectForm { if let Some(features) = &self.custom.feature { for app in features { if !app.app.docker_image.is_active().await? { - is_active = false; - break; + return Ok(false); } } } - Ok(is_active) + Ok(true) } } diff --git a/src/routes/cloud/delete.rs b/src/routes/cloud/delete.rs index 94188c7..2654bde 100644 --- a/src/routes/cloud/delete.rs +++ b/src/routes/cloud/delete.rs @@ -27,7 +27,7 @@ pub async fn item( Some(cloud) => { Ok(cloud) }, - None => Err(JsonResponse::::build().not_found("")) + None => Err(JsonResponse::::build().not_found("not found")) } })?; diff --git a/src/routes/project/deploy.rs b/src/routes/project/deploy.rs index 0fa7030..7cdbb43 100644 --- a/src/routes/project/deploy.rs +++ b/src/routes/project/deploy.rs @@ -137,6 +137,7 @@ pub async fn saved_item( //let cloud_id = Some(1); tracing::debug!("User {:?} is deploying project: {} to cloud: {} ", user, id, cloud_id); + // Validate project let project = db::project::fetch(pg_pool.get_ref(), id) .await .map_err(|err| JsonResponse::::build().internal_server_error(err)) @@ -145,7 +146,8 @@ pub async fn saved_item( None => Err(JsonResponse::::build().not_found("Project not found")), })?; - let id = project.id.clone(); + // Build compose + let id = project.id; let dc = DcBuilder::new(project); let fc = dc.build().map_err(|err| { JsonResponse::::build().internal_server_error(err) @@ -181,6 +183,7 @@ pub async fn saved_item( // let mut payload = forms::project::Payload::default(); let mut payload = forms::project::Payload::try_from(&dc.project) .map_err(|err| JsonResponse::::build().bad_request(err))?; + payload.server = Some(server.into()); payload.cloud = Some(cloud.into()); payload.user_token = Some(user.id.clone()); @@ -188,7 +191,7 @@ pub async fn saved_item( // let compressed = fc.unwrap_or("".to_string()); payload.docker_compose = Some(compress(fc.as_str())); - + // Store deployment attempts into deployment table in db let json_request = dc.project.body.clone(); let deployment = models::Deployment::new( dc.project.id, @@ -209,6 +212,7 @@ pub async fn saved_item( tracing::debug!("Save deployment result: {:?}", result); tracing::debug!("Send project data <<<<<<<<<<<>>>>>>>>>>>>>>>>{:?}", payload); + // Send Payload mq_manager .publish( "install".to_string(), diff --git a/src/routes/project/update.rs b/src/routes/project/update.rs index 4fc8568..9bddfb9 100644 --- a/src/routes/project/update.rs +++ b/src/routes/project/update.rs @@ -47,7 +47,7 @@ pub async fn item( let project_name = form.custom.custom_stack_code.clone(); - if !form.is_readable_docker_image().await.is_ok() { + if Ok(false) == form.is_readable_docker_image().await { return Err(JsonResponse::::build().bad_request("Can not access docker image")); } From 70cbfafe4a03cde5f53937b1306af52bf9b5e7ee Mon Sep 17 00:00:00 2001 From: petru Date: Fri, 22 Mar 2024 22:34:40 +0200 Subject: [PATCH 227/284] 30-access-policies --- src/forms/project/form.rs | 23 ----------------------- src/routes/project/add.rs | 28 ++++++++++++++++++++-------- src/routes/project/update.rs | 2 ++ src/startup.rs | 4 ++-- 4 files changed, 24 insertions(+), 33 deletions(-) diff --git a/src/forms/project/form.rs b/src/forms/project/form.rs index d2498cf..7d3a3a6 100644 --- a/src/forms/project/form.rs +++ b/src/forms/project/form.rs @@ -52,26 +52,3 @@ impl ProjectForm { Ok(is_active) } } - -pub(crate) async fn body_into_form(body: Bytes) -> actix_web::Result { - let body_bytes = actix_web::body::to_bytes(body).await.unwrap(); - let body_str = str::from_utf8(&body_bytes) - .map_err(|err| JsonResponse::::build().internal_server_error(err.to_string()))?; - let deserializer = &mut serde_json::Deserializer::from_str(body_str); - serde_path_to_error::deserialize(deserializer) - .map_err(|err| { - let msg = format!("{}:{:?}", err.path().to_string(), err); - JsonResponse::::build().bad_request(msg) - }) - .and_then(|mut form: forms::project::ProjectForm| { - if !form.validate().is_ok() { - let errors = form.validate().unwrap_err().to_string(); - let err_msg = format!("Invalid data received {:?}", &errors); - tracing::debug!(err_msg); - - return Err(JsonResponse::::build().form_error(errors)); - } - - Ok(form) - }) -} diff --git a/src/routes/project/add.rs b/src/routes/project/add.rs index e1b84bc..ee8c67f 100644 --- a/src/routes/project/add.rs +++ b/src/routes/project/add.rs @@ -12,24 +12,37 @@ use sqlx::PgPool; use std::sync::Arc; use std::str::FromStr; use std::str; +use serde_valid::Validate; #[tracing::instrument(name = "Add project.")] #[post("")] pub async fn item( - body: Bytes, + request_json: web::Json, user: web::ReqData>, pg_pool: Data, ) -> Result { // @todo ACL - let form = forms::project::form::body_into_form(body.clone()).await?; + let request_json = request_json.into_inner(); //todo + let form = serde_json::from_value(request_json.clone()) + .map_err(|err| { + let msg = format!("{}", err); //todo JsonReponse::BadRequest::from(err) + JsonResponse::::build().bad_request(msg) + }) + .and_then(|mut form: forms::project::ProjectForm| { + if !form.validate().is_ok() { + let errors = form.validate().unwrap_err().to_string(); + let err_msg = format!("Invalid data received {:?}", &errors); + tracing::debug!(err_msg); + + return Err(JsonResponse::::build().form_error(errors)); + } + + Ok(form) + })?; + let project_name = form.custom.custom_stack_code.clone(); - let body_bytes = actix_web::body::to_bytes(body).await.unwrap(); - let body_str = str::from_utf8(&body_bytes) - .map_err(|err| JsonResponse::::build().internal_server_error(err.to_string()))?; - let request_json = Value::from_str(body_str).unwrap(); tracing::debug!("Request json: {:?}", request_json); - let body: Value = serde_json::to_value::(form) .or(serde_json::to_value::(forms::project::ProjectForm::default())) .unwrap(); @@ -48,4 +61,3 @@ pub async fn item( JsonResponse::::build().internal_server_error("Internal Server Error") }) } - diff --git a/src/routes/project/update.rs b/src/routes/project/update.rs index ecd72b1..bfd82b6 100644 --- a/src/routes/project/update.rs +++ b/src/routes/project/update.rs @@ -12,6 +12,7 @@ use actix_web::web::Bytes; use tracing::Instrument; use std::str; +/* #[tracing::instrument(name = "Update project.")] #[put("/{id}")] pub async fn item( @@ -74,3 +75,4 @@ pub async fn item( JsonResponse::::build().internal_server_error("") }) } +*/ diff --git a/src/startup.rs b/src/startup.rs index 72d66c6..9c31afd 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -31,7 +31,7 @@ pub async fn run( let authorization = middleware::authorization::try_new(settings.database.connection_string()).await?; let json_config = web::JsonConfig::default() - .error_handler(|err, req| { + .error_handler(|err, req| { //todo let msg: String = match err { error::JsonPayloadError::Deserialize(err) => format!("{{\"kind\":\"deserialize\",\"line\":{}, \"column\":{}, \"msg\":\"{}\"}}", err.line(), err.column(), err), _ => format!("{{\"kind\":\"other\",\"msg\":\"{}\"}}", err) @@ -78,7 +78,7 @@ pub async fn run( .service(crate::routes::project::get::item) .service(crate::routes::project::get::list) .service(crate::routes::project::add::item) - .service(crate::routes::project::update::item) + //.service(crate::routes::project::update::item) todo .service(crate::routes::project::delete::item), ) .service( From db44167062993dad3840d0f8eb504385b22afe34 Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 23 Mar 2024 16:24:43 +0200 Subject: [PATCH 228/284] 30-access-policies project add --- src/helpers/json.rs | 22 +++++++++++++++------- src/routes/project/add.rs | 29 +++++++---------------------- 2 files changed, 22 insertions(+), 29 deletions(-) diff --git a/src/helpers/json.rs b/src/helpers/json.rs index ee209c1..ac77cbe 100644 --- a/src/helpers/json.rs +++ b/src/helpers/json.rs @@ -1,7 +1,9 @@ use actix_web::error::{ErrorBadRequest, ErrorConflict, ErrorInternalServerError, ErrorNotFound, ErrorUnauthorized}; use actix_web::web::Json; -use actix_web::Error; +use actix_web::Error as ActixError; use serde_derive::Serialize; +use std::error::Error as StdError; +use std::convert::From; #[derive(Serialize)] pub(crate) struct JsonResponse { @@ -70,33 +72,33 @@ where pub(crate) fn bad_request>( self, msg: I, - ) -> Error { + ) -> ActixError { ErrorBadRequest(self.set_msg(msg).to_string()) } - pub(crate) fn form_error(self, msg: String) -> Error { + pub(crate) fn form_error(self, msg: String) -> ActixError { ErrorBadRequest(msg) } - pub(crate) fn not_found>(self, msg: I) -> Error { + pub(crate) fn not_found>(self, msg: I) -> ActixError { ErrorNotFound(self.set_msg(msg).to_string()) } pub(crate) fn internal_server_error>( self, msg: I, - ) -> Error { + ) -> ActixError { ErrorInternalServerError(self.set_msg(msg).to_string()) } pub(crate) fn unauthorized>( self, msg: I, - ) -> Error { + ) -> ActixError { ErrorUnauthorized(self.set_msg(msg).to_string()) } - pub(crate) fn conflict>(self, msg: I) -> Error { + pub(crate) fn conflict>(self, msg: I) -> ActixError { ErrorConflict(self.set_msg(msg).to_string()) } } @@ -109,3 +111,9 @@ where JsonResponseBuilder::default() } } + +impl JsonResponse { + pub fn err_bad_request(e: E) -> ActixError { + JsonResponse::::build().bad_request( e.to_string()) + } +} diff --git a/src/routes/project/add.rs b/src/routes/project/add.rs index ee8c67f..892d31a 100644 --- a/src/routes/project/add.rs +++ b/src/routes/project/add.rs @@ -10,39 +10,24 @@ use actix_web::{ use serde_json::Value; use sqlx::PgPool; use std::sync::Arc; -use std::str::FromStr; -use std::str; use serde_valid::Validate; #[tracing::instrument(name = "Add project.")] #[post("")] pub async fn item( - request_json: web::Json, + web::Json(request_json): web::Json, user: web::ReqData>, pg_pool: Data, ) -> Result { // @todo ACL - let request_json = request_json.into_inner(); //todo - let form = serde_json::from_value(request_json.clone()) - .map_err(|err| { - let msg = format!("{}", err); //todo JsonReponse::BadRequest::from(err) - JsonResponse::::build().bad_request(msg) - }) - .and_then(|mut form: forms::project::ProjectForm| { - if !form.validate().is_ok() { - let errors = form.validate().unwrap_err().to_string(); - let err_msg = format!("Invalid data received {:?}", &errors); - tracing::debug!(err_msg); - - return Err(JsonResponse::::build().form_error(errors)); - } - - Ok(form) - })?; + let form: forms::project::ProjectForm= serde_json::from_value(request_json.clone()) + .map_err(JsonResponse::err_bad_request)?; + if !form.validate().is_ok() { + let errors = form.validate().unwrap_err(); + return Err(JsonResponse::err_bad_request(errors)); + } let project_name = form.custom.custom_stack_code.clone(); - - tracing::debug!("Request json: {:?}", request_json); let body: Value = serde_json::to_value::(form) .or(serde_json::to_value::(forms::project::ProjectForm::default())) .unwrap(); From 63888bd8e4060b8bdb6843ecc003d2045ee2606b Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 23 Mar 2024 16:34:50 +0200 Subject: [PATCH 229/284] 30-access-policies POST /project --- src/routes/project/add.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/routes/project/add.rs b/src/routes/project/add.rs index 892d31a..0c17066 100644 --- a/src/routes/project/add.rs +++ b/src/routes/project/add.rs @@ -1,10 +1,10 @@ use crate::db; -use crate::forms; +use crate::forms::project::ProjectForm; use crate::helpers::JsonResponse; use crate::models; use actix_web::{ post, web, - web::{Bytes, Data}, + web::{Data}, Responder, Result, }; use serde_json::Value; @@ -20,7 +20,7 @@ pub async fn item( pg_pool: Data, ) -> Result { // @todo ACL - let form: forms::project::ProjectForm= serde_json::from_value(request_json.clone()) + let form: ProjectForm= serde_json::from_value(request_json.clone()) .map_err(JsonResponse::err_bad_request)?; if !form.validate().is_ok() { let errors = form.validate().unwrap_err(); @@ -28,8 +28,8 @@ pub async fn item( } let project_name = form.custom.custom_stack_code.clone(); - let body: Value = serde_json::to_value::(form) - .or(serde_json::to_value::(forms::project::ProjectForm::default())) + let body: Value = serde_json::to_value::(form) + .or(serde_json::to_value::(ProjectForm::default())) .unwrap(); let project = models::Project::new( From 1637f6f0b5e623a024bc75d01c62645238425285 Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 23 Mar 2024 21:11:07 +0200 Subject: [PATCH 230/284] 30-access-policies POST/PUT /project --- src/helpers/json.rs | 27 +++++++++++++--------- src/routes/project/add.rs | 6 ++--- src/routes/project/update.rs | 43 ++++++++++++++---------------------- src/startup.rs | 2 +- 4 files changed, 37 insertions(+), 41 deletions(-) diff --git a/src/helpers/json.rs b/src/helpers/json.rs index ac77cbe..36f8d39 100644 --- a/src/helpers/json.rs +++ b/src/helpers/json.rs @@ -1,8 +1,7 @@ use actix_web::error::{ErrorBadRequest, ErrorConflict, ErrorInternalServerError, ErrorNotFound, ErrorUnauthorized}; use actix_web::web::Json; -use actix_web::Error as ActixError; +use actix_web::Error; use serde_derive::Serialize; -use std::error::Error as StdError; use std::convert::From; #[derive(Serialize)] @@ -72,33 +71,33 @@ where pub(crate) fn bad_request>( self, msg: I, - ) -> ActixError { + ) -> Error { ErrorBadRequest(self.set_msg(msg).to_string()) } - pub(crate) fn form_error(self, msg: String) -> ActixError { + pub(crate) fn form_error(self, msg: String) -> Error { ErrorBadRequest(msg) } - pub(crate) fn not_found>(self, msg: I) -> ActixError { + pub(crate) fn not_found>(self, msg: I) -> Error { ErrorNotFound(self.set_msg(msg).to_string()) } pub(crate) fn internal_server_error>( self, msg: I, - ) -> ActixError { + ) -> Error { ErrorInternalServerError(self.set_msg(msg).to_string()) } pub(crate) fn unauthorized>( self, msg: I, - ) -> ActixError { + ) -> Error { ErrorUnauthorized(self.set_msg(msg).to_string()) } - pub(crate) fn conflict>(self, msg: I) -> ActixError { + pub(crate) fn conflict>(self, msg: I) -> Error { ErrorConflict(self.set_msg(msg).to_string()) } } @@ -113,7 +112,15 @@ where } impl JsonResponse { - pub fn err_bad_request(e: E) -> ActixError { - JsonResponse::::build().bad_request( e.to_string()) + pub fn bad_request>(msg: I) -> Error { + JsonResponse::::build().bad_request( msg.into()) + } + + pub fn internal_server_error>(msg: I) -> Error { + JsonResponse::::build().internal_server_error( msg.into()) + } + + pub fn not_found>(msg: I) -> Error { + JsonResponse::::build().not_found(msg.into()) } } diff --git a/src/routes/project/add.rs b/src/routes/project/add.rs index 0c17066..683e1d3 100644 --- a/src/routes/project/add.rs +++ b/src/routes/project/add.rs @@ -21,10 +21,10 @@ pub async fn item( ) -> Result { // @todo ACL let form: ProjectForm= serde_json::from_value(request_json.clone()) - .map_err(JsonResponse::err_bad_request)?; + .map_err(|err| JsonResponse::bad_request(err.to_string()))?; if !form.validate().is_ok() { let errors = form.validate().unwrap_err(); - return Err(JsonResponse::err_bad_request(errors)); + return Err(JsonResponse::bad_request(errors.to_string())); } let project_name = form.custom.custom_stack_code.clone(); @@ -43,6 +43,6 @@ pub async fn item( .await .map(|project| JsonResponse::build().set_item(project).ok("Ok")) .map_err(|_| { - JsonResponse::::build().internal_server_error("Internal Server Error") + JsonResponse::internal_server_error("Internal Server Error") }) } diff --git a/src/routes/project/update.rs b/src/routes/project/update.rs index bfd82b6..312c422 100644 --- a/src/routes/project/update.rs +++ b/src/routes/project/update.rs @@ -1,60 +1,51 @@ use std::str::FromStr; -use crate::forms; +use crate::forms::project::ProjectForm; use crate::helpers::JsonResponse; use crate::models; use crate::db; -use actix_web::{web, web::Data, Responder, Result, put}; +use actix_web::{web, Responder, Result, put}; use serde_json::Value; use serde_valid::Validate; use sqlx::PgPool; use std::sync::Arc; -use actix_web::web::Bytes; use tracing::Instrument; use std::str; -/* #[tracing::instrument(name = "Update project.")] #[put("/{id}")] pub async fn item( path: web::Path<(i32,)>, - body: Bytes, + web::Json(request_json): web::Json, user: web::ReqData>, - pg_pool: Data, + pg_pool: web::Data, ) -> Result { let id = path.0; let mut project = db::project::fetch(pg_pool.get_ref(), id) .await - .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .map_err(JsonResponse::internal_server_error) .and_then(|project| match project { Some(project) if project.user_id != user.id => { - Err(JsonResponse::::build().bad_request("Project not found")) + Err(JsonResponse::bad_request("Project not found")) } Some(project) => Ok(project), - None => Err(JsonResponse::::build().not_found("Project not found")), + None => Err(JsonResponse::not_found("Project not found")), })?; - let body_bytes = actix_web::body::to_bytes(body.clone()).await.unwrap(); - let body_str = str::from_utf8(&body_bytes) - .map_err(|err| JsonResponse::::build().internal_server_error(err.to_string()))?; - let request_json = Value::from_str(body_str)?; - tracing::debug!("Request json: {:?}", request_json); - // @todo ACL - let form = forms::project::form::body_into_form(body.clone()).await?; - tracing::debug!("form data: {:?}", form); - - if let Err(errors) = form.validate() { - return Err(JsonResponse::::build().form_error(errors.to_string())); + let form: ProjectForm= serde_json::from_value(request_json.clone()) + .map_err(|err| JsonResponse::bad_request(err.to_string()))?; + if !form.validate().is_ok() { + let errors = form.validate().unwrap_err(); + return Err(JsonResponse::bad_request(errors.to_string())); } let project_name = form.custom.custom_stack_code.clone(); - if !form.is_readable_docker_image().await.is_ok() { - return Err(JsonResponse::::build().bad_request("Can not access docker image")); + return Err(JsonResponse::bad_request("Can not access docker image")); } - let body: Value = serde_json::to_value::(form) - .or(serde_json::to_value::(forms::project::ProjectForm::default())) + let body: Value = serde_json::to_value::(form) + .or(serde_json::to_value::(ProjectForm::default())) .unwrap(); @@ -62,7 +53,6 @@ pub async fn item( project.body = body; project.request_json = request_json; - db::project::update(pg_pool.get_ref(), project) .await .map(|project| { @@ -72,7 +62,6 @@ pub async fn item( }) .map_err(|err| { tracing::error!("Failed to execute query: {:?}", err); - JsonResponse::::build().internal_server_error("") + JsonResponse::internal_server_error("") }) } -*/ diff --git a/src/startup.rs b/src/startup.rs index 9c31afd..35ee007 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -78,7 +78,7 @@ pub async fn run( .service(crate::routes::project::get::item) .service(crate::routes::project::get::list) .service(crate::routes::project::add::item) - //.service(crate::routes::project::update::item) todo + .service(crate::routes::project::update::item) .service(crate::routes::project::delete::item), ) .service( From 304f54be296624b7f2d1c0ea3f08515885bfd42b Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 23 Mar 2024 21:34:44 +0200 Subject: [PATCH 231/284] 30-access-policies admin get project --- src/routes/project/get.rs | 11 +++++------ src/startup.rs | 8 +++++++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/routes/project/get.rs b/src/routes/project/get.rs index 3cd7fc3..7544a79 100644 --- a/src/routes/project/get.rs +++ b/src/routes/project/get.rs @@ -13,18 +13,17 @@ pub async fn item( path: web::Path<(i32,)>, pg_pool: web::Data, ) -> Result { - /// Get project apps of logged user only - let (id,) = path.into_inner(); + let id = path.0; db::project::fetch(pg_pool.get_ref(), id) .await - .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .map_err(|err| JsonResponse::internal_server_error(err.to_string())) .and_then(|project| match project { Some(project) if project.user_id != user.id => { - Err(JsonResponse::::build().not_found("not found")) + Err(JsonResponse::not_found("not found")) } Some(project) => Ok(JsonResponse::build().set_item(Some(project)).ok("OK")), - None => Err(JsonResponse::::build().not_found("not found")), + None => Err(JsonResponse::not_found("not found")), }) } @@ -42,6 +41,6 @@ pub async fn list( db::project::fetch_by_user(pg_pool.get_ref(), &user_id) .await - .map_err(|err| JsonResponse::::build().internal_server_error(err)) + .map_err(|err| JsonResponse::internal_server_error(err)) .map(|projects| JsonResponse::build().set_list(projects).ok("OK")) } diff --git a/src/startup.rs b/src/startup.rs index 35ee007..b0d788b 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -76,11 +76,17 @@ pub async fn run( .service(crate::routes::project::compose::add) .service(crate::routes::project::compose::admin) .service(crate::routes::project::get::item) - .service(crate::routes::project::get::list) .service(crate::routes::project::add::item) .service(crate::routes::project::update::item) .service(crate::routes::project::delete::item), ) + .service( + web::scope("/admin") + .service( + web::scope("/project") + .service(crate::routes::project::get::list) + ) + ) .service( web::scope("/cloud") .service(crate::routes::cloud::get::item) From c00e09356b57aceef8c3a5f44f8e11fd19b23502 Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 23 Mar 2024 21:38:48 +0200 Subject: [PATCH 232/284] 30-access-policies admin routes grouped --- src/routes/project/get.rs | 2 +- src/startup.rs | 20 +++++++------------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/routes/project/get.rs b/src/routes/project/get.rs index 7544a79..7c0ca55 100644 --- a/src/routes/project/get.rs +++ b/src/routes/project/get.rs @@ -29,7 +29,7 @@ pub async fn item( #[tracing::instrument(name = "Get user's project list.")] #[get("/user/{id}")] -pub async fn list( +pub async fn admin_list( user: web::ReqData>, path: web::Path<(String,)>, pg_pool: web::Data, diff --git a/src/startup.rs b/src/startup.rs index b0d788b..56a317f 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -54,12 +54,6 @@ pub async fn run( .service(routes::client::enable_handler) .service(routes::client::disable_handler), ) - .service( - web::scope("/admin/client") - .service(routes::client::admin_enable_handler) - .service(routes::client::admin_update_handler) - .service(routes::client::admin_disable_handler), - ) .service( web::scope("/test") .service(routes::test::deploy::handler) @@ -84,7 +78,13 @@ pub async fn run( web::scope("/admin") .service( web::scope("/project") - .service(crate::routes::project::get::list) + .service(crate::routes::project::get::admin_list) + ) + .service( + web::scope("/client") + .service(routes::client::admin_enable_handler) + .service(routes::client::admin_update_handler) + .service(routes::client::admin_disable_handler), ) ) .service( @@ -103,12 +103,6 @@ pub async fn run( .service(crate::routes::server::update::item) .service(crate::routes::server::delete::item), ) - // @todo stack renamed to project - // .service( - // web::scope("/admin/project") - // .service(routes::project::get::admin_item) - // .service(routes::project::get::admin_list) - // ) .app_data(json_config.clone()) .app_data(pg_pool.clone()) .app_data(mq_manager.clone()) From a720a0339193622941452534a1e5c4ffd6758475 Mon Sep 17 00:00:00 2001 From: petru Date: Tue, 26 Mar 2024 23:07:45 +0200 Subject: [PATCH 233/284] casbin-debug command --- src/console/commands/debug/casbin.rs | 21 +++++++++++++++++++++ src/console/commands/debug/mod.rs | 2 ++ src/console/main.rs | 11 +++++++++++ 3 files changed, 34 insertions(+) create mode 100644 src/console/commands/debug/casbin.rs diff --git a/src/console/commands/debug/casbin.rs b/src/console/commands/debug/casbin.rs new file mode 100644 index 0000000..4662c0f --- /dev/null +++ b/src/console/commands/debug/casbin.rs @@ -0,0 +1,21 @@ +use crate::configuration::get_configuration; +use actix_web::{rt, post, web, HttpResponse, Result, http::header::ContentType}; + +pub struct CasbinCommand { + action: String, + method: String, + subject: String +} + +impl CasbinCommand { + pub fn new(action: String, method: String, subject: String) -> Self { + Self { action, method, subject } + } +} + +impl crate::console::commands::CallableTrait for CasbinCommand { + fn call(&self) -> Result<(), Box> { + println!("action: {}, method: {}, subject: {}", self.action, self.method, self.subject); + Ok(()) + } +} diff --git a/src/console/commands/debug/mod.rs b/src/console/commands/debug/mod.rs index 5f50076..4886274 100644 --- a/src/console/commands/debug/mod.rs +++ b/src/console/commands/debug/mod.rs @@ -1,3 +1,5 @@ mod json; +mod casbin; pub use json::*; +pub use casbin::*; diff --git a/src/console/main.rs b/src/console/main.rs index 257205a..8521d04 100644 --- a/src/console/main.rs +++ b/src/console/main.rs @@ -40,6 +40,14 @@ enum DebugCommands { #[arg(long)] payload: String, }, + Casbin { + #[arg(long)] + action: String, + #[arg(long)] + method: String, + #[arg(long)] + subject: String, + }, } #[derive(Debug, Subcommand)] @@ -65,6 +73,9 @@ fn get_command(cli: Cli) -> Result Ok(Box::new( stacker::console::commands::debug::JsonCommand::new(line, column, payload), )), + DebugCommands::Casbin { action, method, subject } => Ok(Box::new( + stacker::console::commands::debug::CasbinCommand::new(action, method, subject), + )), }, Commands::MQ { command} => match command { AppMqCommands::Listen {} => Ok(Box::new( From ba205923c665d2731670a723612f740be9a218eb Mon Sep 17 00:00:00 2001 From: petru Date: Tue, 26 Mar 2024 23:34:31 +0200 Subject: [PATCH 234/284] casbin-debug casbin main logic --- src/console/commands/debug/casbin.rs | 34 ++++++++++++++++++++++++---- src/console/main.rs | 6 ++--- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/console/commands/debug/casbin.rs b/src/console/commands/debug/casbin.rs index 4662c0f..6484cca 100644 --- a/src/console/commands/debug/casbin.rs +++ b/src/console/commands/debug/casbin.rs @@ -1,21 +1,45 @@ use crate::configuration::get_configuration; use actix_web::{rt, post, web, HttpResponse, Result, http::header::ContentType}; +use crate::middleware; +use actix_casbin_auth::casbin::CoreApi; +use sqlx::PgPool; pub struct CasbinCommand { action: String, - method: String, + path: String, subject: String } impl CasbinCommand { - pub fn new(action: String, method: String, subject: String) -> Self { - Self { action, method, subject } + pub fn new(action: String, path: String, subject: String) -> Self { + Self { action, path, subject } } } impl crate::console::commands::CallableTrait for CasbinCommand { fn call(&self) -> Result<(), Box> { - println!("action: {}, method: {}, subject: {}", self.action, self.method, self.subject); - Ok(()) + rt::System::new().block_on(async { + let settings = get_configuration().expect("Failed to read configuration."); + let db_pool = PgPool::connect(&settings.database.connection_string()) + .await + .expect("Failed to connect to database."); + + let settings = web::Data::new(settings); + let db_pool = web::Data::new(db_pool); + + let mut authorizationService = middleware::authorization::try_new(settings.database.connection_string()).await?; + let casbin_enforcer = authorizationService.get_enforcer(); + let mut lock = casbin_enforcer.write().await; + match lock.enforce_mut(vec![self.subject.clone(), self.path.clone(), self.action.clone()]) { + Ok(true) => println!("TRUE"), + Ok(false) => println!("FALSE"), + Err(err) => { + println!("err {err:?}"); + } + } + drop(lock); + + Ok(()) + }) } } diff --git a/src/console/main.rs b/src/console/main.rs index 8521d04..f339b30 100644 --- a/src/console/main.rs +++ b/src/console/main.rs @@ -44,7 +44,7 @@ enum DebugCommands { #[arg(long)] action: String, #[arg(long)] - method: String, + path: String, #[arg(long)] subject: String, }, @@ -73,8 +73,8 @@ fn get_command(cli: Cli) -> Result Ok(Box::new( stacker::console::commands::debug::JsonCommand::new(line, column, payload), )), - DebugCommands::Casbin { action, method, subject } => Ok(Box::new( - stacker::console::commands::debug::CasbinCommand::new(action, method, subject), + DebugCommands::Casbin { action, path, subject } => Ok(Box::new( + stacker::console::commands::debug::CasbinCommand::new(action, path, subject), )), }, Commands::MQ { command} => match command { From 7dde11789943add5d8d7b8aca2f9fd3f8657eff7 Mon Sep 17 00:00:00 2001 From: vsilent Date: Wed, 27 Mar 2024 12:31:17 +0200 Subject: [PATCH 235/284] security for db records, initial steps, key is hardcoded for testing purposes --- .env | 3 +- Cargo.lock | 640 +++++++++++------- Cargo.toml | 3 + docker-compose.yml | 22 + docker/dev/.env | 5 +- docker/dev/docker-compose.yml | 23 + src/forms/cloud.rs | 124 +++- src/helpers/cloud/mod.rs | 2 + src/helpers/cloud/security.rs | 135 ++++ src/helpers/mod.rs | 3 + .../authentication/method/f_oauth.rs | 11 +- src/models/cloud.rs | 35 + src/routes/cloud/add.rs | 12 +- src/routes/cloud/get.rs | 25 +- src/routes/cloud/update.rs | 2 + src/routes/project/compose.rs | 2 +- src/routes/server/get.rs | 13 +- src/routes/server/update.rs | 2 - src/startup.rs | 5 +- tests/mock_data/cloud.json | 3 +- 20 files changed, 777 insertions(+), 293 deletions(-) create mode 100644 src/helpers/cloud/mod.rs create mode 100644 src/helpers/cloud/security.rs diff --git a/.env b/.env index 14bdc64..1dcbed0 100644 --- a/.env +++ b/.env @@ -4,4 +4,5 @@ DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/stacker POSTGRES_USER=postgres POSTGRES_PASSWORD=postgres POSTGRES_DB=stacker -POSTGRES_PORT=5432 \ No newline at end of file +POSTGRES_PORT=5432 +SECURITY_KEY=SECURITY_KEY_SHOULD_BE_OF_LEN_32 diff --git a/Cargo.lock b/Cargo.lock index f04999e..b5d6160 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,7 +5,7 @@ version = 3 [[package]] name = "actix-casbin-auth" version = "0.4.4" -source = "git+https://github.com/smart--petea/actix-casbin-auth.git?branch=dirty-master#5b76cc4e0df68ccee02c563b947a788ab1cb5193" +source = "git+https://github.com/smart--petea/actix-casbin-auth.git?branch=dirty-master#278bd574038617171a6493aef3d4d4fdef324602" dependencies = [ "actix-service", "actix-web", @@ -20,7 +20,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "bytes", "futures-core", "futures-sink", @@ -56,9 +56,9 @@ dependencies = [ "actix-rt", "actix-service", "actix-utils", - "ahash 0.8.10", + "ahash 0.8.11", "base64 0.21.7", - "bitflags 2.4.2", + "bitflags 2.5.0", "brotli", "bytes", "bytestring", @@ -92,7 +92,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.51", + "syn 2.0.55", ] [[package]] @@ -171,7 +171,7 @@ dependencies = [ "actix-service", "actix-utils", "actix-web-codegen", - "ahash 0.8.10", + "ahash 0.8.11", "bytes", "bytestring", "cfg-if", @@ -205,7 +205,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.55", ] [[package]] @@ -223,6 +223,41 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + [[package]] name = "ahash" version = "0.7.8" @@ -236,9 +271,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b79b82693f705137f8fb9b37871d99e4f9a7df12b917eed79c3d3954830a60b" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "const-random", @@ -250,9 +285,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -391,9 +426,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" [[package]] name = "assert-json-diff" @@ -423,7 +458,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3" dependencies = [ "concurrent-queue", - "event-listener 5.1.0", + "event-listener 5.2.0", "event-listener-strategy 0.5.0", "futures-core", "pin-project-lite", @@ -438,8 +473,8 @@ dependencies = [ "async-lock 3.3.0", "async-task", "concurrent-queue", - "fastrand 2.0.1", - "futures-lite 2.2.0", + "fastrand 2.0.2", + "futures-lite 2.3.0", "slab", ] @@ -451,10 +486,10 @@ checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ "async-channel 2.2.0", "async-executor", - "async-io 2.3.1", + "async-io 2.3.2", "async-lock 3.3.0", "blocking", - "futures-lite 2.2.0", + "futures-lite 2.3.0", "once_cell", ] @@ -491,18 +526,18 @@ dependencies = [ [[package]] name = "async-io" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f97ab0c5b00a7cdbe5a371b9a782ee7be1316095885c8a4ea1daf490eb0ef65" +checksum = "dcccb0f599cfa2f8ace422d3555572f47424da5648a4382a9dd0310ff8210884" dependencies = [ "async-lock 3.3.0", "cfg-if", "concurrent-queue", "futures-io", - "futures-lite 2.2.0", + "futures-lite 2.3.0", "parking", - "polling 3.5.0", - "rustix 0.38.31", + "polling 3.6.0", + "rustix 0.38.32", "slab", "tracing", "windows-sys 0.52.0", @@ -548,13 +583,13 @@ checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799" [[package]] name = "async-trait" -version = "0.1.77" +version = "0.1.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.55", ] [[package]] @@ -581,27 +616,17 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" -[[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 = "autocfg" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", @@ -624,6 +649,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" + [[package]] name = "bitflags" version = "1.3.2" @@ -632,9 +663,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "block-buffer" @@ -663,18 +694,18 @@ dependencies = [ "async-channel 2.2.0", "async-lock 3.3.0", "async-task", - "fastrand 2.0.1", + "fastrand 2.0.2", "futures-io", - "futures-lite 2.2.0", + "futures-lite 2.3.0", "piper", "tracing", ] [[package]] name = "brotli" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "516074a47ef4bce09577a3b379392300159ce5b1ba2e501ff1c819950066100f" +checksum = "d640d25bc63c50fb1f0b545ffd80207d2e10a4c965530809b40ba3386825c391" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -693,9 +724,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.15.3" +version = "3.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b" +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" [[package]] name = "bytecount" @@ -711,9 +742,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "bytestring" @@ -735,9 +766,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" dependencies = [ "serde", ] @@ -787,10 +818,11 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.88" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" dependencies = [ + "jobserver", "libc", ] @@ -828,9 +860,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.1" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", "clap_derive", @@ -838,9 +870,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.1" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ "anstream", "anstyle", @@ -850,14 +882,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.0" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ - "heck", + "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.55", ] [[package]] @@ -872,6 +904,20 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "combine" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +dependencies = [ + "bytes", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", +] + [[package]] name = "concurrent-queue" version = "2.4.0" @@ -902,9 +948,9 @@ dependencies = [ [[package]] name = "const-random" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaf16c9c2c612020bcfd042e170f6e32de9b9d75adb5277cdbbd2e2c8c8299a" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" dependencies = [ "const-random-macro", ] @@ -939,9 +985,12 @@ dependencies = [ [[package]] name = "cookie-factory" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396de984970346b0d9e93d1415082923c679e5ae5c3ee3dcbd104f5610af126b" +checksum = "9885fa71e26b8ab7855e2ec7cae6e9b380edff76cd052e07c683a0319d51b3a2" +dependencies = [ + "futures", +] [[package]] name = "core-foundation" @@ -994,9 +1043,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" dependencies = [ "crossbeam-utils", ] @@ -1029,9 +1078,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", + "rand_core 0.6.4", "typenum", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + [[package]] name = "darling" version = "0.14.4" @@ -1263,12 +1322,12 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "docker-compose-types" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e366950e7785fe0e404901a2b4e5c09ebd6656767f0c2167e34c5068ce0cc2d" +checksum = "6d6fdd6fa1c9e8e716f5f73406b868929f468702449621e7397066478b9bf89c" dependencies = [ "derive_builder 0.13.1", - "indexmap 2.2.3", + "indexmap 2.2.6", "serde", "serde_yaml", ] @@ -1358,9 +1417,9 @@ dependencies = [ [[package]] name = "event-listener" -version = "5.1.0" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7ad6fd685ce13acd6d9541a30f6db6567a7a24c9ffd4ba2955d29e3f22c8b27" +checksum = "2b5fb89194fa3cad959b833185b3063ba881dbfc7030680b314250779fb4cc91" dependencies = [ "concurrent-queue", "parking", @@ -1383,7 +1442,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "feedafcaa9b749175d5ac357452a9d41ea2911da598fde46ce1fe02c37751291" dependencies = [ - "event-listener 5.1.0", + "event-listener 5.2.0", "pin-project-lite", ] @@ -1407,9 +1466,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" [[package]] name = "finl_unicode" @@ -1571,11 +1630,11 @@ dependencies = [ [[package]] name = "futures-lite" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445ba825b27408685aaecefd65178908c36c6e96aaf6d8599419d46e624192ba" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ - "fastrand 2.0.1", + "fastrand 2.0.2", "futures-core", "futures-io", "parking", @@ -1590,7 +1649,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.55", ] [[package]] @@ -1673,6 +1732,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + [[package]] name = "gimli" version = "0.28.1" @@ -1687,9 +1756,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "h2" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb" dependencies = [ "bytes", "fnv", @@ -1697,7 +1766,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 2.2.3", + "indexmap 2.2.6", "slab", "tokio", "tokio-util", @@ -1728,7 +1797,7 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ - "ahash 0.8.10", + "ahash 0.8.11", "allocator-api2", ] @@ -1750,11 +1819,17 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "379dada1584ad501b383485dd706b8afb7a70fcbc7f4da7d780638a5a6124a60" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -1791,9 +1866,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -1932,9 +2007,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.3" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown 0.14.3", @@ -1994,15 +2069,24 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jobserver" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +dependencies = [ + "libc", +] [[package]] name = "js-sys" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -2065,7 +2149,7 @@ version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "libc", "redox_syscall 0.4.1", ] @@ -2117,9 +2201,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "matchers" @@ -2184,9 +2268,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", @@ -2218,17 +2302,6 @@ dependencies = [ "tempfile", ] -[[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 = "nom" version = "7.1.3" @@ -2289,13 +2362,19 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + [[package]] name = "openssl" version = "0.10.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "cfg-if", "foreign-types", "libc", @@ -2312,7 +2391,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.55", ] [[package]] @@ -2440,9 +2519,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.7" +version = "2.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219c0dcc30b6a27553f9cc242972b67f75b60eb0db71f0b5462f38b058c41546" +checksum = "56f8023d0fb78c8e03784ea1c7f3fa36e68a723138990b8d5a47d916b651e7a8" dependencies = [ "memchr", "thiserror", @@ -2451,9 +2530,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.7" +version = "2.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e1288dbd7786462961e69bfd4df7848c1e37e8b74303dbdab82c3a9cdd2809" +checksum = "b0d24f72393fd16ab6ac5738bc33cdb6a9aa73f8b902e8fe29cf4e67d7dd1026" dependencies = [ "pest", "pest_generator", @@ -2461,22 +2540,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.7" +version = "2.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1381c29a877c6d34b8c176e734f35d7f7f5b3adaefe940cb4d1bb7af94678e2e" +checksum = "fdc17e2a6c7d0a492f0158d7a4bd66cc17280308bbaff78d5bef566dca35ab80" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.55", ] [[package]] name = "pest_meta" -version = "2.7.7" +version = "2.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0934d6907f148c22a3acbda520c7eed243ad7487a30f51f6ce52b58b7077a8a" +checksum = "934cd7631c050f4674352a6e835d5f6711ffbfb9345c2fc0107155ac495ae293" dependencies = [ "once_cell", "pest", @@ -2490,27 +2569,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.2.3", + "indexmap 2.2.6", ] [[package]] name = "pin-project" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.55", ] [[package]] @@ -2544,7 +2623,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" dependencies = [ "atomic-waker", - "fastrand 2.0.1", + "fastrand 2.0.2", "futures-io", ] @@ -2572,18 +2651,31 @@ dependencies = [ [[package]] name = "polling" -version = "3.5.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24f040dee2588b4963afb4e420540439d126f73fdacf4a9c486a96d840bac3c9" +checksum = "e0c976a60b2d7e99d6f229e414670a9b85d13ac305cc6d1e9c134de58c5aaaf6" dependencies = [ "cfg-if", "concurrent-queue", + "hermit-abi", "pin-project-lite", - "rustix 0.38.31", + "rustix 0.38.32", "tracing", "windows-sys 0.52.0", ] +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -2622,9 +2714,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -2635,7 +2727,7 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "memchr", "unicase", ] @@ -2740,6 +2832,27 @@ dependencies = [ "futures-io", ] +[[package]] +name = "redis" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d64e978fd98a0e6b105d066ba4889a7301fca65aeac850a877d8797343feeb" +dependencies = [ + "async-trait", + "bytes", + "combine", + "futures-util", + "itoa", + "percent-encoding", + "pin-project-lite", + "ryu", + "sha1_smol", + "socket2 0.5.6", + "tokio", + "tokio-util", + "url", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -2771,13 +2884,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.3" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.5", + "regex-automata 0.4.6", "regex-syntax 0.8.2", ] @@ -2792,9 +2905,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", @@ -2815,9 +2928,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.24" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ "base64 0.21.7", "bytes", @@ -2865,8 +2978,8 @@ version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6273372244d04a8a4b0bec080ea1e710403e88c5d9d83f9808b2bfa64f0982a" dependencies = [ - "ahash 0.8.10", - "bitflags 2.4.2", + "ahash 0.8.11", + "bitflags 2.5.0", "instant", "num-traits", "once_cell", @@ -2885,7 +2998,7 @@ checksum = "9db7f8dc4c9d48183a17ce550574c42995252b82d267eaca3fcd1b979159856c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.55", ] [[package]] @@ -2980,11 +3093,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.31" +version = "0.38.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "errno", "libc", "linux-raw-sys 0.4.13", @@ -3147,14 +3260,14 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.55", ] [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" dependencies = [ "itoa", "ryu", @@ -3163,9 +3276,9 @@ dependencies = [ [[package]] name = "serde_path_to_error" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd154a240de39fdebcf5775d2675c204d7c13cf39a4c697be6493c8e734337c" +checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" dependencies = [ "itoa", "serde", @@ -3200,7 +3313,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70c0e00fab6460447391a1981c21341746bc2d0178a7c46a3bbf667f450ac6e4" dependencies = [ - "indexmap 2.2.3", + "indexmap 2.2.6", "itertools", "num-traits", "once_cell", @@ -3225,7 +3338,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.0", - "syn 2.0.51", + "syn 2.0.55", ] [[package]] @@ -3240,11 +3353,11 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.32" +version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd075d994154d4a774f95b51fb96bdc2832b0ea48425c92546073816cda1f2f" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.2.3", + "indexmap 2.2.6", "itoa", "ryu", "serde", @@ -3262,6 +3375,12 @@ dependencies = [ "digest", ] +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + [[package]] name = "sha2" version = "0.10.8" @@ -3317,9 +3436,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" dependencies = [ "serde", ] @@ -3394,12 +3513,12 @@ 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 0.7.3", - "sqlx-macros 0.7.3", + "sqlx-core 0.7.4", + "sqlx-macros 0.7.4", "sqlx-postgres", ] @@ -3412,7 +3531,7 @@ dependencies = [ "async-trait", "casbin", "dotenv", - "sqlx 0.7.3", + "sqlx 0.7.4", ] [[package]] @@ -3472,17 +3591,16 @@ 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.10", + "ahash 0.8.11", "atoi 2.0.0", "byteorder", "bytes", "crc", "crossbeam-queue", - "dotenvy", "either", "event-listener 2.5.3", "futures-channel", @@ -3492,7 +3610,7 @@ dependencies = [ "futures-util", "hashlink", "hex", - "indexmap 2.2.3", + "indexmap 2.2.6", "log", "memchr", "native-tls", @@ -3519,7 +3637,7 @@ checksum = "9966e64ae989e7e575b19d7265cb79d7fc3cbbdf179835cb0d716f294c2049c9" dependencies = [ "dotenvy", "either", - "heck", + "heck 0.4.1", "hex", "once_cell", "proc-macro2", @@ -3535,27 +3653,26 @@ 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", - "sqlx-core 0.7.3", + "sqlx-core 0.7.4", "sqlx-macros-core", "syn 1.0.109", ] [[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", + "heck 0.4.1", "hex", "once_cell", "proc-macro2", @@ -3563,7 +3680,7 @@ dependencies = [ "serde", "serde_json", "sha2", - "sqlx-core 0.7.3", + "sqlx-core 0.7.4", "sqlx-postgres", "syn 1.0.109", "tempfile", @@ -3573,13 +3690,13 @@ 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 2.0.0", "base64 0.21.7", - "bitflags 2.4.2", + "bitflags 2.5.0", "byteorder", "crc", "dotenvy", @@ -3600,10 +3717,9 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "sha1", "sha2", "smallvec", - "sqlx-core 0.7.3", + "sqlx-core 0.7.4", "stringprep", "thiserror", "tracing", @@ -3629,6 +3745,8 @@ dependencies = [ "actix-cors", "actix-http", "actix-web", + "aes-gcm", + "base64 0.22.0", "brotli", "chrono", "clap", @@ -3637,13 +3755,14 @@ dependencies = [ "derive_builder 0.12.0", "docker-compose-types", "futures", - "futures-lite 2.2.0", + "futures-lite 2.3.0", "futures-util", "glob", "hmac", - "indexmap 2.2.3", + "indexmap 2.2.6", "lapin", "rand 0.8.5", + "redis", "regex", "reqwest", "serde", @@ -3715,9 +3834,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.51" +version = "2.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ab617d94515e94ae53b8406c628598680aa0c9587474ecbe58188f7b345d66c" +checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" dependencies = [ "proc-macro2", "quote", @@ -3776,8 +3895,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", - "fastrand 2.0.1", - "rustix 0.38.31", + "fastrand 2.0.2", + "rustix 0.38.32", "windows-sys 0.52.0", ] @@ -3792,22 +3911,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.55", ] [[package]] @@ -3924,7 +4043,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.55", ] [[package]] @@ -3950,9 +4069,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ "futures-core", "pin-project-lite", @@ -4002,9 +4121,9 @@ dependencies = [ [[package]] name = "tracing-actix-web" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fe0d5feac3f4ca21ba33496bcb1ccab58cca6412b1405ae80f0581541e0ca78" +checksum = "fa069bd1503dd526ee793bb3fce408895136c95fc86d2edb2acf1c646d7f0684" dependencies = [ "actix-web", "mutually_exclusive_features", @@ -4021,7 +4140,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.55", ] [[package]] @@ -4030,7 +4149,7 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5c266b9ac83dedf0e0385ad78514949e6d89491269e7065bee51d2bb8ec7373" dependencies = [ - "ahash 0.8.10", + "ahash 0.8.11", "gethostname", "log", "serde", @@ -4158,11 +4277,21 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "unsafe-libyaml" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] name = "untrusted" @@ -4196,9 +4325,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ "getrandom 0.2.12", "serde", @@ -4230,9 +4359,9 @@ checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -4265,11 +4394,17 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + [[package]] name = "wasm-bindgen" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -4277,24 +4412,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.55", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if", "js-sys", @@ -4304,9 +4439,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4314,28 +4449,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.55", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "web-sys" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", @@ -4362,11 +4497,12 @@ dependencies = [ [[package]] name = "whoami" -version = "1.4.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" +checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" dependencies = [ - "wasm-bindgen", + "redox_syscall 0.4.1", + "wasite", "web-sys", ] @@ -4407,7 +4543,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.3", + "windows-targets 0.52.4", ] [[package]] @@ -4425,7 +4561,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.3", + "windows-targets 0.52.4", ] [[package]] @@ -4445,17 +4581,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" dependencies = [ - "windows_aarch64_gnullvm 0.52.3", - "windows_aarch64_msvc 0.52.3", - "windows_i686_gnu 0.52.3", - "windows_i686_msvc 0.52.3", - "windows_x86_64_gnu 0.52.3", - "windows_x86_64_gnullvm 0.52.3", - "windows_x86_64_msvc 0.52.3", + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", ] [[package]] @@ -4466,9 +4602,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" @@ -4478,9 +4614,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" @@ -4490,9 +4626,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" @@ -4502,9 +4638,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" @@ -4514,9 +4650,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" [[package]] name = "windows_x86_64_gnullvm" @@ -4526,9 +4662,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" [[package]] name = "windows_x86_64_msvc" @@ -4538,9 +4674,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" [[package]] name = "winreg" @@ -4606,7 +4742,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.55", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 982000f..030e403 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,6 +58,9 @@ deadpool-lapin = "0.11.0" docker-compose-types = "0.7.0" #actix-casbin-auth = { git = "https://github.com/casbin-rs/actix-casbin-auth.git"} actix-casbin-auth = { git = "https://github.com/smart--petea/actix-casbin-auth.git", branch = "dirty-master"} +aes-gcm = "0.10.3" +base64 = "0.22.0" +redis = { version = "0.25.2", features = ["tokio-comp"] } [dependencies.sqlx] version = "0.6.3" diff --git a/docker-compose.yml b/docker-compose.yml index eeb10eb..4ba581c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,6 +4,9 @@ volumes: stackerdb: driver: local + redis-data: + driver: local + services: @@ -29,6 +32,25 @@ services: # stackerdb: # condition: service_healthy + redis: + container_name: redis + image: redis + restart: always + ports: + - 6379:6379 + volumes: + - redis-data:/data +# - ./redis/rc.local:/etc/rc.local +# - ./redis/redis.conf:/usr/local/etc/redis/redis.conf + sysctls: + net.core.somaxconn: 1024 + logging: + driver: "json-file" + options: + max-size: "10m" + tag: "container_{{.Name}}" + + # stacker_queue: # image: trydirect/stacker:0.0.7 # container_name: stacker_queue diff --git a/docker/dev/.env b/docker/dev/.env index 6371a97..d60f266 100644 --- a/docker/dev/.env +++ b/docker/dev/.env @@ -1,5 +1,8 @@ +SECURITY_KEY=SECURITY_KEY_SHOULD_BE_OF_LEN_32 + DATABASE_URL=postgres://postgres:postgres@stackerdb:5432/stacker POSTGRES_USER=postgres POSTGRES_PASSWORD=postgres POSTGRES_DB=stacker -POSTGRES_PORT=5432 \ No newline at end of file +POSTGRES_PORT=5432 + diff --git a/docker/dev/docker-compose.yml b/docker/dev/docker-compose.yml index 3577b14..eeac038 100644 --- a/docker/dev/docker-compose.yml +++ b/docker/dev/docker-compose.yml @@ -4,6 +4,9 @@ volumes: stackerdb: driver: local + redis-data: + driver: local + networks: backend: driver: bridge @@ -75,3 +78,23 @@ services: - ./postgresql.conf:/etc/postgresql/postgresql.conf networks: - backend + + redis: + container_name: stackerredis + image: redis:latest + restart: always + ports: + - 6379 + volumes: + - redis-data:/data + # - ./redis/rc.local:/etc/rc.local + # - ./redis/redis.conf:/usr/local/etc/redis/redis.conf + sysctls: + net.core.somaxconn: 1024 + logging: + driver: "json-file" + options: + max-size: "10m" + tag: "container_{{.Name}}" + + diff --git a/src/forms/cloud.rs b/src/forms/cloud.rs index ab040c3..8cc1567 100644 --- a/src/forms/cloud.rs +++ b/src/forms/cloud.rs @@ -1,32 +1,146 @@ use crate::models; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Serialize, Serializer}; use serde_valid::Validate; +use crate::helpers::cloud::security::Secret; +use tracing::Instrument; -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] + +// fn hide_part(value: &Option, s: S) -> Result +// where +// S: Serializer, +// { +// eprintln!("value in serde {:?}", value); +// let result: &str = match value { +// Some(value) => { +// let value = value.as_str(); +// value +// // value.into_iter().take(6).collect::() +// } +// None => "", +// }; +// s.serialize_str(result) +// } +fn hide_parts(value: String) -> String { + value.chars().into_iter().take(6).collect::() + "****" +} + + +#[derive(Default, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Cloud { + pub user_id: Option, pub project_id: Option, #[validate(min_length = 2)] #[validate(max_length = 50)] pub provider: String, + // #[serde(serialize_with = "hide_part")] pub cloud_token: Option, + // #[serde(serialize_with = "hide_part")] pub cloud_key: Option, + // #[serde(serialize_with = "hide_part")] pub cloud_secret: Option, pub save_token: Option, } +impl Cloud { + pub(crate) fn decode(secret: &mut Secret, encrypted_value: String) -> String { + // tracing::error!("encrypted_value {:?}", &encrypted_value); + let b64_decoded = Secret::b64_decode(&encrypted_value).unwrap(); + match secret.decrypt(b64_decoded) { + Ok(decoded) => decoded, + Err(_err) => { + tracing::error!("πŸŸ₯ Could not decode {:?},{:?}",secret.field,_err); + // panic!("Could not decode "); + "".to_owned() + } + } + } + + // @todo should be refactored, may be moved to cloud.into() or Secret::from() + pub(crate) fn decode_model(mut cloud: models::Cloud) -> models::Cloud { + + let encrypted_value = cloud.cloud_token.clone().unwrap(); + let mut secret = Secret::new(); + secret.user_id = cloud.user_id.clone(); + secret.project_id = cloud.project_id.clone().unwrap(); + secret.field = "cloud_token".to_string(); + let cloud_token = Cloud::decode(&mut secret, encrypted_value); + cloud.cloud_token = Some(hide_parts(cloud_token)); + cloud + } +} + +impl std::fmt::Debug for Cloud { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let cloud_key: String = match self.cloud_key.as_ref() { + Some(val) => + { + val.chars().take(4).collect::() + "****" + }, + None => "".to_string(), + }; + let cloud_token: String = match self.cloud_token.as_ref() { + Some(val) => { + eprintln!("cloud token {val:?}"); + val.chars().take(4).collect::() + "****" + }, + None => "".to_string(), + }; + + let cloud_secret: String = match self.cloud_secret.as_ref() { + Some(val) => { + val.chars().take(4).collect::() + "****" + } + None => "".to_string(), + }; + + write!(f, "{} cloud creds: cloud_key : {} cloud_token: {} cloud_secret: {} project_id: {:?}", + self.provider, + cloud_key, + cloud_token, + cloud_secret, + self.project_id + ) + } +} + impl Into for &Cloud { fn into(self) -> models::Cloud { let mut cloud = models::Cloud::default(); cloud.provider = self.provider.clone(); - cloud.cloud_token = self.cloud_token.clone(); - cloud.cloud_key = self.cloud_key.clone(); - cloud.cloud_secret = self.cloud_secret.clone(); + cloud.user_id = self.user_id.clone().unwrap(); + cloud.project_id = self.project_id; + + let mut secret = Secret::new(); + secret.user_id = self.user_id.clone().unwrap(); + secret.project_id = self.project_id.unwrap(); + + if let Some(val) = self.cloud_token.clone() { + secret.field = "cloud_token".to_owned(); + if let Ok(encrypted) = secret.encrypt(val) { + cloud.cloud_token = Some(Secret::b64_encode(&encrypted)); + }; + } + if let Some(val) = self.cloud_key.clone() { + secret.field = "cloud_key".to_owned(); + if let Ok(encrypted) = secret.encrypt(val) { + // cloud.cloud_token = Some(encrypted.data.iter().map(|&c| c as char).collect::()) + cloud.cloud_key = Some(Secret::b64_encode(&encrypted)); + }; + } + if let Some(val) = self.cloud_secret.clone() { + secret.field = "cloud_secret".to_owned(); + if let Ok(encrypted) = secret.encrypt(val) { + cloud.cloud_secret = Some(Secret::b64_encode(&encrypted)) + }; + } cloud.save_token = self.save_token.clone(); cloud } + } + impl Into for models::Cloud { fn into(self) -> Cloud { let mut form = Cloud::default(); diff --git a/src/helpers/cloud/mod.rs b/src/helpers/cloud/mod.rs new file mode 100644 index 0000000..9d2c999 --- /dev/null +++ b/src/helpers/cloud/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod security; +pub use security::*; \ No newline at end of file diff --git a/src/helpers/cloud/security.rs b/src/helpers/cloud/security.rs new file mode 100644 index 0000000..29b997c --- /dev/null +++ b/src/helpers/cloud/security.rs @@ -0,0 +1,135 @@ +use aes_gcm::{ + aead::{Aead, AeadCore, KeyInit, OsRng}, + Aes256Gcm, Nonce, Key // Or `Aes128Gcm` +}; +use base64::{engine::general_purpose, Engine as _}; +use redis::{Commands, Connection}; +use tracing::Instrument; + +#[derive(Debug, Default, PartialEq, Clone)] +pub(crate) struct Secret { + pub(crate) user_id: String, + pub(crate) project_id: i32, + pub(crate) field: String, // cloud_token/cloud_key/cloud_secret + pub(crate) nonce: Vec, +} + + +impl Secret { + pub fn new() -> Self { + + Secret { + user_id: "".to_string(), + project_id: 0, + field: "".to_string(), + nonce: vec![], + } + } + #[tracing::instrument(name = "Secret::connect_storage")] + fn connect_storage() -> Connection { + match redis::Client::open("redis://127.0.0.1/"){ + Ok(client) => { + match client.get_connection() { + Ok(connection) => connection, + Err(_err) => panic!("Error connecting Redis") + } + } + Err(err) => panic!("Could not connect to Redis, {:?}", err) + } + } + + #[tracing::instrument(name = "Secret::save")] + fn save(&self, value: &[u8]) -> &Self { + let mut conn = Secret::connect_storage(); + let key = format!("{}_{}_{}", self.user_id, self.project_id, self.field); + tracing::debug!("Saving into storage.."); + let _: () = match conn.set(key, value) { + Ok(s) => s, + Err(e) => panic!("Could not save to storage {}", e) + }; + self + } + + pub fn b64_encode(value: &Vec) -> String { + general_purpose::STANDARD.encode(value) + } + + pub fn b64_decode(value: &String) -> Result, String> { + general_purpose::STANDARD.decode(value) + .map_err(|e| format!("b64_decode error {}", e)) + } + + #[tracing::instrument(name = "Secret::get")] + fn get(&mut self, key: String) -> &mut Self { + let mut conn = Secret::connect_storage(); + let nonce: Vec = match conn.get(&key) { + Ok(value) => { + tracing::debug!("Got value from storage {:?}", &value); + value + }, + Err(_e) => { + tracing::error!("Could not get value from storage by key {:?} {:?}", &key, _e); + vec![] + } + }; + + self.nonce = nonce; + self + } + + #[tracing::instrument(name = "encrypt.")] + pub fn encrypt(&self, token: String) -> Result, String> { + + // let sec_key = std::env::var("SECURITY_KEY") + // .expect("SECURITY_KEY environment variable is not set") + // .as_bytes(); + let sec_key = "SECURITY_KEY_SHOULD_BE_OF_LEN_32".as_bytes(); + // let key = Aes256Gcm::generate_key(OsRng); + let key: &Key:: = Key::::from_slice(&sec_key); + // eprintln!("encrypt key {key:?}"); + // eprintln!("encrypt: from slice key {key:?}"); + let cipher = Aes256Gcm::new(&key); + // eprintln!("encrypt: Cipher str {cipher:?}"); + let nonce = Aes256Gcm::generate_nonce(&mut OsRng); // 96-bits; unique per message + eprintln!("Nonce bytes {nonce:?}"); + // let nonce_b64: String = general_purpose::STANDARD.encode(nonce); + // eprintln!("Nonce b64 {nonce_b64:?}"); + eprintln!("token {token:?}"); + + let cipher_vec = cipher.encrypt(&nonce, token.as_ref()) + .map_err(|e| format!("{:?}", e))?; + + // store nonce for a limited amount of time + // self.save(cipher_vec.clone()); + self.save(nonce.as_slice()); + + eprintln!("Cipher {cipher_vec:?}"); + Ok(cipher_vec) + } + + #[tracing::instrument(name = "decrypt.")] + pub fn decrypt(&mut self, encrypted_data: Vec) -> Result { + let sec_key = "SECURITY_KEY_SHOULD_BE_OF_LEN_32".as_bytes(); + // let sec_key = std::env::var("SECURITY_KEY") + // .expect("SECURITY_KEY environment variable is not set") + // .as_bytes(); + let key: &Key:: = Key::::from_slice(&sec_key); + // eprintln!("decrypt: Key str {key:?}"); + let rkey = format!("{}_{}_{}", self.user_id, self.project_id, self.field); + eprintln!("decrypt: Key str {rkey:?}"); + self.get(rkey); + // eprintln!("decrypt: nonce b64:decoded {nonce:?}"); + + let nonce = Nonce::from_slice(self.nonce.as_slice()); + eprintln!("decrypt: nonce {nonce:?}"); + + let cipher = Aes256Gcm::new(&key); + // eprintln!("decrypt: Cipher str {cipher:?}"); + eprintln!("decrypt: str {encrypted_data:?}"); + + let plaintext = cipher.decrypt(&nonce, encrypted_data.as_ref()) + .map_err(|e| format!("{:?}", e))?; + + Ok(String::from_utf8(plaintext).map_err(|e| format!("{:?}", e))?) + } +} \ No newline at end of file diff --git a/src/helpers/mod.rs b/src/helpers/mod.rs index 0640df8..368eafd 100644 --- a/src/helpers/mod.rs +++ b/src/helpers/mod.rs @@ -7,5 +7,8 @@ pub use json::*; pub use mq_manager::*; pub mod dockerhub; pub(crate) mod compressor; +pub(crate) mod cloud; pub use dockerhub::*; + +pub use cloud::*; \ No newline at end of file diff --git a/src/middleware/authentication/method/f_oauth.rs b/src/middleware/authentication/method/f_oauth.rs index efe215c..8400e81 100644 --- a/src/middleware/authentication/method/f_oauth.rs +++ b/src/middleware/authentication/method/f_oauth.rs @@ -20,7 +20,7 @@ fn try_extract_token(authentication: String) -> Result { Ok(token.unwrap().into()) } -#[tracing::instrument(name = "try authenticate via bearer")] +#[tracing::instrument(name = "Authenticate with bearer token")] pub async fn try_oauth(req: &mut ServiceRequest) -> Result { let authentication = get_header::(&req, "authorization")?; if authentication.is_none() { @@ -33,7 +33,8 @@ pub async fn try_oauth(req: &mut ServiceRequest) -> Result { .await .map_err(|err| format!("{err}"))?; - let accesscontrol_vals = actix_casbin_auth::CasbinVals { + // println!("user ================== {}", user.id.clone()); + let acl_vals = actix_casbin_auth::CasbinVals { subject: user.id.clone(), domain: None, }; @@ -42,8 +43,8 @@ pub async fn try_oauth(req: &mut ServiceRequest) -> Result { return Err("user already logged".to_string()); } - if req.extensions_mut().insert(accesscontrol_vals).is_some() { - return Err("sth wrong with access control".to_string()); + if req.extensions_mut().insert(acl_vals).is_some() { + return Err("Something wrong with access control".to_string()); } Ok(true) @@ -58,7 +59,7 @@ async fn fetch_user(auth_url: &str, token: &str) -> Result .header(ACCEPT, "application/json") .send() .await - .map_err(|_err| "no resp from auth server".to_string())?; + .map_err(|_err| "No response from OAuth server".to_string())?; if !resp.status().is_success() { return Err("401 Unauthorized".to_string()); diff --git a/src/models/cloud.rs b/src/models/cloud.rs index 91b494c..d0fd31b 100644 --- a/src/models/cloud.rs +++ b/src/models/cloud.rs @@ -14,3 +14,38 @@ pub struct Cloud { pub created_at: DateTime, pub updated_at: DateTime, } + + + +impl std::fmt::Display for Cloud { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let cloud_key: String = match self.cloud_key.as_ref() { + Some(val) => + { + val.chars().take(4).collect::() + "****" + }, + None => "".to_string(), + }; + let cloud_token: String = match self.cloud_token.as_ref() { + Some(val) => { + val.chars().take(4).collect::() + "****" + }, + None => "".to_string(), + }; + + let cloud_secret: String = match self.cloud_secret.as_ref() { + Some(val) => { + val.chars().take(4).collect::() + "****" + } + None => "".to_string(), + }; + + write!(f, "{} cloud creds: cloud_key : {} cloud_token: {} cloud_secret: {} project_id: {:?}", + self.provider, + cloud_key, + cloud_token, + cloud_secret, + self.project_id + ) + } +} diff --git a/src/routes/cloud/add.rs b/src/routes/cloud/add.rs index ca8e7b8..ce4126f 100644 --- a/src/routes/cloud/add.rs +++ b/src/routes/cloud/add.rs @@ -6,18 +6,16 @@ use crate::db; use actix_web::{post, web, Responder, Result}; use sqlx::PgPool; use std::sync::Arc; +use chrono::Utc; use serde_valid::Validate; +use tracing::Instrument; -// workflow -// add, update, list, get(user_id), ACL, -// ACL - access to func for a user -// ACL - access to objects for a user #[tracing::instrument(name = "Add cloud.")] #[post("")] pub async fn add( user: web::ReqData>, - form: web::Json, + mut form: web::Json, pg_pool: web::Data, ) -> Result { @@ -29,8 +27,10 @@ pub async fn add( return Err(JsonResponse::::build().form_error(errors)); } + form.user_id = Some(user.id.clone()); let mut cloud: models::Cloud = form.deref().into(); - cloud.user_id = user.id.clone(); + cloud.created_at = Utc::now(); + cloud.updated_at = Utc::now(); db::cloud::insert(pg_pool.get_ref(), cloud) .await diff --git a/src/routes/cloud/get.rs b/src/routes/cloud/get.rs index 23af867..8298398 100644 --- a/src/routes/cloud/get.rs +++ b/src/routes/cloud/get.rs @@ -4,31 +4,34 @@ use crate::helpers::JsonResponse; use crate::models; use actix_web::{get, web, Responder, Result}; use sqlx::PgPool; +use crate::forms::Cloud; +use tracing::Instrument; -// workflow -// add, update, list, get(user_id), ACL, -// ACL - access to func for a user -// ACL - access to objects for a user - -#[tracing::instrument(name = "Get cloud.")] +#[tracing::instrument(name = "Get cloud credentials.")] #[get("/{id}")] pub async fn item( path: web::Path<(i32,)>, + user: web::ReqData>, pg_pool: web::Data, ) -> Result { let id = path.0; - let cloud = db::cloud::fetch(pg_pool.get_ref(), id) + db::cloud::fetch(pg_pool.get_ref(), id) .await .map_err(|_err| JsonResponse::::build() .internal_server_error("")) .and_then(|cloud| { match cloud { - Some(cloud) => { Ok(cloud) }, - None => Err(JsonResponse::::build().not_found("object not found")) + Some(cloud) if cloud.user_id != user.id => { + Err(JsonResponse::not_found("record not found")) + }, + Some(cloud) => { + let cloud = Cloud::decode_model(cloud); + Ok(JsonResponse::build().set_item(Some(cloud)).ok("OK")) + }, + None => Err(JsonResponse::not_found("record not found")), } - })?; + }) - Ok(JsonResponse::build().set_item(cloud).ok("OK")) } #[tracing::instrument(name = "Get all clouds.")] diff --git a/src/routes/cloud/update.rs b/src/routes/cloud/update.rs index aca859c..3c60360 100644 --- a/src/routes/cloud/update.rs +++ b/src/routes/cloud/update.rs @@ -8,6 +8,7 @@ use sqlx::PgPool; use std::sync::Arc; use tracing::Instrument; use std::ops::Deref; +use chrono::Utc; #[tracing::instrument(name = "Update cloud.")] #[put("/{id}")] @@ -37,6 +38,7 @@ pub async fn item( let mut cloud:models::Cloud = form.deref().into(); cloud.id = cloud_row.id; cloud.user_id = user.id.clone(); + // cloud.updated_at = Utc::now(); tracing::debug!("Updating cloud {:?}", cloud); diff --git a/src/routes/project/compose.rs b/src/routes/project/compose.rs index de52ca0..ca2e414 100644 --- a/src/routes/project/compose.rs +++ b/src/routes/project/compose.rs @@ -7,7 +7,7 @@ use sqlx::PgPool; use std::sync::Arc; #[tracing::instrument(name = "User's generate docker-compose.")] -#[get("/{id}")] +#[get("/{id}/compose")] pub async fn add( user: web::ReqData>, path: web::Path<(i32,)>, diff --git a/src/routes/server/get.rs b/src/routes/server/get.rs index de33e8f..3bd5a6f 100644 --- a/src/routes/server/get.rs +++ b/src/routes/server/get.rs @@ -15,21 +15,24 @@ use sqlx::PgPool; #[get("/{id}")] pub async fn item( path: web::Path<(i32,)>, + user: web::ReqData>, pg_pool: web::Data, ) -> Result { let id = path.0; - let server = db::server::fetch(pg_pool.get_ref(), id) + db::server::fetch(pg_pool.get_ref(), id) .await .map_err(|_err| JsonResponse::::build() .internal_server_error("")) .and_then(|server| { match server { - Some(server) => { Ok(server) }, - None => Err(JsonResponse::::build().not_found("object not found")) + Some(project) if project.user_id != user.id => { + Err(JsonResponse::not_found("not found")) + }, + Some(server) => Ok(JsonResponse::build().set_item(Some(server)).ok("OK")), + None => Err(JsonResponse::not_found("not found")), } - })?; + }) - Ok(JsonResponse::build().set_item(server).ok("OK")) } #[tracing::instrument(name = "Get all servers.")] diff --git a/src/routes/server/update.rs b/src/routes/server/update.rs index e72c296..b074125 100644 --- a/src/routes/server/update.rs +++ b/src/routes/server/update.rs @@ -38,8 +38,6 @@ pub async fn item( server.id = server_row.id; server.project_id = server_row.project_id; server.user_id = user.id.clone(); - // exclude - // server.created_at tracing::debug!("Updating server {:?}", server); diff --git a/src/startup.rs b/src/startup.rs index e199afa..6fa0f6c 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -17,6 +17,7 @@ use crate::middleware; use sqlx::{Pool, Postgres}; use std::net::TcpListener; use tracing_actix_web::TracingLogger; +use redis::Commands; pub async fn run( listener: TcpListener, @@ -41,7 +42,7 @@ pub async fn run( let server = HttpServer::new(move || { App::new() .wrap(TracingLogger::default()) - .wrap(authorization.clone()) + // .wrap(authorization.clone()) .wrap(middleware::authentication::Manager::new()) .wrap(Cors::permissive()) .service( @@ -69,7 +70,6 @@ pub async fn run( .service(crate::routes::project::deploy::item) .service(crate::routes::project::deploy::saved_item) .service(crate::routes::project::compose::add) - .service(crate::routes::project::compose::admin) .service(crate::routes::project::get::item) .service(crate::routes::project::add::item) .service(crate::routes::project::update::item) @@ -80,6 +80,7 @@ pub async fn run( .service( web::scope("/project") .service(crate::routes::project::get::admin_list) + .service(crate::routes::project::compose::admin) ) .service( web::scope("/client") diff --git a/tests/mock_data/cloud.json b/tests/mock_data/cloud.json index 04f7412..3865cd7 100644 --- a/tests/mock_data/cloud.json +++ b/tests/mock_data/cloud.json @@ -1,9 +1,8 @@ { - "user_id": "hy181TZa4DaabUZWklsrxw", "project_id": 1, "provider": "htz", "cloud_token": "cloud_token_here", - "cloud_key": "cloud_token_here", + "cloud_key": "cloud_key_here", "cloud_secret": "cloud_secret_here", "save_token": true } From ac8ebd5ac04912c00e079c0f9af1e8e81beedac0 Mon Sep 17 00:00:00 2001 From: vsilent Date: Wed, 27 Mar 2024 13:02:48 +0200 Subject: [PATCH 236/284] secure all other cloud cred fields --- src/forms/cloud.rs | 49 ++++++++++++++++++++++++++++++++++++----- src/routes/cloud/get.rs | 2 +- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/src/forms/cloud.rs b/src/forms/cloud.rs index 8cc1567..79515c5 100644 --- a/src/forms/cloud.rs +++ b/src/forms/cloud.rs @@ -56,15 +56,39 @@ impl Cloud { } // @todo should be refactored, may be moved to cloud.into() or Secret::from() - pub(crate) fn decode_model(mut cloud: models::Cloud) -> models::Cloud { + pub(crate) fn decode_model(mut cloud: models::Cloud, reveal:bool) -> models::Cloud { let encrypted_value = cloud.cloud_token.clone().unwrap(); let mut secret = Secret::new(); secret.user_id = cloud.user_id.clone(); secret.project_id = cloud.project_id.clone().unwrap(); + secret.field = "cloud_token".to_string(); let cloud_token = Cloud::decode(&mut secret, encrypted_value); - cloud.cloud_token = Some(hide_parts(cloud_token)); + if reveal { + cloud.cloud_token = Some(cloud_token); + } else { + cloud.cloud_token = Some(hide_parts(cloud_token)); + } + + secret.field = "cloud_secret".to_string(); + let encrypted_value = cloud.cloud_secret.clone().unwrap(); + let cloud_secret = Cloud::decode(&mut secret, encrypted_value); + if reveal { + cloud.cloud_secret = Some(cloud_secret); + } else { + cloud.cloud_secret = Some(hide_parts(cloud_secret)); + } + + secret.field = "cloud_key".to_string(); + let encrypted_value = cloud.cloud_key.clone().unwrap(); + let cloud_key = Cloud::decode(&mut secret, encrypted_value); + if reveal { + cloud.cloud_key = Some(cloud_key); + } else { + cloud.cloud_key = Some(hide_parts(cloud_key)); + } + cloud } } @@ -141,14 +165,29 @@ impl Into for &Cloud { } +// on deploy impl Into for models::Cloud { fn into(self) -> Cloud { let mut form = Cloud::default(); form.project_id = self.project_id; form.provider = self.provider; - form.cloud_token = self.cloud_token; - form.cloud_key = self.cloud_key; - form.cloud_secret = self.cloud_secret; + + let mut secret = Secret::new(); + secret.user_id = self.user_id.clone(); + secret.project_id = self.project_id.clone().unwrap(); + + secret.field = "cloud_token".to_string(); + let cloud_token = Cloud::decode(&mut secret, self.cloud_token.unwrap()); + form.cloud_token = Some(cloud_token); + + secret.field = "cloud_key".to_string(); + let cloud_key = Cloud::decode(&mut secret, self.cloud_key.unwrap()); + form.cloud_token = Some(cloud_key); + + secret.field = "cloud_secret".to_string(); + let cloud_secret = Cloud::decode(&mut secret, self.cloud_secret.unwrap()); + form.cloud_secret = Some(cloud_secret); + form.save_token = self.save_token; form diff --git a/src/routes/cloud/get.rs b/src/routes/cloud/get.rs index 8298398..5f0e7f9 100644 --- a/src/routes/cloud/get.rs +++ b/src/routes/cloud/get.rs @@ -25,7 +25,7 @@ pub async fn item( Err(JsonResponse::not_found("record not found")) }, Some(cloud) => { - let cloud = Cloud::decode_model(cloud); + let cloud = Cloud::decode_model(cloud, false); Ok(JsonResponse::build().set_item(Some(cloud)).ok("OK")) }, None => Err(JsonResponse::not_found("record not found")), From 298bd0aa89c7af196471ce0a3a5c4e18abe632f7 Mon Sep 17 00:00:00 2001 From: vsilent Date: Wed, 27 Mar 2024 13:06:52 +0200 Subject: [PATCH 237/284] little of optimization, get rid of duplcates --- src/models/cloud.rs | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/src/models/cloud.rs b/src/models/cloud.rs index d0fd31b..3c2a752 100644 --- a/src/models/cloud.rs +++ b/src/models/cloud.rs @@ -15,30 +15,18 @@ pub struct Cloud { pub updated_at: DateTime, } - +fn mask_string(s: Option<&String>) -> String { + match s { + Some(val) => val.chars().take(4).collect::() + "****", + None => "".to_string(), + } +} impl std::fmt::Display for Cloud { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let cloud_key: String = match self.cloud_key.as_ref() { - Some(val) => - { - val.chars().take(4).collect::() + "****" - }, - None => "".to_string(), - }; - let cloud_token: String = match self.cloud_token.as_ref() { - Some(val) => { - val.chars().take(4).collect::() + "****" - }, - None => "".to_string(), - }; - - let cloud_secret: String = match self.cloud_secret.as_ref() { - Some(val) => { - val.chars().take(4).collect::() + "****" - } - None => "".to_string(), - }; + let cloud_key = mask_string(self.cloud_key.as_ref()); + let cloud_token = mask_string(self.cloud_token.as_ref()); + let cloud_secret = mask_string(self.cloud_secret.as_ref()); write!(f, "{} cloud creds: cloud_key : {} cloud_token: {} cloud_secret: {} project_id: {:?}", self.provider, From 9246620419795615b0d9013ff2ce3d301db6b653 Mon Sep 17 00:00:00 2001 From: vsilent Date: Wed, 27 Mar 2024 13:13:14 +0200 Subject: [PATCH 238/284] reduce repetition and improving readability --- src/forms/cloud.rs | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/src/forms/cloud.rs b/src/forms/cloud.rs index 79515c5..debf975 100644 --- a/src/forms/cloud.rs +++ b/src/forms/cloud.rs @@ -127,6 +127,20 @@ impl std::fmt::Debug for Cloud { } } +fn encrypt_field( + secret: &mut Secret, + field_name: &str, + value: Option, +) -> Option { + if let Some(val) = value { + secret.field = field_name.to_owned(); + if let Ok(encrypted) = secret.encrypt(val) { + return Some(Secret::b64_encode(&encrypted)); + } + } + None +} + impl Into for &Cloud { fn into(self) -> models::Cloud { let mut cloud = models::Cloud::default(); @@ -138,25 +152,9 @@ impl Into for &Cloud { secret.user_id = self.user_id.clone().unwrap(); secret.project_id = self.project_id.unwrap(); - if let Some(val) = self.cloud_token.clone() { - secret.field = "cloud_token".to_owned(); - if let Ok(encrypted) = secret.encrypt(val) { - cloud.cloud_token = Some(Secret::b64_encode(&encrypted)); - }; - } - if let Some(val) = self.cloud_key.clone() { - secret.field = "cloud_key".to_owned(); - if let Ok(encrypted) = secret.encrypt(val) { - // cloud.cloud_token = Some(encrypted.data.iter().map(|&c| c as char).collect::()) - cloud.cloud_key = Some(Secret::b64_encode(&encrypted)); - }; - } - if let Some(val) = self.cloud_secret.clone() { - secret.field = "cloud_secret".to_owned(); - if let Ok(encrypted) = secret.encrypt(val) { - cloud.cloud_secret = Some(Secret::b64_encode(&encrypted)) - }; - } + cloud.cloud_token = encrypt_field(&mut secret, "cloud_token", self.cloud_token.clone()); + cloud.cloud_key = encrypt_field(&mut secret, "cloud_key", self.cloud_key.clone()); + cloud.cloud_secret = encrypt_field(&mut secret, "cloud_secret", self.cloud_secret.clone()); cloud.save_token = self.save_token.clone(); cloud From 6e46901dada60869a67624d02919ad62425b8e91 Mon Sep 17 00:00:00 2001 From: vsilent Date: Wed, 27 Mar 2024 14:08:29 +0200 Subject: [PATCH 239/284] reduce repetition and improving readability --- src/forms/cloud.rs | 48 +++++++++++++++++---------------------- tests/mock_data/README.md | 10 ++++++++ 2 files changed, 31 insertions(+), 27 deletions(-) create mode 100644 tests/mock_data/README.md diff --git a/src/forms/cloud.rs b/src/forms/cloud.rs index debf975..2cdf633 100644 --- a/src/forms/cloud.rs +++ b/src/forms/cloud.rs @@ -55,39 +55,33 @@ impl Cloud { } } + pub(crate) fn decrypt_field( + secret: &mut Secret, + field_name: &str, + encrypted_value: Option, + reveal: bool, + ) -> Option { + if let Some(val) = encrypted_value { + secret.field = field_name.to_owned(); + let decoded_value = Cloud::decode(secret, val); + if reveal { + return Some(decoded_value); + } else { + return Some(hide_parts(decoded_value)); + } + } + None + } + // @todo should be refactored, may be moved to cloud.into() or Secret::from() pub(crate) fn decode_model(mut cloud: models::Cloud, reveal:bool) -> models::Cloud { - let encrypted_value = cloud.cloud_token.clone().unwrap(); let mut secret = Secret::new(); secret.user_id = cloud.user_id.clone(); secret.project_id = cloud.project_id.clone().unwrap(); - - secret.field = "cloud_token".to_string(); - let cloud_token = Cloud::decode(&mut secret, encrypted_value); - if reveal { - cloud.cloud_token = Some(cloud_token); - } else { - cloud.cloud_token = Some(hide_parts(cloud_token)); - } - - secret.field = "cloud_secret".to_string(); - let encrypted_value = cloud.cloud_secret.clone().unwrap(); - let cloud_secret = Cloud::decode(&mut secret, encrypted_value); - if reveal { - cloud.cloud_secret = Some(cloud_secret); - } else { - cloud.cloud_secret = Some(hide_parts(cloud_secret)); - } - - secret.field = "cloud_key".to_string(); - let encrypted_value = cloud.cloud_key.clone().unwrap(); - let cloud_key = Cloud::decode(&mut secret, encrypted_value); - if reveal { - cloud.cloud_key = Some(cloud_key); - } else { - cloud.cloud_key = Some(hide_parts(cloud_key)); - } + cloud.cloud_token = Cloud::decrypt_field(&mut secret, "cloud_token", cloud.cloud_token.clone(), reveal); + cloud.cloud_secret = Cloud::decrypt_field(&mut secret, "cloud_secret", cloud.cloud_secret.clone(), reveal); + cloud.cloud_key = Cloud::decrypt_field(&mut secret, "cloud_key", cloud.cloud_key.clone(), reveal); cloud } diff --git a/tests/mock_data/README.md b/tests/mock_data/README.md new file mode 100644 index 0000000..4321e92 --- /dev/null +++ b/tests/mock_data/README.md @@ -0,0 +1,10 @@ +This directory contains mock data for different endpoints + +Here is some examples of making requests using CURL + +Add new cloud credentials +curl -X POST -v http://localhost:8000/cloud -d @cloud.json --header 'Content-Type: application/json' -H "Authorization: Bearer $TD_BEARER" + +Get cloud credentials +curl -X GET http://localhost:8000/cloud/31 --header 'Content-Type: application/json' -H "Authorization: Bearer $TD_BEARER" + From 62ce2d8095a5d48dcb989ed4f51837090763b70c Mon Sep 17 00:00:00 2001 From: vsilent Date: Wed, 27 Mar 2024 16:25:54 +0200 Subject: [PATCH 240/284] user project list --- src/routes/project/get.rs | 15 +++++++++++++++ src/startup.rs | 1 + 2 files changed, 16 insertions(+) diff --git a/src/routes/project/get.rs b/src/routes/project/get.rs index aa03159..cc9da9c 100644 --- a/src/routes/project/get.rs +++ b/src/routes/project/get.rs @@ -27,6 +27,21 @@ pub async fn item( }) } + +#[tracing::instrument(name = "Get project list.")] +#[get("")] +pub async fn list( + user: web::ReqData>, + pg_pool: web::Data, +) -> Result { + db::project::fetch_by_user(pg_pool.get_ref(), &user.id) + .await + .map_err(|err| JsonResponse::internal_server_error(err)) + .map(|projects| JsonResponse::build().set_list(projects).ok("OK")) +} + + +//admin's endpoint #[tracing::instrument(name = "Get user's project list.")] #[get("/user/{id}")] pub async fn admin_list( diff --git a/src/startup.rs b/src/startup.rs index 6fa0f6c..a66b0e7 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -70,6 +70,7 @@ pub async fn run( .service(crate::routes::project::deploy::item) .service(crate::routes::project::deploy::saved_item) .service(crate::routes::project::compose::add) + .service(crate::routes::project::get::list) .service(crate::routes::project::get::item) .service(crate::routes::project::add::item) .service(crate::routes::project::update::item) From d1f40b75fea624b96bbf475b2d10f2f2a4a307b5 Mon Sep 17 00:00:00 2001 From: vsilent Date: Wed, 27 Mar 2024 19:37:14 +0200 Subject: [PATCH 241/284] redis creds to .env --- .env | 2 ++ src/forms/project/deploy.rs | 4 +++- src/helpers/cloud/security.rs | 6 +++++- src/routes/project/deploy.rs | 14 +++++++------- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/.env b/.env index 1dcbed0..0f19229 100644 --- a/.env +++ b/.env @@ -6,3 +6,5 @@ POSTGRES_PASSWORD=postgres POSTGRES_DB=stacker POSTGRES_PORT=5432 SECURITY_KEY=SECURITY_KEY_SHOULD_BE_OF_LEN_32 + +REDIS_URL=redis://127.0.0.1/ \ No newline at end of file diff --git a/src/forms/project/deploy.rs b/src/forms/project/deploy.rs index ae4c5e8..d0eee09 100644 --- a/src/forms/project/deploy.rs +++ b/src/forms/project/deploy.rs @@ -11,7 +11,9 @@ pub struct Deploy { #[validate] pub(crate) server: Server, #[validate] - pub(crate) cloud: Cloud + pub(crate) cloud: Cloud, + // pub user_id: Option, + // pub project_id: Option } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] diff --git a/src/helpers/cloud/security.rs b/src/helpers/cloud/security.rs index 29b997c..af1e256 100644 --- a/src/helpers/cloud/security.rs +++ b/src/helpers/cloud/security.rs @@ -27,7 +27,11 @@ impl Secret { } #[tracing::instrument(name = "Secret::connect_storage")] fn connect_storage() -> Connection { - match redis::Client::open("redis://127.0.0.1/"){ + + let storage_url = std::env::var("REDIS_URL") + .or_default("redis://127.0.0.1/".to_string()); + + match redis::Client::open(storage_url){ Ok(client) => { match client.get_connection() { Ok(connection) => connection, diff --git a/src/routes/project/deploy.rs b/src/routes/project/deploy.rs index 7cdbb43..b191465 100644 --- a/src/routes/project/deploy.rs +++ b/src/routes/project/deploy.rs @@ -17,7 +17,7 @@ use crate::helpers::compressor::compress; pub async fn item( user: web::ReqData>, path: web::Path<(i32,)>, - form: web::Json, + mut form: web::Json, pg_pool: Data, mq_manager: Data, sets: Data, @@ -49,10 +49,10 @@ pub async fn item( JsonResponse::::build().internal_server_error(err) })?; + form.cloud.user_id = Some(user.id.clone()); + form.cloud.project_id = Some(id); // Save cloud credentials if requested let mut cloud_creds: models::Cloud = (&form.cloud).into(); - cloud_creds.project_id = Some(id); - cloud_creds.user_id = user.id.clone(); if Some(true) == cloud_creds.save_token { db::cloud::insert(pg_pool.get_ref(), cloud_creds.clone()) @@ -105,7 +105,7 @@ pub async fn item( }); tracing::debug!("Save deployment result: {:?}", result); - tracing::debug!("Send project data <<<<<<<<<<<>>>>>>>>>>>>>>>>{:?}", payload); + tracing::debug!("Send project data <<<>>>{:?}", payload); // Send Payload mq_manager @@ -134,7 +134,7 @@ pub async fn saved_item( ) -> Result { let id = path.0; let cloud_id = path.1; - //let cloud_id = Some(1); + tracing::debug!("User {:?} is deploying project: {} to cloud: {} ", user, id, cloud_id); // Validate project @@ -173,7 +173,7 @@ pub async fn saved_item( // if let Some(server) = server.into_iter().nth(0) { // server // } - server.into_iter().nth(0).unwrap() // @todo refactoring is required + server.into_iter().nth(0).unwrap() //@todo refactoring is required for multiple types } Err(_e) => { return Err(JsonResponse::::build().not_found("No servers configured")); @@ -210,7 +210,7 @@ pub async fn saved_item( }); tracing::debug!("Save deployment result: {:?}", result); - tracing::debug!("Send project data <<<<<<<<<<<>>>>>>>>>>>>>>>>{:?}", payload); + tracing::debug!("Send project data <<<>>>{:?}", payload); // Send Payload mq_manager From 330732decc3873f3d73c809b8803493abcecc051 Mon Sep 17 00:00:00 2001 From: vsilent Date: Wed, 27 Mar 2024 19:44:41 +0200 Subject: [PATCH 242/284] fix unwrap_or redis creds to .env --- src/helpers/cloud/security.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/cloud/security.rs b/src/helpers/cloud/security.rs index af1e256..3c9d6b5 100644 --- a/src/helpers/cloud/security.rs +++ b/src/helpers/cloud/security.rs @@ -29,7 +29,7 @@ impl Secret { fn connect_storage() -> Connection { let storage_url = std::env::var("REDIS_URL") - .or_default("redis://127.0.0.1/".to_string()); + .unwrap_or("redis://127.0.0.1/".to_string()); match redis::Client::open(storage_url){ Ok(client) => { From 8edd78303cbf8b20bc87b08dcb6274de6ee8aa33 Mon Sep 17 00:00:00 2001 From: petru Date: Wed, 27 Mar 2024 22:01:17 +0200 Subject: [PATCH 243/284] casbin-debug policies --- Cargo.lock | 1 + Cargo.toml | 1 + src/console/commands/debug/casbin.rs | 9 +++++++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f04999e..c849d15 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3630,6 +3630,7 @@ dependencies = [ "actix-http", "actix-web", "brotli", + "casbin", "chrono", "clap", "config", diff --git a/Cargo.toml b/Cargo.toml index 982000f..d005e9b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,6 +58,7 @@ deadpool-lapin = "0.11.0" docker-compose-types = "0.7.0" #actix-casbin-auth = { git = "https://github.com/casbin-rs/actix-casbin-auth.git"} actix-casbin-auth = { git = "https://github.com/smart--petea/actix-casbin-auth.git", branch = "dirty-master"} +casbin = "2.2.0" [dependencies.sqlx] version = "0.6.3" diff --git a/src/console/commands/debug/casbin.rs b/src/console/commands/debug/casbin.rs index 6484cca..1987821 100644 --- a/src/console/commands/debug/casbin.rs +++ b/src/console/commands/debug/casbin.rs @@ -1,7 +1,8 @@ use crate::configuration::get_configuration; use actix_web::{rt, post, web, HttpResponse, Result, http::header::ContentType}; use crate::middleware; -use actix_casbin_auth::casbin::CoreApi; +//use actix_casbin_auth::casbin::CoreApi; +use casbin::CoreApi; use sqlx::PgPool; pub struct CasbinCommand { @@ -27,10 +28,14 @@ impl crate::console::commands::CallableTrait for CasbinCommand { let settings = web::Data::new(settings); let db_pool = web::Data::new(db_pool); + let mut authorizationService = middleware::authorization::try_new(settings.database.connection_string()).await?; let casbin_enforcer = authorizationService.get_enforcer(); let mut lock = casbin_enforcer.write().await; - match lock.enforce_mut(vec![self.subject.clone(), self.path.clone(), self.action.clone()]) { + let policies = lock.get_model().get_model().get("p").unwrap().get("p").unwrap().get_policy(); + println!("{}", policies.len()); + + match lock.enforce_mut(vec!["".to_string(), self.subject.clone(), self.path.clone(), self.action.clone()]) { Ok(true) => println!("TRUE"), Ok(false) => println!("FALSE"), Err(err) => { From 71edb3a48075123c39bbe6afede718b9f63d077f Mon Sep 17 00:00:00 2001 From: petru Date: Thu, 28 Mar 2024 23:10:46 +0200 Subject: [PATCH 244/284] casbin-debug print all rules --- src/console/commands/debug/casbin.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/console/commands/debug/casbin.rs b/src/console/commands/debug/casbin.rs index 1987821..2513727 100644 --- a/src/console/commands/debug/casbin.rs +++ b/src/console/commands/debug/casbin.rs @@ -33,6 +33,10 @@ impl crate::console::commands::CallableTrait for CasbinCommand { let casbin_enforcer = authorizationService.get_enforcer(); let mut lock = casbin_enforcer.write().await; let policies = lock.get_model().get_model().get("p").unwrap().get("p").unwrap().get_policy(); + for policy in policies { + println!("{policy:?}"); + } + println!("{}", policies.len()); match lock.enforce_mut(vec!["".to_string(), self.subject.clone(), self.path.clone(), self.action.clone()]) { From 82a9e1f9582ab9c251de9562bdaede30db61c9e9 Mon Sep 17 00:00:00 2001 From: vsilent Date: Sat, 30 Mar 2024 20:00:46 +0200 Subject: [PATCH 245/284] server updates --- src/db/cloud.rs | 9 ++- src/db/server.rs | 6 +- src/forms/cloud.rs | 134 +++++++++++++++++++++-------------- src/forms/project/deploy.rs | 6 +- src/forms/project/payload.rs | 2 +- src/forms/server.rs | 12 ++++ src/models/cloud.rs | 43 ++++++++++- src/models/server.rs | 2 +- src/models/user.rs | 2 - src/routes/cloud/add.rs | 6 +- src/routes/cloud/get.rs | 16 ++++- src/routes/cloud/update.rs | 2 +- src/routes/project/deploy.rs | 59 +++++++++++++-- src/routes/project/update.rs | 3 +- 14 files changed, 213 insertions(+), 89 deletions(-) diff --git a/src/db/cloud.rs b/src/db/cloud.rs index a5e71c2..77c840e 100644 --- a/src/db/cloud.rs +++ b/src/db/cloud.rs @@ -55,8 +55,9 @@ pub async fn insert(pool: &PgPool, mut cloud: models::Cloud) -> Result Result Result Result(value: &Option, s: S) -> Result -// where -// S: Serializer, -// { -// eprintln!("value in serde {:?}", value); -// let result: &str = match value { -// Some(value) => { -// let value = value.as_str(); -// value -// // value.into_iter().take(6).collect::() -// } -// None => "", -// }; -// s.serialize_str(result) -// } fn hide_parts(value: String) -> String { value.chars().into_iter().take(6).collect::() + "****" } - #[derive(Default, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Cloud { +pub struct CloudForm { pub user_id: Option, pub project_id: Option, #[validate(min_length = 2)] #[validate(max_length = 50)] pub provider: String, - // #[serde(serialize_with = "hide_part")] pub cloud_token: Option, - // #[serde(serialize_with = "hide_part")] pub cloud_key: Option, - // #[serde(serialize_with = "hide_part")] pub cloud_secret: Option, pub save_token: Option, } -impl Cloud { +impl CloudForm { + #[tracing::instrument(name = "impl CloudForm::decode()")] pub(crate) fn decode(secret: &mut Secret, encrypted_value: String) -> String { // tracing::error!("encrypted_value {:?}", &encrypted_value); let b64_decoded = Secret::b64_decode(&encrypted_value).unwrap(); + // tracing::error!("decoded {:?}", &b64_decoded); match secret.decrypt(b64_decoded) { Ok(decoded) => decoded, Err(_err) => { @@ -63,7 +47,7 @@ impl Cloud { ) -> Option { if let Some(val) = encrypted_value { secret.field = field_name.to_owned(); - let decoded_value = Cloud::decode(secret, val); + let decoded_value = CloudForm::decode(secret, val); if reveal { return Some(decoded_value); } else { @@ -74,20 +58,21 @@ impl Cloud { } // @todo should be refactored, may be moved to cloud.into() or Secret::from() - pub(crate) fn decode_model(mut cloud: models::Cloud, reveal:bool) -> models::Cloud { + #[tracing::instrument(name = "decode_model")] + pub fn decode_model(mut cloud: models::Cloud, reveal:bool) -> models::Cloud { let mut secret = Secret::new(); secret.user_id = cloud.user_id.clone(); secret.project_id = cloud.project_id.clone().unwrap(); - cloud.cloud_token = Cloud::decrypt_field(&mut secret, "cloud_token", cloud.cloud_token.clone(), reveal); - cloud.cloud_secret = Cloud::decrypt_field(&mut secret, "cloud_secret", cloud.cloud_secret.clone(), reveal); - cloud.cloud_key = Cloud::decrypt_field(&mut secret, "cloud_key", cloud.cloud_key.clone(), reveal); + cloud.cloud_token = CloudForm::decrypt_field(&mut secret, "cloud_token", cloud.cloud_token.clone(), reveal); + cloud.cloud_secret = CloudForm::decrypt_field(&mut secret, "cloud_secret", cloud.cloud_secret.clone(), reveal); + cloud.cloud_key = CloudForm::decrypt_field(&mut secret, "cloud_key", cloud.cloud_key.clone(), reveal); cloud } } -impl std::fmt::Debug for Cloud { +impl std::fmt::Debug for CloudForm { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let cloud_key: String = match self.cloud_key.as_ref() { Some(val) => @@ -135,22 +120,30 @@ fn encrypt_field( None } -impl Into for &Cloud { +impl Into for &CloudForm { + #[tracing::instrument(name = "impl Into for &CloudForm")] fn into(self) -> models::Cloud { let mut cloud = models::Cloud::default(); cloud.provider = self.provider.clone(); cloud.user_id = self.user_id.clone().unwrap(); cloud.project_id = self.project_id; - let mut secret = Secret::new(); - secret.user_id = self.user_id.clone().unwrap(); - secret.project_id = self.project_id.unwrap(); - - cloud.cloud_token = encrypt_field(&mut secret, "cloud_token", self.cloud_token.clone()); - cloud.cloud_key = encrypt_field(&mut secret, "cloud_key", self.cloud_key.clone()); - cloud.cloud_secret = encrypt_field(&mut secret, "cloud_secret", self.cloud_secret.clone()); + if Some(true) == self.save_token { + let mut secret = Secret::new(); + secret.user_id = self.user_id.clone().unwrap(); + secret.project_id = self.project_id.unwrap(); + + cloud.cloud_token = encrypt_field(&mut secret, "cloud_token", self.cloud_token.clone()); + cloud.cloud_key = encrypt_field(&mut secret, "cloud_key", self.cloud_key.clone()); + cloud.cloud_secret = encrypt_field(&mut secret, "cloud_secret", self.cloud_secret.clone()); + } else { + cloud.cloud_token = self.cloud_token.clone(); + cloud.cloud_key = self.cloud_key.clone(); + cloud.cloud_secret = self.cloud_secret.clone(); + } cloud.save_token = self.save_token.clone(); - + cloud.created_at = Utc::now(); + cloud.updated_at = Utc::now(); cloud } @@ -158,30 +151,61 @@ impl Into for &Cloud { // on deploy -impl Into for models::Cloud { - fn into(self) -> Cloud { - let mut form = Cloud::default(); +impl Into for models::Cloud { + #[tracing::instrument(name = "Into for models::Cloud .")] + fn into(self) -> CloudForm { + let mut form = CloudForm::default(); form.project_id = self.project_id; form.provider = self.provider; - let mut secret = Secret::new(); - secret.user_id = self.user_id.clone(); - secret.project_id = self.project_id.clone().unwrap(); - - secret.field = "cloud_token".to_string(); - let cloud_token = Cloud::decode(&mut secret, self.cloud_token.unwrap()); - form.cloud_token = Some(cloud_token); - - secret.field = "cloud_key".to_string(); - let cloud_key = Cloud::decode(&mut secret, self.cloud_key.unwrap()); - form.cloud_token = Some(cloud_key); - - secret.field = "cloud_secret".to_string(); - let cloud_secret = Cloud::decode(&mut secret, self.cloud_secret.unwrap()); - form.cloud_secret = Some(cloud_secret); + if Some(true) == self.save_token { + let mut secret = Secret::new(); + secret.user_id = self.user_id.clone(); + secret.project_id = self.project_id.unwrap(); + secret.field = "cloud_token".to_string(); + + let value = match self.cloud_token { + Some(value) => { + CloudForm::decode(&mut secret, value) + } + None => { + tracing::debug!("Skip {}", secret.field); + "".to_string() + } + }; + form.cloud_token = Some(value); + + secret.field = "cloud_key".to_string(); + let value = match self.cloud_key { + Some(value) => { + CloudForm::decode(&mut secret, value) + } + None => { + tracing::debug!("Skipp {}", secret.field); + "".to_string() + } + }; + form.cloud_key = Some(value); + + secret.field = "cloud_secret".to_string(); + let value = match self.cloud_secret { + Some(value) => { + CloudForm::decode(&mut secret, value) + } + None => { + tracing::debug!("Skipp {}", secret.field); + "".to_string() + } + }; + form.cloud_secret = Some(value); + + } else { + form.cloud_token = self.cloud_token; + form.cloud_key = self.cloud_key; + form.cloud_secret = self.cloud_secret; + } form.save_token = self.save_token; - form } } diff --git a/src/forms/project/deploy.rs b/src/forms/project/deploy.rs index d0eee09..86c1453 100644 --- a/src/forms/project/deploy.rs +++ b/src/forms/project/deploy.rs @@ -2,7 +2,7 @@ use serde_derive::{Deserialize, Serialize}; use serde_json::Value; use serde_valid::Validate; use crate::forms; -use crate::forms::{Cloud, Server}; +use crate::forms::{CloudForm, Server}; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Deploy { @@ -11,9 +11,7 @@ pub struct Deploy { #[validate] pub(crate) server: Server, #[validate] - pub(crate) cloud: Cloud, - // pub user_id: Option, - // pub project_id: Option + pub(crate) cloud: CloudForm, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] diff --git a/src/forms/project/payload.rs b/src/forms/project/payload.rs index d7e84d4..5eb115a 100644 --- a/src/forms/project/payload.rs +++ b/src/forms/project/payload.rs @@ -12,7 +12,7 @@ pub struct Payload { pub(crate) user_token: Option, pub(crate) user_email: Option, #[serde(flatten)] - pub cloud: Option, + pub cloud: Option, #[serde(flatten)] pub server: Option, #[serde(flatten)] diff --git a/src/forms/server.rs b/src/forms/server.rs index cba997f..8b78c14 100644 --- a/src/forms/server.rs +++ b/src/forms/server.rs @@ -29,6 +29,18 @@ impl Into for &Server { } } +// impl From for models::Server { +// fn from(self, value: Server) -> &mut Self { +// self.disk_type = value.disk_type.clone(); +// self.region = value.region.clone(); +// self.server = value.server.clone(); +// self.zone = value.zone.clone(); +// self.os = value.os.clone(); +// self.updated_at = Utc::now(); +// self +// } +// } + impl Into for models::Server { fn into(self) -> Server { diff --git a/src/models/cloud.rs b/src/models/cloud.rs index 3c2a752..77c3224 100644 --- a/src/models/cloud.rs +++ b/src/models/cloud.rs @@ -1,7 +1,7 @@ use chrono::{DateTime, Utc}; use serde_derive::{Deserialize, Serialize}; -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Cloud { pub id: i32, pub user_id: String, @@ -37,3 +37,44 @@ impl std::fmt::Display for Cloud { ) } } + +impl Cloud { + pub fn new(user_id: String, + project_id: Option, + provider: String, + cloud_token: Option, + cloud_key: Option, + cloud_secret: Option, + save_token: Option + ) -> Self { + Self { + id: 0, + user_id, + project_id, + provider, + cloud_token, + cloud_key, + cloud_secret, + save_token, + created_at: Utc::now(), + updated_at: Utc::now(), + } + } +} + +impl Default for Cloud { + fn default() -> Self { + Cloud { + id: 0, + provider: "".to_string(), + user_id: "".to_string(), + project_id: Default::default(), + cloud_key: Default::default(), + cloud_token: Default::default(), + cloud_secret: Default::default(), + save_token: Some(false), + created_at: Default::default(), + updated_at: Default::default(), + } + } +} diff --git a/src/models/server.rs b/src/models/server.rs index 3827fcf..3e575a1 100644 --- a/src/models/server.rs +++ b/src/models/server.rs @@ -24,4 +24,4 @@ pub struct Server { pub disk_type: Option, pub created_at: DateTime, pub updated_at: DateTime, -} +} \ No newline at end of file diff --git a/src/models/user.rs b/src/models/user.rs index 8217ac8..2111143 100644 --- a/src/models/user.rs +++ b/src/models/user.rs @@ -7,6 +7,4 @@ pub struct User { pub last_name: String, pub email: String, pub email_confirmed: bool, - // pub phone: Option, - // pub website: Option, } diff --git a/src/routes/cloud/add.rs b/src/routes/cloud/add.rs index ce4126f..ebd261e 100644 --- a/src/routes/cloud/add.rs +++ b/src/routes/cloud/add.rs @@ -15,7 +15,7 @@ use tracing::Instrument; #[post("")] pub async fn add( user: web::ReqData>, - mut form: web::Json, + mut form: web::Json, pg_pool: web::Data, ) -> Result { @@ -28,9 +28,7 @@ pub async fn add( } form.user_id = Some(user.id.clone()); - let mut cloud: models::Cloud = form.deref().into(); - cloud.created_at = Utc::now(); - cloud.updated_at = Utc::now(); + let cloud: models::Cloud = form.deref().into(); db::cloud::insert(pg_pool.get_ref(), cloud) .await diff --git a/src/routes/cloud/get.rs b/src/routes/cloud/get.rs index 5f0e7f9..43ac801 100644 --- a/src/routes/cloud/get.rs +++ b/src/routes/cloud/get.rs @@ -4,7 +4,7 @@ use crate::helpers::JsonResponse; use crate::models; use actix_web::{get, web, Responder, Result}; use sqlx::PgPool; -use crate::forms::Cloud; +use crate::forms::CloudForm; use tracing::Instrument; #[tracing::instrument(name = "Get cloud credentials.")] @@ -25,7 +25,7 @@ pub async fn item( Err(JsonResponse::not_found("record not found")) }, Some(cloud) => { - let cloud = Cloud::decode_model(cloud, false); + let cloud = CloudForm::decode_model(cloud, false); Ok(JsonResponse::build().set_item(Some(cloud)).ok("OK")) }, None => Err(JsonResponse::not_found("record not found")), @@ -43,6 +43,16 @@ pub async fn list( ) -> Result { db::cloud::fetch_by_user(pg_pool.get_ref(), user.id.as_ref()) .await - .map(|clouds| JsonResponse::build().set_list(clouds).ok("OK")) + .map(|clouds| { + + let clouds = clouds + .into_iter() + .map(|cloud| CloudForm::decode_model(cloud, false) ) + // .map_err(|e| tracing::error!("Failed to decode cloud, {:?}", e)) + .collect(); + + JsonResponse::build().set_list(clouds).ok("OK") + + }) .map_err(|_err| JsonResponse::::build().internal_server_error("")) } diff --git a/src/routes/cloud/update.rs b/src/routes/cloud/update.rs index 3c60360..7672f55 100644 --- a/src/routes/cloud/update.rs +++ b/src/routes/cloud/update.rs @@ -14,7 +14,7 @@ use chrono::Utc; #[put("/{id}")] pub async fn item( path: web::Path<(i32,)>, - form: web::Json, + form: web::Json, user: web::ReqData>, pg_pool: Data, ) -> Result { diff --git a/src/routes/project/deploy.rs b/src/routes/project/deploy.rs index b191465..3a9bea3 100644 --- a/src/routes/project/deploy.rs +++ b/src/routes/project/deploy.rs @@ -9,6 +9,7 @@ use sqlx::PgPool; use std::sync::Arc; use serde_valid::Validate; use crate::helpers::compressor::compress; +use chrono::{Utc}; @@ -52,7 +53,9 @@ pub async fn item( form.cloud.user_id = Some(user.id.clone()); form.cloud.project_id = Some(id); // Save cloud credentials if requested - let mut cloud_creds: models::Cloud = (&form.cloud).into(); + let cloud_creds: models::Cloud = (&form.cloud).into(); + + // let cloud_creds = forms::Cloud::decode_model(cloud_creds, false); if Some(true) == cloud_creds.save_token { db::cloud::insert(pg_pool.get_ref(), cloud_creds.clone()) @@ -127,6 +130,7 @@ pub async fn item( #[post("/{id}/deploy/{cloud_id}")] pub async fn saved_item( user: web::ReqData>, + mut form: web::Json, path: web::Path<(i32, i32)>, pg_pool: Data, mq_manager: Data, @@ -137,6 +141,14 @@ pub async fn saved_item( tracing::debug!("User {:?} is deploying project: {} to cloud: {} ", user, id, cloud_id); + if !form.validate().is_ok() { + let errors = form.validate().unwrap_err().to_string(); + let err_msg = format!("Invalid form data received {:?}", &errors); + tracing::debug!(err_msg); + + return Err(JsonResponse::::build().form_error(errors)); + } + // Validate project let project = db::project::fetch(pg_pool.get_ref(), id) .await @@ -169,26 +181,56 @@ pub async fn saved_item( let server = match db::server::fetch_by_project(pg_pool.get_ref(), dc.project.id.clone()).await { Ok(server) => { - // for now we support only one type of servers - // if let Some(server) = server.into_iter().nth(0) { - // server - // } - server.into_iter().nth(0).unwrap() //@todo refactoring is required for multiple types + // currently we support only one type of servers + //@todo multiple server types support + match server.into_iter().nth(0) { + Some(mut server) => { + // new updates + server.disk_type = form.server.disk_type.clone(); + server.region = form.server.region.clone(); + server.server = form.server.server.clone(); + server.zone = form.server.zone.clone(); + server.os = form.server.os.clone(); + server.user_id = user.id.clone(); + server.project_id = id; + server + }, + None => { + // Create new server + let mut server: models::Server = (&form.server).into(); + server.user_id = user.id.clone(); + server.project_id = id; + db::server::insert(pg_pool.get_ref(), server) + .await + .map(|server| server) + .map_err(|_| { + JsonResponse::::build().internal_server_error("Internal Server Error") + })? + } + } } Err(_e) => { return Err(JsonResponse::::build().not_found("No servers configured")); } }; + let server = db::server::update(pg_pool.get_ref(), server) + .await + .map(|server| server) + .map_err(|_| { + JsonResponse::::build().internal_server_error("Internal Server Error") + })?; + + // Building Payload for the 3-d party service through RabbitMQ // let mut payload = forms::project::Payload::default(); let mut payload = forms::project::Payload::try_from(&dc.project) .map_err(|err| JsonResponse::::build().bad_request(err))?; payload.server = Some(server.into()); payload.cloud = Some(cloud.into()); + payload.stack = form.stack.clone().into(); payload.user_token = Some(user.id.clone()); payload.user_email = Some(user.email.clone()); - // let compressed = fc.unwrap_or("".to_string()); payload.docker_compose = Some(compress(fc.as_str())); // Store deployment attempts into deployment table in db @@ -228,3 +270,6 @@ pub async fn saved_item( }) } + + + diff --git a/src/routes/project/update.rs b/src/routes/project/update.rs index 3e1bb19..cdd532e 100644 --- a/src/routes/project/update.rs +++ b/src/routes/project/update.rs @@ -42,7 +42,8 @@ pub async fn item( let project_name = form.custom.custom_stack_code.clone(); if Ok(false) == form.is_readable_docker_image().await { - return Err(JsonResponse::::build().bad_request("Can not access docker image")); + return Err(JsonResponse::::build() + .bad_request("Can not access docker image")); } let body: Value = serde_json::to_value::(form) From 75d2c4dbc8386e4d65193dd51340915f09979ad0 Mon Sep 17 00:00:00 2001 From: vsilent Date: Sat, 30 Mar 2024 20:12:55 +0200 Subject: [PATCH 246/284] Check casbin rule command, readme --- README.md | 6 +++++- src/console/commands/debug/casbin.rs | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 09f466f..ad44ea7 100644 --- a/README.md +++ b/README.md @@ -84,4 +84,8 @@ curl -X POST -H "Content-Type: application/json" -d @custom-stack-payload-2.json curl -X POST http://localhost:8000/client --header 'Content-Type: application/json' -H "Authorization: Bearer $TD_BEARER" test client deploy -http://localhost:8000/test/deploy \ No newline at end of file +http://localhost:8000/test/deploy + + +Test casbin rule +cargo r --bin console debug casbin --path "/project/:id" --action "POST" --subject "hy181TZa4DaabUZWklsrxw" \ No newline at end of file diff --git a/src/console/commands/debug/casbin.rs b/src/console/commands/debug/casbin.rs index 2513727..b05fb2e 100644 --- a/src/console/commands/debug/casbin.rs +++ b/src/console/commands/debug/casbin.rs @@ -39,7 +39,7 @@ impl crate::console::commands::CallableTrait for CasbinCommand { println!("{}", policies.len()); - match lock.enforce_mut(vec!["".to_string(), self.subject.clone(), self.path.clone(), self.action.clone()]) { + match lock.enforce_mut(vec![self.subject.clone(), self.path.clone(), self.action.clone()]) { Ok(true) => println!("TRUE"), Ok(false) => println!("FALSE"), Err(err) => { From 865882d744c13d129bd87d5df3bca4b15c0e2d3a Mon Sep 17 00:00:00 2001 From: vsilent Date: Sat, 30 Mar 2024 20:41:27 +0200 Subject: [PATCH 247/284] enable casbin, use security key from env --- src/helpers/cloud/security.rs | 19 +++++++++---------- src/startup.rs | 2 +- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/helpers/cloud/security.rs b/src/helpers/cloud/security.rs index 3c9d6b5..2e38994 100644 --- a/src/helpers/cloud/security.rs +++ b/src/helpers/cloud/security.rs @@ -84,12 +84,12 @@ impl Secret { #[tracing::instrument(name = "encrypt.")] pub fn encrypt(&self, token: String) -> Result, String> { - // let sec_key = std::env::var("SECURITY_KEY") - // .expect("SECURITY_KEY environment variable is not set") - // .as_bytes(); - let sec_key = "SECURITY_KEY_SHOULD_BE_OF_LEN_32".as_bytes(); + let sec_key = std::env::var("SECURITY_KEY") + .expect("SECURITY_KEY environment variable is not set") + .clone(); + // let key = Aes256Gcm::generate_key(OsRng); - let key: &Key:: = Key::::from_slice(&sec_key); + let key: &Key:: = Key::::from_slice(&sec_key.as_bytes()); // eprintln!("encrypt key {key:?}"); // eprintln!("encrypt: from slice key {key:?}"); let cipher = Aes256Gcm::new(&key); @@ -113,11 +113,10 @@ impl Secret { #[tracing::instrument(name = "decrypt.")] pub fn decrypt(&mut self, encrypted_data: Vec) -> Result { - let sec_key = "SECURITY_KEY_SHOULD_BE_OF_LEN_32".as_bytes(); - // let sec_key = std::env::var("SECURITY_KEY") - // .expect("SECURITY_KEY environment variable is not set") - // .as_bytes(); - let key: &Key:: = Key::::from_slice(&sec_key); + let sec_key = std::env::var("SECURITY_KEY") + .expect("SECURITY_KEY environment variable is not set") + .clone(); + let key: &Key:: = Key::::from_slice(&sec_key.as_bytes()); // eprintln!("decrypt: Key str {key:?}"); let rkey = format!("{}_{}_{}", self.user_id, self.project_id, self.field); eprintln!("decrypt: Key str {rkey:?}"); diff --git a/src/startup.rs b/src/startup.rs index a66b0e7..302070d 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -42,7 +42,7 @@ pub async fn run( let server = HttpServer::new(move || { App::new() .wrap(TracingLogger::default()) - // .wrap(authorization.clone()) + .wrap(authorization.clone()) .wrap(middleware::authentication::Manager::new()) .wrap(Cors::permissive()) .service( From 45839648c4356f4433c2708091bc97ab35e9cf79 Mon Sep 17 00:00:00 2001 From: vsilent Date: Mon, 1 Apr 2024 13:34:53 +0300 Subject: [PATCH 248/284] initial casbin rules --- docker-compose.yml | 2 +- docker/dev/docker-compose.yml | 2 +- ...240401103123_casbin_initial_rules.down.sql | 1 + ...20240401103123_casbin_initial_rules.up.sql | 30 +++++++++++++++++++ src/console/commands/appclient/new.rs | 1 + src/forms/user.rs | 2 ++ .../authentication/method/f_oauth.rs | 7 +++-- src/models/user.rs | 1 + src/routes/project/deploy.rs | 1 + 9 files changed, 42 insertions(+), 5 deletions(-) create mode 100644 migrations/20240401103123_casbin_initial_rules.down.sql create mode 100644 migrations/20240401103123_casbin_initial_rules.up.sql diff --git a/docker-compose.yml b/docker-compose.yml index 4ba581c..808216e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ volumes: services: stacker: - image: trydirect/stacker:0.0.7 + image: trydirect/stacker:0.0.8 build: . container_name: stacker restart: always diff --git a/docker/dev/docker-compose.yml b/docker/dev/docker-compose.yml index eeac038..af707ba 100644 --- a/docker/dev/docker-compose.yml +++ b/docker/dev/docker-compose.yml @@ -16,7 +16,7 @@ networks: services: stacker: - image: trydirect/stacker:0.0.7 + image: trydirect/stacker:0.0.8 build: . container_name: stacker restart: always diff --git a/migrations/20240401103123_casbin_initial_rules.down.sql b/migrations/20240401103123_casbin_initial_rules.down.sql new file mode 100644 index 0000000..d2f607c --- /dev/null +++ b/migrations/20240401103123_casbin_initial_rules.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/migrations/20240401103123_casbin_initial_rules.up.sql b/migrations/20240401103123_casbin_initial_rules.up.sql new file mode 100644 index 0000000..cbd0669 --- /dev/null +++ b/migrations/20240401103123_casbin_initial_rules.up.sql @@ -0,0 +1,30 @@ +-- Add up migration script here +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (1, 'p', 'group_admin', '/client', 'POST', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (2, 'g', 'admin_petru', 'group_admin', '', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (3, 'g', 'user_petru', 'group_user', '', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (4, 'p', 'group_user', '/client/:id/disable', 'PUT', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (5, 'p', 'group_admin', '/admin/client/:id/disable', 'PUT', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (6, 'p', 'group_admin', '/admin/client/:id/enable', 'PUT', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (7, 'p', 'group_user', '/client/:id/enable', 'PUT', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (8, 'p', 'group_user', '/client/:id', 'PUT', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (9, 'p', 'group_admin', '/admin/client/:id', 'PUT', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (10, 'g', 'anonym', 'group_anonymous', '', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (11, 'p', 'group_anonymous', '/health_check', 'GET', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (12, 'p', 'group_anonymous', '/rating/:id', 'GET', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (13, 'p', 'group_user', '/rating/:id', 'GET', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (14, 'p', 'group_admin', '/rating/:id', 'GET', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (15, 'p', 'group_user', '/rating', 'GET', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (16, 'p', 'group_admin', '/rating', 'GET', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (17, 'p', 'group_anonymous', '/rating', 'GET', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (18, 'p', 'group_user', '/rating', 'POST', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (19, 'p', 'group_admin', '/admin/project/user/:userid', 'GET', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (21, 'p', 'group_user', '/project', 'POST', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (33, 'g', 'group_admin', 'group_anonymous', '', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (34, 'g', 'group_user', 'group_anonymous', '', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (37, 'p', 'group_user', '/project/:id', 'GET', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (36, 'p', 'group_user', '/project/:id/compose', 'GET', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (38, 'p', 'group_user', '/project/:id/deploy', 'POST', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (39, 'p', 'group_user', '/project', 'GET', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (40, 'g', 'user', 'group_user', '', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (41, 'p', 'group_user', '/project/:id/deploy/:cloud_id', 'POST', '', '', ''); + diff --git a/src/console/commands/appclient/new.rs b/src/console/commands/appclient/new.rs index ada01ac..accbd76 100644 --- a/src/console/commands/appclient/new.rs +++ b/src/console/commands/appclient/new.rs @@ -31,6 +31,7 @@ impl crate::console::commands::CallableTrait for NewCommand { last_name: "last_name".to_string(), email: "email".to_string(), email_confirmed: true, + role: "role".to_string() }; crate::routes::client::add_handler_inner(&user.id, settings, db_pool).await?; diff --git a/src/forms/user.rs b/src/forms/user.rs index 5a7fa48..0c58d75 100644 --- a/src/forms/user.rs +++ b/src/forms/user.rs @@ -56,6 +56,7 @@ pub struct User { pub deployments_left: Value, #[serde(rename = "suspension_hints")] pub suspension_hints: Option, + pub role: String } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -137,6 +138,7 @@ impl TryInto for UserForm { last_name: self.user.last_name.unwrap_or("Noname".to_string()), email: self.user.email, email_confirmed: self.user.email_confirmed, + role: self.user.role }) } diff --git a/src/middleware/authentication/method/f_oauth.rs b/src/middleware/authentication/method/f_oauth.rs index 8400e81..cec47b4 100644 --- a/src/middleware/authentication/method/f_oauth.rs +++ b/src/middleware/authentication/method/f_oauth.rs @@ -14,7 +14,8 @@ fn try_extract_token(authentication: String) -> Result { } let token = authentication_parts.next(); if token.is_none() { - return Err("Empty bearer token".to_string()); + tracing::error!("Bearer token is missing"); + return Err("Authentication required".to_string()); } Ok(token.unwrap().into()) @@ -33,9 +34,9 @@ pub async fn try_oauth(req: &mut ServiceRequest) -> Result { .await .map_err(|err| format!("{err}"))?; - // println!("user ================== {}", user.id.clone()); + // control access using user role let acl_vals = actix_casbin_auth::CasbinVals { - subject: user.id.clone(), + subject: user.role.clone(), domain: None, }; diff --git a/src/models/user.rs b/src/models/user.rs index 2111143..0f6b1ef 100644 --- a/src/models/user.rs +++ b/src/models/user.rs @@ -6,5 +6,6 @@ pub struct User { pub first_name: String, pub last_name: String, pub email: String, + pub role: String, pub email_confirmed: bool, } diff --git a/src/routes/project/deploy.rs b/src/routes/project/deploy.rs index 3a9bea3..661115e 100644 --- a/src/routes/project/deploy.rs +++ b/src/routes/project/deploy.rs @@ -197,6 +197,7 @@ pub async fn saved_item( }, None => { // Create new server + // form.update_with(server.into()); let mut server: models::Server = (&form.server).into(); server.user_id = user.id.clone(); server.project_id = id; From 3e50dcbe3a3c10f8072432cd766697e9d6980143 Mon Sep 17 00:00:00 2001 From: vsilent Date: Mon, 1 Apr 2024 13:38:22 +0300 Subject: [PATCH 249/284] initial casbin rules --- docker/dev/docker-compose.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docker/dev/docker-compose.yml b/docker/dev/docker-compose.yml index af707ba..6f8c0ab 100644 --- a/docker/dev/docker-compose.yml +++ b/docker/dev/docker-compose.yml @@ -4,7 +4,7 @@ volumes: stackerdb: driver: local - redis-data: + stacker-redis-data: driver: local networks: @@ -13,6 +13,7 @@ networks: name: backend external: true + services: stacker: @@ -32,7 +33,7 @@ services: - ./.env environment: - RUST_LOG=debug - - RUST_BACKTRACE=1 + - RUST_BACKTRACE=full depends_on: stackerdb: condition: service_healthy @@ -79,14 +80,14 @@ services: networks: - backend - redis: + stackerredis: container_name: stackerredis image: redis:latest restart: always ports: - - 6379 + - 127.0.0.1:6379:6379 volumes: - - redis-data:/data + - stacker-redis-data:/data # - ./redis/rc.local:/etc/rc.local # - ./redis/redis.conf:/usr/local/etc/redis/redis.conf sysctls: From 820f52232703b3e7464c0e1fd618db437f660b92 Mon Sep 17 00:00:00 2001 From: vsilent Date: Mon, 1 Apr 2024 22:13:45 +0300 Subject: [PATCH 250/284] remove project_id from cloud, as cloud keys can be use across projects --- Dockerfile | 5 -- ...20240401103123_casbin_initial_rules.up.sql | 70 +++++++++++-------- ...4313_remove_project_id_from_cloud.down.sql | 2 + ...184313_remove_project_id_from_cloud.up.sql | 3 + src/console/commands/appclient/new.rs | 2 +- src/db/cloud.rs | 16 ++--- src/forms/cloud.rs | 11 ++- src/forms/project/deploy.rs | 4 +- src/forms/project/payload.rs | 2 +- src/forms/server.rs | 22 ++---- src/helpers/cloud/security.rs | 8 +-- .../authentication/method/f_oauth.rs | 1 + src/models/cloud.rs | 7 +- src/routes/project/deploy.rs | 4 +- src/routes/server/update.rs | 2 +- 15 files changed, 76 insertions(+), 83 deletions(-) create mode 100644 migrations/20240401184313_remove_project_id_from_cloud.down.sql create mode 100644 migrations/20240401184313_remove_project_id_from_cloud.up.sql diff --git a/Dockerfile b/Dockerfile index 66222d1..8d969e7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -31,11 +31,6 @@ COPY ./src ./src #RUN sqlx migrate run #RUN cargo sqlx prepare -- --bin stacker -# rebuild app with project source -#RUN rm -rf ./target/release/deps/server*; \ -# apt-get install --no-install-recommends -y libssl-dev; \ -# cargo build --release - RUN apt-get update && apt-get install --no-install-recommends -y libssl-dev; \ cargo build --bin=console && cargo build --release diff --git a/migrations/20240401103123_casbin_initial_rules.up.sql b/migrations/20240401103123_casbin_initial_rules.up.sql index cbd0669..effa703 100644 --- a/migrations/20240401103123_casbin_initial_rules.up.sql +++ b/migrations/20240401103123_casbin_initial_rules.up.sql @@ -1,30 +1,42 @@ --- Add up migration script here -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (1, 'p', 'group_admin', '/client', 'POST', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (2, 'g', 'admin_petru', 'group_admin', '', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (3, 'g', 'user_petru', 'group_user', '', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (4, 'p', 'group_user', '/client/:id/disable', 'PUT', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (5, 'p', 'group_admin', '/admin/client/:id/disable', 'PUT', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (6, 'p', 'group_admin', '/admin/client/:id/enable', 'PUT', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (7, 'p', 'group_user', '/client/:id/enable', 'PUT', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (8, 'p', 'group_user', '/client/:id', 'PUT', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (9, 'p', 'group_admin', '/admin/client/:id', 'PUT', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (10, 'g', 'anonym', 'group_anonymous', '', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (11, 'p', 'group_anonymous', '/health_check', 'GET', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (12, 'p', 'group_anonymous', '/rating/:id', 'GET', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (13, 'p', 'group_user', '/rating/:id', 'GET', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (14, 'p', 'group_admin', '/rating/:id', 'GET', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (15, 'p', 'group_user', '/rating', 'GET', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (16, 'p', 'group_admin', '/rating', 'GET', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (17, 'p', 'group_anonymous', '/rating', 'GET', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (18, 'p', 'group_user', '/rating', 'POST', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (19, 'p', 'group_admin', '/admin/project/user/:userid', 'GET', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (21, 'p', 'group_user', '/project', 'POST', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (33, 'g', 'group_admin', 'group_anonymous', '', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (34, 'g', 'group_user', 'group_anonymous', '', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (37, 'p', 'group_user', '/project/:id', 'GET', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (36, 'p', 'group_user', '/project/:id/compose', 'GET', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (38, 'p', 'group_user', '/project/:id/deploy', 'POST', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (39, 'p', 'group_user', '/project', 'GET', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (40, 'g', 'user', 'group_user', '', '', '', ''); -INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (41, 'p', 'group_user', '/project/:id/deploy/:cloud_id', 'POST', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (1, 'g', 'anonym', 'group_anonymous', '', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (2, 'g', 'group_admin', 'group_anonymous', '', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (3, 'g', 'group_user', 'group_anonymous', '', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (4, 'g', 'user', 'group_user', '', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (5, 'g', 'admin_petru', 'group_admin', '', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (6, 'g', 'user_petru', 'group_user', '', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (7, 'p', 'group_anonymous', '/health_check', 'GET', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (8, 'p', 'group_anonymous', '/rating/:id', 'GET', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (9, 'p', 'group_anonymous', '/rating', 'GET', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (10, 'p', 'group_admin', '/client', 'POST', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (11, 'p', 'group_admin', '/rating', 'GET', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (12, 'p', 'group_admin', '/admin/client/:id/disable', 'PUT', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (13, 'p', 'group_admin', '/admin/client/:id/enable', 'PUT', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (14, 'p', 'group_admin', '/admin/client/:id', 'PUT', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (15, 'p', 'group_admin', '/admin/project/user/:userid', 'GET', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (16, 'p', 'group_admin', '/rating/:id', 'GET', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (17, 'p', 'group_user', '/client/:id/enable', 'PUT', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (18, 'p', 'group_user', '/client/:id', 'PUT', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (19, 'p', 'group_user', '/client/:id/disable', 'PUT', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (20, 'p', 'group_user', '/rating/:id', 'GET', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (21, 'p', 'group_user', '/rating', 'GET', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (22, 'p', 'group_user', '/rating', 'POST', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (23, 'p', 'group_user', '/project', 'GET', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (24, 'p', 'group_user', '/project', 'POST', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (25, 'p', 'group_user', '/project/:id', 'GET', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (26, 'p', 'group_user', '/project/:id', 'POST', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (27, 'p', 'group_user', '/project/:id', 'PUT', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (28, 'p', 'group_user', '/project/:id', 'DELETE', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (29, 'p', 'group_user', '/project/:id/compose', 'GET', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (30, 'p', 'group_user', '/project/:id/compose', 'POST', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (31, 'p', 'group_user', '/project/:id/deploy', 'POST', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (32, 'p', 'group_user', '/project/:id/deploy/:cloud_id', 'POST', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (33, 'p', 'group_user', '/server', 'GET', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (34, 'p', 'group_user', '/server', 'POST', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (35, 'p', 'group_user', '/server/:id', 'GET', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (36, 'p', 'group_user', '/server/:id', 'PUT', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (37, 'p', 'group_user', '/cloud', 'GET', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (38, 'p', 'group_user', '/cloud', 'POST', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (39, 'p', 'group_user', '/cloud/:id', 'GET', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (40, 'p', 'group_user', '/cloud/:id', 'PUT', '', '', ''); +INSERT INTO public.casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES (41, 'p', 'group_user', '/cloud/:id', 'DELETE', '', '', ''); diff --git a/migrations/20240401184313_remove_project_id_from_cloud.down.sql b/migrations/20240401184313_remove_project_id_from_cloud.down.sql new file mode 100644 index 0000000..3b99d4c --- /dev/null +++ b/migrations/20240401184313_remove_project_id_from_cloud.down.sql @@ -0,0 +1,2 @@ +-- Add down migration script here +ALTER table cloud ADD COLUMN project_id INT CONSTRAINT cloud_project_id REFERENCES project(id) ON UPDATE CASCADE ON DELETE CASCADE; diff --git a/migrations/20240401184313_remove_project_id_from_cloud.up.sql b/migrations/20240401184313_remove_project_id_from_cloud.up.sql new file mode 100644 index 0000000..4974d95 --- /dev/null +++ b/migrations/20240401184313_remove_project_id_from_cloud.up.sql @@ -0,0 +1,3 @@ +-- Add up migration script here + +alter table cloud DROP column project_id; diff --git a/src/console/commands/appclient/new.rs b/src/console/commands/appclient/new.rs index accbd76..dfafa9f 100644 --- a/src/console/commands/appclient/new.rs +++ b/src/console/commands/appclient/new.rs @@ -24,7 +24,7 @@ impl crate::console::commands::CallableTrait for NewCommand { let settings = web::Data::new(settings); let db_pool = web::Data::new(db_pool); - //todo get user from trydirect + //todo get user from TryDirect let user = crate::models::user::User { id: format!("{}", self.user_id), first_name: "first_name".to_string(), diff --git a/src/db/cloud.rs b/src/db/cloud.rs index 77c840e..92f79d1 100644 --- a/src/db/cloud.rs +++ b/src/db/cloud.rs @@ -48,7 +48,6 @@ pub async fn insert(pool: &PgPool, mut cloud: models::Cloud) -> Result Result Result String { #[derive(Default, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct CloudForm { pub user_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub project_id: Option, #[validate(min_length = 2)] #[validate(max_length = 50)] @@ -63,7 +64,7 @@ impl CloudForm { let mut secret = Secret::new(); secret.user_id = cloud.user_id.clone(); - secret.project_id = cloud.project_id.clone().unwrap(); + secret.provider = cloud.provider.clone(); cloud.cloud_token = CloudForm::decrypt_field(&mut secret, "cloud_token", cloud.cloud_token.clone(), reveal); cloud.cloud_secret = CloudForm::decrypt_field(&mut secret, "cloud_secret", cloud.cloud_secret.clone(), reveal); cloud.cloud_key = CloudForm::decrypt_field(&mut secret, "cloud_key", cloud.cloud_key.clone(), reveal); @@ -126,12 +127,11 @@ impl Into for &CloudForm { let mut cloud = models::Cloud::default(); cloud.provider = self.provider.clone(); cloud.user_id = self.user_id.clone().unwrap(); - cloud.project_id = self.project_id; if Some(true) == self.save_token { let mut secret = Secret::new(); secret.user_id = self.user_id.clone().unwrap(); - secret.project_id = self.project_id.unwrap(); + secret.provider = self.provider.clone(); cloud.cloud_token = encrypt_field(&mut secret, "cloud_token", self.cloud_token.clone()); cloud.cloud_key = encrypt_field(&mut secret, "cloud_key", self.cloud_key.clone()); @@ -155,13 +155,12 @@ impl Into for models::Cloud { #[tracing::instrument(name = "Into for models::Cloud .")] fn into(self) -> CloudForm { let mut form = CloudForm::default(); - form.project_id = self.project_id; - form.provider = self.provider; + form.provider = self.provider.clone(); if Some(true) == self.save_token { let mut secret = Secret::new(); secret.user_id = self.user_id.clone(); - secret.project_id = self.project_id.unwrap(); + secret.provider = self.provider; secret.field = "cloud_token".to_string(); let value = match self.cloud_token { diff --git a/src/forms/project/deploy.rs b/src/forms/project/deploy.rs index 86c1453..e300a18 100644 --- a/src/forms/project/deploy.rs +++ b/src/forms/project/deploy.rs @@ -2,14 +2,14 @@ use serde_derive::{Deserialize, Serialize}; use serde_json::Value; use serde_valid::Validate; use crate::forms; -use crate::forms::{CloudForm, Server}; +use crate::forms::{CloudForm, ServerForm}; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] pub struct Deploy { #[validate] pub(crate) stack: Stack, #[validate] - pub(crate) server: Server, + pub(crate) server: ServerForm, #[validate] pub(crate) cloud: CloudForm, } diff --git a/src/forms/project/payload.rs b/src/forms/project/payload.rs index 5eb115a..6a2c868 100644 --- a/src/forms/project/payload.rs +++ b/src/forms/project/payload.rs @@ -14,7 +14,7 @@ pub struct Payload { #[serde(flatten)] pub cloud: Option, #[serde(flatten)] - pub server: Option, + pub server: Option, #[serde(flatten)] pub stack: forms::project::Stack, pub custom: forms::project::Custom, diff --git a/src/forms/server.rs b/src/forms/server.rs index 8b78c14..134973a 100644 --- a/src/forms/server.rs +++ b/src/forms/server.rs @@ -4,7 +4,7 @@ use serde_valid::Validate; use chrono::{Utc}; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] -pub struct Server { +pub struct ServerForm { // pub cloud_id: i32, // pub project_id: i32, pub region: String, @@ -14,7 +14,7 @@ pub struct Server { pub disk_type: Option, } -impl Into for &Server { +impl Into for &ServerForm { fn into(self) -> models::Server { let mut server = models::Server::default(); server.disk_type = self.disk_type.clone(); @@ -29,22 +29,10 @@ impl Into for &Server { } } -// impl From for models::Server { -// fn from(self, value: Server) -> &mut Self { -// self.disk_type = value.disk_type.clone(); -// self.region = value.region.clone(); -// self.server = value.server.clone(); -// self.zone = value.zone.clone(); -// self.os = value.os.clone(); -// self.updated_at = Utc::now(); -// self -// } -// } +impl Into for models::Server { -impl Into for models::Server { - - fn into(self) -> Server { - let mut form = Server::default(); + fn into(self) -> ServerForm { + let mut form = ServerForm::default(); // form.cloud_id = self.cloud_id; // form.project_id = self.project_id; form.disk_type = self.disk_type; diff --git a/src/helpers/cloud/security.rs b/src/helpers/cloud/security.rs index 2e38994..23e82cc 100644 --- a/src/helpers/cloud/security.rs +++ b/src/helpers/cloud/security.rs @@ -9,7 +9,7 @@ use tracing::Instrument; #[derive(Debug, Default, PartialEq, Clone)] pub(crate) struct Secret { pub(crate) user_id: String, - pub(crate) project_id: i32, + pub(crate) provider: String, pub(crate) field: String, // cloud_token/cloud_key/cloud_secret pub(crate) nonce: Vec, } @@ -20,7 +20,7 @@ impl Secret { Secret { user_id: "".to_string(), - project_id: 0, + provider: "".to_string(), field: "".to_string(), nonce: vec![], } @@ -45,7 +45,7 @@ impl Secret { #[tracing::instrument(name = "Secret::save")] fn save(&self, value: &[u8]) -> &Self { let mut conn = Secret::connect_storage(); - let key = format!("{}_{}_{}", self.user_id, self.project_id, self.field); + let key = format!("{}_{}_{}", self.user_id, self.provider, self.field); tracing::debug!("Saving into storage.."); let _: () = match conn.set(key, value) { Ok(s) => s, @@ -118,7 +118,7 @@ impl Secret { .clone(); let key: &Key:: = Key::::from_slice(&sec_key.as_bytes()); // eprintln!("decrypt: Key str {key:?}"); - let rkey = format!("{}_{}_{}", self.user_id, self.project_id, self.field); + let rkey = format!("{}_{}_{}", self.user_id, self.provider, self.field); eprintln!("decrypt: Key str {rkey:?}"); self.get(rkey); // eprintln!("decrypt: nonce b64:decoded {nonce:?}"); diff --git a/src/middleware/authentication/method/f_oauth.rs b/src/middleware/authentication/method/f_oauth.rs index cec47b4..1b861a7 100644 --- a/src/middleware/authentication/method/f_oauth.rs +++ b/src/middleware/authentication/method/f_oauth.rs @@ -35,6 +35,7 @@ pub async fn try_oauth(req: &mut ServiceRequest) -> Result { .map_err(|err| format!("{err}"))?; // control access using user role + tracing::debug!("ACL check for role: {}", user.role.clone()); let acl_vals = actix_casbin_auth::CasbinVals { subject: user.role.clone(), domain: None, diff --git a/src/models/cloud.rs b/src/models/cloud.rs index 77c3224..b7c8f63 100644 --- a/src/models/cloud.rs +++ b/src/models/cloud.rs @@ -5,7 +5,6 @@ use serde_derive::{Deserialize, Serialize}; pub struct Cloud { pub id: i32, pub user_id: String, - pub project_id: Option, pub provider: String, pub cloud_token: Option, pub cloud_key: Option, @@ -28,19 +27,17 @@ impl std::fmt::Display for Cloud { let cloud_token = mask_string(self.cloud_token.as_ref()); let cloud_secret = mask_string(self.cloud_secret.as_ref()); - write!(f, "{} cloud creds: cloud_key : {} cloud_token: {} cloud_secret: {} project_id: {:?}", + write!(f, "{} cloud creds: cloud_key : {} cloud_token: {} cloud_secret: {}", self.provider, cloud_key, cloud_token, cloud_secret, - self.project_id ) } } impl Cloud { pub fn new(user_id: String, - project_id: Option, provider: String, cloud_token: Option, cloud_key: Option, @@ -50,7 +47,6 @@ impl Cloud { Self { id: 0, user_id, - project_id, provider, cloud_token, cloud_key, @@ -68,7 +64,6 @@ impl Default for Cloud { id: 0, provider: "".to_string(), user_id: "".to_string(), - project_id: Default::default(), cloud_key: Default::default(), cloud_token: Default::default(), cloud_secret: Default::default(), diff --git a/src/routes/project/deploy.rs b/src/routes/project/deploy.rs index 661115e..9510517 100644 --- a/src/routes/project/deploy.rs +++ b/src/routes/project/deploy.rs @@ -168,7 +168,9 @@ pub async fn saved_item( let cloud = match db::cloud::fetch(pg_pool.get_ref(), cloud_id).await { Ok(cloud) => { match cloud { - Some(cloud) => cloud, + Some(mut cloud) => { + cloud + }, None => { return Err(JsonResponse::::build().not_found("No cloud configured")); } diff --git a/src/routes/server/update.rs b/src/routes/server/update.rs index b074125..52f0327 100644 --- a/src/routes/server/update.rs +++ b/src/routes/server/update.rs @@ -13,7 +13,7 @@ use std::ops::Deref; #[put("/{id}")] pub async fn item( path: web::Path<(i32,)>, - form: web::Json, + form: web::Json, user: web::ReqData>, pg_pool: Data, ) -> Result { From 0576773da4b209563289637434df5d97a908f956 Mon Sep 17 00:00:00 2001 From: vsilent Date: Tue, 2 Apr 2024 15:59:58 +0300 Subject: [PATCH 251/284] fix warnings, return app id from docker image validator --- src/console/commands/debug/json.rs | 3 +-- src/forms/cloud.rs | 2 +- src/forms/project/form.rs | 29 ++++++++++++++++++++++++----- src/helpers/cloud/mod.rs | 2 +- src/helpers/cloud/security.rs | 2 +- src/helpers/compressor.rs | 4 ++-- src/helpers/json.rs | 22 +++++++++++----------- src/helpers/mq_manager.rs | 2 +- src/routes/client/disable.rs | 4 ++-- src/routes/client/enable.rs | 4 ++-- src/routes/client/update.rs | 4 ++-- src/routes/cloud/update.rs | 2 -- src/routes/project/deploy.rs | 4 ++-- src/routes/project/update.rs | 12 ++++++++---- src/startup.rs | 6 +----- 15 files changed, 59 insertions(+), 43 deletions(-) diff --git a/src/console/commands/debug/json.rs b/src/console/commands/debug/json.rs index 047faf0..e05e3b0 100644 --- a/src/console/commands/debug/json.rs +++ b/src/console/commands/debug/json.rs @@ -1,5 +1,4 @@ -use crate::configuration::get_configuration; -use actix_web::{rt, post, web, HttpResponse, Result, http::header::ContentType}; +use actix_web::{Result}; pub struct JsonCommand { line: usize, diff --git a/src/forms/cloud.rs b/src/forms/cloud.rs index cc54f81..fe4cdf6 100644 --- a/src/forms/cloud.rs +++ b/src/forms/cloud.rs @@ -1,5 +1,5 @@ use crate::models; -use serde::{Deserialize, Serialize, Serializer}; +use serde::{Deserialize, Serialize}; use serde_valid::Validate; use crate::helpers::cloud::security::Secret; use tracing::Instrument; diff --git a/src/forms/project/form.rs b/src/forms/project/form.rs index a0514a4..b849abb 100644 --- a/src/forms/project/form.rs +++ b/src/forms/project/form.rs @@ -18,18 +18,31 @@ impl TryFrom<&models::Project> for ProjectForm { } } + +#[derive(Serialize, Default)] +pub struct DockerImageReadResult { + pub(crate) id: String, + pub(crate) readable: bool +} + impl ProjectForm { - pub async fn is_readable_docker_image(&self) -> Result { + pub async fn is_readable_docker_image(&self) -> Result { for app in &self.custom.web { if !app.app.docker_image.is_active().await? { - return Ok(false); + return Ok(DockerImageReadResult{ + id: app.app.id.clone(), + readable: false + }); } } if let Some(service) = &self.custom.service { for app in service { if !app.app.docker_image.is_active().await? { - return Ok(false); + return Ok(DockerImageReadResult{ + id: app.app.id.clone(), + readable: false + }); } } } @@ -37,10 +50,16 @@ impl ProjectForm { if let Some(features) = &self.custom.feature { for app in features { if !app.app.docker_image.is_active().await? { - return Ok(false); + return Ok(DockerImageReadResult{ + id: app.app.id.clone(), + readable: false + }); } } } - Ok(true) + Ok(DockerImageReadResult{ + id: "".to_owned(), + readable: true + }) } } \ No newline at end of file diff --git a/src/helpers/cloud/mod.rs b/src/helpers/cloud/mod.rs index 9d2c999..96224c8 100644 --- a/src/helpers/cloud/mod.rs +++ b/src/helpers/cloud/mod.rs @@ -1,2 +1,2 @@ pub(crate) mod security; -pub use security::*; \ No newline at end of file +pub use security::Secret; \ No newline at end of file diff --git a/src/helpers/cloud/security.rs b/src/helpers/cloud/security.rs index 23e82cc..ddb6d1b 100644 --- a/src/helpers/cloud/security.rs +++ b/src/helpers/cloud/security.rs @@ -7,7 +7,7 @@ use redis::{Commands, Connection}; use tracing::Instrument; #[derive(Debug, Default, PartialEq, Clone)] -pub(crate) struct Secret { +pub struct Secret { pub(crate) user_id: String, pub(crate) provider: String, pub(crate) field: String, // cloud_token/cloud_key/cloud_secret diff --git a/src/helpers/compressor.rs b/src/helpers/compressor.rs index c6e1258..ec126fc 100644 --- a/src/helpers/compressor.rs +++ b/src/helpers/compressor.rs @@ -1,5 +1,5 @@ -use brotli::{CompressorWriter, Decompressor}; -use std::io::{Read, Write}; +use brotli::{CompressorWriter}; +use std::io::{Write}; pub fn compress(input: &str) -> Vec { let mut compressed = Vec::new(); diff --git a/src/helpers/json.rs b/src/helpers/json.rs index 36f8d39..ebb9df1 100644 --- a/src/helpers/json.rs +++ b/src/helpers/json.rs @@ -2,7 +2,6 @@ use actix_web::error::{ErrorBadRequest, ErrorConflict, ErrorInternalServerError, use actix_web::web::Json; use actix_web::Error; use serde_derive::Serialize; -use std::convert::From; #[derive(Serialize)] pub(crate) struct JsonResponse { @@ -90,16 +89,17 @@ where ErrorInternalServerError(self.set_msg(msg).to_string()) } - pub(crate) fn unauthorized>( - self, - msg: I, - ) -> Error { - ErrorUnauthorized(self.set_msg(msg).to_string()) - } - - pub(crate) fn conflict>(self, msg: I) -> Error { - ErrorConflict(self.set_msg(msg).to_string()) - } + // not used + // pub(crate) fn unauthorized>( + // self, + // msg: I, + // ) -> Error { + // ErrorUnauthorized(self.set_msg(msg).to_string()) + // } + // + // pub(crate) fn conflict>(self, msg: I) -> Error { + // ErrorConflict(self.set_msg(msg).to_string()) + // } } impl JsonResponse diff --git a/src/helpers/mq_manager.rs b/src/helpers/mq_manager.rs index dfcda23..f38604a 100644 --- a/src/helpers/mq_manager.rs +++ b/src/helpers/mq_manager.rs @@ -127,7 +127,7 @@ impl MqManager { let mut args = FieldTable::default(); args.insert("x-expires".into(), AMQPValue::LongUInt(3600000)); - let queue = channel.queue_declare( + let _queue = channel.queue_declare( queue_name, QueueDeclareOptions { passive: false, diff --git a/src/routes/client/disable.rs b/src/routes/client/disable.rs index 0d1fe3b..1c8b9d1 100644 --- a/src/routes/client/disable.rs +++ b/src/routes/client/disable.rs @@ -15,7 +15,7 @@ pub async fn disable_handler( path: web::Path<(i32,)>, ) -> Result { let client_id = path.0; - let mut client = db::client::fetch(pg_pool.get_ref(), client_id) + let client = db::client::fetch(pg_pool.get_ref(), client_id) .await .map_err(|msg| JsonResponse::::build().internal_server_error(msg)) .and_then( |client| { @@ -38,7 +38,7 @@ pub async fn admin_disable_handler( path: web::Path<(i32,)>, ) -> Result { let client_id = path.0; - let mut client = db::client::fetch(pg_pool.get_ref(), client_id) + let client = db::client::fetch(pg_pool.get_ref(), client_id) .await .map_err(|msg| JsonResponse::::build().internal_server_error(msg))? .ok_or_else(|| JsonResponse::::build().not_found("not found"))?; diff --git a/src/routes/client/enable.rs b/src/routes/client/enable.rs index e3d6c43..e3955a6 100644 --- a/src/routes/client/enable.rs +++ b/src/routes/client/enable.rs @@ -16,7 +16,7 @@ pub async fn enable_handler( path: web::Path<(i32,)>, ) -> Result { let client_id = path.0; - let mut client = db::client::fetch(pg_pool.get_ref(), client_id) + let client = db::client::fetch(pg_pool.get_ref(), client_id) .await .map_err(|msg| JsonResponse::::build().internal_server_error(msg))? .ok_or_else(|| JsonResponse::::build().not_found("not found"))?; @@ -37,7 +37,7 @@ pub async fn admin_enable_handler( path: web::Path<(i32,)>, ) -> Result { let client_id = path.0; - let mut client = db::client::fetch(pg_pool.get_ref(), client_id) + let client = db::client::fetch(pg_pool.get_ref(), client_id) .await .map_err(|msg| JsonResponse::::build().internal_server_error(msg))? .ok_or_else(|| JsonResponse::::build().not_found("not found"))?; diff --git a/src/routes/client/update.rs b/src/routes/client/update.rs index 3ed728b..de09581 100644 --- a/src/routes/client/update.rs +++ b/src/routes/client/update.rs @@ -15,7 +15,7 @@ pub async fn update_handler( path: web::Path<(i32,)>, ) -> Result { let client_id = path.0; - let mut client = db::client::fetch(pg_pool.get_ref(), client_id) + let client = db::client::fetch(pg_pool.get_ref(), client_id) .await .map_err(|msg| JsonResponse::::build().internal_server_error(msg))? .ok_or_else(|| JsonResponse::::build().not_found("not found"))?; @@ -36,7 +36,7 @@ pub async fn admin_update_handler( path: web::Path<(i32,)>, ) -> Result { let client_id = path.0; - let mut client = db::client::fetch(pg_pool.get_ref(), client_id) + let client = db::client::fetch(pg_pool.get_ref(), client_id) .await .map_err(|msg| JsonResponse::::build().internal_server_error(msg))? .ok_or_else(|| JsonResponse::::build().not_found("not found"))?; diff --git a/src/routes/cloud/update.rs b/src/routes/cloud/update.rs index 7672f55..5b4f4a1 100644 --- a/src/routes/cloud/update.rs +++ b/src/routes/cloud/update.rs @@ -8,7 +8,6 @@ use sqlx::PgPool; use std::sync::Arc; use tracing::Instrument; use std::ops::Deref; -use chrono::Utc; #[tracing::instrument(name = "Update cloud.")] #[put("/{id}")] @@ -38,7 +37,6 @@ pub async fn item( let mut cloud:models::Cloud = form.deref().into(); cloud.id = cloud_row.id; cloud.user_id = user.id.clone(); - // cloud.updated_at = Utc::now(); tracing::debug!("Updating cloud {:?}", cloud); diff --git a/src/routes/project/deploy.rs b/src/routes/project/deploy.rs index 9510517..b0d767e 100644 --- a/src/routes/project/deploy.rs +++ b/src/routes/project/deploy.rs @@ -130,7 +130,7 @@ pub async fn item( #[post("/{id}/deploy/{cloud_id}")] pub async fn saved_item( user: web::ReqData>, - mut form: web::Json, + form: web::Json, path: web::Path<(i32, i32)>, pg_pool: Data, mq_manager: Data, @@ -168,7 +168,7 @@ pub async fn saved_item( let cloud = match db::cloud::fetch(pg_pool.get_ref(), cloud_id).await { Ok(cloud) => { match cloud { - Some(mut cloud) => { + Some(cloud) => { cloud }, None => { diff --git a/src/routes/project/update.rs b/src/routes/project/update.rs index cdd532e..a6a8a8c 100644 --- a/src/routes/project/update.rs +++ b/src/routes/project/update.rs @@ -1,5 +1,5 @@ use std::str::FromStr; -use crate::forms::project::ProjectForm; +use crate::forms::project::{ProjectForm, DockerImageReadResult}; use crate::helpers::JsonResponse; use crate::models; use crate::db; @@ -41,11 +41,15 @@ pub async fn item( let project_name = form.custom.custom_stack_code.clone(); - if Ok(false) == form.is_readable_docker_image().await { - return Err(JsonResponse::::build() - .bad_request("Can not access docker image")); + if let Ok(result) = form.is_readable_docker_image().await { + if false == result.readable { + return Err(JsonResponse::::build() + .set_item(result) + .bad_request("Can not access docker image")); + } } + let body: Value = serde_json::to_value::(form) .or(serde_json::to_value::(ProjectForm::default())) .unwrap(); diff --git a/src/startup.rs b/src/startup.rs index 302070d..741393f 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -9,15 +9,11 @@ use actix_web::{ web, App, HttpServer, - HttpResponse, - FromRequest, - rt, }; use crate::middleware; use sqlx::{Pool, Postgres}; use std::net::TcpListener; use tracing_actix_web::TracingLogger; -use redis::Commands; pub async fn run( listener: TcpListener, @@ -32,7 +28,7 @@ pub async fn run( let authorization = middleware::authorization::try_new(settings.database.connection_string()).await?; let json_config = web::JsonConfig::default() - .error_handler(|err, req| { //todo + .error_handler(|err, _req| { //todo let msg: String = match err { error::JsonPayloadError::Deserialize(err) => format!("{{\"kind\":\"deserialize\",\"line\":{}, \"column\":{}, \"msg\":\"{}\"}}", err.line(), err.column(), err), _ => format!("{{\"kind\":\"other\",\"msg\":\"{}\"}}", err) From 28a8e5877c16a39e3758fc8f3fb3783589df2523 Mon Sep 17 00:00:00 2001 From: petru Date: Tue, 2 Apr 2024 21:57:16 +0300 Subject: [PATCH 252/284] casbin-debug explain features --- Cargo.lock | 661 +++++++++++++++------------ Cargo.toml | 1 + src/console/commands/debug/casbin.rs | 2 +- 3 files changed, 378 insertions(+), 286 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c849d15..d93e7a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,8 +4,8 @@ version = 3 [[package]] name = "actix-casbin-auth" -version = "0.4.4" -source = "git+https://github.com/smart--petea/actix-casbin-auth.git?branch=dirty-master#5b76cc4e0df68ccee02c563b947a788ab1cb5193" +version = "1.0.0" +source = "git+https://github.com/smart--petea/actix-casbin-auth.git?branch=dirty-master#2e0c3ae76fa27a3bd515478317e487082b8e8294" dependencies = [ "actix-service", "actix-web", @@ -20,7 +20,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "bytes", "futures-core", "futures-sink", @@ -56,9 +56,9 @@ dependencies = [ "actix-rt", "actix-service", "actix-utils", - "ahash 0.8.10", + "ahash 0.8.11", "base64 0.21.7", - "bitflags 2.4.2", + "bitflags 2.5.0", "brotli", "bytes", "bytestring", @@ -92,7 +92,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.51", + "syn 2.0.57", ] [[package]] @@ -171,7 +171,7 @@ dependencies = [ "actix-service", "actix-utils", "actix-web-codegen", - "ahash 0.8.10", + "ahash 0.8.11", "bytes", "bytestring", "cfg-if", @@ -205,7 +205,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.57", ] [[package]] @@ -236,9 +236,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b79b82693f705137f8fb9b37871d99e4f9a7df12b917eed79c3d3954830a60b" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "const-random", @@ -250,9 +250,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -391,9 +391,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" [[package]] name = "assert-json-diff" @@ -423,23 +423,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3" dependencies = [ "concurrent-queue", - "event-listener 5.1.0", - "event-listener-strategy 0.5.0", + "event-listener 5.2.0", + "event-listener-strategy 0.5.1", "futures-core", "pin-project-lite", ] [[package]] name = "async-executor" -version = "1.8.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ae5ebefcc48e7452b4987947920dac9450be1110cadf34d1b8c116bdbaf97c" +checksum = "10b3e585719c2358d2660232671ca8ca4ddb4be4ce8a1842d6c2dc8685303316" dependencies = [ "async-lock 3.3.0", "async-task", "concurrent-queue", - "fastrand 2.0.1", - "futures-lite 2.2.0", + "fastrand 2.0.2", + "futures-lite 2.3.0", "slab", ] @@ -451,10 +451,10 @@ checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ "async-channel 2.2.0", "async-executor", - "async-io 2.3.1", + "async-io 2.3.2", "async-lock 3.3.0", "blocking", - "futures-lite 2.2.0", + "futures-lite 2.3.0", "once_cell", ] @@ -491,18 +491,18 @@ dependencies = [ [[package]] name = "async-io" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f97ab0c5b00a7cdbe5a371b9a782ee7be1316095885c8a4ea1daf490eb0ef65" +checksum = "dcccb0f599cfa2f8ace422d3555572f47424da5648a4382a9dd0310ff8210884" dependencies = [ "async-lock 3.3.0", "cfg-if", "concurrent-queue", "futures-io", - "futures-lite 2.2.0", + "futures-lite 2.3.0", "parking", - "polling 3.5.0", - "rustix 0.38.31", + "polling 3.6.0", + "rustix 0.38.32", "slab", "tracing", "windows-sys 0.52.0", @@ -548,13 +548,13 @@ checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799" [[package]] name = "async-trait" -version = "0.1.77" +version = "0.1.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.57", ] [[package]] @@ -581,27 +581,17 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" -[[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 = "autocfg" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", @@ -632,9 +622,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "block-buffer" @@ -663,18 +653,18 @@ dependencies = [ "async-channel 2.2.0", "async-lock 3.3.0", "async-task", - "fastrand 2.0.1", + "fastrand 2.0.2", "futures-io", - "futures-lite 2.2.0", + "futures-lite 2.3.0", "piper", "tracing", ] [[package]] name = "brotli" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "516074a47ef4bce09577a3b379392300159ce5b1ba2e501ff1c819950066100f" +checksum = "d640d25bc63c50fb1f0b545ffd80207d2e10a4c965530809b40ba3386825c391" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -693,9 +683,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.15.3" +version = "3.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b" +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" [[package]] name = "bytecount" @@ -711,9 +701,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "bytestring" @@ -735,9 +725,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" dependencies = [ "serde", ] @@ -772,6 +762,9 @@ dependencies = [ "rhai", "ritelinked", "serde", + "slog", + "slog-async", + "slog-term", "thiserror", "tokio", ] @@ -787,10 +780,11 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.88" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" dependencies = [ + "jobserver", "libc", ] @@ -828,9 +822,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.1" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", "clap_derive", @@ -838,9 +832,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.1" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ "anstream", "anstyle", @@ -850,14 +844,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.0" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ - "heck", + "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.57", ] [[package]] @@ -902,9 +896,9 @@ dependencies = [ [[package]] name = "const-random" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaf16c9c2c612020bcfd042e170f6e32de9b9d75adb5277cdbbd2e2c8c8299a" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" dependencies = [ "const-random-macro", ] @@ -939,9 +933,12 @@ dependencies = [ [[package]] name = "cookie-factory" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396de984970346b0d9e93d1415082923c679e5ae5c3ee3dcbd104f5610af126b" +checksum = "9885fa71e26b8ab7855e2ec7cae6e9b380edff76cd052e07c683a0319d51b3a2" +dependencies = [ + "futures", +] [[package]] name = "core-foundation" @@ -994,9 +991,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" dependencies = [ "crossbeam-utils", ] @@ -1238,6 +1235,16 @@ dependencies = [ "dirs-sys", ] +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + [[package]] name = "dirs-sys" version = "0.3.7" @@ -1249,6 +1256,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "dlv-list" version = "0.3.0" @@ -1263,12 +1281,12 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "docker-compose-types" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e366950e7785fe0e404901a2b4e5c09ebd6656767f0c2167e34c5068ce0cc2d" +checksum = "6d6fdd6fa1c9e8e716f5f73406b868929f468702449621e7397066478b9bf89c" dependencies = [ "derive_builder 0.13.1", - "indexmap 2.2.3", + "indexmap 2.2.6", "serde", "serde_yaml", ] @@ -1358,9 +1376,9 @@ dependencies = [ [[package]] name = "event-listener" -version = "5.1.0" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7ad6fd685ce13acd6d9541a30f6db6567a7a24c9ffd4ba2955d29e3f22c8b27" +checksum = "2b5fb89194fa3cad959b833185b3063ba881dbfc7030680b314250779fb4cc91" dependencies = [ "concurrent-queue", "parking", @@ -1379,11 +1397,11 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feedafcaa9b749175d5ac357452a9d41ea2911da598fde46ce1fe02c37751291" +checksum = "332f51cb23d20b0de8458b86580878211da09bcd4503cb579c225b3d124cabb3" dependencies = [ - "event-listener 5.1.0", + "event-listener 5.2.0", "pin-project-lite", ] @@ -1407,9 +1425,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" [[package]] name = "finl_unicode" @@ -1571,11 +1589,11 @@ dependencies = [ [[package]] name = "futures-lite" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445ba825b27408685aaecefd65178908c36c6e96aaf6d8599419d46e624192ba" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ - "fastrand 2.0.1", + "fastrand 2.0.2", "futures-core", "futures-io", "parking", @@ -1590,7 +1608,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.57", ] [[package]] @@ -1687,9 +1705,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "h2" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb" dependencies = [ "bytes", "fnv", @@ -1697,7 +1715,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 2.2.3", + "indexmap 2.2.6", "slab", "tokio", "tokio-util", @@ -1728,7 +1746,7 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ - "ahash 0.8.10", + "ahash 0.8.11", "allocator-api2", ] @@ -1750,11 +1768,17 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "379dada1584ad501b383485dd706b8afb7a70fcbc7f4da7d780638a5a6124a60" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -1791,9 +1815,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -1932,9 +1956,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.3" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown 0.14.3", @@ -1983,6 +2007,17 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +[[package]] +name = "is-terminal" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "itertools" version = "0.12.1" @@ -1994,15 +2029,24 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jobserver" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +dependencies = [ + "libc", +] [[package]] name = "js-sys" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -2061,13 +2105,12 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libredox" -version = "0.0.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "libc", - "redox_syscall 0.4.1", ] [[package]] @@ -2117,9 +2160,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "matchers" @@ -2142,9 +2185,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "mime" @@ -2184,9 +2227,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", @@ -2218,17 +2261,6 @@ dependencies = [ "tempfile", ] -[[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 = "nom" version = "7.1.3" @@ -2295,7 +2327,7 @@ version = "0.10.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "cfg-if", "foreign-types", "libc", @@ -2312,7 +2344,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.57", ] [[package]] @@ -2323,9 +2355,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.101" +version = "0.9.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff" +checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" dependencies = [ "cc", "libc", @@ -2440,9 +2472,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.7" +version = "2.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219c0dcc30b6a27553f9cc242972b67f75b60eb0db71f0b5462f38b058c41546" +checksum = "311fb059dee1a7b802f036316d790138c613a4e8b180c822e3925a662e9f0c95" dependencies = [ "memchr", "thiserror", @@ -2451,9 +2483,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.7" +version = "2.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e1288dbd7786462961e69bfd4df7848c1e37e8b74303dbdab82c3a9cdd2809" +checksum = "f73541b156d32197eecda1a4014d7f868fd2bcb3c550d5386087cfba442bf69c" dependencies = [ "pest", "pest_generator", @@ -2461,22 +2493,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.7" +version = "2.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1381c29a877c6d34b8c176e734f35d7f7f5b3adaefe940cb4d1bb7af94678e2e" +checksum = "c35eeed0a3fab112f75165fdc026b3913f4183133f19b49be773ac9ea966e8bd" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.57", ] [[package]] name = "pest_meta" -version = "2.7.7" +version = "2.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0934d6907f148c22a3acbda520c7eed243ad7487a30f51f6ce52b58b7077a8a" +checksum = "2adbf29bb9776f28caece835398781ab24435585fe0d4dc1374a61db5accedca" dependencies = [ "once_cell", "pest", @@ -2490,34 +2522,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.2.3", + "indexmap 2.2.6", ] [[package]] name = "pin-project" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.57", ] [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -2544,7 +2576,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" dependencies = [ "atomic-waker", - "fastrand 2.0.1", + "fastrand 2.0.2", "futures-io", ] @@ -2572,14 +2604,15 @@ dependencies = [ [[package]] name = "polling" -version = "3.5.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24f040dee2588b4963afb4e420540439d126f73fdacf4a9c486a96d840bac3c9" +checksum = "e0c976a60b2d7e99d6f229e414670a9b85d13ac305cc6d1e9c134de58c5aaaf6" dependencies = [ "cfg-if", "concurrent-queue", + "hermit-abi", "pin-project-lite", - "rustix 0.38.31", + "rustix 0.38.32", "tracing", "windows-sys 0.52.0", ] @@ -2622,9 +2655,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -2635,7 +2668,7 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "memchr", "unicase", ] @@ -2760,9 +2793,9 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ "getrandom 0.2.12", "libredox", @@ -2771,14 +2804,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.3" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.5", - "regex-syntax 0.8.2", + "regex-automata 0.4.6", + "regex-syntax 0.8.3", ] [[package]] @@ -2792,13 +2825,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax 0.8.3", ] [[package]] @@ -2809,15 +2842,15 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "reqwest" -version = "0.11.24" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ "base64 0.21.7", "bytes", @@ -2865,8 +2898,8 @@ version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6273372244d04a8a4b0bec080ea1e710403e88c5d9d83f9808b2bfa64f0982a" dependencies = [ - "ahash 0.8.10", - "bitflags 2.4.2", + "ahash 0.8.11", + "bitflags 2.5.0", "instant", "num-traits", "once_cell", @@ -2885,7 +2918,7 @@ checksum = "9db7f8dc4c9d48183a17ce550574c42995252b82d267eaca3fcd1b979159856c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.57", ] [[package]] @@ -2980,11 +3013,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.31" +version = "0.38.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "errno", "libc", "linux-raw-sys 0.4.13", @@ -3058,6 +3091,12 @@ dependencies = [ "untrusted 0.9.0", ] +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + [[package]] name = "ryu" version = "1.0.17" @@ -3100,9 +3139,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.9.2" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -3113,9 +3152,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.1" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" dependencies = [ "core-foundation-sys", "libc", @@ -3147,14 +3186,14 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.57", ] [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" dependencies = [ "itoa", "ryu", @@ -3163,9 +3202,9 @@ dependencies = [ [[package]] name = "serde_path_to_error" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd154a240de39fdebcf5775d2675c204d7c13cf39a4c697be6493c8e734337c" +checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" dependencies = [ "itoa", "serde", @@ -3200,7 +3239,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70c0e00fab6460447391a1981c21341746bc2d0178a7c46a3bbf667f450ac6e4" dependencies = [ - "indexmap 2.2.3", + "indexmap 2.2.6", "itertools", "num-traits", "once_cell", @@ -3225,7 +3264,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.0", - "syn 2.0.51", + "syn 2.0.57", ] [[package]] @@ -3240,11 +3279,11 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.32" +version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd075d994154d4a774f95b51fb96bdc2832b0ea48425c92546073816cda1f2f" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.2.3", + "indexmap 2.2.6", "itoa", "ryu", "serde", @@ -3315,11 +3354,42 @@ dependencies = [ "autocfg", ] +[[package]] +name = "slog" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8347046d4ebd943127157b94d63abb990fcf729dc4e9978927fdf4ac3c998d06" + +[[package]] +name = "slog-async" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c8038f898a2c79507940990f05386455b3a317d8f18d4caea7cbc3d5096b84" +dependencies = [ + "crossbeam-channel", + "slog", + "take_mut", + "thread_local", +] + +[[package]] +name = "slog-term" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6e022d0b998abfe5c3782c1f03551a596269450ccd677ea51c56f8b214610e8" +dependencies = [ + "is-terminal", + "slog", + "term", + "thread_local", + "time 0.3.34", +] + [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" dependencies = [ "serde", ] @@ -3394,12 +3464,12 @@ 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 0.7.3", - "sqlx-macros 0.7.3", + "sqlx-core 0.7.4", + "sqlx-macros 0.7.4", "sqlx-postgres", ] @@ -3412,7 +3482,7 @@ dependencies = [ "async-trait", "casbin", "dotenv", - "sqlx 0.7.3", + "sqlx 0.7.4", ] [[package]] @@ -3472,17 +3542,16 @@ 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.10", + "ahash 0.8.11", "atoi 2.0.0", "byteorder", "bytes", "crc", "crossbeam-queue", - "dotenvy", "either", "event-listener 2.5.3", "futures-channel", @@ -3492,7 +3561,7 @@ dependencies = [ "futures-util", "hashlink", "hex", - "indexmap 2.2.3", + "indexmap 2.2.6", "log", "memchr", "native-tls", @@ -3519,7 +3588,7 @@ checksum = "9966e64ae989e7e575b19d7265cb79d7fc3cbbdf179835cb0d716f294c2049c9" dependencies = [ "dotenvy", "either", - "heck", + "heck 0.4.1", "hex", "once_cell", "proc-macro2", @@ -3535,27 +3604,26 @@ 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", - "sqlx-core 0.7.3", + "sqlx-core 0.7.4", "sqlx-macros-core", "syn 1.0.109", ] [[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", + "heck 0.4.1", "hex", "once_cell", "proc-macro2", @@ -3563,7 +3631,7 @@ dependencies = [ "serde", "serde_json", "sha2", - "sqlx-core 0.7.3", + "sqlx-core 0.7.4", "sqlx-postgres", "syn 1.0.109", "tempfile", @@ -3573,13 +3641,13 @@ 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 2.0.0", "base64 0.21.7", - "bitflags 2.4.2", + "bitflags 2.5.0", "byteorder", "crc", "dotenvy", @@ -3600,10 +3668,9 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "sha1", "sha2", "smallvec", - "sqlx-core 0.7.3", + "sqlx-core 0.7.4", "stringprep", "thiserror", "tracing", @@ -3638,11 +3705,11 @@ dependencies = [ "derive_builder 0.12.0", "docker-compose-types", "futures", - "futures-lite 2.2.0", + "futures-lite 2.3.0", "futures-util", "glob", "hmac", - "indexmap 2.2.3", + "indexmap 2.2.6", "lapin", "rand 0.8.5", "regex", @@ -3716,9 +3783,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.51" +version = "2.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ab617d94515e94ae53b8406c628598680aa0c9587474ecbe58188f7b345d66c" +checksum = "11a6ae1e52eb25aab8f3fb9fca13be982a373b8f1157ca14b897a825ba4a2d35" dependencies = [ "proc-macro2", "quote", @@ -3758,6 +3825,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" +[[package]] +name = "take_mut" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" + [[package]] name = "tcp-stream" version = "0.26.1" @@ -3777,11 +3850,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", - "fastrand 2.0.1", - "rustix 0.38.31", + "fastrand 2.0.2", + "rustix 0.38.32", "windows-sys 0.52.0", ] +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + [[package]] name = "thin-vec" version = "0.2.13" @@ -3793,22 +3877,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.57", ] [[package]] @@ -3889,9 +3973,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.36.0" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", "bytes", @@ -3925,7 +4009,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.57", ] [[package]] @@ -3951,9 +4035,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ "futures-core", "pin-project-lite", @@ -4003,9 +4087,9 @@ dependencies = [ [[package]] name = "tracing-actix-web" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fe0d5feac3f4ca21ba33496bcb1ccab58cca6412b1405ae80f0581541e0ca78" +checksum = "fa069bd1503dd526ee793bb3fce408895136c95fc86d2edb2acf1c646d7f0684" dependencies = [ "actix-web", "mutually_exclusive_features", @@ -4022,7 +4106,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.57", ] [[package]] @@ -4031,7 +4115,7 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5c266b9ac83dedf0e0385ad78514949e6d89491269e7065bee51d2bb8ec7373" dependencies = [ - "ahash 0.8.10", + "ahash 0.8.11", "gethostname", "log", "serde", @@ -4161,9 +4245,9 @@ checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" [[package]] name = "unsafe-libyaml" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] name = "untrusted" @@ -4197,9 +4281,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ "getrandom 0.2.12", "serde", @@ -4231,9 +4315,9 @@ checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -4266,11 +4350,17 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + [[package]] name = "wasm-bindgen" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -4278,24 +4368,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.57", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if", "js-sys", @@ -4305,9 +4395,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4315,28 +4405,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.57", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "web-sys" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", @@ -4363,11 +4453,12 @@ dependencies = [ [[package]] name = "whoami" -version = "1.4.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" +checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" dependencies = [ - "wasm-bindgen", + "redox_syscall 0.4.1", + "wasite", "web-sys", ] @@ -4408,7 +4499,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.3", + "windows-targets 0.52.4", ] [[package]] @@ -4426,7 +4517,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.3", + "windows-targets 0.52.4", ] [[package]] @@ -4446,17 +4537,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" dependencies = [ - "windows_aarch64_gnullvm 0.52.3", - "windows_aarch64_msvc 0.52.3", - "windows_i686_gnu 0.52.3", - "windows_i686_msvc 0.52.3", - "windows_x86_64_gnu 0.52.3", - "windows_x86_64_gnullvm 0.52.3", - "windows_x86_64_msvc 0.52.3", + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", ] [[package]] @@ -4467,9 +4558,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" @@ -4479,9 +4570,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" @@ -4491,9 +4582,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" @@ -4503,9 +4594,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" @@ -4515,9 +4606,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" [[package]] name = "windows_x86_64_gnullvm" @@ -4527,9 +4618,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" [[package]] name = "windows_x86_64_msvc" @@ -4539,9 +4630,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" [[package]] name = "winreg" @@ -4607,32 +4698,32 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.51", + "syn 2.0.57", ] [[package]] name = "zstd" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bffb3309596d527cfcba7dfc6ed6052f1d39dfbd7c867aa2e865e4a449c10110" +checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "7.0.0" +version = "7.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43747c7422e2924c11144d5229878b98180ef8b06cca4ab5af37afc8a8d8ea3e" +checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a" dependencies = [ "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.9+zstd.1.5.5" +version = "2.0.10+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" dependencies = [ "cc", "pkg-config", diff --git a/Cargo.toml b/Cargo.toml index d005e9b..0f3e51f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,6 +75,7 @@ features = [ [features] default = ["indexmap"] indexmap = ["dep:indexmap"] +explain = ["actix-casbin-auth/explain", "actix-casbin-auth/logging"] [dev-dependencies] glob = "0.3" diff --git a/src/console/commands/debug/casbin.rs b/src/console/commands/debug/casbin.rs index 2513727..b05fb2e 100644 --- a/src/console/commands/debug/casbin.rs +++ b/src/console/commands/debug/casbin.rs @@ -39,7 +39,7 @@ impl crate::console::commands::CallableTrait for CasbinCommand { println!("{}", policies.len()); - match lock.enforce_mut(vec!["".to_string(), self.subject.clone(), self.path.clone(), self.action.clone()]) { + match lock.enforce_mut(vec![self.subject.clone(), self.path.clone(), self.action.clone()]) { Ok(true) => println!("TRUE"), Ok(false) => println!("FALSE"), Err(err) => { From 57c76712357f4a9c0806705774729458b29a849f Mon Sep 17 00:00:00 2001 From: petru Date: Wed, 3 Apr 2024 22:08:05 +0300 Subject: [PATCH 253/284] casbin-debug --- Cargo.lock | 52 ++++++++++++++-------------- README.md | 2 +- src/console/commands/debug/casbin.rs | 8 ++--- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d93e7a9..67e6d46 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,7 +5,7 @@ version = 3 [[package]] name = "actix-casbin-auth" version = "1.0.0" -source = "git+https://github.com/smart--petea/actix-casbin-auth.git?branch=dirty-master#2e0c3ae76fa27a3bd515478317e487082b8e8294" +source = "git+https://github.com/smart--petea/actix-casbin-auth.git?branch=dirty-master#bbc6d08900521c684c46bab59c4b92394ca5bd57" dependencies = [ "actix-service", "actix-web", @@ -92,7 +92,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -205,7 +205,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -554,7 +554,7 @@ checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -839,7 +839,7 @@ dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim 0.11.0", + "strsim 0.11.1", ] [[package]] @@ -851,7 +851,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -1608,7 +1608,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -1705,9 +1705,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "h2" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ "bytes", "fnv", @@ -2344,7 +2344,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -2501,7 +2501,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -2542,7 +2542,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -2918,7 +2918,7 @@ checksum = "9db7f8dc4c9d48183a17ce550574c42995252b82d267eaca3fcd1b979159856c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -3186,7 +3186,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -3263,8 +3263,8 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "strsim 0.11.0", - "syn 2.0.57", + "strsim 0.11.1", + "syn 2.0.58", ] [[package]] @@ -3760,9 +3760,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "strsim" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" @@ -3783,9 +3783,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.57" +version = "2.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11a6ae1e52eb25aab8f3fb9fca13be982a373b8f1157ca14b897a825ba4a2d35" +checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" dependencies = [ "proc-macro2", "quote", @@ -3892,7 +3892,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -4009,7 +4009,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -4106,7 +4106,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -4377,7 +4377,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", "wasm-bindgen-shared", ] @@ -4411,7 +4411,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4698,7 +4698,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] diff --git a/README.md b/README.md index ad44ea7..0541a60 100644 --- a/README.md +++ b/README.md @@ -88,4 +88,4 @@ http://localhost:8000/test/deploy Test casbin rule -cargo r --bin console debug casbin --path "/project/:id" --action "POST" --subject "hy181TZa4DaabUZWklsrxw" \ No newline at end of file +cargo r --bin console --features=explain debug casbin --path /client --action POST --subject admin_petru diff --git a/src/console/commands/debug/casbin.rs b/src/console/commands/debug/casbin.rs index b05fb2e..8a14695 100644 --- a/src/console/commands/debug/casbin.rs +++ b/src/console/commands/debug/casbin.rs @@ -31,14 +31,14 @@ impl crate::console::commands::CallableTrait for CasbinCommand { let mut authorizationService = middleware::authorization::try_new(settings.database.connection_string()).await?; let casbin_enforcer = authorizationService.get_enforcer(); + let mut lock = casbin_enforcer.write().await; let policies = lock.get_model().get_model().get("p").unwrap().get("p").unwrap().get_policy(); - for policy in policies { - println!("{policy:?}"); + for (pos, policy) in policies.iter().enumerate() { + println!("{pos}: {policy:?}"); } - println!("{}", policies.len()); - + lock.enable_log(true); match lock.enforce_mut(vec![self.subject.clone(), self.path.clone(), self.action.clone()]) { Ok(true) => println!("TRUE"), Ok(false) => println!("FALSE"), From d52877e6b93f0048e2e98ce89daaf9d2d0adf3b8 Mon Sep 17 00:00:00 2001 From: petru Date: Thu, 4 Apr 2024 10:09:09 +0300 Subject: [PATCH 254/284] casbin-debug --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 0f3e51f..87b9ce7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ name = "server" [[bin]] path = "src/console/main.rs" name = "console" +required-features = ["explain"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From 41b1ca6e182d19a0eec0b460d45db38632bdbee4 Mon Sep 17 00:00:00 2001 From: vsilent Date: Sun, 7 Apr 2024 09:04:45 +0300 Subject: [PATCH 255/284] unfinished tag fix --- src/helpers/dockerhub.rs | 195 ++++++++++++++++++---- tests/mock_data/custom-stack-payload.json | 2 +- 2 files changed, 161 insertions(+), 36 deletions(-) diff --git a/src/helpers/dockerhub.rs b/src/helpers/dockerhub.rs index 81f4feb..60ace37 100644 --- a/src/helpers/dockerhub.rs +++ b/src/helpers/dockerhub.rs @@ -65,29 +65,58 @@ pub struct RepoResults { pub results: Vec, } +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] +pub struct OfficialRepoResults { + pub count: Option, + pub next: Option, + pub previous: Option, + pub results: Vec, +} + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct RepoResult { pub name: String, - pub namespace: String, - pub repository_type: String, - pub status: i64, - pub status_description: String, - pub description: String, - pub is_private: bool, - pub star_count: i64, - pub pull_count: i64, + pub namespace: Option, + pub repository_type: Option, + pub status: Option, + pub status_description: Option, + pub description: Option, + pub is_private: Option, + pub star_count: Option, + pub pull_count: Option, pub last_updated: String, - pub date_registered: String, - pub affiliation: String, - pub media_types: Vec, - pub content_types: Vec, + pub date_registered: Option, + pub affiliation: Option, + pub media_types: Option>, + pub content_types: Option>, } + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct OfficialRepoResult { + pub images: Vec, + pub last_updated: String, + pub last_updater: i64, + pub content_type: String, + pub creator: i64, + pub digest: Option, + pub full_size: i64, + pub id: i64, + pub last_updater_username: String, + pub media_type: String, + pub name: String, + pub repository: i64, + pub tag_last_pulled: Option, + pub tag_last_pushed: Option, + pub tag_status: String, + pub v2: bool, +} #[derive(Default, Debug, Clone, PartialEq, Serialize, Validate)] pub struct DockerHub<'a> { pub(crate) creds: DockerHubCreds<'a>, pub(crate) repos: String, pub(crate) image: String, + pub(crate) tag: Option, } impl<'a> DockerHub<'a> { @@ -105,33 +134,86 @@ impl<'a> DockerHub<'a> { .map_err(|err| format!("{:?}", err)) } - pub async fn lookup_public_repo(&self) -> Result { - let url = format!("https://hub.docker.com/v2/repositories/{}", &self.repos); - tracing::debug!("Validate public repositories {:?}", url); + pub async fn lookup_public_repos(&'a self) -> Result { + + let url = format!("https://hub.docker.com/v2/repositories/{}", self.repos); + tracing::debug!("Validate public repository {:?}", &url); let client = reqwest::Client::new() - .get(url) + .get(&url) .header("Accept", "application/json"); let client = self.set_token(client).await?; client .send() .await .map_err(|err| { - tracing::debug!("πŸŸ₯Error response {:?}", err); - format!("{}", err) + let msg = format!("πŸŸ₯Error response {:?}", err); + tracing::debug!(msg); + msg })? .json::() .await - .map_err(|err| format!("πŸŸ₯Error on getting results:: {}", err)) + .map_err(|err| { + let msg = format!("πŸŸ₯Error on getting results:: {} url: {}", &err, &url); + tracing::error!(msg); + msg + }) .map(|repositories| { - tracing::debug!("Get public image repositories response {:?}", repositories); + tracing::debug!("Get public image repo {:?} response {:?}", &url, repositories); if repositories.count.unwrap_or(0) > 0 { // let's find at least one active tag let active = repositories .results .into_iter() - .any(|repo| repo.status == 1); - tracing::debug!("βœ… Image is active"); + .any(|repo| repo.status == Some(1)); + tracing::debug!("βœ… Image is active. url: {:?}", &url); active + } else { + tracing::debug!("πŸŸ₯ Image tag is not active, url: {:?}", &url); + false + } + }) + } + + pub async fn lookup_official_repos(&'a self) -> Result { + // search in official library repositories + let url = format!("https://hub.docker.com/v2/repositories/library/{}/tags", self.repos); + return self.lookup(&url).await; + } + + pub async fn lookup(&'a self, url: &String) -> Result { + tracing::debug!("Search official repos {:?}", url); + let client = reqwest::Client::new() + .get(url) + .header("Accept", "application/json"); + let client = self.set_token(client).await?; + client + .send() + .await + .map_err(|err| format!("πŸŸ₯{}", err))? + .json::() + .await + .map_err(|err| { + tracing::debug!("πŸŸ₯Error response {:?}", err); + format!("{}", err) + }) + .map(|tags| { + tracing::debug!("Validate official image response {:?}", tags); + if tags.count.unwrap_or(0) > 0 { + // let's find at least one active tag + let result = tags + .results + .into_iter() + .any(|tag| { + tracing::debug!("official: {:?}", tag); + if "active".to_string() == tag.tag_status { + tracing::debug!("βœ… Image is active"); + true + } else { + false + } + }); + tracing::debug!("βœ… result is {:?}", result); + result } else { tracing::debug!("πŸŸ₯ Image tag is not active"); false @@ -139,7 +221,7 @@ impl<'a> DockerHub<'a> { }) } - pub async fn lookup_private_repo(&self) -> Result { + pub async fn lookup_private_repo(&'a self) -> Result { let url = format!( "https://hub.docker.com/v2/namespaces/{}/repositories/{}/tags", &self.creds.username, &self.repos @@ -168,29 +250,60 @@ impl<'a> DockerHub<'a> { .into_iter() .any(|tag| tag.tag_status.contains("active")); tracing::debug!("βœ… Image is active"); - active + return active; } else { tracing::debug!("πŸŸ₯ Image tag is not active"); false } }) } - pub async fn is_active(&'a self) -> Result { + pub async fn is_active(&'a mut self) -> Result { // if namespace/user is not set change endpoint and return a different response + + // let repo = self.repos.clone(); + // if self.repos.contains(':') { + // let _repo = repo.split(':') + // .collect::>(); + // self.repos = _repo.first().expect("split error").to_string(); + // self.tag = Some(_repo.last().expect("split error").to_string()); + // } + + // let n = self.repos.split(':').collect::>(); + // if let Some(name: &str) == n.first() { + // self.repos = name.to_string(); + // } + // if let Some(name: &str) == n.last() { + // self.tag = name.to_string(); + // } + if self.creds.username.is_empty() { - match self.lookup_public_repo().await { - Ok(result) => Ok(result), - Err(_e) => Ok(false), - } + + if Ok(true) == self.lookup_official_repos().await { + tracing::debug!("official: true"); + return Ok(true); + } else { + tracing::debug!("official: false"); + }; + + if Ok(true) == self.lookup_public_repos().await { + tracing::debug!("public: true"); + return Ok(true); + }; + + Ok(false) + } else { - match self.lookup_private_repo().await { - Ok(result) => Ok(result), - Err(_e) => Ok(false), - } + + if Ok(true) == self.lookup_private_repo().await { + tracing::debug!("private: true"); + return Ok(true); + }; + + Ok(false) } } - pub async fn set_token(&self, client: RequestBuilder) -> Result { + pub async fn set_token(&'a self, client: RequestBuilder) -> Result { if self.creds.password.is_empty() { tracing::debug!("Password is empty. Image should be public"); return Ok(client); @@ -217,13 +330,25 @@ impl<'a> From<&'a DockerImage> for DockerHub<'a> { None => "", }; + let name = image.dockerhub_name.clone().unwrap_or("".to_string()); + let mut tag = "".to_string(); + + if name.contains(':') { + let parts = name + .split(':') + .collect::>(); + let name = parts.first().expect("Could not split").to_string(); + tag = parts.last().expect("Could not split").to_string(); + } + DockerHub { creds: DockerHubCreds { username: username, password: password, }, - repos: image.dockerhub_name.clone().unwrap_or("".to_string()), + repos: name, image: format!("{}", image), + tag: Some(tag), } } } diff --git a/tests/mock_data/custom-stack-payload.json b/tests/mock_data/custom-stack-payload.json index ab48715..88fe2c2 100644 --- a/tests/mock_data/custom-stack-payload.json +++ b/tests/mock_data/custom-stack-payload.json @@ -1 +1 @@ -{"commonDomain":"","domainList":{},"region":"","zone":null,"server":"cx11","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":[],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":true,"disk_type":"pd-standart","cloud_token":"*******************","cloud_key":"*********","cloud_secret":"****************","disk_size":40,"provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-annually","custom":{"networks":[{"name":"default_network","id":"lsnd2ttg3ivhw3db5"}],"web":[{"_etag":null,"_id":"lsq2tdff3c0acf2lj","_created":"2023-04-28T09:46:19.470502","_updated":"2024-02-09T13:44:36.854036","name":"PostgREST","code":"postgrest","role":["postgrest"],"type":"web","default":false,"popularity":null,"descr":null,"ports":{"public":["3000","8080"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":null,"category_id":null,"parent_app_id":null,"full_description":null,"description":null,"plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"postgrest","form":null,"requirements":null,"docker_image_is_internal":true,"custom_preset":{"volumes":[],"environment":[{"key":"PGRST_OPENAPI_SERVER_PROXY_URI","value":"http://DOMAIN_NAME:3000"},{"key":"PGRST_DB_ANON_ROLE","value":"anon"},{"key":"PGRST_DB_SCHEMA","value":"public"},{"key":"PGHOST","value":"postgresql_host"},{"key":"PGPORT","value":"5432"},{"key":"PGUSER","value":"user"},{"key":"PGDATABASE","value":"database"},{"key":"PGPASSWORD ","value":"password"}],"shared_ports":[{"host_port":"3000","container_port":"3000"}],"restart":"always"},"category":[null],"group":[],"versions":[{"_id":556,"name":"Postgrest","version":"latest","update_status":"published","tag":"latest"}],"links":[{"url":"https://postgrest.org","title":"Vendor","type":"vendor","follow":false},{"repo_owner":"PostgREST","repo_name":"postgrest","type":"github","follow":false}],"version":{"_id":556,"name":"Postgrest","version":"latest","update_status":"published","tag":"latest"},"network":["lsnd2ttg3ivhw3db5"],"restart":"always","timestamp":"2024-02-17T12:50:01.659Z","volumes":[],"environment":[{"key":"PGRST_OPENAPI_SERVER_PROXY_URI","value":"http://DOMAIN_NAME:3000"},{"key":"PGRST_DB_ANON_ROLE","value":"anon"},{"key":"PGRST_DB_SCHEMA","value":"public"},{"key":"PGHOST","value":"postgresql_host"},{"key":"PGPORT","value":"5432"},{"key":"PGUSER","value":"user"},{"key":"PGDATABASE","value":"database"},{"key":"PGPASSWORD ","value":"password"}],"shared_ports":[{"host_port":"3000","container_port":"3000"}],"domain":"","dockerhub_name":"postgrest"}],"feature":[],"service":[],"servers_count":3,"project_name":"Databases","custom_stack_code":"databases"}} \ No newline at end of file +{"commonDomain":"","domainList":{},"region":"","zone":null,"server":"cx11","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":[],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":true,"disk_type":"pd-standart","cloud_token":"*******************","cloud_key":"*********","cloud_secret":"****************","disk_size":40,"provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-annually","custom":{"networks":[{"name":"default_network","id":"lsnd2ttg3ivhw3db5"}],"web":[{"_etag":null,"_id":"lsq2tdff3c0acf2lj","_created":"2023-04-28T09:46:19.470502","_updated":"2024-02-09T13:44:36.854036","name":"PostgREST","code":"postgrest","role":["postgrest"],"type":"web","default":false,"popularity":null,"descr":null,"ports":{"public":["3000","8080"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":null,"category_id":null,"parent_app_id":null,"full_description":null,"description":null,"plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"","form":null,"requirements":null,"docker_image_is_internal":true,"custom_preset":{"volumes":[],"environment":[{"key":"PGRST_OPENAPI_SERVER_PROXY_URI","value":"http://DOMAIN_NAME:3000"},{"key":"PGRST_DB_ANON_ROLE","value":"anon"},{"key":"PGRST_DB_SCHEMA","value":"public"},{"key":"PGHOST","value":"postgresql_host"},{"key":"PGPORT","value":"5432"},{"key":"PGUSER","value":"user"},{"key":"PGDATABASE","value":"database"},{"key":"PGPASSWORD ","value":"password"}],"shared_ports":[{"host_port":"3000","container_port":"3000"}],"restart":"always"},"category":[null],"group":[],"versions":[{"_id":556,"name":"Postgrest","version":"latest","update_status":"published","tag":"latest"}],"links":[{"url":"https://postgrest.org","title":"Vendor","type":"vendor","follow":false},{"repo_owner":"PostgREST","repo_name":"postgrest","type":"github","follow":false}],"version":{"_id":556,"name":"Postgrest","version":"latest","update_status":"published","tag":"latest"},"network":["lsnd2ttg3ivhw3db5"],"restart":"always","timestamp":"2024-02-17T12:50:01.659Z","volumes":[],"environment":[{"key":"PGRST_OPENAPI_SERVER_PROXY_URI","value":"http://DOMAIN_NAME:3000"},{"key":"PGRST_DB_ANON_ROLE","value":"anon"},{"key":"PGRST_DB_SCHEMA","value":"public"},{"key":"PGHOST","value":"postgresql_host"},{"key":"PGPORT","value":"5432"},{"key":"PGUSER","value":"user"},{"key":"PGDATABASE","value":"database"},{"key":"PGPASSWORD ","value":"password"}],"shared_ports":[{"host_port":"3000","container_port":"3000"}],"domain":"","dockerhub_name":"mariadb:11.3.2"}],"feature":[],"service":[],"servers_count":3,"project_name":"Databases","custom_stack_code":"databases"}} \ No newline at end of file From 4bae859b938f518c0686c6d1e6c112764969f3c0 Mon Sep 17 00:00:00 2001 From: petru Date: Sun, 7 Apr 2024 21:46:56 +0300 Subject: [PATCH 256/284] casbin-debug command --- README.md | 2 ++ src/console/commands/debug/casbin.rs | 12 ++++-------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 0541a60..18723b4 100644 --- a/README.md +++ b/README.md @@ -88,4 +88,6 @@ http://localhost:8000/test/deploy Test casbin rule +``` cargo r --bin console --features=explain debug casbin --path /client --action POST --subject admin_petru +``` diff --git a/src/console/commands/debug/casbin.rs b/src/console/commands/debug/casbin.rs index 8a14695..ba6bb62 100644 --- a/src/console/commands/debug/casbin.rs +++ b/src/console/commands/debug/casbin.rs @@ -38,15 +38,11 @@ impl crate::console::commands::CallableTrait for CasbinCommand { println!("{pos}: {policy:?}"); } - lock.enable_log(true); - match lock.enforce_mut(vec![self.subject.clone(), self.path.clone(), self.action.clone()]) { - Ok(true) => println!("TRUE"), - Ok(false) => println!("FALSE"), - Err(err) => { - println!("err {err:?}"); - } + #[cfg(feature = "explain")] + { + lock.enable_log(true); } - drop(lock); + lock.enforce_mut(vec![self.subject.clone(), self.path.clone(), self.action.clone()]); Ok(()) }) From b943f4cf005414b29bc1d531ba5aae9ff4839f74 Mon Sep 17 00:00:00 2001 From: vsilent Date: Mon, 8 Apr 2024 10:40:02 +0300 Subject: [PATCH 257/284] from to try_from, repo name format error fix --- src/forms/project/docker_image.rs | 2 +- src/helpers/dockerhub.rs | 84 ++++++++++++++++++++----------- src/routes/project/update.rs | 23 +++++++-- 3 files changed, 76 insertions(+), 33 deletions(-) diff --git a/src/forms/project/docker_image.rs b/src/forms/project/docker_image.rs index e9737d0..a018174 100644 --- a/src/forms/project/docker_image.rs +++ b/src/forms/project/docker_image.rs @@ -41,7 +41,7 @@ impl fmt::Display for DockerImage { impl DockerImage { #[tracing::instrument(name = "is_active")] pub async fn is_active(&self) -> Result { - DockerHub::from(self).is_active().await + DockerHub::try_from(self)?.is_active().await } } diff --git a/src/helpers/dockerhub.rs b/src/helpers/dockerhub.rs index 60ace37..7309cda 100644 --- a/src/helpers/dockerhub.rs +++ b/src/helpers/dockerhub.rs @@ -114,6 +114,7 @@ pub struct OfficialRepoResult { #[derive(Default, Debug, Clone, PartialEq, Serialize, Validate)] pub struct DockerHub<'a> { pub(crate) creds: DockerHubCreds<'a>, + #[validate(pattern = r"^[^:]+(:[^:]*)?$")] pub(crate) repos: String, pub(crate) image: String, pub(crate) tag: Option, @@ -260,20 +261,22 @@ impl<'a> DockerHub<'a> { pub async fn is_active(&'a mut self) -> Result { // if namespace/user is not set change endpoint and return a different response - // let repo = self.repos.clone(); - // if self.repos.contains(':') { - // let _repo = repo.split(':') - // .collect::>(); - // self.repos = _repo.first().expect("split error").to_string(); - // self.tag = Some(_repo.last().expect("split error").to_string()); - // } - - // let n = self.repos.split(':').collect::>(); - // if let Some(name: &str) == n.first() { - // self.repos = name.to_string(); - // } - // if let Some(name: &str) == n.last() { - // self.tag = name.to_string(); + // let n = self.repos + // .split(':') + // .map(|x| x.to_string()) + // .collect::>(); + // + // match n.len() { + // 1 => { + // self.repos = n.first().unwrap().into(); + // } + // 2 => { + // self.repos = n.first().unwrap().to_string(); + // self.tag = n.last().map(|s| s.to_string()); + // } + // _ => { + // return Err(format!("Wrong format of repository name")); + // } // } if self.creds.username.is_empty() { @@ -319,8 +322,12 @@ impl<'a> DockerHub<'a> { } } -impl<'a> From<&'a DockerImage> for DockerHub<'a> { - fn from(image: &'a DockerImage) -> Self { + +impl<'a> TryFrom<&'a DockerImage> for DockerHub<'a> { + type Error = String; + + fn try_from(image: &'a DockerImage) -> Result { + let username = match image.dockerhub_user { Some(ref username) => username, None => "", @@ -331,24 +338,45 @@ impl<'a> From<&'a DockerImage> for DockerHub<'a> { }; let name = image.dockerhub_name.clone().unwrap_or("".to_string()); - let mut tag = "".to_string(); - - if name.contains(':') { - let parts = name - .split(':') - .collect::>(); - let name = parts.first().expect("Could not split").to_string(); - tag = parts.last().expect("Could not split").to_string(); - } + let n = name + .split(':') + .map(|x| x.to_string()) + .collect::>(); - DockerHub { + let (name, tag) = match n.len() { + 1 => { + ( + n.first().unwrap().into(), + Some("".to_string()) + ) + } + 2 => { + ( + n.first().unwrap().to_string(), + n.last().map(|s| s.to_string()) + ) + } + _ => { + return Err(format!("Wrong format of repository name")); + } + }; + + let hub = DockerHub { creds: DockerHubCreds { username: username, password: password, }, repos: name, image: format!("{}", image), - tag: Some(tag), + tag: tag, + }; + + if hub.validate().is_ok() { + Ok(hub) + } else { + let errors = hub.validate().unwrap_err(); + tracing::debug!("DockerHub image properties are not valid {:?}", errors); + return Err(format!("{:?}", errors)); } } -} +} \ No newline at end of file diff --git a/src/routes/project/update.rs b/src/routes/project/update.rs index a6a8a8c..0303d5c 100644 --- a/src/routes/project/update.rs +++ b/src/routes/project/update.rs @@ -34,6 +34,7 @@ pub async fn item( // @todo ACL let form: ProjectForm= serde_json::from_value(request_json.clone()) .map_err(|err| JsonResponse::bad_request(err.to_string()))?; + if !form.validate().is_ok() { let errors = form.validate().unwrap_err(); return Err(JsonResponse::bad_request(errors.to_string())); @@ -41,11 +42,25 @@ pub async fn item( let project_name = form.custom.custom_stack_code.clone(); - if let Ok(result) = form.is_readable_docker_image().await { - if false == result.readable { + // if let Ok(result) = form.is_readable_docker_image().await { + // if false == result.readable { + // return Err(JsonResponse::::build() + // .set_item(result) + // .bad_request("Can not access docker image")); + // } + // } + + match form.is_readable_docker_image().await { + Ok(result) => { + if false == result.readable { + return Err(JsonResponse::::build() + .set_item(result) + .bad_request("Can not access docker image")); + } + } + Err(e) => { return Err(JsonResponse::::build() - .set_item(result) - .bad_request("Can not access docker image")); + .bad_request(e)); } } From 869ce5422c52623146a1f72c2f65caaa3c28f325 Mon Sep 17 00:00:00 2001 From: vsilent Date: Wed, 10 Apr 2024 12:22:58 +0300 Subject: [PATCH 258/284] remove extra structure --- src/helpers/dockerhub.rs | 73 +++++++++-------------- src/routes/project/update.rs | 8 --- tests/mock_data/custom-stack-payload.json | 2 +- 3 files changed, 29 insertions(+), 54 deletions(-) diff --git a/src/helpers/dockerhub.rs b/src/helpers/dockerhub.rs index 7309cda..fda20f0 100644 --- a/src/helpers/dockerhub.rs +++ b/src/helpers/dockerhub.rs @@ -32,23 +32,24 @@ struct Image { #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] struct Tag { - content_type: String, - creator: i64, - digest: Option, - full_size: i64, - id: i64, - images: Vec, - last_updated: String, - last_updater: i64, - last_updater_username: String, - media_type: String, - name: String, - repository: i64, - tag_last_pulled: Option, - tag_last_pushed: Option, - tag_status: String, - v2: bool, + pub content_type: String, + pub creator: i64, + pub digest: Option, + pub full_size: i64, + pub id: i64, + pub images: Vec, + pub last_updated: String, + pub last_updater: i64, + pub last_updater_username: String, + pub media_type: String, + pub name: String, + pub repository: i64, + pub tag_last_pulled: Option, + pub tag_last_pushed: Option, + pub tag_status: String, + pub v2: bool, } + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)] struct TagResult { pub count: Option, @@ -70,7 +71,7 @@ pub struct OfficialRepoResults { pub count: Option, pub next: Option, pub previous: Option, - pub results: Vec, + pub results: Vec, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -92,29 +93,11 @@ pub struct RepoResult { } -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct OfficialRepoResult { - pub images: Vec, - pub last_updated: String, - pub last_updater: i64, - pub content_type: String, - pub creator: i64, - pub digest: Option, - pub full_size: i64, - pub id: i64, - pub last_updater_username: String, - pub media_type: String, - pub name: String, - pub repository: i64, - pub tag_last_pulled: Option, - pub tag_last_pushed: Option, - pub tag_status: String, - pub v2: bool, -} #[derive(Default, Debug, Clone, PartialEq, Serialize, Validate)] pub struct DockerHub<'a> { pub(crate) creds: DockerHubCreds<'a>, - #[validate(pattern = r"^[^:]+(:[^:]*)?$")] + //#[validate(pattern = r"^[^:]+(:[^:]*)?$")] + #[validate(pattern = r"^([a-z-_0-9]+)(:[a-z-_0-9\.]+)?$")] pub(crate) repos: String, pub(crate) image: String, pub(crate) tag: Option, @@ -213,7 +196,7 @@ impl<'a> DockerHub<'a> { false } }); - tracing::debug!("βœ… result is {:?}", result); + tracing::debug!("βœ… search official repos result is {:?}", result); result } else { tracing::debug!("πŸŸ₯ Image tag is not active"); @@ -357,7 +340,7 @@ impl<'a> TryFrom<&'a DockerImage> for DockerHub<'a> { ) } _ => { - return Err(format!("Wrong format of repository name")); + return Err("Wrong format of repository name".to_owned()); } }; @@ -371,12 +354,12 @@ impl<'a> TryFrom<&'a DockerImage> for DockerHub<'a> { tag: tag, }; - if hub.validate().is_ok() { - Ok(hub) - } else { - let errors = hub.validate().unwrap_err(); - tracing::debug!("DockerHub image properties are not valid {:?}", errors); - return Err(format!("{:?}", errors)); + if let Err(errors) = hub.validate() { + let msg = "DockerHub image properties are not valid. Please verify repository name"; + tracing::debug!("{:?} {:?}", msg, errors); + return Err(format!("{:?}", msg)); } + + Ok(hub) } } \ No newline at end of file diff --git a/src/routes/project/update.rs b/src/routes/project/update.rs index 0303d5c..38d08ea 100644 --- a/src/routes/project/update.rs +++ b/src/routes/project/update.rs @@ -42,14 +42,6 @@ pub async fn item( let project_name = form.custom.custom_stack_code.clone(); - // if let Ok(result) = form.is_readable_docker_image().await { - // if false == result.readable { - // return Err(JsonResponse::::build() - // .set_item(result) - // .bad_request("Can not access docker image")); - // } - // } - match form.is_readable_docker_image().await { Ok(result) => { if false == result.readable { diff --git a/tests/mock_data/custom-stack-payload.json b/tests/mock_data/custom-stack-payload.json index 88fe2c2..f602dbb 100644 --- a/tests/mock_data/custom-stack-payload.json +++ b/tests/mock_data/custom-stack-payload.json @@ -1 +1 @@ -{"commonDomain":"","domainList":{},"region":"","zone":null,"server":"cx11","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":[],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":true,"disk_type":"pd-standart","cloud_token":"*******************","cloud_key":"*********","cloud_secret":"****************","disk_size":40,"provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-annually","custom":{"networks":[{"name":"default_network","id":"lsnd2ttg3ivhw3db5"}],"web":[{"_etag":null,"_id":"lsq2tdff3c0acf2lj","_created":"2023-04-28T09:46:19.470502","_updated":"2024-02-09T13:44:36.854036","name":"PostgREST","code":"postgrest","role":["postgrest"],"type":"web","default":false,"popularity":null,"descr":null,"ports":{"public":["3000","8080"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":null,"category_id":null,"parent_app_id":null,"full_description":null,"description":null,"plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"","form":null,"requirements":null,"docker_image_is_internal":true,"custom_preset":{"volumes":[],"environment":[{"key":"PGRST_OPENAPI_SERVER_PROXY_URI","value":"http://DOMAIN_NAME:3000"},{"key":"PGRST_DB_ANON_ROLE","value":"anon"},{"key":"PGRST_DB_SCHEMA","value":"public"},{"key":"PGHOST","value":"postgresql_host"},{"key":"PGPORT","value":"5432"},{"key":"PGUSER","value":"user"},{"key":"PGDATABASE","value":"database"},{"key":"PGPASSWORD ","value":"password"}],"shared_ports":[{"host_port":"3000","container_port":"3000"}],"restart":"always"},"category":[null],"group":[],"versions":[{"_id":556,"name":"Postgrest","version":"latest","update_status":"published","tag":"latest"}],"links":[{"url":"https://postgrest.org","title":"Vendor","type":"vendor","follow":false},{"repo_owner":"PostgREST","repo_name":"postgrest","type":"github","follow":false}],"version":{"_id":556,"name":"Postgrest","version":"latest","update_status":"published","tag":"latest"},"network":["lsnd2ttg3ivhw3db5"],"restart":"always","timestamp":"2024-02-17T12:50:01.659Z","volumes":[],"environment":[{"key":"PGRST_OPENAPI_SERVER_PROXY_URI","value":"http://DOMAIN_NAME:3000"},{"key":"PGRST_DB_ANON_ROLE","value":"anon"},{"key":"PGRST_DB_SCHEMA","value":"public"},{"key":"PGHOST","value":"postgresql_host"},{"key":"PGPORT","value":"5432"},{"key":"PGUSER","value":"user"},{"key":"PGDATABASE","value":"database"},{"key":"PGPASSWORD ","value":"password"}],"shared_ports":[{"host_port":"3000","container_port":"3000"}],"domain":"","dockerhub_name":"mariadb:11.3.2"}],"feature":[],"service":[],"servers_count":3,"project_name":"Databases","custom_stack_code":"databases"}} \ No newline at end of file +{"commonDomain":"","domainList":{},"region":"","zone":null,"server":"cx11","os":"ubuntu-20.04","ssl":"letsencrypt","vars":[],"integrated_features":[],"extended_features":[],"subscriptions":[],"form_app":[],"save_token":true,"disk_type":"pd-standart","cloud_token":"*******************","cloud_key":"*********","cloud_secret":"****************","disk_size":40,"provider":"htz","stack_code":"custom-stack","selected_plan":"plan-individual-annually","custom":{"networks":[{"name":"default_network","id":"lsnd2ttg3ivhw3db5"}],"web":[{"_etag":null,"_id":"lsq2tdff3c0acf2lj","_created":"2023-04-28T09:46:19.470502","_updated":"2024-02-09T13:44:36.854036","name":"PostgREST","code":"postgrest","role":["postgrest"],"type":"web","default":false,"popularity":null,"descr":null,"ports":{"public":["3000","8080"]},"commercial":null,"subscription":null,"autodeploy":null,"suggested":null,"dependency":null,"avoid_render":null,"price":null,"icon":null,"category_id":null,"parent_app_id":null,"full_description":null,"description":null,"plan_type":null,"ansible_var":null,"repo_dir":null,"cpu":"0.0","ram_size":null,"disk_size":null,"dockerhub_image":"","form":null,"requirements":null,"docker_image_is_internal":true,"custom_preset":{"volumes":[],"environment":[{"key":"PGRST_OPENAPI_SERVER_PROXY_URI","value":"http://DOMAIN_NAME:3000"},{"key":"PGRST_DB_ANON_ROLE","value":"anon"},{"key":"PGRST_DB_SCHEMA","value":"public"},{"key":"PGHOST","value":"postgresql_host"},{"key":"PGPORT","value":"5432"},{"key":"PGUSER","value":"user"},{"key":"PGDATABASE","value":"database"},{"key":"PGPASSWORD ","value":"password"}],"shared_ports":[{"host_port":"3000","container_port":"3000"}],"restart":"always"},"category":[null],"group":[],"versions":[{"_id":556,"name":"Postgrest","version":"latest","update_status":"published","tag":"latest"}],"links":[{"url":"https://postgrest.org","title":"Vendor","type":"vendor","follow":false},{"repo_owner":"PostgREST","repo_name":"postgrest","type":"github","follow":false}],"version":{"_id":556,"name":"Postgrest","version":"latest","update_status":"published","tag":"latest"},"network":["lsnd2ttg3ivhw3db5"],"restart":"always","timestamp":"2024-02-17T12:50:01.659Z","volumes":[],"environment":[{"key":"PGRST_OPENAPI_SERVER_PROXY_URI","value":"http://DOMAIN_NAME:3000"},{"key":"PGRST_DB_ANON_ROLE","value":"anon"},{"key":"PGRST_DB_SCHEMA","value":"public"},{"key":"PGHOST","value":"postgresql_host"},{"key":"PGPORT","value":"5432"},{"key":"PGUSER","value":"user"},{"key":"PGDATABASE","value":"database"},{"key":"PGPASSWORD ","value":"password"}],"shared_ports":[{"host_port":"3000","container_port":"3000"}],"domain":"","dockerhub_name":"mariadb:11.3.2-latest"}],"feature":[],"service":[],"servers_count":3,"project_name":"Databases","custom_stack_code":"databases"}} \ No newline at end of file From 83b9079c9b0f90bc7567f29aa036b9efe141f1a6 Mon Sep 17 00:00:00 2001 From: petru Date: Thu, 11 Apr 2024 18:26:18 +0300 Subject: [PATCH 259/284] 47 --- src/forms/mod.rs | 3 +- src/forms/{rating.rs => rating/add.rs} | 4 +-- src/forms/rating/mod.rs | 5 ++++ src/forms/rating/useredit.rs | 12 ++++++++ src/routes/rating/add.rs | 2 +- src/routes/rating/edit.rs | 38 ++++++++++++++++++++++++++ src/routes/rating/mod.rs | 2 ++ src/startup.rs | 3 +- 8 files changed, 63 insertions(+), 6 deletions(-) rename src/forms/{rating.rs => rating/add.rs} (92%) create mode 100644 src/forms/rating/mod.rs create mode 100644 src/forms/rating/useredit.rs create mode 100644 src/routes/rating/edit.rs diff --git a/src/forms/mod.rs b/src/forms/mod.rs index 0647181..a5651bf 100644 --- a/src/forms/mod.rs +++ b/src/forms/mod.rs @@ -1,10 +1,9 @@ -mod rating; +pub mod rating; pub mod project; pub mod user; pub(crate) mod cloud; pub(crate) mod server; -pub use rating::*; pub use cloud::*; pub use server::*; pub use user::UserForm; diff --git a/src/forms/rating.rs b/src/forms/rating/add.rs similarity index 92% rename from src/forms/rating.rs rename to src/forms/rating/add.rs index e3f8281..a2c90d2 100644 --- a/src/forms/rating.rs +++ b/src/forms/rating/add.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use serde_valid::Validate; #[derive(Serialize, Deserialize, Debug, Validate)] -pub struct Rating { +pub struct AddRating { pub obj_id: i32, // product external id pub category: models::RateCategory, // rating of product | rating of service etc #[validate(max_length = 1000)] @@ -13,7 +13,7 @@ pub struct Rating { pub rate: i32, // } -impl Into for Rating { +impl Into for AddRating { fn into(self) -> models::Rating { let mut rating = models::Rating::default(); rating.obj_id = self.obj_id; diff --git a/src/forms/rating/mod.rs b/src/forms/rating/mod.rs new file mode 100644 index 0000000..ae8dbdf --- /dev/null +++ b/src/forms/rating/mod.rs @@ -0,0 +1,5 @@ +mod add; +mod useredit; + +pub use add::AddRating as Add; +pub use useredit::UserEditRating as UserEdit; diff --git a/src/forms/rating/useredit.rs b/src/forms/rating/useredit.rs new file mode 100644 index 0000000..668a1da --- /dev/null +++ b/src/forms/rating/useredit.rs @@ -0,0 +1,12 @@ +use crate::models; +use serde::{Deserialize, Serialize}; +use serde_valid::Validate; + +#[derive(Serialize, Deserialize, Debug, Validate)] +pub struct UserEditRating { + #[validate(max_length = 1000)] + pub comment: Option, // always linked to a product + #[validate(minimum = 0)] + #[validate(maximum = 10)] + pub rate: i32, // +} diff --git a/src/routes/rating/add.rs b/src/routes/rating/add.rs index e91dbe6..34d8c50 100644 --- a/src/routes/rating/add.rs +++ b/src/routes/rating/add.rs @@ -15,7 +15,7 @@ use std::sync::Arc; #[post("")] pub async fn add_handler( user: web::ReqData>, - form: web::Json, + form: web::Json, pg_pool: web::Data, ) -> Result { let _product = db::product::fetch_by_obj(pg_pool.get_ref(), form.obj_id) diff --git a/src/routes/rating/edit.rs b/src/routes/rating/edit.rs new file mode 100644 index 0000000..e8ca98a --- /dev/null +++ b/src/routes/rating/edit.rs @@ -0,0 +1,38 @@ +use crate::forms; +use crate::helpers::JsonResponse; +use crate::models; +use crate::db; +use actix_web::{put, web, Responder, Result}; +use sqlx::PgPool; +use std::sync::Arc; + +// workflow +// add, update, list, get(user_id), ACL, +// ACL - access to func for a user +// ACL - access to objects for a user + +#[tracing::instrument(name = "User edit rating.")] +#[put("")] +pub async fn user_edit_handler( + path: web::Path<(i32,)>, + user: web::ReqData>, + form: web::Json, + pg_pool: web::Data, +) -> Result { + let rate_id = path.0; + let rating = db::rating::fetch(pg_pool.get_ref(), rate_id) + .await + .map_err(|_err| JsonResponse::::build().internal_server_error("")) + .and_then(|rating| { + match rating { + Some(rating) => { Ok(rating) }, + None => Err(JsonResponse::::build().not_found("not found")) + } + })?; + + //todo check if form is valid + //todo add update_model function to form + //todo add the db saving of the model + + Ok(JsonResponse::build().set_item(rating).ok("OK")) +} diff --git a/src/routes/rating/mod.rs b/src/routes/rating/mod.rs index b13668a..c654b78 100644 --- a/src/routes/rating/mod.rs +++ b/src/routes/rating/mod.rs @@ -1,5 +1,7 @@ pub mod add; pub mod get; +mod edit; pub use add::*; pub use get::*; +pub use edit::*; diff --git a/src/startup.rs b/src/startup.rs index e199afa..814ca91 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -62,7 +62,8 @@ pub async fn run( web::scope("/rating") .service(routes::rating::add_handler) .service(routes::rating::get_handler) - .service(routes::rating::list_handler), + .service(routes::rating::list_handler) + .service(routes::rating::user_edit_handler), ) .service( web::scope("/project") From 15744042843c8fe443e8438b2ae378ff0091fae0 Mon Sep 17 00:00:00 2001 From: vsilent Date: Fri, 12 Apr 2024 11:54:35 +0300 Subject: [PATCH 260/284] social field should be optional --- src/forms/user.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/forms/user.rs b/src/forms/user.rs index 0c58d75..9009c7a 100644 --- a/src/forms/user.rs +++ b/src/forms/user.rs @@ -25,7 +25,7 @@ pub struct User { pub email: String, #[serde(rename = "email_confirmed")] pub email_confirmed: bool, - pub social: bool, + pub social: Option, pub website: Option, pub currency: Value, pub phone: Option, From b7b3db518f344c4ff0b20e05f6a428a588095a8a Mon Sep 17 00:00:00 2001 From: vsilent Date: Fri, 12 Apr 2024 12:06:30 +0300 Subject: [PATCH 261/284] cleanup --- src/forms/user.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/forms/user.rs b/src/forms/user.rs index 9009c7a..5cf6735 100644 --- a/src/forms/user.rs +++ b/src/forms/user.rs @@ -129,9 +129,6 @@ pub struct SuspensionHints { impl TryInto for UserForm { type Error = String; fn try_into(self) -> Result { - // let id = self.id.parse::().map_err( - // |msg| { format!("{:?}", msg) } - // )?; Ok(UserModel { id: self.user.id, first_name: self.user.first_name.unwrap_or("Noname".to_string()), From dba85f876720d272a28c6f700b7fa9b2ffc394a3 Mon Sep 17 00:00:00 2001 From: petru Date: Fri, 12 Apr 2024 16:57:52 +0300 Subject: [PATCH 262/284] 47 validate rating when added --- src/routes/rating/add.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/routes/rating/add.rs b/src/routes/rating/add.rs index 34d8c50..7770eaa 100644 --- a/src/routes/rating/add.rs +++ b/src/routes/rating/add.rs @@ -5,6 +5,7 @@ use crate::db; use actix_web::{post, web, Responder, Result}; use sqlx::PgPool; use std::sync::Arc; +use serde_valid::Validate; // workflow // add, update, list, get(user_id), ACL, @@ -18,6 +19,10 @@ pub async fn add_handler( form: web::Json, pg_pool: web::Data, ) -> Result { + if let Err(errors) = form.validate() { + return Err(JsonResponse::::build().form_error(errors.to_string())); + } + let _product = db::product::fetch_by_obj(pg_pool.get_ref(), form.obj_id) .await .map_err(|_msg| JsonResponse::::build().internal_server_error(_msg))? From 2c189c92f05570588c5c49f10ab5029d33d277f5 Mon Sep 17 00:00:00 2001 From: petru Date: Fri, 12 Apr 2024 17:31:09 +0300 Subject: [PATCH 263/284] 47 casbin rule for user edit rating --- .../20240412141011_casbin_user_rating_edit.down.sql | 3 +++ .../20240412141011_casbin_user_rating_edit.up.sql | 5 +++++ src/routes/rating/edit.rs | 11 ++++++++--- 3 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 migrations/20240412141011_casbin_user_rating_edit.down.sql create mode 100644 migrations/20240412141011_casbin_user_rating_edit.up.sql diff --git a/migrations/20240412141011_casbin_user_rating_edit.down.sql b/migrations/20240412141011_casbin_user_rating_edit.down.sql new file mode 100644 index 0000000..66634cc --- /dev/null +++ b/migrations/20240412141011_casbin_user_rating_edit.down.sql @@ -0,0 +1,3 @@ +-- Add down migration script here +DELETE FROM casbin_rule +WHERE ptype = 'p' and v0 = 'group_user' and v1 = '/rating/:id' and v2 = 'PUT'; diff --git a/migrations/20240412141011_casbin_user_rating_edit.up.sql b/migrations/20240412141011_casbin_user_rating_edit.up.sql new file mode 100644 index 0000000..79d4b19 --- /dev/null +++ b/migrations/20240412141011_casbin_user_rating_edit.up.sql @@ -0,0 +1,5 @@ +-- Add up migration script here +INSERT INTO casbin_rule +(id, ptype, v0, v1, v2, v3, v4, v5) +VALUES((select max(id) + 1 from casbin_rule cr), 'p', 'group_user', '/rating/:id', 'PUT', '', '', ''); + diff --git a/src/routes/rating/edit.rs b/src/routes/rating/edit.rs index e8ca98a..69399e2 100644 --- a/src/routes/rating/edit.rs +++ b/src/routes/rating/edit.rs @@ -5,6 +5,7 @@ use crate::db; use actix_web::{put, web, Responder, Result}; use sqlx::PgPool; use std::sync::Arc; +use serde_valid::Validate; // workflow // add, update, list, get(user_id), ACL, @@ -12,25 +13,29 @@ use std::sync::Arc; // ACL - access to objects for a user #[tracing::instrument(name = "User edit rating.")] -#[put("")] +#[put("/{id}")] pub async fn user_edit_handler( path: web::Path<(i32,)>, user: web::ReqData>, form: web::Json, pg_pool: web::Data, ) -> Result { + if let Err(errors) = form.validate() { + return Err(JsonResponse::::build().form_error(errors.to_string())); + } + let rate_id = path.0; let rating = db::rating::fetch(pg_pool.get_ref(), rate_id) .await .map_err(|_err| JsonResponse::::build().internal_server_error("")) .and_then(|rating| { match rating { - Some(rating) => { Ok(rating) }, + Some(rating) if rating.user_id != user.id => Err(JsonResponse::::build().not_found("not found")), + Some(rating) => Ok(rating), None => Err(JsonResponse::::build().not_found("not found")) } })?; - //todo check if form is valid //todo add update_model function to form //todo add the db saving of the model From ef67676c33b86a1b8524a4d95148b50253e25216 Mon Sep 17 00:00:00 2001 From: petru Date: Fri, 12 Apr 2024 17:50:06 +0300 Subject: [PATCH 264/284] 47 edit rating logic --- src/db/rating.rs | 28 ++++++++++++++++++++++++++++ src/forms/rating/useredit.rs | 15 ++++++++++++++- src/routes/rating/edit.rs | 17 +++++++++++++---- 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/src/db/rating.rs b/src/db/rating.rs index 599c49c..114d47d 100644 --- a/src/db/rating.rs +++ b/src/db/rating.rs @@ -131,3 +131,31 @@ pub async fn insert(pool: &PgPool, mut rating: models::Rating) -> Result Result { + let query_span = tracing::info_span!("Updating rating into the database"); + sqlx::query!( + r#" + UPDATE rating + SET + comment=$1, + rate=$2, + updated_at=NOW() at time zone 'utc' + WHERE id = $3 + "#, + rating.comment, + rating.rate, + rating.id + ) + .execute(pool) + .instrument(query_span) + .await + .map(|_|{ + tracing::info!("Rating {} has been saved to the database", rating.id); + rating + }) + .map_err(|err| { + tracing::error!("Failed to execute query: {:?}", err); + "".to_string() + }) +} diff --git a/src/forms/rating/useredit.rs b/src/forms/rating/useredit.rs index 668a1da..4f5ae02 100644 --- a/src/forms/rating/useredit.rs +++ b/src/forms/rating/useredit.rs @@ -8,5 +8,18 @@ pub struct UserEditRating { pub comment: Option, // always linked to a product #[validate(minimum = 0)] #[validate(maximum = 10)] - pub rate: i32, // + pub rate: Option, // +} + +impl UserEditRating { + pub fn update(self, rating: &mut models::Rating) + { + if let Some(comment) = self.comment { + rating.comment.insert(comment); + } + + if let Some(rate) = self.rate { + rating.rate.insert(rate); + } + } } diff --git a/src/routes/rating/edit.rs b/src/routes/rating/edit.rs index 69399e2..90b1d4a 100644 --- a/src/routes/rating/edit.rs +++ b/src/routes/rating/edit.rs @@ -25,7 +25,7 @@ pub async fn user_edit_handler( } let rate_id = path.0; - let rating = db::rating::fetch(pg_pool.get_ref(), rate_id) + let mut rating = db::rating::fetch(pg_pool.get_ref(), rate_id) .await .map_err(|_err| JsonResponse::::build().internal_server_error("")) .and_then(|rating| { @@ -36,8 +36,17 @@ pub async fn user_edit_handler( } })?; - //todo add update_model function to form - //todo add the db saving of the model + form.into_inner().update(&mut rating); - Ok(JsonResponse::build().set_item(rating).ok("OK")) + db::rating::update(pg_pool.get_ref(), rating) + .await + .map(|rating| { + JsonResponse::::build() + .set_item(rating) + .ok("success") + }) + .map_err(|err| { + tracing::error!("Failed to execute query: {:?}", err); + JsonResponse::::build().internal_server_error("Rating not update") + }) } From dbe6b9a76a1ab36347c6f1de78f7ef997af10495 Mon Sep 17 00:00:00 2001 From: petru Date: Fri, 12 Apr 2024 21:23:17 +0300 Subject: [PATCH 265/284] 47 show only visible --- src/db/rating.rs | 32 +++++++++++++++++++++++++++++++- src/routes/rating/add.rs | 2 +- src/routes/rating/get.rs | 6 +++--- src/startup.rs | 6 +++--- 4 files changed, 38 insertions(+), 8 deletions(-) diff --git a/src/db/rating.rs b/src/db/rating.rs index 114d47d..e56a747 100644 --- a/src/db/rating.rs +++ b/src/db/rating.rs @@ -16,7 +16,9 @@ pub async fn fetch_all(pool: &PgPool) -> Result, String> { rate, created_at, updated_at - FROM rating"# + FROM rating + ORDER BY id DESC + "# ) .fetch_all(pool) .instrument(query_span) @@ -159,3 +161,31 @@ pub async fn update(pool: &PgPool, rating: models::Rating) -> Result Result, String> { + let query_span = tracing::info_span!("Fetch all ratings."); + sqlx::query_as!( + models::Rating, + r#"SELECT + id, + user_id, + obj_id, + category as "category: _", + comment, + hidden, + rate, + created_at, + updated_at + FROM rating + WHERE hidden = false + ORDER BY id DESC + "#, + ) + .fetch_all(pool) + .instrument(query_span) + .await + .map_err(|e| { + tracing::error!("Failed to execute fetch query: {:?}", e); + "".to_string() + }) +} diff --git a/src/routes/rating/add.rs b/src/routes/rating/add.rs index 7770eaa..ff7de88 100644 --- a/src/routes/rating/add.rs +++ b/src/routes/rating/add.rs @@ -14,7 +14,7 @@ use serde_valid::Validate; #[tracing::instrument(name = "Add rating.")] #[post("")] -pub async fn add_handler( +pub async fn user_add_handler( user: web::ReqData>, form: web::Json, pg_pool: web::Data, diff --git a/src/routes/rating/get.rs b/src/routes/rating/get.rs index 46c138a..f6edc84 100644 --- a/src/routes/rating/get.rs +++ b/src/routes/rating/get.rs @@ -6,7 +6,7 @@ use sqlx::PgPool; #[tracing::instrument(name = "Get rating.")] #[get("/{id}")] -pub async fn get_handler( +pub async fn anonymous_get_handler( path: web::Path<(i32,)>, pg_pool: web::Data, ) -> Result { @@ -26,11 +26,11 @@ pub async fn get_handler( #[tracing::instrument(name = "Get all ratings.")] #[get("")] -pub async fn list_handler( +pub async fn anonymous_list_handler( path: web::Path<()>, pg_pool: web::Data, ) -> Result { - db::rating::fetch_all(pg_pool.get_ref()) + db::rating::fetch_all_visible(pg_pool.get_ref()) .await .map(|ratings| JsonResponse::build().set_list(ratings).ok("OK")) .map_err(|_err| JsonResponse::::build().internal_server_error("")) diff --git a/src/startup.rs b/src/startup.rs index 814ca91..8868858 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -60,9 +60,9 @@ pub async fn run( ) .service( web::scope("/rating") - .service(routes::rating::add_handler) - .service(routes::rating::get_handler) - .service(routes::rating::list_handler) + .service(routes::rating::user_add_handler) + .service(routes::rating::anonymous_get_handler) + .service(routes::rating::anonymous_list_handler) .service(routes::rating::user_edit_handler), ) .service( From 4758398d6ee52b0b01ead63874e01a4137ce2e0f Mon Sep 17 00:00:00 2001 From: petru Date: Fri, 12 Apr 2024 21:29:30 +0300 Subject: [PATCH 266/284] 47 anonymous_get visible --- src/routes/rating/edit.rs | 5 ++--- src/routes/rating/get.rs | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/routes/rating/edit.rs b/src/routes/rating/edit.rs index 90b1d4a..06a65a8 100644 --- a/src/routes/rating/edit.rs +++ b/src/routes/rating/edit.rs @@ -30,9 +30,8 @@ pub async fn user_edit_handler( .map_err(|_err| JsonResponse::::build().internal_server_error("")) .and_then(|rating| { match rating { - Some(rating) if rating.user_id != user.id => Err(JsonResponse::::build().not_found("not found")), - Some(rating) => Ok(rating), - None => Err(JsonResponse::::build().not_found("not found")) + Some(rating) if rating.user_id == user.id=> Ok(rating), + _ => Err(JsonResponse::::build().not_found("not found")) } })?; diff --git a/src/routes/rating/get.rs b/src/routes/rating/get.rs index f6edc84..3e7d958 100644 --- a/src/routes/rating/get.rs +++ b/src/routes/rating/get.rs @@ -16,8 +16,8 @@ pub async fn anonymous_get_handler( .map_err(|_err| JsonResponse::::build().internal_server_error("")) .and_then(|rating| { match rating { - Some(rating) => { Ok(rating) }, - None => Err(JsonResponse::::build().not_found("not found")) + Some(rating) if rating.hidden == Some(false) => { Ok(rating) }, + _ => Err(JsonResponse::::build().not_found("not found")) } })?; From 1390f700c643d66a1735e291a1deec4ce2ac1476 Mon Sep 17 00:00:00 2001 From: petru Date: Fri, 12 Apr 2024 21:38:56 +0300 Subject: [PATCH 267/284] 47 admin_get_rating --- ...412141011_casbin_user_rating_edit.down.sql | 3 +++ ...40412141011_casbin_user_rating_edit.up.sql | 3 +++ src/routes/rating/get.rs | 24 +++++++++++++++++-- src/startup.rs | 4 ++++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/migrations/20240412141011_casbin_user_rating_edit.down.sql b/migrations/20240412141011_casbin_user_rating_edit.down.sql index 66634cc..24fb943 100644 --- a/migrations/20240412141011_casbin_user_rating_edit.down.sql +++ b/migrations/20240412141011_casbin_user_rating_edit.down.sql @@ -1,3 +1,6 @@ -- Add down migration script here DELETE FROM casbin_rule WHERE ptype = 'p' and v0 = 'group_user' and v1 = '/rating/:id' and v2 = 'PUT'; + +DELETE FROM casbin_rule +WHERE ptype = 'p' and v0 = 'group_admin' and v1 = '/admin/rating/:id' and v2 = 'GET'; diff --git a/migrations/20240412141011_casbin_user_rating_edit.up.sql b/migrations/20240412141011_casbin_user_rating_edit.up.sql index 79d4b19..845e59b 100644 --- a/migrations/20240412141011_casbin_user_rating_edit.up.sql +++ b/migrations/20240412141011_casbin_user_rating_edit.up.sql @@ -3,3 +3,6 @@ INSERT INTO casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES((select max(id) + 1 from casbin_rule cr), 'p', 'group_user', '/rating/:id', 'PUT', '', '', ''); +INSERT INTO casbin_rule +(id, ptype, v0, v1, v2, v3, v4, v5) +VALUES((select max(id) + 1 from casbin_rule cr), 'p', 'group_admin', '/admin/rating/:id', 'GET', '', '', ''); diff --git a/src/routes/rating/get.rs b/src/routes/rating/get.rs index 3e7d958..4b54f20 100644 --- a/src/routes/rating/get.rs +++ b/src/routes/rating/get.rs @@ -4,7 +4,7 @@ use crate::models; use actix_web::{get, web, Responder, Result}; use sqlx::PgPool; -#[tracing::instrument(name = "Get rating.")] +#[tracing::instrument(name = "Anonymouse get rating.")] #[get("/{id}")] pub async fn anonymous_get_handler( path: web::Path<(i32,)>, @@ -24,7 +24,7 @@ pub async fn anonymous_get_handler( Ok(JsonResponse::build().set_item(rating).ok("OK")) } -#[tracing::instrument(name = "Get all ratings.")] +#[tracing::instrument(name = "Anonymous get all ratings.")] #[get("")] pub async fn anonymous_list_handler( path: web::Path<()>, @@ -35,3 +35,23 @@ pub async fn anonymous_list_handler( .map(|ratings| JsonResponse::build().set_list(ratings).ok("OK")) .map_err(|_err| JsonResponse::::build().internal_server_error("")) } + +#[tracing::instrument(name = "Admin get rating.")] +#[get("/{id}")] +pub async fn admin_get_handler( + path: web::Path<(i32,)>, + pg_pool: web::Data, +) -> Result { + let rate_id = path.0; + let rating = db::rating::fetch(pg_pool.get_ref(), rate_id) + .await + .map_err(|_err| JsonResponse::::build().internal_server_error("")) + .and_then(|rating| { + match rating { + Some(rating) => { Ok(rating) }, + _ => Err(JsonResponse::::build().not_found("not found")) + } + })?; + + Ok(JsonResponse::build().set_item(rating).ok("OK")) +} diff --git a/src/startup.rs b/src/startup.rs index 8868858..0fb7d54 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -78,6 +78,10 @@ pub async fn run( ) .service( web::scope("/admin") + .service( + web::scope("/rating") + .service(routes::rating::admin_get_handler) + ) .service( web::scope("/project") .service(crate::routes::project::get::admin_list) From 842df597ea73a9e1184dd73b765352b3cc046a30 Mon Sep 17 00:00:00 2001 From: petru Date: Fri, 12 Apr 2024 21:46:38 +0300 Subject: [PATCH 268/284] 47 admin_list_handler, transaction --- .../20240412141011_casbin_user_rating_edit.down.sql | 3 +++ .../20240412141011_casbin_user_rating_edit.up.sql | 8 ++++++++ src/routes/rating/get.rs | 12 ++++++++++++ src/startup.rs | 1 + 4 files changed, 24 insertions(+) diff --git a/migrations/20240412141011_casbin_user_rating_edit.down.sql b/migrations/20240412141011_casbin_user_rating_edit.down.sql index 24fb943..a9a6679 100644 --- a/migrations/20240412141011_casbin_user_rating_edit.down.sql +++ b/migrations/20240412141011_casbin_user_rating_edit.down.sql @@ -4,3 +4,6 @@ WHERE ptype = 'p' and v0 = 'group_user' and v1 = '/rating/:id' and v2 = 'PUT'; DELETE FROM casbin_rule WHERE ptype = 'p' and v0 = 'group_admin' and v1 = '/admin/rating/:id' and v2 = 'GET'; + +DELETE FROM casbin_rule +WHERE ptype = 'p' and v0 = 'group_admin' and v1 = '/admin/rating' and v2 = 'GET'; diff --git a/migrations/20240412141011_casbin_user_rating_edit.up.sql b/migrations/20240412141011_casbin_user_rating_edit.up.sql index 845e59b..ca44313 100644 --- a/migrations/20240412141011_casbin_user_rating_edit.up.sql +++ b/migrations/20240412141011_casbin_user_rating_edit.up.sql @@ -1,4 +1,6 @@ -- Add up migration script here +BEGIN TRANSACTION; + INSERT INTO casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES((select max(id) + 1 from casbin_rule cr), 'p', 'group_user', '/rating/:id', 'PUT', '', '', ''); @@ -6,3 +8,9 @@ VALUES((select max(id) + 1 from casbin_rule cr), 'p', 'group_user', '/rating/:id INSERT INTO casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES((select max(id) + 1 from casbin_rule cr), 'p', 'group_admin', '/admin/rating/:id', 'GET', '', '', ''); + +INSERT INTO casbin_rule +(id, ptype, v0, v1, v2, v3, v4, v5) +VALUES((select max(id) + 1 from casbin_rule cr), 'p', 'group_admin', '/admin/rating', 'GET', '', '', ''); + +COMMIT TRANSACTION; diff --git a/src/routes/rating/get.rs b/src/routes/rating/get.rs index 4b54f20..1880b7b 100644 --- a/src/routes/rating/get.rs +++ b/src/routes/rating/get.rs @@ -55,3 +55,15 @@ pub async fn admin_get_handler( Ok(JsonResponse::build().set_item(rating).ok("OK")) } + +#[tracing::instrument(name = "Admin get the list of ratings.")] +#[get("")] +pub async fn admin_list_handler( + path: web::Path<()>, + pg_pool: web::Data, +) -> Result { + db::rating::fetch_all(pg_pool.get_ref()) + .await + .map(|ratings| JsonResponse::build().set_list(ratings).ok("OK")) + .map_err(|_err| JsonResponse::::build().internal_server_error("")) +} diff --git a/src/startup.rs b/src/startup.rs index 0fb7d54..b798ea8 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -81,6 +81,7 @@ pub async fn run( .service( web::scope("/rating") .service(routes::rating::admin_get_handler) + .service(routes::rating::admin_list_handler) ) .service( web::scope("/project") From 9b130dd62c82ed758181dd9a12dcc14c7be36efb Mon Sep 17 00:00:00 2001 From: petru Date: Fri, 12 Apr 2024 22:03:51 +0300 Subject: [PATCH 269/284] 47 user delete rating. partially --- ...412141011_casbin_user_rating_edit.down.sql | 3 +++ ...40412141011_casbin_user_rating_edit.up.sql | 4 +++ src/routes/rating/delete.rs | 25 +++++++++++++++++++ src/routes/rating/mod.rs | 2 ++ src/startup.rs | 3 ++- 5 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/routes/rating/delete.rs diff --git a/migrations/20240412141011_casbin_user_rating_edit.down.sql b/migrations/20240412141011_casbin_user_rating_edit.down.sql index a9a6679..32e4c56 100644 --- a/migrations/20240412141011_casbin_user_rating_edit.down.sql +++ b/migrations/20240412141011_casbin_user_rating_edit.down.sql @@ -2,6 +2,9 @@ DELETE FROM casbin_rule WHERE ptype = 'p' and v0 = 'group_user' and v1 = '/rating/:id' and v2 = 'PUT'; +DELETE FROM casbin_rule +WHERE ptype = 'p' and v0 = 'group_user' and v1 = '/rating/:id' and v2 = 'DELETE'; + DELETE FROM casbin_rule WHERE ptype = 'p' and v0 = 'group_admin' and v1 = '/admin/rating/:id' and v2 = 'GET'; diff --git a/migrations/20240412141011_casbin_user_rating_edit.up.sql b/migrations/20240412141011_casbin_user_rating_edit.up.sql index ca44313..51f85fa 100644 --- a/migrations/20240412141011_casbin_user_rating_edit.up.sql +++ b/migrations/20240412141011_casbin_user_rating_edit.up.sql @@ -5,6 +5,10 @@ INSERT INTO casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES((select max(id) + 1 from casbin_rule cr), 'p', 'group_user', '/rating/:id', 'PUT', '', '', ''); +INSERT INTO casbin_rule +(id, ptype, v0, v1, v2, v3, v4, v5) +VALUES((select max(id) + 1 from casbin_rule cr), 'p', 'group_user', '/rating/:id', 'DELETE', '', '', ''); + INSERT INTO casbin_rule (id, ptype, v0, v1, v2, v3, v4, v5) VALUES((select max(id) + 1 from casbin_rule cr), 'p', 'group_admin', '/admin/rating/:id', 'GET', '', '', ''); diff --git a/src/routes/rating/delete.rs b/src/routes/rating/delete.rs new file mode 100644 index 0000000..646ea1d --- /dev/null +++ b/src/routes/rating/delete.rs @@ -0,0 +1,25 @@ +use crate::db; +use crate::helpers::JsonResponse; +use crate::models; +use actix_web::{delete, web, Responder, Result}; +use sqlx::PgPool; + +#[tracing::instrument(name = "User delete rating.")] +#[delete("/{id}")] +pub async fn user_delete_handler( + path: web::Path<(i32,)>, + pg_pool: web::Data, +) -> Result { + let rate_id = path.0; + let rating = db::rating::fetch(pg_pool.get_ref(), rate_id) + .await + .map_err(|_err| JsonResponse::::build().internal_server_error("")) + .and_then(|rating| { + match rating { + Some(rating) if rating.hidden == Some(false) => { Ok(rating) }, + _ => Err(JsonResponse::::build().not_found("not found")) + } + })?; + + Ok(JsonResponse::build().set_item(rating).ok("OK")) +} diff --git a/src/routes/rating/mod.rs b/src/routes/rating/mod.rs index c654b78..2bd48db 100644 --- a/src/routes/rating/mod.rs +++ b/src/routes/rating/mod.rs @@ -1,7 +1,9 @@ pub mod add; pub mod get; mod edit; +mod delete; pub use add::*; pub use get::*; pub use edit::*; +pub use delete::*; diff --git a/src/startup.rs b/src/startup.rs index b798ea8..e070bea 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -60,9 +60,10 @@ pub async fn run( ) .service( web::scope("/rating") - .service(routes::rating::user_add_handler) .service(routes::rating::anonymous_get_handler) .service(routes::rating::anonymous_list_handler) + .service(routes::rating::user_add_handler) + .service(routes::rating::user_delete_handler) .service(routes::rating::user_edit_handler), ) .service( From 72ce432c711d75f05ced0c4d6219b46d7c23d11b Mon Sep 17 00:00:00 2001 From: petru Date: Sat, 13 Apr 2024 15:16:43 +0300 Subject: [PATCH 270/284] 47 user delete rating --- src/db/rating.rs | 4 +++- src/routes/rating/delete.rs | 18 +++++++++++++++--- src/routes/rating/edit.rs | 2 +- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/db/rating.rs b/src/db/rating.rs index e56a747..32f1948 100644 --- a/src/db/rating.rs +++ b/src/db/rating.rs @@ -142,11 +142,13 @@ pub async fn update(pool: &PgPool, rating: models::Rating) -> Result