Refactor TLS/mTLS certificate handling in echo, event-stream, gRPC, and other servers

- Introduced a `certPath` utility to streamline certificate file path resolution.
- Updated all server files to use the new `certPath` function for loading TLS/mTLS certificates.
- Removed hardcoded certificate files from the repository to enhance security.
- Added `node-forge` as a dependency for certificate generation.
- Ensured that the Playwright configuration initializes certificates before server startup.
- Updated tests to reference the new certificate paths, ensuring compatibility with the refactored structure.
This commit is contained in:
Bob Qiu committed 2026-10-08 14:07:51 +08:00
1 parent 621c94fe5e
commit c6f87cf983
23 files changed
+194 -206

No files matched your search

+3
View File
@@ -45,3 +45,6 @@ final.rc
test-results/
playwright-report/
blob-report/
# TLS/mTLS key pairs generated by misc/certs.js
packages/insomnia-test/misc/fixtures/generated/
+1
View File
@@ -27616,6 +27616,7 @@
"git-http-backend": "^1.1.2",
"graphql": "^17.0.2",
"monocart-coverage-reports": "^2.13.0",
"node-forge": "^1.4.0",
"socket.io": "^4.8.3",
"ws": "^8.21.1",
"zod": "^4.4.3"
+145
View File
@@ -0,0 +1,145 @@
// Generates the TLS/mTLS fixtures the mock servers and specs use, so no
// private key has to be committed. Output goes to misc/fixtures/generated/
// (git-ignored). Idempotent: does nothing when every file already exists, so
// playwright.config.ts can call it once before the webServers start and each
// server can call it again as a no-op (or to run standalone).
const crypto = require("node:crypto");
const fs = require("node:fs");
const path = require("node:path");
const forge = require("node-forge");
const CERT_DIR = path.join(__dirname, "fixtures", "generated");
const FILES = [
"localhost-key.pem",
"localhost-cert.pem",
"mtls-ca.pem",
"mtls-server-key.pem",
"mtls-server-cert.pem",
"mtls-client-key.pem",
"mtls-client-cert.pem",
];
const TEN_YEARS_MS = 10 * 365 * 24 * 60 * 60 * 1000;
function generateKeyPair() {
const { privateKey } = crypto.generateKeyPairSync("rsa", {
modulusLength: 2048,
});
const privatePem = privateKey.export({ type: "pkcs8", format: "pem" });
const forgePrivate = forge.pki.privateKeyFromPem(privatePem);
const forgePublic = forge.pki.setRsaPublicKey(forgePrivate.n, forgePrivate.e);
return { privatePem, forgePrivate, forgePublic };
}
function createCert({ commonName, issuer, issuerKey, key, extensions }) {
const cert = forge.pki.createCertificate();
cert.publicKey = key.forgePublic;
cert.serialNumber = crypto.randomBytes(8).toString("hex");
// Back-date the start so a clock a little behind this machine's still accepts it.
cert.validity.notBefore = new Date(Date.now() - 24 * 60 * 60 * 1000);
cert.validity.notAfter = new Date(Date.now() + TEN_YEARS_MS);
const subject = [{ name: "commonName", value: commonName }];
cert.setSubject(subject);
cert.setIssuer(issuer ?? subject);
cert.setExtensions(extensions);
cert.sign(issuerKey ?? key.forgePrivate, forge.md.sha256.create());
return forge.pki.certificateToPem(cert);
}
const LOCALHOST_SAN = {
name: "subjectAltName",
altNames: [
{ type: 2, value: "localhost" },
{ type: 7, ip: "127.0.0.1" },
],
};
function generate() {
fs.mkdirSync(CERT_DIR, { recursive: true });
const write = (name, contents) =>
fs.writeFileSync(path.join(CERT_DIR, name), contents);
// Self-signed localhost cert, used by every plain HTTPS/WSS/gRPC-TLS server.
const localhostKey = generateKeyPair();
write("localhost-key.pem", localhostKey.privatePem);
write(
"localhost-cert.pem",
createCert({
commonName: "localhost",
key: localhostKey,
extensions: [LOCALHOST_SAN],
}),
);
// CA that signs the mTLS server and client certs. Its private key is only
// needed to sign them, so it's never written to disk.
const caKey = generateKeyPair();
const caName = [{ name: "commonName", value: "Insomnia Test mTLS CA" }];
const caPem = createCert({
commonName: "Insomnia Test mTLS CA",
key: caKey,
extensions: [
{ name: "basicConstraints", cA: true },
{ name: "keyUsage", keyCertSign: true, cRLSign: true },
],
});
write("mtls-ca.pem", caPem);
const serverKey = generateKeyPair();
write("mtls-server-key.pem", serverKey.privatePem);
write(
"mtls-server-cert.pem",
createCert({
commonName: "localhost",
issuer: caName,
issuerKey: caKey.forgePrivate,
key: serverKey,
extensions: [
{ name: "basicConstraints", cA: false },
{ name: "extKeyUsage", serverAuth: true },
LOCALHOST_SAN,
],
}),
);
const clientKey = generateKeyPair();
write("mtls-client-key.pem", clientKey.privatePem);
write(
"mtls-client-cert.pem",
createCert({
commonName: "insomnia-test-client",
issuer: caName,
issuerKey: caKey.forgePrivate,
key: clientKey,
extensions: [
{ name: "basicConstraints", cA: false },
{ name: "extKeyUsage", clientAuth: true },
],
}),
);
}
/**
* Generates the fixtures when any is missing.
* @returns The directory the PEM files live in
*/
function ensureCerts() {
const complete = FILES.every((name) =>
fs.existsSync(path.join(CERT_DIR, name)),
);
if (!complete) generate();
return CERT_DIR;
}
/**
* @param name - A fixture file name, e.g. `"localhost-key.pem"`
* @returns The absolute path to that generated file, creating it first if needed
*/
function certPath(name) {
ensureCerts();
return path.join(CERT_DIR, name);
}
module.exports = { CERT_DIR, ensureCerts, certPath };
+6 -5
View File
@@ -6,6 +6,7 @@ const https = require("node:https");
const fs = require("node:fs");
const path = require("node:path");
const { graphql, buildSchema } = require("graphql");
const { certPath } = require("./certs");
const PETSTORE_SWAGGER = fs.readFileSync(
path.join(__dirname, "fixtures", "petstore-swagger.json"),
@@ -66,14 +67,14 @@ const GRAPHQL_ROOT = {
};
const HTTPS_OPTIONS = {
key: fs.readFileSync(path.join(__dirname, "fixtures", "localhost-key.pem")),
cert: fs.readFileSync(path.join(__dirname, "fixtures", "localhost-cert.pem")),
key: fs.readFileSync(certPath("localhost-key.pem")),
cert: fs.readFileSync(certPath("localhost-cert.pem")),
};
const MTLS_CA = fs.readFileSync(path.join(__dirname, "fixtures", "mtls-ca.pem"));
const MTLS_CA = fs.readFileSync(certPath("mtls-ca.pem"));
const MTLS_SERVER_OPTIONS = {
key: fs.readFileSync(path.join(__dirname, "fixtures", "mtls-server-key.pem")),
cert: fs.readFileSync(path.join(__dirname, "fixtures", "mtls-server-cert.pem")),
key: fs.readFileSync(certPath("mtls-server-key.pem")),
cert: fs.readFileSync(certPath("mtls-server-cert.pem")),
};
const CUSTOM_CA_HTTPS_OPTIONS = { ...MTLS_SERVER_OPTIONS };
@@ -4,11 +4,11 @@
const http = require("node:http");
const https = require("node:https");
const fs = require("node:fs");
const path = require("node:path");
const { certPath } = require("./certs");
const HTTPS_OPTIONS = {
key: fs.readFileSync(path.join(__dirname, "fixtures", "localhost-key.pem")),
cert: fs.readFileSync(path.join(__dirname, "fixtures", "localhost-cert.pem")),
key: fs.readFileSync(certPath("localhost-key.pem")),
cert: fs.readFileSync(certPath("localhost-cert.pem")),
};
const MAX_REPLY_DELAY_MS = 60_000;
@@ -1,17 +0,0 @@
-----BEGIN CERTIFICATE-----
MIICyTCCAbGgAwIBAgIJAKxqgBxIan+zMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
BAMMCWxvY2FsaG9zdDAeFw0yNjA3MjgwODM4NTNaFw0zNjA3MjUwODM4NTNaMBQx
EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAL3lolmhRAGFlchkIXWmriWhopx7mC8xCNmNOAvyavdAc9C5XvTiPUocfhwZ
sRdYUpnfaG0xRYzZut9bBex27QyE2Im8l4A0K0lLCZIjbEGvbZBk0f/cjR89+8T6
ckA1gsOfvVlIFqqnv5FnQ4e+pihwRZItKnQI93KCl0sbWLYmt/IQhiXQVotzKBua
AHgmOp7seS6LvD3Y3ebEAJFEmPE85tD04nvUW3GpLmrKmRhd6Zsh+vjjjv+RqHFF
UKKXir0Isv28XkV32G4GT8iqXDR+Y6Oiz82/u5wol9QNiHfVH93hxDWTozk4S+Sv
gYbmBwltS3+Wtv+MMcn7wfVniuECAwEAAaMeMBwwGgYDVR0RBBMwEYIJbG9jYWxo
b3N0hwR/AAABMA0GCSqGSIb3DQEBCwUAA4IBAQBOM4YV/SZSnCD21e2B5/7LxTKr
MPyTk3trugMSnOYeWamakhriDQs8cB3K2eEGFEbDAF0XQZ/Dpz+UGhqnMz+WcRTi
G7G4gapQLhOZTzH8nU+yu2SDzYOA6EVYQJBtrHIZhpZuQ4WFEosr3KckRfTMeLB3
snb5NFgQEy84DKuwG8fAhI18YcpEitw84bD6fTdRCHCHYkEM6Y2+seD8hsfznX/m
rKcj90xqEJuEmbAEDI7x18RIheGmdnx84AIf0E9JkxXgKdmPeFnqEN5Kduzrfc14
L/NYei534YG+7pyk6LMuSiNAy2HqZ3EeCE/Ft0WXolUo2MXCmSfYeUjAboCm
-----END CERTIFICATE-----
@@ -1,28 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC95aJZoUQBhZXI
ZCF1pq4loaKce5gvMQjZjTgL8mr3QHPQuV704j1KHH4cGbEXWFKZ32htMUWM2brf
WwXsdu0MhNiJvJeANCtJSwmSI2xBr22QZNH/3I0fPfvE+nJANYLDn71ZSBaqp7+R
Z0OHvqYocEWSLSp0CPdygpdLG1i2JrfyEIYl0FaLcygbmgB4Jjqe7Hkui7w92N3m
xACRRJjxPObQ9OJ71FtxqS5qypkYXembIfr4447/kahxRVCil4q9CLL9vF5Fd9hu
Bk/Iqlw0fmOjos/Nv7ucKJfUDYh31R/d4cQ1k6M5OEvkr4GG5gcJbUt/lrb/jDHJ
+8H1Z4rhAgMBAAECggEACnUP2LG5xf+uPOfOs+Tm6Cmbg9SGj+q6Wwic0oOaAl2p
QxBCO2gOCfvBshh0GR4DBng4DvNMqjH/SXeAvwHZkfvq1MLu8N9uls2sDEEpIADi
HrZ+ngFuQA8wwysriX+o4M72JWmD3gf407AFFv+XtNhh7GfSU6t+vO6WGEu8OeOV
feuYBfyJPFShIKnAtBj8s7ya/nqfLRtvwWEMEhv3F8Xe/O+qyPBY8kuoD69GqBP+
m4RV3yEM3VAcBHZFAc6goIDvqSC6TLOdtVlwMMTQkkPw//q2MyMut3U7y8qbUJgx
3LOyXtkEBzJmg+QM5b3ksOt8voKwWyvLba/eA6moJQKBgQD4rQXsB6UHrb4V42yB
aB+XUYjLsNX8ETfnrAT8DHbv7KuusmvmfSixsEM/LTDpy8HILeHWsj3gBWJtvkXY
/eZoEE/kHV1alfNsGX2fqbkI/XjGa9QDDTxwTfuTCu8P82SttmE3tjt3yqsByD/R
wtNdnaxHaWcrfhtbacJhsqCrfwKBgQDDfW182hqfdM5KhSY8LsMfhuUUexzXh+CH
Oy+OwfIbGRHWz9K0Twd1pPtd34SqBmkCdp4sHd2mlNJsqr/Odfj15/uLjkXxx6QH
0crm3feLCLyava4oVpTlZieuPqCymQt5iesoOrlblK8TC7oKSsp9z1UUHiunLgMP
cYLQTHJ5nwKBgQC2k6pWaiJzac+3GFvRAxa2ralHC9WAFVA7ayPZvnkQnG5MfDkW
Z+wZ0bT9zHsuHGhxRaabUBB3ytxCgMGdmISzAM73R8wDtzaatnhyYlU1UYx7+i0V
9IDcX5UGl69/wY64r7/e/I/a2tUFIPYiVu2CvUIAyFV0LEl/qz2JJ3IplwKBgEPQ
7D2Gr/unGrVRUX1JP5ldQ3UCbHP8iBCBoLLmZyWtYbniaJbyX4UZUbY0ByKwjJc1
LRPi3HSgZgsahOWLmW09J8828N66QhYQWlISqIBL7JnFuXf26TpXYOaahUbPvuJP
zQssrAawIrf5tnVBktNoLHyJJt2dIaSm3RmDm6bDAoGAbLPB8enxDggrBJldcNh/
NgTaitfEtP2AdHlJcVJ2ROxOY7B4nJTxdQS+rlUHUIvILG/rn+s5iELYv96ZSpG9
wcfDLzRtf82hDuk78usNUSeecsUp7jDTB5NW+yqvupda3SmcAg+dtzvQL8hnLFpw
2oDkGN8z9PagokFIreRXrVE=
-----END PRIVATE KEY-----
@@ -1,27 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAt0but6x1QUc9UT/9pTpBdISfEUNBJRq6rfEVbKQba+2n/OOp
OFFKMURkvaumhgBjbjSGOAp96ROw57cTJjDtL412dbnbR1UpCm2pIfeg1dpzsVcG
MV8GVG87R/DrwFjl2gBv5V7GGE5G+0e49OC3ObynelShIZaLBV/n3J0jSRAkvt6k
hbdXcW6EXvyMo5LgyVpfMk9JPC46SBU91CdAEYdbV9t6dNzAe+iHuBuAtZNadlTv
l5mv6PdX9ZsqFZUsF9o7ILUfcl9/9qw1jKMNjb5BiLT0hrQXtGGLmn11xVy9gUgq
kl6DTZ10LAAkZ+M4to1xSHExGuKtWhW3Ir4FXQIDAQABAoIBAQC3C4LzsqxRDANz
mIONd8dTxfjQVulDU5TKkJOjM6uneW5jpkSl2JpO5k3vGPZxswWbVZ4PbnseQ+pV
IoVfiVH6QkDjh0I31hftMGTRZe4eZ9VQcufee1dpEMaWLUpniuHVfsZCwQr7z4IZ
CSLyf1S/t2lVRhy/3Qjvzz9VGSPanTCPw3J2qI7eM7jWnr/KveOskzbxWu4+m8pq
/+yCt1HfUvmEFWXFNrVd/7Q3s0ikUAsP2c+Qcl7sSOgj1NgMoOeDmvt+pUPLuzs7
1ZtT7ZS9slubGUnlmM4UtlABwNIZpDgYB87qUifrhqxqLssgsHuFugrJgUTDe6h9
cxAIpGjJAoGBAOzV8W9SrAe9GgveTtMvfYigKvWk08cNy+UAgq/VGUj/igNwrNnx
PIqx2CffYV65lrDTJrIaQq+iaiVlAnBz1ANgl9biX29jf2MUV7GxpmE1eSu14gZe
pW7gKhza8yUCRGyLcRS6ty0TPa20bxRJ/7p0YowRF9Iof8RksmOaXX4fAoGBAMYb
hWe5HzyPcBBM9ZIN+PSm2MZInZN+Y+zDTdh6RZpNoZmtMSN29ayVaG/WceaBVrEZ
rVLH5vMDpfAQjrqMk2vsRuCUiInnqIYc+HU0woUMZ6+aoAjbuYHgOOJ+jKupv+Dl
sgMFfvMM7J+kRizRmXJUIxYzfhRvxKZK7Sw0ExUDAoGALhNZSz0cNs01WgW/9BoT
JBd1BCEzClDG0CCPTEH7D1aXtR+goS3rh1geI3Oz78fPZ0tNBe1R9/VzDR9foB0I
rDeIkserpXIIAHCetvVG1zaeAkD6Xh7ftHhr+P0nvJV6VluyfkPtCxnpL/ggfCQB
Wnb2DSXuKnaylLS6d+I6OiUCgYB8KbWUC7ejKjdPUBy9fJpjI8tLgymXzqhsNQAu
RHwpOKym96CLnLxffYjmR1493SRrfS9facC64Ld43bfG/eJLytulWBK3dATwgWnL
c9TStLKrodrZknUTDGg6tJwP3yVOnEfUkvY8+QW5DKma34cv28Hd4UoNHvv+SYma
ocyv5wKBgC6nBQUe3UUJTZZD8stTbuGi1xk2BN7fw9QceGdLgP/2Ll9z/W4ZJtKJ
Btuvm5KlXNUrPRbIbCNhWdFWHBVi9GXQA28CfQyO2Cni8B+dcYP5kLuNJwMtddzg
8hxvfq5JsDbzoJIWJG6LxSffHQqminFtGTOC8h62j+lDBA5mJ1zR
-----END RSA PRIVATE KEY-----
@@ -1,17 +0,0 @@
-----BEGIN CERTIFICATE-----
MIICvDCCAaQCCQCbsBiedsHb1DANBgkqhkiG9w0BAQsFADAgMR4wHAYDVQQDDBVJ
bnNvbW5pYSBUZXN0IG1UTFMgQ0EwHhcNMjYwODEwMDQzNzI0WhcNMzYwODA3MDQz
NzI0WjAgMR4wHAYDVQQDDBVJbnNvbW5pYSBUZXN0IG1UTFMgQ0EwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3Ru63rHVBRz1RP/2lOkF0hJ8RQ0ElGrqt
8RVspBtr7af846k4UUoxRGS9q6aGAGNuNIY4Cn3pE7DntxMmMO0vjXZ1udtHVSkK
bakh96DV2nOxVwYxXwZUbztH8OvAWOXaAG/lXsYYTkb7R7j04Lc5vKd6VKEhlosF
X+fcnSNJECS+3qSFt1dxboRe/IyjkuDJWl8yT0k8LjpIFT3UJ0ARh1tX23p03MB7
6Ie4G4C1k1p2VO+Xma/o91f1myoVlSwX2jsgtR9yX3/2rDWMow2NvkGItPSGtBe0
YYuafXXFXL2BSCqSXoNNnXQsACRn4zi2jXFIcTEa4q1aFbcivgVdAgMBAAEwDQYJ
KoZIhvcNAQELBQADggEBAJGRCkDsLj/KMgRiuvP4WCLvMCvjjXL8jRidR6hhnnn3
ukGUcSjzKa80/usQw8tFvHTil9meZHEt1gjzyzDWZpUGI9qtdgkOWKdgVA/c0gb+
uwQArd9hy5qqQ2wzeBA4dj7xrsHcUEpdepKe+WhwFp2jcJXmzJniDIkSMQBm1isb
GiwhLGv/MN5Pg1WD9ImYjVA69IYQyFKeOpstbVq194jgCP769+D/g+l97gRsCHnb
Iz7mQNWS5DY1pVTL1SqGknapoC1Q23YWsmkIohyAhDaLCOlh6A8l0lvSy69LKuNk
jwDtZFVGFZfRTSxpGLm7LBWwqmEOKnP3CsGKeKOl/xE=
-----END CERTIFICATE-----
@@ -1,17 +0,0 @@
-----BEGIN CERTIFICATE-----
MIICuzCCAaMCCQDLYupB7sEMJTANBgkqhkiG9w0BAQsFADAgMR4wHAYDVQQDDBVJ
bnNvbW5pYSBUZXN0IG1UTFMgQ0EwHhcNMjYwODEwMDQzNzI0WhcNMzYwODA3MDQz
NzI0WjAfMR0wGwYDVQQDDBRpbnNvbW5pYS10ZXN0LWNsaWVudDCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBAN5r/CkX/6MFLdQO7v5pXTgqQjPi/Y1yVcW+
ksJgBwLoAbQnRvSIKne7hYFfWSVbKMzGa8Mhtgx0+R2wKRCPC+/OjOHOGaG10fmu
XmEulRc6A2sNUlC2O9joQnWg39eLk6/98d95OEgWAoSLBwHfhlKcmB+albNmug0e
Egi1RnrAWJHzi+HNVNiDYb4v/jgyWwIqQTeVJRh4XE6HHiihP8LtXl6klmrZGUnP
Zwvp/Z3YmQyQtwHz5aXQjhnoQCRzNlrnxtp/hglL3X+DudYN8sLwW8SbTN1GWDv+
qvhN9ZSnxOLx7r0Y5EibWkmDQDvEZhXatWtju6qpd0mzzU2L96ECAwEAATANBgkq
hkiG9w0BAQsFAAOCAQEAdB+E8pLopdrq7Z95DWk/v1shkySE06O9QFe5HQPdiKXX
ffxI0EzcOwgvzpTNwYlKj/Yrq9Py2135zcZhWOvTbfjjo4otV+3Ib3AqJDfu2211
hRhwLi6fBXRUcxRNaGf68gHxv/5Cp9akUGP91N29Rk4C2113wUUhaC/4kx4P5qHM
GmfbcGsjpDmP+Z2Q9BulP3G5KneDrefGGs0w3q4YAuxFmQJgGaNC2xaplmskSAgT
QewpzYYe5KinqsMM5tKtF756jqsBr6YoMXXJCN07hLD+OzEkaJLElnkxpq+zsr01
UOrBxfw0PuPeJhvEsxy9Fk5Rmx+pZihOryGqySx03w==
-----END CERTIFICATE-----
@@ -1,27 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA3mv8KRf/owUt1A7u/mldOCpCM+L9jXJVxb6SwmAHAugBtCdG
9Igqd7uFgV9ZJVsozMZrwyG2DHT5HbApEI8L786M4c4ZobXR+a5eYS6VFzoDaw1S
ULY72OhCdaDf14uTr/3x33k4SBYChIsHAd+GUpyYH5qVs2a6DR4SCLVGesBYkfOL
4c1U2INhvi/+ODJbAipBN5UlGHhcToceKKE/wu1eXqSWatkZSc9nC+n9ndiZDJC3
AfPlpdCOGehAJHM2WufG2n+GCUvdf4O51g3ywvBbxJtM3UZYO/6q+E31lKfE4vHu
vRjkSJtaSYNAO8RmFdq1a2O7qql3SbPNTYv3oQIDAQABAoIBAQC2j6vJjwkkpXuY
Mym3aIQ7NXRhYk77an08cc/D+03F9OhxFkwHKjyxShmqtrhVER3L9pE8+M6UKu7O
j2klTkRd8Qtxy9j+Al72sUiGO9Xj2pozpBuMZAd7YigqpIEWSlpOegGti7HGeUpX
wEVgJDf8VswGJLv7JLZRTf0/aIsQ9IdyEHIi7J0HCmsDOOrVJ4YzvylmPjhm6IAf
0ICWzkorKDqeGPb7SptOgn85dRaV1LalrnI0SNANeIYx7eFjI/250A4K1VP5CZO8
NGxfnCbwa08on65+ushkt8L2ofK9nBJf32eN6jlVIFGc3QlnPoAsTGQJPp+asg6C
yA8ecuYBAoGBAPvt8okdNsqF3CmUfG2/poofsfbZL+8DvavZgr/e3DwoL1MTpspj
KS3RoaRM9XxRzoQbZ0r1LYQIaO5/TJ8PFVYxjvRyXGw/PQmHDSElV+5kCt4G9XIx
XJP/uGlg8eVLVNXc9ooDAN/5mgiXZ3n1vsOr2/Zcn2w+WzIsZXNea7O9AoGBAOID
/EUTBgRdvCZHrxS+gyhSYLL3aS1gQs2oQoA20JVgodfJ6IdALeib0zwj+qww4MBy
lZY4qIMDPwVIu4StLK6Ge6i0HSrHBhYwd58ktzRIRUimH+GIO6oyOPhsY/Anv+XA
wfHWLtNtMFhB8/81sHgGpFxFRiv4oiNb8Td8Sh+1AoGAcnkNkrYelmm6v34ECA5k
izCZufO4LyABCFw+aBbI9eDAmDw+tonWRUaS70g057d4YljdV5cOhocXvv9C/qdo
55B/R53LVzho8LJYCe6hBOaadYat8qRxT6KL1f5CDBFty/uqXs28kQkmr660Sxua
AelOeqRdoF65K5Q2yPRndfUCgYEApau0NFHAfFzVON4cyUDo1RqlRSo0D43bCfMH
ZAJKHOTrXUjkSJfTzwjB6viYm7VsWcTkP2wioX40qMPqqFNkSD3N0RjNtHiUzpkS
ZjY8kHdVSe5zuhbpXVVZC0gwbW5FrL0BrSqJwnLsGBWoK++H/kMoIXap/DtRZkfT
5g8WKm0CgYA1BV4LYp3wowS075xkrMjDpSsOn2JNecDxhOifD3GGmSk0snMly0VJ
DqCsrfdfuKIXQm10rfco/ekOX/TW2aaKopx/FNCBQytEvZ6vBv0+Ks0Q5YZBpKaO
3nnYkfsQ3DC3ARoElqaaTYRS8HZyWsn4q8eI0TXDBkWGT+nnc7aErw==
-----END RSA PRIVATE KEY-----
@@ -1,18 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIC1TCCAb2gAwIBAgIJAMti6kHuwQwkMA0GCSqGSIb3DQEBCwUAMCAxHjAcBgNV
BAMMFUluc29tbmlhIFRlc3QgbVRMUyBDQTAeFw0yNjA4MTAwNDM3MjRaFw0zNjA4
MDcwNDM3MjRaMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEB
BQADggEPADCCAQoCggEBALchFJX3FxMAlZM36I7rt1CFMGAFHgvA/InV8aKkAXom
LXxCKs9/6VE0G03r+YBNp5OpMrsgQrn0djYom/9D8QnNSsmEBP/NBJJD/jgd2ueD
7/jcsERupZ3DfpL2Kqk4nTq/M7Z/yP4z/JQUjJ5WqJBPnirZZHFo1jQ8Of4+V37j
/Nw+Hk7IRcr8yOFhxY5XznR1hhszrR+3M/RDDt84jr7b9+Vaid26zYc2CVdJU9Y7
sGOyd/+5pcwOZMHdGciQGVLupXH3wwab42xmQZSUTZa81LTITToqJ81ehqjLe4+i
KtE6SyEQqSBysnyv+ZnKSe2FN51ROuwoI0fgVBsERpECAwEAAaMeMBwwGgYDVR0R
BBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEBCwUAA4IBAQAzkyo+YeQH
S90xtLm8p+NB6l0mWSwzP01HMuSa7DfMPYrKH2AA8ft9H8OJ0OZmNeJDn7JzLtGf
XuiBqHmILQLWuehpLXggj3cihqRhJTnVNrCjr/DTbsV38H0YbfKps2akaNxf1Y+c
353G4sj82iHl+0AXNfDhYp/p1E6pJpVnv7bmasLxTsQEBqV+4hyfmj2vzaKN1Mro
zf+UxAhcUH42feMVoYWEJT7Whfdn0kBuRp/40gZLIRwXGRXYtrIi9H5QWBoZLiQV
MWZnjZvDCtMrRsSDYdrFODZzdDMDIrFuc9QfdaQ7+OjlEnFUVyhQ3teT9kc1gsSc
0ISbCcg9H/sA
-----END CERTIFICATE-----
@@ -1,27 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAtyEUlfcXEwCVkzfojuu3UIUwYAUeC8D8idXxoqQBeiYtfEIq
z3/pUTQbTev5gE2nk6kyuyBCufR2Niib/0PxCc1KyYQE/80EkkP+OB3a54Pv+Nyw
RG6lncN+kvYqqTidOr8ztn/I/jP8lBSMnlaokE+eKtlkcWjWNDw5/j5XfuP83D4e
TshFyvzI4WHFjlfOdHWGGzOtH7cz9EMO3ziOvtv35VqJ3brNhzYJV0lT1juwY7J3
/7mlzA5kwd0ZyJAZUu6lcffDBpvjbGZBlJRNlrzUtMhNOionzV6GqMt7j6Iq0TpL
IRCpIHKyfK/5mcpJ7YU3nVE67CgjR+BUGwRGkQIDAQABAoIBAHqecdRAUHjuyTh8
FQGtn18Q72U7x/SC0hXQ5SzLuBl7+rTa8SNjOGyhAS9ZtARO+sgKYOefIE62+3gk
FOAFNB4mEc+A0IAfXNI7KLuWcf7W/xWZX4VSuR47ykLJBaOtPsoZQJ0QTxq24Iae
g9F5oQCP7w4t5e1yDwuG0CYGxDs3dfbYYcngGRPGPQi3U7O7ZSHhkI6ovkmkhkLo
kKXD73hMxtAT+CRX91lRUTc976U85F3xHgg1KTliO9tPb8+Rz+EESLFrinz81z4X
UynQqVTIPy/eiRwaAjYpOlzTjpar0Lo9l7YBmrv3irDjBqLxBx2T2hmAWoFc6O11
YKLsHAECgYEA7NGVxjeqkKfKyQSbxCykdfQvtlstIyvpOfwGBbsyCNeRwodt3GLj
iv24p+vyQTh6orVkOb6PnhU9nLDdjpbVUr/uWJyKvoTEoy8GqoDvVkDc3ZUFSfN9
d+oy48Vcr9ylZl6oCEH5JlbM6QJQbgyXKWE8SfF+nc5vTyGs/QwhqqECgYEAxfY/
tHMvqJV17IAMatDpBgbR7QLiocmBLjWGFugY1YWtRaNmnXJYnvjvcL9RMt7VSZbk
RBqedAuMmaS5/H4zm++PSfcV7kb4QeQfy7bsLcesBWeT6ptgDVUnsIcPeXDdSqMM
bvo/GEysevy51Qvao6phvFgXzYnceMEcNteNhfECgYEAkNCpEglAWC0DKGGVDyVt
fGPSOWUP+Q4FFNw0opSSSC3qiFZgrAAcvQXiQW1bOt7av1zE6TrKgBTlFEhjc6pw
0KVljvJLNa3iwRcksGcf9FK9vRI/pbUr6IRikj5CK5h13F/NyR7uyK8TpvkvTdyN
I1S+lUkD8GQoVO925Vbhz4ECgYEAueprp+Ap2S0NA+C6SLMMtdE/5FS6XXFudeRk
myy87gNOWMF+BM439o0Z6oxzCNCIBUXF+UP6nkeec0lmNoCbnY5dxvxbx101mERT
rDGOG+yTXLwLCeGEUuEvljUxzj62RXtdmPhCu2J+9j5VlIU+gEjq40Tkje80dN//
zG2iBzECgYAT7pihEvHy1RKUsQ/BUjHDZMTFN2sW64o045heux0fi1/byUQptYRC
drfVOyuxRal88qrTvxUQvFOuVvfQTeBq+hcNREeLM1xasJmtyMyTSZriyFh26jHO
5Oa12t4ulgnORLyCg/sKoS+A2nVyKv2YryfzPx1H/5szUy+MbEGSDw==
-----END RSA PRIVATE KEY-----
+6 -5
View File
@@ -6,22 +6,23 @@ const path = require("node:path");
const grpc = require("@grpc/grpc-js");
const protoLoader = require("@grpc/proto-loader");
const { ReflectionService } = require("@grpc/reflection");
const { certPath } = require("./certs");
const PROTO_PATH = path.join(__dirname, "protos", "hello.proto");
const TLS_KEY = fs.readFileSync(
path.join(__dirname, "fixtures", "localhost-key.pem"),
certPath("localhost-key.pem"),
);
const TLS_CERT = fs.readFileSync(
path.join(__dirname, "fixtures", "localhost-cert.pem"),
certPath("localhost-cert.pem"),
);
const MTLS_CA = fs.readFileSync(path.join(__dirname, "fixtures", "mtls-ca.pem"));
const MTLS_CA = fs.readFileSync(certPath("mtls-ca.pem"));
const MTLS_KEY = fs.readFileSync(
path.join(__dirname, "fixtures", "mtls-server-key.pem"),
certPath("mtls-server-key.pem"),
);
const MTLS_CERT = fs.readFileSync(
path.join(__dirname, "fixtures", "mtls-server-cert.pem"),
certPath("mtls-server-cert.pem"),
);
const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
+6 -3
View File
@@ -3,17 +3,17 @@
const https = require("node:https");
const fs = require("node:fs");
const path = require("node:path");
const express = require("express");
const { McpServer } = require("@modelcontextprotocol/sdk/server/mcp.js");
const {
StreamableHTTPServerTransport,
} = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
const z = require("zod/v4");
const { certPath } = require("./certs");
const HTTPS_OPTIONS = {
key: fs.readFileSync(path.join(__dirname, "fixtures", "localhost-key.pem")),
cert: fs.readFileSync(path.join(__dirname, "fixtures", "localhost-cert.pem")),
key: fs.readFileSync(certPath("localhost-key.pem")),
cert: fs.readFileSync(certPath("localhost-cert.pem")),
};
function getServer() {
@@ -78,6 +78,9 @@ function getServer() {
return server;
}
// A loopback-only mock with no cookies or sessions, so there is no ambient
// credential for a cross-site request to ride on and CSRF tokens don't apply.
// nosemgrep: javascript.express.security.audit.express-check-csurf-middleware-usage.express-check-csurf-middleware-usage
const app = express();
app.use(express.json());
@@ -11,6 +11,9 @@ const CLIENT_SECRET = "test-client-secret";
const USERNAME = "testuser";
const PASSWORD = "testpass";
// A loopback-only mock with no cookies or sessions, so there is no ambient
// credential for a cross-site request to ride on and CSRF tokens don't apply.
// nosemgrep: javascript.express.security.audit.express-check-csurf-middleware-usage.express-check-csurf-middleware-usage
const app = express();
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
+3 -3
View File
@@ -4,15 +4,15 @@
const { createServer } = require("node:http");
const { createServer: createHttpsServer } = require("node:https");
const fs = require("node:fs");
const path = require("node:path");
const { Server } = require("socket.io");
const { certPath } = require("./certs");
const PORT = process.env.SOCKET_PORT || 3000;
const SECURE_PORT = process.env.SOCKET_SECURE_PORT || 3001;
const HTTPS_OPTIONS = {
key: fs.readFileSync(path.join(__dirname, "fixtures", "localhost-key.pem")),
cert: fs.readFileSync(path.join(__dirname, "fixtures", "localhost-cert.pem")),
key: fs.readFileSync(certPath("localhost-key.pem")),
cert: fs.readFileSync(certPath("localhost-cert.pem")),
};
const httpServer = createServer();
@@ -4,15 +4,15 @@
const { createServer } = require("node:http");
const { createServer: createHttpsServer } = require("node:https");
const fs = require("node:fs");
const path = require("node:path");
const { WebSocketServer } = require("ws");
const { certPath } = require("./certs");
const PORT = process.env.WS_PORT || 4040;
const SECURE_PORT = process.env.WS_SECURE_PORT || 4041;
const HTTPS_OPTIONS = {
key: fs.readFileSync(path.join(__dirname, "fixtures", "localhost-key.pem")),
cert: fs.readFileSync(path.join(__dirname, "fixtures", "localhost-cert.pem")),
key: fs.readFileSync(certPath("localhost-key.pem")),
cert: fs.readFileSync(certPath("localhost-cert.pem")),
};
function handleRequest(req, res) {
+1
View File
@@ -27,6 +27,7 @@
"git-http-backend": "^1.1.2",
"graphql": "^17.0.2",
"monocart-coverage-reports": "^2.13.0",
"node-forge": "^1.4.0",
"socket.io": "^4.8.3",
"ws": "^8.21.1",
"zod": "^4.4.3"
@@ -2,6 +2,8 @@ import path from "node:path";
import { defineConfig, devices } from "@playwright/test";
import { ensureCerts } from "./misc/certs";
// By default, misc/fixtures.ts launches the app straight out of the
// sibling ../insomnia source checkout (its local `electron` binary against
// packages/insomnia) instead of a packaged build — so the app under test
@@ -22,6 +24,10 @@ const isDevMode =
process.env.INSOMNIA_DEV_MODE !== "0";
const INSOMNIA_SRC_PACKAGE = path.resolve(__dirname, "..", "insomnia");
// The mock servers' TLS/mTLS key pairs are generated rather than committed.
// Do it here, once, before any webServer below starts reading them.
ensureCerts();
export default defineConfig({
timeout: 90 * 1000,
testDir: "./tests",
@@ -3,6 +3,7 @@ import path from "node:path";
import { faker } from "@faker-js/faker";
import { ProjectType } from "../../enums/project-types";
import { certPath } from "../../misc/certs";
import { expect, GRPC_SERVER_MTLS,test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
@@ -38,8 +39,8 @@ test("Verify Client Certificate Toggle Controls mTLS Enforcement For gRPC Reques
await certificatesFlow.addClientCertificate(collection, {
host: "localhost",
cert: path.join(__dirname, "../../misc/fixtures/mtls-client-cert.pem"),
key: path.join(__dirname, "../../misc/fixtures/mtls-client-key.pem"),
cert: certPath("mtls-client-cert.pem"),
key: certPath("mtls-client-key.pem"),
});
const greeting = faker.person.firstName();
@@ -1,9 +1,9 @@
import path from "node:path";
import { faker } from "@faker-js/faker";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { certPath } from "../../misc/certs";
import {
DEFAULT_TIMEOUT,
expect,
@@ -41,7 +41,7 @@ test("Verify Custom CA Root Certificate Establishes Trust For HTTPS Request", as
await certificatesFlow.setCaCertificate(
collection,
path.join(__dirname, "../../misc/fixtures/mtls-ca.pem"),
certPath("mtls-ca.pem"),
);
const requestAfterCa = await httpRequestFlow.create(collection, {
@@ -4,6 +4,7 @@ import { faker } from "@faker-js/faker";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { certPath } from "../../misc/certs";
import {
DEFAULT_TIMEOUT,
expect,
@@ -47,8 +48,8 @@ test("Verify Client Certificate Toggle Controls mTLS Enforcement For HTTP Reques
await certificatesFlow.addClientCertificate(collection, {
host: "localhost",
cert: path.join(__dirname, "../../misc/fixtures/mtls-client-cert.pem"),
key: path.join(__dirname, "../../misc/fixtures/mtls-client-key.pem"),
cert: certPath("mtls-client-cert.pem"),
key: certPath("mtls-client-key.pem"),
});
const requestWithCert = await httpRequestFlow.create(collection, {