feat & chore: update actix-web and deps and use actix-auth-middleware for guarding auth routes

This commit is contained in:
Aravinth Manivannan 2022-03-26 12:45:36 +05:30
parent 81f3f5e450
commit 7ff66c551d
Signed by: realaravinth
GPG key ID: AD9F0F08E855ED88
21 changed files with 877 additions and 949 deletions

1143
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -22,10 +22,10 @@ name = "tests-migrate"
path = "./src/tests-migrate.rs" path = "./src/tests-migrate.rs"
[dependencies] [dependencies]
actix-web = "4.0.0-beta.9" actix-web = "4.0.1"
actix-identity = "0.4.0-beta.2" actix-identity = "0.4.0-beta.2"
actix-session = "0.5.0-beta.2" actix-session = { version = "0.6.1", features = ["cookie-session"]}
actix-http = "3.0.0-beta.8" actix-http = "3.0.4"
actix-rt = "2" actix-rt = "2"
actix-cors = "0.6.0-beta.2" actix-cors = "0.6.0-beta.2"
actix-service = "2.0.0" actix-service = "2.0.0"
@ -40,7 +40,7 @@ sqlx = { version = "0.5.9", features = [ "runtime-actix-rustls", "postgres", "ti
argon2-creds = { branch = "master", git = "https://github.com/realaravinth/argon2-creds"} argon2-creds = { branch = "master", git = "https://github.com/realaravinth/argon2-creds"}
derive_builder = "0.10" derive_builder = "0.11"
validator = { version = "0.14", features = ["derive"]} validator = { version = "0.14", features = ["derive"]}
derive_more = "0.99" derive_more = "0.99"
@ -69,6 +69,13 @@ sailfish = "0.3.2"
#tokio = "1.11.0" #tokio = "1.11.0"
[dependencies.actix-auth-middleware]
branch = "v4"
features = ["actix_identity_backend"]
git = "https://github.com/realaravinth/actix-auth-middleware"
version = "0.2"
[build-dependencies] [build-dependencies]
sqlx = { version = "0.5.9", features = [ "runtime-actix-rustls", "uuid", "postgres", "time", "offline" ] } sqlx = { version = "0.5.9", features = [ "runtime-actix-rustls", "uuid", "postgres", "time", "offline" ] }
#serde_yaml = "0.8.17" #serde_yaml = "0.8.17"

View file

@ -1,82 +1,82 @@
{ {
"db": "PostgreSQL", "db": "PostgreSQL",
"03c9789e83a398bed96354924a0e63ccaa97bec667fda1b8277bb9afda9a6fcd": { "03c9789e83a398bed96354924a0e63ccaa97bec667fda1b8277bb9afda9a6fcd": {
"query": "DELETE \n FROM survey_campaigns \n WHERE \n user_id = (\n SELECT \n ID \n FROM \n survey_admins \n WHERE \n name = $1\n )\n AND\n id = ($2)",
"describe": { "describe": {
"columns": [], "columns": [],
"nullable": [],
"parameters": { "parameters": {
"Left": [ "Left": [
"Text", "Text",
"Uuid" "Uuid"
] ]
},
"nullable": []
} }
}, },
"query": "DELETE \n FROM survey_campaigns \n WHERE \n user_id = (\n SELECT \n ID \n FROM \n survey_admins \n WHERE \n name = $1\n )\n AND\n id = ($2)"
},
"0d22134cc5076304b7895827f006ee8269cc500f400114a7472b83f0f1c568b5": { "0d22134cc5076304b7895827f006ee8269cc500f400114a7472b83f0f1c568b5": {
"query": "INSERT INTO survey_admins \n (name , password, secret) VALUES ($1, $2, $3)",
"describe": { "describe": {
"columns": [], "columns": [],
"nullable": [],
"parameters": { "parameters": {
"Left": [ "Left": [
"Varchar", "Varchar",
"Text", "Text",
"Varchar" "Varchar"
] ]
},
"nullable": []
} }
}, },
"query": "INSERT INTO survey_admins \n (name , password, secret) VALUES ($1, $2, $3)"
},
"1373df097fa0e58b23a374753318ae53a44559aa0e7eb64680185baf1c481723": { "1373df097fa0e58b23a374753318ae53a44559aa0e7eb64680185baf1c481723": {
"query": "SELECT password FROM survey_admins WHERE name = ($1)",
"describe": { "describe": {
"columns": [ "columns": [
{ {
"ordinal": 0,
"name": "password", "name": "password",
"ordinal": 0,
"type_info": "Text" "type_info": "Text"
} }
], ],
"nullable": [
false
],
"parameters": { "parameters": {
"Left": [ "Left": [
"Text" "Text"
] ]
},
"nullable": [
false
]
} }
}, },
"query": "SELECT password FROM survey_admins WHERE name = ($1)"
},
"19686bfe8772cbc6831d46d18994e2b9aa40c7181eae9a31e51451cce95f04e8": { "19686bfe8772cbc6831d46d18994e2b9aa40c7181eae9a31e51451cce95f04e8": {
"query": "SELECT name, password FROM survey_admins WHERE email = ($1)",
"describe": { "describe": {
"columns": [ "columns": [
{ {
"ordinal": 0,
"name": "name", "name": "name",
"ordinal": 0,
"type_info": "Varchar" "type_info": "Varchar"
}, },
{ {
"ordinal": 1,
"name": "password", "name": "password",
"ordinal": 1,
"type_info": "Text" "type_info": "Text"
} }
], ],
"nullable": [
false,
false
],
"parameters": { "parameters": {
"Left": [ "Left": [
"Text" "Text"
] ]
},
"nullable": [
false,
false
]
} }
}, },
"query": "SELECT name, password FROM survey_admins WHERE email = ($1)"
},
"1b7e17bfc949fa97e8dec1f95e35a02bcf3aa1aa72a1f6f6c8884e885fc3b953": { "1b7e17bfc949fa97e8dec1f95e35a02bcf3aa1aa72a1f6f6c8884e885fc3b953": {
"query": "insert into survey_admins \n (name , password, email, secret) values ($1, $2, $3, $4)",
"describe": { "describe": {
"columns": [], "columns": [],
"nullable": [],
"parameters": { "parameters": {
"Left": [ "Left": [
"Varchar", "Varchar",
@ -84,152 +84,152 @@
"Varchar", "Varchar",
"Varchar" "Varchar"
] ]
},
"nullable": []
} }
}, },
"query": "insert into survey_admins \n (name , password, email, secret) values ($1, $2, $3, $4)"
},
"2ccaecfee4d2f29ef5278188b304017719720aa986d680d4727a1facbb869c7a": { "2ccaecfee4d2f29ef5278188b304017719720aa986d680d4727a1facbb869c7a": {
"query": "DELETE FROM survey_admins WHERE name = ($1)",
"describe": { "describe": {
"columns": [], "columns": [],
"nullable": [],
"parameters": { "parameters": {
"Left": [ "Left": [
"Text" "Text"
] ]
},
"nullable": []
} }
}, },
"query": "DELETE FROM survey_admins WHERE name = ($1)"
},
"43b3e771f38bf8059832169227705be06a28925af1b3799ffef5371d511fd138": { "43b3e771f38bf8059832169227705be06a28925af1b3799ffef5371d511fd138": {
"query": "\n INSERT INTO survey_users (created_at, id) VALUES($1, $2)",
"describe": { "describe": {
"columns": [], "columns": [],
"nullable": [],
"parameters": { "parameters": {
"Left": [ "Left": [
"Timestamptz", "Timestamptz",
"Uuid" "Uuid"
] ]
},
"nullable": []
} }
}, },
"query": "\n INSERT INTO survey_users (created_at, id) VALUES($1, $2)"
},
"536541ecf2e1c0403c74b6e2e09b42b73a7741ae4a348ff539ac410022e03ace": { "536541ecf2e1c0403c74b6e2e09b42b73a7741ae4a348ff539ac410022e03ace": {
"query": "SELECT EXISTS (SELECT 1 from survey_admins WHERE name = $1)",
"describe": { "describe": {
"columns": [ "columns": [
{ {
"ordinal": 0,
"name": "exists", "name": "exists",
"ordinal": 0,
"type_info": "Bool" "type_info": "Bool"
} }
], ],
"nullable": [
null
],
"parameters": { "parameters": {
"Left": [ "Left": [
"Text" "Text"
] ]
},
"nullable": [
null
]
} }
}, },
"query": "SELECT EXISTS (SELECT 1 from survey_admins WHERE name = $1)"
},
"55dde28998a6d12744806035f0a648494a403c7d09ea3caf91bf54869a81aa73": { "55dde28998a6d12744806035f0a648494a403c7d09ea3caf91bf54869a81aa73": {
"query": "UPDATE survey_admins set password = $1\n WHERE name = $2",
"describe": { "describe": {
"columns": [], "columns": [],
"nullable": [],
"parameters": { "parameters": {
"Left": [ "Left": [
"Text", "Text",
"Text" "Text"
] ]
},
"nullable": []
} }
}, },
"query": "UPDATE survey_admins set password = $1\n WHERE name = $2"
},
"58ec3b8f98c27e13ec2732f8ee23f6eb9845ac5d9fd97b1e5c9f2eed4b1f5693": { "58ec3b8f98c27e13ec2732f8ee23f6eb9845ac5d9fd97b1e5c9f2eed4b1f5693": {
"query": "SELECT name \n FROM survey_campaigns\n WHERE \n id = $1\n AND\n user_id = (SELECT ID from survey_admins WHERE name = $2)",
"describe": { "describe": {
"columns": [ "columns": [
{ {
"ordinal": 0,
"name": "name", "name": "name",
"ordinal": 0,
"type_info": "Varchar" "type_info": "Varchar"
} }
], ],
"nullable": [
false
],
"parameters": { "parameters": {
"Left": [ "Left": [
"Uuid", "Uuid",
"Text" "Text"
] ]
},
"nullable": [
false
]
} }
}, },
"query": "SELECT name \n FROM survey_campaigns\n WHERE \n id = $1\n AND\n user_id = (SELECT ID from survey_admins WHERE name = $2)"
},
"683707dbc847b37c58c29aaad0d1a978c9fe0657da13af99796e4461134b5a43": { "683707dbc847b37c58c29aaad0d1a978c9fe0657da13af99796e4461134b5a43": {
"query": "UPDATE survey_admins set email = $1\n WHERE name = $2",
"describe": { "describe": {
"columns": [], "columns": [],
"nullable": [],
"parameters": { "parameters": {
"Left": [ "Left": [
"Varchar", "Varchar",
"Text" "Text"
] ]
},
"nullable": []
} }
}, },
"query": "UPDATE survey_admins set email = $1\n WHERE name = $2"
},
"6a26daa84578aed2b2085697cb8358ed7c0a50ba9597fd387b4b09b0a8a154db": { "6a26daa84578aed2b2085697cb8358ed7c0a50ba9597fd387b4b09b0a8a154db": {
"query": "SELECT EXISTS (SELECT 1 from survey_admins WHERE email = $1)",
"describe": { "describe": {
"columns": [ "columns": [
{ {
"ordinal": 0,
"name": "exists", "name": "exists",
"ordinal": 0,
"type_info": "Bool" "type_info": "Bool"
} }
], ],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [ "nullable": [
null null
]
}
},
"70cc7bfc9b6ff5b68db70c069c0947d51bfc4a53cedc020016ee25ff98586c93": {
"query": "SELECT \n name, id\n FROM \n survey_campaigns \n WHERE\n user_id = (\n SELECT \n ID\n FROM \n survey_admins\n WHERE\n name = $1\n )",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "name",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "id",
"type_info": "Uuid"
}
], ],
"parameters": { "parameters": {
"Left": [ "Left": [
"Text" "Text"
] ]
}
}, },
"query": "SELECT EXISTS (SELECT 1 from survey_admins WHERE email = $1)"
},
"70cc7bfc9b6ff5b68db70c069c0947d51bfc4a53cedc020016ee25ff98586c93": {
"describe": {
"columns": [
{
"name": "name",
"ordinal": 0,
"type_info": "Varchar"
},
{
"name": "id",
"ordinal": 1,
"type_info": "Uuid"
}
],
"nullable": [ "nullable": [
false, false,
false false
],
"parameters": {
"Left": [
"Text"
] ]
} }
}, },
"query": "SELECT \n name, id\n FROM \n survey_campaigns \n WHERE\n user_id = (\n SELECT \n ID\n FROM \n survey_admins\n WHERE\n name = $1\n )"
},
"82feafc36533144e49ba374c8c47ca4aa0d6558a9803778ad28cfa7b62382c3e": { "82feafc36533144e49ba374c8c47ca4aa0d6558a9803778ad28cfa7b62382c3e": {
"query": "\n INSERT INTO survey_campaigns (\n user_id, ID, name, difficulties, created_at\n ) VALUES(\n (SELECT id FROM survey_admins WHERE name = $1),\n $2, $3, $4, $5\n );",
"describe": { "describe": {
"columns": [], "columns": [],
"nullable": [],
"parameters": { "parameters": {
"Left": [ "Left": [
"Text", "Text",
@ -238,82 +238,82 @@
"Int4Array", "Int4Array",
"Timestamptz" "Timestamptz"
] ]
},
"nullable": []
} }
}, },
"query": "\n INSERT INTO survey_campaigns (\n user_id, ID, name, difficulties, created_at\n ) VALUES(\n (SELECT id FROM survey_admins WHERE name = $1),\n $2, $3, $4, $5\n );"
},
"8320dda2b3e107d1451fdfb35eb2a4b8e97364e7b1b74ffe4d6913faf132fb61": { "8320dda2b3e107d1451fdfb35eb2a4b8e97364e7b1b74ffe4d6913faf132fb61": {
"query": "SELECT ID \n FROM survey_responses \n WHERE \n user_id = $1 \n AND \n device_software_recognised = $2;",
"describe": { "describe": {
"columns": [ "columns": [
{ {
"ordinal": 0,
"name": "id", "name": "id",
"ordinal": 0,
"type_info": "Int4" "type_info": "Int4"
} }
], ],
"nullable": [
false
],
"parameters": { "parameters": {
"Left": [ "Left": [
"Uuid", "Uuid",
"Text" "Text"
] ]
},
"nullable": [
false
]
} }
}, },
"query": "SELECT ID \n FROM survey_responses \n WHERE \n user_id = $1 \n AND \n device_software_recognised = $2;"
},
"9cdade613ce724631cc3f187510758ee0929e93ff3f8ce81fe35594756644246": { "9cdade613ce724631cc3f187510758ee0929e93ff3f8ce81fe35594756644246": {
"query": "SELECT difficulties FROM survey_campaigns WHERE id = $1;",
"describe": { "describe": {
"columns": [ "columns": [
{ {
"ordinal": 0,
"name": "difficulties", "name": "difficulties",
"ordinal": 0,
"type_info": "Int4Array" "type_info": "Int4Array"
} }
], ],
"nullable": [
false
],
"parameters": { "parameters": {
"Left": [ "Left": [
"Uuid" "Uuid"
] ]
},
"nullable": [
false
]
} }
}, },
"query": "SELECT difficulties FROM survey_campaigns WHERE id = $1;"
},
"a721cfa249acf328c2f29c4cf8c2aeba1a635bcf49d18ced5474caa10b7cae4f": { "a721cfa249acf328c2f29c4cf8c2aeba1a635bcf49d18ced5474caa10b7cae4f": {
"query": "INSERT INTO survey_benches \n (resp_id, difficulty, duration) \n VALUES ($1, $2, $3);",
"describe": { "describe": {
"columns": [], "columns": [],
"nullable": [],
"parameters": { "parameters": {
"Left": [ "Left": [
"Int4", "Int4",
"Int4", "Int4",
"Float4" "Float4"
] ]
},
"nullable": []
} }
}, },
"query": "INSERT INTO survey_benches \n (resp_id, difficulty, duration) \n VALUES ($1, $2, $3);"
},
"ab951c5c318174c6538037947c2f52c61bcfe5e5be1901379b715e77f5214dd2": { "ab951c5c318174c6538037947c2f52c61bcfe5e5be1901379b715e77f5214dd2": {
"query": "UPDATE survey_admins set secret = $1\n WHERE name = $2",
"describe": { "describe": {
"columns": [], "columns": [],
"nullable": [],
"parameters": { "parameters": {
"Left": [ "Left": [
"Varchar", "Varchar",
"Text" "Text"
] ]
},
"nullable": []
} }
}, },
"query": "UPDATE survey_admins set secret = $1\n WHERE name = $2"
},
"b4cd1e5240de1968c8b6d56672cec639b22f41ebf2754dadbf00efe0948c7e68": { "b4cd1e5240de1968c8b6d56672cec639b22f41ebf2754dadbf00efe0948c7e68": {
"query": "INSERT INTO survey_responses (\n user_id, \n campaign_id,\n device_user_provided,\n device_software_recognised,\n threads\n ) VALUES ($1, $2, $3, $4, $5);",
"describe": { "describe": {
"columns": [], "columns": [],
"nullable": [],
"parameters": { "parameters": {
"Left": [ "Left": [
"Uuid", "Uuid",
@ -322,55 +322,55 @@
"Varchar", "Varchar",
"Int4" "Int4"
] ]
},
"nullable": []
} }
}, },
"query": "INSERT INTO survey_responses (\n user_id, \n campaign_id,\n device_user_provided,\n device_software_recognised,\n threads\n ) VALUES ($1, $2, $3, $4, $5);"
},
"c757589ef26a005e3285e7ab20d8a44c4f2e1cb125f8db061dd198cc380bf807": { "c757589ef26a005e3285e7ab20d8a44c4f2e1cb125f8db061dd198cc380bf807": {
"query": "UPDATE survey_admins set name = $1\n WHERE name = $2",
"describe": { "describe": {
"columns": [], "columns": [],
"nullable": [],
"parameters": { "parameters": {
"Left": [ "Left": [
"Varchar", "Varchar",
"Text" "Text"
] ]
},
"nullable": []
} }
}, },
"query": "UPDATE survey_admins set name = $1\n WHERE name = $2"
},
"e9cf5d6d8c9e8327d5c809d47a14a933f324e267f1e7dbb48e1caf1c021adc3f": { "e9cf5d6d8c9e8327d5c809d47a14a933f324e267f1e7dbb48e1caf1c021adc3f": {
"query": "SELECT secret FROM survey_admins WHERE name = ($1)",
"describe": { "describe": {
"columns": [ "columns": [
{ {
"ordinal": 0,
"name": "secret", "name": "secret",
"ordinal": 0,
"type_info": "Varchar" "type_info": "Varchar"
} }
], ],
"nullable": [
false
],
"parameters": { "parameters": {
"Left": [ "Left": [
"Text" "Text"
] ]
},
"nullable": [
false
]
} }
}, },
"query": "SELECT secret FROM survey_admins WHERE name = ($1)"
},
"fcdc5fe5d496eb516c805e64ec96d9626b74ab33cd6e75e5a08ae88967403b72": { "fcdc5fe5d496eb516c805e64ec96d9626b74ab33cd6e75e5a08ae88967403b72": {
"query": "INSERT INTO survey_response_tokens \n (resp_id, user_id, id)\n VALUES ($1, $2, $3);",
"describe": { "describe": {
"columns": [], "columns": [],
"nullable": [],
"parameters": { "parameters": {
"Left": [ "Left": [
"Int4", "Int4",
"Uuid", "Uuid",
"Uuid" "Uuid"
] ]
}
}, },
"nullable": [] "query": "INSERT INTO survey_response_tokens \n (resp_id, user_id, id)\n VALUES ($1, $2, $3);"
}
} }
} }

View file

@ -25,8 +25,8 @@ use crate::errors::*;
use crate::AppData; use crate::AppData;
pub mod routes { pub mod routes {
use crate::middleware::auth::GetLoginRoute; use actix_auth_middleware::GetLoginRoute;
use url::Url;
pub struct Auth { pub struct Auth {
pub logout: &'static str, pub logout: &'static str,
pub login: &'static str, pub login: &'static str,

View file

@ -352,10 +352,10 @@ mod tests {
use crate::api::v1::bench::Submission; use crate::api::v1::bench::Submission;
use crate::data::Data; use crate::data::Data;
use crate::errors::*; use crate::errors::*;
use crate::middleware::auth::GetLoginRoute;
use crate::tests::*; use crate::tests::*;
use crate::*; use crate::*;
use actix_auth_middleware::GetLoginRoute;
use actix_web::{http::header, test}; use actix_web::{http::header, test};
#[actix_rt::test] #[actix_rt::test]

View file

@ -14,6 +14,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
use actix_auth_middleware::*;
use actix_web::web::ServiceConfig; use actix_web::web::ServiceConfig;
pub mod account; pub mod account;
@ -23,6 +24,7 @@ pub mod campaigns;
mod tests; mod tests;
pub use super::{get_random, get_uuid, RedirectQuery}; pub use super::{get_random, get_uuid, RedirectQuery};
use crate::api::v1::bench::SURVEY_USER_ID;
pub fn services(cfg: &mut ServiceConfig) { pub fn services(cfg: &mut ServiceConfig) {
auth::services(cfg); auth::services(cfg);
@ -30,12 +32,8 @@ pub fn services(cfg: &mut ServiceConfig) {
campaigns::services(cfg); campaigns::services(cfg);
} }
pub fn get_admin_check_login() -> crate::CheckLogin<auth::routes::Auth> { pub fn get_admin_check_login() -> Authentication<auth::routes::Auth> {
use crate::middleware::auth::*; Authentication::with_identity(super::ROUTES.admin.auth)
CheckLogin::new(
crate::V1_API_ROUTES.admin.auth,
AuthenticatedSession::ActixIdentity,
)
} }
pub mod routes { pub mod routes {

View file

@ -17,7 +17,9 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::str::FromStr; use std::str::FromStr;
use actix_auth_middleware::*;
use actix_session::Session; use actix_session::Session;
use actix_web::{dev::Payload, HttpRequest};
use actix_web::{http, web, HttpResponse, Responder}; use actix_web::{http, web, HttpResponse, Responder};
use futures::future::try_join_all; use futures::future::try_join_all;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -32,7 +34,7 @@ pub const SURVEY_USER_ID: &str = "survey_user_id";
pub mod routes { pub mod routes {
use crate::middleware::auth::GetLoginRoute; use actix_auth_middleware::GetLoginRoute;
pub struct Benches { pub struct Benches {
pub submit: &'static str, pub submit: &'static str,
@ -173,14 +175,27 @@ pub struct SubmissionProof {
pub proof: String, pub proof: String,
} }
pub fn get_check_login() -> crate::CheckLogin<routes::Benches> { fn is_session_authenticated(r: &HttpRequest, mut pl: &mut Payload) -> bool {
use crate::middleware::auth::*; use actix_web::FromRequest;
CheckLogin::new( matches!(
crate::V1_API_ROUTES.benches, Session::from_request(&r, &mut pl).into_inner().map(|x| {
AuthenticatedSession::ActixSession, let val = x.get::<String>(SURVEY_USER_ID);
println!("{:#?}", val);
val
}),
Ok(Ok(Some(_)))
) )
} }
pub fn get_check_login() -> Authentication<routes::Benches> {
Authentication::new(crate::V1_API_ROUTES.benches, is_session_authenticated)
}
//
// pub fn get_auth_middleware() -> Authentication<routes::Routes> {
// Authentication::with_identity(V1_API_ROUTES)
// }
//}
#[my_codegen::post( #[my_codegen::post(
path = "crate::V1_API_ROUTES.benches.submit", path = "crate::V1_API_ROUTES.benches.submit",
wrap = "get_check_login()" wrap = "get_check_login()"

View file

@ -18,6 +18,7 @@ use std::env;
use std::sync::Arc; use std::sync::Arc;
use actix_identity::{CookieIdentityPolicy, IdentityService}; use actix_identity::{CookieIdentityPolicy, IdentityService};
use actix_session::{storage::CookieSessionStore, SessionMiddleware};
use actix_web::{ use actix_web::{
error::InternalError, http::StatusCode, middleware as actix_middleware, error::InternalError, http::StatusCode, middleware as actix_middleware,
web::JsonConfig, App, HttpServer, web::JsonConfig, App, HttpServer,
@ -28,7 +29,6 @@ use log::info;
mod api; mod api;
mod data; mod data;
mod errors; mod errors;
mod middleware;
mod pages; mod pages;
mod settings; mod settings;
mod static_assets; mod static_assets;
@ -38,7 +38,6 @@ mod tests;
pub use crate::data::Data; pub use crate::data::Data;
pub use api::v1::ROUTES as V1_API_ROUTES; pub use api::v1::ROUTES as V1_API_ROUTES;
pub use middleware::auth::CheckLogin;
pub use pages::routes::ROUTES as PAGES; pub use pages::routes::ROUTES as PAGES;
pub use settings::Settings; pub use settings::Settings;
pub use static_assets::static_files::assets; pub use static_assets::static_files::assets;
@ -136,16 +135,17 @@ pub fn get_json_err() -> JsonConfig {
} }
#[cfg(not(tarpaulin_include))] #[cfg(not(tarpaulin_include))]
pub fn get_survey_session() -> actix_session::CookieSession { pub fn get_survey_session() -> actix_session::SessionMiddleware<CookieSessionStore> {
use actix_web::cookie::Key;
let cookie_secret = &SETTINGS.server.cookie_secret2; let cookie_secret = &SETTINGS.server.cookie_secret2;
actix_session::CookieSession::signed(cookie_secret.as_bytes()) let key = Key::from(cookie_secret.as_bytes());
.lazy(true) SessionMiddleware::builder(CookieSessionStore::default(), key)
.domain(&SETTINGS.server.domain) .cookie_domain(Some(SETTINGS.server.domain.clone()))
.name("survey-id") .cookie_name("survey-id".into())
.http_only(true) .cookie_path("/".to_string())
.path("/") .cookie_secure(false)
.max_age(30 * 60) .cookie_http_only(true)
.secure(false) .build()
} }
#[cfg(not(tarpaulin_include))] #[cfg(not(tarpaulin_include))]

View file

@ -1,245 +0,0 @@
/*
* Copyright (C) 2021 Aravinth Manivannan <realaravinth@batsense.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#![allow(clippy::type_complexity)]
use std::rc::Rc;
use crate::api::v1::bench::SURVEY_USER_ID;
use actix_http::body::AnyBody;
use actix_identity::Identity;
use actix_service::{Service, Transform};
use actix_session::Session;
use actix_web::dev::{ServiceRequest, ServiceResponse};
use actix_web::{http, Error, FromRequest, HttpResponse};
#[derive(Clone)]
pub enum AuthenticatedSession {
ActixIdentity,
ActixSession,
}
use futures::future::{ok, Either, Ready};
pub trait GetLoginRoute {
fn get_login_route(&self, src: Option<&str>) -> String;
}
pub struct CheckLogin<T: GetLoginRoute> {
login: Rc<T>,
session_type: AuthenticatedSession,
}
impl<T: GetLoginRoute> CheckLogin<T> {
pub fn new(login: T, session_type: AuthenticatedSession) -> Self {
let login = Rc::new(login);
Self {
login,
session_type,
}
}
}
impl<S, GT> Transform<S, ServiceRequest> for CheckLogin<GT>
where
S: Service<ServiceRequest, Response = ServiceResponse<AnyBody>, Error = Error>,
S::Future: 'static,
GT: GetLoginRoute,
{
type Response = ServiceResponse<AnyBody>;
type Error = Error;
type Transform = CheckLoginMiddleware<S, GT>;
type InitError = ();
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ok(CheckLoginMiddleware {
service,
login: self.login.clone(),
session_type: self.session_type.clone(),
})
}
}
pub struct CheckLoginMiddleware<S, GT> {
service: S,
login: Rc<GT>,
session_type: AuthenticatedSession,
}
impl<S, GT> Service<ServiceRequest> for CheckLoginMiddleware<S, GT>
where
S: Service<ServiceRequest, Response = ServiceResponse<AnyBody>, Error = Error>,
S::Future: 'static,
GT: GetLoginRoute,
{
type Response = ServiceResponse<AnyBody>;
type Error = Error;
type Future = Either<S::Future, Ready<Result<Self::Response, Self::Error>>>;
actix_service::forward_ready!(service);
fn call(&self, req: ServiceRequest) -> Self::Future {
let (r, mut pl) = req.into_parts();
let mut is_authenticated = || match self.session_type {
AuthenticatedSession::ActixSession => matches!(
Session::from_request(&r, &mut pl)
.into_inner()
.map(|x| x.get::<String>(SURVEY_USER_ID)),
Ok(Ok(Some(_)))
),
AuthenticatedSession::ActixIdentity => matches!(
Identity::from_request(&r, &mut pl)
.into_inner()
.map(|x| x.identity()),
Ok(Some(_))
),
};
if is_authenticated() {
let req = ServiceRequest::from_parts(r, pl);
Either::Left(self.service.call(req))
} else {
let path = r.uri().path_and_query().map(|path| path.as_str());
let path = self.login.get_login_route(path);
let req = ServiceRequest::from_parts(r, pl);
Either::Right(ok(req.into_response(
HttpResponse::Found()
.insert_header((http::header::LOCATION, path))
.finish(),
)))
}
}
}
#[cfg(test)]
mod tests {
use url::Url;
use crate::api::v1::bench::Submission;
use crate::data::Data;
use crate::middleware::auth::GetLoginRoute;
use crate::tests::*;
use crate::*;
use actix_web::{http::header, test};
#[actix_rt::test]
async fn auth_middleware_works() {
fn make_uri(path: &str, queries: &Option<Vec<(&str, &str)>>) -> String {
let mut url = Url::parse("http://x/").unwrap();
let final_path;
url.set_path(path);
if let Some(queries) = queries {
{
let mut query_pairs = url.query_pairs_mut();
queries.iter().for_each(|(k, v)| {
query_pairs.append_pair(k, v);
});
}
final_path = format!("{}?{}", url.path(), url.query().unwrap());
} else {
final_path = url.path().to_string();
}
final_path
}
const NAME: &str = "testmiddlewareuser";
const EMAIL: &str = "testuserupda@testmiddlewareuser.com";
const PASSWORD: &str = "longpassword2";
const DEVICE_USER_PROVIDED: &str = "foo";
const DEVICE_SOFTWARE_RECOGNISED: &str = "Foobar.v2";
const THREADS: i32 = 4;
let queries = Some(vec![
("foo", "bar"),
("src", "/x/y/z"),
("with_q", "/a/b/c/?goo=x"),
]);
{
let data = Data::new().await;
delete_user(NAME, &data).await;
}
let (data, _creds, signin_resp) =
register_and_signin(NAME, EMAIL, PASSWORD).await;
let cookies = get_cookie!(signin_resp);
let survey = get_survey_user(data.clone()).await;
let survey_cookie = get_cookie!(survey);
let campaign = create_new_campaign(NAME, data.clone(), cookies.clone()).await;
let bench_submit_route =
V1_API_ROUTES.benches.submit_route(&campaign.campaign_id);
let bench_routes = vec![
(&bench_submit_route, queries.clone()),
(&bench_submit_route, None),
];
let app = get_app!(data).await;
// let campaign_routes = vec![
// (Some(V1_API_ROUTES.camp.submit), queries.clone()),
// (None, None),
// (Some(V1_API_ROUTES.benches.submit), None),
// ];
let bench_submit_payload = Submission {
device_user_provided: DEVICE_USER_PROVIDED.into(),
device_software_recognised: DEVICE_SOFTWARE_RECOGNISED.into(),
threads: THREADS,
benches: BENCHES.clone(),
};
for (from, query) in bench_routes.iter() {
let route = make_uri(from, query);
let signin_resp = test::call_service(
&app,
post_request!(&bench_submit_payload, &route).to_request(),
)
.await;
assert_eq!(signin_resp.status(), StatusCode::FOUND);
let redirect_to = V1_API_ROUTES.benches.get_login_route(Some(&route));
let headers = signin_resp.headers();
assert_eq!(headers.get(header::LOCATION).unwrap(), &redirect_to);
let add_feedback_resp = test::call_service(
&app,
post_request!(&bench_submit_payload, &route)
.cookie(survey_cookie.clone())
.to_request(),
)
.await;
assert_eq!(add_feedback_resp.status(), StatusCode::OK);
}
}
// let signin_resp = test::call_service(
// &app,
// test::TestRequest::get()
// .uri(V1_API_ROUTES.benches.get_login_route(redirect_to).as_ref().unwrap())
// .to_request(),
// )
// .await;
// assert_eq!(signin_resp.status(), StatusCode::FOUND);
// let headers = signin_resp.headers();
// assert_eq!(
// headers.get(header::LOCATION).unwrap(),
// redirect_to.as_ref().unwrap()
// )
//
}

View file

@ -1,18 +0,0 @@
/*
* Copyright (C) 2021 Aravinth Manivannan <realaravinth@batsense.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
pub mod auth;

View file

@ -55,7 +55,7 @@ lazy_static! {
pub async fn join() -> impl Responder { pub async fn join() -> impl Responder {
HttpResponse::Ok() HttpResponse::Ok()
.content_type("text/html; charset=utf-8") .content_type("text/html; charset=utf-8")
.body(&*INDEX) .body(&*INDEX.as_str())
} }
#[my_codegen::post(path = "PAGES.auth.join")] #[my_codegen::post(path = "PAGES.auth.join")]

View file

@ -58,7 +58,7 @@ lazy_static! {
pub async fn login() -> impl Responder { pub async fn login() -> impl Responder {
HttpResponse::Ok() HttpResponse::Ok()
.content_type("text/html; charset=utf-8") .content_type("text/html; charset=utf-8")
.body(&*INDEX) .body(&*INDEX.as_str())
} }
#[post(path = "PAGES.auth.login")] #[post(path = "PAGES.auth.login")]

View file

@ -26,7 +26,7 @@ pub fn services(cfg: &mut actix_web::web::ServiceConfig) {
} }
pub mod routes { pub mod routes {
use crate::middleware::auth::GetLoginRoute; use actix_auth_middleware::GetLoginRoute;
use url::Url; use url::Url;
pub struct Auth { pub struct Auth {

View file

@ -58,11 +58,11 @@ async fn error(path: web::Path<usize>) -> impl Responder {
let resp = match path.into_inner() { let resp = match path.into_inner() {
500 => HttpResponse::InternalServerError() 500 => HttpResponse::InternalServerError()
.content_type("text/html; charset=utf-8") .content_type("text/html; charset=utf-8")
.body(&*INTERNAL_SERVER_ERROR_BODY), .body(&*INTERNAL_SERVER_ERROR_BODY.as_str()),
_ => HttpResponse::InternalServerError() _ => HttpResponse::InternalServerError()
.content_type("text/html; charset=utf-8") .content_type("text/html; charset=utf-8")
.body(&*UNKNOWN_ERROR_BODY), .body(&*UNKNOWN_ERROR_BODY.as_str()),
}; };
resp resp

View file

@ -13,7 +13,7 @@
* *
* You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. * You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
use actix_auth_middleware::*;
use actix_web::web::ServiceConfig; use actix_web::web::ServiceConfig;
pub mod auth; pub mod auth;
@ -30,9 +30,8 @@ pub fn services(cfg: &mut ServiceConfig) {
errors::services(cfg); errors::services(cfg);
} }
pub fn get_page_check_login() -> crate::CheckLogin<auth::routes::Auth> { pub fn get_page_check_login() -> Authentication<auth::routes::Auth> {
use crate::middleware::auth::*; Authentication::with_identity(crate::PAGES.auth)
CheckLogin::new(crate::PAGES.auth, AuthenticatedSession::ActixIdentity)
} }
#[cfg(not(tarpaulin_include))] #[cfg(not(tarpaulin_include))]

View file

@ -54,6 +54,6 @@ pub async fn bench(path: web::Path<String>) -> PageResult<impl Responder> {
Err(_) => Err(PageError::PageDoesntExist), Err(_) => Err(PageError::PageDoesntExist),
Ok(_) => Ok(HttpResponse::Ok() Ok(_) => Ok(HttpResponse::Ok()
.content_type("text/html; charset=utf-8") .content_type("text/html; charset=utf-8")
.body(&*BENCH)), .body(&*BENCH.as_str())),
} }
} }

View file

@ -102,7 +102,7 @@ pub async fn home(data: AppData, id: Identity) -> impl Responder {
HttpResponse::Ok() HttpResponse::Ok()
.content_type("text/html; charset=utf-8") .content_type("text/html; charset=utf-8")
.body(&page) .body(page)
} }
#[cfg(test)] #[cfg(test)]

View file

@ -60,7 +60,7 @@ lazy_static! {
pub async fn new_campaign() -> impl Responder { pub async fn new_campaign() -> impl Responder {
HttpResponse::Ok() HttpResponse::Ok()
.content_type("text/html; charset=utf-8") .content_type("text/html; charset=utf-8")
.body(&*INDEX) .body(&*INDEX.as_str())
} }
#[post( #[post(

View file

@ -14,6 +14,8 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
use actix_auth_middleware::GetLoginRoute;
use super::auth::routes::Auth; use super::auth::routes::Auth;
use super::errors::routes::Errors; use super::errors::routes::Errors;
use super::panel::routes::Panel; use super::panel::routes::Panel;
@ -57,6 +59,25 @@ impl Routes {
} }
} }
impl GetLoginRoute for Routes {
fn get_login_route(&self, src: Option<&str>) -> String {
if let Some(redirect_to) = src {
// uri::Builder::new().path_and_query(
format!(
"{}?redirect_to={}",
self.auth.join.to_string(),
urlencoding::encode(redirect_to)
)
// let mut url: Uri = self.register.parse().unwrap();
// url.qu
// url.query_pairs_mut()
// .append_pair("redirect_to", redirect_to);
} else {
self.auth.join.to_string()
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View file

@ -16,7 +16,7 @@
*/ */
use std::borrow::Cow; use std::borrow::Cow;
use actix_web::body::Body; use actix_web::body::BoxBody;
use actix_web::{get, http::header, web, HttpResponse, Responder}; use actix_web::{get, http::header, web, HttpResponse, Responder};
use log::debug; use log::debug;
use mime_guess::from_path; use mime_guess::from_path;
@ -61,9 +61,9 @@ struct Asset;
fn handle_assets(path: &str) -> HttpResponse { fn handle_assets(path: &str) -> HttpResponse {
match Asset::get(path) { match Asset::get(path) {
Some(content) => { Some(content) => {
let body: Body = match content.data { let body: BoxBody = match content.data {
Cow::Borrowed(bytes) => bytes.into(), Cow::Borrowed(bytes) => BoxBody::new(bytes),
Cow::Owned(bytes) => bytes.into(), Cow::Owned(bytes) => BoxBody::new(bytes),
}; };
HttpResponse::Ok() HttpResponse::Ok()
@ -91,9 +91,9 @@ struct Favicons;
fn handle_favicons(path: &str) -> HttpResponse { fn handle_favicons(path: &str) -> HttpResponse {
match Favicons::get(path) { match Favicons::get(path) {
Some(content) => { Some(content) => {
let body: Body = match content.data { let body: BoxBody = match content.data {
Cow::Borrowed(bytes) => bytes.into(), Cow::Borrowed(bytes) => BoxBody::new(bytes),
Cow::Owned(bytes) => bytes.into(), Cow::Owned(bytes) => BoxBody::new(bytes),
}; };
HttpResponse::Ok() HttpResponse::Ok()

View file

@ -19,7 +19,13 @@ use std::sync::Arc;
use actix_web::cookie::Cookie; use actix_web::cookie::Cookie;
use actix_web::test; use actix_web::test;
use actix_web::{dev::ServiceResponse, error::ResponseError, http::StatusCode}; use actix_web::{
body::{BoxBody, EitherBody},
dev::ServiceResponse,
error::ResponseError,
http::StatusCode,
};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use serde::Serialize; use serde::Serialize;
use uuid::Uuid; use uuid::Uuid;
@ -110,7 +116,7 @@ pub async fn register_and_signin(
name: &str, name: &str,
email: &str, email: &str,
password: &str, password: &str,
) -> (Arc<data::Data>, Login, ServiceResponse) { ) -> (Arc<Data>, Login, ServiceResponse<EitherBody<BoxBody>>) {
register(name, email, password).await; register(name, email, password).await;
signin(name, password).await signin(name, password).await
} }
@ -136,7 +142,10 @@ pub async fn register(name: &str, email: &str, password: &str) {
} }
/// signin util /// signin util
pub async fn signin(name: &str, password: &str) -> (Arc<Data>, Login, ServiceResponse) { pub async fn signin(
name: &str,
password: &str,
) -> (Arc<Data>, Login, ServiceResponse<EitherBody<BoxBody>>) {
let data = Data::new().await; let data = Data::new().await;
let app = get_app!(data.clone()).await; let app = get_app!(data.clone()).await;
@ -226,7 +235,7 @@ pub async fn create_new_campaign(
uuid uuid
} }
pub async fn get_survey_user(data: Arc<Data>) -> ServiceResponse { pub async fn get_survey_user(data: Arc<Data>) -> ServiceResponse<EitherBody<BoxBody>> {
let app = get_app!(data).await; let app = get_app!(data).await;
let signin_resp = test::call_service( let signin_resp = test::call_service(
&app, &app,
@ -306,6 +315,11 @@ pub async fn submit_bench(
post_request!(&payload, &route).cookie(cookies).to_request(), post_request!(&payload, &route).cookie(cookies).to_request(),
) )
.await; .await;
if add_feedback_resp.status() != StatusCode::OK {
let headers = add_feedback_resp.headers();
println!("{:#?}", headers);
}
assert_eq!(add_feedback_resp.status(), StatusCode::OK); assert_eq!(add_feedback_resp.status(), StatusCode::OK);
let proof: SubmissionProof = test::read_body_json(add_feedback_resp).await; let proof: SubmissionProof = test::read_body_json(add_feedback_resp).await;