host.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. import _ from "lodash";
  2. import { castJsonIfNeed } from "../lib/helpers.js";
  3. import deadHostModel from "../models/dead_host.js";
  4. import proxyHostModel from "../models/proxy_host.js";
  5. import redirectionHostModel from "../models/redirection_host.js";
  6. const internalHost = {
  7. /**
  8. * Makes sure that the ssl_* and hsts_* fields play nicely together.
  9. * ie: if there is no cert, then force_ssl is off.
  10. * if force_ssl is off, then hsts_enabled is definitely off.
  11. *
  12. * @param {object} data
  13. * @param {object} [existing_data]
  14. * @returns {object}
  15. */
  16. cleanSslHstsData: (data, existingData) => {
  17. const combinedData = _.assign({}, existingData || {}, data);
  18. if (!combinedData.certificate_id) {
  19. combinedData.ssl_forced = false;
  20. combinedData.http2_support = false;
  21. }
  22. if (!combinedData.ssl_forced) {
  23. combinedData.hsts_enabled = false;
  24. }
  25. if (!combinedData.hsts_enabled) {
  26. combinedData.hsts_subdomains = false;
  27. }
  28. return combinedData;
  29. },
  30. /**
  31. * used by the getAll functions of hosts, this removes the certificate meta if present
  32. *
  33. * @param {Array} rows
  34. * @returns {Array}
  35. */
  36. cleanAllRowsCertificateMeta: (rows) => {
  37. rows.map((_, idx) => {
  38. if (typeof rows[idx].certificate !== "undefined" && rows[idx].certificate) {
  39. rows[idx].certificate.meta = {};
  40. }
  41. return true;
  42. });
  43. return rows;
  44. },
  45. /**
  46. * used by the get/update functions of hosts, this removes the certificate meta if present
  47. *
  48. * @param {Object} row
  49. * @returns {Object}
  50. */
  51. cleanRowCertificateMeta: (row) => {
  52. if (typeof row.certificate !== "undefined" && row.certificate) {
  53. row.certificate.meta = {};
  54. }
  55. return row;
  56. },
  57. /**
  58. * This returns all the host types with any domain listed in the provided domainNames array.
  59. * This is used by the certificates to temporarily disable any host that is using the domain
  60. *
  61. * @param {Array} domainNames
  62. * @returns {Promise}
  63. */
  64. getHostsWithDomains: async (domainNames) => {
  65. const responseObject = {
  66. total_count: 0,
  67. dead_hosts: [],
  68. proxy_hosts: [],
  69. redirection_hosts: [],
  70. };
  71. const proxyRes = await proxyHostModel.query().where("is_deleted", 0);
  72. responseObject.proxy_hosts = internalHost._getHostsWithDomains(proxyRes, domainNames);
  73. responseObject.total_count += responseObject.proxy_hosts.length;
  74. const redirRes = await redirectionHostModel.query().where("is_deleted", 0);
  75. responseObject.redirection_hosts = internalHost._getHostsWithDomains(redirRes, domainNames);
  76. responseObject.total_count += responseObject.redirection_hosts.length;
  77. const deadRes = await deadHostModel.query().where("is_deleted", 0);
  78. responseObject.dead_hosts = internalHost._getHostsWithDomains(deadRes, domainNames);
  79. responseObject.total_count += responseObject.dead_hosts.length;
  80. return responseObject;
  81. },
  82. /**
  83. * Internal use only, checks to see if the domain is already taken by any other record
  84. *
  85. * @param {String} hostname
  86. * @param {String} [ignore_type] 'proxy', 'redirection', 'dead'
  87. * @param {Integer} [ignore_id] Must be supplied if type was also supplied
  88. * @returns {Promise}
  89. */
  90. isHostnameTaken: (hostname, ignore_type, ignore_id) => {
  91. const promises = [
  92. proxyHostModel
  93. .query()
  94. .where("is_deleted", 0)
  95. .andWhere(castJsonIfNeed("domain_names"), "like", `%${hostname}%`),
  96. redirectionHostModel
  97. .query()
  98. .where("is_deleted", 0)
  99. .andWhere(castJsonIfNeed("domain_names"), "like", `%${hostname}%`),
  100. deadHostModel
  101. .query()
  102. .where("is_deleted", 0)
  103. .andWhere(castJsonIfNeed("domain_names"), "like", `%${hostname}%`),
  104. ];
  105. return Promise.all(promises).then((promises_results) => {
  106. let is_taken = false;
  107. if (promises_results[0]) {
  108. // Proxy Hosts
  109. if (
  110. internalHost._checkHostnameRecordsTaken(
  111. hostname,
  112. promises_results[0],
  113. ignore_type === "proxy" && ignore_id ? ignore_id : 0,
  114. )
  115. ) {
  116. is_taken = true;
  117. }
  118. }
  119. if (promises_results[1]) {
  120. // Redirection Hosts
  121. if (
  122. internalHost._checkHostnameRecordsTaken(
  123. hostname,
  124. promises_results[1],
  125. ignore_type === "redirection" && ignore_id ? ignore_id : 0,
  126. )
  127. ) {
  128. is_taken = true;
  129. }
  130. }
  131. if (promises_results[2]) {
  132. // Dead Hosts
  133. if (
  134. internalHost._checkHostnameRecordsTaken(
  135. hostname,
  136. promises_results[2],
  137. ignore_type === "dead" && ignore_id ? ignore_id : 0,
  138. )
  139. ) {
  140. is_taken = true;
  141. }
  142. }
  143. return {
  144. hostname: hostname,
  145. is_taken: is_taken,
  146. };
  147. });
  148. },
  149. /**
  150. * Private call only
  151. *
  152. * @param {String} hostname
  153. * @param {Array} existingRows
  154. * @param {Integer} [ignoreId]
  155. * @returns {Boolean}
  156. */
  157. _checkHostnameRecordsTaken: (hostname, existingRows, ignoreId) => {
  158. let isTaken = false;
  159. if (existingRows?.length) {
  160. existingRows.map((existingRow) => {
  161. existingRow.domain_names.map((existingHostname) => {
  162. // Does this domain match?
  163. if (existingHostname.toLowerCase() === hostname.toLowerCase()) {
  164. if (!ignoreId || ignoreId !== existingRow.id) {
  165. isTaken = true;
  166. }
  167. }
  168. return true;
  169. });
  170. return true;
  171. });
  172. }
  173. return isTaken;
  174. },
  175. /**
  176. * Private call only
  177. *
  178. * @param {Array} hosts
  179. * @param {Array} domainNames
  180. * @returns {Array}
  181. */
  182. _getHostsWithDomains: (hosts, domainNames) => {
  183. const response = [];
  184. if (hosts?.length) {
  185. hosts.map((host) => {
  186. let hostMatches = false;
  187. domainNames.map((domainName) => {
  188. host.domain_names.map((hostDomainName) => {
  189. if (domainName.toLowerCase() === hostDomainName.toLowerCase()) {
  190. hostMatches = true;
  191. }
  192. return true;
  193. });
  194. return true;
  195. });
  196. if (hostMatches) {
  197. response.push(host);
  198. }
  199. return true;
  200. });
  201. }
  202. return response;
  203. },
  204. };
  205. export default internalHost;