Fixed tags, added checks, much refactor - such wow
- Fixed host_tags retrieval (now supports multiple tags and properly handles none) - Added status code check - Added check for failed authorization - Renamed target_compilation -> mdm_compilation - Fixed and refactored squeeze_html_form()
This commit is contained in:
parent
87231e227f
commit
d833c2a76a
|
@ -1,11 +1,11 @@
|
||||||
#General settings
|
#General settings
|
||||||
hostname = "mein-iserv.de"
|
hostname = "mein-iserv.de"
|
||||||
session_cookie = "IServSAT=mvuvFvCZSlpvuwhk0mmNwF1NKEQypM4d; IServSession=xEPqyJO1a5nsVd34HEpbPqQGMMQKapvw"
|
cookie = "IServSAT=mvuvFvCZSlpvuwhk0mmNwF1NKEQypM4d; IServSession=xEPqyJO1a5nsVd34HEpbPqQGMMQKapvw"
|
||||||
|
|
||||||
# Targeted device settings
|
# Targeted device settings
|
||||||
target_ip = "10.1.1.1"
|
host_ip = "10.1.1.1"
|
||||||
target_room = 123
|
host_room = 123
|
||||||
target_compilation = 1
|
mdm_compilation = 1
|
||||||
|
|
||||||
|
|
||||||
[host_filter]
|
[host_filter]
|
||||||
|
|
163
src/main.rs
163
src/main.rs
|
@ -87,7 +87,7 @@ args_or_config! {
|
||||||
|optional:
|
|optional:
|
||||||
|
|
||||||
#[clap(long, help("Numerical compilation id the newly added device should be assigned to. HINT: The id can be found at the end of the url when inspecting a compilation in the mdm admin section. If this is not specified, the new device will not be added to a collection."))]
|
#[clap(long, help("Numerical compilation id the newly added device should be assigned to. HINT: The id can be found at the end of the url when inspecting a compilation in the mdm admin section. If this is not specified, the new device will not be added to a collection."))]
|
||||||
target_compilation: u16
|
mdm_compilation: u16
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! print_banner {
|
macro_rules! print_banner {
|
||||||
|
@ -115,12 +115,23 @@ fn main_loop(args: &Config) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
.send()?;
|
.send()?;
|
||||||
let status = &resp.status();
|
let status = &resp.status();
|
||||||
let plain = &resp.text()?;
|
let plain = &resp.text()?;
|
||||||
|
|
||||||
|
if plain.contains("class=\"login-form\"") {
|
||||||
|
eprintln!("ERR: Failed to authorize. Server forwarded to login site. HINT: Check the provided cookie.");
|
||||||
|
std::process::exit(187);
|
||||||
|
}
|
||||||
|
|
||||||
|
if status.is_client_error() || status.is_server_error() {
|
||||||
|
eprintln!("ERR: Received error status (status code: {:?})", status);
|
||||||
|
std::process::exit(187);
|
||||||
|
}
|
||||||
|
|
||||||
let content = squeeze(
|
let content = squeeze(
|
||||||
&plain,
|
&plain,
|
||||||
"<script id=\"crud-data\" type=\"application/json\">",
|
"<script id=\"crud-data\" type=\"application/json\">",
|
||||||
"</script>",
|
"</script>",
|
||||||
);
|
);
|
||||||
let json: serde_json::Value = serde_json::from_str(content).expect("Failed to parse JSON data. This may be because the server did not return valid JSON data to parse.");
|
let json: serde_json::Value = serde_json::from_str(content).expect("ERR: Failed to parse JSON data. This may be because the server did not return valid JSON data to parse.");
|
||||||
let json_part = &json["data"][0]["name"]["rendered"]
|
let json_part = &json["data"][0]["name"]["rendered"]
|
||||||
.to_string()
|
.to_string()
|
||||||
.replace("\\", "");
|
.replace("\\", "");
|
||||||
|
@ -135,46 +146,59 @@ No new host: skipping (Retry in {}s)
|
||||||
std::thread::sleep(std::time::Duration::from_secs(5));
|
std::thread::sleep(std::time::Duration::from_secs(5));
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let host_id = squeeze(json_part, "data-host-id=\"", "\"");
|
let host_id = squeeze(json_part, "data-host-id=\"", "\"");
|
||||||
let device_name = squeeze(json_part, "</span>", "</a>");
|
let device_name = squeeze(json_part, "</span>", "</a>");
|
||||||
print_banner!("1/8 Found host\nHost id: {}\nDevice name: {}\nReceived response status: {:?}", host_id, device_name, status);
|
print_banner!("1/8 Found host\nHost id: {}\nDevice name: {}\nReceived response status: {:?}", host_id, device_name, status);
|
||||||
|
|
||||||
let dest = format!("https://{}/iserv/admin/host/edit/{}", args.hostname, &host_id);
|
let dest = format!("https://{}/iserv/admin/host/edit/{}", args.hostname, &host_id);
|
||||||
let resp = client.get(&dest).header(header.0, header.1).send()?;
|
let resp = client.get(&dest).header(header.0, header.1).send()?;
|
||||||
//TODO Check for non 200 response
|
|
||||||
let status = &resp.status();
|
let status = &resp.status();
|
||||||
if !status.is_success() && *status != 300 {
|
if !status.is_success() {
|
||||||
eprintln!("WARN: Found invalid Status Code: {status}");
|
eprintln!("{}, {}", "WARN: Found invalid Status Code: ".bright_yellow(), status);
|
||||||
return Ok(())
|
return Ok(())
|
||||||
}
|
}
|
||||||
let plain = &resp.text()?;
|
let plain = &resp.text()?;
|
||||||
std::fs::write("lol.out.html", plain)?;
|
|
||||||
let mut form_ip: &str = &args.host_ip;
|
let mut form_ip: &str = &args.host_ip;
|
||||||
let form_name = squeeze_html_form(plain, "name=\"host[name]\"", "value=\"", "\"");
|
let mut form_ip_index = 2;
|
||||||
let form_tags = squeeze_html_form(plain, "name=\"host[tags][]\"", "value=\"", "\"");
|
let form_name = squeeze_html_form(plain, "name=\"host[name]\"", ">", "value=\"", "\"");
|
||||||
let form_mac = squeeze_html_form(plain, "name=\"host[mac]\"", "value=\"", "\"");
|
let plain_inner_tags = squeeze(plain, "name=\"host[tags][]\"", "</select>");
|
||||||
let form_description = squeeze_html_form(plain, "name=\"host[description]\"", ">", "<");
|
let mut form_tags = Vec::new();
|
||||||
let form_token = squeeze_html_form(plain, "name=\"host[_token]\"", "value=\"", "\"");
|
squeeze_loop(&mut form_tags, plain_inner_tags, "<option value=\"", "\"", " selected=\"selected\"", 3, "host[tags][]");
|
||||||
let mut form_data = [
|
|
||||||
("host[name]", form_name),
|
let form_mac = squeeze_html_form(plain, "name=\"host[mac]\"", ">", "value=\"", "\"");
|
||||||
("host[tags][]", form_tags),
|
let form_description = squeeze_html_form(plain, "name=\"host[description]\"", "/textarea>", ">", "<");
|
||||||
("host[room]", &args.host_room.to_string()),
|
let form_token = squeeze_html_form(plain, "name=\"host[_token]\"", ">", "value=\"", "\"");
|
||||||
("host[ip]", &form_ip),
|
let mut form_data = Vec::from([
|
||||||
("host[mac]", form_mac),
|
("host[name]",form_name),
|
||||||
("host[internet]", "1"),
|
].map(|(a, b)| (Cow::Borrowed(a), Cow::Borrowed(b))));
|
||||||
("host[proxyEnforce]", "0"),
|
|
||||||
("host[owner]", ""),
|
// empty tag fields are not permitted
|
||||||
("host[controllable]", "0"),
|
if !(form_tags.is_empty()) {
|
||||||
("host[inventoryNumber]", ""),
|
form_ip_index += form_tags.len();
|
||||||
("host[shutdown]", ""),
|
form_data.extend(form_tags);
|
||||||
("host[description]", form_description),
|
}
|
||||||
("host[image][id]", ""),
|
|
||||||
("host[image][x]", ""),
|
let host_room: &str = &args.host_room.to_string();
|
||||||
("host[image][y]", ""),
|
form_data.extend([
|
||||||
("host[actions][submit]", ""),
|
("host[room]", host_room),
|
||||||
("host[_token]", form_token),
|
("host[ip]", form_ip),
|
||||||
];
|
("host[mac]", form_mac),
|
||||||
print_banner!("2/8 Received current host properties\nReceived response status: {:?}", status);
|
("host[internet]", "1"),
|
||||||
|
("host[proxyEnforce]", "0"),
|
||||||
|
("host[owner]", ""),
|
||||||
|
("host[controllable]", "0"),
|
||||||
|
("host[inventoryNumber]", ""),
|
||||||
|
("host[shutdown]", ""),
|
||||||
|
("host[description]", form_description),
|
||||||
|
("host[image][id]", ""),
|
||||||
|
("host[image][x]", ""),
|
||||||
|
("host[image][y]", ""),
|
||||||
|
("host[actions][submit]", ""),
|
||||||
|
("host[_token]", form_token),
|
||||||
|
].map(|(a, b)| (Cow::Borrowed(a), Cow::Borrowed(b))));
|
||||||
|
|
||||||
|
print_banner!("2/8 Received current host properties\nReceived response status: {:?}", status);
|
||||||
|
|
||||||
println!("{:#?}", form_data);
|
println!("{:#?}", form_data);
|
||||||
let resp = client
|
let resp = client
|
||||||
|
@ -183,18 +207,22 @@ No new host: skipping (Retry in {}s)
|
||||||
.form(&form_data)
|
.form(&form_data)
|
||||||
.send()?;
|
.send()?;
|
||||||
let status = &resp.status();
|
let status = &resp.status();
|
||||||
|
if !status.is_success() {
|
||||||
|
eprintln!("{}, {}", "WARN: Found invalid Status Code: ".bright_yellow(), status);
|
||||||
|
return Ok(())
|
||||||
|
}
|
||||||
let plain = &resp.text()?;
|
let plain = &resp.text()?;
|
||||||
|
|
||||||
|
|
||||||
if !plain.contains("<form name=\"host\"") {
|
if !plain.contains("<form name=\"host\"") {
|
||||||
print_banner!("3/8 The configured ip was accepted {}\nReceived response status: {:?}", form_ip, status);
|
print_banner!("3/8 The configured ip was accepted {}\nReceived response status: {:?}", form_ip, status);
|
||||||
print_banner!("{}", "4/8 IP address resubmission was skipped");
|
print_banner!("{}", "4/8 Ip address resubmission was skipped");
|
||||||
} else {
|
} else {
|
||||||
// retrieve next available ip address from sent form
|
// retrieve next available ip address from sent form
|
||||||
form_ip = squeeze_html_form(plain, "name=\"host[ip]\"", "value=\"", "\"");
|
form_ip = squeeze_html_form(plain, "name=\"host[ip]\"", ">", "value=\"", "\"");
|
||||||
form_data[3] = ("host[ip]", form_ip);
|
form_data[form_ip_index] = ("host[ip]".into(), form_ip.into());
|
||||||
print_banner!("3/8 Received recommended ip: {}\nReceived response status: {:?}", form_ip, status);
|
print_banner!("3/8 Received recommended ip: {}\nReceived response status: {:?}", form_ip, status);
|
||||||
|
|
||||||
let resp = client
|
let resp = client
|
||||||
.post(&dest)
|
.post(&dest)
|
||||||
.header(header.0, header.1)
|
.header(header.0, header.1)
|
||||||
|
@ -204,15 +232,18 @@ No new host: skipping (Retry in {}s)
|
||||||
print_banner!("4/8 Sucessfully updated host\nReceived response status: {:?}", status);
|
print_banner!("4/8 Sucessfully updated host\nReceived response status: {:?}", status);
|
||||||
}
|
}
|
||||||
|
|
||||||
let target_compilation = if let Some(t) = args.target_compilation { t } else { return Ok(()) };
|
let target_compilation = if let Some(t) = args.mdm_compilation { t } else { return Ok(()) };
|
||||||
|
|
||||||
let resp = client
|
let resp = client
|
||||||
.get(format!("https://{}/iserv/admin/mdm/ios/compilation/edit/{}", args.hostname, target_compilation))
|
.get(format!("https://{}/iserv/admin/mdm/ios/compilation/edit/{}", args.hostname, target_compilation))
|
||||||
.header(header.0, header.1)
|
.header(header.0, header.1)
|
||||||
.send()?;
|
.send()?;
|
||||||
//TODO Check for non 200 response
|
|
||||||
|
|
||||||
let status = &resp.status();
|
let status = &resp.status();
|
||||||
|
if !status.is_success() {
|
||||||
|
eprintln!("{}, {}", "WARN: Found invalid Status Code: ".bright_yellow(), status);
|
||||||
|
return Ok(())
|
||||||
|
}
|
||||||
let plain = &resp.text()?;
|
let plain = &resp.text()?;
|
||||||
|
|
||||||
print_banner!("5/8 Received MDM compilation\nReceived response status: {:?}", status);
|
print_banner!("5/8 Received MDM compilation\nReceived response status: {:?}", status);
|
||||||
|
@ -220,32 +251,32 @@ No new host: skipping (Retry in {}s)
|
||||||
let mut form_data = Vec::from([
|
let mut form_data = Vec::from([
|
||||||
(
|
(
|
||||||
"ioscompilation[name]",
|
"ioscompilation[name]",
|
||||||
squeeze_html_form(plain, "name=\"ioscompilation[name]\"", "value=\"", "\"")
|
squeeze_html_form(plain, "name=\"ioscompilation[name]\"", ">", "value=\"", "\"")
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"ioscompilation[description]",
|
"ioscompilation[description]",
|
||||||
squeeze_html_form(plain, "name=\"ioscompilation[description]\"", "value=\"", "\"")
|
squeeze_html_form(plain, "name=\"ioscompilation[description]\"", ">", "value=\"", "\"")
|
||||||
),
|
),
|
||||||
].map(|(a, b)| (Cow::Borrowed(a), Cow::Borrowed(b))));
|
].map(|(a, b)| (Cow::Borrowed(a), Cow::Borrowed(b))));
|
||||||
|
|
||||||
// push apps
|
// push apps
|
||||||
let plain_inner_applications = squeeze_html_form(plain, "name=\"ioscompilation[applications][]\"", ">", "</select>");
|
let plain_inner_applications = squeeze(plain, "name=\"ioscompilation[applications][]\"", "</select>");
|
||||||
squeeze_loop(&mut form_data, plain_inner_applications, "<option value=\"", "\"", " selected=\"selected\"", 3, "ioscompilation[applications][]");
|
squeeze_loop(&mut form_data, plain_inner_applications, "<option value=\"", "\"", " selected=\"selected\"", 3, "ioscompilation[applications][]");
|
||||||
|
|
||||||
// push profiles
|
// push profiles
|
||||||
let plain_inner_profiles = squeeze_html_form(plain, "name=\"ioscompilation[profiles][]\"", ">", "</select>");
|
let plain_inner_profiles = squeeze(plain, "name=\"ioscompilation[profiles][]\"", "</select>");
|
||||||
squeeze_loop(&mut form_data, plain_inner_profiles, "<option value=\"", "\"", " selected=\"selected\"", 3, "ioscompilation[profiles][]");
|
squeeze_loop(&mut form_data, plain_inner_profiles, "<option value=\"", "\"", " selected=\"selected\"", 3, "ioscompilation[profiles][]");
|
||||||
|
|
||||||
// push existing devices
|
// push existing devices
|
||||||
let plain_inner_devices = squeeze_html_form(plain, "name=\"ioscompilation[devices][]\"", ">", "</select>");
|
let plain_inner_devices = squeeze(plain, "name=\"ioscompilation[devices][]\"", "</select>");
|
||||||
squeeze_loop(&mut form_data, plain_inner_devices, "<option value=\"", "\"", " selected=\"selected\"", 3, "ioscompilation[devices][]");
|
squeeze_loop(&mut form_data, plain_inner_devices, "<option value=\"", "\"", " selected=\"", 3, "ioscompilation[devices][]");
|
||||||
|
|
||||||
// push new device
|
// push new device
|
||||||
let mdm_new_idevice_id = squeeze_right(plain_inner_devices, "<option value=\"", &format!("\">{}", form_name));
|
let mdm_new_idevice_id = squeeze_right(plain_inner_devices, "<option value=\"", &format!("\">{}", form_name));
|
||||||
if plain_inner_devices.contains(form_name) {
|
if plain_inner_devices.contains(form_name) {
|
||||||
form_data.push(("ioscompilation[devices][]".into(), mdm_new_idevice_id.into()));
|
form_data.push(("ioscompilation[devices][]".into(), mdm_new_idevice_id.into()));
|
||||||
} else {
|
} else {
|
||||||
eprintln!("{}", "WARN: Device not found in compilation form.\nSkipping compilation edit...".bright_red());
|
eprintln!("{}", "WARN: Device not found in compilation form.\nSkipping compilation edit...".bright_yellow());
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,15 +284,19 @@ No new host: skipping (Retry in {}s)
|
||||||
form_data.push(("ioscompilation[actions][submit]".into(), "".into()));
|
form_data.push(("ioscompilation[actions][submit]".into(), "".into()));
|
||||||
|
|
||||||
//push token
|
//push token
|
||||||
let form_token = squeeze_html_form(plain, "name=\"ioscompilation[_token]\"", "value=\"", "\"");
|
let form_token = squeeze_html_form(plain, "name=\"ioscompilation[_token]\"", ">", "value=\"", "\"");
|
||||||
form_data.push(("ioscompilation[_token]".into(), form_token.into()));
|
form_data.push(("ioscompilation[_token]".into(), form_token.into()));
|
||||||
let resp = client
|
let resp = client
|
||||||
.post(format!("https://{}/iserv/admin/mdm/ios/compilation/edit/{}", args.hostname, args.target_compilation.unwrap()))
|
.post(format!("https://{}/iserv/admin/mdm/ios/compilation/edit/{}", args.hostname, args.mdm_compilation.unwrap()))
|
||||||
.header(header.0, header.1)
|
.header(header.0, header.1)
|
||||||
.form(&form_data)
|
.form(&form_data)
|
||||||
.send()?;
|
.send()?;
|
||||||
|
|
||||||
let status = &resp.status();
|
let status = &resp.status();
|
||||||
|
if !status.is_success() {
|
||||||
|
eprintln!("{}, {}", "WARN: Found invalid Status Code: ".bright_yellow(), status);
|
||||||
|
return Ok(())
|
||||||
|
}
|
||||||
print_banner!("6/8 Added device to MDM Compilation\nReceived response status: {:?}", status);
|
print_banner!("6/8 Added device to MDM Compilation\nReceived response status: {:?}", status);
|
||||||
|
|
||||||
let resp = client
|
let resp = client
|
||||||
|
@ -270,8 +305,12 @@ No new host: skipping (Retry in {}s)
|
||||||
.send()?;
|
.send()?;
|
||||||
|
|
||||||
let status = &resp.status();
|
let status = &resp.status();
|
||||||
|
if !status.is_success() {
|
||||||
|
eprintln!("{}, {}", "WARN: Found invalid Status Code: ".bright_yellow(), status);
|
||||||
|
return Ok(())
|
||||||
|
}
|
||||||
let plain = &resp.text()?;
|
let plain = &resp.text()?;
|
||||||
let csrf_token = squeeze_html_form(plain, "name=\"iserv_crud_multi_select[_token]\"", "value=\"", "\"");
|
let csrf_token = squeeze_html_form(plain, "name=\"iserv_crud_multi_select[_token]\"", ">", "value=\"", "\"");
|
||||||
|
|
||||||
print_banner!("7/8 Retrieved CSRF token\nReceived response status: {:?}", status);
|
print_banner!("7/8 Retrieved CSRF token\nReceived response status: {:?}", status);
|
||||||
|
|
||||||
|
@ -287,6 +326,10 @@ No new host: skipping (Retry in {}s)
|
||||||
.form(&form_data)
|
.form(&form_data)
|
||||||
.send()?;
|
.send()?;
|
||||||
let status = &resp.status();
|
let status = &resp.status();
|
||||||
|
if !status.is_success() {
|
||||||
|
eprintln!("{}, {}", "WARN: Found invalid Status Code: ".bright_yellow(), status);
|
||||||
|
return Ok(())
|
||||||
|
}
|
||||||
print_banner!("8/8 Confirmed device actions\nReceived response status: {:?}", status);
|
print_banner!("8/8 Confirmed device actions\nReceived response status: {:?}", status);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -326,29 +369,15 @@ fn squeeze_right<'inp>(input: &'inp str, before: &str, after: &str) -> &'inp str
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn squeeze_html_form<'inp>(
|
fn squeeze_html_form<'inp>(
|
||||||
input: &'inp str,
|
input: &'inp str,
|
||||||
first: &str,
|
outer_before: &str,
|
||||||
second: &str,
|
outer_after: &str,
|
||||||
last: &str,
|
inner_before: &str,
|
||||||
|
inner_after: &str
|
||||||
) -> &'inp str {
|
) -> &'inp str {
|
||||||
//find first occurence (broad search)
|
let outer_str = squeeze(input, outer_before, outer_after);
|
||||||
if let Some(from_first_bytes) = input.find(first) {
|
squeeze(outer_str, inner_before, inner_after)
|
||||||
let after_first_bytes = from_first_bytes + first.len();
|
|
||||||
let after_first = &input[after_first_bytes..];
|
|
||||||
//find second occurence (field search)
|
|
||||||
if let Some(rel_from_second_bytes) = after_first.find(second) {
|
|
||||||
let after_second_bytes = rel_from_second_bytes + after_first_bytes + second.len();
|
|
||||||
let after_second = &input[after_second_bytes..];
|
|
||||||
//find closing last match (excluded from output)
|
|
||||||
if let Some(rel_from_last_byte) = after_second.find(last) {
|
|
||||||
let from_last_byte = rel_from_last_byte + after_second_bytes;
|
|
||||||
return &input[after_second_bytes..from_last_byte];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn squeeze_loop<'inp>(
|
fn squeeze_loop<'inp>(
|
||||||
|
|
Loading…
Reference in New Issue