0
Fork 0
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:
Jian-Chen Chen (jesse) 2020-07-01 01:05:29 +08:00 committed by GitHub
parent dd9b3cff55
commit 912482a5ae
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 70 additions and 21 deletions

View file

@ -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",

View file

@ -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);

View file

@ -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

View file

@ -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"