Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: client certificates fixes (#34873) and URL pattern support #34939

Open
wants to merge 10 commits into
base: main
Choose a base branch
from

Conversation

mmacvicar
Copy link

Bug Fixes

Fix for #34873

  • Makes ALPN use a proxy if available and the secureContext for the origin.
  • Enable lookup fixtures in places that were missing, like the client certificates socks proxy.
  • Private domains now work if available thorugh a proxy and using client certificates.

Support for patterns in clientCertificates

For example:

@mmacvicar mmacvicar changed the title Client certificates fixes (#34873) and URL pattern support feat: client certificates fixes (#34873) and URL pattern support Feb 27, 2025

This comment has been minimized.

@@ -357,3 +431,181 @@ export function rewriteOpenSSLErrorIfNeeded(error: Error): Error {
'You could probably modernize the certificate by following the steps at https://github.com/nodejs/node/issues/40672#issuecomment-1243648223',
].join('\n'));
}

/*
Pattern is a pattern that matches a URL. Based on the Chromium
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe consider using URLPattern as it becomes a standard.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, also it solves the parsing which I really wanted to avoid. I tried it and ended up discarding it, there was something I was missing I cannot remember now. Let me check that and get back.

Copy link
Author

@mmacvicar mmacvicar Feb 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So! URLPattern would do the job nicely for this and most cases where playwright needs to do url matching. However, it has been available in Node.js current (23.x) only since last month, on the browser is also early and experimental, it is still missing in firefox and people is discussing APIs to match url lists due to performance concerns.

Said that, there is an alternative which is ditching [.] in favor of {.}?, which would make it work as a subset of URLPattern instead of following the chromium patterns. That would make sense if the project is looking forward to adopt URLPattern broadly, in the meantime I opted for the chromium patterns as 1) it was the only I knew was used for this, it pops out when people search about auto selecting client certs, 2) it is fairly simple to implement.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For reference: #34915

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please stay away from URLPattern.

@mmacvicar
Copy link
Author

@microsoft-github-policy-service agree

@mmacvicar mmacvicar force-pushed the fix_client_certs_private_domains branch from 1da0b4e to bfe6e65 Compare February 27, 2025 14:48

This comment has been minimized.

This comment has been minimized.

@yury-s yury-s requested a review from mxschmitt February 28, 2025 21:56
@mmacvicar mmacvicar force-pushed the fix_client_certs_private_domains branch from 0223cc7 to 87c3cb9 Compare March 1, 2025 03:03
Copy link
Contributor

github-actions bot commented Mar 1, 2025

Test results for "tests 1"

5 flaky ⚠️ [firefox-page] › tests/page/page-evaluate.spec.ts:403:3 › should throw for too deep reference chain @firefox-ubuntu-22.04-node18
⚠️ [playwright-test] › tests/ui-mode-test-output.spec.ts:80:5 › should show console messages for test @macos-latest-node18-1
⚠️ [playwright-test] › tests/ui-mode-trace.spec.ts:341:5 › should work behind reverse proxy @ubuntu-latest-node18-1
⚠️ [webkit-page] › tests/page/page-screenshot.spec.ts:345:5 › page screenshot › should work while navigating @webkit-ubuntu-22.04-node18
⚠️ [playwright-test] › tests/ui-mode-test-watch.spec.ts:145:5 › should watch all @windows-latest-node18-1

38672 passed, 793 skipped
✔️✔️✔️

Merge workflow run.

@@ -549,7 +549,7 @@ Does not enforce fixed viewport, allows resizing window in the headed mode.

## context-option-clientCertificates
- `clientCertificates` <[Array]<[Object]>>
- `origin` <[string]> Exact origin that the certificate is valid for. Origin includes `https` protocol, a hostname and optionally a port.
- `origin` <[string]> Exact origin or chromium enterprise policy style URL pattern that the certificate is valid for. Origin includes `https` protocol, a hostname and optionally a port.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding yet another pattern will definitely slow things down. If you absolutely need a pattern, use regex.

@@ -39,10 +39,15 @@ function loadDummyServerCertsIfNeeded() {
dummyServerTlsOptions = { key, cert };
}

type ALPNCacheOptions = {
socket?: stream.Duplex | undefined;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we would drop | undefined and use ? notation for both properties unless this would be a refactoring that needs to update all the call sites.

}
}

// Only used for fixtures
type SocksProxyConnectionOptions = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are in the server non-user-facing code, you can introduce a property fooForTest if you need it.

this.internal = new stream.Duplex({
read: () => {},
write: (data, encoding, callback) => {
this.socksProxy._socksProxy.sendSocketData({ uid: this.uid, data });
callback();
}
});
this.socksProxy.alpnCache.get(rewriteToLocalhostIfNeeded(this.host), this.port, alpnProtocolChosenByServer => {
const secureContext = this.socksProxy.secureContextForOrigin(new URL(`https://${this.host}:${this.port}`).origin);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't do more than one thing in a single PR. Your changes look reasonable, but reviewing them together is a bit hard, especially since they touch user-facing API. Please split it into fixes for those!

Copy link
Author

@mmacvicar mmacvicar Mar 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are essentially 2 things here + things that were needed just to test them. First, there is the fix to #34873 which straightens the ALPN behavior, this one can be indeed isolated. Although, it does fix more than one thing, for example, apart from not using the proxy to figure the protocol, it did not used the secure context either. As they touched the same parts and required some changes to be tested, if separated I could make a couple of dependants PRs.

Then there is the patterns, that one is very isolated with the only problem that in order to be tested it required changes done in the previous part. I just tried to avoid having dependant PRs.

Would that split make sense of you would go even smaller? I could do one addressing all of the ALPNCache issues, just ensuring it reaches out hosts in the same way the client would and another one for the patterns depending on the first.

Copy link
Member

@pavelfeldman pavelfeldman Mar 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if separated I could make a couple of dependants PRs.

I'd very much prefer that.

Would that split make sense of you would go even smaller?

I need to understand the PR in order to review it. Making it about one thing helps keep track of things. I don't have a question of "Ok, this line changed, which of the 4 things this PR does did it change for?". Does not need to be a PR per line, but proper scoping would minimize the amount of questions and friction during the review.

@@ -357,3 +431,181 @@ export function rewriteOpenSSLErrorIfNeeded(error: Error): Error {
'You could probably modernize the certificate by following the steps at https://github.com/nodejs/node/issues/40672#issuecomment-1243648223',
].join('\n'));
}

/*
Pattern is a pattern that matches a URL. Based on the Chromium
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please stay away from URLPattern.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants