Skip to content

Commit c5a319c

Browse files
authored
Merge pull request #4347 from NginxProxyManager/develop
v2.12.3
2 parents b4f4996 + c4df89d commit c5a319c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1461
-741
lines changed

.version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.12.2
1+
2.12.3

Jenkinsfile

+3-3
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ pipeline {
128128
sh 'docker-compose down --remove-orphans --volumes -t 30 || true'
129129
}
130130
unstable {
131-
dir(path: 'testing/results') {
131+
dir(path: 'test/results') {
132132
archiveArtifacts(allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml')
133133
}
134134
}
@@ -161,7 +161,7 @@ pipeline {
161161
sh 'docker-compose down --remove-orphans --volumes -t 30 || true'
162162
}
163163
unstable {
164-
dir(path: 'testing/results') {
164+
dir(path: 'test/results') {
165165
archiveArtifacts(allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml')
166166
}
167167
}
@@ -199,7 +199,7 @@ pipeline {
199199
sh 'docker-compose down --remove-orphans --volumes -t 30 || true'
200200
}
201201
unstable {
202-
dir(path: 'testing/results') {
202+
dir(path: 'test/results') {
203203
archiveArtifacts(allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml')
204204
}
205205
}

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<p align="center">
22
<img src="https://nginxproxymanager.com/github.png">
33
<br><br>
4-
<img src="https://img.shields.io/badge/version-2.12.2-green.svg?style=for-the-badge">
4+
<img src="https://img.shields.io/badge/version-2.12.3-green.svg?style=for-the-badge">
55
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager">
66
<img src="https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge">
77
</a>

backend/internal/access-list.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ const internalAccessList = {
258258
})
259259
.where('access_list.is_deleted', 0)
260260
.andWhere('access_list.id', data.id)
261+
.groupBy('access_list.id')
261262
.allowGraph('[owner,items,clients,proxy_hosts.[certificate,access_list.[clients,items]]]')
262263
.first();
263264

@@ -507,8 +508,13 @@ const internalAccessList = {
507508
if (typeof item.password !== 'undefined' && item.password.length) {
508509
logger.info('Adding: ' + item.username);
509510

510-
utils.execFile('/usr/bin/htpasswd', ['-b', htpasswd_file, item.username, item.password])
511-
.then((/*result*/) => {
511+
utils.execFile('openssl', ['passwd', '-apr1', item.password])
512+
.then((res) => {
513+
try {
514+
fs.appendFileSync(htpasswd_file, item.username + ':' + res + '\n', {encoding: 'utf8'});
515+
} catch (err) {
516+
reject(err);
517+
}
512518
next();
513519
})
514520
.catch((err) => {

backend/internal/certificate.js

+6
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,9 @@ const internalCertificate = {
313313
.where('is_deleted', 0)
314314
.andWhere('id', data.id)
315315
.allowGraph('[owner]')
316+
.allowGraph('[proxy_hosts]')
317+
.allowGraph('[redirection_hosts]')
318+
.allowGraph('[dead_hosts]')
316319
.first();
317320

318321
if (access_data.permission_visibility !== 'all') {
@@ -464,6 +467,9 @@ const internalCertificate = {
464467
.where('is_deleted', 0)
465468
.groupBy('id')
466469
.allowGraph('[owner]')
470+
.allowGraph('[proxy_hosts]')
471+
.allowGraph('[redirection_hosts]')
472+
.allowGraph('[dead_hosts]')
467473
.orderBy('nice_name', 'ASC');
468474

469475
if (access_data.permission_visibility !== 'all') {

backend/internal/stream.js

+98-21
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
const _ = require('lodash');
2-
const error = require('../lib/error');
3-
const utils = require('../lib/utils');
4-
const streamModel = require('../models/stream');
5-
const internalNginx = require('./nginx');
6-
const internalAuditLog = require('./audit-log');
7-
const {castJsonIfNeed} = require('../lib/helpers');
1+
const _ = require('lodash');
2+
const error = require('../lib/error');
3+
const utils = require('../lib/utils');
4+
const streamModel = require('../models/stream');
5+
const internalNginx = require('./nginx');
6+
const internalAuditLog = require('./audit-log');
7+
const internalCertificate = require('./certificate');
8+
const internalHost = require('./host');
9+
const {castJsonIfNeed} = require('../lib/helpers');
810

911
function omissions () {
10-
return ['is_deleted'];
12+
return ['is_deleted', 'owner.is_deleted', 'certificate.is_deleted'];
1113
}
1214

1315
const internalStream = {
@@ -18,6 +20,12 @@ const internalStream = {
1820
* @returns {Promise}
1921
*/
2022
create: (access, data) => {
23+
const create_certificate = data.certificate_id === 'new';
24+
25+
if (create_certificate) {
26+
delete data.certificate_id;
27+
}
28+
2129
return access.can('streams:create', data)
2230
.then((/*access_data*/) => {
2331
// TODO: At this point the existing ports should have been checked
@@ -27,16 +35,44 @@ const internalStream = {
2735
data.meta = {};
2836
}
2937

38+
// streams aren't routed by domain name so don't store domain names in the DB
39+
let data_no_domains = structuredClone(data);
40+
delete data_no_domains.domain_names;
41+
3042
return streamModel
3143
.query()
32-
.insertAndFetch(data)
44+
.insertAndFetch(data_no_domains)
3345
.then(utils.omitRow(omissions()));
3446
})
47+
.then((row) => {
48+
if (create_certificate) {
49+
return internalCertificate.createQuickCertificate(access, data)
50+
.then((cert) => {
51+
// update host with cert id
52+
return internalStream.update(access, {
53+
id: row.id,
54+
certificate_id: cert.id
55+
});
56+
})
57+
.then(() => {
58+
return row;
59+
});
60+
} else {
61+
return row;
62+
}
63+
})
64+
.then((row) => {
65+
// re-fetch with cert
66+
return internalStream.get(access, {
67+
id: row.id,
68+
expand: ['certificate', 'owner']
69+
});
70+
})
3571
.then((row) => {
3672
// Configure nginx
3773
return internalNginx.configure(streamModel, 'stream', row)
3874
.then(() => {
39-
return internalStream.get(access, {id: row.id, expand: ['owner']});
75+
return row;
4076
});
4177
})
4278
.then((row) => {
@@ -60,6 +96,12 @@ const internalStream = {
6096
* @return {Promise}
6197
*/
6298
update: (access, data) => {
99+
const create_certificate = data.certificate_id === 'new';
100+
101+
if (create_certificate) {
102+
delete data.certificate_id;
103+
}
104+
63105
return access.can('streams:update', data.id)
64106
.then((/*access_data*/) => {
65107
// TODO: at this point the existing streams should have been checked
@@ -71,16 +113,32 @@ const internalStream = {
71113
throw new error.InternalValidationError('Stream could not be updated, IDs do not match: ' + row.id + ' !== ' + data.id);
72114
}
73115

116+
if (create_certificate) {
117+
return internalCertificate.createQuickCertificate(access, {
118+
domain_names: data.domain_names || row.domain_names,
119+
meta: _.assign({}, row.meta, data.meta)
120+
})
121+
.then((cert) => {
122+
// update host with cert id
123+
data.certificate_id = cert.id;
124+
})
125+
.then(() => {
126+
return row;
127+
});
128+
} else {
129+
return row;
130+
}
131+
})
132+
.then((row) => {
133+
// Add domain_names to the data in case it isn't there, so that the audit log renders correctly. The order is important here.
134+
data = _.assign({}, {
135+
domain_names: row.domain_names
136+
}, data);
137+
74138
return streamModel
75139
.query()
76140
.patchAndFetchById(row.id, data)
77141
.then(utils.omitRow(omissions()))
78-
.then((saved_row) => {
79-
return internalNginx.configure(streamModel, 'stream', saved_row)
80-
.then(() => {
81-
return internalStream.get(access, {id: row.id, expand: ['owner']});
82-
});
83-
})
84142
.then((saved_row) => {
85143
// Add to audit log
86144
return internalAuditLog.add(access, {
@@ -93,6 +151,17 @@ const internalStream = {
93151
return saved_row;
94152
});
95153
});
154+
})
155+
.then(() => {
156+
return internalStream.get(access, {id: data.id, expand: ['owner', 'certificate']})
157+
.then((row) => {
158+
return internalNginx.configure(streamModel, 'stream', row)
159+
.then((new_meta) => {
160+
row.meta = new_meta;
161+
row = internalHost.cleanRowCertificateMeta(row);
162+
return _.omit(row, omissions());
163+
});
164+
});
96165
});
97166
},
98167

@@ -115,7 +184,7 @@ const internalStream = {
115184
.query()
116185
.where('is_deleted', 0)
117186
.andWhere('id', data.id)
118-
.allowGraph('[owner]')
187+
.allowGraph('[owner,certificate]')
119188
.first();
120189

121190
if (access_data.permission_visibility !== 'all') {
@@ -132,6 +201,7 @@ const internalStream = {
132201
if (!row || !row.id) {
133202
throw new error.ItemNotFoundError(data.id);
134203
}
204+
row = internalHost.cleanRowCertificateMeta(row);
135205
// Custom omissions
136206
if (typeof data.omit !== 'undefined' && data.omit !== null) {
137207
row = _.omit(row, data.omit);
@@ -197,14 +267,14 @@ const internalStream = {
197267
.then(() => {
198268
return internalStream.get(access, {
199269
id: data.id,
200-
expand: ['owner']
270+
expand: ['certificate', 'owner']
201271
});
202272
})
203273
.then((row) => {
204274
if (!row || !row.id) {
205275
throw new error.ItemNotFoundError(data.id);
206276
} else if (row.enabled) {
207-
throw new error.ValidationError('Host is already enabled');
277+
throw new error.ValidationError('Stream is already enabled');
208278
}
209279

210280
row.enabled = 1;
@@ -250,7 +320,7 @@ const internalStream = {
250320
if (!row || !row.id) {
251321
throw new error.ItemNotFoundError(data.id);
252322
} else if (!row.enabled) {
253-
throw new error.ValidationError('Host is already disabled');
323+
throw new error.ValidationError('Stream is already disabled');
254324
}
255325

256326
row.enabled = 0;
@@ -298,7 +368,7 @@ const internalStream = {
298368
.query()
299369
.where('is_deleted', 0)
300370
.groupBy('id')
301-
.allowGraph('[owner]')
371+
.allowGraph('[owner,certificate]')
302372
.orderByRaw('CAST(incoming_port AS INTEGER) ASC');
303373

304374
if (access_data.permission_visibility !== 'all') {
@@ -317,6 +387,13 @@ const internalStream = {
317387
}
318388

319389
return query.then(utils.omitRows(omissions()));
390+
})
391+
.then((rows) => {
392+
if (typeof expand !== 'undefined' && expand !== null && expand.indexOf('certificate') !== -1) {
393+
return internalHost.cleanAllRowsCertificateMeta(rows);
394+
}
395+
396+
return rows;
320397
});
321398
},
322399

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
const migrate_name = 'stream_ssl';
2+
const logger = require('../logger').migrate;
3+
4+
/**
5+
* Migrate
6+
*
7+
* @see http://knexjs.org/#Schema
8+
*
9+
* @param {Object} knex
10+
* @returns {Promise}
11+
*/
12+
exports.up = function (knex) {
13+
logger.info('[' + migrate_name + '] Migrating Up...');
14+
15+
return knex.schema.table('stream', (table) => {
16+
table.integer('certificate_id').notNull().unsigned().defaultTo(0);
17+
})
18+
.then(function () {
19+
logger.info('[' + migrate_name + '] stream Table altered');
20+
});
21+
};
22+
23+
/**
24+
* Undo Migrate
25+
*
26+
* @param {Object} knex
27+
* @returns {Promise}
28+
*/
29+
exports.down = function (knex) {
30+
logger.info('[' + migrate_name + '] Migrating Down...');
31+
32+
return knex.schema.table('stream', (table) => {
33+
table.dropColumn('certificate_id');
34+
})
35+
.then(function () {
36+
logger.info('[' + migrate_name + '] stream Table altered');
37+
});
38+
};

0 commit comments

Comments
 (0)