diff --git a/backend/internal/proxy-host.js b/backend/internal/proxy-host.js index 3299012a6b..f264f62f99 100644 --- a/backend/internal/proxy-host.js +++ b/backend/internal/proxy-host.js @@ -40,7 +40,7 @@ const internalProxyHost = { return Promise.all(domain_name_check_promises).then((check_results) => { check_results.map((result) => { if (result.is_taken) { - throw new errs.ValidationError(`${result.hostname} is already in use`); + throw new errs.ValidationError(result.hostname + " is already in use"); } return true; }); @@ -137,7 +137,7 @@ const internalProxyHost = { return Promise.all(domain_name_check_promises).then((check_results) => { check_results.map((result) => { if (result.is_taken) { - throw new errs.ValidationError(`${result.hostname} is already in use`); + throw new errs.ValidationError(result.hostname + " is already in use"); } return true; }); @@ -151,7 +151,7 @@ const internalProxyHost = { if (row.id !== thisData.id) { // Sanity check that something crazy hasn't happened throw new errs.InternalValidationError( - `Proxy Host could not be updated, IDs do not match: ${row.id} !== ${thisData.id}`, + "Proxy Host could not be updated, IDs do not match: " + row.id + " !== " + thisData.id, ); } @@ -248,7 +248,7 @@ const internalProxyHost = { } if (typeof thisData.expand !== "undefined" && thisData.expand !== null) { - query.withGraphFetched(`[${thisData.expand.join(", ")}]`); + query.withGraphFetched("[" + thisData.expand.join(", ") + "]"); } return query.then(utils.omitRow(omissions())); @@ -266,6 +266,54 @@ const internalProxyHost = { }); }, + /** + * @param {Access} access + * @param {Object} data + * @param {String} data.domain + * @param {Array} [data.expand] + * @param {Array} [data.omit] + * @return {Promise} + */ + getByDomain: (access, data) => { + const thisData = data || {}; + + return access.can("proxy_hosts:get", thisData.domain) + .then((access_data) => { + let query = proxyHostModel + .query() + .where("is_deleted", 0) + .andWhere(castJsonIfNeed("domain_names"), "like", "%" + thisData.domain + "%") + .allowGraph("[owner,access_list.[clients,items],certificate]") + .modify((queryBuilder) => { + if (thisData.expand) { + queryBuilder.withGraphFetched("[" + thisData.expand.join(', ') + "]"); + } + }) + .first(); + + if (access_data.permission_visibility !== "all") { + query.andWhere("owner_user_id", access.token.getUserId(1)); + } + + if (typeof thisData.expand !== "undefined" && thisData.expand !== null) { + query.withGraphFetched("[" + thisData.expand.join(', ') + "]"); + } + + return query.then(utils.omitRow(omissions())); + }) + .then((row) => { + if (!row || !row.id) { + throw new error.ItemNotFoundError(thisData.id); + } + row = internalHost.cleanRowCertificateMeta(row); + // Custom omissions + if (typeof thisData.omit !== "undefined" && thisData.omit !== null) { + row = _.omit(row, thisData.omit); + } + return row; + }); + }, + /** * @param {Access} access * @param {Object} data @@ -436,12 +484,12 @@ const internalProxyHost = { // Query is used for searching if (typeof searchQuery === "string" && searchQuery.length > 0) { query.where(function () { - this.where(castJsonIfNeed("domain_names"), "like", `%${searchQuery}%`); + this.where(castJsonIfNeed("domain_names"), "like", "%" + searchQuery + "%"); }); } if (typeof expand !== "undefined" && expand !== null) { - query.withGraphFetched(`[${expand.join(", ")}]`); + query.withGraphFetched("[" + expand.join(", ") + "]"); } const rows = await query.then(utils.omitRows(omissions())); diff --git a/backend/routes/nginx/proxy_hosts.js b/backend/routes/nginx/proxy_hosts.js index 7045a195cc..cdd40c747a 100644 --- a/backend/routes/nginx/proxy_hosts.js +++ b/backend/routes/nginx/proxy_hosts.js @@ -118,6 +118,51 @@ router } }) +/** + * Specific proxy-host by domain + * + * /api/nginx/proxy-hosts/domain/:domain + */ +router + .route("/domain/:domain") + .options((_, res) => { + res.sendStatus(204); + }) + .all(jwtdecode()) + + /** + * GET /api/nginx/proxy-hosts/domain/:domain + * + * Retrieve a specific proxy-host by domain + */ + .get(async (req, res, next) => { + try { + const data = await validator({ + required: ["domain"], + additionalProperties: false, + properties: { + domain: { + type: "string", + }, + expand: { + $ref: "common#/properties/expand" + } + } + }, { + domain: req.params.domain, + expand: (typeof req.query.expand === "string" ? req.query.expand.split(",") : null) + }); + const row = internalProxyHost.getByDomain(res.locals.access, { + domain: data.domain, + expand: data.expand + }); + res.status(200).send(row); + } catch (err) { + debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`); + next(err); + } + }) + /** * PUT /api/nginx/proxy-hosts/123 * @@ -152,6 +197,52 @@ router } }); +/** + * Specific proxy-host by domain + * + * /api/nginx/proxy-hosts/domain/:domain + */ +router + .route('/domain/:domain') + .options((req, res) => { + res.sendStatus(204); + }) + .all(jwtdecode()) + + /** + * GET /api/nginx/proxy-hosts/domain/:domain + * + * Retrieve a specific proxy-host by domain + */ + .get((req, res, next) => { + validator({ + required: ['domain'], + additionalProperties: false, + properties: { + domain: { + type: 'string' + }, + expand: { + $ref: 'common#/properties/expand' + } + } + }, { + domain: req.params.domain, + expand: (typeof req.query.expand === 'string' ? req.query.expand.split(',') : null) + }) + .then((data) => { + return internalProxyHost.getByDomain(res.locals.access, { + domain: data.domain, + expand: data.expand + }); + }) + .then((row) => { + res.status(200) + .send(row); + }) + .catch(next); + }); + /** * Enable proxy-host *