blob: 28f8cac56aa29abcf46c5f2bb910bf41e9688ba3 [file] [log] [blame]
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001<?php
2/*
3 see /api
4*/
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01005require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01006cors("set_headers");
7header('Content-Type: application/json');
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01008error_reporting(0);
9
10function api_log($_data) {
11 global $redis;
12 $data_var = array();
13 foreach ($_data as $data => &$value) {
14 if ($data == 'csrf_token') {
15 continue;
16 }
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +010017
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +010018 $value = json_decode($value, true);
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +010019 if ($value) {
20 if (is_array($value)) unset($value["csrf_token"]);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +010021 foreach ($value as $key => &$val) {
22 if(preg_match("/pass/i", $key)) {
23 $val = '*';
24 }
25 }
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +010026 $value = json_encode($value);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +010027 }
28 $data_var[] = $data . "='" . $value . "'";
29 }
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +010030
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +010031 try {
32 $log_line = array(
33 'time' => time(),
34 'uri' => $_SERVER['REQUEST_URI'],
35 'method' => $_SERVER['REQUEST_METHOD'],
36 'remote' => get_remote_ip(),
37 'data' => implode(', ', $data_var)
38 );
39 $redis->lPush('API_LOG', json_encode($log_line));
40 }
41 catch (RedisException $e) {
42 $_SESSION['return'][] = array(
43 'type' => 'danger',
44 'msg' => 'Redis: '.$e
45 );
46 return false;
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +010047 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +010048}
49
50if (isset($_GET['query'])) {
51
52 $query = explode('/', $_GET['query']);
53 $action = (isset($query[0])) ? $query[0] : null;
54 $category = (isset($query[1])) ? $query[1] : null;
55 $object = (isset($query[2])) ? $query[2] : null;
56 $extra = (isset($query[3])) ? $query[3] : null;
57
58 // accept json in request body
59 if(strpos($_SERVER['HTTP_CONTENT_TYPE'], 'application/json') !== false) {
60 $request = file_get_contents('php://input');
61 $requestDecoded = json_decode($request, true);
62
63 // check for valid json
64 if ($action != 'get' && $requestDecoded === null) {
65 http_response_code(400);
66 echo json_encode(array(
67 'type' => 'error',
68 'msg' => 'Request body doesn\'t contain valid json!'
69 ));
70 exit;
71 }
72
73 // add
74 if ($action == 'add') {
75 $_POST['attr'] = $request;
76 }
77
78 // edit
79 if ($action == 'edit') {
80 $_POST['attr'] = json_encode($requestDecoded['attr']);
81 $_POST['items'] = json_encode($requestDecoded['items']);
82 }
83
84 // delete
85 if ($action == 'delete') {
86 $_POST['items'] = $request;
87 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +010088 }
89 api_log($_POST);
90
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +010091
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +010092 $request_incomplete = json_encode(array(
93 'type' => 'error',
94 'msg' => 'Cannot find attributes in post data'
95 ));
96
97 switch ($action) {
98 case "add":
99 if ($_SESSION['mailcow_cc_api_access'] == 'ro' || isset($_SESSION['pending_mailcow_cc_username'])) {
100 http_response_code(403);
101 echo json_encode(array(
102 'type' => 'error',
103 'msg' => 'API read/write access denied'
104 ));
105 exit();
106 }
107 function process_add_return($return) {
108 $generic_failure = json_encode(array(
109 'type' => 'error',
110 'msg' => 'Cannot add item'
111 ));
112 $generic_success = json_encode(array(
113 'type' => 'success',
114 'msg' => 'Task completed'
115 ));
116 if ($return === false) {
117 echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_failure;
118 }
119 else {
120 echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_success;
121 }
122 }
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100123 if (!isset($_POST['attr']) && $category != "fido2-registration" && $category != "webauthn-tfa-registration") {
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100124 echo $request_incomplete;
125 exit;
126 }
127 else {
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100128 if ($category != "fido2-registration" && $category != "webauthn-tfa-registration") {
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100129 $attr = (array)json_decode($_POST['attr'], true);
130 }
131 unset($attr['csrf_token']);
132 }
133 // only allow POST requests to POST API endpoints
134 if ($_SERVER['REQUEST_METHOD'] != 'POST') {
135 http_response_code(405);
136 echo json_encode(array(
137 'type' => 'error',
138 'msg' => 'only POST method is allowed'
139 ));
140 exit();
141 }
142
143 switch ($category) {
144 // fido2-registration via POST
145 case "fido2-registration":
146 header('Content-Type: application/json');
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +0200147 if (isset($_SESSION["mailcow_cc_role"])) {
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100148 $post = trim(file_get_contents('php://input'));
149 if ($post) {
150 $post = json_decode($post);
151 }
152 $clientDataJSON = base64_decode($post->clientDataJSON);
153 $attestationObject = base64_decode($post->attestationObject);
154 $challenge = $_SESSION['challenge'];
155 try {
156 $data = $WebAuthn->processCreate($clientDataJSON, $attestationObject, $challenge, $GLOBALS['FIDO2_UV_FLAG_REGISTER'], $GLOBALS['FIDO2_USER_PRESENT_FLAG']);
157 }
158 catch (Throwable $ex) {
159 $return = new stdClass();
160 $return->success = false;
161 $return->msg = $ex->getMessage();
162 echo json_encode($return);
163 exit;
164 }
165 fido2(array("action" => "register", "registration" => $data));
166 $return = new stdClass();
167 $return->success = true;
168 echo json_encode($return);
169 exit;
170 }
171 else {
172 echo $request_incomplete;
173 exit;
174 }
175 break;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100176 case "webauthn-tfa-registration":
177 if (isset($_SESSION["mailcow_cc_role"])) {
178 // parse post data
179 $post = trim(file_get_contents('php://input'));
180 if ($post) $post = json_decode($post);
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +0100181
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100182 // process registration data from authenticator
183 try {
184 // decode base64 strings
185 $clientDataJSON = base64_decode($post->clientDataJSON);
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +0100186 $attestationObject = base64_decode($post->attestationObject);
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100187
188 // processCreate($clientDataJSON, $attestationObject, $challenge, $requireUserVerification=false, $requireUserPresent=true, $failIfRootMismatch=true)
189 $data = $WebAuthn->processCreate($clientDataJSON, $attestationObject, $_SESSION['challenge'], false, true);
190
191 // safe authenticator in mysql `tfa` table
192 $_data['tfa_method'] = $post->tfa_method;
193 $_data['key_id'] = $post->key_id;
194 $_data['confirm_password'] = $post->confirm_password;
195 $_data['registration'] = $data;
196 set_tfa($_data);
197 }
198 catch (Throwable $ex) {
199 // err
200 $return = new stdClass();
201 $return->success = false;
202 $return->msg = $ex->getMessage();
203 echo json_encode($return);
204 exit;
205 }
206
207
208 // send response
209 $return = new stdClass();
210 $return->success = true;
211 echo json_encode($return);
212 exit;
213 }
214 else {
215 // err - request incomplete
216 echo $request_incomplete;
217 exit;
218 }
219 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100220 case "time_limited_alias":
221 process_add_return(mailbox('add', 'time_limited_alias', $attr));
222 break;
223 case "relayhost":
224 process_add_return(relayhost('add', $attr));
225 break;
226 case "transport":
227 process_add_return(transport('add', $attr));
228 break;
229 case "rsetting":
230 process_add_return(rsettings('add', $attr));
231 break;
232 case "mailbox":
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100233 switch ($object) {
234 case "template":
235 process_add_return(mailbox('add', 'mailbox_templates', $attr));
236 break;
237 default:
238 process_add_return(mailbox('add', 'mailbox', $attr));
239 break;
240 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100241 break;
242 case "oauth2-client":
243 process_add_return(oauth2('add', 'client', $attr));
244 break;
245 case "domain":
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100246 switch ($object) {
247 case "template":
248 process_add_return(mailbox('add', 'domain_templates', $attr));
249 break;
250 default:
251 process_add_return(mailbox('add', 'domain', $attr));
252 break;
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +0100253 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100254 break;
255 case "resource":
256 process_add_return(mailbox('add', 'resource', $attr));
257 break;
258 case "alias":
259 process_add_return(mailbox('add', 'alias', $attr));
260 break;
261 case "filter":
262 process_add_return(mailbox('add', 'filter', $attr));
263 break;
264 case "global-filter":
265 process_add_return(mailbox('add', 'global_filter', $attr));
266 break;
267 case "domain-policy":
268 process_add_return(policy('add', 'domain', $attr));
269 break;
270 case "mailbox-policy":
271 process_add_return(policy('add', 'mailbox', $attr));
272 break;
273 case "alias-domain":
274 process_add_return(mailbox('add', 'alias_domain', $attr));
275 break;
276 case "fwdhost":
277 process_add_return(fwdhost('add', $attr));
278 break;
279 case "dkim":
280 process_add_return(dkim('add', $attr));
281 break;
282 case "dkim_duplicate":
283 process_add_return(dkim('duplicate', $attr));
284 break;
285 case "dkim_import":
286 process_add_return(dkim('import', $attr));
287 break;
288 case "domain-admin":
289 process_add_return(domain_admin('add', $attr));
290 break;
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +0100291 case "sso":
292 switch ($object) {
293 case "domain-admin":
294 $data = domain_admin_sso('issue', $attr);
295 if($data) {
296 echo json_encode($data);
297 exit(0);
298 }
299 process_add_return($data);
300 break;
301 }
302 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100303 case "admin":
304 process_add_return(admin('add', $attr));
305 break;
306 case "syncjob":
307 process_add_return(mailbox('add', 'syncjob', $attr));
308 break;
309 case "bcc":
310 process_add_return(bcc('add', $attr));
311 break;
312 case "recipient_map":
313 process_add_return(recipient_map('add', $attr));
314 break;
315 case "tls-policy-map":
316 process_add_return(tls_policy_maps('add', $attr));
317 break;
318 case "app-passwd":
319 process_add_return(app_passwd('add', $attr));
320 break;
321 // return no route found if no case is matched
322 default:
323 http_response_code(404);
324 echo json_encode(array(
325 'type' => 'error',
326 'msg' => 'route not found'
327 ));
328 exit();
329 }
330 break;
331 case "process":
332 // only allow POST requests to process API endpoints
333 if ($_SERVER['REQUEST_METHOD'] != 'POST') {
334 http_response_code(405);
335 echo json_encode(array(
336 'type' => 'error',
337 'msg' => 'only POST method is allowed'
338 ));
339 exit();
340 }
341 switch ($category) {
342 case "fido2-args":
343 header('Content-Type: application/json');
344 $post = trim(file_get_contents('php://input'));
345 if ($post) {
346 $post = json_decode($post);
347 }
348 $clientDataJSON = base64_decode($post->clientDataJSON);
349 $authenticatorData = base64_decode($post->authenticatorData);
350 $signature = base64_decode($post->signature);
351 $id = base64_decode($post->id);
352 $challenge = $_SESSION['challenge'];
353 $process_fido2 = fido2(array("action" => "get_by_b64cid", "cid" => $post->id));
354 if ($process_fido2['pub_key'] === false) {
355 $return = new stdClass();
356 $return->success = false;
357 echo json_encode($return);
358 exit;
359 }
360 try {
361 $WebAuthn->processGet($clientDataJSON, $authenticatorData, $signature, $process_fido2['pub_key'], $challenge, null, $GLOBALS['FIDO2_UV_FLAG_LOGIN'], $GLOBALS['FIDO2_USER_PRESENT_FLAG']);
362 }
363 catch (Throwable $ex) {
364 unset($process_fido2);
365 $return = new stdClass();
366 $return->success = false;
367 echo json_encode($return);
368 exit;
369 }
370 $return = new stdClass();
371 $return->success = true;
372 $stmt = $pdo->prepare("SELECT `superadmin` FROM `admin` WHERE `username` = :username");
373 $stmt->execute(array(':username' => $process_fido2['username']));
374 $obj_props = $stmt->fetch(PDO::FETCH_ASSOC);
375 if ($obj_props['superadmin'] === 1) {
376 $_SESSION["mailcow_cc_role"] = "admin";
377 }
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +0200378 elseif ($obj_props['superadmin'] === 0) {
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100379 $_SESSION["mailcow_cc_role"] = "domainadmin";
380 }
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +0200381 else {
382 $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :username");
383 $stmt->execute(array(':username' => $process_fido2['username']));
384 $row = $stmt->fetch(PDO::FETCH_ASSOC);
385 if ($row['username'] == $process_fido2['username']) {
386 $_SESSION["mailcow_cc_role"] = "user";
387 }
388 }
389 if (empty($_SESSION["mailcow_cc_role"])) {
390 session_unset();
391 session_destroy();
392 exit;
393 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100394 $_SESSION["mailcow_cc_username"] = $process_fido2['username'];
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100395 $_SESSION["fido2_cid"] = $process_fido2['cid'];
396 unset($_SESSION["challenge"]);
397 $_SESSION['return'][] = array(
398 'type' => 'success',
399 'log' => array("fido2_login"),
400 'msg' => array('logged_in_as', $process_fido2['username'])
401 );
402 echo json_encode($return);
403 break;
404 }
405 break;
406 case "get":
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +0200407 function process_get_return($data, $object = true) {
408 if ($object === true) {
409 $ret_str = '{}';
410 }
411 else {
412 $ret_str = '[]';
413 }
414 echo (!isset($data) || empty($data)) ? $ret_str : json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100415 }
416 // only allow GET requests to GET API endpoints
417 if ($_SERVER['REQUEST_METHOD'] != 'GET') {
418 http_response_code(405);
419 echo json_encode(array(
420 'type' => 'error',
421 'msg' => 'only GET method is allowed'
422 ));
423 exit();
424 }
425 switch ($category) {
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100426 // fido2
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100427 case "fido2-registration":
428 header('Content-Type: application/json');
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +0200429 if (isset($_SESSION["mailcow_cc_role"])) {
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100430 // Exclude existing CredentialIds, if any
431 $excludeCredentialIds = fido2(array("action" => "get_user_cids"));
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100432 $createArgs = $WebAuthn->getCreateArgs($_SESSION["mailcow_cc_username"], $_SESSION["mailcow_cc_username"], $_SESSION["mailcow_cc_username"], 30, true, $GLOBALS['FIDO2_UV_FLAG_REGISTER'], null, $excludeCredentialIds);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100433 print(json_encode($createArgs));
434 $_SESSION['challenge'] = $WebAuthn->getChallenge();
435 return;
436 }
437 else {
438 return;
439 }
440 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100441 case "fido2-get-args":
442 header('Content-Type: application/json');
443 // Login without username, no ids!
444 // $ids = fido2(array("action" => "get_all_cids"));
445 // if (count($ids) == 0) {
446 // return;
447 // }
448 $ids = NULL;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100449
450 $getArgs = $WebAuthn->getGetArgs($ids, 30, false, false, false, false, $GLOBALS['FIDO2_UV_FLAG_LOGIN']);
451 print(json_encode($getArgs));
452 $_SESSION['challenge'] = $WebAuthn->getChallenge();
453 return;
454 break;
455 // webauthn two factor authentication
456 case "webauthn-tfa-registration":
457 if (isset($_SESSION["mailcow_cc_role"])) {
458 // Exclude existing CredentialIds, if any
459 $stmt = $pdo->prepare("SELECT `keyHandle` FROM `tfa` WHERE username = :username AND authmech = :authmech");
460 $stmt->execute(array(
461 ':username' => $_SESSION['mailcow_cc_username'],
462 ':authmech' => 'webauthn'
463 ));
464 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
465 while($row = array_shift($rows)) {
466 $excludeCredentialIds[] = base64_decode($row['keyHandle']);
467 }
468 // getCreateArgs($userId, $userName, $userDisplayName, $timeout=20, $requireResidentKey=false, $requireUserVerification=false, $crossPlatformAttachment=null, $excludeCredentialIds=array())
469 // cross-platform: true, if type internal is not allowed
470 // false, if only internal is allowed
471 // null, if internal and cross-platform is allowed
472 $createArgs = $WebAuthn->getCreateArgs($_SESSION["mailcow_cc_username"], $_SESSION["mailcow_cc_username"], $_SESSION["mailcow_cc_username"], 30, false, $GLOBALS['WEBAUTHN_UV_FLAG_REGISTER'], null, $excludeCredentialIds);
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +0100473
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100474 print(json_encode($createArgs));
475 $_SESSION['challenge'] = $WebAuthn->getChallenge();
476 return;
477
478 }
479 else {
480 return;
481 }
482 break;
483 case "webauthn-tfa-get-args":
484 $stmt = $pdo->prepare("SELECT `keyHandle` FROM `tfa` WHERE username = :username AND authmech = :authmech");
485 $stmt->execute(array(
486 ':username' => $_SESSION['pending_mailcow_cc_username'],
487 ':authmech' => 'webauthn'
488 ));
489 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
490 if (count($rows) == 0) {
491 print(json_encode(array(
492 'type' => 'error',
493 'msg' => 'Cannot find matching credentialIds'
494 )));
495 exit;
496 }
497 while($row = array_shift($rows)) {
498 $cids[] = base64_decode($row['keyHandle']);
499 }
500
501 $getArgs = $WebAuthn->getGetArgs($cids, 30, false, false, false, false, $GLOBALS['WEBAUTHN_UV_FLAG_LOGIN']);
502 $getArgs->publicKey->extensions = array('appid' => "https://".$getArgs->publicKey->rpId);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100503 print(json_encode($getArgs));
504 $_SESSION['challenge'] = $WebAuthn->getChallenge();
505 return;
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +0100506 break;
507 case "fail2ban":
508 if (!isset($_SESSION['mailcow_cc_role'])){
509 switch ($object) {
510 case 'banlist':
511 header('Content-Type: text/plain');
512 echo fail2ban('banlist', 'get', $extra);
513 break;
514 }
515 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100516 break;
517 }
518 if (isset($_SESSION['mailcow_cc_role'])) {
519 switch ($category) {
520 case "rspamd":
521 switch ($object) {
522 case "actions":
523 $data = rspamd_actions();
524 if ($data) {
525 echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
526 }
527 else {
528 echo '{}';
529 }
530 break;
531 }
532 break;
533
534 case "domain":
535 switch ($object) {
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +0100536 case "datatables":
537 $table = ['domain', 'd'];
538 $primaryKey = 'domain';
539 $columns = [
540 ['db' => 'domain', 'dt' => 2],
541 ['db' => 'aliases', 'dt' => 3, 'order_subquery' => "SELECT COUNT(*) FROM `alias` WHERE (`domain`= `d`.`domain` OR `domain` IN (SELECT `alias_domain` FROM `alias_domain` WHERE `target_domain` = `d`.`domain`)) AND `address` NOT IN (SELECT `username` FROM `mailbox`)"],
542 ['db' => 'mailboxes', 'dt' => 4, 'order_subquery' => "SELECT COUNT(*) FROM `mailbox` WHERE `mailbox`.`domain` = `d`.`domain` AND (`mailbox`.`kind` = '' OR `mailbox`.`kind` = NULL)"],
543 ['db' => 'quota', 'dt' => 5, 'order_subquery' => "SELECT COALESCE(SUM(`mailbox`.`quota`), 0) FROM `mailbox` WHERE `mailbox`.`domain` = `d`.`domain` AND (`mailbox`.`kind` = '' OR `mailbox`.`kind` = NULL)"],
544 ['db' => 'stats', 'dt' => 6, 'dummy' => true, 'order_subquery' => "SELECT SUM(bytes) FROM `quota2` WHERE `quota2`.`username` IN (SELECT `username` FROM `mailbox` WHERE `domain` = `d`.`domain`)"],
545 ['db' => 'defquota', 'dt' => 7],
546 ['db' => 'maxquota', 'dt' => 8],
547 ['db' => 'backupmx', 'dt' => 10],
548 ['db' => 'tags', 'dt' => 14, 'dummy' => true, 'search' => ['join' => 'LEFT JOIN `tags_domain` AS `td` ON `td`.`domain` = `d`.`domain`', 'where_column' => '`td`.`tag_name`']],
549 ['db' => 'active', 'dt' => 15],
550 ];
551
552 require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/lib/ssp.class.php';
553 global $pdo;
554 if($_SESSION['mailcow_cc_role'] === 'admin') {
555 $data = SSP::simple($_GET, $pdo, $table, $primaryKey, $columns);
556 } elseif ($_SESSION['mailcow_cc_role'] === 'domainadmin') {
557 $data = SSP::complex($_GET, $pdo, $table, $primaryKey, $columns,
558 'INNER JOIN domain_admins as da ON da.domain = d.domain',
559 [
560 'condition' => 'da.active = 1 and da.username = :username',
561 'bindings' => ['username' => $_SESSION['mailcow_cc_username']]
562 ]);
563 }
564
565 if (!empty($data['data'])) {
566 $domainsData = [];
567 foreach ($data['data'] as $domain) {
568 if ($details = mailbox('get', 'domain_details', $domain[2])) {
569 $domainsData[] = $details;
570 }
571 }
572 $data['data'] = $domainsData;
573 }
574
575 process_get_return($data);
576 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100577 case "all":
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100578 $tags = null;
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +0100579 if (isset($_GET['tags']) && $_GET['tags'] != '')
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100580 $tags = explode(',', $_GET['tags']);
581
582 $domains = mailbox('get', 'domains', null, $tags);
583
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100584 if (!empty($domains)) {
585 foreach ($domains as $domain) {
586 if ($details = mailbox('get', 'domain_details', $domain)) {
587 $data[] = $details;
588 }
589 else {
590 continue;
591 }
592 }
593 process_get_return($data);
594 }
595 else {
596 echo '{}';
597 }
598 break;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100599 case "template":
600 switch ($extra){
601 case "all":
602 process_get_return(mailbox('get', 'domain_templates'));
603 break;
604 default:
605 process_get_return(mailbox('get', 'domain_templates', $extra));
606 break;
607 }
608 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100609 default:
610 $data = mailbox('get', 'domain_details', $object);
611 process_get_return($data);
612 break;
613 }
614 break;
615
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +0200616 case "passwordpolicy":
617 switch ($object) {
618 case "html":
619 $password_complexity_rules = password_complexity('html');
620 if ($password_complexity_rules !== false) {
621 process_get_return($password_complexity_rules);
622 }
623 else {
624 echo '{}';
625 }
626 break;
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +0100627 default:
628 $password_complexity_rules = password_complexity('get');
629 if ($password_complexity_rules !== false) {
630 process_get_return($password_complexity_rules);
631 }
632 else {
633 echo '{}';
634 }
635 break;
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +0200636 }
637 break;
638
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100639 case "app-passwd":
640 switch ($object) {
641 case "all":
642 if (empty($extra)) {
643 $app_passwds = app_passwd('get');
644 }
645 else {
646 $app_passwds = app_passwd('get', array('username' => $extra));
647 }
648 if (!empty($app_passwds)) {
649 foreach ($app_passwds as $app_passwd) {
Matthias Andreas Benkardb4b5cc12021-12-28 18:02:04 +0100650 $details = app_passwd('details', $app_passwd['id']);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100651 if ($details !== false) {
652 $data[] = $details;
653 }
654 else {
655 continue;
656 }
657 }
658 process_get_return($data);
659 }
660 else {
661 echo '{}';
662 }
663 break;
664
665 default:
666 $data = app_passwd('details', array('id' => $object['id']));
667 process_get_return($data);
668 break;
669 }
670 break;
671
672 case "mailq":
673 switch ($object) {
674 case "all":
675 $mailq = mailq('get');
676 if (!empty($mailq)) {
677 echo $mailq;
678 }
679 else {
680 echo '[]';
681 }
682 break;
683 }
684 break;
Matthias Andreas Benkardb4b5cc12021-12-28 18:02:04 +0100685
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100686 case "postcat":
687 switch ($object) {
688 default:
689 $data = mailq('cat', array('qid' => $object));
690 echo $data;
691 break;
692 }
693 break;
694
695 case "global_filters":
696 $global_filters = mailbox('get', 'global_filter_details');
697 switch ($object) {
698 case "all":
699 if (!empty($global_filters)) {
700 process_get_return($global_filters);
701 }
702 else {
703 echo '{}';
704 }
705 break;
706 case "prefilter":
707 if (!empty($global_filters['prefilter'])) {
708 process_get_return($global_filters['prefilter']);
709 }
710 else {
711 echo '{}';
712 }
713 break;
714 case "postfilter":
715 if (!empty($global_filters['postfilter'])) {
716 process_get_return($global_filters['postfilter']);
717 }
718 else {
719 echo '{}';
720 }
721 break;
722 }
723 break;
724
725 case "rl-domain":
726 switch ($object) {
727 case "all":
728 $domains = array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains'));
729 if (!empty($domains)) {
730 foreach ($domains as $domain) {
731 if ($details = ratelimit('get', 'domain', $domain)) {
732 $details['domain'] = $domain;
733 $data[] = $details;
734 }
735 else {
736 continue;
737 }
738 }
739 process_get_return($data);
740 }
741 else {
742 echo '{}';
743 }
744 break;
745
746 default:
747 $data = ratelimit('get', 'domain', $object);
748 process_get_return($data);
749 break;
750 }
751 break;
752
753 case "rl-mbox":
754 switch ($object) {
755 case "all":
756 $domains = mailbox('get', 'domains');
757 if (!empty($domains)) {
758 foreach ($domains as $domain) {
759 $mailboxes = mailbox('get', 'mailboxes', $domain);
760 if (!empty($mailboxes)) {
761 foreach ($mailboxes as $mailbox) {
762 if ($details = ratelimit('get', 'mailbox', $mailbox)) {
763 $details['mailbox'] = $mailbox;
764 $data[] = $details;
765 }
766 else {
767 continue;
768 }
769 }
770 }
771 }
772 process_get_return($data);
773 }
774 else {
775 echo '{}';
776 }
777 break;
778
779 default:
780 $data = ratelimit('get', 'mailbox', $object);
781 process_get_return($data);
782 break;
783 }
784 break;
785
786 case "relayhost":
787 switch ($object) {
788 case "all":
789 $relayhosts = relayhost('get');
790 if (!empty($relayhosts)) {
791 foreach ($relayhosts as $relayhost) {
792 if ($details = relayhost('details', $relayhost['id'])) {
793 $data[] = $details;
794 }
795 else {
796 continue;
797 }
798 }
799 process_get_return($data);
800 }
801 else {
802 echo '{}';
803 }
804 break;
805
806 default:
807 $data = relayhost('details', $object);
808 process_get_return($data);
809 break;
810 }
811 break;
812
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +0200813 case "last-login":
814 if ($object) {
815 // extra == days
816 if (isset($extra) && intval($extra) >= 1) {
817 $data = last_login('get', $object, intval($extra));
818 }
819 else {
820 $data = last_login('get', $object);
821 }
822 process_get_return($data);
823 }
824 break;
825
826 // Todo: move to delete
827 case "reset-last-login":
828 if ($object) {
829 $data = last_login('reset', $object);
830 process_get_return($data);
831 }
832 break;
833
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100834 case "transport":
835 switch ($object) {
836 case "all":
837 $transports = transport('get');
838 if (!empty($transports)) {
839 foreach ($transports as $transport) {
840 if ($details = transport('details', $transport['id'])) {
841 $data[] = $details;
842 }
843 else {
844 continue;
845 }
846 }
847 process_get_return($data);
848 }
849 else {
850 echo '{}';
851 }
852 break;
853
854 default:
855 $data = transport('details', $object);
856 process_get_return($data);
857 break;
858 }
859 break;
860
861 case "rsetting":
862 switch ($object) {
863 case "all":
864 $rsettings = rsettings('get');
865 if (!empty($rsettings)) {
866 foreach ($rsettings as $rsetting) {
867 if ($details = rsettings('details', $rsetting['id'])) {
868 $data[] = $details;
869 }
870 else {
871 continue;
872 }
873 }
874 process_get_return($data);
875 }
876 else {
877 echo '{}';
878 }
879 break;
880
881 default:
882 $data = rsettings('details', $object);
883 process_get_return($data);
884 break;
885 }
886 break;
887
888 case "oauth2-client":
889 switch ($object) {
890 case "all":
891 $clients = oauth2('get', 'clients');
892 if (!empty($clients)) {
893 foreach ($clients as $client) {
894 if ($details = oauth2('details', 'client', $client)) {
895 $data[] = $details;
896 }
897 else {
898 continue;
899 }
900 }
901 process_get_return($data);
902 }
903 else {
904 echo '{}';
905 }
906 break;
907
908 default:
909 $data = oauth2('details', 'client', $object);
910 process_get_return($data);
911 break;
912 }
913 break;
914
915 case "logs":
916 switch ($object) {
917 case "dovecot":
918 // 0 is first record, so empty is fine
919 if (isset($extra)) {
920 $extra = preg_replace('/[^\d\-]/i', '', $extra);
921 $logs = get_logs('dovecot-mailcow', $extra);
922 }
923 else {
924 $logs = get_logs('dovecot-mailcow');
925 }
926 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
927 break;
928 case "ratelimited":
929 // 0 is first record, so empty is fine
930 if (isset($extra)) {
931 $extra = preg_replace('/[^\d\-]/i', '', $extra);
932 $logs = get_logs('ratelimited', $extra);
933 }
934 else {
935 $logs = get_logs('ratelimited');
936 }
937 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
938 break;
939 case "netfilter":
940 // 0 is first record, so empty is fine
941 if (isset($extra)) {
942 $extra = preg_replace('/[^\d\-]/i', '', $extra);
943 $logs = get_logs('netfilter-mailcow', $extra);
944 }
945 else {
946 $logs = get_logs('netfilter-mailcow');
947 }
948 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
949 break;
950 case "postfix":
951 // 0 is first record, so empty is fine
952 if (isset($extra)) {
953 $extra = preg_replace('/[^\d\-]/i', '', $extra);
954 $logs = get_logs('postfix-mailcow', $extra);
955 }
956 else {
957 $logs = get_logs('postfix-mailcow');
958 }
959 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
960 break;
961 case "autodiscover":
962 // 0 is first record, so empty is fine
963 if (isset($extra)) {
964 $extra = preg_replace('/[^\d\-]/i', '', $extra);
965 $logs = get_logs('autodiscover-mailcow', $extra);
966 }
967 else {
968 $logs = get_logs('autodiscover-mailcow');
969 }
970 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
971 break;
972 case "sogo":
973 // 0 is first record, so empty is fine
974 if (isset($extra)) {
975 $extra = preg_replace('/[^\d\-]/i', '', $extra);
976 $logs = get_logs('sogo-mailcow', $extra);
977 }
978 else {
979 $logs = get_logs('sogo-mailcow');
980 }
981 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
982 break;
983 case "ui":
984 // 0 is first record, so empty is fine
985 if (isset($extra)) {
986 $extra = preg_replace('/[^\d\-]/i', '', $extra);
987 $logs = get_logs('mailcow-ui', $extra);
988 }
989 else {
990 $logs = get_logs('mailcow-ui');
991 }
992 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
993 break;
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +0200994 case "sasl":
995 // 0 is first record, so empty is fine
996 if (isset($extra)) {
997 $extra = preg_replace('/[^\d\-]/i', '', $extra);
998 $logs = get_logs('sasl', $extra);
999 }
1000 else {
1001 $logs = get_logs('sasl');
1002 }
1003 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
1004 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001005 case "watchdog":
1006 // 0 is first record, so empty is fine
1007 if (isset($extra)) {
1008 $extra = preg_replace('/[^\d\-]/i', '', $extra);
1009 $logs = get_logs('watchdog-mailcow', $extra);
1010 }
1011 else {
1012 $logs = get_logs('watchdog-mailcow');
1013 }
1014 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
1015 break;
1016 case "acme":
1017 // 0 is first record, so empty is fine
1018 if (isset($extra)) {
1019 $extra = preg_replace('/[^\d\-]/i', '', $extra);
1020 $logs = get_logs('acme-mailcow', $extra);
1021 }
1022 else {
1023 $logs = get_logs('acme-mailcow');
1024 }
1025 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
1026 break;
1027 case "api":
1028 // 0 is first record, so empty is fine
1029 if (isset($extra)) {
1030 $extra = preg_replace('/[^\d\-]/i', '', $extra);
1031 $logs = get_logs('api-mailcow', $extra);
1032 }
1033 else {
1034 $logs = get_logs('api-mailcow');
1035 }
1036 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
1037 break;
1038 case "rspamd-history":
1039 // 0 is first record, so empty is fine
1040 if (isset($extra)) {
1041 $extra = preg_replace('/[^\d\-]/i', '', $extra);
1042 $logs = get_logs('rspamd-history', $extra);
1043 }
1044 else {
1045 $logs = get_logs('rspamd-history');
1046 }
1047 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
1048 break;
1049 case "rspamd-stats":
1050 $logs = get_logs('rspamd-stats');
1051 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
1052 break;
1053 // return no route found if no case is matched
1054 default:
1055 http_response_code(404);
1056 echo json_encode(array(
1057 'type' => 'error',
1058 'msg' => 'route not found'
1059 ));
1060 exit();
1061 }
1062 break;
1063 case "mailbox":
1064 switch ($object) {
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001065 case "datatables":
1066 $table = ['mailbox', 'm'];
1067 $primaryKey = 'username';
1068 $columns = [
1069 ['db' => 'username', 'dt' => 2],
1070 ['db' => 'quota', 'dt' => 3],
1071 ['db' => 'last_mail_login', 'dt' => 4, 'dummy' => true, 'order_subquery' => "SELECT MAX(`datetime`) FROM `sasl_log` WHERE `service` != 'SSO' AND `username` = `m`.`username`"],
1072 ['db' => 'last_pw_change', 'dt' => 5, 'dummy' => true, 'order_subquery' => "JSON_EXTRACT(attributes, '$.passwd_update')"],
1073 ['db' => 'in_use', 'dt' => 6, 'dummy' => true, 'order_subquery' => "(SELECT SUM(bytes) FROM `quota2` WHERE `quota2`.`username` = `m`.`username`) / `m`.`quota`"],
1074 ['db' => 'messages', 'dt' => 17, 'dummy' => true, 'order_subquery' => "SELECT SUM(messages) FROM `quota2` WHERE `quota2`.`username` = `m`.`username`"],
1075 ['db' => 'tags', 'dt' => 20, 'dummy' => true, 'search' => ['join' => 'LEFT JOIN `tags_mailbox` AS `tm` ON `tm`.`username` = `m`.`username`', 'where_column' => '`tm`.`tag_name`']],
1076 ['db' => 'active', 'dt' => 21]
1077 ];
1078
1079 require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/lib/ssp.class.php';
1080 global $pdo;
1081 if($_SESSION['mailcow_cc_role'] === 'admin') {
1082 $data = SSP::complex($_GET, $pdo, $table, $primaryKey, $columns, null, "(`m`.`kind` = '' OR `m`.`kind` = NULL)");
1083 } elseif ($_SESSION['mailcow_cc_role'] === 'domainadmin') {
1084 $data = SSP::complex($_GET, $pdo, $table, $primaryKey, $columns,
1085 'INNER JOIN domain_admins as da ON da.domain = m.domain',
1086 [
1087 'condition' => "(`m`.`kind` = '' OR `m`.`kind` = NULL) AND `da`.`active` = 1 AND `da`.`username` = :username",
1088 'bindings' => ['username' => $_SESSION['mailcow_cc_username']]
1089 ]);
1090 }
1091
1092 if (!empty($data['data'])) {
1093 $mailboxData = [];
1094 foreach ($data['data'] as $mailbox) {
1095 if ($details = mailbox('get', 'mailbox_details', $mailbox[2])) {
1096 $mailboxData[] = $details;
1097 }
1098 }
1099 $data['data'] = $mailboxData;
1100 }
1101
1102 process_get_return($data);
1103 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001104 case "all":
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02001105 case "reduced":
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001106 $tags = null;
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001107 if (isset($_GET['tags']) && $_GET['tags'] != '')
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001108 $tags = explode(',', $_GET['tags']);
1109
1110 if (empty($extra)) $domains = mailbox('get', 'domains');
1111 else $domains = explode(',', $extra);
1112
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001113 if (!empty($domains)) {
1114 foreach ($domains as $domain) {
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001115 $mailboxes = mailbox('get', 'mailboxes', $domain, $tags);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001116 if (!empty($mailboxes)) {
1117 foreach ($mailboxes as $mailbox) {
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001118 if ($details = mailbox('get', 'mailbox_details', $mailbox, $object)) $data[] = $details;
1119 else continue;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001120 }
1121 }
1122 }
1123 process_get_return($data);
1124 }
1125 else {
1126 echo '{}';
1127 }
1128 break;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001129 case "template":
1130 switch ($extra){
1131 case "all":
1132 process_get_return(mailbox('get', 'mailbox_templates'));
1133 break;
1134 default:
1135 process_get_return(mailbox('get', 'mailbox_templates', $extra));
1136 break;
1137 }
1138 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001139 default:
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001140 $tags = null;
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001141 if (isset($_GET['tags']) && $_GET['tags'] != '')
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001142 $tags = explode(',', $_GET['tags']);
1143
1144 if ($tags === null) {
1145 $data = mailbox('get', 'mailbox_details', $object);
1146 process_get_return($data);
1147 } else {
1148 $mailboxes = mailbox('get', 'mailboxes', $object, $tags);
1149 if (is_array($mailboxes)) {
1150 foreach ($mailboxes as $mailbox) {
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001151 if ($details = mailbox('get', 'mailbox_details', $mailbox))
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001152 $data[] = $details;
1153 }
1154 }
1155 process_get_return($data, false);
1156 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001157 break;
1158 }
1159 break;
Matthias Andreas Benkardb4b5cc12021-12-28 18:02:04 +01001160 case "bcc-destination-options":
1161 $domains = mailbox('get', 'domains');
1162 $alias_domains = mailbox('get', 'alias_domains');
1163 $data = array();
1164 if (!empty($domains)) {
1165 foreach ($domains as $domain) {
1166 $data['domains'][] = $domain;
1167 $mailboxes = mailbox('get', 'mailboxes', $domain);
1168 foreach ($mailboxes as $mailbox) {
1169 $data['mailboxes'][$mailbox][] = $mailbox;
1170 $user_alias_details = user_get_alias_details($mailbox);
1171 foreach ($user_alias_details['direct_aliases'] as $k => $v) {
1172 $data['mailboxes'][$mailbox][] = $k;
1173 }
1174 foreach ($user_alias_details['shared_aliases'] as $k => $v) {
1175 $data['mailboxes'][$mailbox][] = $k;
1176 }
1177 }
1178 }
1179 }
1180 if (!empty($alias_domains)) {
1181 foreach ($alias_domains as $alias_domain) {
1182 $data['alias_domains'][] = $alias_domain;
1183 }
1184 }
1185 process_get_return($data);
1186 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001187 case "syncjobs":
1188 switch ($object) {
1189 case "all":
1190 $domains = mailbox('get', 'domains');
1191 if (!empty($domains)) {
1192 foreach ($domains as $domain) {
1193 $mailboxes = mailbox('get', 'mailboxes', $domain);
1194 if (!empty($mailboxes)) {
1195 foreach ($mailboxes as $mailbox) {
1196 $syncjobs = mailbox('get', 'syncjobs', $mailbox);
1197 if (!empty($syncjobs)) {
1198 foreach ($syncjobs as $syncjob) {
1199 if (isset($extra)) {
1200 $details = mailbox('get', 'syncjob_details', $syncjob, explode(',', $extra));
1201 }
1202 else {
1203 $details = mailbox('get', 'syncjob_details', $syncjob);
1204 }
1205 if ($details) {
1206 $data[] = $details;
1207 }
1208 else {
1209 continue;
1210 }
1211 }
1212 }
1213 }
1214 }
1215 }
1216 process_get_return($data);
1217 }
1218 else {
1219 echo '{}';
1220 }
1221 break;
1222
1223 default:
1224 $syncjobs = mailbox('get', 'syncjobs', $object);
1225 if (!empty($syncjobs)) {
1226 foreach ($syncjobs as $syncjob) {
1227 if (isset($extra)) {
1228 $details = mailbox('get', 'syncjob_details', $syncjob, explode(',', $extra));
1229 }
1230 else {
1231 $details = mailbox('get', 'syncjob_details', $syncjob);
1232 }
1233 if ($details) {
1234 $data[] = $details;
1235 }
1236 else {
1237 continue;
1238 }
1239 }
1240 }
1241 process_get_return($data);
1242 break;
1243 }
1244 break;
1245 case "active-user-sieve":
1246 if (isset($object)) {
1247 $sieve_filter = mailbox('get', 'active_user_sieve', $object);
1248 if (!empty($sieve_filter)) {
1249 $data[] = $sieve_filter;
1250 }
1251 }
1252 process_get_return($data);
1253 break;
1254 case "filters":
1255 switch ($object) {
1256 case "all":
1257 $domains = mailbox('get', 'domains');
1258 if (!empty($domains)) {
1259 foreach ($domains as $domain) {
1260 $mailboxes = mailbox('get', 'mailboxes', $domain);
1261 if (!empty($mailboxes)) {
1262 foreach ($mailboxes as $mailbox) {
1263 $filters = mailbox('get', 'filters', $mailbox);
1264 if (!empty($filters)) {
1265 foreach ($filters as $filter) {
1266 if ($details = mailbox('get', 'filter_details', $filter)) {
1267 $data[] = $details;
1268 }
1269 else {
1270 continue;
1271 }
1272 }
1273 }
1274 }
1275 }
1276 }
1277 process_get_return($data);
1278 }
1279 else {
1280 echo '{}';
1281 }
1282 break;
1283
1284 default:
1285 $filters = mailbox('get', 'filters', $object);
1286 if (!empty($filters)) {
1287 foreach ($filters as $filter) {
1288 if ($details = mailbox('get', 'filter_details', $filter)) {
1289 $data[] = $details;
1290 }
1291 else {
1292 continue;
1293 }
1294 }
1295 }
1296 process_get_return($data);
1297 break;
1298 }
1299 break;
1300 case "bcc":
1301 switch ($object) {
1302 case "all":
1303 $bcc_items = bcc('get');
1304 if (!empty($bcc_items)) {
1305 foreach ($bcc_items as $bcc_item) {
1306 if ($details = bcc('details', $bcc_item)) {
1307 $data[] = $details;
1308 }
1309 else {
1310 continue;
1311 }
1312 }
1313 }
1314 process_get_return($data);
1315 break;
1316 default:
1317 $data = bcc('details', $object);
1318 if (!empty($data)) {
1319 $data[] = $details;
1320 }
1321 process_get_return($data);
1322 break;
1323 }
1324 break;
1325 case "recipient_map":
1326 switch ($object) {
1327 case "all":
1328 $recipient_map_items = recipient_map('get');
1329 if (!empty($recipient_map_items)) {
1330 foreach ($recipient_map_items as $recipient_map_item) {
1331 if ($details = recipient_map('details', $recipient_map_item)) {
1332 $data[] = $details;
1333 }
1334 else {
1335 continue;
1336 }
1337 }
1338 }
1339 process_get_return($data);
1340 break;
1341 default:
1342 $data = recipient_map('details', $object);
1343 if (!empty($data)) {
1344 $data[] = $details;
1345 }
1346 process_get_return($data);
1347 break;
1348 }
1349 break;
1350 case "tls-policy-map":
1351 switch ($object) {
1352 case "all":
1353 $tls_policy_maps_items = tls_policy_maps('get');
1354 if (!empty($tls_policy_maps_items)) {
1355 foreach ($tls_policy_maps_items as $tls_policy_maps_item) {
1356 if ($details = tls_policy_maps('details', $tls_policy_maps_item)) {
1357 $data[] = $details;
1358 }
1359 else {
1360 continue;
1361 }
1362 }
1363 }
1364 process_get_return($data);
1365 break;
1366 default:
1367 $data = tls_policy_maps('details', $object);
1368 if (!empty($data)) {
1369 $data[] = $details;
1370 }
1371 process_get_return($data);
1372 break;
1373 }
1374 break;
1375 case "policy_wl_mailbox":
1376 switch ($object) {
1377 default:
1378 $data = policy('get', 'mailbox', $object)['whitelist'];
1379 process_get_return($data);
1380 break;
1381 }
1382 break;
1383 case "policy_bl_mailbox":
1384 switch ($object) {
1385 default:
1386 $data = policy('get', 'mailbox', $object)['blacklist'];
1387 process_get_return($data);
1388 break;
1389 }
1390 break;
1391 case "policy_wl_domain":
1392 switch ($object) {
1393 default:
1394 $data = policy('get', 'domain', $object)['whitelist'];
1395 process_get_return($data);
1396 break;
1397 }
1398 break;
1399 case "policy_bl_domain":
1400 switch ($object) {
1401 default:
1402 $data = policy('get', 'domain', $object)['blacklist'];
1403 process_get_return($data);
1404 break;
1405 }
1406 break;
1407 case "time_limited_aliases":
1408 switch ($object) {
1409 default:
1410 $data = mailbox('get', 'time_limited_aliases', $object);
1411 process_get_return($data);
1412 break;
1413 }
1414 break;
1415 case "fail2ban":
1416 switch ($object) {
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001417 case 'banlist':
1418 header('Content-Type: text/plain');
1419 echo fail2ban('banlist', 'get', $extra);
1420 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001421 default:
1422 $data = fail2ban('get');
1423 process_get_return($data);
1424 break;
1425 }
1426 break;
1427 case "resource":
1428 switch ($object) {
1429 case "all":
1430 $domains = mailbox('get', 'domains');
1431 if (!empty($domains)) {
1432 foreach ($domains as $domain) {
1433 $resources = mailbox('get', 'resources', $domain);
1434 if (!empty($resources)) {
1435 foreach ($resources as $resource) {
1436 if ($details = mailbox('get', 'resource_details', $resource)) {
1437 $data[] = $details;
1438 }
1439 else {
1440 continue;
1441 }
1442 }
1443 }
1444 }
1445 process_get_return($data);
1446 }
1447 else {
1448 echo '{}';
1449 }
1450 break;
1451 default:
1452 $data = mailbox('get', 'resource_details', $object);
1453 process_get_return($data);
1454 break;
1455 }
1456 break;
1457 case "fwdhost":
1458 switch ($object) {
1459 case "all":
1460 process_get_return(fwdhost('get'));
1461 break;
1462 default:
1463 process_get_return(fwdhost('details', $object));
1464 break;
1465 }
1466 break;
1467 case "quarantine":
1468 // "all" will not print details
1469 switch ($object) {
1470 case "all":
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02001471 process_get_return(quarantine('get'), false);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001472 break;
1473 default:
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02001474 process_get_return(quarantine('details', $object), false);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001475 break;
1476 }
1477 break;
1478 case "alias-domain":
1479 switch ($object) {
1480 case "all":
1481 $alias_domains = mailbox('get', 'alias_domains');
1482 if (!empty($alias_domains)) {
1483 foreach ($alias_domains as $alias_domain) {
1484 if ($details = mailbox('get', 'alias_domain_details', $alias_domain)) {
1485 $data[] = $details;
1486 }
1487 else {
1488 continue;
1489 }
1490 }
1491 }
1492 process_get_return($data);
1493 break;
1494 default:
1495 process_get_return(mailbox('get', 'alias_domain_details', $object));
1496 break;
1497 }
1498 break;
1499 case "alias":
1500 switch ($object) {
1501 case "all":
1502 if (empty($extra)) {
1503 $domains = array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains'));
1504 }
1505 else {
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02001506 $domains = explode(',', $extra);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001507 }
1508 if (!empty($domains)) {
1509 foreach ($domains as $domain) {
1510 $aliases = mailbox('get', 'aliases', $domain);
1511 if (!empty($aliases)) {
1512 foreach ($aliases as $alias) {
1513 if ($details = mailbox('get', 'alias_details', $alias)) {
1514 $data[] = $details;
1515 }
1516 else {
1517 continue;
1518 }
1519 }
1520 }
1521 }
1522 process_get_return($data);
1523 }
1524 else {
1525 echo '{}';
1526 }
1527 break;
1528
1529 default:
1530 process_get_return(mailbox('get', 'alias_details', $object));
1531 break;
1532 }
1533 break;
1534 case "domain-admin":
1535 switch ($object) {
1536 case "all":
1537 $domain_admins = domain_admin('get');
1538 if (!empty($domain_admins)) {
1539 foreach ($domain_admins as $domain_admin) {
1540 if ($details = domain_admin('details', $domain_admin)) {
1541 $data[] = $details;
1542 }
1543 else {
1544 continue;
1545 }
1546 }
1547 process_get_return($data);
1548 }
1549 else {
1550 echo '{}';
1551 }
1552 break;
1553
1554 default:
1555 process_get_return(domain_admin('details', $object));
1556 break;
1557 }
1558 break;
1559 case "admin":
1560 switch ($object) {
1561 case "all":
1562 $admins = admin('get');
1563 if (!empty($admins)) {
1564 foreach ($admins as $admin) {
1565 if ($details = admin('details', $admin)) {
1566 $data[] = $details;
1567 }
1568 else {
1569 continue;
1570 }
1571 }
1572 process_get_return($data);
1573 }
1574 else {
1575 echo '{}';
1576 }
1577 break;
1578
1579 default:
1580 process_get_return(admin('details', $object));
1581 break;
1582 }
1583 break;
1584 case "dkim":
1585 switch ($object) {
1586 default:
1587 $data = dkim('details', $object);
1588 process_get_return($data);
1589 break;
1590 }
1591 break;
1592 case "presets":
1593 switch ($object) {
1594 case "rspamd":
1595 process_get_return(presets('get', 'rspamd'));
1596 break;
1597 case "sieve":
1598 process_get_return(presets('get', 'sieve'));
1599 break;
1600 }
1601 break;
1602 case "status":
1603 if ($_SESSION['mailcow_cc_role'] == "admin") {
1604 switch ($object) {
1605 case "containers":
1606 $containers = (docker('info'));
1607 foreach ($containers as $container => $container_info) {
1608 $container . ' (' . $container_info['Config']['Image'] . ')';
1609 $containerstarttime = ($container_info['State']['StartedAt']);
1610 $containerstate = ($container_info['State']['Status']);
1611 $containerimage = ($container_info['Config']['Image']);
1612 $temp[$container] = array(
1613 'type' => 'info',
1614 'container' => $container,
1615 'state' => $containerstate,
1616 'started_at' => $containerstarttime,
1617 'image' => $containerimage
1618 );
1619 }
1620 echo json_encode($temp, JSON_UNESCAPED_SLASHES);
1621 break;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001622 case "container":
1623 $container_stats = docker('container_stats', $extra);
1624 echo json_encode($container_stats);
1625 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001626 case "vmail":
1627 $exec_fields_vmail = array('cmd' => 'system', 'task' => 'df', 'dir' => '/var/vmail');
1628 $vmail_df = explode(',', json_decode(docker('post', 'dovecot-mailcow', 'exec', $exec_fields_vmail), true));
1629 $temp = array(
1630 'type' => 'info',
1631 'disk' => $vmail_df[0],
1632 'used' => $vmail_df[2],
1633 'total'=> $vmail_df[1],
1634 'used_percent' => $vmail_df[4]
1635 );
1636 echo json_encode($temp, JSON_UNESCAPED_SLASHES);
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001637 break;
1638 case "solr":
1639 $solr_status = solr_status();
1640 $solr_size = ($solr_status['status']['dovecot-fts']['index']['size']);
1641 $solr_documents = ($solr_status['status']['dovecot-fts']['index']['numDocs']);
1642 if (strtolower(getenv('SKIP_SOLR')) != 'n') {
1643 $solr_enabled = false;
1644 }
1645 else {
1646 $solr_enabled = true;
1647 }
1648 echo json_encode(array(
1649 'type' => 'info',
1650 'solr_enabled' => $solr_enabled,
1651 'solr_size' => $solr_size,
1652 'solr_documents' => $solr_documents
1653 ));
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001654 break;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001655 case "host":
1656 if (!$extra){
1657 $stats = docker("host_stats");
1658 echo json_encode($stats);
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001659 }
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001660 else if ($extra == "ip") {
1661 // get public ips
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001662
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001663 $curl = curl_init();
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001664 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
1665 curl_setopt($curl, CURLOPT_POST, 0);
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01001666 curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);
1667 curl_setopt($curl, CURLOPT_TIMEOUT, 15);
1668 curl_setopt($curl, CURLOPT_URL, 'http://ipv4.mailcow.email');
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001669 $ipv4 = curl_exec($curl);
1670 curl_setopt($curl, CURLOPT_URL, 'http://ipv6.mailcow.email');
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001671 $ipv6 = curl_exec($curl);
1672 $ips = array(
1673 "ipv4" => $ipv4,
1674 "ipv6" => $ipv6
1675 );
1676 curl_close($curl);
1677 echo json_encode($ips);
1678 }
1679 break;
1680 case "version":
1681 echo json_encode(array(
1682 'version' => $GLOBALS['MAILCOW_GIT_VERSION']
1683 ));
1684 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001685 }
1686 }
1687 break;
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001688 case "spam-score":
1689 $score = mailbox('get', 'spam_score', $object);
1690 if ($score)
1691 $score = array("score" => preg_replace("/\s+/", "", $score));
1692 process_get_return($score);
1693 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001694 break;
1695 // return no route found if no case is matched
1696 default:
1697 http_response_code(404);
1698 echo json_encode(array(
1699 'type' => 'error',
1700 'msg' => 'route not found'
1701 ));
1702 exit();
1703 }
1704 }
1705 break;
1706 case "delete":
1707 if ($_SESSION['mailcow_cc_api_access'] == 'ro' || isset($_SESSION['pending_mailcow_cc_username']) || !isset($_SESSION["mailcow_cc_username"])) {
1708 http_response_code(403);
1709 echo json_encode(array(
1710 'type' => 'error',
1711 'msg' => 'API read/write access denied'
1712 ));
1713 exit();
1714 }
1715 function process_delete_return($return) {
1716 $generic_failure = json_encode(array(
1717 'type' => 'error',
1718 'msg' => 'Cannot delete item'
1719 ));
1720 $generic_success = json_encode(array(
1721 'type' => 'success',
1722 'msg' => 'Task completed'
1723 ));
1724 if ($return === false) {
1725 echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_failure;
1726 }
1727 else {
1728 echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_success;
1729 }
1730 }
1731 if (!isset($_POST['items'])) {
1732 echo $request_incomplete;
1733 exit;
1734 }
1735 else {
1736 $items = (array)json_decode($_POST['items'], true);
1737 }
1738 // only allow POST requests to POST API endpoints
1739 if ($_SERVER['REQUEST_METHOD'] != 'POST') {
1740 http_response_code(405);
1741 echo json_encode(array(
1742 'type' => 'error',
1743 'msg' => 'only POST method is allowed'
1744 ));
1745 exit();
1746 }
1747 switch ($category) {
1748 case "alias":
1749 process_delete_return(mailbox('delete', 'alias', array('id' => $items)));
1750 break;
1751 case "oauth2-client":
1752 process_delete_return(oauth2('delete', 'client', array('id' => $items)));
1753 break;
1754 case "app-passwd":
1755 process_delete_return(app_passwd('delete', array('id' => $items)));
1756 break;
1757 case "relayhost":
1758 process_delete_return(relayhost('delete', array('id' => $items)));
1759 break;
1760 case "transport":
1761 process_delete_return(transport('delete', array('id' => $items)));
1762 break;
1763 case "rsetting":
1764 process_delete_return(rsettings('delete', array('id' => $items)));
1765 break;
1766 case "syncjob":
1767 process_delete_return(mailbox('delete', 'syncjob', array('id' => $items)));
1768 break;
1769 case "filter":
1770 process_delete_return(mailbox('delete', 'filter', array('id' => $items)));
1771 break;
1772 case "mailq":
1773 process_delete_return(mailq('delete', array('qid' => $items)));
1774 break;
1775 case "qitem":
1776 process_delete_return(quarantine('delete', array('id' => $items)));
1777 break;
1778 case "bcc":
1779 process_delete_return(bcc('delete', array('id' => $items)));
1780 break;
1781 case "recipient_map":
1782 process_delete_return(recipient_map('delete', array('id' => $items)));
1783 break;
1784 case "tls-policy-map":
1785 process_delete_return(tls_policy_maps('delete', array('id' => $items)));
1786 break;
1787 case "fwdhost":
1788 process_delete_return(fwdhost('delete', array('forwardinghost' => $items)));
1789 break;
1790 case "dkim":
1791 process_delete_return(dkim('delete', array('domains' => $items)));
1792 break;
1793 case "domain":
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001794 switch ($object){
1795 case "tag":
1796 process_delete_return(mailbox('delete', 'tags_domain', array('tags' => $items, 'domain' => $extra)));
1797 break;
1798 case "template":
1799 process_delete_return(mailbox('delete', 'domain_templates', array('ids' => $items)));
1800 break;
1801 default:
1802 process_delete_return(mailbox('delete', 'domain', array('domain' => $items)));
1803 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001804 break;
1805 case "alias-domain":
1806 process_delete_return(mailbox('delete', 'alias_domain', array('alias_domain' => $items)));
1807 break;
1808 case "mailbox":
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001809 switch ($object){
1810 case "tag":
1811 process_delete_return(mailbox('delete', 'tags_mailbox', array('tags' => $items, 'username' => $extra)));
1812 break;
1813 case "template":
1814 process_delete_return(mailbox('delete', 'mailbox_templates', array('ids' => $items)));
1815 break;
1816 default:
1817 process_delete_return(mailbox('delete', 'mailbox', array('username' => $items)));
1818 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001819 break;
1820 case "resource":
1821 process_delete_return(mailbox('delete', 'resource', array('name' => $items)));
1822 break;
1823 case "mailbox-policy":
1824 process_delete_return(policy('delete', 'mailbox', array('prefid' => $items)));
1825 break;
1826 case "domain-policy":
1827 process_delete_return(policy('delete', 'domain', array('prefid' => $items)));
1828 break;
1829 case "time_limited_alias":
1830 process_delete_return(mailbox('delete', 'time_limited_alias', array('address' => $items)));
1831 break;
1832 case "eas_cache":
1833 process_delete_return(mailbox('delete', 'eas_cache', array('username' => $items)));
1834 break;
1835 case "sogo_profile":
1836 process_delete_return(mailbox('delete', 'sogo_profile', array('username' => $items)));
1837 break;
1838 case "domain-admin":
1839 process_delete_return(domain_admin('delete', array('username' => $items)));
1840 break;
1841 case "admin":
1842 process_delete_return(admin('delete', array('username' => $items)));
1843 break;
1844 case "rlhash":
1845 echo ratelimit('delete', null, implode($items));
1846 break;
1847 // return no route found if no case is matched
1848 default:
1849 http_response_code(404);
1850 echo json_encode(array(
1851 'type' => 'error',
1852 'msg' => 'route not found'
1853 ));
1854 exit();
1855 }
1856 break;
1857 case "edit":
1858 if ($_SESSION['mailcow_cc_api_access'] == 'ro' || isset($_SESSION['pending_mailcow_cc_username']) || !isset($_SESSION["mailcow_cc_username"])) {
1859 http_response_code(403);
1860 echo json_encode(array(
1861 'type' => 'error',
1862 'msg' => 'API read/write access denied'
1863 ));
1864 exit();
1865 }
1866 function process_edit_return($return) {
1867 $generic_failure = json_encode(array(
1868 'type' => 'error',
1869 'msg' => 'Cannot edit item'
1870 ));
1871 $generic_success = json_encode(array(
1872 'type' => 'success',
1873 'msg' => 'Task completed'
1874 ));
1875 if ($return === false) {
1876 echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_failure;
1877 }
1878 else {
1879 echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_success;
1880 }
1881 }
1882 if (!isset($_POST['attr'])) {
1883 echo $request_incomplete;
1884 exit;
1885 }
1886 else {
1887 $attr = (array)json_decode($_POST['attr'], true);
1888 unset($attr['csrf_token']);
1889 $items = isset($_POST['items']) ? (array)json_decode($_POST['items'], true) : null;
1890 }
1891 // only allow POST requests to POST API endpoints
1892 if ($_SERVER['REQUEST_METHOD'] != 'POST') {
1893 http_response_code(405);
1894 echo json_encode(array(
1895 'type' => 'error',
1896 'msg' => 'only POST method is allowed'
1897 ));
1898 exit();
1899 }
1900 switch ($category) {
1901 case "bcc":
1902 process_edit_return(bcc('edit', array_merge(array('id' => $items), $attr)));
1903 break;
1904 case "pushover":
1905 process_edit_return(pushover('edit', array_merge(array('username' => $items), $attr)));
1906 break;
1907 case "pushover-test":
1908 process_edit_return(pushover('test', array_merge(array('username' => $items), $attr)));
1909 break;
1910 case "oauth2-client":
1911 process_edit_return(oauth2('edit', 'client', array_merge(array('id' => $items), $attr)));
1912 break;
1913 case "recipient_map":
1914 process_edit_return(recipient_map('edit', array_merge(array('id' => $items), $attr)));
1915 break;
1916 case "app-passwd":
1917 process_edit_return(app_passwd('edit', array_merge(array('id' => $items), $attr)));
1918 break;
1919 case "tls-policy-map":
1920 process_edit_return(tls_policy_maps('edit', array_merge(array('id' => $items), $attr)));
1921 break;
1922 case "alias":
1923 process_edit_return(mailbox('edit', 'alias', array_merge(array('id' => $items), $attr)));
1924 break;
1925 case "rspamd-map":
1926 process_edit_return(rspamd_maps('edit', array_merge(array('map' => $items), $attr)));
1927 break;
1928 case "fido2-fn":
1929 process_edit_return(fido2(array('action' => 'edit_fn', 'fido2_attrs' => $attr)));
1930 break;
1931 case "app_links":
1932 process_edit_return(customize('edit', 'app_links', $attr));
1933 break;
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02001934 case "passwordpolicy":
1935 process_edit_return(password_complexity('edit', $attr));
1936 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001937 case "relayhost":
1938 process_edit_return(relayhost('edit', array_merge(array('id' => $items), $attr)));
1939 break;
1940 case "transport":
1941 process_edit_return(transport('edit', array_merge(array('id' => $items), $attr)));
1942 break;
1943 case "rsetting":
1944 process_edit_return(rsettings('edit', array_merge(array('id' => $items), $attr)));
1945 break;
1946 case "delimiter_action":
1947 process_edit_return(mailbox('edit', 'delimiter_action', array_merge(array('username' => $items), $attr)));
1948 break;
1949 case "tls_policy":
1950 process_edit_return(mailbox('edit', 'tls_policy', array_merge(array('username' => $items), $attr)));
1951 break;
1952 case "quarantine_notification":
1953 process_edit_return(mailbox('edit', 'quarantine_notification', array_merge(array('username' => $items), $attr)));
1954 break;
1955 case "quarantine_category":
1956 process_edit_return(mailbox('edit', 'quarantine_category', array_merge(array('username' => $items), $attr)));
1957 break;
1958 case "qitem":
1959 process_edit_return(quarantine('edit', array_merge(array('id' => $items), $attr)));
1960 break;
1961 case "quarantine":
1962 process_edit_return(quarantine('edit', $attr));
1963 break;
1964 case "quota_notification":
1965 process_edit_return(quota_notification('edit', $attr));
1966 break;
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02001967 case "quota_notification_bcc":
1968 process_edit_return(quota_notification_bcc('edit', $attr));
1969 break;
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01001970 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001971 case "mailq":
1972 process_edit_return(mailq('edit', array_merge(array('qid' => $items), $attr)));
1973 break;
1974 case "time_limited_alias":
1975 process_edit_return(mailbox('edit', 'time_limited_alias', array_merge(array('address' => $items), $attr)));
1976 break;
1977 case "mailbox":
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001978 switch ($object) {
1979 case "template":
1980 process_edit_return(mailbox('edit', 'mailbox_templates', array_merge(array('ids' => $items), $attr)));
1981 break;
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001982 case "custom-attribute":
1983 process_edit_return(mailbox('edit', 'mailbox_custom_attribute', array_merge(array('mailboxes' => $items), $attr)));
1984 break;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001985 default:
1986 process_edit_return(mailbox('edit', 'mailbox', array_merge(array('username' => $items), $attr)));
1987 break;
1988 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001989 break;
1990 case "syncjob":
1991 process_edit_return(mailbox('edit', 'syncjob', array_merge(array('id' => $items), $attr)));
1992 break;
1993 case "filter":
1994 process_edit_return(mailbox('edit', 'filter', array_merge(array('id' => $items), $attr)));
1995 break;
1996 case "resource":
1997 process_edit_return(mailbox('edit', 'resource', array_merge(array('name' => $items), $attr)));
1998 break;
1999 case "domain":
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01002000 switch ($object) {
2001 case "template":
2002 process_edit_return(mailbox('edit', 'domain_templates', array_merge(array('ids' => $items), $attr)));
2003 break;
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01002004 case "footer":
2005 process_edit_return(mailbox('edit', 'domain_wide_footer', array_merge(array('domains' => $items), $attr)));
2006 break;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01002007 default:
2008 process_edit_return(mailbox('edit', 'domain', array_merge(array('domain' => $items), $attr)));
2009 break;
2010 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002011 break;
2012 case "rl-domain":
2013 process_edit_return(ratelimit('edit', 'domain', array_merge(array('object' => $items), $attr)));
2014 break;
2015 case "rl-mbox":
2016 process_edit_return(ratelimit('edit', 'mailbox', array_merge(array('object' => $items), $attr)));
2017 break;
2018 case "user-acl":
2019 process_edit_return(acl('edit', 'user', array_merge(array('username' => $items), $attr)));
2020 break;
2021 case "da-acl":
2022 process_edit_return(acl('edit', 'domainadmin', array_merge(array('username' => $items), $attr)));
2023 break;
2024 case "alias-domain":
2025 process_edit_return(mailbox('edit', 'alias_domain', array_merge(array('alias_domain' => $items), $attr)));
2026 break;
2027 case "spam-score":
2028 process_edit_return(mailbox('edit', 'spam_score', array_merge(array('username' => $items), $attr)));
2029 break;
2030 case "domain-admin":
2031 process_edit_return(domain_admin('edit', array_merge(array('username' => $items), $attr)));
2032 break;
2033 case "admin":
2034 process_edit_return(admin('edit', array_merge(array('username' => $items), $attr)));
2035 break;
2036 case "fwdhost":
2037 process_edit_return(fwdhost('edit', array_merge(array('fwdhost' => $items), $attr)));
2038 break;
2039 case "fail2ban":
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01002040 switch ($object) {
2041 case 'banlist':
2042 process_edit_return(fail2ban('banlist', 'refresh', $items));
2043 break;
2044 default:
2045 process_edit_return(fail2ban('edit', array_merge(array('network' => $items), $attr)));
2046 break;
2047 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002048 break;
2049 case "ui_texts":
2050 process_edit_return(customize('edit', 'ui_texts', $attr));
2051 break;
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01002052 case "ip_check":
2053 process_edit_return(customize('edit', 'ip_check', $attr));
2054 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002055 case "self":
2056 if ($_SESSION['mailcow_cc_role'] == "domainadmin") {
2057 process_edit_return(domain_admin('edit', $attr));
2058 }
2059 elseif ($_SESSION['mailcow_cc_role'] == "user") {
2060 process_edit_return(edit_user_account($attr));
2061 }
2062 break;
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01002063 case "cors":
2064 process_edit_return(cors('edit', $attr));
2065 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002066 // return no route found if no case is matched
2067 default:
2068 http_response_code(404);
2069 echo json_encode(array(
2070 'type' => 'error',
2071 'msg' => 'route not found'
2072 ));
2073 exit();
2074 }
2075 break;
2076 // return no route found if no case is matched
2077 default:
2078 http_response_code(404);
2079 echo json_encode(array(
2080 'type' => 'error',
2081 'msg' => 'route not found'
2082 ));
2083 exit();
2084 }
2085}
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01002086if (array_key_exists('mailcow_cc_api', $_SESSION) && $_SESSION['mailcow_cc_api'] === true) {
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002087 if (isset($_SESSION['mailcow_cc_api']) && $_SESSION['mailcow_cc_api'] === true) {
2088 unset($_SESSION['return']);
2089 }
2090}