functions.xmpp.inc.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. <?php
  2. function xmpp_control($_action, $_data = null) {
  3. global $lang;
  4. $_data_log = $_data;
  5. switch ($_action) {
  6. case 'reload':
  7. $curl = curl_init();
  8. curl_setopt($curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
  9. curl_setopt($curl, CURLOPT_URL, 'http://ejabberd:5280/api/reload_config');
  10. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  11. curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);
  12. curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
  13. curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
  14. $response = curl_exec($curl);
  15. curl_close($curl);
  16. if ($response === "0") {
  17. $_SESSION['return'][] = array(
  18. 'type' => 'success',
  19. 'log' => array(__FUNCTION__, $_action, $_data_log),
  20. 'msg' => 'xmpp_reloaded'
  21. );
  22. }
  23. else {
  24. $_SESSION['return'][] = array(
  25. 'type' => 'danger',
  26. 'log' => array(__FUNCTION__, $_action, $_data_log),
  27. 'msg' => 'xmpp_reload_failed'
  28. );
  29. }
  30. break;
  31. case 'restart':
  32. $curl = curl_init();
  33. curl_setopt($curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
  34. curl_setopt($curl, CURLOPT_URL, 'http://ejabberd:5280/api/restart');
  35. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  36. curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);
  37. curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
  38. curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
  39. $response = curl_exec($curl);
  40. curl_close($curl);
  41. if ($response === "0") {
  42. $_SESSION['return'][] = array(
  43. 'type' => 'success',
  44. 'log' => array(__FUNCTION__, $_action, $_data_log),
  45. 'msg' => 'xmpp_restarted'
  46. );
  47. }
  48. else {
  49. // If no host is available, the container might be in sleeping state, we need to restart the container
  50. $response = json_decode(docker('post', 'ejabberd-mailcow', 'restart'), true);
  51. if (isset($response['type']) && $response['type'] == "success") {
  52. $_SESSION['return'][] = array(
  53. 'type' => 'success',
  54. 'log' => array(__FUNCTION__, $_action, $_data_log),
  55. 'msg' => 'xmpp_restarted'
  56. );
  57. }
  58. else {
  59. $_SESSION['return'][] = array(
  60. 'type' => 'danger',
  61. 'log' => array(__FUNCTION__, $_action, $_data_log),
  62. 'msg' => 'xmpp_restart_failed'
  63. );
  64. }
  65. }
  66. break;
  67. case 'status':
  68. if ($_SESSION['mailcow_cc_role'] != "admin") {
  69. $_SESSION['return'][] = array(
  70. 'type' => 'danger',
  71. 'log' => array(__FUNCTION__, $_action, $_data_log),
  72. 'msg' => 'access_denied'
  73. );
  74. return false;
  75. }
  76. foreach (array(
  77. 'onlineusers' => 'stats?name=onlineusers',
  78. 'uptimeseconds' => 'stats?name=uptimeseconds',
  79. 'muc_online_rooms' => 'muc_online_rooms?service=global'
  80. ) as $stat => $url) {
  81. $curl = curl_init();
  82. curl_setopt($curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
  83. curl_setopt($curl, CURLOPT_URL, 'http://ejabberd:5280/api/' . $url);
  84. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  85. curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);
  86. curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
  87. curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
  88. $response_json = json_decode(curl_exec($curl), true);
  89. if (isset($response_json['stat'])) {
  90. $response_data[$stat] = $response_json['stat'];
  91. }
  92. else {
  93. $response_data[$stat] = $response_json;
  94. }
  95. curl_close($curl);
  96. // Something went wrong
  97. if ($response_data[$stat] === false) {
  98. $response_data[$stat] = '?';
  99. }
  100. }
  101. return $response_data;
  102. break;
  103. }
  104. }
  105. function xmpp_rebuild_configs() {
  106. global $pdo;
  107. global $lang;
  108. $_data_log = $_data;
  109. try {
  110. $xmpp_domains = array();
  111. $stmt = $pdo->query('SELECT CONCAT(`xmpp_prefix`, ".", `domain`) AS `xmpp_host`, `domain` FROM `domain` WHERE `xmpp` = 1');
  112. $xmpp_domain_rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
  113. foreach ($xmpp_domain_rows as $xmpp_domain_row) {
  114. $xmpp_domains[$xmpp_domain_row['domain']] = array('xmpp_host' => $xmpp_domain_row['xmpp_host']);
  115. $stmt = $pdo->query('SELECT CONCAT(`local_part`, "@", CONCAT(`domain`.`xmpp_prefix`, ".", `domain`.`domain`)) AS `xmpp_username` FROM `mailbox`
  116. JOIN `domain`
  117. WHERE `domain`.`xmpp` = 1
  118. AND JSON_VALUE(`attributes`, "$.xmpp_admin") = 1');
  119. $xmpp_admin_rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
  120. foreach ($xmpp_admin_rows as $xmpp_admin_row) {
  121. $xmpp_domains[$xmpp_domain_row['domain']]['xmpp_admins'][] = $xmpp_admin_row['xmpp_username'];
  122. }
  123. }
  124. touch('/ejabberd/ejabberd_hosts.yml');
  125. touch('/ejabberd/ejabberd_acl.yml');
  126. touch('/etc/nginx/conf.d/ZZZ-ejabberd.conf');
  127. $ejabberd_hosts_md5 = md5_file('/ejabberd/ejabberd_hosts.yml');
  128. $ejabberd_acl_md5 = md5_file('/ejabberd/ejabberd_acl.yml');
  129. $ejabberd_site_md5 = md5_file('/etc/nginx/conf.d/ZZZ-ejabberd.conf');
  130. if (!empty($xmpp_domains)) {
  131. // Handle hosts file
  132. $hosts_handle = fopen('/ejabberd/ejabberd_hosts.yml', 'w');
  133. if (!$hosts_handle) {
  134. throw new Exception($lang['danger']['file_open_error']);
  135. }
  136. fwrite($hosts_handle, '# Autogenerated by mailcow' . PHP_EOL);
  137. fwrite($hosts_handle, 'hosts:' . PHP_EOL);
  138. foreach ($xmpp_domains as $domain => $domain_values) {
  139. fwrite($hosts_handle, ' - ' . $xmpp_domains[$domain]['xmpp_host'] . PHP_EOL);
  140. }
  141. fclose($hosts_handle);
  142. // Handle ACL file
  143. $acl_handle = fopen('/ejabberd/ejabberd_acl.yml', 'w');
  144. if (!$acl_handle) {
  145. throw new Exception($lang['danger']['file_open_error']);
  146. }
  147. fwrite($acl_handle, '# Autogenerated by mailcow' . PHP_EOL);
  148. fwrite($acl_handle, 'append_host_config:' . PHP_EOL);
  149. foreach ($xmpp_domains as $domain => $domain_values) {
  150. fwrite($acl_handle, ' ' . $xmpp_domains[$domain]['xmpp_host'] . ':' . PHP_EOL);
  151. fwrite($acl_handle, ' acl:' . PHP_EOL);
  152. fwrite($acl_handle, ' admin:' . PHP_EOL);
  153. fwrite($acl_handle, ' user:' . PHP_EOL);
  154. foreach ($xmpp_domains[$domain]['xmpp_admins'] as $xmpp_admin) {
  155. fwrite($acl_handle, ' - ' . $xmpp_admin . PHP_EOL);
  156. }
  157. }
  158. fclose($acl_handle);
  159. // Handle Nginx site
  160. $site_handle = @fopen('/etc/nginx/conf.d/ZZZ-ejabberd.conf', 'r+');
  161. if ($site_handle !== false) {
  162. ftruncate($site_handle, 0);
  163. fclose($site_handle);
  164. }
  165. $site_handle = fopen('/etc/nginx/conf.d/ZZZ-ejabberd.conf', 'w');
  166. if (!$site_handle) {
  167. throw new Exception($lang['danger']['file_open_error']);
  168. }
  169. fwrite($site_handle, '# Autogenerated by mailcow' . PHP_EOL);
  170. foreach ($xmpp_domains as $domain => $domain_values) {
  171. $site_config = <<<EOF
  172. server {
  173. root /web;
  174. include /etc/nginx/conf.d/listen_ssl.active;
  175. include /etc/nginx/conf.d/listen_plain.active;
  176. ssl_certificate /etc/ssl/mail/cert.pem;
  177. ssl_certificate_key /etc/ssl/mail/key.pem;
  178. server_name %s conference.%s proxy.%s pubsub.%s upload.%s;
  179. if (\$request_uri ~* "%%0A|%%0D") {
  180. return 403;
  181. }
  182. set_real_ip_from 10.0.0.0/8;
  183. set_real_ip_from 172.16.0.0/12;
  184. set_real_ip_from 192.168.0.0/16;
  185. set_real_ip_from fc00::/7;
  186. real_ip_header X-Forwarded-For;
  187. real_ip_recursive on;
  188. location / {
  189. proxy_pass http://ejabberd:5281/;
  190. proxy_set_header Host \$http_host;
  191. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  192. proxy_set_header X-Real-IP \$remote_addr;
  193. proxy_redirect off;
  194. }
  195. }
  196. EOF;
  197. fwrite($site_handle, sprintf($site_config,
  198. $xmpp_domains[$domain]['xmpp_host'],
  199. $xmpp_domains[$domain]['xmpp_host'],
  200. $xmpp_domains[$domain]['xmpp_host'],
  201. $xmpp_domains[$domain]['xmpp_host'],
  202. $xmpp_domains[$domain]['xmpp_host']
  203. ));
  204. }
  205. fclose($site_handle);
  206. }
  207. else {
  208. // Write empty hosts file
  209. $hosts_handle = fopen('/ejabberd/ejabberd_hosts.yml', 'w');
  210. if (!$hosts_handle) {
  211. throw new Exception($lang['danger']['file_open_error']);
  212. }
  213. fwrite($hosts_handle, '# Autogenerated by mailcow' . PHP_EOL);
  214. fclose($hosts_handle);
  215. // Write empty ACL file
  216. $acl_handle = fopen('/ejabberd/ejabberd_acl.yml', 'w');
  217. if (!$acl_handle) {
  218. throw new Exception($lang['danger']['file_open_error']);
  219. }
  220. fwrite($acl_handle, '# Autogenerated by mailcow' . PHP_EOL);
  221. fclose($acl_handle);
  222. // Write empty Nginx site
  223. $acl_handle = fopen('/etc/nginx/conf.d/ZZZ-ejabberd.conf', 'w');
  224. if (!$acl_handle) {
  225. throw new Exception($lang['danger']['file_open_error']);
  226. }
  227. fwrite($acl_handle, '# Autogenerated by mailcow' . PHP_EOL);
  228. fclose($acl_handle);
  229. }
  230. if (md5_file('/ejabberd/ejabberd_acl.yml') != $ejabberd_acl_md5) {
  231. xmpp_control('restart');
  232. $_SESSION['return'][] = array(
  233. 'type' => 'success',
  234. 'log' => array(__FUNCTION__, $_action, $_data_log),
  235. 'msg' => 'xmpp_maps_updated'
  236. );
  237. }
  238. elseif (md5_file('/ejabberd/ejabberd_hosts.yml') != $ejabberd_hosts_md5) {
  239. xmpp_control('reload');
  240. $_SESSION['return'][] = array(
  241. 'type' => 'success',
  242. 'log' => array(__FUNCTION__, $_action, $_data_log),
  243. 'msg' => 'xmpp_maps_updated'
  244. );
  245. }
  246. if (md5_file('/etc/nginx/conf.d/ZZZ-ejabberd.conf') != $ejabberd_site_md5) {
  247. $response = json_decode(docker('post', 'nginx-mailcow', 'exec', array("cmd" => "reload", "task" => "nginx"), 'Content-type: application/json'), true);
  248. if (isset($response['type']) && $response['type'] == "success") {
  249. $_SESSION['return'][] = array(
  250. 'type' => 'success',
  251. 'log' => array(__FUNCTION__, $_action, $_data_log),
  252. 'msg' => 'nginx_reloaded'
  253. );
  254. }
  255. else {
  256. if (!empty($response['msg'])) {
  257. $error = $response['msg'];
  258. }
  259. else {
  260. $error = '-';
  261. }
  262. $_SESSION['return'][] = array(
  263. 'type' => 'danger',
  264. 'log' => array(__FUNCTION__, $_action, $_data_log),
  265. 'msg' => array('nginx_reload_failed', htmlspecialchars($error))
  266. );
  267. }
  268. }
  269. }
  270. catch (Exception $e) {
  271. $_SESSION['return'][] = array(
  272. 'type' => 'danger',
  273. 'log' => array(__FUNCTION__, $_action, $_data_log),
  274. 'msg' => array('xmpp_map_write_error', htmlspecialchars($e->getMessage()))
  275. );
  276. }
  277. }