diff --git a/docs/src/api/params.md b/docs/src/api/params.md index e974d13001..8aadbbe078 100644 --- a/docs/src/api/params.md +++ b/docs/src/api/params.md @@ -524,13 +524,16 @@ Does not enforce fixed viewport, allows resizing window in the headed mode. ## context-option-clientCertificates - `clientCertificates` <[Array]<[Object]>> - `url` <[string]> Glob pattern to match the URLs that the certificate is valid for. - - `certs` <[Array]<[Object]>> List of client certificates to be used. - - `certPath` ?<[string]> Path to the file with the certificate in PEM format. - - `keyPath` ?<[string]> Path to the file with the private key in PEM format. - - `pfxPath` ?<[string]> Path to the PFX or PKCS12 encoded private key and certificate chain. - - `passphrase` ?<[string]> Passphrase for the private key (PEM or PFX). + - `certPath` ?<[string]> Path to the file with the certificate in PEM format. + - `keyPath` ?<[string]> Path to the file with the private key in PEM format. + - `pfxPath` ?<[string]> Path to the PFX or PKCS12 encoded private key and certificate chain. + - `passphrase` ?<[string]> Passphrase for the private key (PEM or PFX). -An array of client certificates to be used. Each certificate object must have both `certPath` and `keyPath` or a single `pfxPath` to load the client certificate. Optionally, `passphrase` property should be provided if the private key is encrypted. If the certificate is valid only for specific URLs, the `url` property should be provided with a glob pattern to match the URLs that the certificate is valid for. +TLS Client Authentication allows the server to request a client certificate and verify it. + +**Details** + +An array of client certificates to be used. Each certificate object must have both `certPath` and `keyPath` or a single `pfxPath` to load the client certificate. Optionally, `passphrase` property should be provided if the certficiate is encrypted. If the certificate is valid only for specific URLs, the `url` property should be provided with a glob pattern to match the URLs that the certificate is valid for. :::note Using Client Certificates in combination with Proxy Servers is not supported. diff --git a/docs/src/test-api/class-testoptions.md b/docs/src/test-api/class-testoptions.md index d862287f13..67a6339d50 100644 --- a/docs/src/test-api/class-testoptions.md +++ b/docs/src/test-api/class-testoptions.md @@ -148,22 +148,14 @@ export default defineConfig({ import { defineConfig } from '@playwright/test'; export default defineConfig({ - projects: [ - { - name: 'Microsoft Edge', - use: { - ...devices['Desktop Edge'], - clientCertificates: [{ - url: 'https://example.com/**', - certs: [{ - certPath: './cert.pem', - keyPath: './key.pem', - passphrase: 'mysecretpassword', - }], - }], - }, - }, - ] + use: { + clientCertificates: [{ + url: 'https://example.com', + certPath: './cert.pem', + keyPath: './key.pem', + passphrase: 'mysecretpassword', + }], + }, }); ``` diff --git a/packages/playwright-core/src/client/browserContext.ts b/packages/playwright-core/src/client/browserContext.ts index 5100b0db25..8a1cd7309d 100644 --- a/packages/playwright-core/src/client/browserContext.ts +++ b/packages/playwright-core/src/client/browserContext.ts @@ -550,20 +550,16 @@ function toAcceptDownloadsProtocol(acceptDownloads?: boolean) { return 'deny'; } -export async function toClientCertificatesProtocol(clientCertificates?: BrowserContextOptions['clientCertificates']): Promise { - if (!clientCertificates) +export async function toClientCertificatesProtocol(certs?: BrowserContextOptions['clientCertificates']): Promise { + if (!certs) return undefined; - return await Promise.all(clientCertificates.map(async clientCertificate => { + return await Promise.all(certs.map(async cert => { return { - url: clientCertificate.url, - certs: await Promise.all(clientCertificate.certs.map(async cert => { - return { - cert: cert.certPath ? await fs.promises.readFile(cert.certPath) : undefined, - key: cert.keyPath ? await fs.promises.readFile(cert.keyPath) : undefined, - pfx: cert.pfxPath ? await fs.promises.readFile(cert.pfxPath) : undefined, - passphrase: cert.passphrase, - }; - })) + url: cert.url, + cert: cert.certPath ? await fs.promises.readFile(cert.certPath) : undefined, + key: cert.keyPath ? await fs.promises.readFile(cert.keyPath) : undefined, + pfx: cert.pfxPath ? await fs.promises.readFile(cert.pfxPath) : undefined, + passphrase: cert.passphrase, }; })); } diff --git a/packages/playwright-core/src/client/types.ts b/packages/playwright-core/src/client/types.ts index 4c6f23d977..0e9b0e9a38 100644 --- a/packages/playwright-core/src/client/types.ts +++ b/packages/playwright-core/src/client/types.ts @@ -49,12 +49,10 @@ export const kLifecycleEvents: Set = new Set(['load', 'domconten export type ClientCertificate = { url: string; - certs: { - certPath?: string; - keyPath?: string; - pfxPath?: string; - passphrase?: string; - }[]; + certPath?: string; + keyPath?: string; + pfxPath?: string; + passphrase?: string; }; export type BrowserContextOptions = Omit & { diff --git a/packages/playwright-core/src/protocol/validator.ts b/packages/playwright-core/src/protocol/validator.ts index 9fa68b7bb9..42b5354e8f 100644 --- a/packages/playwright-core/src/protocol/validator.ts +++ b/packages/playwright-core/src/protocol/validator.ts @@ -338,12 +338,10 @@ scheme.PlaywrightNewRequestParams = tObject({ extraHTTPHeaders: tOptional(tArray(tType('NameValue'))), clientCertificates: tOptional(tArray(tObject({ url: tString, - certs: tArray(tObject({ - cert: tOptional(tBinary), - key: tOptional(tBinary), - passphrase: tOptional(tString), - pfx: tOptional(tBinary), - })), + cert: tOptional(tBinary), + key: tOptional(tBinary), + passphrase: tOptional(tString), + pfx: tOptional(tBinary), }))), httpCredentials: tOptional(tObject({ username: tString, @@ -548,12 +546,10 @@ scheme.BrowserTypeLaunchPersistentContextParams = tObject({ ignoreHTTPSErrors: tOptional(tBoolean), clientCertificates: tOptional(tArray(tObject({ url: tString, - certs: tArray(tObject({ - cert: tOptional(tBinary), - key: tOptional(tBinary), - passphrase: tOptional(tString), - pfx: tOptional(tBinary), - })), + cert: tOptional(tBinary), + key: tOptional(tBinary), + passphrase: tOptional(tString), + pfx: tOptional(tBinary), }))), javaScriptEnabled: tOptional(tBoolean), bypassCSP: tOptional(tBoolean), @@ -636,12 +632,10 @@ scheme.BrowserNewContextParams = tObject({ ignoreHTTPSErrors: tOptional(tBoolean), clientCertificates: tOptional(tArray(tObject({ url: tString, - certs: tArray(tObject({ - cert: tOptional(tBinary), - key: tOptional(tBinary), - passphrase: tOptional(tString), - pfx: tOptional(tBinary), - })), + cert: tOptional(tBinary), + key: tOptional(tBinary), + passphrase: tOptional(tString), + pfx: tOptional(tBinary), }))), javaScriptEnabled: tOptional(tBoolean), bypassCSP: tOptional(tBoolean), @@ -707,12 +701,10 @@ scheme.BrowserNewContextForReuseParams = tObject({ ignoreHTTPSErrors: tOptional(tBoolean), clientCertificates: tOptional(tArray(tObject({ url: tString, - certs: tArray(tObject({ - cert: tOptional(tBinary), - key: tOptional(tBinary), - passphrase: tOptional(tString), - pfx: tOptional(tBinary), - })), + cert: tOptional(tBinary), + key: tOptional(tBinary), + passphrase: tOptional(tString), + pfx: tOptional(tBinary), }))), javaScriptEnabled: tOptional(tBoolean), bypassCSP: tOptional(tBoolean), @@ -2527,12 +2519,10 @@ scheme.AndroidDeviceLaunchBrowserParams = tObject({ ignoreHTTPSErrors: tOptional(tBoolean), clientCertificates: tOptional(tArray(tObject({ url: tString, - certs: tArray(tObject({ - cert: tOptional(tBinary), - key: tOptional(tBinary), - passphrase: tOptional(tString), - pfx: tOptional(tBinary), - })), + cert: tOptional(tBinary), + key: tOptional(tBinary), + passphrase: tOptional(tString), + pfx: tOptional(tBinary), }))), javaScriptEnabled: tOptional(tBoolean), bypassCSP: tOptional(tBoolean), diff --git a/packages/playwright-core/src/server/browserContext.ts b/packages/playwright-core/src/server/browserContext.ts index 45ecfb4dc1..056bc9e1b4 100644 --- a/packages/playwright-core/src/server/browserContext.ts +++ b/packages/playwright-core/src/server/browserContext.ts @@ -725,21 +725,17 @@ export function verifyGeolocation(geolocation?: types.Geolocation) { export function verifyClientCertificates(clientCertificates?: channels.BrowserNewContextParams['clientCertificates']) { if (!clientCertificates) return; - for (const { url, certs } of clientCertificates) { - if (!url) + for (const cert of clientCertificates) { + if (!cert.url) throw new Error(`clientCertificates.url is required`); - if (!certs.length) - throw new Error('No certs specified for url: ' + url); - for (const cert of certs) { - if (!cert.cert && !cert.key && !cert.passphrase && !cert.pfx) - throw new Error('None of cert, key, passphrase or pfx is specified'); - if (cert.cert && !cert.key) - throw new Error('cert is specified without key'); - if (!cert.cert && cert.key) - throw new Error('key is specified without cert'); - if (cert.pfx && (cert.cert || cert.key)) - throw new Error('pfx is specified together with cert, key or passphrase'); - } + if (!cert.cert && !cert.key && !cert.passphrase && !cert.pfx) + throw new Error('None of cert, key, passphrase or pfx is specified'); + if (cert.cert && !cert.key) + throw new Error('cert is specified without key'); + if (!cert.cert && cert.key) + throw new Error('key is specified without cert'); + if (cert.pfx && (cert.cert || cert.key)) + throw new Error('pfx is specified together with cert, key or passphrase'); } } diff --git a/packages/playwright-core/src/server/socksClientCertificatesInterceptor.ts b/packages/playwright-core/src/server/socksClientCertificatesInterceptor.ts index 5b3759bd11..04770cd528 100644 --- a/packages/playwright-core/src/server/socksClientCertificatesInterceptor.ts +++ b/packages/playwright-core/src/server/socksClientCertificatesInterceptor.ts @@ -196,15 +196,13 @@ export function clientCertificatesToTLSOptions( key: [] as { pem: Buffer, passphrase?: string }[], cert: [] as Buffer[], }; - for (const { certs } of matchingCerts) { - for (const cert of certs) { - if (cert.cert) - tlsOptions.cert.push(cert.cert); - if (cert.key) - tlsOptions.key.push({ pem: cert.key, passphrase: cert.passphrase }); - if (cert.pfx) - tlsOptions.pfx.push({ buf: cert.pfx, passphrase: cert.passphrase }); - } + for (const cert of matchingCerts) { + if (cert.cert) + tlsOptions.cert.push(cert.cert); + if (cert.key) + tlsOptions.key.push({ pem: cert.key, passphrase: cert.passphrase }); + if (cert.pfx) + tlsOptions.pfx.push({ buf: cert.pfx, passphrase: cert.passphrase }); } return tlsOptions; } diff --git a/packages/playwright-core/types/types.d.ts b/packages/playwright-core/types/types.d.ts index 2d9b0e6a6d..0d38ca7c2b 100644 --- a/packages/playwright-core/types/types.d.ts +++ b/packages/playwright-core/types/types.d.ts @@ -13166,9 +13166,13 @@ export interface BrowserType { chromiumSandbox?: boolean; /** + * TLS Client Authentication allows the server to request a client certificate and verify it. + * + * **Details** + * * An array of client certificates to be used. Each certificate object must have both `certPath` and `keyPath` or a * single `pfxPath` to load the client certificate. Optionally, `passphrase` property should be provided if the - * private key is encrypted. If the certificate is valid only for specific URLs, the `url` property should be provided + * certficiate is encrypted. If the certificate is valid only for specific URLs, the `url` property should be provided * with a glob pattern to match the URLs that the certificate is valid for. * * **NOTE** Using Client Certificates in combination with Proxy Servers is not supported. @@ -13183,29 +13187,24 @@ export interface BrowserType { url: string; /** - * List of client certificates to be used. + * Path to the file with the certificate in PEM format. */ - certs: Array<{ - /** - * Path to the file with the certificate in PEM format. - */ - certPath?: string; + certPath?: string; - /** - * Path to the file with the private key in PEM format. - */ - keyPath?: string; + /** + * Path to the file with the private key in PEM format. + */ + keyPath?: string; - /** - * Path to the PFX or PKCS12 encoded private key and certificate chain. - */ - pfxPath?: string; + /** + * Path to the PFX or PKCS12 encoded private key and certificate chain. + */ + pfxPath?: string; - /** - * Passphrase for the private key (PEM or PFX). - */ - passphrase?: string; - }>; + /** + * Passphrase for the private key (PEM or PFX). + */ + passphrase?: string; }>; /** @@ -15578,9 +15577,13 @@ export interface APIRequest { baseURL?: string; /** + * TLS Client Authentication allows the server to request a client certificate and verify it. + * + * **Details** + * * An array of client certificates to be used. Each certificate object must have both `certPath` and `keyPath` or a * single `pfxPath` to load the client certificate. Optionally, `passphrase` property should be provided if the - * private key is encrypted. If the certificate is valid only for specific URLs, the `url` property should be provided + * certficiate is encrypted. If the certificate is valid only for specific URLs, the `url` property should be provided * with a glob pattern to match the URLs that the certificate is valid for. * * **NOTE** Using Client Certificates in combination with Proxy Servers is not supported. @@ -15595,29 +15598,24 @@ export interface APIRequest { url: string; /** - * List of client certificates to be used. + * Path to the file with the certificate in PEM format. */ - certs: Array<{ - /** - * Path to the file with the certificate in PEM format. - */ - certPath?: string; + certPath?: string; - /** - * Path to the file with the private key in PEM format. - */ - keyPath?: string; + /** + * Path to the file with the private key in PEM format. + */ + keyPath?: string; - /** - * Path to the PFX or PKCS12 encoded private key and certificate chain. - */ - pfxPath?: string; + /** + * Path to the PFX or PKCS12 encoded private key and certificate chain. + */ + pfxPath?: string; - /** - * Passphrase for the private key (PEM or PFX). - */ - passphrase?: string; - }>; + /** + * Passphrase for the private key (PEM or PFX). + */ + passphrase?: string; }>; /** @@ -16772,9 +16770,13 @@ export interface Browser extends EventEmitter { bypassCSP?: boolean; /** + * TLS Client Authentication allows the server to request a client certificate and verify it. + * + * **Details** + * * An array of client certificates to be used. Each certificate object must have both `certPath` and `keyPath` or a * single `pfxPath` to load the client certificate. Optionally, `passphrase` property should be provided if the - * private key is encrypted. If the certificate is valid only for specific URLs, the `url` property should be provided + * certficiate is encrypted. If the certificate is valid only for specific URLs, the `url` property should be provided * with a glob pattern to match the URLs that the certificate is valid for. * * **NOTE** Using Client Certificates in combination with Proxy Servers is not supported. @@ -16789,29 +16791,24 @@ export interface Browser extends EventEmitter { url: string; /** - * List of client certificates to be used. + * Path to the file with the certificate in PEM format. */ - certs: Array<{ - /** - * Path to the file with the certificate in PEM format. - */ - certPath?: string; + certPath?: string; - /** - * Path to the file with the private key in PEM format. - */ - keyPath?: string; + /** + * Path to the file with the private key in PEM format. + */ + keyPath?: string; - /** - * Path to the PFX or PKCS12 encoded private key and certificate chain. - */ - pfxPath?: string; + /** + * Path to the PFX or PKCS12 encoded private key and certificate chain. + */ + pfxPath?: string; - /** - * Passphrase for the private key (PEM or PFX). - */ - passphrase?: string; - }>; + /** + * Passphrase for the private key (PEM or PFX). + */ + passphrase?: string; }>; /** @@ -20223,9 +20220,13 @@ export interface BrowserContextOptions { bypassCSP?: boolean; /** + * TLS Client Authentication allows the server to request a client certificate and verify it. + * + * **Details** + * * An array of client certificates to be used. Each certificate object must have both `certPath` and `keyPath` or a * single `pfxPath` to load the client certificate. Optionally, `passphrase` property should be provided if the - * private key is encrypted. If the certificate is valid only for specific URLs, the `url` property should be provided + * certficiate is encrypted. If the certificate is valid only for specific URLs, the `url` property should be provided * with a glob pattern to match the URLs that the certificate is valid for. * * **NOTE** Using Client Certificates in combination with Proxy Servers is not supported. @@ -20240,29 +20241,24 @@ export interface BrowserContextOptions { url: string; /** - * List of client certificates to be used. + * Path to the file with the certificate in PEM format. */ - certs: Array<{ - /** - * Path to the file with the certificate in PEM format. - */ - certPath?: string; + certPath?: string; - /** - * Path to the file with the private key in PEM format. - */ - keyPath?: string; + /** + * Path to the file with the private key in PEM format. + */ + keyPath?: string; - /** - * Path to the PFX or PKCS12 encoded private key and certificate chain. - */ - pfxPath?: string; + /** + * Path to the PFX or PKCS12 encoded private key and certificate chain. + */ + pfxPath?: string; - /** - * Passphrase for the private key (PEM or PFX). - */ - passphrase?: string; - }>; + /** + * Passphrase for the private key (PEM or PFX). + */ + passphrase?: string; }>; /** diff --git a/packages/playwright/src/index.ts b/packages/playwright/src/index.ts index 5685afb33b..9a159c984a 100644 --- a/packages/playwright/src/index.ts +++ b/packages/playwright/src/index.ts @@ -479,12 +479,10 @@ function resolveFileToConfig(file: string | undefined) { type ClientCertificates = NonNullable; function resolveClientCerticates(clientCertificates: ClientCertificates): ClientCertificates { - for (const { certs } of clientCertificates) { - for (const cert of certs) { - cert.certPath = resolveFileToConfig(cert.certPath); - cert.keyPath = resolveFileToConfig(cert.keyPath); - cert.pfxPath = resolveFileToConfig(cert.pfxPath); - } + for (const cert of clientCertificates) { + cert.certPath = resolveFileToConfig(cert.certPath); + cert.keyPath = resolveFileToConfig(cert.keyPath); + cert.pfxPath = resolveFileToConfig(cert.pfxPath); } return clientCertificates; } diff --git a/packages/playwright/types/test.d.ts b/packages/playwright/types/test.d.ts index 9d1d053a70..e7cee67b65 100644 --- a/packages/playwright/types/test.d.ts +++ b/packages/playwright/types/test.d.ts @@ -5202,9 +5202,13 @@ export interface PlaywrightTestOptions { */ colorScheme: ColorScheme; /** + * TLS Client Authentication allows the server to request a client certificate and verify it. + * + * **Details** + * * An array of client certificates to be used. Each certificate object must have both `certPath` and `keyPath` or a * single `pfxPath` to load the client certificate. Optionally, `passphrase` property should be provided if the - * private key is encrypted. If the certificate is valid only for specific URLs, the `url` property should be provided + * certficiate is encrypted. If the certificate is valid only for specific URLs, the `url` property should be provided * with a glob pattern to match the URLs that the certificate is valid for. * * **NOTE** Using Client Certificates in combination with Proxy Servers is not supported. @@ -5219,22 +5223,14 @@ export interface PlaywrightTestOptions { * import { defineConfig } from '@playwright/test'; * * export default defineConfig({ - * projects: [ - * { - * name: 'Microsoft Edge', - * use: { - * ...devices['Desktop Edge'], - * clientCertificates: [{ - * url: 'https://example.com/**', - * certs: [{ - * certPath: './cert.pem', - * keyPath: './key.pem', - * passphrase: 'mysecretpassword', - * }], - * }], - * }, - * }, - * ] + * use: { + * clientCertificates: [{ + * url: 'https://example.com', + * certPath: './cert.pem', + * keyPath: './key.pem', + * passphrase: 'mysecretpassword', + * }], + * }, * }); * ``` * diff --git a/packages/protocol/src/channels.ts b/packages/protocol/src/channels.ts index f36b711b5b..00ce092d2c 100644 --- a/packages/protocol/src/channels.ts +++ b/packages/protocol/src/channels.ts @@ -583,12 +583,10 @@ export type PlaywrightNewRequestParams = { extraHTTPHeaders?: NameValue[], clientCertificates?: { url: string, - certs: { - cert?: Binary, - key?: Binary, - passphrase?: string, - pfx?: Binary, - }[], + cert?: Binary, + key?: Binary, + passphrase?: string, + pfx?: Binary, }[], httpCredentials?: { username: string, @@ -616,12 +614,10 @@ export type PlaywrightNewRequestOptions = { extraHTTPHeaders?: NameValue[], clientCertificates?: { url: string, - certs: { - cert?: Binary, - key?: Binary, - passphrase?: string, - pfx?: Binary, - }[], + cert?: Binary, + key?: Binary, + passphrase?: string, + pfx?: Binary, }[], httpCredentials?: { username: string, @@ -969,12 +965,10 @@ export type BrowserTypeLaunchPersistentContextParams = { ignoreHTTPSErrors?: boolean, clientCertificates?: { url: string, - certs: { - cert?: Binary, - key?: Binary, - passphrase?: string, - pfx?: Binary, - }[], + cert?: Binary, + key?: Binary, + passphrase?: string, + pfx?: Binary, }[], javaScriptEnabled?: boolean, bypassCSP?: boolean, @@ -1051,12 +1045,10 @@ export type BrowserTypeLaunchPersistentContextOptions = { ignoreHTTPSErrors?: boolean, clientCertificates?: { url: string, - certs: { - cert?: Binary, - key?: Binary, - passphrase?: string, - pfx?: Binary, - }[], + cert?: Binary, + key?: Binary, + passphrase?: string, + pfx?: Binary, }[], javaScriptEnabled?: boolean, bypassCSP?: boolean, @@ -1168,12 +1160,10 @@ export type BrowserNewContextParams = { ignoreHTTPSErrors?: boolean, clientCertificates?: { url: string, - certs: { - cert?: Binary, - key?: Binary, - passphrase?: string, - pfx?: Binary, - }[], + cert?: Binary, + key?: Binary, + passphrase?: string, + pfx?: Binary, }[], javaScriptEnabled?: boolean, bypassCSP?: boolean, @@ -1236,12 +1226,10 @@ export type BrowserNewContextOptions = { ignoreHTTPSErrors?: boolean, clientCertificates?: { url: string, - certs: { - cert?: Binary, - key?: Binary, - passphrase?: string, - pfx?: Binary, - }[], + cert?: Binary, + key?: Binary, + passphrase?: string, + pfx?: Binary, }[], javaScriptEnabled?: boolean, bypassCSP?: boolean, @@ -1307,12 +1295,10 @@ export type BrowserNewContextForReuseParams = { ignoreHTTPSErrors?: boolean, clientCertificates?: { url: string, - certs: { - cert?: Binary, - key?: Binary, - passphrase?: string, - pfx?: Binary, - }[], + cert?: Binary, + key?: Binary, + passphrase?: string, + pfx?: Binary, }[], javaScriptEnabled?: boolean, bypassCSP?: boolean, @@ -1375,12 +1361,10 @@ export type BrowserNewContextForReuseOptions = { ignoreHTTPSErrors?: boolean, clientCertificates?: { url: string, - certs: { - cert?: Binary, - key?: Binary, - passphrase?: string, - pfx?: Binary, - }[], + cert?: Binary, + key?: Binary, + passphrase?: string, + pfx?: Binary, }[], javaScriptEnabled?: boolean, bypassCSP?: boolean, @@ -4583,12 +4567,10 @@ export type AndroidDeviceLaunchBrowserParams = { ignoreHTTPSErrors?: boolean, clientCertificates?: { url: string, - certs: { - cert?: Binary, - key?: Binary, - passphrase?: string, - pfx?: Binary, - }[], + cert?: Binary, + key?: Binary, + passphrase?: string, + pfx?: Binary, }[], javaScriptEnabled?: boolean, bypassCSP?: boolean, @@ -4649,12 +4631,10 @@ export type AndroidDeviceLaunchBrowserOptions = { ignoreHTTPSErrors?: boolean, clientCertificates?: { url: string, - certs: { - cert?: Binary, - key?: Binary, - passphrase?: string, - pfx?: Binary, - }[], + cert?: Binary, + key?: Binary, + passphrase?: string, + pfx?: Binary, }[], javaScriptEnabled?: boolean, bypassCSP?: boolean, diff --git a/packages/protocol/src/protocol.yml b/packages/protocol/src/protocol.yml index a6b91ce3c0..7e986cd96a 100644 --- a/packages/protocol/src/protocol.yml +++ b/packages/protocol/src/protocol.yml @@ -446,15 +446,10 @@ ContextOptions: type: object properties: url: string - certs: - type: array - items: - type: object - properties: - cert: binary? - key: binary? - passphrase: string? - pfx: binary? + cert: binary? + key: binary? + passphrase: string? + pfx: binary? javaScriptEnabled: boolean? bypassCSP: boolean? userAgent: string? @@ -701,15 +696,10 @@ Playwright: type: object properties: url: string - certs: - type: array - items: - type: object - properties: - cert: binary? - key: binary? - passphrase: string? - pfx: binary? + cert: binary? + key: binary? + passphrase: string? + pfx: binary? httpCredentials: type: object? properties: diff --git a/tests/library/client-certificates.spec.ts b/tests/library/client-certificates.spec.ts index 6de4da2c9b..fff370b595 100644 --- a/tests/library/client-certificates.spec.ts +++ b/tests/library/client-certificates.spec.ts @@ -79,27 +79,22 @@ test.skip(({ mode }) => mode !== 'default'); const kDummyFileName = __filename; const kValidationSubTests: [BrowserContextOptions, string][] = [ - [{ clientCertificates: [{ url: 'test', certs: [] }] }, 'No certs specified for url: test'], - [{ clientCertificates: [{ url: 'test', certs: [{}] }] }, 'None of cert, key, passphrase or pfx is specified'], + [{ clientCertificates: [{ url: 'test' }] }, 'None of cert, key, passphrase or pfx is specified'], [{ clientCertificates: [{ url: 'test', - certs: [{ - certPath: kDummyFileName, - keyPath: kDummyFileName, - pfxPath: kDummyFileName, - passphrase: kDummyFileName, - }] + certPath: kDummyFileName, + keyPath: kDummyFileName, + pfxPath: kDummyFileName, + passphrase: kDummyFileName, }] }, 'pfx is specified together with cert, key or passphrase'], [{ proxy: { server: 'http://localhost:8080' }, clientCertificates: [{ url: 'test', - certs: [{ - certPath: kDummyFileName, - keyPath: kDummyFileName, - }] + certPath: kDummyFileName, + keyPath: kDummyFileName, }] }, 'Cannot specify both proxy and clientCertificates'], ]; @@ -123,10 +118,8 @@ test.describe('fetch', () => { const request = await playwright.request.newContext({ clientCertificates: [{ url: server.PREFIX, - certs: [{ - certPath: asset('client-certificates/client/trusted/cert.pem'), - keyPath: asset('client-certificates/client/trusted/key.pem'), - }], + certPath: asset('client-certificates/client/trusted/cert.pem'), + keyPath: asset('client-certificates/client/trusted/key.pem'), }], }); const response = await request.get(server.PREFIX + '/one-style.html'); @@ -141,10 +134,8 @@ test.describe('fetch', () => { const request = await playwright.request.newContext({ clientCertificates: [{ url: serverURL, - certs: [{ - certPath: asset('client-certificates/client/self-signed/cert.pem'), - keyPath: asset('client-certificates/client/self-signed/key.pem'), - }], + certPath: asset('client-certificates/client/self-signed/cert.pem'), + keyPath: asset('client-certificates/client/self-signed/key.pem'), }], }); const response = await request.get(serverURL); @@ -159,10 +150,8 @@ test.describe('fetch', () => { const request = await playwright.request.newContext({ clientCertificates: [{ url: serverURL, - certs: [{ - certPath: asset('client-certificates/client/trusted/cert.pem'), - keyPath: asset('client-certificates/client/trusted/key.pem'), - }], + certPath: asset('client-certificates/client/trusted/cert.pem'), + keyPath: asset('client-certificates/client/trusted/key.pem'), }], }); const response = await request.get(serverURL); @@ -177,10 +166,8 @@ test.describe('fetch', () => { const request = await playwright.request.newContext({ clientCertificates: [{ url: serverURL, - certs: [{ - certPath: asset('client-certificates/client/trusted/cert.pem'), - keyPath: asset('client-certificates/client/trusted/key.pem'), - }], + certPath: asset('client-certificates/client/trusted/cert.pem'), + keyPath: asset('client-certificates/client/trusted/key.pem'), }], }); const page = await browser.newPage({ ignoreHTTPSErrors: true }); @@ -206,10 +193,8 @@ test.describe('browser', () => { const page = await browser.newPage({ clientCertificates: [{ url: server.PREFIX, - certs: [{ - certPath: asset('client-certificates/client/trusted/cert.pem'), - keyPath: asset('client-certificates/client/trusted/key.pem'), - }], + certPath: asset('client-certificates/client/trusted/cert.pem'), + keyPath: asset('client-certificates/client/trusted/key.pem'), }], }); await page.goto(server.PREFIX + '/one-style.html'); @@ -223,10 +208,8 @@ test.describe('browser', () => { const page = await browser.newPage({ clientCertificates: [{ url: 'https://not-matching.com', - certs: [{ - certPath: asset('client-certificates/client/trusted/cert.pem'), - keyPath: asset('client-certificates/client/trusted/key.pem'), - }], + certPath: asset('client-certificates/client/trusted/cert.pem'), + keyPath: asset('client-certificates/client/trusted/key.pem'), }], }); await page.goto(serverURL); @@ -239,10 +222,8 @@ test.describe('browser', () => { const page = await browser.newPage({ clientCertificates: [{ url: serverURL, - certs: [{ - certPath: asset('client-certificates/client/self-signed/cert.pem'), - keyPath: asset('client-certificates/client/self-signed/key.pem'), - }], + certPath: asset('client-certificates/client/self-signed/cert.pem'), + keyPath: asset('client-certificates/client/self-signed/key.pem'), }], }); await page.goto(serverURL); @@ -255,10 +236,8 @@ test.describe('browser', () => { const page = await browser.newPage({ clientCertificates: [{ url: serverURL, - certs: [{ - certPath: asset('client-certificates/client/trusted/cert.pem'), - keyPath: asset('client-certificates/client/trusted/key.pem'), - }], + certPath: asset('client-certificates/client/trusted/cert.pem'), + keyPath: asset('client-certificates/client/trusted/key.pem'), }], }); await page.goto(serverURL); @@ -270,10 +249,8 @@ test.describe('browser', () => { const page = await browser.newPage({ clientCertificates: [{ url: 'https://just-there-that-the-client-certificates-proxy-server-is-getting-launched.com', - certs: [{ - certPath: asset('client-certificates/client/trusted/cert.pem'), - keyPath: asset('client-certificates/client/trusted/key.pem'), - }], + certPath: asset('client-certificates/client/trusted/cert.pem'), + keyPath: asset('client-certificates/client/trusted/key.pem'), }], }); await page.goto(browserName === 'webkit' && platform === 'darwin' ? httpsServer.EMPTY_PAGE.replace('localhost', 'local.playwright') : httpsServer.EMPTY_PAGE); @@ -293,10 +270,8 @@ test.describe('browser', () => { const { page } = await launchPersistent({ clientCertificates: [{ url: serverURL, - certs: [{ - certPath: asset('client-certificates/client/trusted/cert.pem'), - keyPath: asset('client-certificates/client/trusted/key.pem'), - }], + certPath: asset('client-certificates/client/trusted/cert.pem'), + keyPath: asset('client-certificates/client/trusted/key.pem'), }], }); await page.goto(serverURL);