Add CLI flags for cookie URL, domain, path, httpOnly, secure, and expires (#266)
* Add CLI flags for cookie URL, domain, path, httpOnly, secure, and expires Extends the `cookies set` command to support setting cookies with additional parameters before loading a page, solving authentication workflows where cookies need to be set for different domains. **Key changes:** - Added CLI flags: `--url`, `--domain`, `--path`, `--httpOnly`, `--secure`, `--sameSite`, `--expires` - Added comprehensive test coverage for all new flags and combinations - Updated help documentation with usage examples - No daemon changes needed - it already supported these parameters **Example usage:** ```bash agent-browser cookies set session_id "abc123" --url https://app.example.com --httpOnly --secure ``` This allows setting cookies for a URL before opening the page, eliminating the need for workarounds in cross-domain authentication scenarios. Fixes #261 * Update lock * Fix compilation error
This commit is contained in:
Generated
+1
-1
@@ -4,7 +4,7 @@ version = 4
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agent-browser"
|
name = "agent-browser"
|
||||||
version = "0.6.0"
|
version = "0.7.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dirs",
|
"dirs",
|
||||||
"libc",
|
"libc",
|
||||||
|
|||||||
+191
-3
@@ -485,14 +485,106 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result<Value, ParseError
|
|||||||
"set" => {
|
"set" => {
|
||||||
let name = rest.get(1).ok_or_else(|| ParseError::MissingArguments {
|
let name = rest.get(1).ok_or_else(|| ParseError::MissingArguments {
|
||||||
context: "cookies set".to_string(),
|
context: "cookies set".to_string(),
|
||||||
usage: "cookies set <name> <value>",
|
usage: "cookies set <name> <value> [--url <url>] [--domain <domain>] [--path <path>] [--httpOnly] [--secure] [--sameSite <Strict|Lax|None>] [--expires <timestamp>]",
|
||||||
})?;
|
})?;
|
||||||
let value = rest.get(2).ok_or_else(|| ParseError::MissingArguments {
|
let value = rest.get(2).ok_or_else(|| ParseError::MissingArguments {
|
||||||
context: "cookies set".to_string(),
|
context: "cookies set".to_string(),
|
||||||
usage: "cookies set <name> <value>",
|
usage: "cookies set <name> <value> [--url <url>] [--domain <domain>] [--path <path>] [--httpOnly] [--secure] [--sameSite <Strict|Lax|None>] [--expires <timestamp>]",
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
let mut cookie = json!({ "name": name, "value": value });
|
||||||
|
|
||||||
|
// Parse optional flags
|
||||||
|
let mut i = 3;
|
||||||
|
while i < rest.len() {
|
||||||
|
match rest[i] {
|
||||||
|
"--url" => {
|
||||||
|
if let Some(url) = rest.get(i + 1) {
|
||||||
|
cookie["url"] = json!(url);
|
||||||
|
i += 2;
|
||||||
|
} else {
|
||||||
|
return Err(ParseError::MissingArguments {
|
||||||
|
context: "cookies set --url".to_string(),
|
||||||
|
usage: "--url <url>",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"--domain" => {
|
||||||
|
if let Some(domain) = rest.get(i + 1) {
|
||||||
|
cookie["domain"] = json!(domain);
|
||||||
|
i += 2;
|
||||||
|
} else {
|
||||||
|
return Err(ParseError::MissingArguments {
|
||||||
|
context: "cookies set --domain".to_string(),
|
||||||
|
usage: "--domain <domain>",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"--path" => {
|
||||||
|
if let Some(path) = rest.get(i + 1) {
|
||||||
|
cookie["path"] = json!(path);
|
||||||
|
i += 2;
|
||||||
|
} else {
|
||||||
|
return Err(ParseError::MissingArguments {
|
||||||
|
context: "cookies set --path".to_string(),
|
||||||
|
usage: "--path <path>",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"--httpOnly" => {
|
||||||
|
cookie["httpOnly"] = json!(true);
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
"--secure" => {
|
||||||
|
cookie["secure"] = json!(true);
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
"--sameSite" => {
|
||||||
|
if let Some(same_site) = rest.get(i + 1) {
|
||||||
|
// Validate sameSite value
|
||||||
|
if *same_site == "Strict" || *same_site == "Lax" || *same_site == "None" {
|
||||||
|
cookie["sameSite"] = json!(same_site);
|
||||||
|
i += 2;
|
||||||
|
} else {
|
||||||
|
return Err(ParseError::MissingArguments {
|
||||||
|
context: "cookies set --sameSite".to_string(),
|
||||||
|
usage: "--sameSite <Strict|Lax|None>",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(ParseError::MissingArguments {
|
||||||
|
context: "cookies set --sameSite".to_string(),
|
||||||
|
usage: "--sameSite <Strict|Lax|None>",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"--expires" => {
|
||||||
|
if let Some(expires_str) = rest.get(i + 1) {
|
||||||
|
if let Ok(expires) = expires_str.parse::<i64>() {
|
||||||
|
cookie["expires"] = json!(expires);
|
||||||
|
i += 2;
|
||||||
|
} else {
|
||||||
|
return Err(ParseError::MissingArguments {
|
||||||
|
context: "cookies set --expires".to_string(),
|
||||||
|
usage: "--expires <timestamp>",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(ParseError::MissingArguments {
|
||||||
|
context: "cookies set --expires".to_string(),
|
||||||
|
usage: "--expires <timestamp>",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// Unknown flag, skip it (or could error)
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(
|
Ok(
|
||||||
json!({ "id": id, "action": "cookies_set", "cookies": [{ "name": name, "value": value }] }),
|
json!({ "id": id, "action": "cookies_set", "cookies": [cookie] }),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
"clear" => Ok(json!({ "id": id, "action": "cookies_clear" })),
|
"clear" => Ok(json!({ "id": id, "action": "cookies_clear" })),
|
||||||
@@ -1254,6 +1346,102 @@ mod tests {
|
|||||||
assert_eq!(cmd["action"], "cookies_clear");
|
assert_eq!(cmd["action"], "cookies_clear");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cookies_set_with_url() {
|
||||||
|
let cmd = parse_command(&args("cookies set mycookie myvalue --url https://example.com"), &default_flags()).unwrap();
|
||||||
|
assert_eq!(cmd["action"], "cookies_set");
|
||||||
|
assert_eq!(cmd["cookies"][0]["name"], "mycookie");
|
||||||
|
assert_eq!(cmd["cookies"][0]["value"], "myvalue");
|
||||||
|
assert_eq!(cmd["cookies"][0]["url"], "https://example.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cookies_set_with_domain() {
|
||||||
|
let cmd = parse_command(&args("cookies set mycookie myvalue --domain example.com"), &default_flags()).unwrap();
|
||||||
|
assert_eq!(cmd["action"], "cookies_set");
|
||||||
|
assert_eq!(cmd["cookies"][0]["name"], "mycookie");
|
||||||
|
assert_eq!(cmd["cookies"][0]["value"], "myvalue");
|
||||||
|
assert_eq!(cmd["cookies"][0]["domain"], "example.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cookies_set_with_path() {
|
||||||
|
let cmd = parse_command(&args("cookies set mycookie myvalue --path /api"), &default_flags()).unwrap();
|
||||||
|
assert_eq!(cmd["action"], "cookies_set");
|
||||||
|
assert_eq!(cmd["cookies"][0]["name"], "mycookie");
|
||||||
|
assert_eq!(cmd["cookies"][0]["value"], "myvalue");
|
||||||
|
assert_eq!(cmd["cookies"][0]["path"], "/api");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cookies_set_with_httponly() {
|
||||||
|
let cmd = parse_command(&args("cookies set mycookie myvalue --httpOnly"), &default_flags()).unwrap();
|
||||||
|
assert_eq!(cmd["action"], "cookies_set");
|
||||||
|
assert_eq!(cmd["cookies"][0]["name"], "mycookie");
|
||||||
|
assert_eq!(cmd["cookies"][0]["value"], "myvalue");
|
||||||
|
assert_eq!(cmd["cookies"][0]["httpOnly"], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cookies_set_with_secure() {
|
||||||
|
let cmd = parse_command(&args("cookies set mycookie myvalue --secure"), &default_flags()).unwrap();
|
||||||
|
assert_eq!(cmd["action"], "cookies_set");
|
||||||
|
assert_eq!(cmd["cookies"][0]["name"], "mycookie");
|
||||||
|
assert_eq!(cmd["cookies"][0]["value"], "myvalue");
|
||||||
|
assert_eq!(cmd["cookies"][0]["secure"], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cookies_set_with_samesite() {
|
||||||
|
let cmd = parse_command(&args("cookies set mycookie myvalue --sameSite Strict"), &default_flags()).unwrap();
|
||||||
|
assert_eq!(cmd["action"], "cookies_set");
|
||||||
|
assert_eq!(cmd["cookies"][0]["name"], "mycookie");
|
||||||
|
assert_eq!(cmd["cookies"][0]["value"], "myvalue");
|
||||||
|
assert_eq!(cmd["cookies"][0]["sameSite"], "Strict");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cookies_set_with_expires() {
|
||||||
|
let cmd = parse_command(&args("cookies set mycookie myvalue --expires 1234567890"), &default_flags()).unwrap();
|
||||||
|
assert_eq!(cmd["action"], "cookies_set");
|
||||||
|
assert_eq!(cmd["cookies"][0]["name"], "mycookie");
|
||||||
|
assert_eq!(cmd["cookies"][0]["value"], "myvalue");
|
||||||
|
assert_eq!(cmd["cookies"][0]["expires"], 1234567890);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cookies_set_with_multiple_flags() {
|
||||||
|
let cmd = parse_command(&args("cookies set mycookie myvalue --url https://example.com --httpOnly --secure --sameSite Lax"), &default_flags()).unwrap();
|
||||||
|
assert_eq!(cmd["action"], "cookies_set");
|
||||||
|
assert_eq!(cmd["cookies"][0]["name"], "mycookie");
|
||||||
|
assert_eq!(cmd["cookies"][0]["value"], "myvalue");
|
||||||
|
assert_eq!(cmd["cookies"][0]["url"], "https://example.com");
|
||||||
|
assert_eq!(cmd["cookies"][0]["httpOnly"], true);
|
||||||
|
assert_eq!(cmd["cookies"][0]["secure"], true);
|
||||||
|
assert_eq!(cmd["cookies"][0]["sameSite"], "Lax");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cookies_set_with_all_flags() {
|
||||||
|
let cmd = parse_command(&args("cookies set mycookie myvalue --url https://example.com --domain example.com --path /api --httpOnly --secure --sameSite None --expires 9999999999"), &default_flags()).unwrap();
|
||||||
|
assert_eq!(cmd["action"], "cookies_set");
|
||||||
|
assert_eq!(cmd["cookies"][0]["name"], "mycookie");
|
||||||
|
assert_eq!(cmd["cookies"][0]["value"], "myvalue");
|
||||||
|
assert_eq!(cmd["cookies"][0]["url"], "https://example.com");
|
||||||
|
assert_eq!(cmd["cookies"][0]["domain"], "example.com");
|
||||||
|
assert_eq!(cmd["cookies"][0]["path"], "/api");
|
||||||
|
assert_eq!(cmd["cookies"][0]["httpOnly"], true);
|
||||||
|
assert_eq!(cmd["cookies"][0]["secure"], true);
|
||||||
|
assert_eq!(cmd["cookies"][0]["sameSite"], "None");
|
||||||
|
assert_eq!(cmd["cookies"][0]["expires"], 9999999999i64);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cookies_set_invalid_samesite() {
|
||||||
|
let result = parse_command(&args("cookies set mycookie myvalue --sameSite Invalid"), &default_flags());
|
||||||
|
assert!(result.is_err());
|
||||||
|
}
|
||||||
|
|
||||||
// === Storage Tests ===
|
// === Storage Tests ===
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
+34
-6
@@ -1082,18 +1082,46 @@ Usage: agent-browser cookies [operation] [args]
|
|||||||
Manage browser cookies for the current context.
|
Manage browser cookies for the current context.
|
||||||
|
|
||||||
Operations:
|
Operations:
|
||||||
get Get all cookies (default)
|
get Get all cookies (default)
|
||||||
set <name> <value> Set a cookie
|
set <name> <value> [options] Set a cookie with optional properties
|
||||||
clear Clear all cookies
|
clear Clear all cookies
|
||||||
|
|
||||||
|
Cookie Set Options:
|
||||||
|
--url <url> URL for the cookie (allows setting before page load)
|
||||||
|
--domain <domain> Cookie domain (e.g., ".example.com")
|
||||||
|
--path <path> Cookie path (e.g., "/api")
|
||||||
|
--httpOnly Set HttpOnly flag (prevents JavaScript access)
|
||||||
|
--secure Set Secure flag (HTTPS only)
|
||||||
|
--sameSite <Strict|Lax|None> SameSite policy
|
||||||
|
--expires <timestamp> Expiration time (Unix timestamp in seconds)
|
||||||
|
|
||||||
|
Note: If --url, --domain, and --path are all omitted, the cookie will be set
|
||||||
|
for the current page URL.
|
||||||
|
|
||||||
Global Options:
|
Global Options:
|
||||||
--json Output as JSON
|
--json Output as JSON
|
||||||
--session <name> Use specific session
|
--session <name> Use specific session
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
agent-browser cookies
|
# Simple cookie for current page
|
||||||
agent-browser cookies get
|
|
||||||
agent-browser cookies set session_id "abc123"
|
agent-browser cookies set session_id "abc123"
|
||||||
|
|
||||||
|
# Set cookie for a URL before loading it (useful for authentication)
|
||||||
|
agent-browser cookies set session_id "abc123" --url https://app.example.com
|
||||||
|
|
||||||
|
# Set secure, httpOnly cookie with domain and path
|
||||||
|
agent-browser cookies set auth_token "xyz789" --domain example.com --path /api --httpOnly --secure
|
||||||
|
|
||||||
|
# Set cookie with SameSite policy
|
||||||
|
agent-browser cookies set tracking_consent "yes" --sameSite Strict
|
||||||
|
|
||||||
|
# Set cookie with expiration (Unix timestamp)
|
||||||
|
agent-browser cookies set temp_token "temp123" --expires 1735689600
|
||||||
|
|
||||||
|
# Get all cookies
|
||||||
|
agent-browser cookies
|
||||||
|
|
||||||
|
# Clear all cookies
|
||||||
agent-browser cookies clear
|
agent-browser cookies clear
|
||||||
"##
|
"##
|
||||||
}
|
}
|
||||||
@@ -1494,7 +1522,7 @@ Network: agent-browser network <action>
|
|||||||
requests [--clear] [--filter <pattern>]
|
requests [--clear] [--filter <pattern>]
|
||||||
|
|
||||||
Storage:
|
Storage:
|
||||||
cookies [get|set|clear] Manage cookies
|
cookies [get|set|clear] Manage cookies (set supports --url, --domain, --path, --httpOnly, --secure, --sameSite, --expires)
|
||||||
storage <local|session> Manage web storage
|
storage <local|session> Manage web storage
|
||||||
|
|
||||||
Tabs:
|
Tabs:
|
||||||
|
|||||||
Reference in New Issue
Block a user