chore: rewrite error for unsupported PFX errors
This commit is contained in:
parent
71e614dc5a
commit
2adc16bca2
|
|
@ -40,7 +40,7 @@ import { Tracing } from './trace/recorder/tracing';
|
||||||
import type * as types from './types';
|
import type * as types from './types';
|
||||||
import type { HeadersArray, ProxySettings } from './types';
|
import type { HeadersArray, ProxySettings } from './types';
|
||||||
import { kMaxCookieExpiresDateInSeconds } from './network';
|
import { kMaxCookieExpiresDateInSeconds } from './network';
|
||||||
import { clientCertificatesToTLSOptions } from './socksClientCertificatesInterceptor';
|
import { clientCertificatesToTLSOptions, rewriteOpenSSLErrorIfNeeded } from './socksClientCertificatesInterceptor';
|
||||||
|
|
||||||
type FetchRequestOptions = {
|
type FetchRequestOptions = {
|
||||||
userAgent: string;
|
userAgent: string;
|
||||||
|
|
@ -452,7 +452,7 @@ export abstract class APIRequestContext extends SdkObject {
|
||||||
body.on('data', chunk => chunks.push(chunk));
|
body.on('data', chunk => chunks.push(chunk));
|
||||||
body.on('end', notifyBodyFinished);
|
body.on('end', notifyBodyFinished);
|
||||||
});
|
});
|
||||||
request.on('error', reject);
|
request.on('error', error => reject(rewriteOpenSSLErrorIfNeeded(error)));
|
||||||
|
|
||||||
const disposeListener = () => {
|
const disposeListener = () => {
|
||||||
reject(new Error('Request context disposed.'));
|
reject(new Error('Request context disposed.'));
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import fs from 'fs';
|
||||||
import tls from 'tls';
|
import tls from 'tls';
|
||||||
import stream from 'stream';
|
import stream from 'stream';
|
||||||
import { createSocket, createTLSSocket } from '../utils/happy-eyeballs';
|
import { createSocket, createTLSSocket } from '../utils/happy-eyeballs';
|
||||||
import { ManualPromise } from '../utils';
|
import { ManualPromise, rewriteErrorMessage } from '../utils';
|
||||||
import type { SocksSocketClosedPayload, SocksSocketDataPayload, SocksSocketRequestedPayload } from '../common/socksProxy';
|
import type { SocksSocketClosedPayload, SocksSocketDataPayload, SocksSocketRequestedPayload } from '../common/socksProxy';
|
||||||
import { SocksProxy } from '../common/socksProxy';
|
import { SocksProxy } from '../common/socksProxy';
|
||||||
import type * as channels from '@protocol/channels';
|
import type * as channels from '@protocol/channels';
|
||||||
|
|
@ -150,8 +150,9 @@ class SocksProxyConnection {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleError = (error: Error) => {
|
const handleError = (error: Error) => {
|
||||||
debugLogger.log('client-certificates', `error when connecting to target: ${error.message}`);
|
error = rewriteOpenSSLErrorIfNeeded(error);
|
||||||
const responseBody = 'Playwright client-certificate error: ' + error.message;
|
debugLogger.log('client-certificates', `error when connecting to target: ${error.message.replaceAll('\n', ' ')}`);
|
||||||
|
const responseBody = 'Playwright client-certificate error: ' + error.message.replaceAll('\n', '<br>');
|
||||||
if (internalTLS?.alpnProtocol === 'h2') {
|
if (internalTLS?.alpnProtocol === 'h2') {
|
||||||
// This method is available only in Node.js 20+
|
// This method is available only in Node.js 20+
|
||||||
if ('performServerHandshake' in http2) {
|
if ('performServerHandshake' in http2) {
|
||||||
|
|
@ -297,3 +298,17 @@ export function clientCertificatesToTLSOptions(
|
||||||
function rewriteToLocalhostIfNeeded(host: string): string {
|
function rewriteToLocalhostIfNeeded(host: string): string {
|
||||||
return host === 'local.playwright' ? 'localhost' : host;
|
return host === 'local.playwright' ? 'localhost' : host;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function rewriteOpenSSLErrorIfNeeded(error: Error): Error {
|
||||||
|
if (error.message !== 'unsupported')
|
||||||
|
return error;
|
||||||
|
return rewriteErrorMessage(error, [
|
||||||
|
'Unsupported TLS certificate.',
|
||||||
|
'Node.js (OpenSSL) has deprecated certifiates with the security algorithm of the given client-certifiate.',
|
||||||
|
'To fix this issue, you need to modernise the certificates by running the following command:',
|
||||||
|
'openssl pkcs12 -in oldPfxFile.pfx -nodes -legacy -out decryptedPfxFile.tmp',
|
||||||
|
'openssl pkcs12 -in decryptedPfxFile.tmp -export -out newPfxFile.pfx',
|
||||||
|
'Then, you can use the newPfxFile.pfx in your client-certificates configuration.',
|
||||||
|
'For more information, please refer to OpenSSL: https://github.com/openssl/openssl/blob/master/README-PROVIDERS.md#the-legacy-provider',
|
||||||
|
].join('\n'));
|
||||||
|
}
|
||||||
BIN
tests/assets/client-certificates/client/trusted/cert-legacy.pfx
Normal file
BIN
tests/assets/client-certificates/client/trusted/cert-legacy.pfx
Normal file
Binary file not shown.
|
|
@ -169,6 +169,51 @@ test.describe('fetch', () => {
|
||||||
await request.dispose();
|
await request.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('pass with trusted client certificates in pfx format', async ({ playwright, startCCServer, asset }) => {
|
||||||
|
const serverURL = await startCCServer();
|
||||||
|
const request = await playwright.request.newContext({
|
||||||
|
ignoreHTTPSErrors: true,
|
||||||
|
clientCertificates: [{
|
||||||
|
origin: new URL(serverURL).origin,
|
||||||
|
pfxPath: asset('client-certificates/client/trusted/cert.pfx'),
|
||||||
|
passphrase: 'secure'
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
const response = await request.get(serverURL);
|
||||||
|
expect(response.url()).toBe(serverURL);
|
||||||
|
expect(response.status()).toBe(200);
|
||||||
|
expect(await response.text()).toContain('Hello Alice, your certificate was issued by localhost!');
|
||||||
|
await request.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should throw a http error if the pfx passphrase is incorect', async ({ playwright, startCCServer, asset, browserName }) => {
|
||||||
|
const serverURL = await startCCServer({ useFakeLocalhost: browserName === 'webkit' && process.platform === 'darwin' });
|
||||||
|
const request = await playwright.request.newContext({
|
||||||
|
ignoreHTTPSErrors: true,
|
||||||
|
clientCertificates: [{
|
||||||
|
origin: new URL(serverURL).origin,
|
||||||
|
pfxPath: asset('client-certificates/client/trusted/cert.pfx'),
|
||||||
|
passphrase: 'this-password-is-incorrect'
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
await expect(request.get(serverURL)).rejects.toThrow('mac verify failure');
|
||||||
|
await request.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should pass with matching certificates in legacy pfx format', async ({ playwright, startCCServer, asset, browserName }) => {
|
||||||
|
const serverURL = await startCCServer({ useFakeLocalhost: browserName === 'webkit' && process.platform === 'darwin' });
|
||||||
|
const request = await playwright.request.newContext({
|
||||||
|
ignoreHTTPSErrors: true,
|
||||||
|
clientCertificates: [{
|
||||||
|
origin: new URL(serverURL).origin,
|
||||||
|
pfxPath: asset('client-certificates/client/trusted/cert-legacy.pfx'),
|
||||||
|
passphrase: 'secure'
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
await expect(request.get(serverURL)).rejects.toThrow('Unsupported TLS certificate');
|
||||||
|
await request.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
test('should work in the browser with request interception', async ({ browser, playwright, startCCServer, asset }) => {
|
test('should work in the browser with request interception', async ({ browser, playwright, startCCServer, asset }) => {
|
||||||
const serverURL = await startCCServer();
|
const serverURL = await startCCServer();
|
||||||
const request = await playwright.request.newContext({
|
const request = await playwright.request.newContext({
|
||||||
|
|
@ -272,6 +317,21 @@ test.describe('browser', () => {
|
||||||
await page.close();
|
await page.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should pass with matching certificates in legacy pfx format', async ({ browser, startCCServer, asset, browserName }) => {
|
||||||
|
const serverURL = await startCCServer({ useFakeLocalhost: browserName === 'webkit' && process.platform === 'darwin' });
|
||||||
|
const page = await browser.newPage({
|
||||||
|
ignoreHTTPSErrors: true,
|
||||||
|
clientCertificates: [{
|
||||||
|
origin: new URL(serverURL).origin,
|
||||||
|
pfxPath: asset('client-certificates/client/trusted/cert-legacy.pfx'),
|
||||||
|
passphrase: 'secure'
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
await page.goto(serverURL);
|
||||||
|
await expect(page.getByText('Unsupported TLS certificate.')).toBeVisible();
|
||||||
|
await page.close();
|
||||||
|
});
|
||||||
|
|
||||||
test('should throw a http error if the pfx passphrase is incorect', async ({ browser, startCCServer, asset, browserName }) => {
|
test('should throw a http error if the pfx passphrase is incorect', async ({ browser, startCCServer, asset, browserName }) => {
|
||||||
const serverURL = await startCCServer({ useFakeLocalhost: browserName === 'webkit' && process.platform === 'darwin' });
|
const serverURL = await startCCServer({ useFakeLocalhost: browserName === 'webkit' && process.platform === 'darwin' });
|
||||||
const page = await browser.newPage({
|
const page = await browser.newPage({
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue