slicc-cdp-client 1.41.21

Shared CDP connection for slicc-cdp CLIs
Documentation
#[test]
fn response_body_is_rechecked_after_late_redirect_metadata() {
    let mut cdp = pending(|message| {
        vec![
            json!({"method":"Network.responseReceivedExtraInfo","sessionId":"S","params":{"requestId":"R","statusCode":302,"headers":{"Location":redirect_url("seven")}}}),
            json!({"id":message["id"],"result":{"body":base64_encode(REDIRECT_MARKER.as_bytes()),"base64Encoded":true}}),
        ]
    });
    cdp.requests.insert("R".into(), false);
    assert!(cdp.call("Network.getResponseBody", json!({"requestId":"R"}), Some("S")).is_err());
}

#[test]
fn ordinary_source_reads_remain_readable() {
    let mut cdp = redirect_body_backend("ordinary source".into());
    cdp.absorb(json!({"method":"Runtime.executionContextCreated","sessionId":"S","params":{"context":{"id":1,"origin":"https://example.test","auxData":{"isDefault":true}}}}));
    cdp.absorb(json!({"method":"Debugger.scriptParsed","sessionId":"S","params":{"scriptId":"JS","url":"https://example.test/source","executionContextId":1}}));
    cdp.absorb(json!({"method":"CSS.styleSheetAdded","sessionId":"S","params":{"header":{"styleSheetId":"CSS","sourceURL":"https://example.test/source"}}}));
    for (method, params) in [
        ("CSS.getStyleSheetText", json!({"styleSheetId":"CSS"})),
        ("Debugger.getScriptSource", json!({"scriptId":"JS"})),
        ("Page.getResourceContent", json!({"frameId":"F","url":"https://example.test/source"})),
    ] {
        let result = cdp.call(method, params, Some("S")).unwrap();
        assert_eq!(result["text"], "ordinary source");
    }
}

#[test]
fn guard_session_redirect_taint_blocks_client_session_source_reads() {
    let mut cdp = redirect_body_backend(REDIRECT_MARKER.into());
    cdp.session_targets.insert("S".into(), "T".into());
    cdp.guards.insert("T".into(), "G".into());
    cdp.guard_sessions.insert("G".into());
    cdp.absorb(json!({"method":"Network.requestWillBeSent","sessionId":"G","params":{"requestId":"R","request":{"url":"https://example.test/source"}}}));
    cdp.absorb(json!({"method":"Network.responseReceivedExtraInfo","sessionId":"G","params":{"requestId":"R","headers":{"Location":redirect_url("seven")},"statusCode":302}}));
    cdp.absorb(json!({"method":"Runtime.executionContextCreated","sessionId":"S","params":{"context":{"id":1,"origin":"https://example.test","auxData":{"isDefault":true}}}}));
    cdp.absorb(json!({"method":"Debugger.scriptParsed","sessionId":"S","params":{"scriptId":"JS","url":"https://example.test/source#client-fragment","executionContextId":1}}));
    cdp.absorb(json!({"method":"CSS.styleSheetAdded","sessionId":"S","params":{"header":{"styleSheetId":"CSS","sourceURL":"https://example.test/source#client-fragment"}}}));
    cdp.guards.remove("T");
    for (method, params) in [
        ("CSS.getStyleSheetText", json!({"styleSheetId":"CSS"})),
        ("Debugger.getScriptSource", json!({"scriptId":"JS"})),
        ("Page.getResourceContent", json!({"url":"https://example.test/source#client-fragment","frameId":"FRAME"})),
    ] {
        let result = cdp.call(method, params, Some("S"));
        assert!(result.is_err(), "guard-only taint did not block {method}: {result:?}");
    }
}

#[test]
fn multiply_encoded_nested_urls_and_json_slashes_are_redacted() {
    for host in ["seven", "vault"] {
        let url = redirect_url(host);
        let mut encoded = url.bytes().map(|byte| match byte {
            b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'_' | b'.' | b'~' => char::from(byte).to_string(),
            _ => format!("%{byte:02X}"),
        }).collect::<String>();
        for _ in 0..4 {
            let input = format!("https://example.test/?next={encoded}&control=ordinary");
            let mut cdp = url_backend("about:blank");
            let result = cdp.after("Runtime.evaluate", &json!({}), Some("S"), json!({"text":input})).unwrap();
            let output = result["text"].as_str().unwrap();
            assert!(!output.contains(REDIRECT_MARKER), "{output}");
            assert!(output.contains("&control=ordinary"));
            encoded = encoded.replace('%', "%25");
        }
        let input = url.replace('/', "\\/");
        let mut cdp = url_backend("about:blank");
        let result = cdp.after("Runtime.evaluate", &json!({}), Some("S"), json!({"text":input})).unwrap();
        assert_eq!(result["text"], format!("https://{host}.sliccy.ai"));
    }
}