Files
nginx-proxy-manager/backend/internal/host.js
Jamie Curnow a12553fec7 Convert backend to ESM
- About 5 years overdue
- Remove eslint, use bomejs instead
2025-09-03 13:59:40 +10:00

252 lines
6.0 KiB
JavaScript

import _ from "lodash";
import { castJsonIfNeed } from "../lib/helpers.js";
import deadHostModel from "../models/dead_host.js";
import proxyHostModel from "../models/proxy_host.js";
import redirectionHostModel from "../models/redirection_host.js";
const internalHost = {
/**
* Makes sure that the ssl_* and hsts_* fields play nicely together.
* ie: if there is no cert, then force_ssl is off.
* if force_ssl is off, then hsts_enabled is definitely off.
*
* @param {object} data
* @param {object} [existing_data]
* @returns {object}
*/
cleanSslHstsData: (data, existingData) => {
const combinedData = _.assign({}, existingData || {}, data);
if (!combinedData.certificate_id) {
combinedData.ssl_forced = false;
combinedData.http2_support = false;
}
if (!combinedData.ssl_forced) {
combinedData.hsts_enabled = false;
}
if (!combinedData.hsts_enabled) {
combinedData.hsts_subdomains = false;
}
return combinedData;
},
/**
* used by the getAll functions of hosts, this removes the certificate meta if present
*
* @param {Array} rows
* @returns {Array}
*/
cleanAllRowsCertificateMeta: (rows) => {
rows.map((_, idx) => {
if (typeof rows[idx].certificate !== "undefined" && rows[idx].certificate) {
rows[idx].certificate.meta = {};
}
return true;
});
return rows;
},
/**
* used by the get/update functions of hosts, this removes the certificate meta if present
*
* @param {Object} row
* @returns {Object}
*/
cleanRowCertificateMeta: (row) => {
if (typeof row.certificate !== "undefined" && row.certificate) {
row.certificate.meta = {};
}
return row;
},
/**
* This returns all the host types with any domain listed in the provided domain_names array.
* This is used by the certificates to temporarily disable any host that is using the domain
*
* @param {Array} domain_names
* @returns {Promise}
*/
getHostsWithDomains: (domain_names) => {
const promises = [
proxyHostModel.query().where("is_deleted", 0),
redirectionHostModel.query().where("is_deleted", 0),
deadHostModel.query().where("is_deleted", 0),
];
return Promise.all(promises).then((promises_results) => {
const response_object = {
total_count: 0,
dead_hosts: [],
proxy_hosts: [],
redirection_hosts: [],
};
if (promises_results[0]) {
// Proxy Hosts
response_object.proxy_hosts = internalHost._getHostsWithDomains(promises_results[0], domain_names);
response_object.total_count += response_object.proxy_hosts.length;
}
if (promises_results[1]) {
// Redirection Hosts
response_object.redirection_hosts = internalHost._getHostsWithDomains(
promises_results[1],
domain_names,
);
response_object.total_count += response_object.redirection_hosts.length;
}
if (promises_results[2]) {
// Dead Hosts
response_object.dead_hosts = internalHost._getHostsWithDomains(promises_results[2], domain_names);
response_object.total_count += response_object.dead_hosts.length;
}
return response_object;
});
},
/**
* Internal use only, checks to see if the domain is already taken by any other 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}
*/
isHostnameTaken: (hostname, ignore_type, ignore_id) => {
const promises = [
proxyHostModel
.query()
.where("is_deleted", 0)
.andWhere(castJsonIfNeed("domain_names"), "like", `%${hostname}%`),
redirectionHostModel
.query()
.where("is_deleted", 0)
.andWhere(castJsonIfNeed("domain_names"), "like", `%${hostname}%`),
deadHostModel
.query()
.where("is_deleted", 0)
.andWhere(castJsonIfNeed("domain_names"), "like", `%${hostname}%`),
];
return Promise.all(promises).then((promises_results) => {
let is_taken = false;
if (promises_results[0]) {
// Proxy Hosts
if (
internalHost._checkHostnameRecordsTaken(
hostname,
promises_results[0],
ignore_type === "proxy" && ignore_id ? ignore_id : 0,
)
) {
is_taken = true;
}
}
if (promises_results[1]) {
// Redirection Hosts
if (
internalHost._checkHostnameRecordsTaken(
hostname,
promises_results[1],
ignore_type === "redirection" && ignore_id ? ignore_id : 0,
)
) {
is_taken = true;
}
}
if (promises_results[2]) {
// Dead Hosts
if (
internalHost._checkHostnameRecordsTaken(
hostname,
promises_results[2],
ignore_type === "dead" && ignore_id ? ignore_id : 0,
)
) {
is_taken = true;
}
}
return {
hostname: hostname,
is_taken: is_taken,
};
});
},
/**
* Private call only
*
* @param {String} hostname
* @param {Array} existingRows
* @param {Integer} [ignoreId]
* @returns {Boolean}
*/
_checkHostnameRecordsTaken: (hostname, existingRows, ignoreId) => {
let isTaken = false;
if (existingRows?.length) {
existingRows.map((existingRow) => {
existingRow.domain_names.map((existingHostname) => {
// Does this domain match?
if (existingHostname.toLowerCase() === hostname.toLowerCase()) {
if (!ignoreId || ignoreId !== existingRow.id) {
isTaken = true;
}
}
return true;
});
return true;
});
}
return isTaken;
},
/**
* Private call only
*
* @param {Array} hosts
* @param {Array} domainNames
* @returns {Array}
*/
_getHostsWithDomains: (hosts, domainNames) => {
const response = [];
if (hosts?.length) {
hosts.map((host) => {
let hostMatches = false;
domainNames.map((domainName) => {
host.domain_names.map((hostDomainName) => {
if (domainName.toLowerCase() === hostDomainName.toLowerCase()) {
hostMatches = true;
}
return true;
});
return true;
});
if (hostMatches) {
response.push(host);
}
return true;
});
}
return response;
},
};
export default internalHost;