refactor: use net::CanonicalCookie::IsDomainMatch()
(#46748)
* refactor: use net::CanonicalCookie::IsDomainMatch() Previously we had been rolling our own impl * test: add pattern-matching tests for our cookie API
This commit is contained in:
parent
06a99d6770
commit
74c4ae0b55
2 changed files with 160 additions and 23 deletions
|
@ -102,27 +102,6 @@ namespace electron::api {
|
|||
|
||||
namespace {
|
||||
|
||||
// Returns whether |domain| matches |filter|.
|
||||
bool MatchesDomain(std::string filter, const std::string& domain) {
|
||||
// Add a leading '.' character to the filter domain if it doesn't exist.
|
||||
if (net::cookie_util::DomainIsHostOnly(filter))
|
||||
filter.insert(0, ".");
|
||||
|
||||
std::string sub_domain(domain);
|
||||
// Strip any leading '.' character from the input cookie domain.
|
||||
if (!net::cookie_util::DomainIsHostOnly(sub_domain))
|
||||
sub_domain = sub_domain.substr(1);
|
||||
|
||||
// Now check whether the domain argument is a subdomain of the filter domain.
|
||||
for (sub_domain.insert(0, "."); sub_domain.length() >= filter.length();) {
|
||||
if (sub_domain == filter)
|
||||
return true;
|
||||
const size_t next_dot = sub_domain.find('.', 1); // Skip over leading dot.
|
||||
sub_domain.erase(0, next_dot);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns whether |cookie| matches |filter|.
|
||||
bool MatchesCookie(const base::Value::Dict& filter,
|
||||
const net::CanonicalCookie& cookie) {
|
||||
|
@ -131,8 +110,7 @@ bool MatchesCookie(const base::Value::Dict& filter,
|
|||
return false;
|
||||
if ((str = filter.FindString("path")) && *str != cookie.Path())
|
||||
return false;
|
||||
if ((str = filter.FindString("domain")) &&
|
||||
!MatchesDomain(*str, cookie.Domain()))
|
||||
if ((str = filter.FindString("domain")) && !cookie.IsDomainMatch(*str))
|
||||
return false;
|
||||
std::optional<bool> secure_filter = filter.FindBool("secure");
|
||||
if (secure_filter && *secure_filter != cookie.SecureAttribute())
|
||||
|
|
|
@ -260,6 +260,165 @@ describe('session module', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('domain matching', () => {
|
||||
let testSession: Electron.Session;
|
||||
|
||||
beforeEach(() => {
|
||||
testSession = session.fromPartition(`cookies-domain-test-${Date.now()}`);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
// Clear cookies after each test
|
||||
await testSession.clearStorageData({ storages: ['cookies'] });
|
||||
});
|
||||
|
||||
// Helper to set a cookie and then test if it's retrieved with a domain filter
|
||||
async function testDomainMatching (setCookieOpts: Electron.CookiesSetDetails,
|
||||
domain: string,
|
||||
expectMatch: boolean) {
|
||||
await testSession.cookies.set(setCookieOpts);
|
||||
const cookies = await testSession.cookies.get({ domain });
|
||||
|
||||
if (expectMatch) {
|
||||
expect(cookies).to.have.lengthOf(1);
|
||||
expect(cookies[0].name).to.equal(setCookieOpts.name);
|
||||
expect(cookies[0].value).to.equal(setCookieOpts.value);
|
||||
} else {
|
||||
expect(cookies).to.have.lengthOf(0);
|
||||
}
|
||||
}
|
||||
|
||||
it('should match exact domain', async () => {
|
||||
await testDomainMatching({
|
||||
url: 'http://example.com',
|
||||
name: 'exactMatch',
|
||||
value: 'value1',
|
||||
domain: 'example.com'
|
||||
}, 'example.com', true);
|
||||
});
|
||||
|
||||
it('should match subdomain when filter has leading dot', async () => {
|
||||
await testDomainMatching({
|
||||
url: 'http://sub.example.com',
|
||||
name: 'subdomainMatch',
|
||||
value: 'value2',
|
||||
domain: '.example.com'
|
||||
}, 'sub.example.com', true);
|
||||
});
|
||||
|
||||
it('should match subdomain when filter has no leading dot (host-only normalization)', async () => {
|
||||
await testDomainMatching({
|
||||
url: 'http://sub.example.com',
|
||||
name: 'hostOnlyNormalization',
|
||||
value: 'value3',
|
||||
domain: 'example.com'
|
||||
}, 'sub.example.com', true);
|
||||
});
|
||||
|
||||
it('should not match unrelated domain', async () => {
|
||||
await testDomainMatching({
|
||||
url: 'http://example.com',
|
||||
name: 'noMatch',
|
||||
value: 'value4',
|
||||
domain: 'example.com'
|
||||
}, 'other.com', false);
|
||||
});
|
||||
|
||||
it('should match domain with a leading dot in both cookie and filter', async () => {
|
||||
await testDomainMatching({
|
||||
url: 'http://example.com',
|
||||
name: 'leadingDotBoth',
|
||||
value: 'value5',
|
||||
domain: '.example.com'
|
||||
}, '.example.com', true);
|
||||
});
|
||||
|
||||
it('should handle case insensitivity in domain', async () => {
|
||||
await testDomainMatching({
|
||||
url: 'http://example.com',
|
||||
name: 'caseInsensitive',
|
||||
value: 'value7',
|
||||
domain: 'Example.com'
|
||||
}, 'example.com', true);
|
||||
});
|
||||
|
||||
it('should handle IP address matching', async () => {
|
||||
await testDomainMatching({
|
||||
url: 'http://127.0.0.1',
|
||||
name: 'ipExactMatch',
|
||||
value: 'value8',
|
||||
domain: '127.0.0.1'
|
||||
}, '127.0.0.1', true);
|
||||
});
|
||||
|
||||
it('should not match different IP addresses', async () => {
|
||||
await testDomainMatching({
|
||||
url: 'http://127.0.0.1',
|
||||
name: 'ipMismatch',
|
||||
value: 'value9',
|
||||
domain: '127.0.0.1'
|
||||
}, '127.0.0.2', false);
|
||||
});
|
||||
|
||||
it('should handle complex subdomain matching properly', async () => {
|
||||
// Set a cookie with domain .example.com
|
||||
await testSession.cookies.set({
|
||||
url: 'http://a.b.example.com',
|
||||
name: 'complexSubdomain',
|
||||
value: 'value11',
|
||||
domain: '.example.com'
|
||||
});
|
||||
|
||||
// This should match the cookie
|
||||
const cookies1 = await testSession.cookies.get({ domain: 'a.b.example.com' });
|
||||
expect(cookies1).to.have.lengthOf(1);
|
||||
expect(cookies1[0].name).to.equal('complexSubdomain');
|
||||
|
||||
// This should also match
|
||||
const cookies2 = await testSession.cookies.get({ domain: 'b.example.com' });
|
||||
expect(cookies2).to.have.lengthOf(1);
|
||||
|
||||
// This should also match
|
||||
const cookies3 = await testSession.cookies.get({ domain: 'example.com' });
|
||||
expect(cookies3).to.have.lengthOf(1);
|
||||
|
||||
// This should not match
|
||||
const cookies4 = await testSession.cookies.get({ domain: 'otherexample.com' });
|
||||
expect(cookies4).to.have.lengthOf(0);
|
||||
});
|
||||
|
||||
it('should handle multiple cookies with different domains', async () => {
|
||||
// Set two cookies with different domains
|
||||
await testSession.cookies.set({
|
||||
url: 'http://example.com',
|
||||
name: 'cookie1',
|
||||
value: 'domain1',
|
||||
domain: 'example.com'
|
||||
});
|
||||
|
||||
await testSession.cookies.set({
|
||||
url: 'http://other.com',
|
||||
name: 'cookie2',
|
||||
value: 'domain2',
|
||||
domain: 'other.com'
|
||||
});
|
||||
|
||||
// Filter for the first domain
|
||||
const cookies1 = await testSession.cookies.get({ domain: 'example.com' });
|
||||
expect(cookies1).to.have.lengthOf(1);
|
||||
expect(cookies1[0].name).to.equal('cookie1');
|
||||
|
||||
// Filter for the second domain
|
||||
const cookies2 = await testSession.cookies.get({ domain: 'other.com' });
|
||||
expect(cookies2).to.have.lengthOf(1);
|
||||
expect(cookies2[0].name).to.equal('cookie2');
|
||||
|
||||
// Get all cookies
|
||||
const allCookies = await testSession.cookies.get({});
|
||||
expect(allCookies).to.have.lengthOf(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ses.clearStorageData(options)', () => {
|
||||
afterEach(closeAllWindows);
|
||||
it('clears localstorage data', async () => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue