Skip to content

Commit

Permalink
Merge pull request #54 from tag1consulting/form_id
Browse files Browse the repository at this point in the history
don't hard code form_id, respect validation
  • Loading branch information
jeremyandrews authored Jan 27, 2023
2 parents 8a18513 + 4ead6f1 commit 872cebd
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 17 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Changelog

## 0.5.1-dev
- in `drupal::log_in`
o allow `form_id` other than the default of `user_login_form`
o properly validate status code if configured
o propery post login to configured path

## 0.5.0 January 24, 2023
- add support for building with [rustls](https://docs.rs/rustls) via the `rustls-tls` feature
Expand Down
68 changes: 53 additions & 15 deletions src/drupal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ use std::env;
pub fn get_form(html: &str, name: &str) -> String {
let re = Regex::new(&format!(
// Lazy match to avoid matching multiple forms.
r#"<form.*?(data-drupal-selector|id)="{}".*?>(.*?)</form>"#,
name
r#"<form.*?(data-drupal-selector|id)="{name}".*?>(.*?)</form>"#,
))
.unwrap();
// Strip carriage returns to simplify regex.
Expand Down Expand Up @@ -588,9 +587,6 @@ pub async fn log_in(
// (or default) login password.
let password = env::var("GOOSE_PASS").unwrap_or_else(|_| login.password.to_string());

// Load the log in page.
let goose = user.get(login.url).await?;

// By default verify that the standard user-login-form exists on the page.
let default_validation = crate::Validate::builder()
.text(r#"<form class="user-login-form"#)
Expand All @@ -601,6 +597,19 @@ pub async fn log_in(
&default_validation
};

// Load the log in page.
let goose = if validate.status.is_some() {
// Build request manually if validating a specific status code.
let goose_request = GooseRequest::builder()
.path(login.url)
.expect_status_code(validate.status.unwrap())
.build();
user.request(goose_request).await.unwrap()
} else {
// Otherwise follow default validation rules for status codes.
user.get(login.url).await.unwrap()
};

let mut login_request = goose.request.clone();
let login_page = crate::validate_and_load_static_assets(user, goose, validate).await?;

Expand Down Expand Up @@ -632,15 +641,52 @@ pub async fn log_in(
return Ok("".to_string());
}

// Also extract the form_id (defaults to `user_login_form`).
let form_id = get_form_value(&login_form, "form_id");
if form_id.is_empty() {
user.set_failure(
&format!("{}: no form_id on page", login.url),
&mut login_request,
None,
Some(&login_form),
)?;
// Return an empty string as log-in failed. Enable the debug log to
// determine why.
return Ok("".to_string());
}

// By default verify that the username is in the title of the logged in page.
let default_validation = crate::Validate::builder().title(login.username).build();
let validate = if let Some(validation) = login.logged_in_page_validation {
validation
} else {
&default_validation
};

// Build log in form with username and password from environment.
let params = [
("name", &username),
("pass", &password),
("form_build_id", &form_build_id),
("form_id", &"user_login_form".to_string()),
("form_id", &form_id),
("op", &"Log+in".to_string()),
];
let mut logged_in_user = user.post_form("/user/login", &params).await?;
// Post the log in form.
let mut logged_in_user = if validate.status.is_some() {
// Build request manually if validating a specific status code.
let url = user.build_url(login.url)?;
// A request builder object is necessary to post a form.
let reqwest_request_builder = user.client.post(&url);
let goose_request = GooseRequest::builder()
.path(login.url)
.method(GooseMethod::Post)
.expect_status_code(validate.status.unwrap())
.set_request_builder(reqwest_request_builder.form(&params))
.build();
user.request(goose_request).await.unwrap()
} else {
user.post_form(login.url, &params).await?
};

// A successful log in is redirected.
if !logged_in_user.request.redirected {
Expand Down Expand Up @@ -670,14 +716,6 @@ pub async fn log_in(
return Ok(html);
}

// By default verify that the username is in the title of the logged in page.
let default_validation = crate::Validate::builder().title(login.username).build();
let validate = if let Some(validation) = login.logged_in_page_validation {
validation
} else {
&default_validation
};

// Check the title to verify that the user is actually logged in.
let logged_in_page =
crate::validate_and_load_static_assets(user, logged_in_user, validate).await?;
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -733,7 +733,7 @@ pub async fn load_static_elements(user: &mut GooseUser, html: &str) {
// Use a case-insensitive regular expression to find all src=<foo> in the html, where
// <foo> is the URL to local image and js assets.
// @TODO: parse HTML5 srcset= also
let src_elements = Regex::new(format!(r#"(?i)src="(({}|/).*?)""#, base_url).as_str()).unwrap();
let src_elements = Regex::new(format!(r#"(?i)src="(({base_url}|/).*?)""#).as_str()).unwrap();
for url in src_elements.captures_iter(html) {
let is_js = url[1].to_string().contains(".js");
let resource_type = if is_js { "js" } else { "img" };
Expand All @@ -744,7 +744,7 @@ pub async fn load_static_elements(user: &mut GooseUser, html: &str) {

// Use a case-insensitive regular expression to find all href=<foo> in the html, where
// <foo> is the URL to local css assets.
let css = Regex::new(format!(r#"(?i)href="(({}|/).*?\.css.*?)""#, base_url).as_str()).unwrap();
let css = Regex::new(format!(r#"(?i)href="(({base_url}|/).*?\.css.*?)""#).as_str()).unwrap();
for url in css.captures_iter(html) {
let _ = user.get_named(&url[1], "static asset: css").await;
}
Expand Down

0 comments on commit 872cebd

Please sign in to comment.