mirror of
https://github.com/verdaccio/verdaccio.git
synced 2025-01-13 22:48:31 -05:00
feat: ca certificate is optional for https configuration (#1853)
* setup https server * typed handleHttps * fix if condition * generate certificate on the fly * revert yarn.lock Co-authored-by: Juan Picado <juanpicado19@gmail.com>
This commit is contained in:
parent
dd9b3cff55
commit
912482a5ae
4 changed files with 70 additions and 21 deletions
|
@ -72,7 +72,7 @@
|
||||||
"@typescript-eslint/eslint-plugin": "2.12.0",
|
"@typescript-eslint/eslint-plugin": "2.12.0",
|
||||||
"@verdaccio/babel-preset": "^9.6.1",
|
"@verdaccio/babel-preset": "^9.6.1",
|
||||||
"@verdaccio/eslint-config": "^8.5.0",
|
"@verdaccio/eslint-config": "^8.5.0",
|
||||||
"@verdaccio/types": "^9.3.0",
|
"@verdaccio/types": "^9.7.0",
|
||||||
"all-contributors-cli": "6.16.0",
|
"all-contributors-cli": "6.16.0",
|
||||||
"codecov": "3.7.0",
|
"codecov": "3.7.0",
|
||||||
"cross-env": "7.0.2",
|
"cross-env": "7.0.2",
|
||||||
|
@ -81,16 +81,17 @@
|
||||||
"fs-extra": "8.1.0",
|
"fs-extra": "8.1.0",
|
||||||
"get-stdin": "7.0.0",
|
"get-stdin": "7.0.0",
|
||||||
"husky": "2.7.0",
|
"husky": "2.7.0",
|
||||||
"lockfile-lint": "4.2.2",
|
|
||||||
"in-publish": "2.0.1",
|
"in-publish": "2.0.1",
|
||||||
"jest": "25.3.0",
|
"jest": "25.3.0",
|
||||||
"jest-environment-node": "25.3.0",
|
"jest-environment-node": "25.3.0",
|
||||||
"jest-junit": "9.0.0",
|
"jest-junit": "9.0.0",
|
||||||
"lint-staged": "8.2.1",
|
"lint-staged": "8.2.1",
|
||||||
|
"lockfile-lint": "4.2.2",
|
||||||
"nock": "11.7.2",
|
"nock": "11.7.2",
|
||||||
"prettier": "1.19.1",
|
"prettier": "1.19.1",
|
||||||
"puppeteer": "1.8.0",
|
"puppeteer": "1.8.0",
|
||||||
"rimraf": "3.0.2",
|
"rimraf": "3.0.2",
|
||||||
|
"selfsigned": "1.10.7",
|
||||||
"standard-version": "8.0.0",
|
"standard-version": "8.0.0",
|
||||||
"supertest": "4.0.2",
|
"supertest": "4.0.2",
|
||||||
"typescript": "3.7.5",
|
"typescript": "3.7.5",
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { assign, isObject, isFunction } from 'lodash';
|
import { assign, isObject, isFunction } from 'lodash';
|
||||||
|
import express from 'express';
|
||||||
import URL from 'url';
|
import URL from 'url';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import http from 'http';
|
import http from 'http';
|
||||||
|
@ -8,7 +9,7 @@ import endPointAPI from '../api/index';
|
||||||
import { getListListenAddresses, resolveConfigPath } from './cli/utils';
|
import { getListListenAddresses, resolveConfigPath } from './cli/utils';
|
||||||
import { API_ERROR, certPem, csrPem, keyPem } from './constants';
|
import { API_ERROR, certPem, csrPem, keyPem } from './constants';
|
||||||
|
|
||||||
import { Callback } from '@verdaccio/types';
|
import { Callback, ConfigWithHttps, HttpsConfKeyCert, HttpsConfPfx } from '@verdaccio/types';
|
||||||
import { Application } from 'express';
|
import { Application } from 'express';
|
||||||
|
|
||||||
const logger = require('./logger');
|
const logger = require('./logger');
|
||||||
|
@ -47,11 +48,6 @@ function startVerdaccio(config: any, cliListen: string, configPath: string, pkgV
|
||||||
addresses.forEach(function(addr): void {
|
addresses.forEach(function(addr): void {
|
||||||
let webServer;
|
let webServer;
|
||||||
if (addr.proto === 'https') {
|
if (addr.proto === 'https') {
|
||||||
// https must either have key cert and ca or a pfx and (optionally) a passphrase
|
|
||||||
if (!config.https || !((config.https.key && config.https.cert && config.https.ca) || config.https.pfx)) {
|
|
||||||
logHTTPSWarning(configPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
webServer = handleHTTPS(app, configPath, config);
|
webServer = handleHTTPS(app, configPath, config);
|
||||||
} else {
|
} else {
|
||||||
// http
|
// http
|
||||||
|
@ -79,7 +75,7 @@ function logHTTPSWarning(storageLocation) {
|
||||||
logger.logger.fatal(
|
logger.logger.fatal(
|
||||||
[
|
[
|
||||||
'You have enabled HTTPS and need to specify either ',
|
'You have enabled HTTPS and need to specify either ',
|
||||||
' "https.key", "https.cert" and "https.ca" or ',
|
' "https.key" and "https.cert" or ',
|
||||||
' "https.pfx" and optionally "https.passphrase" ',
|
' "https.pfx" and optionally "https.passphrase" ',
|
||||||
'to run https server',
|
'to run https server',
|
||||||
'',
|
'',
|
||||||
|
@ -98,28 +94,39 @@ function logHTTPSWarning(storageLocation) {
|
||||||
' https:',
|
' https:',
|
||||||
` key: ${resolveConfigPath(storageLocation, keyPem)}`,
|
` key: ${resolveConfigPath(storageLocation, keyPem)}`,
|
||||||
` cert: ${resolveConfigPath(storageLocation, certPem)}`,
|
` cert: ${resolveConfigPath(storageLocation, certPem)}`,
|
||||||
` ca: ${resolveConfigPath(storageLocation, csrPem)}`,
|
|
||||||
].join('\n')
|
].join('\n')
|
||||||
);
|
);
|
||||||
process.exit(2);
|
process.exit(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleHTTPS(app, configPath, config) {
|
function handleHTTPS(app: express.Application, configPath: string, config: ConfigWithHttps): https.Server {
|
||||||
try {
|
try {
|
||||||
let httpsOptions = {
|
let httpsOptions = {
|
||||||
secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3, // disable insecure SSLv2 and SSLv3
|
secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3, // disable insecure SSLv2 and SSLv3
|
||||||
};
|
};
|
||||||
|
|
||||||
if (config.https.pfx) {
|
const keyCertConfig = config.https as HttpsConfKeyCert;
|
||||||
|
const pfxConfig = config.https as HttpsConfPfx;
|
||||||
|
|
||||||
|
// https must either have key and cert or a pfx and (optionally) a passphrase
|
||||||
|
if (!((keyCertConfig.key && keyCertConfig.cert) || pfxConfig.pfx)) {
|
||||||
|
logHTTPSWarning(configPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pfxConfig.pfx) {
|
||||||
|
const { pfx, passphrase } = pfxConfig;
|
||||||
httpsOptions = assign(httpsOptions, {
|
httpsOptions = assign(httpsOptions, {
|
||||||
pfx: fs.readFileSync(config.https.pfx),
|
pfx: fs.readFileSync(pfx),
|
||||||
passphrase: config.https.passphrase || '',
|
passphrase: passphrase || '',
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
const { key, cert, ca } = keyCertConfig;
|
||||||
httpsOptions = assign(httpsOptions, {
|
httpsOptions = assign(httpsOptions, {
|
||||||
key: fs.readFileSync(config.https.key),
|
key: fs.readFileSync(key),
|
||||||
cert: fs.readFileSync(config.https.cert),
|
cert: fs.readFileSync(cert),
|
||||||
ca: fs.readFileSync(config.https.ca),
|
...(ca && {
|
||||||
|
ca: fs.readFileSync(ca),
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return https.createServer(httpsOptions, app);
|
return https.createServer(httpsOptions, app);
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
import selfsigned from 'selfsigned';
|
||||||
|
import os from 'os';
|
||||||
|
import fs from 'fs';
|
||||||
|
|
||||||
import startServer from '../../../../src';
|
import startServer from '../../../../src';
|
||||||
import config from '../../partials/config';
|
import config from '../../partials/config';
|
||||||
|
@ -140,6 +143,32 @@ describe('startServer via API', () => {
|
||||||
global.process = realProcess;
|
global.process = realProcess;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should start a https server with key and cert', async (done) => {
|
||||||
|
const store = path.join(__dirname, 'partials/store');
|
||||||
|
const serverName = 'verdaccio-test';
|
||||||
|
const version = '1.0.0';
|
||||||
|
const address = 'https://www.domain.com:443';
|
||||||
|
const { private: key, cert } = selfsigned.generate();
|
||||||
|
const keyPath = path.join(os.tmpdir(), 'key.pem');
|
||||||
|
const certPath = path.join(os.tmpdir(), 'crt.pem');
|
||||||
|
fs.writeFileSync(keyPath, key);
|
||||||
|
fs.writeFileSync(certPath, cert);
|
||||||
|
|
||||||
|
const conf = config();
|
||||||
|
conf.https = {
|
||||||
|
key: keyPath,
|
||||||
|
cert: certPath,
|
||||||
|
};
|
||||||
|
|
||||||
|
await startServer(conf, address, store, version, serverName,
|
||||||
|
(webServer, addrs) => {
|
||||||
|
expect(webServer).toBeDefined();
|
||||||
|
expect(addrs).toBeDefined();
|
||||||
|
expect(addrs.proto).toBe('https');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
test('should fails if config is missing', async () => {
|
test('should fails if config is missing', async () => {
|
||||||
try {
|
try {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|
20
yarn.lock
20
yarn.lock
|
@ -2225,10 +2225,10 @@
|
||||||
resolved "https://registry.npmjs.org/@verdaccio/streams/-/streams-9.7.0.tgz#21d35e1c60c5dee58e54878374d3d354f06ebcdb"
|
resolved "https://registry.npmjs.org/@verdaccio/streams/-/streams-9.7.0.tgz#21d35e1c60c5dee58e54878374d3d354f06ebcdb"
|
||||||
integrity sha512-h0GvmR1sjaH/H1MOBWJkmNSCuTI7cKYoyvWlP6S1gMEgfTnpwza9sW0F6RYttfYYzaDqyk6niVL6kDre2zVGEw==
|
integrity sha512-h0GvmR1sjaH/H1MOBWJkmNSCuTI7cKYoyvWlP6S1gMEgfTnpwza9sW0F6RYttfYYzaDqyk6niVL6kDre2zVGEw==
|
||||||
|
|
||||||
"@verdaccio/types@^9.3.0":
|
"@verdaccio/types@^9.7.0":
|
||||||
version "9.5.0"
|
version "9.7.0"
|
||||||
resolved "https://registry.verdaccio.org/@verdaccio%2ftypes/-/types-9.5.0.tgz#1acd3cdebe2c8ea57dac9a0739512830e05e6bbf"
|
resolved "https://registry.npmjs.org/@verdaccio/types/-/types-9.7.0.tgz#6ec72aee7be2617c609cd736cb6e7b70cc5199c7"
|
||||||
integrity sha512-zUCkSQF0qShq/9OCEq6bZgHtz0lP0npkxXGc0Ch8P5fPiTlih1MBY5GxqM0ervMGw8ojH2mCYQ0655pKicYg1A==
|
integrity sha512-QeijEgVBVRTGyOteIl+RD4aiEbiUM1SkN7UAjZxhwns0o2YebdO+Z2iphmx0EZdo4STnWLuGSRlJexTaU/+lDQ==
|
||||||
|
|
||||||
"@verdaccio/ui-theme@1.11.0":
|
"@verdaccio/ui-theme@1.11.0":
|
||||||
version "1.11.0"
|
version "1.11.0"
|
||||||
|
@ -7138,6 +7138,11 @@ node-fetch@^2.2.0, node-fetch@^2.3.0:
|
||||||
resolved "https://registry.verdaccio.org/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
|
resolved "https://registry.verdaccio.org/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
|
||||||
integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
|
integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
|
||||||
|
|
||||||
|
node-forge@0.9.0:
|
||||||
|
version "0.9.0"
|
||||||
|
resolved "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579"
|
||||||
|
integrity sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==
|
||||||
|
|
||||||
node-gyp-build@~4.1.0:
|
node-gyp-build@~4.1.0:
|
||||||
version "4.1.1"
|
version "4.1.1"
|
||||||
resolved "https://registry.verdaccio.org/node-gyp-build/-/node-gyp-build-4.1.1.tgz#d7270b5d86717068d114cc57fff352f96d745feb"
|
resolved "https://registry.verdaccio.org/node-gyp-build/-/node-gyp-build-4.1.1.tgz#d7270b5d86717068d114cc57fff352f96d745feb"
|
||||||
|
@ -8462,6 +8467,13 @@ saxes@^3.1.9:
|
||||||
dependencies:
|
dependencies:
|
||||||
xmlchars "^2.1.1"
|
xmlchars "^2.1.1"
|
||||||
|
|
||||||
|
selfsigned@1.10.7:
|
||||||
|
version "1.10.7"
|
||||||
|
resolved "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.7.tgz#da5819fd049d5574f28e88a9bcc6dbc6e6f3906b"
|
||||||
|
integrity sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA==
|
||||||
|
dependencies:
|
||||||
|
node-forge "0.9.0"
|
||||||
|
|
||||||
semver-compare@^1.0.0:
|
semver-compare@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.verdaccio.org/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc"
|
resolved "https://registry.verdaccio.org/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc"
|
||||||
|
|
Loading…
Add table
Reference in a new issue