Skip to content

Commit 7307515

Browse files
committed
Add certificate to streams database model
1 parent 1d3d5be commit 7307515

File tree

5 files changed

+164
-17
lines changed

5 files changed

+164
-17
lines changed

backend/internal/stream.js

Lines changed: 85 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
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');
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');
79

810
function omissions () {
911
return ['is_deleted'];
@@ -17,6 +19,12 @@ const internalStream = {
1719
* @returns {Promise}
1820
*/
1921
create: (access, data) => {
22+
let create_certificate = data.certificate_id === 'new';
23+
24+
if (create_certificate) {
25+
delete data.certificate_id;
26+
}
27+
2028
return access.can('streams:create', data)
2129
.then((/*access_data*/) => {
2230
// TODO: At this point the existing ports should have been checked
@@ -26,11 +34,40 @@ const internalStream = {
2634
data.meta = {};
2735
}
2836

37+
let data_no_domains = structuredClone(data);
38+
39+
// streams aren't routed by ___domain name so don't store ___domain names in the DB
40+
delete data_no_domains.domain_names;
41+
2942
return streamModel
3043
.query()
31-
.insertAndFetch(data)
44+
.insertAndFetch(data_no_domains)
3245
.then(utils.omitRow(omissions()));
3346
})
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+
})
3471
.then((row) => {
3572
// Configure nginx
3673
return internalNginx.configure(streamModel, 'stream', row)
@@ -59,6 +96,12 @@ const internalStream = {
5996
* @return {Promise}
6097
*/
6198
update: (access, data) => {
99+
let create_certificate = data.certificate_id === 'new';
100+
101+
if (create_certificate) {
102+
delete data.certificate_id;
103+
}
104+
62105
return access.can('streams:update', data.id)
63106
.then((/*access_data*/) => {
64107
// TODO: at this point the existing streams should have been checked
@@ -70,6 +113,28 @@ const internalStream = {
70113
throw new error.InternalValidationError('Stream could not be updated, IDs do not match: ' + row.id + ' !== ' + data.id);
71114
}
72115

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+
73138
return streamModel
74139
.query()
75140
.patchAndFetchById(row.id, data)
@@ -114,7 +179,7 @@ const internalStream = {
114179
.query()
115180
.where('is_deleted', 0)
116181
.andWhere('id', data.id)
117-
.allowGraph('[owner]')
182+
.allowGraph('[owner,certificate]')
118183
.first();
119184

120185
if (access_data.permission_visibility !== 'all') {
@@ -131,6 +196,7 @@ const internalStream = {
131196
if (!row) {
132197
throw new error.ItemNotFoundError(data.id);
133198
}
199+
row = internalHost.cleanRowCertificateMeta(row);
134200
// Custom omissions
135201
if (typeof data.omit !== 'undefined' && data.omit !== null) {
136202
row = _.omit(row, data.omit);
@@ -196,14 +262,14 @@ const internalStream = {
196262
.then(() => {
197263
return internalStream.get(access, {
198264
id: data.id,
199-
expand: ['owner']
265+
expand: ['certificate', 'owner']
200266
});
201267
})
202268
.then((row) => {
203269
if (!row) {
204270
throw new error.ItemNotFoundError(data.id);
205271
} else if (row.enabled) {
206-
throw new error.ValidationError('Host is already enabled');
272+
throw new error.ValidationError('Stream is already enabled');
207273
}
208274

209275
row.enabled = 1;
@@ -249,7 +315,7 @@ const internalStream = {
249315
if (!row) {
250316
throw new error.ItemNotFoundError(data.id);
251317
} else if (!row.enabled) {
252-
throw new error.ValidationError('Host is already disabled');
318+
throw new error.ValidationError('Stream is already disabled');
253319
}
254320

255321
row.enabled = 0;
@@ -297,7 +363,7 @@ const internalStream = {
297363
.query()
298364
.where('is_deleted', 0)
299365
.groupBy('id')
300-
.allowGraph('[owner]')
366+
.allowGraph('[owner,certificate]')
301367
.orderBy('incoming_port', 'ASC');
302368

303369
if (access_data.permission_visibility !== 'all') {
@@ -316,6 +382,13 @@ const internalStream = {
316382
}
317383

318384
return query.then(utils.omitRows(omissions()));
385+
})
386+
.then((rows) => {
387+
if (typeof expand !== 'undefined' && expand !== null && expand.indexOf('certificate') !== -1) {
388+
return internalHost.cleanAllRowsCertificateMeta(rows);
389+
}
390+
391+
return rows;
319392
});
320393
},
321394

Lines changed: 38 additions & 0 deletions
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+
};

backend/models/stream.js

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
// Objection Docs:
22
// http://vincit.github.io/objection.js/
33

4-
const db = require('../db');
5-
const Model = require('objection').Model;
6-
const User = require('./user');
7-
const now = require('./now_helper');
4+
const db = require('../db');
5+
const Model = require('objection').Model;
6+
const User = require('./user');
7+
const now = require('./now_helper');
8+
const Certificate = require('./certificate');
89

910
Model.knex(db);
1011

@@ -47,6 +48,17 @@ class Stream extends Model {
4748
modify: function (qb) {
4849
qb.where('user.is_deleted', 0);
4950
}
51+
},
52+
certificate: {
53+
relation: Model.HasOneRelation,
54+
modelClass: Certificate,
55+
join: {
56+
from: 'stream.certificate_id',
57+
to: 'certificate.id'
58+
},
59+
modify: function (qb) {
60+
qb.where('certificate.is_deleted', 0);
61+
}
5062
}
5163
};
5264
}

backend/schema/endpoints/streams.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@
4646
"udp_forwarding": {
4747
"type": "boolean"
4848
},
49+
"domain_names": {
50+
"$ref": "../definitions.json#/definitions/domain_names"
51+
},
52+
"certificate_id": {
53+
"$ref": "../definitions.json#/definitions/certificate_id"
54+
},
4955
"enabled": {
5056
"$ref": "../definitions.json#/definitions/enabled"
5157
},
@@ -78,6 +84,12 @@
7884
"udp_forwarding": {
7985
"$ref": "#/definitions/udp_forwarding"
8086
},
87+
"domain_names": {
88+
"$ref": "../definitions.json#/definitions/domain_names"
89+
},
90+
"certificate_id": {
91+
"$ref": "#/definitions/certificate_id"
92+
},
8193
"enabled": {
8294
"$ref": "#/definitions/enabled"
8395
},
@@ -137,6 +149,12 @@
137149
"udp_forwarding": {
138150
"$ref": "#/definitions/udp_forwarding"
139151
},
152+
"domain_names": {
153+
"$ref": "../definitions.json#/definitions/domain_names"
154+
},
155+
"certificate_id": {
156+
"$ref": "#/definitions/certificate_id"
157+
},
140158
"meta": {
141159
"$ref": "#/definitions/meta"
142160
}
@@ -177,6 +195,12 @@
177195
"udp_forwarding": {
178196
"$ref": "#/definitions/udp_forwarding"
179197
},
198+
"domain_names": {
199+
"$ref": "../definitions.json#/definitions/domain_names"
200+
},
201+
"certificate_id": {
202+
"$ref": "#/definitions/certificate_id"
203+
},
180204
"meta": {
181205
"$ref": "#/definitions/meta"
182206
}

frontend/js/app/nginx/stream/main.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ module.exports = Mn.View.extend({
8888
onRender: function () {
8989
let view = this;
9090

91-
view.fetch(['owner'])
91+
view.fetch(['owner', 'certificate'])
9292
.then(response => {
9393
if (!view.isDestroyed()) {
9494
if (response && response.length) {

0 commit comments

Comments
 (0)