style: cargo fmt (fixes the CI format-check failure)
This commit is contained in:
+72
-16
@@ -34,11 +34,50 @@ pub enum ParseError {
|
|||||||
/// suggestions on an unknown command (issue #29). Not exhaustive — just the
|
/// suggestions on an unknown command (issue #29). Not exhaustive — just the
|
||||||
/// common verbs plus a few known wrong-guesses mapped to the real command.
|
/// common verbs plus a few known wrong-guesses mapped to the real command.
|
||||||
const KNOWN_COMMANDS: &[&str] = &[
|
const KNOWN_COMMANDS: &[&str] = &[
|
||||||
"open", "navigate", "click", "fill", "type", "press", "snapshot", "screenshot", "eval", "get",
|
"open",
|
||||||
"text", "html", "frames", "find", "wait", "scroll", "hover", "select", "check", "uncheck",
|
"navigate",
|
||||||
"tab", "tabs", "close", "back", "forward", "reload", "sessions", "status", "daemon", "doctor",
|
"click",
|
||||||
"upgrade", "connect", "cookies", "mouse", "keyboard", "stream", "frame", "profiles", "title",
|
"fill",
|
||||||
"url", "is", "drag", "dialog", "upload",
|
"type",
|
||||||
|
"press",
|
||||||
|
"snapshot",
|
||||||
|
"screenshot",
|
||||||
|
"eval",
|
||||||
|
"get",
|
||||||
|
"text",
|
||||||
|
"html",
|
||||||
|
"frames",
|
||||||
|
"find",
|
||||||
|
"wait",
|
||||||
|
"scroll",
|
||||||
|
"hover",
|
||||||
|
"select",
|
||||||
|
"check",
|
||||||
|
"uncheck",
|
||||||
|
"tab",
|
||||||
|
"tabs",
|
||||||
|
"close",
|
||||||
|
"back",
|
||||||
|
"forward",
|
||||||
|
"reload",
|
||||||
|
"sessions",
|
||||||
|
"status",
|
||||||
|
"daemon",
|
||||||
|
"doctor",
|
||||||
|
"upgrade",
|
||||||
|
"connect",
|
||||||
|
"cookies",
|
||||||
|
"mouse",
|
||||||
|
"keyboard",
|
||||||
|
"stream",
|
||||||
|
"frame",
|
||||||
|
"profiles",
|
||||||
|
"title",
|
||||||
|
"url",
|
||||||
|
"is",
|
||||||
|
"drag",
|
||||||
|
"dialog",
|
||||||
|
"upload",
|
||||||
];
|
];
|
||||||
|
|
||||||
/// Levenshtein distance, capped — small inputs only (command names).
|
/// Levenshtein distance, capped — small inputs only (command names).
|
||||||
@@ -547,7 +586,9 @@ fn parse_command_inner(args: &[String], flags: &Flags) -> Result<Value, ParseErr
|
|||||||
context: "type".to_string(),
|
context: "type".to_string(),
|
||||||
usage: "type <selector> <text> (or: type --focused <text>) [--key-events]",
|
usage: "type <selector> <text> (or: type --focused <text>) [--key-events]",
|
||||||
})?;
|
})?;
|
||||||
Ok(json!({ "id": id, "action": "type", "selector": sel, "text": rest[1..].join(" "), "keyEvents": key_events }))
|
Ok(
|
||||||
|
json!({ "id": id, "action": "type", "selector": sel, "text": rest[1..].join(" "), "keyEvents": key_events }),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
"pick" => {
|
"pick" => {
|
||||||
// pick <selector|@ref> --option "<text>" — atomic combobox select:
|
// pick <selector|@ref> --option "<text>" — atomic combobox select:
|
||||||
@@ -761,7 +802,8 @@ fn parse_command_inner(args: &[String], flags: &Flags) -> Result<Value, ParseErr
|
|||||||
_ => {
|
_ => {
|
||||||
return Err(ParseError::InvalidValue {
|
return Err(ParseError::InvalidValue {
|
||||||
message: format!("scroll --at: invalid coordinate `{}`", val),
|
message: format!("scroll --at: invalid coordinate `{}`", val),
|
||||||
usage: "scroll [direction] [amount] --at <x,y> (e.g. --at 640,400)",
|
usage:
|
||||||
|
"scroll [direction] [amount] --at <x,y> (e.g. --at 640,400)",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -970,17 +1012,21 @@ fn parse_command_inner(args: &[String], flags: &Flags) -> Result<Value, ParseErr
|
|||||||
"--full" | "-f" => full_page = true,
|
"--full" | "-f" => full_page = true,
|
||||||
// `--clip x,y,w,h` captures a pixel region (issue #34).
|
// `--clip x,y,w,h` captures a pixel region (issue #34).
|
||||||
"--clip" => {
|
"--clip" => {
|
||||||
let raw = rest.get(i + 1).ok_or_else(|| ParseError::MissingArguments {
|
let raw = rest
|
||||||
context: "screenshot --clip".to_string(),
|
.get(i + 1)
|
||||||
usage: "screenshot --clip <x,y,w,h> [path]",
|
.ok_or_else(|| ParseError::MissingArguments {
|
||||||
})?;
|
context: "screenshot --clip".to_string(),
|
||||||
|
usage: "screenshot --clip <x,y,w,h> [path]",
|
||||||
|
})?;
|
||||||
let nums: Vec<f64> = raw
|
let nums: Vec<f64> = raw
|
||||||
.split(',')
|
.split(',')
|
||||||
.filter_map(|n| n.trim().parse::<f64>().ok())
|
.filter_map(|n| n.trim().parse::<f64>().ok())
|
||||||
.collect();
|
.collect();
|
||||||
if nums.len() != 4 {
|
if nums.len() != 4 {
|
||||||
return Err(ParseError::InvalidValue {
|
return Err(ParseError::InvalidValue {
|
||||||
message: format!("--clip expects 'x,y,w,h' (4 numbers), got '{raw}'"),
|
message: format!(
|
||||||
|
"--clip expects 'x,y,w,h' (4 numbers), got '{raw}'"
|
||||||
|
),
|
||||||
usage: "screenshot --clip <x,y,w,h> [path]",
|
usage: "screenshot --clip <x,y,w,h> [path]",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -4128,7 +4174,11 @@ mod tests {
|
|||||||
fn test_type_key_events() {
|
fn test_type_key_events() {
|
||||||
// --key-events sends real keystrokes (for autocomplete/combobox) and must
|
// --key-events sends real keystrokes (for autocomplete/combobox) and must
|
||||||
// not be swallowed into the typed text.
|
// not be swallowed into the typed text.
|
||||||
let cmd = parse_command(&args("type #postal 201-0001 --key-events"), &default_flags()).unwrap();
|
let cmd = parse_command(
|
||||||
|
&args("type #postal 201-0001 --key-events"),
|
||||||
|
&default_flags(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
assert_eq!(cmd["action"], "type");
|
assert_eq!(cmd["action"], "type");
|
||||||
assert_eq!(cmd["selector"], "#postal");
|
assert_eq!(cmd["selector"], "#postal");
|
||||||
assert_eq!(cmd["text"], "201-0001");
|
assert_eq!(cmd["text"], "201-0001");
|
||||||
@@ -4426,8 +4476,11 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_screenshot_clip() {
|
fn test_screenshot_clip() {
|
||||||
// `--clip x,y,w,h` captures a pixel region (issue #34); the path still parses.
|
// `--clip x,y,w,h` captures a pixel region (issue #34); the path still parses.
|
||||||
let cmd = parse_command(&args("screenshot --clip 10,20,200,40 out.png"), &default_flags())
|
let cmd = parse_command(
|
||||||
.unwrap();
|
&args("screenshot --clip 10,20,200,40 out.png"),
|
||||||
|
&default_flags(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
assert_eq!(cmd["action"], "screenshot");
|
assert_eq!(cmd["action"], "screenshot");
|
||||||
assert_eq!(cmd["clip"]["x"], 10.0);
|
assert_eq!(cmd["clip"]["x"], 10.0);
|
||||||
assert_eq!(cmd["clip"]["y"], 20.0);
|
assert_eq!(cmd["clip"]["y"], 20.0);
|
||||||
@@ -5005,7 +5058,10 @@ mod tests {
|
|||||||
assert_eq!(nearest_command("sesions").as_deref(), Some("sessions"));
|
assert_eq!(nearest_command("sesions").as_deref(), Some("sessions"));
|
||||||
assert_eq!(nearest_command("session").as_deref(), Some("sessions"));
|
assert_eq!(nearest_command("session").as_deref(), Some("sessions"));
|
||||||
assert_eq!(nearest_command("clik").as_deref(), Some("click"));
|
assert_eq!(nearest_command("clik").as_deref(), Some("click"));
|
||||||
assert_eq!(nearest_command("screenshits").as_deref(), Some("screenshot"));
|
assert_eq!(
|
||||||
|
nearest_command("screenshits").as_deref(),
|
||||||
|
Some("screenshot")
|
||||||
|
);
|
||||||
// Nonsense with no close match stays silent.
|
// Nonsense with no close match stays silent.
|
||||||
assert_eq!(nearest_command("xyzzy"), None);
|
assert_eq!(nearest_command("xyzzy"), None);
|
||||||
// The unknown-command error embeds the suggestion.
|
// The unknown-command error embeds the suggestion.
|
||||||
|
|||||||
@@ -3244,8 +3244,14 @@ async fn handle_type(cmd: &Value, state: &mut DaemonState) -> Result<Value, Stri
|
|||||||
.get("text")
|
.get("text")
|
||||||
.and_then(|v| v.as_str())
|
.and_then(|v| v.as_str())
|
||||||
.ok_or("Missing 'text' parameter")?;
|
.ok_or("Missing 'text' parameter")?;
|
||||||
interaction::type_text_into_active_context(&mgr.client, &session_id, text, None, key_events)
|
interaction::type_text_into_active_context(
|
||||||
.await?;
|
&mgr.client,
|
||||||
|
&session_id,
|
||||||
|
text,
|
||||||
|
None,
|
||||||
|
key_events,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
return Ok(json!({ "typed": text, "focused": true }));
|
return Ok(json!({ "typed": text, "focused": true }));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3836,12 +3842,9 @@ async fn handle_gettext(cmd: &Value, state: &mut DaemonState) -> Result<Value, S
|
|||||||
async fn handle_frames(_cmd: &Value, state: &mut DaemonState) -> Result<Value, String> {
|
async fn handle_frames(_cmd: &Value, state: &mut DaemonState) -> Result<Value, String> {
|
||||||
let mgr = state.browser.as_ref().ok_or("Browser not launched")?;
|
let mgr = state.browser.as_ref().ok_or("Browser not launched")?;
|
||||||
let session_id = mgr.active_session_id()?.to_string();
|
let session_id = mgr.active_session_id()?.to_string();
|
||||||
let frames = super::element::collect_all_frames_text(
|
let frames =
|
||||||
&mgr.client,
|
super::element::collect_all_frames_text(&mgr.client, &session_id, &state.iframe_sessions)
|
||||||
&session_id,
|
.await?;
|
||||||
&state.iframe_sessions,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
let list: Vec<Value> = frames
|
let list: Vec<Value> = frames
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
@@ -4337,7 +4340,10 @@ async fn handle_cf_status(_cmd: &Value, state: &mut DaemonState) -> Result<Value
|
|||||||
let url = mgr.get_url().await.unwrap_or_default();
|
let url = mgr.get_url().await.unwrap_or_default();
|
||||||
|
|
||||||
// 1. Is the page a Cloudflare challenge right now?
|
// 1. Is the page a Cloudflare challenge right now?
|
||||||
let probe_raw = mgr.evaluate(CF_CHALLENGE_JS, None).await.unwrap_or(Value::Null);
|
let probe_raw = mgr
|
||||||
|
.evaluate(CF_CHALLENGE_JS, None)
|
||||||
|
.await
|
||||||
|
.unwrap_or(Value::Null);
|
||||||
let probe = parse_json_string(probe_raw, "cf challenge probe").unwrap_or(Value::Null);
|
let probe = parse_json_string(probe_raw, "cf challenge probe").unwrap_or(Value::Null);
|
||||||
let challenged = probe
|
let challenged = probe
|
||||||
.get("challenged")
|
.get("challenged")
|
||||||
|
|||||||
@@ -579,7 +579,10 @@ impl BrowserManager {
|
|||||||
crate::connect::log_connect_mode(
|
crate::connect::log_connect_mode(
|
||||||
&ws_url,
|
&ws_url,
|
||||||
true,
|
true,
|
||||||
DAEMON_SESSION.get().map(String::as_str).unwrap_or("default"),
|
DAEMON_SESSION
|
||||||
|
.get()
|
||||||
|
.map(String::as_str)
|
||||||
|
.unwrap_or("default"),
|
||||||
);
|
);
|
||||||
let manager = if engine == "lightpanda" {
|
let manager = if engine == "lightpanda" {
|
||||||
initialize_lightpanda_manager(ws_url, process).await?
|
initialize_lightpanda_manager(ws_url, process).await?
|
||||||
@@ -681,7 +684,10 @@ impl BrowserManager {
|
|||||||
crate::connect::log_connect_mode(
|
crate::connect::log_connect_mode(
|
||||||
&ws_url,
|
&ws_url,
|
||||||
false,
|
false,
|
||||||
DAEMON_SESSION.get().map(String::as_str).unwrap_or("default"),
|
DAEMON_SESSION
|
||||||
|
.get()
|
||||||
|
.map(String::as_str)
|
||||||
|
.unwrap_or("default"),
|
||||||
);
|
);
|
||||||
let client = Arc::new(CdpClient::connect_with_headers(&ws_url, headers).await?);
|
let client = Arc::new(CdpClient::connect_with_headers(&ws_url, headers).await?);
|
||||||
let mut manager = Self {
|
let mut manager = Self {
|
||||||
@@ -2815,7 +2821,9 @@ mod tests {
|
|||||||
its tab is gone (closed, navigated across processes, or lost after an extension \
|
its tab is gone (closed, navigated across processes, or lost after an extension \
|
||||||
restart). Re-attach by re-opening your target URL before retrying."
|
restart). Re-attach by re-opening your target URL before retrying."
|
||||||
));
|
));
|
||||||
assert!(is_stale_target_error("unknown sessionId cb-tab-7 for Page.navigate"));
|
assert!(is_stale_target_error(
|
||||||
|
"unknown sessionId cb-tab-7 for Page.navigate"
|
||||||
|
));
|
||||||
assert!(is_stale_target_error("no attached tab for Page.navigate"));
|
assert!(is_stale_target_error("no attached tab for Page.navigate"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2823,8 +2831,12 @@ mod tests {
|
|||||||
fn stale_target_error_ignores_unrelated_failures() {
|
fn stale_target_error_ignores_unrelated_failures() {
|
||||||
// A genuine navigation failure (bad URL, DNS, blocked) must NOT trigger
|
// A genuine navigation failure (bad URL, DNS, blocked) must NOT trigger
|
||||||
// the open-a-fresh-tab recovery — that would mask the real error.
|
// the open-a-fresh-tab recovery — that would mask the real error.
|
||||||
assert!(!is_stale_target_error("Navigation failed: net::ERR_NAME_NOT_RESOLVED"));
|
assert!(!is_stale_target_error(
|
||||||
assert!(!is_stale_target_error("CDP command timed out: Page.navigate"));
|
"Navigation failed: net::ERR_NAME_NOT_RESOLVED"
|
||||||
|
));
|
||||||
|
assert!(!is_stale_target_error(
|
||||||
|
"CDP command timed out: Page.navigate"
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn page(target_id: &str) -> PageInfo {
|
fn page(target_id: &str) -> PageInfo {
|
||||||
@@ -2931,7 +2943,10 @@ mod tests {
|
|||||||
let dirty = "\u{200d}\u{2061}\u{200d}\u{2063}\u{200b}\u{2062}\u{feff}GitHub";
|
let dirty = "\u{200d}\u{2061}\u{200d}\u{2063}\u{200b}\u{2062}\u{feff}GitHub";
|
||||||
assert_eq!(sanitize_title(dirty), "GitHub");
|
assert_eq!(sanitize_title(dirty), "GitHub");
|
||||||
// Clean titles (incl. CJK + normal punctuation) pass through untouched.
|
// Clean titles (incl. CJK + normal punctuation) pass through untouched.
|
||||||
assert_eq!(sanitize_title("購入手続きへ - メルカリ"), "購入手続きへ - メルカリ");
|
assert_eq!(
|
||||||
|
sanitize_title("購入手続きへ - メルカリ"),
|
||||||
|
"購入手続きへ - メルカリ"
|
||||||
|
);
|
||||||
assert_eq!(sanitize_title(" Hello World "), "Hello World");
|
assert_eq!(sanitize_title(" Hello World "), "Hello World");
|
||||||
// Emoji and real content survive; only the invisibles are dropped.
|
// Emoji and real content survive; only the invisibles are dropped.
|
||||||
assert_eq!(sanitize_title("✓ Done\u{200b}"), "✓ Done");
|
assert_eq!(sanitize_title("✓ Done\u{200b}"), "✓ Done");
|
||||||
@@ -2963,7 +2978,10 @@ mod tests {
|
|||||||
// A pinned target that IS in the live set is simply not prunable anyway.
|
// A pinned target that IS in the live set is simply not prunable anyway.
|
||||||
let mut live2 = HashSet::new();
|
let mut live2 = HashSet::new();
|
||||||
live2.insert("A".to_string());
|
live2.insert("A".to_string());
|
||||||
assert_eq!(prunable_target_ids(&pages, &live2, Some("A")), vec!["B".to_string()]);
|
assert_eq!(
|
||||||
|
prunable_target_ids(&pages, &live2, Some("A")),
|
||||||
|
vec!["B".to_string()]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1028,7 +1028,9 @@ async fn eval_text_in_frame(client: &CdpClient, session_id: &str, frame_id: &str
|
|||||||
.await
|
.await
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|v| v.get("executionContextId").and_then(|c| c.as_i64()));
|
.and_then(|v| v.get("executionContextId").and_then(|c| c.as_i64()));
|
||||||
let Some(ctx_id) = ctx else { return String::new() };
|
let Some(ctx_id) = ctx else {
|
||||||
|
return String::new();
|
||||||
|
};
|
||||||
let res = client
|
let res = client
|
||||||
.send_command(
|
.send_command(
|
||||||
"Runtime.evaluate",
|
"Runtime.evaluate",
|
||||||
@@ -1099,7 +1101,10 @@ pub async fn collect_all_frames_text(
|
|||||||
let (kind, text) = if is_top {
|
let (kind, text) = if is_top {
|
||||||
("top", eval_text_default(client, top_session).await)
|
("top", eval_text_default(client, top_session).await)
|
||||||
} else {
|
} else {
|
||||||
("inline", eval_text_in_frame(client, top_session, &fid).await)
|
(
|
||||||
|
"inline",
|
||||||
|
eval_text_in_frame(client, top_session, &fid).await,
|
||||||
|
)
|
||||||
};
|
};
|
||||||
out.push(FrameText {
|
out.push(FrameText {
|
||||||
frame_id: fid,
|
frame_id: fid,
|
||||||
|
|||||||
@@ -65,7 +65,11 @@ pub async fn click(
|
|||||||
// the element's click in its own (frame) session, always hitting the right
|
// the element's click in its own (frame) session, always hitting the right
|
||||||
// element in the right tab. Double/right clicks still need true pointer
|
// element in the right tab. Double/right clicks still need true pointer
|
||||||
// semantics, and `coord` mode is an explicit opt-out.
|
// semantics, and `coord` mode is an explicit opt-out.
|
||||||
if mode != "coord" && button == "left" && click_count == 1 && prefer_dom_dispatch(ref_map, selector_or_ref) {
|
if mode != "coord"
|
||||||
|
&& button == "left"
|
||||||
|
&& click_count == 1
|
||||||
|
&& prefer_dom_dispatch(ref_map, selector_or_ref)
|
||||||
|
{
|
||||||
return dom_click(
|
return dom_click(
|
||||||
client,
|
client,
|
||||||
session_id,
|
session_id,
|
||||||
@@ -319,7 +323,14 @@ pub async fn dblclick(
|
|||||||
if std::env::var("AGENT_BROWSER_CLICK_MODE").as_deref() != Ok("coord")
|
if std::env::var("AGENT_BROWSER_CLICK_MODE").as_deref() != Ok("coord")
|
||||||
&& prefer_dom_dispatch(ref_map, selector_or_ref)
|
&& prefer_dom_dispatch(ref_map, selector_or_ref)
|
||||||
{
|
{
|
||||||
return dom_dblclick(client, session_id, ref_map, selector_or_ref, iframe_sessions).await;
|
return dom_dblclick(
|
||||||
|
client,
|
||||||
|
session_id,
|
||||||
|
ref_map,
|
||||||
|
selector_or_ref,
|
||||||
|
iframe_sessions,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
click(
|
click(
|
||||||
client,
|
client,
|
||||||
@@ -387,7 +398,14 @@ pub async fn hover(
|
|||||||
// Coordinate `mouseMoved` drifts to the foreground tab over the relay and
|
// Coordinate `mouseMoved` drifts to the foreground tab over the relay and
|
||||||
// can't reach an OOPIF — DOM-dispatch the hover there (issues #31/#36).
|
// can't reach an OOPIF — DOM-dispatch the hover there (issues #31/#36).
|
||||||
if prefer_dom_dispatch(ref_map, selector_or_ref) {
|
if prefer_dom_dispatch(ref_map, selector_or_ref) {
|
||||||
return dom_hover(client, session_id, ref_map, selector_or_ref, iframe_sessions).await;
|
return dom_hover(
|
||||||
|
client,
|
||||||
|
session_id,
|
||||||
|
ref_map,
|
||||||
|
selector_or_ref,
|
||||||
|
iframe_sessions,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
let (x, y, _w, _h, effective_session_id) = resolve_element_center(
|
let (x, y, _w, _h, effective_session_id) = resolve_element_center(
|
||||||
client,
|
client,
|
||||||
|
|||||||
@@ -345,7 +345,16 @@ pub async fn take_snapshot(
|
|||||||
frame_id: Option<&str>,
|
frame_id: Option<&str>,
|
||||||
iframe_sessions: &HashMap<String, String>,
|
iframe_sessions: &HashMap<String, String>,
|
||||||
) -> Result<String, String> {
|
) -> Result<String, String> {
|
||||||
take_snapshot_at_depth(client, session_id, options, ref_map, frame_id, iframe_sessions, 0).await
|
take_snapshot_at_depth(
|
||||||
|
client,
|
||||||
|
session_id,
|
||||||
|
options,
|
||||||
|
ref_map,
|
||||||
|
frame_id,
|
||||||
|
iframe_sessions,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
|||||||
+37
-8
@@ -228,13 +228,28 @@ pub fn print_response_with_opts(resp: &Response, action: Option<&str>, opts: &Ou
|
|||||||
// because its response carries `url`/`title`, which later generic
|
// because its response carries `url`/`title`, which later generic
|
||||||
// renderers would otherwise swallow.
|
// renderers would otherwise swallow.
|
||||||
if action == Some("cf_status") {
|
if action == Some("cf_status") {
|
||||||
let challenged = data.get("challenged").and_then(|v| v.as_bool()).unwrap_or(false);
|
let challenged = data
|
||||||
let rec = data.get("recommendation").and_then(|v| v.as_str()).unwrap_or("?");
|
.get("challenged")
|
||||||
|
.and_then(|v| v.as_bool())
|
||||||
|
.unwrap_or(false);
|
||||||
|
let rec = data
|
||||||
|
.get("recommendation")
|
||||||
|
.and_then(|v| v.as_str())
|
||||||
|
.unwrap_or("?");
|
||||||
let cl = data.get("clearance");
|
let cl = data.get("clearance");
|
||||||
let present = cl.and_then(|c| c.get("present")).and_then(|v| v.as_bool()).unwrap_or(false);
|
let present = cl
|
||||||
let expired = cl.and_then(|c| c.get("expired")).and_then(|v| v.as_bool()).unwrap_or(false);
|
.and_then(|c| c.get("present"))
|
||||||
|
.and_then(|v| v.as_bool())
|
||||||
|
.unwrap_or(false);
|
||||||
|
let expired = cl
|
||||||
|
.and_then(|c| c.get("expired"))
|
||||||
|
.and_then(|v| v.as_bool())
|
||||||
|
.unwrap_or(false);
|
||||||
let expires_in = cl.and_then(|c| c.get("expiresIn")).and_then(|v| v.as_i64());
|
let expires_in = cl.and_then(|c| c.get("expiresIn")).and_then(|v| v.as_i64());
|
||||||
let device = data.get("deviceVerified").and_then(|v| v.as_bool()).unwrap_or(false);
|
let device = data
|
||||||
|
.get("deviceVerified")
|
||||||
|
.and_then(|v| v.as_bool())
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
let (icon, headline) = match rec {
|
let (icon, headline) = match rec {
|
||||||
"proceed" => (color::success_indicator().to_string(), "cleared — no challenge, proceed"),
|
"proceed" => (color::success_indicator().to_string(), "cleared — no challenge, proceed"),
|
||||||
@@ -243,7 +258,10 @@ pub fn print_response_with_opts(resp: &Response, action: Option<&str>, opts: &Ou
|
|||||||
_ => (color::cyan("•").to_string(), "unknown"),
|
_ => (color::cyan("•").to_string(), "unknown"),
|
||||||
};
|
};
|
||||||
println!("{} {}", icon, headline);
|
println!("{} {}", icon, headline);
|
||||||
println!(" challenged: {}", if challenged { "yes" } else { "no" });
|
println!(
|
||||||
|
" challenged: {}",
|
||||||
|
if challenged { "yes" } else { "no" }
|
||||||
|
);
|
||||||
let cl_desc = if !present {
|
let cl_desc = if !present {
|
||||||
"absent".to_string()
|
"absent".to_string()
|
||||||
} else if expired {
|
} else if expired {
|
||||||
@@ -254,7 +272,14 @@ pub fn print_response_with_opts(resp: &Response, action: Option<&str>, opts: &Ou
|
|||||||
"present (session)".to_string()
|
"present (session)".to_string()
|
||||||
};
|
};
|
||||||
println!(" cf_clearance: {}", cl_desc);
|
println!(" cf_clearance: {}", cl_desc);
|
||||||
println!(" device trusted: {}", if device { "yes (CF_VERIFIED_DEVICE)" } else { "no" });
|
println!(
|
||||||
|
" device trusted: {}",
|
||||||
|
if device {
|
||||||
|
"yes (CF_VERIFIED_DEVICE)"
|
||||||
|
} else {
|
||||||
|
"no"
|
||||||
|
}
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,7 +407,11 @@ pub fn print_response_with_opts(resp: &Response, action: Option<&str>, opts: &Ou
|
|||||||
let count = list.len();
|
let count = list.len();
|
||||||
println!(
|
println!(
|
||||||
"{}",
|
"{}",
|
||||||
color::bold(&format!("{} frame{}", count, if count == 1 { "" } else { "s" }))
|
color::bold(&format!(
|
||||||
|
"{} frame{}",
|
||||||
|
count,
|
||||||
|
if count == 1 { "" } else { "s" }
|
||||||
|
))
|
||||||
);
|
);
|
||||||
for f in list {
|
for f in list {
|
||||||
let idx = f.get("index").and_then(|v| v.as_i64()).unwrap_or(0);
|
let idx = f.get("index").and_then(|v| v.as_i64()).unwrap_or(0);
|
||||||
|
|||||||
Reference in New Issue
Block a user