mirror of
https://github.com/cypress-io/cypress.git
synced 2026-01-10 16:50:03 -06:00
* https-proxy: unused file * server: wrap all https requests that use a proxy * server: use request lib in ensureUrl if proxy is in use. this makes runs tab work behind a proxy * electron: pass --proxy-server to app itself, so the embedded github login page works * cli: first attempt at env vars from windows registry * cli: api cleanup * cli: lint * cli: fix crash on no proxy, add tests * add desktop-gui watch to terminals.json * cli: pass along --proxy-source * electron: pass --proxy-bypass-list too * server: whitelist proxy* args * cli: better wording * desktop-gui: display proxy settings * extension: force proxy [wip] * extension: finally, i am victorious over coffeescript * extension: add -loopback to bypasslist * extension: revert changes Revert "extension: force proxy [wip]" This reverts commit 3ab6ba42a763f25ee65f12eb8b79eb597efc9b11. * desktop-gui: skip proxysettings if there aren't any * https-proxy, server: proxy directConnections using https-proxy-agent * https-agent: pool httpsAgents * https-proxy: work when they're not on a proxy * https-proxy: ci - use agent 1.0 * https-proxy: tests * desktop-gui: hide proxy settings when not using proxy * https-proxy: pass req through to https-proxy-agent callback * cli: use get-windows-proxy * desktop-gui: always show proxy settings * server: use get-windows-proxy * electron, server: supply electron proxy config when window launched * server: fix * https-proxy: cleanup * server: clean up ensureUrl * https-proxy: cleanup * cli: fix * cli: fix destructuring * server: enable ForeverAgent to pool HTTPS/HTTP connections #3192 * server: updating snapshot * https-proxy: don't crash, do error if proxy unreachable * https-proxy: * get-windows-proxy@1.0.0 * https-proxy: use proxy-from-env to decide on a proxy for a url * server: fallback to HTTP_PROXY globally if HTTPS_PROXY not set * server: proxy args test * cli: add proxy tests * cli: add test that loadSystemProxySettings is called during download * cli, server: account for the fact that CI has some proxy vars set * https-proxy: "" * cli, https-proxy, server: "" * desktop-gui: update settings gui * desktop-gui: cypress tests for proxy settings * server: strict undefined check * cli, server: move get-windows-proxy to scope, optionalDeps * server, cli: use new and improved get-windows-proxy * cli, server: 1.5.0 * server: re-check for proxy since cli may have failed to load the lib * server, cli: 1.5.1 * server: NO_PROXY=localhost by default, clean up * https-proxy: disable Nagle's on proxy sockets \#3192 * https-proxy: use setNoDelay on upstream, cache https agent * https-proxy: test basic auth * https-proxy: add todo: remove this * server: add custom HTTP(s) Agent implementation w keepalive, tunneling * server: typescript for agent * add ts to zunder * server: more ts * ts: add missing Agent type declaration * server: create CombinedAgent * server: use agent in more places * ts: more declarations * server: make script work even if debug port not supplied * server: begin some testing * server, ts: agent, tests * server: test * server: agent works with websockets now * server: update snapshot * server: work out some more bugs with websockets * server: more websockets * server: add net_profiler * https-proxy: fix dangling socket on direct connection * server: fix potential 'headers have already been sent' * https-proxy: nab another dangler * server: update test to expect agent * https-proxy: fix failing test * desktop-gui: change on-link * server: add tests for empty response case * server: tests * server: send keep-alive with requests * server: make net profiler hook on socket.connect * server: only hook profiler once * server: update tests, add keep-alive test * server: only regen headers if needed * server: move http_overrides into CombinedAgent, make it proxy-proof for #112 * server: update snapshot * server: undo * server: avoid circular dependency * https-proxy, server: use our Agent instead of https-proxy-agent * server: add dependency back * cli: actually use proxy for download * server, launcher, ts: typescript * Revert "server, launcher, ts: typescript" This reverts commitd3f8b8bbb6. * Revert "Revert "server, launcher, ts: typescript"" This reverts commit818dfdfd00. * ts, server: respond to PR * server, ts: types * ts: really fix types * https-proxy, server: export CA from https-proxy * agent, server, https-proxy: move agent to own package * agent => networking, move connect into networking * fix tests * fix test * networking: respond to PR changes, add more unit tests * rename ctx * networking, ts: add more tests * server: add ensureUrl tests * https-proxy: remove https-proxy-agent * server: use CombinedAgent for API * server: updates * add proxy performance tests * add perf tests to workflow * circle * run perf tests with --no-sandbox * networking, ts: ch-ch-ch-ch-changes * server, networking: pr changes * run networking tests in circle * server: fix performance test * https-proxy: test that sockets are being closed * https-proxy: write, not emit * networking: fix test * networking: bubble err in connect * networking: style * networking: clean p connect error handling * networking => network * server: make perf tests really work * server: really report * server: use args from browser * server: use AI to determine max run time * server: load electron only when needed Co-authored-by: Brian Mann <brian@cypress.io>
241 lines
5.9 KiB
CoffeeScript
241 lines
5.9 KiB
CoffeeScript
_ = require("lodash")
|
|
fs = require("fs-extra")
|
|
os = require("os")
|
|
path = require("path")
|
|
Forge = require("node-forge")
|
|
Promise = require("bluebird")
|
|
|
|
fs = Promise.promisifyAll(fs)
|
|
|
|
pki = Forge.pki
|
|
|
|
generateKeyPairAsync = Promise.promisify(pki.rsa.generateKeyPair)
|
|
|
|
ipAddressRe = /^[\d\.]+$/
|
|
asterisksRe = /\*/g
|
|
|
|
CAattrs = [{
|
|
name: "commonName",
|
|
value: "CypressProxyCA"
|
|
}, {
|
|
name: "countryName",
|
|
value: "Internet"
|
|
}, {
|
|
shortName: "ST",
|
|
value: "Internet"
|
|
}, {
|
|
name: "localityName",
|
|
value: "Internet"
|
|
}, {
|
|
name: "organizationName",
|
|
value: "Cypress.io"
|
|
}, {
|
|
shortName: "OU",
|
|
value: "CA"
|
|
}]
|
|
|
|
CAextensions = [{
|
|
name: "basicConstraints",
|
|
cA: true
|
|
}, {
|
|
name: "keyUsage",
|
|
keyCertSign: true,
|
|
digitalSignature: true,
|
|
nonRepudiation: true,
|
|
keyEncipherment: true,
|
|
dataEncipherment: true
|
|
}, {
|
|
name: "extKeyUsage",
|
|
serverAuth: true,
|
|
clientAuth: true,
|
|
codeSigning: true,
|
|
emailProtection: true,
|
|
timeStamping: true
|
|
}, {
|
|
name: "nsCertType",
|
|
client: true,
|
|
server: true,
|
|
email: true,
|
|
objsign: true,
|
|
sslCA: true,
|
|
emailCA: true,
|
|
objCA: true
|
|
}, {
|
|
name: "subjectKeyIdentifier"
|
|
}]
|
|
|
|
ServerAttrs = [{
|
|
name: "countryName",
|
|
value: "Internet"
|
|
}, {
|
|
shortName: "ST",
|
|
value: "Internet"
|
|
}, {
|
|
name: "localityName",
|
|
value: "Internet"
|
|
}, {
|
|
name: "organizationName",
|
|
value: "Cypress Proxy CA"
|
|
}, {
|
|
shortName: "OU",
|
|
value: "Cypress Proxy Server Certificate"
|
|
}]
|
|
|
|
ServerExtensions = [{
|
|
name: "basicConstraints",
|
|
cA: false
|
|
}, {
|
|
name: "keyUsage",
|
|
keyCertSign: false,
|
|
digitalSignature: true,
|
|
nonRepudiation: false,
|
|
keyEncipherment: true,
|
|
dataEncipherment: true
|
|
}, {
|
|
name: "extKeyUsage",
|
|
serverAuth: true,
|
|
clientAuth: true,
|
|
codeSigning: false,
|
|
emailProtection: false,
|
|
timeStamping: false
|
|
}, {
|
|
name: "nsCertType",
|
|
client: true,
|
|
server: true,
|
|
email: false,
|
|
objsign: false,
|
|
sslCA: false,
|
|
emailCA: false,
|
|
objCA: false
|
|
}, {
|
|
name: "subjectKeyIdentifier"
|
|
}]
|
|
|
|
class CA
|
|
|
|
randomSerialNumber: ->
|
|
## generate random 16 bytes hex string
|
|
sn = ""
|
|
|
|
for i in [1..4]
|
|
sn += ("00000000" + Math.floor(Math.random()*Math.pow(256, 4)).toString(16)).slice(-8)
|
|
|
|
sn
|
|
|
|
generateCA: ->
|
|
generateKeyPairAsync({bits: 512})
|
|
.then (keys) =>
|
|
cert = pki.createCertificate()
|
|
cert.publicKey = keys.publicKey
|
|
cert.serialNumber = @randomSerialNumber()
|
|
cert.validity.notBefore = new Date()
|
|
cert.validity.notAfter = new Date()
|
|
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 10)
|
|
cert.setSubject(CAattrs)
|
|
cert.setIssuer(CAattrs)
|
|
cert.setExtensions(CAextensions)
|
|
cert.sign(keys.privateKey, Forge.md.sha256.create())
|
|
|
|
@CAcert = cert
|
|
@CAkeys = keys
|
|
|
|
Promise.all([
|
|
fs.writeFileAsync(path.join(@certsFolder, "ca.pem"), pki.certificateToPem(cert))
|
|
fs.writeFileAsync(path.join(@keysFolder, "ca.private.key"), pki.privateKeyToPem(keys.privateKey))
|
|
fs.writeFileAsync(path.join(@keysFolder, "ca.public.key"), pki.publicKeyToPem(keys.publicKey))
|
|
])
|
|
|
|
loadCA: ->
|
|
Promise.props({
|
|
certPEM: fs.readFileAsync(path.join(@certsFolder, "ca.pem"), "utf-8")
|
|
keyPrivatePEM: fs.readFileAsync(path.join(@keysFolder, "ca.private.key"), "utf-8")
|
|
keyPublicPEM: fs.readFileAsync(path.join(@keysFolder, "ca.public.key"), "utf-8")
|
|
})
|
|
.then (results) =>
|
|
@CAcert = pki.certificateFromPem(results.certPEM)
|
|
@CAkeys = {
|
|
privateKey: pki.privateKeyFromPem(results.keyPrivatePEM)
|
|
publicKey: pki.publicKeyFromPem(results.keyPublicPEM)
|
|
}
|
|
.return(undefined)
|
|
|
|
generateServerCertificateKeys: (hosts) ->
|
|
hosts = [].concat(hosts)
|
|
|
|
mainHost = hosts[0]
|
|
keysServer = pki.rsa.generateKeyPair(1024)
|
|
certServer = pki.createCertificate()
|
|
|
|
certServer.publicKey = keysServer.publicKey
|
|
certServer.serialNumber = @randomSerialNumber()
|
|
certServer.validity.notBefore = new Date
|
|
certServer.validity.notAfter = new Date
|
|
certServer.validity.notAfter.setFullYear(certServer.validity.notBefore.getFullYear() + 2)
|
|
|
|
attrsServer = _.clone(ServerAttrs)
|
|
attrsServer.unshift({
|
|
name: "commonName",
|
|
value: mainHost
|
|
})
|
|
|
|
certServer.setSubject(attrsServer)
|
|
certServer.setIssuer(@CAcert.issuer.attributes)
|
|
certServer.setExtensions(ServerExtensions.concat([{
|
|
name: "subjectAltName",
|
|
altNames: hosts.map (host) ->
|
|
if host.match(ipAddressRe)
|
|
{type: 7, ip: host}
|
|
else
|
|
{type: 2, value: host}
|
|
}]))
|
|
|
|
certServer.sign(@CAkeys.privateKey, Forge.md.sha256.create())
|
|
|
|
certPem = pki.certificateToPem(certServer)
|
|
keyPrivatePem = pki.privateKeyToPem(keysServer.privateKey)
|
|
keyPublicPem = pki.publicKeyToPem(keysServer.publicKey)
|
|
|
|
dest = mainHost.replace(asterisksRe, "_")
|
|
|
|
Promise.all([
|
|
fs.writeFileAsync(path.join(@certsFolder, dest + ".pem"), certPem)
|
|
fs.writeFileAsync(path.join(@keysFolder, dest + ".key"), keyPrivatePem)
|
|
fs.writeFileAsync(path.join(@keysFolder, dest + ".public.key"), keyPublicPem)
|
|
])
|
|
.return([certPem, keyPrivatePem])
|
|
|
|
getCertificateKeysForHostname: (hostname) ->
|
|
dest = hostname.replace(asterisksRe, "_")
|
|
|
|
Promise.all([
|
|
fs.readFileAsync(path.join(@certsFolder, dest + ".pem"))
|
|
fs.readFileAsync(path.join(@keysFolder, dest + ".key"))
|
|
])
|
|
|
|
getCACertPath: ->
|
|
path.join(@certsFolder, "ca.pem")
|
|
|
|
@create = (caFolder) ->
|
|
ca = new CA
|
|
|
|
if not caFolder
|
|
caFolder = path.join(os.tmpdir(), 'cy-ca')
|
|
|
|
ca.baseCAFolder = caFolder
|
|
ca.certsFolder = path.join(ca.baseCAFolder, "certs")
|
|
ca.keysFolder = path.join(ca.baseCAFolder, "keys")
|
|
|
|
Promise.all([
|
|
fs.ensureDirAsync(ca.baseCAFolder)
|
|
fs.ensureDirAsync(ca.certsFolder)
|
|
fs.ensureDirAsync(ca.keysFolder)
|
|
])
|
|
.then ->
|
|
fs.statAsync(path.join(ca.certsFolder, "ca.pem"))
|
|
.bind(ca)
|
|
.then(ca.loadCA)
|
|
.catch(ca.generateCA)
|
|
.return(ca)
|
|
|
|
module.exports = CA
|