mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2025-09-18 12:50:35 +00:00
Compare commits
101 Commits
eb2d759fd8
...
dependabot
Author | SHA1 | Date | |
---|---|---|---|
|
b9afd7ce45 | ||
|
487fa6d31b | ||
|
5b6ca1bf00 | ||
|
5039738aa3 | ||
|
4451be8f1c | ||
|
bee2fd1978 | ||
|
c8adbdfc15 | ||
|
aff4182ab8 | ||
|
8c9d2745e2 | ||
|
076d14b5e4 | ||
|
8a6d815152 | ||
|
54d463ac36 | ||
|
a23dc24021 | ||
|
4f9df893c8 | ||
|
304b38e82b | ||
|
1b0929ade6 | ||
|
ddbafb62a6 | ||
|
9a0383bc73 | ||
|
307cb94e84 | ||
|
63ae924fbc | ||
|
1710a263c0 | ||
|
1357774f21 | ||
|
5f54490d86 | ||
|
c97b8a339d | ||
|
ed1d90ee7f | ||
|
70894e55b8 | ||
|
817021a43d | ||
|
36e3449a56 | ||
|
db9f25638f | ||
|
ddd3355d95 | ||
|
aade8b42fc | ||
|
3735f3c11d | ||
|
b84762b5b9 | ||
|
953faeac15 | ||
|
c58f3f3ec9 | ||
|
0ee4d04d5f | ||
|
94f6756250 | ||
|
27e3f73854 | ||
|
d98f4b43dc | ||
|
ff3116a626 | ||
|
7047750b04 | ||
|
0792fc0768 | ||
|
9758c12ca3 | ||
|
ccd69c8867 | ||
|
23fd1fec6c | ||
|
6f04543744 | ||
|
cbb1fe44ca | ||
|
4c23f22d5b | ||
|
af5d3eccd6 | ||
|
a87283b030 | ||
|
97dbbdd60f | ||
|
ec81f2489a | ||
|
d0ec8e89aa | ||
|
9a96fbb5f4 | ||
|
a573450bb8 | ||
|
60a25ffbd5 | ||
|
7d2369b380 | ||
|
64f00e8dba | ||
|
c99143f548 | ||
|
cc4ee6919a | ||
|
8a69c65b40 | ||
|
95ee5ca958 | ||
|
40f22d30c4 | ||
|
30dfa9e3de | ||
|
b873499feb | ||
|
ef69be2036 | ||
|
7580e65dd4 | ||
|
f11dc5d7c1 | ||
|
77061a7bd6 | ||
|
b6afc19135 | ||
|
09ba400d09 | ||
|
0291cfc270 | ||
|
34267e0af9 | ||
|
f327c1e825 | ||
|
6f539979ec | ||
|
3d8079a137 | ||
|
6d6d83c0d0 | ||
|
100a4888d0 | ||
|
34a46bd733 | ||
|
7f8adc7e50 | ||
|
98d118cb74 | ||
|
4fb93542c3 | ||
|
4fe305520a | ||
|
76be31cf76 | ||
|
55dadb2004 | ||
|
d9cdb3dc2c | ||
|
0cab720f23 | ||
|
f5879dff6c | ||
|
5e66d677f1 | ||
|
18830f81b0 | ||
|
341ac65587 | ||
|
078baa255a | ||
|
bf9d9bd43b | ||
|
a394b25e61 | ||
|
1c47fc2ba4 | ||
|
312e2ab80c | ||
|
d147ccd88d | ||
|
03fd292c61 | ||
|
b09147eca8 | ||
|
c5a319cb20 | ||
|
2cee211fb0 |
15
Jenkinsfile
vendored
15
Jenkinsfile
vendored
@@ -241,12 +241,17 @@ pipeline {
|
||||
}
|
||||
steps {
|
||||
script {
|
||||
npmGithubPrComment("""Docker Image for build ${BUILD_NUMBER} is available on
|
||||
[DockerHub](https://cloud.docker.com/repository/docker/nginxproxymanager/${IMAGE}-dev)
|
||||
as `nginxproxymanager/${IMAGE}-dev:${BRANCH_LOWER}`
|
||||
npmGithubPrComment("""Docker Image for build ${BUILD_NUMBER} is available on [DockerHub](https://cloud.docker.com/repository/docker/nginxproxymanager/${IMAGE}-dev):
|
||||
```
|
||||
nginxproxymanager/${IMAGE}-dev:${BRANCH_LOWER}
|
||||
```
|
||||
|
||||
**Note:** ensure you backup your NPM instance before testing this image! Especially if there are database changes
|
||||
**Note:** this is a different docker image namespace than the official image
|
||||
> [!NOTE]
|
||||
> Ensure you backup your NPM instance before testing this image! Especially if there are database changes.
|
||||
> This is a different docker image namespace than the official image.
|
||||
|
||||
> [!WARNING]
|
||||
> Changes and additions to DNS Providers require verification by at least 2 members of the community!
|
||||
""", true)
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<p align="center">
|
||||
<img src="https://nginxproxymanager.com/github.png">
|
||||
<br><br>
|
||||
<img src="https://img.shields.io/badge/version-2.12.3-green.svg?style=for-the-badge">
|
||||
<img src="https://img.shields.io/badge/version-2.12.6-green.svg?style=for-the-badge">
|
||||
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager">
|
||||
<img src="https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge">
|
||||
</a>
|
||||
|
@@ -3,6 +3,8 @@
|
||||
const schema = require('./schema');
|
||||
const logger = require('./logger').global;
|
||||
|
||||
const IP_RANGES_FETCH_ENABLED = process.env.IP_RANGES_FETCH_ENABLED !== 'false';
|
||||
|
||||
async function appStart () {
|
||||
const migrate = require('./migrate');
|
||||
const setup = require('./setup');
|
||||
@@ -13,7 +15,16 @@ async function appStart () {
|
||||
return migrate.latest()
|
||||
.then(setup)
|
||||
.then(schema.getCompiledSchema)
|
||||
.then(internalIpRanges.fetch)
|
||||
.then(() => {
|
||||
if (IP_RANGES_FETCH_ENABLED) {
|
||||
logger.info('IP Ranges fetch is enabled');
|
||||
return internalIpRanges.fetch().catch((err) => {
|
||||
logger.error('IP Ranges fetch failed, continuing anyway:', err.message);
|
||||
});
|
||||
} else {
|
||||
logger.info('IP Ranges fetch is disabled by environment variable');
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
internalCertificate.initTimer();
|
||||
internalIpRanges.initTimer();
|
||||
|
@@ -1,5 +1,5 @@
|
||||
const _ = require('lodash');
|
||||
const fs = require('fs');
|
||||
const fs = require('node:fs');
|
||||
const batchflow = require('batchflow');
|
||||
const logger = require('../logger').access;
|
||||
const error = require('../lib/error');
|
||||
@@ -38,7 +38,7 @@ const internalAccessList = {
|
||||
.then((row) => {
|
||||
data.id = row.id;
|
||||
|
||||
let promises = [];
|
||||
const promises = [];
|
||||
|
||||
// Now add the items
|
||||
data.items.map((item) => {
|
||||
@@ -116,7 +116,7 @@ const internalAccessList = {
|
||||
.then((row) => {
|
||||
if (row.id !== data.id) {
|
||||
// Sanity check that something crazy hasn't happened
|
||||
throw new error.InternalValidationError('Access List could not be updated, IDs do not match: ' + row.id + ' !== ' + data.id);
|
||||
throw new error.InternalValidationError(`Access List could not be updated, IDs do not match: ${row.id} !== ${data.id}`);
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
@@ -135,10 +135,10 @@ const internalAccessList = {
|
||||
.then(() => {
|
||||
// Check for items and add/update/remove them
|
||||
if (typeof data.items !== 'undefined' && data.items) {
|
||||
let promises = [];
|
||||
let items_to_keep = [];
|
||||
const promises = [];
|
||||
const items_to_keep = [];
|
||||
|
||||
data.items.map(function (item) {
|
||||
data.items.map((item) => {
|
||||
if (item.password) {
|
||||
promises.push(accessListAuthModel
|
||||
.query()
|
||||
@@ -154,7 +154,7 @@ const internalAccessList = {
|
||||
}
|
||||
});
|
||||
|
||||
let query = accessListAuthModel
|
||||
const query = accessListAuthModel
|
||||
.query()
|
||||
.delete()
|
||||
.where('access_list_id', data.id);
|
||||
@@ -175,9 +175,9 @@ const internalAccessList = {
|
||||
.then(() => {
|
||||
// Check for clients and add/update/remove them
|
||||
if (typeof data.clients !== 'undefined' && data.clients) {
|
||||
let promises = [];
|
||||
const promises = [];
|
||||
|
||||
data.clients.map(function (client) {
|
||||
data.clients.map((client) => {
|
||||
if (client.address) {
|
||||
promises.push(accessListClientModel
|
||||
.query()
|
||||
@@ -190,7 +190,7 @@ const internalAccessList = {
|
||||
}
|
||||
});
|
||||
|
||||
let query = accessListClientModel
|
||||
const query = accessListClientModel
|
||||
.query()
|
||||
.delete()
|
||||
.where('access_list_id', data.id);
|
||||
@@ -249,7 +249,7 @@ const internalAccessList = {
|
||||
|
||||
return access.can('access_lists:get', data.id)
|
||||
.then((access_data) => {
|
||||
let query = accessListModel
|
||||
const query = accessListModel
|
||||
.query()
|
||||
.select('access_list.*', accessListModel.raw('COUNT(proxy_host.id) as proxy_host_count'))
|
||||
.leftJoin('proxy_host', function() {
|
||||
@@ -267,7 +267,7 @@ const internalAccessList = {
|
||||
}
|
||||
|
||||
if (typeof data.expand !== 'undefined' && data.expand !== null) {
|
||||
query.withGraphFetched('[' + data.expand.join(', ') + ']');
|
||||
query.withGraphFetched(`[${data.expand.join(', ')}]`);
|
||||
}
|
||||
|
||||
return query.then(utils.omitRow(omissions()));
|
||||
@@ -327,7 +327,7 @@ const internalAccessList = {
|
||||
// 3. reconfigure those hosts, then reload nginx
|
||||
|
||||
// set the access_list_id to zero for these items
|
||||
row.proxy_hosts.map(function (val, idx) {
|
||||
row.proxy_hosts.map((_val, idx) => {
|
||||
row.proxy_hosts[idx].access_list_id = 0;
|
||||
});
|
||||
|
||||
@@ -340,11 +340,11 @@ const internalAccessList = {
|
||||
})
|
||||
.then(() => {
|
||||
// delete the htpasswd file
|
||||
let htpasswd_file = internalAccessList.getFilename(row);
|
||||
const htpasswd_file = internalAccessList.getFilename(row);
|
||||
|
||||
try {
|
||||
fs.unlinkSync(htpasswd_file);
|
||||
} catch (err) {
|
||||
} catch (_err) {
|
||||
// do nothing
|
||||
}
|
||||
})
|
||||
@@ -374,7 +374,7 @@ const internalAccessList = {
|
||||
getAll: (access, expand, search_query) => {
|
||||
return access.can('access_lists:list')
|
||||
.then((access_data) => {
|
||||
let query = accessListModel
|
||||
const query = accessListModel
|
||||
.query()
|
||||
.select('access_list.*', accessListModel.raw('COUNT(proxy_host.id) as proxy_host_count'))
|
||||
.leftJoin('proxy_host', function() {
|
||||
@@ -393,19 +393,19 @@ const internalAccessList = {
|
||||
// Query is used for searching
|
||||
if (typeof search_query === 'string') {
|
||||
query.where(function () {
|
||||
this.where('name', 'like', '%' + search_query + '%');
|
||||
this.where('name', 'like', `%${search_query}%`);
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof expand !== 'undefined' && expand !== null) {
|
||||
query.withGraphFetched('[' + expand.join(', ') + ']');
|
||||
query.withGraphFetched(`[${expand.join(', ')}]`);
|
||||
}
|
||||
|
||||
return query.then(utils.omitRows(omissions()));
|
||||
})
|
||||
.then((rows) => {
|
||||
if (rows) {
|
||||
rows.map(function (row, idx) {
|
||||
rows.map((row, idx) => {
|
||||
if (typeof row.items !== 'undefined' && row.items) {
|
||||
rows[idx] = internalAccessList.maskItems(row);
|
||||
}
|
||||
@@ -424,7 +424,7 @@ const internalAccessList = {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
getCount: (user_id, visibility) => {
|
||||
let query = accessListModel
|
||||
const query = accessListModel
|
||||
.query()
|
||||
.count('id as count')
|
||||
.where('is_deleted', 0);
|
||||
@@ -445,7 +445,7 @@ const internalAccessList = {
|
||||
*/
|
||||
maskItems: (list) => {
|
||||
if (list && typeof list.items !== 'undefined') {
|
||||
list.items.map(function (val, idx) {
|
||||
list.items.map((val, idx) => {
|
||||
let repeat_for = 8;
|
||||
let first_char = '*';
|
||||
|
||||
@@ -468,7 +468,7 @@ const internalAccessList = {
|
||||
* @returns {String}
|
||||
*/
|
||||
getFilename: (list) => {
|
||||
return '/data/access/' + list.id;
|
||||
return `/data/access/${list.id}`;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -479,15 +479,15 @@ const internalAccessList = {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
build: (list) => {
|
||||
logger.info('Building Access file #' + list.id + ' for: ' + list.name);
|
||||
logger.info(`Building Access file #${list.id} for: ${list.name}`);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let htpasswd_file = internalAccessList.getFilename(list);
|
||||
const htpasswd_file = internalAccessList.getFilename(list);
|
||||
|
||||
// 1. remove any existing access file
|
||||
try {
|
||||
fs.unlinkSync(htpasswd_file);
|
||||
} catch (err) {
|
||||
} catch (_err) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@@ -504,14 +504,14 @@ const internalAccessList = {
|
||||
if (list.items.length) {
|
||||
return new Promise((resolve, reject) => {
|
||||
batchflow(list.items).sequential()
|
||||
.each((i, item, next) => {
|
||||
.each((_i, item, next) => {
|
||||
if (typeof item.password !== 'undefined' && item.password.length) {
|
||||
logger.info('Adding: ' + item.username);
|
||||
logger.info(`Adding: ${item.username}`);
|
||||
|
||||
utils.execFile('openssl', ['passwd', '-apr1', item.password])
|
||||
.then((res) => {
|
||||
try {
|
||||
fs.appendFileSync(htpasswd_file, item.username + ':' + res + '\n', {encoding: 'utf8'});
|
||||
fs.appendFileSync(htpasswd_file, `${item.username}:${res}\n`, {encoding: 'utf8'});
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
@@ -528,7 +528,7 @@ const internalAccessList = {
|
||||
reject(err);
|
||||
})
|
||||
.end((results) => {
|
||||
logger.success('Built Access file #' + list.id + ' for: ' + list.name);
|
||||
logger.success(`Built Access file #${list.id} for: ${list.name}`);
|
||||
resolve(results);
|
||||
});
|
||||
});
|
||||
|
@@ -1,6 +1,6 @@
|
||||
const _ = require('lodash');
|
||||
const fs = require('fs');
|
||||
const https = require('https');
|
||||
const fs = require('node:fs');
|
||||
const https = require('node:https');
|
||||
const tempWrite = require('temp-write');
|
||||
const moment = require('moment');
|
||||
const archiver = require('archiver');
|
||||
@@ -49,7 +49,7 @@ const internalCertificate = {
|
||||
processExpiringHosts: () => {
|
||||
if (!internalCertificate.intervalProcessing) {
|
||||
internalCertificate.intervalProcessing = true;
|
||||
logger.info('Renewing SSL certs expiring within ' + internalCertificate.renewBeforeExpirationBy[0] + ' ' + internalCertificate.renewBeforeExpirationBy[1] + ' ...');
|
||||
logger.info(`Renewing SSL certs expiring within ${internalCertificate.renewBeforeExpirationBy[0]} ${internalCertificate.renewBeforeExpirationBy[1]} ...`);
|
||||
|
||||
const expirationThreshold = moment().add(internalCertificate.renewBeforeExpirationBy[0], internalCertificate.renewBeforeExpirationBy[1]).format('YYYY-MM-DD HH:mm:ss');
|
||||
|
||||
@@ -70,7 +70,7 @@ const internalCertificate = {
|
||||
*/
|
||||
let sequence = Promise.resolve();
|
||||
|
||||
certificates.forEach(function (certificate) {
|
||||
certificates.forEach((certificate) => {
|
||||
sequence = sequence.then(() =>
|
||||
internalCertificate
|
||||
.renew(
|
||||
@@ -202,7 +202,7 @@ const internalCertificate = {
|
||||
.then(() => {
|
||||
// At this point, the letsencrypt cert should exist on disk.
|
||||
// Lets get the expiry date from the file and update the row silently
|
||||
return internalCertificate.getCertificateInfoFromFile('/etc/letsencrypt/live/npm-' + certificate.id + '/fullchain.pem')
|
||||
return internalCertificate.getCertificateInfoFromFile(`${internalCertificate.getLiveCertPath(certificate.id)}/fullchain.pem`)
|
||||
.then((cert_info) => {
|
||||
return certificateModel
|
||||
.query()
|
||||
@@ -263,7 +263,7 @@ const internalCertificate = {
|
||||
.then((row) => {
|
||||
if (row.id !== data.id) {
|
||||
// Sanity check that something crazy hasn't happened
|
||||
throw new error.InternalValidationError('Certificate could not be updated, IDs do not match: ' + row.id + ' !== ' + data.id);
|
||||
throw new error.InternalValidationError(`Certificate could not be updated, IDs do not match: ${row.id} !== ${data.id}`);
|
||||
}
|
||||
|
||||
return certificateModel
|
||||
@@ -308,7 +308,7 @@ const internalCertificate = {
|
||||
|
||||
return access.can('certificates:get', data.id)
|
||||
.then((access_data) => {
|
||||
let query = certificateModel
|
||||
const query = certificateModel
|
||||
.query()
|
||||
.where('is_deleted', 0)
|
||||
.andWhere('id', data.id)
|
||||
@@ -323,7 +323,7 @@ const internalCertificate = {
|
||||
}
|
||||
|
||||
if (typeof data.expand !== 'undefined' && data.expand !== null) {
|
||||
query.withGraphFetched('[' + data.expand.join(', ') + ']');
|
||||
query.withGraphFetched(`[${data.expand.join(', ')}]`);
|
||||
}
|
||||
|
||||
return query.then(utils.omitRow(omissions()));
|
||||
@@ -354,17 +354,17 @@ const internalCertificate = {
|
||||
})
|
||||
.then((certificate) => {
|
||||
if (certificate.provider === 'letsencrypt') {
|
||||
const zipDirectory = '/etc/letsencrypt/live/npm-' + data.id;
|
||||
const zipDirectory = internalCertificate.getLiveCertPath(data.id);
|
||||
|
||||
if (!fs.existsSync(zipDirectory)) {
|
||||
throw new error.ItemNotFoundError('Certificate ' + certificate.nice_name + ' does not exists');
|
||||
throw new error.ItemNotFoundError(`Certificate ${certificate.nice_name} does not exists`);
|
||||
}
|
||||
|
||||
let certFiles = fs.readdirSync(zipDirectory)
|
||||
const certFiles = fs.readdirSync(zipDirectory)
|
||||
.filter((fn) => fn.endsWith('.pem'))
|
||||
.map((fn) => fs.realpathSync(path.join(zipDirectory, fn)));
|
||||
const downloadName = 'npm-' + data.id + '-' + `${Date.now()}.zip`;
|
||||
const opName = '/tmp/' + downloadName;
|
||||
const downloadName = `npm-${data.id}-${Date.now()}.zip`;
|
||||
const opName = `/tmp/${downloadName}`;
|
||||
internalCertificate.zipFiles(certFiles, opName)
|
||||
.then(() => {
|
||||
logger.debug('zip completed : ', opName);
|
||||
@@ -392,7 +392,7 @@ const internalCertificate = {
|
||||
return new Promise((resolve, reject) => {
|
||||
source
|
||||
.map((fl) => {
|
||||
let fileName = path.basename(fl);
|
||||
const fileName = path.basename(fl);
|
||||
logger.debug(fl, 'added to certificate zip');
|
||||
archive.file(fl, { name: fileName });
|
||||
});
|
||||
@@ -462,7 +462,7 @@ const internalCertificate = {
|
||||
getAll: (access, expand, search_query) => {
|
||||
return access.can('certificates:list')
|
||||
.then((access_data) => {
|
||||
let query = certificateModel
|
||||
const query = certificateModel
|
||||
.query()
|
||||
.where('is_deleted', 0)
|
||||
.groupBy('id')
|
||||
@@ -479,12 +479,12 @@ const internalCertificate = {
|
||||
// Query is used for searching
|
||||
if (typeof search_query === 'string') {
|
||||
query.where(function () {
|
||||
this.where('nice_name', 'like', '%' + search_query + '%');
|
||||
this.where('nice_name', 'like', `%${search_query}%`);
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof expand !== 'undefined' && expand !== null) {
|
||||
query.withGraphFetched('[' + expand.join(', ') + ']');
|
||||
query.withGraphFetched(`[${expand.join(', ')}]`);
|
||||
}
|
||||
|
||||
return query.then(utils.omitRows(omissions()));
|
||||
@@ -499,7 +499,7 @@ const internalCertificate = {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
getCount: (user_id, visibility) => {
|
||||
let query = certificateModel
|
||||
const query = certificateModel
|
||||
.query()
|
||||
.count('id as count')
|
||||
.where('is_deleted', 0);
|
||||
@@ -521,7 +521,7 @@ const internalCertificate = {
|
||||
writeCustomCert: (certificate) => {
|
||||
logger.info('Writing Custom Certificate:', certificate);
|
||||
|
||||
const dir = '/data/custom_ssl/npm-' + certificate.id;
|
||||
const dir = `/data/custom_ssl/npm-${certificate.id}`;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
if (certificate.provider === 'letsencrypt') {
|
||||
@@ -531,7 +531,7 @@ const internalCertificate = {
|
||||
|
||||
let certData = certificate.meta.certificate;
|
||||
if (typeof certificate.meta.intermediate_certificate !== 'undefined') {
|
||||
certData = certData + '\n' + certificate.meta.intermediate_certificate;
|
||||
certData = `${certData}\n${certificate.meta.intermediate_certificate}`;
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -543,7 +543,7 @@ const internalCertificate = {
|
||||
return;
|
||||
}
|
||||
|
||||
fs.writeFile(dir + '/fullchain.pem', certData, function (err) {
|
||||
fs.writeFile(`${dir}/fullchain.pem`, certData, (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
@@ -553,7 +553,7 @@ const internalCertificate = {
|
||||
})
|
||||
.then(() => {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.writeFile(dir + '/privkey.pem', certificate.meta.certificate_key, function (err) {
|
||||
fs.writeFile(`${dir}/privkey.pem`, certificate.meta.certificate_key, (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
@@ -576,7 +576,6 @@ const internalCertificate = {
|
||||
return internalCertificate.create(access, {
|
||||
provider: 'letsencrypt',
|
||||
domain_names: data.domain_names,
|
||||
ssl_key_type: data.ssl_key_type,
|
||||
meta: data.meta
|
||||
});
|
||||
},
|
||||
@@ -592,7 +591,7 @@ const internalCertificate = {
|
||||
validate: (data) => {
|
||||
return new Promise((resolve) => {
|
||||
// Put file contents into an object
|
||||
let files = {};
|
||||
const files = {};
|
||||
_.map(data.files, (file, name) => {
|
||||
if (internalCertificate.allowedSslFiles.indexOf(name) !== -1) {
|
||||
files[name] = file.data.toString();
|
||||
@@ -604,7 +603,7 @@ const internalCertificate = {
|
||||
.then((files) => {
|
||||
// For each file, create a temp file and write the contents to it
|
||||
// Then test it depending on the file type
|
||||
let promises = [];
|
||||
const promises = [];
|
||||
_.map(files, (content, type) => {
|
||||
promises.push(new Promise((resolve) => {
|
||||
if (type === 'certificate_key') {
|
||||
@@ -689,11 +688,11 @@ const internalCertificate = {
|
||||
reject(new error.ValidationError('Result Validation Error: Validation timed out. This could be due to the key being passphrase-protected.'));
|
||||
}, 10000);
|
||||
utils
|
||||
.exec('openssl pkey -in ' + filepath + ' -check -noout 2>&1 ')
|
||||
.exec(`openssl pkey -in ${filepath} -check -noout 2>&1 `)
|
||||
.then((result) => {
|
||||
clearTimeout(failTimeout);
|
||||
if (!result.toLowerCase().includes('key is valid')) {
|
||||
reject(new error.ValidationError('Result Validation Error: ' + result));
|
||||
reject(new error.ValidationError(`Result Validation Error: ${result}`));
|
||||
}
|
||||
fs.unlinkSync(filepath);
|
||||
resolve(true);
|
||||
@@ -701,7 +700,7 @@ const internalCertificate = {
|
||||
.catch((err) => {
|
||||
clearTimeout(failTimeout);
|
||||
fs.unlinkSync(filepath);
|
||||
reject(new error.ValidationError('Certificate Key is not valid (' + err.message + ')', err));
|
||||
reject(new error.ValidationError(`Certificate Key is not valid (${err.message})`, err));
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -736,9 +735,9 @@ const internalCertificate = {
|
||||
* @param {Boolean} [throw_expired] Throw when the certificate is out of date
|
||||
*/
|
||||
getCertificateInfoFromFile: (certificate_file, throw_expired) => {
|
||||
let certData = {};
|
||||
const certData = {};
|
||||
|
||||
return utils.exec('openssl x509 -in ' + certificate_file + ' -subject -noout')
|
||||
return utils.execFile('openssl', ['x509', '-in', certificate_file, '-subject', '-noout'])
|
||||
.then((result) => {
|
||||
// Examples:
|
||||
// subject=CN = *.jc21.com
|
||||
@@ -746,11 +745,11 @@ const internalCertificate = {
|
||||
const regex = /(?:subject=)?[^=]+=\s+(\S+)/gim;
|
||||
const match = regex.exec(result);
|
||||
if (match && typeof match[1] !== 'undefined') {
|
||||
certData['cn'] = match[1];
|
||||
certData.cn = match[1];
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
return utils.exec('openssl x509 -in ' + certificate_file + ' -issuer -noout');
|
||||
return utils.execFile('openssl', ['x509', '-in', certificate_file, '-issuer', '-noout']);
|
||||
})
|
||||
|
||||
.then((result) => {
|
||||
@@ -761,11 +760,11 @@ const internalCertificate = {
|
||||
const regex = /^(?:issuer=)?(.*)$/gim;
|
||||
const match = regex.exec(result);
|
||||
if (match && typeof match[1] !== 'undefined') {
|
||||
certData['issuer'] = match[1];
|
||||
certData.issuer = match[1];
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
return utils.exec('openssl x509 -in ' + certificate_file + ' -dates -noout');
|
||||
return utils.execFile('openssl', ['x509', '-in', certificate_file, '-dates', '-noout']);
|
||||
})
|
||||
.then((result) => {
|
||||
// notBefore=Jul 14 04:04:29 2018 GMT
|
||||
@@ -774,7 +773,7 @@ const internalCertificate = {
|
||||
let validTo = null;
|
||||
|
||||
const lines = result.split('\n');
|
||||
lines.map(function (str) {
|
||||
lines.map((str) => {
|
||||
const regex = /^(\S+)=(.*)$/gim;
|
||||
const match = regex.exec(str.trim());
|
||||
|
||||
@@ -790,21 +789,21 @@ const internalCertificate = {
|
||||
});
|
||||
|
||||
if (!validFrom || !validTo) {
|
||||
throw new error.ValidationError('Could not determine dates from certificate: ' + result);
|
||||
throw new error.ValidationError(`Could not determine dates from certificate: ${result}`);
|
||||
}
|
||||
|
||||
if (throw_expired && validTo < parseInt(moment().format('X'), 10)) {
|
||||
throw new error.ValidationError('Certificate has expired');
|
||||
}
|
||||
|
||||
certData['dates'] = {
|
||||
certData.dates = {
|
||||
from: validFrom,
|
||||
to: validTo
|
||||
};
|
||||
|
||||
return certData;
|
||||
}).catch((err) => {
|
||||
throw new error.ValidationError('Certificate is not valid (' + err.message + ')', err);
|
||||
throw new error.ValidationError(`Certificate is not valid (${err.message})`, err);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -815,7 +814,7 @@ const internalCertificate = {
|
||||
* @param {Boolean} [remove]
|
||||
* @returns {Object}
|
||||
*/
|
||||
cleanMeta: function (meta, remove) {
|
||||
cleanMeta: (meta, remove) => {
|
||||
internalCertificate.allowedSslFiles.map((key) => {
|
||||
if (typeof meta[key] !== 'undefined' && meta[key]) {
|
||||
if (remove) {
|
||||
@@ -835,25 +834,35 @@ const internalCertificate = {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
requestLetsEncryptSsl: (certificate) => {
|
||||
logger.info('Requesting Let\'sEncrypt certificates for Cert #' + certificate.id + ': ' + certificate.domain_names.join(', '));
|
||||
logger.info(`Requesting LetsEncrypt certificates for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
|
||||
|
||||
const cmd = `${certbotCommand} certonly ` +
|
||||
`--config '${letsencryptConfig}' ` +
|
||||
`--key-type '${certificate.ssl_key_type}' ` +
|
||||
'--work-dir "/tmp/letsencrypt-lib" ' +
|
||||
'--logs-dir "/tmp/letsencrypt-log" ' +
|
||||
`--cert-name "npm-${certificate.id}" ` +
|
||||
'--agree-tos ' +
|
||||
'--authenticator webroot ' +
|
||||
`--email '${certificate.meta.letsencrypt_email}' ` +
|
||||
'--preferred-challenges "dns,http" ' +
|
||||
`--domains "${certificate.domain_names.join(',')}" ` +
|
||||
(letsencryptServer !== null ? `--server '${letsencryptServer}' ` : '') +
|
||||
(letsencryptStaging && letsencryptServer === null ? '--staging ' : '');
|
||||
const args = [
|
||||
'certonly',
|
||||
'--config',
|
||||
letsencryptConfig,
|
||||
'--work-dir',
|
||||
'/tmp/letsencrypt-lib',
|
||||
'--logs-dir',
|
||||
'/tmp/letsencrypt-log',
|
||||
'--cert-name',
|
||||
`npm-${certificate.id}`,
|
||||
'--agree-tos',
|
||||
'--authenticator',
|
||||
'webroot',
|
||||
'--email',
|
||||
certificate.meta.letsencrypt_email,
|
||||
'--preferred-challenges',
|
||||
'dns,http',
|
||||
'--domains',
|
||||
certificate.domain_names.join(','),
|
||||
];
|
||||
|
||||
logger.info('Command:', cmd);
|
||||
const adds = internalCertificate.getAdditionalCertbotArgs(certificate.id);
|
||||
args.push(...adds.args);
|
||||
|
||||
return utils.exec(cmd)
|
||||
logger.info(`Command: ${certbotCommand} ${args ? args.join(' ') : ''}`);
|
||||
|
||||
return utils.execFile(certbotCommand, args, adds.opts)
|
||||
.then((result) => {
|
||||
logger.success(result);
|
||||
return result;
|
||||
@@ -870,51 +879,48 @@ const internalCertificate = {
|
||||
requestLetsEncryptSslWithDnsChallenge: async (certificate) => {
|
||||
await certbot.installPlugin(certificate.meta.dns_provider);
|
||||
const dnsPlugin = dnsPlugins[certificate.meta.dns_provider];
|
||||
logger.info(`Requesting Let'sEncrypt certificates via ${dnsPlugin.name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
|
||||
logger.info(`Requesting LetsEncrypt certificates via ${dnsPlugin.name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
|
||||
|
||||
const credentialsLocation = '/etc/letsencrypt/credentials/credentials-' + certificate.id;
|
||||
const credentialsLocation = `/etc/letsencrypt/credentials/credentials-${certificate.id}`;
|
||||
fs.mkdirSync('/etc/letsencrypt/credentials', { recursive: true });
|
||||
fs.writeFileSync(credentialsLocation, certificate.meta.dns_provider_credentials, {mode: 0o600});
|
||||
|
||||
// Whether the plugin has a --<name>-credentials argument
|
||||
const hasConfigArg = certificate.meta.dns_provider !== 'route53';
|
||||
|
||||
let mainCmd = certbotCommand + ' certonly ' +
|
||||
`--config '${letsencryptConfig}' ` +
|
||||
`--key-type '${certificate.ssl_key_type}' ` +
|
||||
'--work-dir "/tmp/letsencrypt-lib" ' +
|
||||
'--logs-dir "/tmp/letsencrypt-log" ' +
|
||||
`--cert-name 'npm-${certificate.id}' ` +
|
||||
'--agree-tos ' +
|
||||
`--email '${certificate.meta.letsencrypt_email}' ` +
|
||||
`--domains '${certificate.domain_names.join(',')}' ` +
|
||||
`--authenticator '${dnsPlugin.full_plugin_name}' ` +
|
||||
(
|
||||
hasConfigArg
|
||||
? `--${dnsPlugin.full_plugin_name}-credentials '${credentialsLocation}' `
|
||||
: ''
|
||||
) +
|
||||
(
|
||||
certificate.meta.propagation_seconds !== undefined
|
||||
? `--${dnsPlugin.full_plugin_name}-propagation-seconds '${certificate.meta.propagation_seconds}' `
|
||||
: ''
|
||||
) +
|
||||
(letsencryptServer !== null ? `--server '${letsencryptServer}' ` : '') +
|
||||
(letsencryptStaging && letsencryptServer === null ? '--staging ' : '');
|
||||
const args = [
|
||||
'certonly',
|
||||
'--config',
|
||||
letsencryptConfig,
|
||||
'--work-dir',
|
||||
'/tmp/letsencrypt-lib',
|
||||
'--logs-dir',
|
||||
'/tmp/letsencrypt-log',
|
||||
'--cert-name',
|
||||
`npm-${certificate.id}`,
|
||||
'--agree-tos',
|
||||
'--email',
|
||||
certificate.meta.letsencrypt_email,
|
||||
'--domains',
|
||||
certificate.domain_names.join(','),
|
||||
'--authenticator',
|
||||
dnsPlugin.full_plugin_name,
|
||||
];
|
||||
|
||||
// Prepend the path to the credentials file as an environment variable
|
||||
if (certificate.meta.dns_provider === 'route53') {
|
||||
mainCmd = 'AWS_CONFIG_FILE=\'' + credentialsLocation + '\' ' + mainCmd;
|
||||
if (hasConfigArg) {
|
||||
args.push(`--${dnsPlugin.full_plugin_name}-credentials`, credentialsLocation);
|
||||
}
|
||||
if (certificate.meta.propagation_seconds !== undefined) {
|
||||
args.push(`--${dnsPlugin.full_plugin_name}-propagation-seconds`, certificate.meta.propagation_seconds.toString());
|
||||
}
|
||||
|
||||
if (certificate.meta.dns_provider === 'duckdns') {
|
||||
mainCmd = mainCmd + ' --dns-duckdns-no-txt-restore';
|
||||
}
|
||||
const adds = internalCertificate.getAdditionalCertbotArgs(certificate.id, certificate.meta.dns_provider);
|
||||
args.push(...adds.args);
|
||||
|
||||
logger.info('Command:', mainCmd);
|
||||
logger.info(`Command: ${certbotCommand} ${args ? args.join(' ') : ''}`);
|
||||
|
||||
try {
|
||||
const result = await utils.exec(mainCmd);
|
||||
const result = await utils.execFile(certbotCommand, args, adds.opts);
|
||||
logger.info(result);
|
||||
return result;
|
||||
} catch (err) {
|
||||
@@ -942,7 +948,7 @@ const internalCertificate = {
|
||||
|
||||
return renewMethod(certificate)
|
||||
.then(() => {
|
||||
return internalCertificate.getCertificateInfoFromFile('/etc/letsencrypt/live/npm-' + certificate.id + '/fullchain.pem');
|
||||
return internalCertificate.getCertificateInfoFromFile(`${internalCertificate.getLiveCertPath(certificate.id)}/fullchain.pem`);
|
||||
})
|
||||
.then((cert_info) => {
|
||||
return certificateModel
|
||||
@@ -974,23 +980,31 @@ const internalCertificate = {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
renewLetsEncryptSsl: (certificate) => {
|
||||
logger.info('Renewing Let\'sEncrypt certificates for Cert #' + certificate.id + ': ' + certificate.domain_names.join(', '));
|
||||
logger.info(`Renewing LetsEncrypt certificates for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
|
||||
|
||||
const cmd = certbotCommand + ' renew --force-renewal ' +
|
||||
`--config '${letsencryptConfig}' ` +
|
||||
`--key-type '${certificate.ssl_key_type}' ` +
|
||||
'--work-dir "/tmp/letsencrypt-lib" ' +
|
||||
'--logs-dir "/tmp/letsencrypt-log" ' +
|
||||
`--cert-name 'npm-${certificate.id}' ` +
|
||||
'--preferred-challenges "dns,http" ' +
|
||||
'--no-random-sleep-on-renew ' +
|
||||
'--disable-hook-validation ' +
|
||||
(letsencryptServer !== null ? `--server '${letsencryptServer}' ` : '') +
|
||||
(letsencryptStaging && letsencryptServer === null ? '--staging ' : '');
|
||||
const args = [
|
||||
'renew',
|
||||
'--force-renewal',
|
||||
'--config',
|
||||
letsencryptConfig,
|
||||
'--work-dir',
|
||||
'/tmp/letsencrypt-lib',
|
||||
'--logs-dir',
|
||||
'/tmp/letsencrypt-log',
|
||||
'--cert-name',
|
||||
`npm-${certificate.id}`,
|
||||
'--preferred-challenges',
|
||||
'dns,http',
|
||||
'--no-random-sleep-on-renew',
|
||||
'--disable-hook-validation',
|
||||
];
|
||||
|
||||
logger.info('Command:', cmd);
|
||||
const adds = internalCertificate.getAdditionalCertbotArgs(certificate.id, certificate.meta.dns_provider);
|
||||
args.push(...adds.args);
|
||||
|
||||
return utils.exec(cmd)
|
||||
logger.info(`Command: ${certbotCommand} ${args ? args.join(' ') : ''}`);
|
||||
|
||||
return utils.execFile(certbotCommand, args, adds.opts)
|
||||
.then((result) => {
|
||||
logger.info(result);
|
||||
return result;
|
||||
@@ -1008,28 +1022,29 @@ const internalCertificate = {
|
||||
throw Error(`Unknown DNS provider '${certificate.meta.dns_provider}'`);
|
||||
}
|
||||
|
||||
logger.info(`Renewing Let'sEncrypt certificates via ${dnsPlugin.name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
|
||||
logger.info(`Renewing LetsEncrypt certificates via ${dnsPlugin.name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
|
||||
|
||||
let mainCmd = certbotCommand + ' renew --force-renewal ' +
|
||||
`--config "${letsencryptConfig}" ` +
|
||||
`--key-type '${certificate.ssl_key_type}' ` +
|
||||
'--work-dir "/tmp/letsencrypt-lib" ' +
|
||||
'--logs-dir "/tmp/letsencrypt-log" ' +
|
||||
`--cert-name 'npm-${certificate.id}' ` +
|
||||
'--disable-hook-validation ' +
|
||||
'--no-random-sleep-on-renew ' +
|
||||
(letsencryptServer !== null ? `--server '${letsencryptServer}' ` : '') +
|
||||
(letsencryptStaging && letsencryptServer === null ? '--staging ' : '');
|
||||
const args = [
|
||||
'renew',
|
||||
'--force-renewal',
|
||||
'--config',
|
||||
letsencryptConfig,
|
||||
'--work-dir',
|
||||
'/tmp/letsencrypt-lib',
|
||||
'--logs-dir',
|
||||
'/tmp/letsencrypt-log',
|
||||
'--cert-name',
|
||||
`npm-${certificate.id}`,
|
||||
'--disable-hook-validation',
|
||||
'--no-random-sleep-on-renew',
|
||||
];
|
||||
|
||||
// Prepend the path to the credentials file as an environment variable
|
||||
if (certificate.meta.dns_provider === 'route53') {
|
||||
const credentialsLocation = '/etc/letsencrypt/credentials/credentials-' + certificate.id;
|
||||
mainCmd = 'AWS_CONFIG_FILE=\'' + credentialsLocation + '\' ' + mainCmd;
|
||||
}
|
||||
const adds = internalCertificate.getAdditionalCertbotArgs(certificate.id, certificate.meta.dns_provider);
|
||||
args.push(...adds.args);
|
||||
|
||||
logger.info('Command:', mainCmd);
|
||||
logger.info(`Command: ${certbotCommand} ${args ? args.join(' ') : ''}`);
|
||||
|
||||
return utils.exec(mainCmd)
|
||||
return utils.execFile(certbotCommand, args, adds.opts)
|
||||
.then(async (result) => {
|
||||
logger.info(result);
|
||||
return result;
|
||||
@@ -1042,26 +1057,29 @@ const internalCertificate = {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
revokeLetsEncryptSsl: (certificate, throw_errors) => {
|
||||
logger.info('Revoking Let\'sEncrypt certificates for Cert #' + certificate.id + ': ' + certificate.domain_names.join(', '));
|
||||
logger.info(`Revoking LetsEncrypt certificates for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
|
||||
|
||||
const mainCmd = certbotCommand + ' revoke ' +
|
||||
`--config '${letsencryptConfig}' ` +
|
||||
`--key-type '${certificate.ssl_key_type}' ` +
|
||||
'--work-dir "/tmp/letsencrypt-lib" ' +
|
||||
'--logs-dir "/tmp/letsencrypt-log" ' +
|
||||
`--cert-path '/etc/letsencrypt/live/npm-${certificate.id}/fullchain.pem' ` +
|
||||
'--delete-after-revoke ' +
|
||||
(letsencryptServer !== null ? `--server '${letsencryptServer}' ` : '') +
|
||||
(letsencryptStaging && letsencryptServer === null ? '--staging ' : '');
|
||||
const args = [
|
||||
'revoke',
|
||||
'--config',
|
||||
letsencryptConfig,
|
||||
'--work-dir',
|
||||
'/tmp/letsencrypt-lib',
|
||||
'--logs-dir',
|
||||
'/tmp/letsencrypt-log',
|
||||
'--cert-path',
|
||||
`${internalCertificate.getLiveCertPath(certificate.id)}/fullchain.pem`,
|
||||
'--delete-after-revoke',
|
||||
];
|
||||
|
||||
// Don't fail command if file does not exist
|
||||
const delete_credentialsCmd = `rm -f '/etc/letsencrypt/credentials/credentials-${certificate.id}' || true`;
|
||||
const adds = internalCertificate.getAdditionalCertbotArgs(certificate.id);
|
||||
args.push(...adds.args);
|
||||
|
||||
logger.info('Command:', mainCmd + '; ' + delete_credentialsCmd);
|
||||
logger.info(`Command: ${certbotCommand} ${args ? args.join(' ') : ''}`);
|
||||
|
||||
return utils.exec(mainCmd)
|
||||
return utils.execFile(certbotCommand, args, adds.opts)
|
||||
.then(async (result) => {
|
||||
await utils.exec(delete_credentialsCmd);
|
||||
await utils.exec(`rm -f '/etc/letsencrypt/credentials/credentials-${certificate.id}' || true`);
|
||||
logger.info(result);
|
||||
return result;
|
||||
})
|
||||
@@ -1079,9 +1097,8 @@ const internalCertificate = {
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
hasLetsEncryptSslCerts: (certificate) => {
|
||||
const letsencryptPath = '/etc/letsencrypt/live/npm-' + certificate.id;
|
||||
|
||||
return fs.existsSync(letsencryptPath + '/fullchain.pem') && fs.existsSync(letsencryptPath + '/privkey.pem');
|
||||
const letsencryptPath = internalCertificate.getLiveCertPath(certificate.id);
|
||||
return fs.existsSync(`${letsencryptPath}/fullchain.pem`) && fs.existsSync(`${letsencryptPath}/privkey.pem`);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -1093,7 +1110,7 @@ const internalCertificate = {
|
||||
*/
|
||||
disableInUseHosts: (in_use_result) => {
|
||||
if (in_use_result.total_count) {
|
||||
let promises = [];
|
||||
const promises = [];
|
||||
|
||||
if (in_use_result.proxy_hosts.length) {
|
||||
promises.push(internalNginx.bulkDeleteConfigs('proxy_host', in_use_result.proxy_hosts));
|
||||
@@ -1123,7 +1140,7 @@ const internalCertificate = {
|
||||
*/
|
||||
enableInUseHosts: (in_use_result) => {
|
||||
if (in_use_result.total_count) {
|
||||
let promises = [];
|
||||
const promises = [];
|
||||
|
||||
if (in_use_result.proxy_hosts.length) {
|
||||
promises.push(internalNginx.bulkGenerateConfigs('proxy_host', in_use_result.proxy_hosts));
|
||||
@@ -1156,12 +1173,12 @@ const internalCertificate = {
|
||||
|
||||
// Create a test challenge file
|
||||
const testChallengeDir = '/data/letsencrypt-acme-challenge/.well-known/acme-challenge';
|
||||
const testChallengeFile = testChallengeDir + '/test-challenge';
|
||||
const testChallengeFile = `${testChallengeDir}/test-challenge`;
|
||||
fs.mkdirSync(testChallengeDir, {recursive: true});
|
||||
fs.writeFileSync(testChallengeFile, 'Success', {encoding: 'utf8'});
|
||||
|
||||
async function performTestForDomain (domain) {
|
||||
logger.info('Testing http challenge for ' + domain);
|
||||
logger.info(`Testing http challenge for ${domain}`);
|
||||
const url = `http://${domain}/.well-known/acme-challenge/test-challenge`;
|
||||
const formBody = `method=G&url=${encodeURI(url)}&bodytype=T&requestbody=&headername=User-Agent&headervalue=None&locationid=1&ch=false&cc=false`;
|
||||
const options = {
|
||||
@@ -1175,13 +1192,16 @@ const internalCertificate = {
|
||||
|
||||
const result = await new Promise((resolve) => {
|
||||
|
||||
const req = https.request('https://www.site24x7.com/tools/restapi-tester', options, function (res) {
|
||||
const req = https.request('https://www.site24x7.com/tools/restapi-tester', options, (res) => {
|
||||
let responseBody = '';
|
||||
|
||||
res.on('data', (chunk) => responseBody = responseBody + chunk);
|
||||
res.on('end', function () {
|
||||
res.on('data', (chunk) => {
|
||||
responseBody = responseBody + chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const parsedBody = JSON.parse(responseBody + '');
|
||||
const parsedBody = JSON.parse(`${responseBody}`);
|
||||
if (res.statusCode !== 200) {
|
||||
logger.warn(`Failed to test HTTP challenge for domain ${domain} because HTTP status code ${res.statusCode} was returned: ${parsedBody.message}`);
|
||||
resolve(undefined);
|
||||
@@ -1202,7 +1222,7 @@ const internalCertificate = {
|
||||
// Make sure to write the request body.
|
||||
req.write(formBody);
|
||||
req.end();
|
||||
req.on('error', function (e) { logger.warn(`Failed to test HTTP challenge for domain ${domain}`, e);
|
||||
req.on('error', (e) => { logger.warn(`Failed to test HTTP challenge for domain ${domain}`, e);
|
||||
resolve(undefined); });
|
||||
});
|
||||
|
||||
@@ -1244,6 +1264,34 @@ const internalCertificate = {
|
||||
fs.unlinkSync(testChallengeFile);
|
||||
|
||||
return results;
|
||||
},
|
||||
|
||||
getAdditionalCertbotArgs: (certificate_id, dns_provider) => {
|
||||
const args = [];
|
||||
if (letsencryptServer !== null) {
|
||||
args.push('--server', letsencryptServer);
|
||||
}
|
||||
if (letsencryptStaging && letsencryptServer === null) {
|
||||
args.push('--staging');
|
||||
}
|
||||
|
||||
// For route53, add the credentials file as an environment variable,
|
||||
// inheriting the process env
|
||||
const opts = {};
|
||||
if (certificate_id && dns_provider === 'route53') {
|
||||
opts.env = process.env;
|
||||
opts.env.AWS_CONFIG_FILE = `/etc/letsencrypt/credentials/credentials-${certificate_id}`;
|
||||
}
|
||||
|
||||
if (dns_provider === 'duckdns') {
|
||||
args.push('--dns-duckdns-no-txt-restore');
|
||||
}
|
||||
|
||||
return {args: args, opts: opts};
|
||||
},
|
||||
|
||||
getLiveCertPath: (certificate_id) => {
|
||||
return `/etc/letsencrypt/live/npm-${certificate_id}`;
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -229,32 +229,8 @@ const internalHost = {
|
||||
}
|
||||
|
||||
return response;
|
||||
},
|
||||
|
||||
/**
|
||||
* Internal use only, checks to see if the there is another default server record
|
||||
*
|
||||
* @param {String} hostname
|
||||
* @param {String} [ignore_type] 'proxy', 'redirection', 'dead'
|
||||
* @param {Integer} [ignore_id] Must be supplied if type was also supplied
|
||||
* @returns {Promise}
|
||||
*/
|
||||
checkDefaultServerNotExist: function (hostname) {
|
||||
let promises = proxyHostModel
|
||||
.query()
|
||||
.where('default_server', true)
|
||||
.andWhere('domain_names', 'not like', '%' + hostname + '%');
|
||||
|
||||
|
||||
return Promise.resolve(promises)
|
||||
.then((promises_results) => {
|
||||
if (promises_results.length > 0){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = internalHost;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
const _ = require('lodash');
|
||||
const fs = require('fs');
|
||||
const fs = require('node:fs');
|
||||
const logger = require('../logger').nginx;
|
||||
const config = require('../lib/config');
|
||||
const utils = require('../lib/utils');
|
||||
@@ -57,9 +57,9 @@ const internalNginx = {
|
||||
// It will always look like this:
|
||||
// nginx: [alert] could not open error log file: open() "/var/log/nginx/error.log" failed (6: No such device or address)
|
||||
|
||||
let valid_lines = [];
|
||||
let err_lines = err.message.split('\n');
|
||||
err_lines.map(function (line) {
|
||||
const valid_lines = [];
|
||||
const err_lines = err.message.split('\n');
|
||||
err_lines.map((line) => {
|
||||
if (line.indexOf('/var/log/nginx/error.log') === -1) {
|
||||
valid_lines.push(line);
|
||||
}
|
||||
@@ -105,7 +105,7 @@ const internalNginx = {
|
||||
logger.info('Testing Nginx configuration');
|
||||
}
|
||||
|
||||
return utils.exec('/usr/sbin/nginx -t -g "error_log off;"');
|
||||
return utils.execFile('/usr/sbin/nginx', ['-t', '-g', 'error_log off;']);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -115,7 +115,7 @@ const internalNginx = {
|
||||
return internalNginx.test()
|
||||
.then(() => {
|
||||
logger.info('Reloading Nginx');
|
||||
return utils.exec('/usr/sbin/nginx -s reload');
|
||||
return utils.execFile('/usr/sbin/nginx', ['-s', 'reload']);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -128,7 +128,7 @@ const internalNginx = {
|
||||
if (host_type === 'default') {
|
||||
return '/data/nginx/default_host/site.conf';
|
||||
}
|
||||
return '/data/nginx/' + internalNginx.getFileFriendlyHostType(host_type) + '/' + host_id + '.conf';
|
||||
return `/data/nginx/${internalNginx.getFileFriendlyHostType(host_type)}/${host_id}.conf`;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -141,7 +141,7 @@ const internalNginx = {
|
||||
let template;
|
||||
|
||||
try {
|
||||
template = fs.readFileSync(__dirname + '/../templates/_location.conf', {encoding: 'utf8'});
|
||||
template = fs.readFileSync(`${__dirname}/../templates/_location.conf`, {encoding: 'utf8'});
|
||||
} catch (err) {
|
||||
reject(new error.ConfigurationError(err.message));
|
||||
return;
|
||||
@@ -152,7 +152,7 @@ const internalNginx = {
|
||||
|
||||
const locationRendering = async () => {
|
||||
for (let i = 0; i < host.locations.length; i++) {
|
||||
let locationCopy = Object.assign({}, {access_list_id: host.access_list_id}, {certificate_id: host.certificate_id},
|
||||
const locationCopy = Object.assign({}, {access_list_id: host.access_list_id}, {certificate_id: host.certificate_id},
|
||||
{ssl_forced: host.ssl_forced}, {caching_enabled: host.caching_enabled}, {block_exploits: host.block_exploits},
|
||||
{allow_websocket_upgrade: host.allow_websocket_upgrade}, {http2_support: host.http2_support},
|
||||
{hsts_enabled: host.hsts_enabled}, {hsts_subdomains: host.hsts_subdomains}, {access_list: host.access_list},
|
||||
@@ -183,21 +183,21 @@ const internalNginx = {
|
||||
*/
|
||||
generateConfig: (host_type, host_row) => {
|
||||
// Prevent modifying the original object:
|
||||
let host = JSON.parse(JSON.stringify(host_row));
|
||||
const host = JSON.parse(JSON.stringify(host_row));
|
||||
const nice_host_type = internalNginx.getFileFriendlyHostType(host_type);
|
||||
|
||||
if (config.debug()) {
|
||||
logger.info('Generating ' + nice_host_type + ' Config:', JSON.stringify(host, null, 2));
|
||||
logger.info(`Generating ${nice_host_type} Config:`, JSON.stringify(host, null, 2));
|
||||
}
|
||||
|
||||
const renderEngine = utils.getRenderEngine();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let template = null;
|
||||
let filename = internalNginx.getConfigName(nice_host_type, host.id);
|
||||
const filename = internalNginx.getConfigName(nice_host_type, host.id);
|
||||
|
||||
try {
|
||||
template = fs.readFileSync(__dirname + '/../templates/' + nice_host_type + '.conf', {encoding: 'utf8'});
|
||||
template = fs.readFileSync(`${__dirname}/../templates/${nice_host_type}.conf`, {encoding: 'utf8'});
|
||||
} catch (err) {
|
||||
reject(new error.ConfigurationError(err.message));
|
||||
return;
|
||||
@@ -252,7 +252,7 @@ const internalNginx = {
|
||||
})
|
||||
.catch((err) => {
|
||||
if (config.debug()) {
|
||||
logger.warn('Could not write ' + filename + ':', err.message);
|
||||
logger.warn(`Could not write ${filename}:`, err.message);
|
||||
}
|
||||
|
||||
reject(new error.ConfigurationError(err.message));
|
||||
@@ -278,10 +278,10 @@ const internalNginx = {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let template = null;
|
||||
let filename = '/data/nginx/temp/letsencrypt_' + certificate.id + '.conf';
|
||||
const filename = `/data/nginx/temp/letsencrypt_${certificate.id}.conf`;
|
||||
|
||||
try {
|
||||
template = fs.readFileSync(__dirname + '/../templates/letsencrypt-request.conf', {encoding: 'utf8'});
|
||||
template = fs.readFileSync(`${__dirname}/../templates/letsencrypt-request.conf`, {encoding: 'utf8'});
|
||||
} catch (err) {
|
||||
reject(new error.ConfigurationError(err.message));
|
||||
return;
|
||||
@@ -302,7 +302,7 @@ const internalNginx = {
|
||||
})
|
||||
.catch((err) => {
|
||||
if (config.debug()) {
|
||||
logger.warn('Could not write ' + filename + ':', err.message);
|
||||
logger.warn(`Could not write ${filename}:`, err.message);
|
||||
}
|
||||
|
||||
reject(new error.ConfigurationError(err.message));
|
||||
@@ -316,7 +316,7 @@ const internalNginx = {
|
||||
* @param {String} filename
|
||||
*/
|
||||
deleteFile: (filename) => {
|
||||
logger.debug('Deleting file: ' + filename);
|
||||
logger.debug(`Deleting file: ${filename}`);
|
||||
try {
|
||||
fs.unlinkSync(filename);
|
||||
} catch (err) {
|
||||
@@ -330,7 +330,7 @@ const internalNginx = {
|
||||
* @returns String
|
||||
*/
|
||||
getFileFriendlyHostType: (host_type) => {
|
||||
return host_type.replace(new RegExp('-', 'g'), '_');
|
||||
return host_type.replace(/-/g, '_');
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -340,7 +340,7 @@ const internalNginx = {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
deleteLetsEncryptRequestConfig: (certificate) => {
|
||||
const config_file = '/data/nginx/temp/letsencrypt_' + certificate.id + '.conf';
|
||||
const config_file = `/data/nginx/temp/letsencrypt_${certificate.id}.conf`;
|
||||
return new Promise((resolve/*, reject*/) => {
|
||||
internalNginx.deleteFile(config_file);
|
||||
resolve();
|
||||
@@ -355,7 +355,7 @@ const internalNginx = {
|
||||
*/
|
||||
deleteConfig: (host_type, host, delete_err_file) => {
|
||||
const config_file = internalNginx.getConfigName(internalNginx.getFileFriendlyHostType(host_type), typeof host === 'undefined' ? 0 : host.id);
|
||||
const config_file_err = config_file + '.err';
|
||||
const config_file_err = `${config_file}.err`;
|
||||
|
||||
return new Promise((resolve/*, reject*/) => {
|
||||
internalNginx.deleteFile(config_file);
|
||||
@@ -373,7 +373,7 @@ const internalNginx = {
|
||||
*/
|
||||
renameConfigAsError: (host_type, host) => {
|
||||
const config_file = internalNginx.getConfigName(internalNginx.getFileFriendlyHostType(host_type), typeof host === 'undefined' ? 0 : host.id);
|
||||
const config_file_err = config_file + '.err';
|
||||
const config_file_err = `${config_file}.err`;
|
||||
|
||||
return new Promise((resolve/*, reject*/) => {
|
||||
fs.unlink(config_file, () => {
|
||||
@@ -392,8 +392,8 @@ const internalNginx = {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
bulkGenerateConfigs: (host_type, hosts) => {
|
||||
let promises = [];
|
||||
hosts.map(function (host) {
|
||||
const promises = [];
|
||||
hosts.map((host) => {
|
||||
promises.push(internalNginx.generateConfig(host_type, host));
|
||||
});
|
||||
|
||||
@@ -406,8 +406,8 @@ const internalNginx = {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
bulkDeleteConfigs: (host_type, hosts) => {
|
||||
let promises = [];
|
||||
hosts.map(function (host) {
|
||||
const promises = [];
|
||||
hosts.map((host) => {
|
||||
promises.push(internalNginx.deleteConfig(host_type, host, true));
|
||||
});
|
||||
|
||||
@@ -418,14 +418,12 @@ const internalNginx = {
|
||||
* @param {string} config
|
||||
* @returns {boolean}
|
||||
*/
|
||||
advancedConfigHasDefaultLocation: function (cfg) {
|
||||
return !!cfg.match(/^(?:.*;)?\s*?location\s*?\/\s*?{/im);
|
||||
},
|
||||
advancedConfigHasDefaultLocation: (cfg) => !!cfg.match(/^(?:.*;)?\s*?location\s*?\/\s*?{/im),
|
||||
|
||||
/**
|
||||
* @returns {boolean}
|
||||
*/
|
||||
ipv6Enabled: function () {
|
||||
ipv6Enabled: () => {
|
||||
if (typeof process.env.DISABLE_IPV6 !== 'undefined') {
|
||||
const disabled = process.env.DISABLE_IPV6.toLowerCase();
|
||||
return !(disabled === 'on' || disabled === 'true' || disabled === '1' || disabled === 'yes');
|
||||
|
@@ -44,22 +44,6 @@ const internalProxyHost = {
|
||||
});
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
// Get a list of the domain names and check each of them against default records
|
||||
if (data.default_server){
|
||||
if (data.domain_names.length > 1) {
|
||||
throw new error.ValidationError('Default server cant be set for multiple domain!');
|
||||
}
|
||||
|
||||
return internalHost
|
||||
.checkDefaultServerNotExist(data.domain_names[0])
|
||||
.then((result) => {
|
||||
if (!result){
|
||||
throw new error.ValidationError('One default server already exists');
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
// At this point the domains should have been checked
|
||||
data.owner_user_id = access.token.getUserId(1);
|
||||
@@ -157,22 +141,6 @@ const internalProxyHost = {
|
||||
});
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
// Get a list of the domain names and check each of them against default records
|
||||
if (data.default_server){
|
||||
if (data.domain_names.length > 1) {
|
||||
throw new error.ValidationError('Default server cant be set for multiple domain!');
|
||||
}
|
||||
|
||||
return internalHost
|
||||
.checkDefaultServerNotExist(data.domain_names[0])
|
||||
.then((result) => {
|
||||
if (!result){
|
||||
throw new error.ValidationError('One default server already exists');
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
return internalProxyHost.get(access, {id: data.id});
|
||||
})
|
||||
@@ -185,7 +153,6 @@ const internalProxyHost = {
|
||||
if (create_certificate) {
|
||||
return internalCertificate.createQuickCertificate(access, {
|
||||
domain_names: data.domain_names || row.domain_names,
|
||||
ssl_key_type: data.ssl_key_type || row.ssl_key_type,
|
||||
meta: _.assign({}, row.meta, data.meta)
|
||||
})
|
||||
.then((cert) => {
|
||||
|
@@ -369,7 +369,7 @@ const internalStream = {
|
||||
.where('is_deleted', 0)
|
||||
.groupBy('id')
|
||||
.allowGraph('[owner,certificate]')
|
||||
.orderByRaw('CAST(incoming_port AS INTEGER) ASC');
|
||||
.orderBy('incoming_port', 'ASC');
|
||||
|
||||
if (access_data.permission_visibility !== 'all') {
|
||||
query.andWhere('owner_user_id', access.token.getUserId(1));
|
||||
|
@@ -11,7 +11,7 @@ const certbot = {
|
||||
/**
|
||||
* @param {array} pluginKeys
|
||||
*/
|
||||
installPlugins: async function (pluginKeys) {
|
||||
installPlugins: async (pluginKeys) => {
|
||||
let hasErrors = false;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -21,7 +21,7 @@ const certbot = {
|
||||
}
|
||||
|
||||
batchflow(pluginKeys).sequential()
|
||||
.each((i, pluginKey, next) => {
|
||||
.each((_i, pluginKey, next) => {
|
||||
certbot.installPlugin(pluginKey)
|
||||
.then(() => {
|
||||
next();
|
||||
@@ -51,7 +51,7 @@ const certbot = {
|
||||
* @param {string} pluginKey
|
||||
* @returns {Object}
|
||||
*/
|
||||
installPlugin: async function (pluginKey) {
|
||||
installPlugin: async (pluginKey) => {
|
||||
if (typeof dnsPlugins[pluginKey] === 'undefined') {
|
||||
// throw Error(`Certbot plugin ${pluginKey} not found`);
|
||||
throw new error.ItemNotFoundError(pluginKey);
|
||||
@@ -63,8 +63,15 @@ const certbot = {
|
||||
plugin.version = plugin.version.replace(/{{certbot-version}}/g, CERTBOT_VERSION_REPLACEMENT);
|
||||
plugin.dependencies = plugin.dependencies.replace(/{{certbot-version}}/g, CERTBOT_VERSION_REPLACEMENT);
|
||||
|
||||
const cmd = '. /opt/certbot/bin/activate && pip install --no-cache-dir ' + plugin.dependencies + ' ' + plugin.package_name + plugin.version + ' ' + ' && deactivate';
|
||||
return utils.exec(cmd)
|
||||
// SETUPTOOLS_USE_DISTUTILS is required for certbot plugins to install correctly
|
||||
// in new versions of Python
|
||||
let env = Object.assign({}, process.env, {SETUPTOOLS_USE_DISTUTILS: 'stdlib'});
|
||||
if (typeof plugin.env === 'object') {
|
||||
env = Object.assign(env, plugin.env);
|
||||
}
|
||||
|
||||
const cmd = `. /opt/certbot/bin/activate && pip install --no-cache-dir ${plugin.dependencies} ${plugin.package_name}${plugin.version} && deactivate`;
|
||||
return utils.exec(cmd, {env})
|
||||
.then((result) => {
|
||||
logger.complete(`Installed ${pluginKey}`);
|
||||
return result;
|
||||
|
@@ -1,13 +1,13 @@
|
||||
const _ = require('lodash');
|
||||
const exec = require('child_process').exec;
|
||||
const execFile = require('child_process').execFile;
|
||||
const exec = require('node:child_process').exec;
|
||||
const execFile = require('node:child_process').execFile;
|
||||
const { Liquid } = require('liquidjs');
|
||||
const logger = require('../logger').global;
|
||||
const error = require('./error');
|
||||
|
||||
module.exports = {
|
||||
|
||||
exec: async function(cmd, options = {}) {
|
||||
exec: async (cmd, options = {}) => {
|
||||
logger.debug('CMD:', cmd);
|
||||
|
||||
const { stdout, stderr } = await new Promise((resolve, reject) => {
|
||||
@@ -29,15 +29,19 @@ module.exports = {
|
||||
/**
|
||||
* @param {String} cmd
|
||||
* @param {Array} args
|
||||
* @param {Object|undefined} options
|
||||
* @returns {Promise}
|
||||
*/
|
||||
execFile: function (cmd, args) {
|
||||
// logger.debug('CMD: ' + cmd + ' ' + (args ? args.join(' ') : ''));
|
||||
execFile: (cmd, args, options) => {
|
||||
logger.debug(`CMD: ${cmd} ${args ? args.join(' ') : ''}`);
|
||||
if (typeof options === 'undefined') {
|
||||
options = {};
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
execFile(cmd, args, function (err, stdout, /*stderr*/) {
|
||||
execFile(cmd, args, options, (err, stdout, stderr) => {
|
||||
if (err && typeof err === 'object') {
|
||||
reject(err);
|
||||
reject(new error.CommandError(stderr, 1, err));
|
||||
} else {
|
||||
resolve(stdout.trim());
|
||||
}
|
||||
@@ -51,7 +55,7 @@ module.exports = {
|
||||
* @param {Array} omissions
|
||||
* @returns {Function}
|
||||
*/
|
||||
omitRow: function (omissions) {
|
||||
omitRow: (omissions) => {
|
||||
/**
|
||||
* @param {Object} row
|
||||
* @returns {Object}
|
||||
@@ -67,7 +71,7 @@ module.exports = {
|
||||
* @param {Array} omissions
|
||||
* @returns {Function}
|
||||
*/
|
||||
omitRows: function (omissions) {
|
||||
omitRows: (omissions) => {
|
||||
/**
|
||||
* @param {Array} rows
|
||||
* @returns {Object}
|
||||
@@ -83,9 +87,9 @@ module.exports = {
|
||||
/**
|
||||
* @returns {Object} Liquid render engine
|
||||
*/
|
||||
getRenderEngine: function () {
|
||||
getRenderEngine: () => {
|
||||
const renderEngine = new Liquid({
|
||||
root: __dirname + '/../templates/'
|
||||
root: `${__dirname}/../templates/`
|
||||
});
|
||||
|
||||
/**
|
||||
|
@@ -1,51 +0,0 @@
|
||||
const migrate_name = 'identifier_for_migrate';
|
||||
const logger = require('../logger').migrate;
|
||||
|
||||
/**
|
||||
* Migrate
|
||||
*
|
||||
* @see http://knexjs.org/#Schema
|
||||
*
|
||||
* @param {Object} knex
|
||||
* @param {Promise} Promise
|
||||
* @returns {Promise}
|
||||
*/
|
||||
exports.up = function (knex) {
|
||||
|
||||
logger.info(`[${migrate_name}] Migrating Up...`);
|
||||
|
||||
return knex.schema.alterTable('proxy_host', (table) => {
|
||||
table.enum('ssl_key_type', ['ecdsa', 'rsa']).defaultTo('ecdsa').notNullable();
|
||||
}).then(() => {
|
||||
logger.info(`[${migrate_name}] Column 'ssl_key_type' added to table 'proxy_host'`);
|
||||
|
||||
return knex.schema.alterTable('certificate', (table) => {
|
||||
table.enum('ssl_key_type', ['ecdsa', 'rsa']).defaultTo('ecdsa').notNullable();
|
||||
});
|
||||
}).then(() => {
|
||||
logger.info(`[${migrate_name}] Column 'ssl_key_type' added to table 'proxy_host'`);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Undo Migrate
|
||||
*
|
||||
* @param {Object} knex
|
||||
* @param {Promise} Promise
|
||||
* @returns {Promise}
|
||||
*/
|
||||
exports.down = function (knex) {
|
||||
logger.info(`[${migrate_name}] Migrating Down...`);
|
||||
|
||||
return knex.schema.alterTable('proxy_host', (table) => {
|
||||
table.dropColumn('ssl_key_type');
|
||||
}).then(() => {
|
||||
logger.info(`[${migrate_name}] Column 'ssl_key_type' removed from table 'proxy_host'`);
|
||||
|
||||
return knex.schema.alterTable('certificate', (table) => {
|
||||
table.dropColumn('ssl_key_type');
|
||||
});
|
||||
}).then(() => {
|
||||
logger.info(`[${migrate_name}] Column 'ssl_key_type' removed from table 'proxy_host'`);
|
||||
});
|
||||
};
|
@@ -1,40 +0,0 @@
|
||||
const migrate_name = 'default_server';
|
||||
const logger = require('../logger').migrate;
|
||||
|
||||
/**
|
||||
* Migrate Up
|
||||
*
|
||||
* @param {Object} knex
|
||||
* @param {Promise} Promise
|
||||
* @returns {Promise}
|
||||
*/
|
||||
exports.up = function (knex) {
|
||||
logger.info(`[${migrate_name}] Migrating Up...`);
|
||||
|
||||
// Add default_server column to proxy_host table
|
||||
return knex.schema.table('proxy_host', (table) => {
|
||||
table.boolean('default_server').notNullable().defaultTo(false);
|
||||
})
|
||||
.then(() => {
|
||||
logger.info(`[${migrate_name}] Column 'default_server' added to 'proxy_host' table`);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Migrate Down
|
||||
*
|
||||
* @param {Object} knex
|
||||
* @param {Promise} Promise
|
||||
* @returns {Promise}
|
||||
*/
|
||||
exports.down = function (knex) {
|
||||
logger.info(`[${migrate_name}] Migrating Down...`);
|
||||
|
||||
// Remove default_server column from proxy_host table
|
||||
return knex.schema.table('proxy_host', (table) => {
|
||||
table.dropColumn('default_server');
|
||||
})
|
||||
.then(() => {
|
||||
logger.info(`[${migrate_name}] Column 'default_server' removed from 'proxy_host' table`);
|
||||
});
|
||||
};
|
@@ -21,7 +21,6 @@ const boolFields = [
|
||||
'enabled',
|
||||
'hsts_enabled',
|
||||
'hsts_subdomains',
|
||||
'default_server',
|
||||
];
|
||||
|
||||
class ProxyHost extends Model {
|
||||
|
@@ -6,7 +6,7 @@ const apiValidator = require('../../lib/validator/api');
|
||||
const internalCertificate = require('../../internal/certificate');
|
||||
const schema = require('../../schema');
|
||||
|
||||
let router = express.Router({
|
||||
const router = express.Router({
|
||||
caseSensitive: true,
|
||||
strict: true,
|
||||
mergeParams: true
|
||||
@@ -231,7 +231,7 @@ router
|
||||
*/
|
||||
router
|
||||
.route('/:certificate_id/download')
|
||||
.options((req, res) => {
|
||||
.options((_req, res) => {
|
||||
res.sendStatus(204);
|
||||
})
|
||||
.all(jwtdecode())
|
||||
|
@@ -181,7 +181,7 @@ router
|
||||
return internalUser.setPassword(res.locals.access, payload);
|
||||
})
|
||||
.then((result) => {
|
||||
res.status(201)
|
||||
res.status(200)
|
||||
.send(result);
|
||||
})
|
||||
.catch(next);
|
||||
@@ -212,7 +212,7 @@ router
|
||||
return internalUser.setPermissions(res.locals.access, payload);
|
||||
})
|
||||
.then((result) => {
|
||||
res.status(201)
|
||||
res.status(200)
|
||||
.send(result);
|
||||
})
|
||||
.catch(next);
|
||||
@@ -238,7 +238,7 @@ router
|
||||
.post((req, res, next) => {
|
||||
internalUser.loginAs(res.locals.access, {id: parseInt(req.params.user_id, 10)})
|
||||
.then((result) => {
|
||||
res.status(201)
|
||||
res.status(200)
|
||||
.send(result);
|
||||
})
|
||||
.catch(next);
|
||||
|
@@ -110,6 +110,11 @@
|
||||
"caching_enabled": {
|
||||
"description": "Should we cache assets",
|
||||
"type": "boolean"
|
||||
},
|
||||
"email": {
|
||||
"description": "Email address",
|
||||
"type": "string",
|
||||
"pattern": "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -41,11 +41,6 @@
|
||||
"owner": {
|
||||
"$ref": "./user-object.json"
|
||||
},
|
||||
"ssl_key_type": {
|
||||
"type": "string",
|
||||
"enum": ["ecdsa", "rsa"],
|
||||
"description": "Type of SSL key (either ecdsa or rsa)"
|
||||
},
|
||||
"meta": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
@@ -74,7 +69,7 @@
|
||||
"type": "object"
|
||||
},
|
||||
"letsencrypt_email": {
|
||||
"type": "string"
|
||||
"$ref": "../common.json#/properties/email"
|
||||
},
|
||||
"propagation_seconds": {
|
||||
"type": "integer",
|
||||
|
@@ -22,7 +22,6 @@
|
||||
"enabled",
|
||||
"locations",
|
||||
"hsts_enabled",
|
||||
"default_server",
|
||||
"hsts_subdomains"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
@@ -149,15 +148,6 @@
|
||||
"$ref": "./access-list-object.json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ssl_key_type": {
|
||||
"type": "string",
|
||||
"enum": ["ecdsa", "rsa"],
|
||||
"description": "Type of SSL key (either ecdsa or rsa)"
|
||||
},
|
||||
"default_server": {
|
||||
"type": "boolean",
|
||||
"description": "Defines if the server is the default for unmatched requests"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"type": "array",
|
||||
"description": "Proxy Hosts list",
|
||||
"description": "Streams list",
|
||||
"items": {
|
||||
"$ref": "./proxy-host-object.json"
|
||||
"$ref": "./stream-object.json"
|
||||
}
|
||||
}
|
||||
|
@@ -79,12 +79,6 @@
|
||||
},
|
||||
"locations": {
|
||||
"$ref": "../../../../components/proxy-host-object.json#/properties/locations"
|
||||
},
|
||||
"ssl_key_type": {
|
||||
"$ref": "../../../../components/proxy-host-object.json#/properties/ssl_key_type"
|
||||
},
|
||||
"default_server": {
|
||||
"$ref": "../../../../components/proxy-host-object.json#/properties/default_server"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -67,12 +67,6 @@
|
||||
},
|
||||
"locations": {
|
||||
"$ref": "../../../components/proxy-host-object.json#/properties/locations"
|
||||
},
|
||||
"ssl_key_type": {
|
||||
"$ref": "../../../components/proxy-host-object.json#/properties/ssl_key_type"
|
||||
},
|
||||
"default_server": {
|
||||
"$ref": "../../../components/proxy-host-object.json#/properties/default_server"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -21,10 +21,10 @@ const setupDefaultUser = () => {
|
||||
.then((row) => {
|
||||
if (!row || !row.id) {
|
||||
// Create a new user and set password
|
||||
const email = process.env.INITIAL_ADMIN_EMAIL || 'admin@example.com';
|
||||
const email = (process.env.INITIAL_ADMIN_EMAIL || 'admin@example.com').toLowerCase();
|
||||
const password = process.env.INITIAL_ADMIN_PASSWORD || 'changeme';
|
||||
|
||||
logger.info('Creating a new user: ' + email + ' with password: ' + password);
|
||||
logger.info(`Creating a new user: ${email} with password: ${password}`);
|
||||
|
||||
const data = {
|
||||
is_deleted: 0,
|
||||
@@ -113,20 +113,20 @@ const setupCertbotPlugins = () => {
|
||||
.andWhere('provider', 'letsencrypt')
|
||||
.then((certificates) => {
|
||||
if (certificates && certificates.length) {
|
||||
let plugins = [];
|
||||
let promises = [];
|
||||
const plugins = [];
|
||||
const promises = [];
|
||||
|
||||
certificates.map(function (certificate) {
|
||||
certificates.map((certificate) => {
|
||||
if (certificate.meta && certificate.meta.dns_challenge === true) {
|
||||
if (plugins.indexOf(certificate.meta.dns_provider) === -1) {
|
||||
plugins.push(certificate.meta.dns_provider);
|
||||
}
|
||||
|
||||
// Make sure credentials file exists
|
||||
const credentials_loc = '/etc/letsencrypt/credentials/credentials-' + certificate.id;
|
||||
const credentials_loc = `/etc/letsencrypt/credentials/credentials-${certificate.id}`;
|
||||
// Escape single quotes and backslashes
|
||||
const escapedCredentials = certificate.meta.dns_provider_credentials.replaceAll('\'', '\\\'').replaceAll('\\', '\\\\');
|
||||
const credentials_cmd = '[ -f \'' + credentials_loc + '\' ] || { mkdir -p /etc/letsencrypt/credentials 2> /dev/null; echo \'' + escapedCredentials + '\' > \'' + credentials_loc + '\' && chmod 600 \'' + credentials_loc + '\'; }';
|
||||
const credentials_cmd = `[ -f '${credentials_loc}' ] || { mkdir -p /etc/letsencrypt/credentials 2> /dev/null; echo '${escapedCredentials}' > '${credentials_loc}' && chmod 600 '${credentials_loc}'; }`;
|
||||
promises.push(utils.exec(credentials_cmd));
|
||||
}
|
||||
});
|
||||
@@ -136,7 +136,7 @@ const setupCertbotPlugins = () => {
|
||||
if (promises.length) {
|
||||
return Promise.all(promises)
|
||||
.then(() => {
|
||||
logger.info('Added Certbot plugins ' + plugins.join(', '));
|
||||
logger.info(`Added Certbot plugins ${plugins.join(', ')}`);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -165,9 +165,7 @@ const setupLogrotation = () => {
|
||||
return runLogrotate();
|
||||
};
|
||||
|
||||
module.exports = function () {
|
||||
return setupDefaultUser()
|
||||
module.exports = () => setupDefaultUser()
|
||||
.then(setupDefaultSettings)
|
||||
.then(setupCertbotPlugins)
|
||||
.then(setupLogrotation);
|
||||
};
|
||||
|
@@ -1,13 +1,13 @@
|
||||
listen 80{% if default_server == true %} default_server{% endif %};
|
||||
listen 80;
|
||||
{% if ipv6 -%}
|
||||
listen [::]:80{% if default_server == true %} default_server{% endif %};
|
||||
listen [::]:80;
|
||||
{% else -%}
|
||||
#listen [::]:80;
|
||||
{% endif %}
|
||||
{% if certificate -%}
|
||||
listen 443 ssl{% if default_server == true %} default_server{% endif %};
|
||||
listen 443 ssl;
|
||||
{% if ipv6 -%}
|
||||
listen [::]:443 ssl{% if default_server == true %} default_server{% endif %};
|
||||
listen [::]:443 ssl;
|
||||
{% else -%}
|
||||
#listen [::]:443;
|
||||
{% endif %}
|
||||
|
@@ -492,9 +492,9 @@ boxen@^4.2.0:
|
||||
widest-line "^3.1.0"
|
||||
|
||||
brace-expansion@^1.1.7:
|
||||
version "1.1.11"
|
||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
||||
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
|
||||
version "1.1.12"
|
||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.12.tgz#ab9b454466e5a8cc3a187beaad580412a9c5b843"
|
||||
integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==
|
||||
dependencies:
|
||||
balanced-match "^1.0.0"
|
||||
concat-map "0.0.1"
|
||||
|
@@ -53,11 +53,9 @@ COPY --from=testca /home/step/certs/root_ca.crt /etc/ssl/certs/NginxProxyManager
|
||||
# Remove frontend service not required for prod, dev nginx config as well
|
||||
RUN rm -rf /etc/s6-overlay/s6-rc.d/user/contents.d/frontend /etc/nginx/conf.d/dev.conf \
|
||||
&& chmod 644 /etc/logrotate.d/nginx-proxy-manager
|
||||
COPY docker/start-container /usr/local/bin/start-container
|
||||
RUN chmod +x /usr/local/bin/start-container
|
||||
|
||||
VOLUME [ "/data" ]
|
||||
ENTRYPOINT [ "start-container" ]
|
||||
ENTRYPOINT [ "/init" ]
|
||||
|
||||
LABEL org.label-schema.schema-version="1.0" \
|
||||
org.label-schema.license="MIT" \
|
||||
|
@@ -36,8 +36,5 @@ RUN rm -f /etc/nginx/conf.d/production.conf \
|
||||
COPY --from=pebbleca /test/certs/pebble.minica.pem /etc/ssl/certs/pebble.minica.pem
|
||||
COPY --from=testca /home/step/certs/root_ca.crt /etc/ssl/certs/NginxProxyManager.crt
|
||||
|
||||
COPY start-container /usr/local/bin/start-container
|
||||
RUN chmod +x /usr/local/bin/start-container
|
||||
|
||||
EXPOSE 80 81 443
|
||||
ENTRYPOINT [ "start-container" ]
|
||||
ENTRYPOINT [ "/init" ]
|
||||
|
@@ -1,5 +1,7 @@
|
||||
text = True
|
||||
non-interactive = True
|
||||
webroot-path = /data/letsencrypt-acme-challenge
|
||||
key-type = ecdsa
|
||||
elliptic-curve = secp384r1
|
||||
preferred-chain = ISRG Root X1
|
||||
server =
|
||||
|
@@ -18,6 +18,7 @@ services:
|
||||
MYSQL_DATABASE: 'npm'
|
||||
MYSQL_USER: 'npm'
|
||||
MYSQL_PASSWORD: 'npmpass'
|
||||
MARIADB_AUTO_UPGRADE: '1'
|
||||
volumes:
|
||||
- mysql_vol:/var/lib/mysql
|
||||
networks:
|
||||
|
@@ -1,4 +1,6 @@
|
||||
text = True
|
||||
non-interactive = True
|
||||
webroot-path = /data/letsencrypt-acme-challenge
|
||||
key-type = ecdsa
|
||||
elliptic-curve = secp384r1
|
||||
preferred-chain = ISRG Root X1
|
||||
|
@@ -1,6 +1,4 @@
|
||||
# intermediate configuration. tweak to your needs.
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers "ALL:RC4-SHA:AES128-SHA:AES256-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:AES256-GCM-SHA384:AES128-GCM-SHA256:RSA-AES256-CBC-SHA:RC4-MD5:DES-CBC3-SHA:AES256-SHA:RC4-SHA:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
|
||||
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
|
||||
ssl_prefer_server_ciphers off;
|
||||
ssl_ecdh_curve X25519:prime256v1:secp384r1;
|
||||
ssl_dhparam /etc/ssl/certs/dhparam.pem;
|
@@ -8,21 +8,53 @@ log_info 'Setting ownership ...'
|
||||
# root
|
||||
chown root /tmp/nginx
|
||||
|
||||
# npm user and group
|
||||
chown -R "$PUID:$PGID" /data
|
||||
chown -R "$PUID:$PGID" /etc/letsencrypt
|
||||
chown -R "$PUID:$PGID" /run/nginx
|
||||
chown -R "$PUID:$PGID" /tmp/nginx
|
||||
chown -R "$PUID:$PGID" /var/cache/nginx
|
||||
chown -R "$PUID:$PGID" /var/lib/logrotate
|
||||
chown -R "$PUID:$PGID" /var/lib/nginx
|
||||
chown -R "$PUID:$PGID" /var/log/nginx
|
||||
locations=(
|
||||
"/data"
|
||||
"/etc/letsencrypt"
|
||||
"/run/nginx"
|
||||
"/tmp/nginx"
|
||||
"/var/cache/nginx"
|
||||
"/var/lib/logrotate"
|
||||
"/var/lib/nginx"
|
||||
"/var/log/nginx"
|
||||
"/etc/nginx/nginx"
|
||||
"/etc/nginx/nginx.conf"
|
||||
"/etc/nginx/conf.d"
|
||||
)
|
||||
|
||||
# Don't chown entire /etc/nginx folder as this causes crashes on some systems
|
||||
chown -R "$PUID:$PGID" /etc/nginx/nginx
|
||||
chown -R "$PUID:$PGID" /etc/nginx/nginx.conf
|
||||
chown -R "$PUID:$PGID" /etc/nginx/conf.d
|
||||
chownit() {
|
||||
local dir="$1"
|
||||
local recursive="${2:-true}"
|
||||
|
||||
# Prevents errors when installing python certbot plugins when non-root
|
||||
chown "$PUID:$PGID" /opt/certbot /opt/certbot/bin
|
||||
find /opt/certbot/lib/python*/site-packages -not -user "$PUID" -execdir chown "$PUID:$PGID" {} \+
|
||||
local have
|
||||
have="$(stat -c '%u:%g' "$dir")"
|
||||
echo "- $dir ... "
|
||||
|
||||
if [ "$have" != "$PUID:$PGID" ]; then
|
||||
if [ "$recursive" = 'true' ] && [ -d "$dir" ]; then
|
||||
chown -R "$PUID:$PGID" "$dir"
|
||||
else
|
||||
chown "$PUID:$PGID" "$dir"
|
||||
fi
|
||||
echo " DONE"
|
||||
else
|
||||
echo " SKIPPED"
|
||||
fi
|
||||
}
|
||||
|
||||
for loc in "${locations[@]}"; do
|
||||
chownit "$loc"
|
||||
done
|
||||
|
||||
if [ "$(is_true "${SKIP_CERTBOT_OWNERSHIP:-}")" = '1' ]; then
|
||||
log_info 'Skipping ownership change of certbot directories'
|
||||
else
|
||||
log_info 'Changing ownership of certbot directories, this may take some time ...'
|
||||
chownit "/opt/certbot" false
|
||||
chownit "/opt/certbot/bin" false
|
||||
|
||||
# Handle all site-packages directories efficiently
|
||||
find /opt/certbot/lib -type d -name "site-packages" | while read -r SITE_PACKAGES_DIR; do
|
||||
chownit "$SITE_PACKAGES_DIR"
|
||||
done
|
||||
fi
|
||||
|
@@ -5,12 +5,9 @@ set -e
|
||||
|
||||
log_info 'Dynamic resolvers ...'
|
||||
|
||||
DISABLE_IPV6=$(echo "${DISABLE_IPV6:-}" | tr '[:upper:]' '[:lower:]')
|
||||
|
||||
# Dynamically generate resolvers file, if resolver is IPv6, enclose in `[]`
|
||||
# thanks @tfmm
|
||||
if [ "$DISABLE_IPV6" == "true" ] || [ "$DISABLE_IPV6" == "on" ] || [ "$DISABLE_IPV6" == "1" ] || [ "$DISABLE_IPV6" == "yes" ];
|
||||
then
|
||||
if [ "$(is_true "$DISABLE_IPV6")" = '1' ]; then
|
||||
echo resolver "$(awk 'BEGIN{ORS=" "} $1=="nameserver" { sub(/%.*$/,"",$2); print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf) ipv6=off valid=10s;" > /etc/nginx/conf.d/include/resolvers.conf
|
||||
else
|
||||
echo resolver "$(awk 'BEGIN{ORS=" "} $1=="nameserver" { sub(/%.*$/,"",$2); print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf) valid=10s;" > /etc/nginx/conf.d/include/resolvers.conf
|
||||
|
@@ -8,14 +8,11 @@ set -e
|
||||
|
||||
log_info 'IPv6 ...'
|
||||
|
||||
# Lowercase
|
||||
DISABLE_IPV6=$(echo "${DISABLE_IPV6:-}" | tr '[:upper:]' '[:lower:]')
|
||||
|
||||
process_folder () {
|
||||
FILES=$(find "$1" -type f -name "*.conf")
|
||||
SED_REGEX=
|
||||
|
||||
if [ "$DISABLE_IPV6" == "true" ] || [ "$DISABLE_IPV6" == "on" ] || [ "$DISABLE_IPV6" == "1" ] || [ "$DISABLE_IPV6" == "yes" ]; then
|
||||
if [ "$(is_true "$DISABLE_IPV6")" = '1' ]; then
|
||||
# IPV6 is disabled
|
||||
echo "Disabling IPV6 in hosts in: $1"
|
||||
SED_REGEX='s/^([^#]*)listen \[::\]/\1#listen [::]/g'
|
||||
|
@@ -56,3 +56,13 @@ get_group_id () {
|
||||
getent group "$1" | cut -d: -f3
|
||||
fi
|
||||
}
|
||||
|
||||
# param $1: value
|
||||
is_true () {
|
||||
VAL=$(echo "${1:-}" | tr '[:upper:]' '[:lower:]')
|
||||
if [ "$VAL" == 'true' ] || [ "$VAL" == 'on' ] || [ "$VAL" == '1' ] || [ "$VAL" == 'yes' ]; then
|
||||
echo '1'
|
||||
else
|
||||
echo '0'
|
||||
fi
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@ BLUE='\E[1;34m'
|
||||
GREEN='\E[1;32m'
|
||||
RESET='\E[0m'
|
||||
|
||||
S6_OVERLAY_VERSION=3.2.0.2
|
||||
S6_OVERLAY_VERSION=3.2.1.0
|
||||
TARGETPLATFORM=${1:-linux/amd64}
|
||||
|
||||
# Determine the correct binary file for the architecture given
|
||||
|
@@ -1,13 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
FILE="/etc/ssl/certs/dhparam.pem"
|
||||
|
||||
if [ ! -f "$FILE" ]; then
|
||||
echo "the $FILE does not exist, creating..."
|
||||
openssl dhparam -out "$FILE" 2048
|
||||
else
|
||||
echo "the $FILE already exists, skipping..."
|
||||
fi
|
||||
|
||||
echo "run default script"
|
||||
exec /init
|
@@ -161,6 +161,14 @@ The easy fix is to add a Docker environment variable to the Nginx Proxy Manager
|
||||
DISABLE_IPV6: 'true'
|
||||
```
|
||||
|
||||
## Disabling IP Ranges Fetch
|
||||
|
||||
By default, NPM fetches IP ranges from CloudFront and Cloudflare during application startup. In environments with limited internet access or to speed up container startup, this fetch can be disabled:
|
||||
|
||||
```yml
|
||||
environment:
|
||||
IP_RANGES_FETCH_ENABLED: 'false'
|
||||
```
|
||||
|
||||
## Custom Nginx Configurations
|
||||
|
||||
|
@@ -21,7 +21,7 @@ services:
|
||||
# Add any other Stream port you want to expose
|
||||
# - '21:21' # FTP
|
||||
|
||||
environment:
|
||||
#environment:
|
||||
# Uncomment this if you want to change the location of
|
||||
# the SQLite DB file within the container
|
||||
# DB_SQLITE_FILE: "/data/database.sqlite"
|
||||
|
@@ -1065,9 +1065,9 @@ vfile@^6.0.0:
|
||||
vfile-message "^4.0.0"
|
||||
|
||||
vite@^5.4.8:
|
||||
version "5.4.14"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.14.tgz#ff8255edb02134df180dcfca1916c37a6abe8408"
|
||||
integrity sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==
|
||||
version "5.4.20"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.20.tgz#3267a5e03f21212f44edfd72758138e8fcecd76a"
|
||||
integrity sha512-j3lYzGC3P+B5Yfy/pfKNgVEg4+UtcIJcVRt2cDjIOmhLourAqPqf8P7acgxeiSgUB7E3p2P8/3gNIgDLpwzs4g==
|
||||
dependencies:
|
||||
esbuild "^0.21.3"
|
||||
postcss "^8.4.43"
|
||||
|
@@ -72,7 +72,7 @@
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-6">
|
||||
<div class="col-sm-12 col-md-12">
|
||||
<div class="form-group">
|
||||
<label class="custom-switch">
|
||||
<input type="checkbox" class="custom-switch-input" name="allow_websocket_upgrade" value="1"<%- allow_websocket_upgrade ? ' checked' : '' %>>
|
||||
@@ -81,15 +81,6 @@
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-6">
|
||||
<div class="form-group">
|
||||
<label class="custom-switch">
|
||||
<input type="checkbox" class="custom-switch-input" name="default_server" value="1"<%- default_server ? ' checked' : '' %>>
|
||||
<span class="custom-switch-indicator"></span>
|
||||
<span class="custom-switch-description"><%- i18n('proxy-hosts', 'default-server') %></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12 col-md-12">
|
||||
<div class="form-group">
|
||||
@@ -114,15 +105,6 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-12 letsencrypt">
|
||||
<div class="form-group">
|
||||
<label class="form-label"><%- i18n('all-hosts', 'ssl-key-type') %></label>
|
||||
<select name="ssl_key_type" class="form-control custom-select">
|
||||
<option value="ecdsa" data-data="{"id":"ecdsa"}" <%- ssl_key_type == 'ecdsa' ? 'selected' : '' %>>ECDSA</option>
|
||||
<option value="rsa" data-data="{"id":"rsa"}" <%- ssl_key_type == 'rsa' ? 'selected' : '' %>>RSA</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-6">
|
||||
<div class="form-group">
|
||||
<label class="custom-switch">
|
||||
|
@@ -167,7 +167,6 @@ module.exports = Mn.View.extend({
|
||||
data.hsts_enabled = !!data.hsts_enabled;
|
||||
data.hsts_subdomains = !!data.hsts_subdomains;
|
||||
data.ssl_forced = !!data.ssl_forced;
|
||||
data.default_server = !!data.default_server;
|
||||
|
||||
if (typeof data.meta === 'undefined') data.meta = {};
|
||||
data.meta.letsencrypt_agree = data.meta.letsencrypt_agree == 1;
|
||||
|
@@ -60,7 +60,7 @@
|
||||
},
|
||||
"footer": {
|
||||
"fork-me": "Fork me on Github",
|
||||
"copy": "© 2024 <a href=\"{url}\" target=\"_blank\">jc21.com</a>.",
|
||||
"copy": "© 2025 <a href=\"{url}\" target=\"_blank\">jc21.com</a>.",
|
||||
"theme": "Theme by <a href=\"{url}\" target=\"_blank\">Tabler</a>"
|
||||
},
|
||||
"dashboard": {
|
||||
@@ -77,7 +77,6 @@
|
||||
"block-exploits": "Block Common Exploits",
|
||||
"caching-enabled": "Cache Assets",
|
||||
"ssl-certificate": "SSL Certificate",
|
||||
"ssl-key-type": "SSL Key Type",
|
||||
"none": "None",
|
||||
"new-cert": "Request a new SSL Certificate",
|
||||
"with-le": "with Let's Encrypt",
|
||||
@@ -132,7 +131,6 @@
|
||||
"help-content": "A Proxy Host is the incoming endpoint for a web service that you want to forward.\nIt provides optional SSL termination for your service that might not have SSL support built in.\nProxy Hosts are the most common use for the Nginx Proxy Manager.",
|
||||
"access-list": "Access List",
|
||||
"allow-websocket-upgrade": "Websockets Support",
|
||||
"default-server": "Default Server",
|
||||
"ignore-invalid-upstream-ssl": "Ignore Invalid SSL",
|
||||
"custom-forward-host-help": "Add a path for sub-folder forwarding.\nExample: 203.0.113.25/path/",
|
||||
"search": "Search Host…"
|
||||
|
@@ -10,8 +10,6 @@ const model = Backbone.Model.extend({
|
||||
modified_on: null,
|
||||
domain_names: [],
|
||||
certificate_id: 0,
|
||||
ssl_key_type: 'ecdsa',
|
||||
default_server: false,
|
||||
ssl_forced: false,
|
||||
http2_support: false,
|
||||
hsts_enabled: false,
|
||||
|
@@ -14,8 +14,6 @@ const model = Backbone.Model.extend({
|
||||
forward_port: null,
|
||||
access_list_id: 0,
|
||||
certificate_id: 0,
|
||||
ssl_key_type: 'ecdsa',
|
||||
default_server: false,
|
||||
ssl_forced: false,
|
||||
hsts_enabled: false,
|
||||
hsts_subdomains: false,
|
||||
|
@@ -14,8 +14,6 @@ const model = Backbone.Model.extend({
|
||||
forward_domain_name: '',
|
||||
preserve_path: true,
|
||||
certificate_id: 0,
|
||||
ssl_key_type: 'ecdsa',
|
||||
default_server: false,
|
||||
ssl_forced: false,
|
||||
hsts_enabled: false,
|
||||
hsts_subdomains: false,
|
||||
|
@@ -26,8 +26,8 @@
|
||||
"messageformat": "^2.3.0",
|
||||
"messageformat-loader": "^0.8.1",
|
||||
"mini-css-extract-plugin": "^0.9.0",
|
||||
"moment": "^2.29.4",
|
||||
"node-sass": "^9.0.0",
|
||||
"moment": "^2.30.1",
|
||||
"sass": "^1.92.1",
|
||||
"nodemon": "^2.0.2",
|
||||
"numeral": "^2.0.6",
|
||||
"sass-loader": "^10.0.0",
|
||||
|
@@ -167,4 +167,5 @@ $pink: #f66d9b;
|
||||
|
||||
textarea.form-control.text-monospace {
|
||||
font-size: 12px;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
1491
frontend/yarn.lock
1491
frontend/yarn.lock
File diff suppressed because it is too large
Load Diff
@@ -10,9 +10,9 @@
|
||||
"active24": {
|
||||
"name": "Active24",
|
||||
"package_name": "certbot-dns-active24",
|
||||
"version": "~=1.5.1",
|
||||
"version": "~=2.0.0",
|
||||
"dependencies": "",
|
||||
"credentials": "dns_active24_token=\"TOKEN\"",
|
||||
"credentials": "dns_active24_api_key = <identifier>\ndns_active24_secret = <secret>",
|
||||
"full_plugin_name": "dns-active24"
|
||||
},
|
||||
"aliyun": {
|
||||
@@ -31,6 +31,14 @@
|
||||
"credentials": "# This plugin supported API authentication using either Service Principals or utilizing a Managed Identity assigned to the virtual machine.\n# Regardless which authentication method used, the identity will need the “DNS Zone Contributor” role assigned to it.\n# As multiple Azure DNS Zones in multiple resource groups can exist, the config file needs a mapping of zone to resource group ID. Multiple zones -> ID mappings can be listed by using the key dns_azure_zoneX where X is a unique number. At least 1 zone mapping is required.\n\n# Using a service principal (option 1)\ndns_azure_sp_client_id = 912ce44a-0156-4669-ae22-c16a17d34ca5\ndns_azure_sp_client_secret = E-xqXU83Y-jzTI6xe9fs2YC~mck3ZzUih9\ndns_azure_tenant_id = ed1090f3-ab18-4b12-816c-599af8a88cf7\n\n# Using used assigned MSI (option 2)\n# dns_azure_msi_client_id = 912ce44a-0156-4669-ae22-c16a17d34ca5\n\n# Using system assigned MSI (option 3)\n# dns_azure_msi_system_assigned = true\n\n# Zones (at least one always required)\ndns_azure_zone1 = example.com:/subscriptions/c135abce-d87d-48df-936c-15596c6968a5/resourceGroups/dns1\ndns_azure_zone2 = example.org:/subscriptions/99800903-fb14-4992-9aff-12eaf2744622/resourceGroups/dns2",
|
||||
"full_plugin_name": "dns-azure"
|
||||
},
|
||||
"baidu": {
|
||||
"name": "baidu",
|
||||
"package_name": "certbot-dns-baidu",
|
||||
"version": "~=0.1.1",
|
||||
"dependencies": "",
|
||||
"credentials": "dns_baidu_access_key = 12345678\ndns_baidu_secret_key = 1234567890abcdef1234567890abcdef",
|
||||
"full_plugin_name": "dns-baidu"
|
||||
},
|
||||
"beget": {
|
||||
"name":"Beget",
|
||||
"package_name": "certbot-beget-plugin",
|
||||
@@ -47,11 +55,19 @@
|
||||
"credentials": "# Bunny API token used by Certbot (see https://dash.bunny.net/account/settings)\ndns_bunny_api_key = xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx",
|
||||
"full_plugin_name": "dns-bunny"
|
||||
},
|
||||
"cdmon": {
|
||||
"name": "cdmon",
|
||||
"package_name": "certbot-dns-cdmon",
|
||||
"version": "~=0.4.1",
|
||||
"dependencies": "",
|
||||
"credentials": "dns_cdmon_api_key=your-cdmon-api-token\ndns_cdmon_domain=your_domain_is_optional",
|
||||
"full_plugin_name": "dns-cdmon"
|
||||
},
|
||||
"cloudflare": {
|
||||
"name": "Cloudflare",
|
||||
"package_name": "certbot-dns-cloudflare",
|
||||
"version": "=={{certbot-version}}",
|
||||
"dependencies": "cloudflare==2.19.* acme=={{certbot-version}}",
|
||||
"dependencies": "acme=={{certbot-version}}",
|
||||
"credentials": "# Cloudflare API token\ndns_cloudflare_api_token=0123456789abcdef0123456789abcdef01234567",
|
||||
"full_plugin_name": "dns-cloudflare"
|
||||
},
|
||||
@@ -90,11 +106,19 @@
|
||||
"cpanel": {
|
||||
"name": "cPanel",
|
||||
"package_name": "certbot-dns-cpanel",
|
||||
"version": "~=0.2.2",
|
||||
"version": "~=0.4.0",
|
||||
"dependencies": "",
|
||||
"credentials": "cpanel_url = https://cpanel.example.com:2083\ncpanel_username = user\ncpanel_password = hunter2",
|
||||
"credentials": "cpanel_url = https://cpanel.example.com:2083\ncpanel_username = your_username\ncpanel_password = your_password\ncpanel_token = your_api_token",
|
||||
"full_plugin_name": "cpanel"
|
||||
},
|
||||
"ddnss": {
|
||||
"name": "DDNSS",
|
||||
"package_name": "certbot-dns-ddnss",
|
||||
"version": "~=1.1.0",
|
||||
"dependencies": "",
|
||||
"credentials": "dns_ddnss_token = YOUR_DDNSS_API_TOKEN",
|
||||
"full_plugin_name": "dns-ddnss"
|
||||
},
|
||||
"desec": {
|
||||
"name": "deSEC",
|
||||
"package_name": "certbot-dns-desec",
|
||||
@@ -164,7 +188,7 @@
|
||||
"package_name": "certbot-dns-domainoffensive",
|
||||
"version": "~=2.0.0",
|
||||
"dependencies": "",
|
||||
"credentials": "dns_do_api_token = YOUR_DO_DE_AUTH_TOKEN",
|
||||
"credentials": "dns_domainoffensive_api_token = YOUR_DO_DE_AUTH_TOKEN",
|
||||
"full_plugin_name": "dns-domainoffensive"
|
||||
},
|
||||
"domeneshop": {
|
||||
@@ -199,6 +223,14 @@
|
||||
"credentials": "dns_eurodns_applicationId = myuser\ndns_eurodns_apiKey = mysecretpassword\ndns_eurodns_endpoint = https://rest-api.eurodns.com/user-api-gateway/proxy",
|
||||
"full_plugin_name": "dns-eurodns"
|
||||
},
|
||||
"firstdomains": {
|
||||
"name": "First Domains",
|
||||
"package_name": "certbot-dns-firstdomains",
|
||||
"version": ">=1.0",
|
||||
"dependencies": "",
|
||||
"credentials": "dns_firstdomains_username = myremoteuser\ndns_firstdomains_password = verysecureremoteuserpassword",
|
||||
"full_plugin_name": "dns-firstdomains"
|
||||
},
|
||||
"freedns": {
|
||||
"name": "FreeDNS",
|
||||
"package_name": "certbot-dns-freedns",
|
||||
@@ -209,8 +241,8 @@
|
||||
},
|
||||
"gandi": {
|
||||
"name": "Gandi Live DNS",
|
||||
"package_name": "certbot_plugin_gandi",
|
||||
"version": "~=1.5.0",
|
||||
"package_name": "certbot-dns-gandi",
|
||||
"version": "~=1.6.1",
|
||||
"dependencies": "",
|
||||
"credentials": "# Gandi personal access token\ndns_gandi_token=PERSONAL_ACCESS_TOKEN",
|
||||
"full_plugin_name": "dns-gandi"
|
||||
@@ -383,6 +415,14 @@
|
||||
"credentials": "dns_netcup_customer_id = 123456\ndns_netcup_api_key = 0123456789abcdef0123456789abcdef01234567\ndns_netcup_api_password = abcdef0123456789abcdef01234567abcdef0123",
|
||||
"full_plugin_name": "dns-netcup"
|
||||
},
|
||||
"nicru": {
|
||||
"name": "nic.ru",
|
||||
"package_name": "certbot-dns-nicru",
|
||||
"version": "~=1.0.3",
|
||||
"dependencies": "",
|
||||
"credentials": "dns_nicru_client_id = application-id\ndns_nicru_client_secret = application-token\ndns_nicru_username = 0001110/NIC-D\ndns_nicru_password = password\ndns_nicru_scope = .+:.+/zones/example.com(/.+)?\ndns_nicru_service = DNS_SERVICE_NAME\ndns_nicru_zone = example.com",
|
||||
"full_plugin_name": "dns-nicru"
|
||||
},
|
||||
"njalla": {
|
||||
"name": "Njalla",
|
||||
"package_name": "certbot-dns-njalla",
|
||||
@@ -471,13 +511,29 @@
|
||||
"credentials": "[default]\naws_access_key_id=AKIAIOSFODNN7EXAMPLE\naws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
|
||||
"full_plugin_name": "dns-route53"
|
||||
},
|
||||
"spaceship": {
|
||||
"name": "Spaceship",
|
||||
"package_name": "certbot-dns-spaceship",
|
||||
"version": "~=1.0.4",
|
||||
"dependencies": "",
|
||||
"credentials": "[spaceship]\napi_key=your_api_key\napi_secret=your_api_secret",
|
||||
"full_plugin_name": "dns-spaceship"
|
||||
},
|
||||
"strato": {
|
||||
"name": "Strato",
|
||||
"package_name": "certbot-dns-strato",
|
||||
"version": "~=0.2.1",
|
||||
"version": "~=0.2.2",
|
||||
"dependencies": "",
|
||||
"credentials": "dns_strato_username = user\ndns_strato_password = pass\n# uncomment if youre using two factor authentication:\n# dns_strato_totp_devicename = 2fa_device\n# dns_strato_totp_secret = 2fa_secret\n#\n# uncomment if domain name contains special characters\n# insert domain display name as seen on your account page here\n# dns_strato_domain_display_name = my-punicode-url.de\n#\n# if youre not using strato.de or another special endpoint you can customise it below\n# you will probably only need to adjust the host, but you can also change the complete endpoint url\n# dns_strato_custom_api_scheme = https\n# dns_strato_custom_api_host = www.strato.de\n# dns_strato_custom_api_port = 443\n# dns_strato_custom_api_path = \"/apps/CustomerService\"",
|
||||
"full_plugin_name": "dns-strato"
|
||||
},
|
||||
"selectelv2": {
|
||||
"name": "Selectel api v2",
|
||||
"package_name": "certbot-dns-selectel-api-v2",
|
||||
"version": "~=0.3.0",
|
||||
"dependencies": "",
|
||||
"credentials": "dns_selectel_api_v2_account_id = your_account_id\ndns_selectel_api_v2_project_name = your_project\ndns_selectel_api_v2_username = your_username\ndns_selectel_api_v2_password = your_password",
|
||||
"full_plugin_name": "dns-selectel-api-v2"
|
||||
},
|
||||
"timeweb": {
|
||||
"name": "Timeweb Cloud",
|
||||
|
@@ -10,7 +10,7 @@ describe('Certificates endpoints', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('Validate custom certificate', function() {
|
||||
it('Validate custom certificate', () => {
|
||||
cy.task('backendApiPostFiles', {
|
||||
token: token,
|
||||
path: '/api/nginx/certificates/validate',
|
||||
@@ -25,7 +25,7 @@ describe('Certificates endpoints', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('Custom certificate lifecycle', function() {
|
||||
it('Custom certificate lifecycle', () => {
|
||||
// Create custom cert
|
||||
cy.task('backendApiPost', {
|
||||
token: token,
|
||||
@@ -73,7 +73,7 @@ describe('Certificates endpoints', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('Request Certificate - CVE-2024-46256/CVE-2024-46257', function() {
|
||||
it('Request Certificate - CVE-2024-46256/CVE-2024-46257', () => {
|
||||
cy.task('backendApiPost', {
|
||||
token: token,
|
||||
path: '/api/nginx/certificates',
|
||||
@@ -96,4 +96,28 @@ describe('Certificates endpoints', () => {
|
||||
expect(data.error.message).to.contain('data/domain_names/0 must match pattern');
|
||||
});
|
||||
});
|
||||
|
||||
it('Request Certificate - LE Email Escaped', () => {
|
||||
cy.task('backendApiPost', {
|
||||
token: token,
|
||||
path: '/api/nginx/certificates',
|
||||
data: {
|
||||
domain_names: ['test.com"||echo hello-world||\\\\n test.com"'],
|
||||
meta: {
|
||||
dns_challenge: false,
|
||||
letsencrypt_agree: true,
|
||||
letsencrypt_email: "admin@example.com' --version;echo hello-world",
|
||||
},
|
||||
provider: 'letsencrypt',
|
||||
},
|
||||
returnOnError: true,
|
||||
}).then((data) => {
|
||||
cy.validateSwaggerSchema('post', 400, '/nginx/certificates', data);
|
||||
expect(data).to.have.property('error');
|
||||
expect(data.error).to.have.property('message');
|
||||
expect(data.error).to.have.property('code');
|
||||
expect(data.error.code).to.equal(400);
|
||||
expect(data.error.message).to.contain('data/meta/letsencrypt_email must match pattern');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
25
test/cypress/e2e/api/Dashboard.cy.js
Normal file
25
test/cypress/e2e/api/Dashboard.cy.js
Normal file
@@ -0,0 +1,25 @@
|
||||
/// <reference types="cypress" />
|
||||
|
||||
describe('Dashboard endpoints', () => {
|
||||
let token;
|
||||
|
||||
before(() => {
|
||||
cy.getToken().then((tok) => {
|
||||
token = tok;
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to get host counts', () => {
|
||||
cy.task('backendApiGet', {
|
||||
token: token,
|
||||
path: '/api/reports/hosts'
|
||||
}).then((data) => {
|
||||
cy.validateSwaggerSchema('get', 200, '/reports/hosts', data);
|
||||
expect(data).to.have.property('dead');
|
||||
expect(data).to.have.property('proxy');
|
||||
expect(data).to.have.property('redirection');
|
||||
expect(data).to.have.property('stream');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
@@ -9,7 +9,7 @@ describe('Full Certificate Provisions', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to create new http certificate', function() {
|
||||
it('Should be able to create new http certificate', () => {
|
||||
cy.task('backendApiPost', {
|
||||
token: token,
|
||||
path: '/api/nginx/certificates',
|
||||
@@ -32,7 +32,7 @@ describe('Full Certificate Provisions', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to create new DNS certificate with Powerdns', function() {
|
||||
it('Should be able to create new DNS certificate with Powerdns', () => {
|
||||
cy.task('backendApiPost', {
|
||||
token: token,
|
||||
path: '/api/nginx/certificates',
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/// <reference types="cypress" />
|
||||
|
||||
describe('Basic API checks', () => {
|
||||
it('Should return a valid health payload', function () {
|
||||
it('Should return a valid health payload', () => {
|
||||
cy.task('backendApiGet', {
|
||||
path: '/api/',
|
||||
}).then((data) => {
|
||||
@@ -10,9 +10,9 @@ describe('Basic API checks', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('Should return a valid schema payload', function () {
|
||||
it('Should return a valid schema payload', () => {
|
||||
cy.task('backendApiGet', {
|
||||
path: '/api/schema?ts=' + Date.now(),
|
||||
path: `/api/schema?ts=${Date.now()}`,
|
||||
}).then((data) => {
|
||||
expect(data.openapi).to.be.equal('3.1.0');
|
||||
});
|
||||
|
@@ -1,12 +1,12 @@
|
||||
/// <reference types="cypress" />
|
||||
|
||||
describe('LDAP with Authentik', () => {
|
||||
let token;
|
||||
let _token;
|
||||
if (Cypress.env('skipStackCheck') === 'true' || Cypress.env('stack') === 'postgres') {
|
||||
|
||||
before(() => {
|
||||
cy.getToken().then((tok) => {
|
||||
token = tok;
|
||||
_token = tok;
|
||||
|
||||
// cy.task('backendApiPut', {
|
||||
// token: token,
|
||||
@@ -45,7 +45,7 @@ describe('LDAP with Authentik', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it.skip('Should log in with LDAP', function() {
|
||||
it.skip('Should log in with LDAP', () => {
|
||||
// cy.task('backendApiPost', {
|
||||
// token: token,
|
||||
// path: '/api/auth',
|
||||
|
@@ -1,12 +1,12 @@
|
||||
/// <reference types="cypress" />
|
||||
|
||||
describe('OAuth with Authentik', () => {
|
||||
let token;
|
||||
let _token;
|
||||
if (Cypress.env('skipStackCheck') === 'true' || Cypress.env('stack') === 'postgres') {
|
||||
|
||||
before(() => {
|
||||
cy.getToken().then((tok) => {
|
||||
token = tok;
|
||||
_token = tok;
|
||||
|
||||
// cy.task('backendApiPut', {
|
||||
// token: token,
|
||||
@@ -47,7 +47,7 @@ describe('OAuth with Authentik', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it.skip('Should log in with OAuth', function() {
|
||||
it.skip('Should log in with OAuth', () => {
|
||||
// cy.task('backendApiGet', {
|
||||
// path: '/oauth/login?redirect_base=' + encodeURI(Cypress.config('baseUrl')),
|
||||
// }).then((data) => {
|
||||
|
@@ -9,7 +9,7 @@ describe('Proxy Hosts endpoints', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to create a http host', function() {
|
||||
it('Should be able to create a http host', () => {
|
||||
cy.task('backendApiPost', {
|
||||
token: token,
|
||||
path: '/api/nginx/proxy-hosts',
|
||||
|
@@ -9,7 +9,7 @@ describe('Settings endpoints', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('Get all settings', function() {
|
||||
it('Get all settings', () => {
|
||||
cy.task('backendApiGet', {
|
||||
token: token,
|
||||
path: '/api/settings',
|
||||
@@ -19,7 +19,7 @@ describe('Settings endpoints', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('Get default-site setting', function() {
|
||||
it('Get default-site setting', () => {
|
||||
cy.task('backendApiGet', {
|
||||
token: token,
|
||||
path: '/api/settings/default-site',
|
||||
@@ -30,7 +30,7 @@ describe('Settings endpoints', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('Default Site congratulations', function() {
|
||||
it('Default Site congratulations', () => {
|
||||
cy.task('backendApiPut', {
|
||||
token: token,
|
||||
path: '/api/settings/default-site',
|
||||
@@ -46,7 +46,7 @@ describe('Settings endpoints', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('Default Site 404', function() {
|
||||
it('Default Site 404', () => {
|
||||
cy.task('backendApiPut', {
|
||||
token: token,
|
||||
path: '/api/settings/default-site',
|
||||
@@ -62,7 +62,7 @@ describe('Settings endpoints', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('Default Site 444', function() {
|
||||
it('Default Site 444', () => {
|
||||
cy.task('backendApiPut', {
|
||||
token: token,
|
||||
path: '/api/settings/default-site',
|
||||
@@ -78,7 +78,7 @@ describe('Settings endpoints', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('Default Site redirect', function() {
|
||||
it('Default Site redirect', () => {
|
||||
cy.task('backendApiPut', {
|
||||
token: token,
|
||||
path: '/api/settings/default-site',
|
||||
@@ -100,7 +100,7 @@ describe('Settings endpoints', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('Default Site html', function() {
|
||||
it('Default Site html', () => {
|
||||
cy.task('backendApiPut', {
|
||||
token: token,
|
||||
path: '/api/settings/default-site',
|
||||
|
@@ -33,7 +33,7 @@ describe('Streams', () => {
|
||||
cy.exec('rm -f /test/results/testssl.json');
|
||||
});
|
||||
|
||||
it('Should be able to create TCP Stream', function() {
|
||||
it('Should be able to create TCP Stream', () => {
|
||||
cy.task('backendApiPost', {
|
||||
token: token,
|
||||
path: '/api/nginx/streams',
|
||||
@@ -65,7 +65,7 @@ describe('Streams', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to create UDP Stream', function() {
|
||||
it('Should be able to create UDP Stream', () => {
|
||||
cy.task('backendApiPost', {
|
||||
token: token,
|
||||
path: '/api/nginx/streams',
|
||||
@@ -92,7 +92,7 @@ describe('Streams', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to create TCP/UDP Stream', function() {
|
||||
it('Should be able to create TCP/UDP Stream', () => {
|
||||
cy.task('backendApiPost', {
|
||||
token: token,
|
||||
path: '/api/nginx/streams',
|
||||
@@ -124,7 +124,7 @@ describe('Streams', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to create SSL TCP Stream', function() {
|
||||
it('Should be able to create SSL TCP Stream', () => {
|
||||
let certID = 0;
|
||||
|
||||
// Create custom cert
|
||||
@@ -184,7 +184,7 @@ describe('Streams', () => {
|
||||
cy.exec('/testssl/testssl.sh --quiet --add-ca="$(/bin/mkcert -CAROOT)/rootCA.pem" --jsonfile=/test/results/testssl.json website1.example.com:1503', {
|
||||
timeout: 120000, // 2 minutes
|
||||
}).then((result) => {
|
||||
cy.task('log', '[testssl.sh] ' + result.stdout);
|
||||
cy.task('log', `[testssl.sh] ${result.stdout}`);
|
||||
|
||||
const allowedSeverities = ["INFO", "OK", "LOW", "MEDIUM"];
|
||||
const ignoredIDs = [
|
||||
@@ -210,4 +210,16 @@ describe('Streams', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to List Streams', () => {
|
||||
cy.task('backendApiGet', {
|
||||
token: token,
|
||||
path: '/api/nginx/streams?expand=owner,certificate',
|
||||
}).then((data) => {
|
||||
cy.validateSwaggerSchema('get', 200, '/nginx/streams', data);
|
||||
expect(data.length).to.be.greaterThan(0);
|
||||
expect(data[0]).to.have.property('id');
|
||||
expect(data[0]).to.have.property('enabled');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
@@ -9,7 +9,7 @@ describe('Users endpoints', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to get yourself', function() {
|
||||
it('Should be able to get yourself', () => {
|
||||
cy.task('backendApiGet', {
|
||||
token: token,
|
||||
path: '/api/users/me'
|
||||
@@ -20,7 +20,7 @@ describe('Users endpoints', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to get all users', function() {
|
||||
it('Should be able to get all users', () => {
|
||||
cy.task('backendApiGet', {
|
||||
token: token,
|
||||
path: '/api/users'
|
||||
@@ -30,7 +30,7 @@ describe('Users endpoints', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be able to update yourself', function() {
|
||||
it('Should be able to update yourself', () => {
|
||||
cy.task('backendApiPut', {
|
||||
token: token,
|
||||
path: '/api/users/me',
|
||||
|
949
test/yarn.lock
949
test/yarn.lock
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user