feat(firefox): support custom policies.json (#35926)

This commit is contained in:
Dmitry Gozman 2025-05-14 08:38:24 +00:00 committed by GitHub
parent 807f3c5a30
commit 191d912f20
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 202 additions and 4 deletions

View File

@ -1071,6 +1071,8 @@ Whether to run browser in headless mode. More details for
Firefox user preferences. Learn more about the Firefox user preferences at
[`about:config`](https://support.mozilla.org/en-US/kb/about-config-editor-firefox).
You can also provide a path to a custom [`policies.json` file](https://mozilla.github.io/policy-templates/) via `PLAYWRIGHT_FIREFOX_POLICIES_JSON` environment variable.
## csharp-java-browser-option-firefoxuserprefs
* langs: csharp, java
- `firefoxUserPrefs` <[Object]<[string], [any]>>
@ -1078,6 +1080,8 @@ Firefox user preferences. Learn more about the Firefox user preferences at
Firefox user preferences. Learn more about the Firefox user preferences at
[`about:config`](https://support.mozilla.org/en-US/kb/about-config-editor-firefox).
You can also provide a path to a custom [`policies.json` file](https://mozilla.github.io/policy-templates/) via `PLAYWRIGHT_FIREFOX_POLICIES_JSON` environment variable.
## browser-option-logger
* langs: js
- `logger` <[Logger]>

View File

@ -14899,6 +14899,9 @@ export interface BrowserType<Unused = {}> {
/**
* Firefox user preferences. Learn more about the Firefox user preferences at
* [`about:config`](https://support.mozilla.org/en-US/kb/about-config-editor-firefox).
*
* You can also provide a path to a custom [`policies.json` file](https://mozilla.github.io/policy-templates/) via
* `PLAYWRIGHT_FIREFOX_POLICIES_JSON` environment variable.
*/
firefoxUserPrefs?: { [key: string]: string|number|boolean; };
@ -15323,6 +15326,9 @@ export interface BrowserType<Unused = {}> {
/**
* Firefox user preferences. Learn more about the Firefox user preferences at
* [`about:config`](https://support.mozilla.org/en-US/kb/about-config-editor-firefox).
*
* You can also provide a path to a custom [`policies.json` file](https://mozilla.github.io/policy-templates/) via
* `PLAYWRIGHT_FIREFOX_POLICIES_JSON` environment variable.
*/
firefoxUserPrefs?: { [key: string]: string|number|boolean; };
@ -21730,6 +21736,9 @@ export interface LaunchOptions {
/**
* Firefox user preferences. Learn more about the Firefox user preferences at
* [`about:config`](https://support.mozilla.org/en-US/kb/about-config-editor-firefox).
*
* You can also provide a path to a custom [`policies.json` file](https://mozilla.github.io/policy-templates/) via
* `PLAYWRIGHT_FIREFOX_POLICIES_JSON` environment variable.
*/
firefoxUserPrefs?: { [key: string]: string|number|boolean; };

View File

@ -14899,6 +14899,9 @@ export interface BrowserType<Unused = {}> {
/**
* Firefox user preferences. Learn more about the Firefox user preferences at
* [`about:config`](https://support.mozilla.org/en-US/kb/about-config-editor-firefox).
*
* You can also provide a path to a custom [`policies.json` file](https://mozilla.github.io/policy-templates/) via
* `PLAYWRIGHT_FIREFOX_POLICIES_JSON` environment variable.
*/
firefoxUserPrefs?: { [key: string]: string|number|boolean; };
@ -15323,6 +15326,9 @@ export interface BrowserType<Unused = {}> {
/**
* Firefox user preferences. Learn more about the Firefox user preferences at
* [`about:config`](https://support.mozilla.org/en-US/kb/about-config-editor-firefox).
*
* You can also provide a path to a custom [`policies.json` file](https://mozilla.github.io/policy-templates/) via
* `PLAYWRIGHT_FIREFOX_POLICIES_JSON` environment variable.
*/
firefoxUserPrefs?: { [key: string]: string|number|boolean; };
@ -21730,6 +21736,9 @@ export interface LaunchOptions {
/**
* Firefox user preferences. Learn more about the Firefox user preferences at
* [`about:config`](https://support.mozilla.org/en-US/kb/about-config-editor-firefox).
*
* You can also provide a path to a custom [`policies.json` file](https://mozilla.github.io/policy-templates/) via
* `PLAYWRIGHT_FIREFOX_POLICIES_JSON` environment variable.
*/
firefoxUserPrefs?: { [key: string]: string|number|boolean; };

View File

@ -16,7 +16,7 @@ openssl req \
## Trusted client-certificate (server signed/valid)
```
```bash
mkdir -p client/trusted
# generate server-signed (valid) certifcate
openssl req \
@ -40,9 +40,39 @@ openssl x509 \
openssl pkcs12 -export -out client/trusted/cert.pfx -inkey client/trusted/key.pem -in client/trusted/cert.pem -passout pass:secure
```
## Trusted certificate for localhost (server signed/valid)
```bash
mkdir -p client/localhost
# generate server-signed (valid) certifcate
openssl req \
-newkey rsa:4096 \
-keyout client/localhost/localhost.key \
-out client/localhost/localhost.csr \
-nodes \
-days 365 \
-subj "/CN=localhost" \
-addext "subjectAltName=DNS:localhost,DNS:127.0.0.1"
# put extensions
echo "subjectAltName=DNS:localhost,DNS:127.0.0.1" > client/localhost/localhost.ext
# sign with server_cert.pem
openssl x509 \
-req \
-in client/localhost/localhost.csr \
-CA server/server_cert.pem \
-CAkey server/server_key.pem \
-set_serial 01 \
-out client/localhost/localhost.pem \
-days 365 \
-extfile client/localhost/localhost.ext
```
## Self-signed certificate (invalid)
```
```bash
mkdir -p client/self-signed
openssl req \
-newkey rsa:4096 \

View File

@ -0,0 +1,27 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIEizCCAnMCAQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0B
AQEFAAOCAg8AMIICCgKCAgEA3MsXKGgqi6ibh/9wSQOADbPj0rQWsA9DP3SmeOiH
w+m0e/oBKDf0Sp6wfAeYycpnDrBFDRNl6lJg8hVXkUaMwnojV5/hjD8mfAGZpUhK
/7b7EZdjMY1euJbelIJxvD+ZwdY5RNZWb5B4NtwYyrHJ985EauTkdTNM1kBMtUzj
k7CenE37MZwoxW0NQpvTX+MJMmhZynO2QYEP+MxNd51WJDcJv05J3pF0T1MbjXZn
liNTf5F7HTnMu4vMgEOTQIWtcMsP0h/4TdK714/iUaFpEPt28UcoLZPVc9Sn6iKF
rbqtUscMgMfYkqQ4Dz8+YxU8MSQ8c87Ux60MKpLCBHs5JB1R51zfceUrI//PhkXD
zacVpP90D1roAngb5ef7x6OIzxrpGNlOto0Rwa6YMLOTlTR9E9v24P+EmKEnGilT
ztSL26CGFuWAqyNyrJggem+anUDJa9ni3nZXI2YUYCYEyCORaedV8zkyPzB30/Qq
rwm48ITmXUvyEbUlVC8kU2c0q+FRsOZGKyMFFPTHGVuSFyQLftgKdARHeAdmRxfx
mMM+L7HprJNhSNvKrG+vNxnvXrY/6U4K7TyCTWaw5nG0fLZld7t/TX2vT747eE2H
4EomF3xxn8iSLM5IH7NCasKmoa+a7s1PSU+uNx6vOGuJm0vqT/G1JkiL/HVfACsI
5u0CAwEAAaAyMDAGCSqGSIb3DQEJDjEjMCEwHwYDVR0RBBgwFoIJbG9jYWxob3N0
ggkxMjcuMC4wLjEwDQYJKoZIhvcNAQELBQADggIBAKz5LKzuOQKjT9IJA/ltZxB4
As+G2EcA6CUTcW5OTfZLhXlSKFNtlVe/NIsvZRS95pFCkpp01OPmjN0x/hB9ti9+
2dbOKn3dXlCGIqGKMgh7Hzf4MowY3uOt/+DYY/zeD3Dj7MQELtt3y/ZDD2kcog1G
1XUDSD77ptpl08JrXDgzzU29930j5TONcwKx0cBknUXfpDkmVACC4l3h3OIA8bTh
YGM82bgbN9n2Pj7/bfO+ZD3JhlLkHko6bef2OEeUd7KXXEbG/D1TJnkzkjFC7LXp
X6gaN5UVz33HV5cZVhMi9KIZO1IA2W4i0tbD1+dFXzN9Ei+AijleI7oxrVdYoC2i
RKPDkO8oTc1ikjwXf6S0b60g+0QqabBsKcViRMpq1h6EWi28XycNfZLFBA9X67GU
tEY5JroiWlTPJrNAdcCynVu2sAZG7Hf6AI4SLIUAScTgQEPsi0FbrkWiBzTYrNwh
faYcb/Vd0OuudGehUoBq1YyJR76CVIcIEwkPLBzJ8xvMrolWZJBoCG4MG1C+m+u6
4815IvuMsUnOnYwgUK3pd9eCgdgZUWDMpb29OkGAj9Io3ZrrfJTqd27QcSYzqEQl
6PE5DflYqSABJRMcAV0xw6m012HKdgxKTK0QTdlLb8AP8s3G9uJ3RnQOMoJJWs5H
BiK08R0zxv88ctjSzYah
-----END CERTIFICATE REQUEST-----

View File

@ -0,0 +1 @@
subjectAltName=DNS:localhost,DNS:127.0.0.1

View File

@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
eH8L0+a3Lq6SZB1iV/r/6xVQlDJn
-----END PRIVATE KEY-----

View File

@ -0,0 +1,29 @@
-----BEGIN CERTIFICATE-----
MIIE6DCCAtCgAwIBAgIBATANBgkqhkiG9w0BAQsFADA2MRIwEAYDVQQDDAlsb2Nh
bGhvc3QxIDAeBgNVBAoMF0NsaWVudCBDZXJ0aWZpY2F0ZSBEZW1vMB4XDTI1MDUw
NjE4MDg0M1oXDTI2MDUwNjE4MDg0M1owFDESMBAGA1UEAwwJbG9jYWxob3N0MIIC
IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA3MsXKGgqi6ibh/9wSQOADbPj
0rQWsA9DP3SmeOiHw+m0e/oBKDf0Sp6wfAeYycpnDrBFDRNl6lJg8hVXkUaMwnoj
V5/hjD8mfAGZpUhK/7b7EZdjMY1euJbelIJxvD+ZwdY5RNZWb5B4NtwYyrHJ985E
auTkdTNM1kBMtUzjk7CenE37MZwoxW0NQpvTX+MJMmhZynO2QYEP+MxNd51WJDcJ
v05J3pF0T1MbjXZnliNTf5F7HTnMu4vMgEOTQIWtcMsP0h/4TdK714/iUaFpEPt2
8UcoLZPVc9Sn6iKFrbqtUscMgMfYkqQ4Dz8+YxU8MSQ8c87Ux60MKpLCBHs5JB1R
51zfceUrI//PhkXDzacVpP90D1roAngb5ef7x6OIzxrpGNlOto0Rwa6YMLOTlTR9
E9v24P+EmKEnGilTztSL26CGFuWAqyNyrJggem+anUDJa9ni3nZXI2YUYCYEyCOR
aedV8zkyPzB30/Qqrwm48ITmXUvyEbUlVC8kU2c0q+FRsOZGKyMFFPTHGVuSFyQL
ftgKdARHeAdmRxfxmMM+L7HprJNhSNvKrG+vNxnvXrY/6U4K7TyCTWaw5nG0fLZl
d7t/TX2vT747eE2H4EomF3xxn8iSLM5IH7NCasKmoa+a7s1PSU+uNx6vOGuJm0vq
T/G1JkiL/HVfACsI5u0CAwEAAaMjMCEwHwYDVR0RBBgwFoIJbG9jYWxob3N0ggkx
MjcuMC4wLjEwDQYJKoZIhvcNAQELBQADggIBAB205rDQEWyvjjwoTMZ1xgPtwbxt
CzodNh2RPywx5APudHukTt3tHc9AJXQda8g23Dpl2Bmyli5Uyn9ufLOzyqUPmwdD
+tjk6HQvbhkVyylTA8b/HpO3hljcju+BIeHnFvBZxo9+aDhxbC1sICIIR9eJn62m
GFdweb32Ijd1tdL0ZEqTlkO+m2/27wVaNfMUhLLcA+6b31iyt1k2Pcl1l4TzMneW
Dr8BPZLbOZWSAaTLfYuFPnY2qsJ/gnX2Of06HNtNC0THFb6fWcPgc8dJb/04Ggjh
/GjbisNMZPrv18HQlG+GVZFGNq0iWqX+CPxZYxBLslLuRKixORTb0tSV4l0/qVYP
+y1FqEfm+VPxAUJCMm7TH0CpXVSejasRiF5T60rS58OXTqNgf3yHPci1jKkLwMT2
Y7BsLjakVSY+esxpRCdVE5SlSODpIVyCcFtMYzDZR8SXy6bReb9f4KKbtOwsH7gB
qPt2yf2hUkl07VfCTx+xk4e6j/mzVcKItqsPFPb1x/FAuB+/7Buwd/sgd80QPhTk
gvi7GRW1QwtzQIidosSrHlbXMwlxseXX78tMaXxIycys8Rj6AHNjcPWD8f8VeBNS
J9ajswRkIj2sLTGUJybVRZYzUSsjuJab1Lerf/4PALnVQSrajtBfkDVJy3vg29gq
zYZHyXcanSQrccdE
-----END CERTIFICATE-----

View File

@ -58,7 +58,7 @@ export class TestServer {
static async create(dirPath: string, port: number, loopback?: string): Promise<TestServer> {
const server = new TestServer(dirPath, port, loopback);
await new Promise(x => server._server.once('listening', x));
await server.waitUntilReady();
return server;
}
@ -68,7 +68,7 @@ export class TestServer {
cert: await fs.promises.readFile(path.join(__dirname, 'cert.pem')),
passphrase: 'aaaa',
});
await new Promise(x => server._server.once('listening', x));
await server.waitUntilReady();
return server;
}
@ -121,6 +121,10 @@ export class TestServer {
this.EMPTY_PAGE = `${protocol}://${same_origin}:${port}/empty.html`;
}
async waitUntilReady() {
await new Promise(x => this._server.once('listening', x));
}
_onSocket(socket: net.Socket) {
// ECONNRESET and HPE_INVALID_EOF_STATE are legit errors given
// that tab closing aborts outgoing connections to the server.

View File

@ -14,7 +14,9 @@
* limitations under the License.
*/
import fs from 'fs';
import { playwrightTest as it, expect } from '../../config/browserTest';
import { TestServer } from '../../config/testserver';
it('should pass firefox user preferences', async ({ browserType, mode }) => {
it.skip(mode.startsWith('service'));
@ -43,3 +45,34 @@ it('should pass firefox user preferences in persistent', async ({ mode, launchPe
const error = await page.goto('https://example.com').catch(e => e);
expect(error.message).toContain('NS_ERROR_PROXY_CONNECTION_REFUSED');
});
it('should support custom firefox policies', async ({ browserType, mode, asset, loopback }, testInfo) => {
it.skip(mode.startsWith('service'));
const policies = {
'policies': {
'Certificates': {
'Install': [asset('client-certificates/server/server_cert.pem')],
},
},
};
const policiesPath = testInfo.outputPath('policies.json');
await fs.promises.writeFile(policiesPath, JSON.stringify(policies));
const port = 48112;
const server = new TestServer(asset(''), port, loopback, {
key: await fs.promises.readFile(asset('client-certificates/client/localhost/localhost.key')),
cert: await fs.promises.readFile(asset('client-certificates/client/localhost/localhost.pem')),
});
await server.waitUntilReady();
const browser = await browserType.launch({
env: { ...process.env, 'PLAYWRIGHT_FIREFOX_POLICIES_JSON': policiesPath },
});
const page = await browser.newPage();
await page.goto(server.PREFIX + '/frames/frame.html');
await expect(page.locator('body')).toHaveText(`Hi, I'm frame`);
await browser.close();
await server.stop();
});