Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 85 additions & 10 deletions rust/src/providers/ollama/cookies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,16 +153,35 @@ pub(super) fn resolve_browser_cookie_header(
return Ok(Some(cached.cookie_header));
}

match crate::providers::browser_cookies_for_domain(OLLAMA_COOKIE_DOMAIN) {
Ok(cookies) => {
let url = Url::parse("https://ollama.com/settings")
.map_err(|e| ProviderError::Other(e.to_string()))?;
Ok(ollama_cookie_header_for_url(&cookies, &url)
.filter(|h| has_recognized_ollama_session_cookie(h)))
}
Err(ProviderError::NoCookies) => Ok(None),
Err(err) => Err(err),
}
let url = Url::parse("https://ollama.com/settings")
.map_err(|e| ProviderError::Other(e.to_string()))?;

// Upstream Win-CodexBar #426: the generic `browser_cookies_for_domain` helper
// stops at the FIRST installed browser that has *any* cookies for the domain,
// even if those cookies are stale/irrelevant (e.g. a consent or CDN cookie left
// behind in Chrome/Edge from a one-off visit) and don't include a recognized
// Ollama session cookie. That starves out a later browser (often Brave) that
// actually holds the logged-in session. Walk every detected browser ourselves
// and keep going until one yields a header with a recognized session cookie.
use crate::browser::cookies::CookieExtractor;
use crate::browser::detection::BrowserDetector;

let cookie_sets = BrowserDetector::detect_all()
.into_iter()
.filter_map(|browser| {
CookieExtractor::extract_for_domain(&browser, OLLAMA_COOKIE_DOMAIN).ok()
});
Ok(first_recognized_cookie_header(cookie_sets, &url))
}

/// Return the header for the first cookie set (in order) that contains a
/// recognized Ollama session cookie for `url`, skipping sets that decrypt
/// fine but carry no usable session (see `resolve_browser_cookie_header`).
fn first_recognized_cookie_header(
mut cookie_sets: impl Iterator<Item = Vec<Cookie>>,
url: &Url,
) -> Option<String> {
cookie_sets.find_map(|cookies| ollama_cookie_header_for_url(&cookies, url))
}

pub(super) fn should_attach_ollama_cookie(url: &Url) -> bool {
Expand Down Expand Up @@ -285,6 +304,62 @@ mod tests {
);
}

#[test]
fn first_recognized_cookie_header_skips_browsers_without_a_session_cookie() {
// Regression for #426: an earlier-priority browser (e.g. Chrome/Edge)
// may hold only stale/irrelevant ollama.com cookies (analytics,
// consent) with no session cookie at all. The old
// `browser_cookies_for_domain` helper stopped at that first non-empty
// result and never reached a later browser (e.g. Brave) that actually
// holds the logged-in session.
let irrelevant_only = vec![Cookie {
name: "aid".to_string(),
value: "device-id".to_string(),
domain: "ollama.com".to_string(),
path: "/".to_string(),
expires: None,
is_secure: true,
is_http_only: false,
}];
let real_session = vec![Cookie {
name: OLLAMA_SESSION_COOKIE_NAME.to_string(),
value: "abc123".to_string(),
domain: "ollama.com".to_string(),
path: "/".to_string(),
expires: None,
is_secure: true,
is_http_only: true,
}];

let url = Url::parse("https://ollama.com/settings").unwrap();
let header =
first_recognized_cookie_header(vec![irrelevant_only, real_session].into_iter(), &url);

assert_eq!(
header.as_deref(),
Some("__Secure-session=abc123"),
"should skip the first (irrelevant) cookie set and use the second (real session)"
);
}

#[test]
fn first_recognized_cookie_header_none_when_no_set_has_a_session_cookie() {
let only_irrelevant = vec![Cookie {
name: "aid".to_string(),
value: "device-id".to_string(),
domain: "ollama.com".to_string(),
path: "/".to_string(),
expires: None,
is_secure: true,
is_http_only: false,
}];

let url = Url::parse("https://ollama.com/settings").unwrap();
let header = first_recognized_cookie_header(vec![only_irrelevant].into_iter(), &url);

assert_eq!(header, None);
}

#[test]
fn ignores_empty_cookie_input() {
assert_eq!(normalize_cookie_header(" "), None);
Expand Down
Loading