blob: fc34b25951a7104c4d8811ffdd3b2f048a64e6ab [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
Matthias Andreas Benkard97f12022026-10-23 08:46:40 +020050// Block requests not intended for direct API use by checking the 'Sec-Fetch-Dest' header.
51if (isset($_SERVER['HTTP_SEC_FETCH_DEST']) && $_SERVER['HTTP_SEC_FETCH_DEST'] !== 'empty') {
52 header('HTTP/1.1 403 Forbidden');
53 exit;
54}
55
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +010056if (isset($_GET['query'])) {
57
58 $query = explode('/', $_GET['query']);
59 $action = (isset($query[0])) ? $query[0] : null;
60 $category = (isset($query[1])) ? $query[1] : null;
61 $object = (isset($query[2])) ? $query[2] : null;
62 $extra = (isset($query[3])) ? $query[3] : null;
63
64 // accept json in request body
65 if(strpos($_SERVER['HTTP_CONTENT_TYPE'], 'application/json') !== false) {
66 $request = file_get_contents('php://input');
67 $requestDecoded = json_decode($request, true);
68
69 // check for valid json
70 if ($action != 'get' && $requestDecoded === null) {
71 http_response_code(400);
72 echo json_encode(array(
73 'type' => 'error',
74 'msg' => 'Request body doesn\'t contain valid json!'
75 ));
76 exit;
77 }
78
79 // add
80 if ($action == 'add') {
81 $_POST['attr'] = $request;
82 }
83
84 // edit
85 if ($action == 'edit') {
86 $_POST['attr'] = json_encode($requestDecoded['attr']);
87 $_POST['items'] = json_encode($requestDecoded['items']);
88 }
89
90 // delete
91 if ($action == 'delete') {
92 $_POST['items'] = $request;
93 }
Matthias Andreas Benkard97f12022026-10-23 08:46:40 +020094
95 // search
96 if ($action == 'search') {
97 // placeholder for search, as the request body is already decoded and available in $requestDecoded
98 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +010099 }
100 api_log($_POST);
101
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100102
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100103 $request_incomplete = json_encode(array(
104 'type' => 'error',
105 'msg' => 'Cannot find attributes in post data'
106 ));
107
108 switch ($action) {
109 case "add":
110 if ($_SESSION['mailcow_cc_api_access'] == 'ro' || isset($_SESSION['pending_mailcow_cc_username'])) {
111 http_response_code(403);
112 echo json_encode(array(
113 'type' => 'error',
114 'msg' => 'API read/write access denied'
115 ));
116 exit();
117 }
118 function process_add_return($return) {
119 $generic_failure = json_encode(array(
120 'type' => 'error',
121 'msg' => 'Cannot add item'
122 ));
123 $generic_success = json_encode(array(
124 'type' => 'success',
125 'msg' => 'Task completed'
126 ));
127 if ($return === false) {
128 echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_failure;
129 }
130 else {
131 echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_success;
132 }
133 }
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100134 if (!isset($_POST['attr']) && $category != "fido2-registration" && $category != "webauthn-tfa-registration") {
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100135 echo $request_incomplete;
136 exit;
137 }
138 else {
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100139 if ($category != "fido2-registration" && $category != "webauthn-tfa-registration") {
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100140 $attr = (array)json_decode($_POST['attr'], true);
141 }
142 unset($attr['csrf_token']);
143 }
144 // only allow POST requests to POST API endpoints
145 if ($_SERVER['REQUEST_METHOD'] != 'POST') {
146 http_response_code(405);
147 echo json_encode(array(
148 'type' => 'error',
149 'msg' => 'only POST method is allowed'
150 ));
151 exit();
152 }
153
154 switch ($category) {
155 // fido2-registration via POST
156 case "fido2-registration":
157 header('Content-Type: application/json');
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +0200158 if (isset($_SESSION["mailcow_cc_role"])) {
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100159 $post = trim(file_get_contents('php://input'));
160 if ($post) {
161 $post = json_decode($post);
162 }
163 $clientDataJSON = base64_decode($post->clientDataJSON);
164 $attestationObject = base64_decode($post->attestationObject);
165 $challenge = $_SESSION['challenge'];
166 try {
167 $data = $WebAuthn->processCreate($clientDataJSON, $attestationObject, $challenge, $GLOBALS['FIDO2_UV_FLAG_REGISTER'], $GLOBALS['FIDO2_USER_PRESENT_FLAG']);
168 }
169 catch (Throwable $ex) {
170 $return = new stdClass();
171 $return->success = false;
172 $return->msg = $ex->getMessage();
173 echo json_encode($return);
174 exit;
175 }
176 fido2(array("action" => "register", "registration" => $data));
Matthias Andreas Benkard97f12022026-10-23 08:46:40 +0200177 // Release pending_tfa_setup session hold
178 unset($_SESSION['pending_tfa_setup']);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100179 $return = new stdClass();
180 $return->success = true;
181 echo json_encode($return);
182 exit;
183 }
184 else {
185 echo $request_incomplete;
186 exit;
187 }
188 break;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100189 case "webauthn-tfa-registration":
190 if (isset($_SESSION["mailcow_cc_role"])) {
191 // parse post data
192 $post = trim(file_get_contents('php://input'));
193 if ($post) $post = json_decode($post);
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +0100194
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100195 // process registration data from authenticator
196 try {
197 // decode base64 strings
198 $clientDataJSON = base64_decode($post->clientDataJSON);
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +0100199 $attestationObject = base64_decode($post->attestationObject);
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100200
201 // processCreate($clientDataJSON, $attestationObject, $challenge, $requireUserVerification=false, $requireUserPresent=true, $failIfRootMismatch=true)
202 $data = $WebAuthn->processCreate($clientDataJSON, $attestationObject, $_SESSION['challenge'], false, true);
203
204 // safe authenticator in mysql `tfa` table
205 $_data['tfa_method'] = $post->tfa_method;
206 $_data['key_id'] = $post->key_id;
207 $_data['confirm_password'] = $post->confirm_password;
208 $_data['registration'] = $data;
209 set_tfa($_data);
210 }
211 catch (Throwable $ex) {
212 // err
213 $return = new stdClass();
214 $return->success = false;
215 $return->msg = $ex->getMessage();
216 echo json_encode($return);
217 exit;
218 }
219
220
221 // send response
222 $return = new stdClass();
223 $return->success = true;
224 echo json_encode($return);
225 exit;
226 }
227 else {
228 // err - request incomplete
229 echo $request_incomplete;
230 exit;
231 }
232 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100233 case "time_limited_alias":
234 process_add_return(mailbox('add', 'time_limited_alias', $attr));
235 break;
236 case "relayhost":
237 process_add_return(relayhost('add', $attr));
238 break;
239 case "transport":
240 process_add_return(transport('add', $attr));
241 break;
242 case "rsetting":
243 process_add_return(rsettings('add', $attr));
244 break;
245 case "mailbox":
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100246 switch ($object) {
247 case "template":
248 process_add_return(mailbox('add', 'mailbox_templates', $attr));
249 break;
250 default:
251 process_add_return(mailbox('add', 'mailbox', $attr));
252 break;
253 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100254 break;
255 case "oauth2-client":
256 process_add_return(oauth2('add', 'client', $attr));
257 break;
258 case "domain":
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100259 switch ($object) {
260 case "template":
261 process_add_return(mailbox('add', 'domain_templates', $attr));
262 break;
263 default:
264 process_add_return(mailbox('add', 'domain', $attr));
265 break;
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +0100266 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100267 break;
268 case "resource":
269 process_add_return(mailbox('add', 'resource', $attr));
270 break;
271 case "alias":
272 process_add_return(mailbox('add', 'alias', $attr));
273 break;
274 case "filter":
275 process_add_return(mailbox('add', 'filter', $attr));
276 break;
277 case "global-filter":
278 process_add_return(mailbox('add', 'global_filter', $attr));
279 break;
280 case "domain-policy":
281 process_add_return(policy('add', 'domain', $attr));
282 break;
283 case "mailbox-policy":
284 process_add_return(policy('add', 'mailbox', $attr));
285 break;
286 case "alias-domain":
287 process_add_return(mailbox('add', 'alias_domain', $attr));
288 break;
289 case "fwdhost":
290 process_add_return(fwdhost('add', $attr));
291 break;
292 case "dkim":
293 process_add_return(dkim('add', $attr));
294 break;
295 case "dkim_duplicate":
296 process_add_return(dkim('duplicate', $attr));
297 break;
298 case "dkim_import":
299 process_add_return(dkim('import', $attr));
300 break;
301 case "domain-admin":
302 process_add_return(domain_admin('add', $attr));
303 break;
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +0100304 case "sso":
305 switch ($object) {
306 case "domain-admin":
307 $data = domain_admin_sso('issue', $attr);
308 if($data) {
309 echo json_encode($data);
310 exit(0);
311 }
312 process_add_return($data);
313 break;
314 }
315 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100316 case "admin":
317 process_add_return(admin('add', $attr));
318 break;
319 case "syncjob":
320 process_add_return(mailbox('add', 'syncjob', $attr));
321 break;
322 case "bcc":
323 process_add_return(bcc('add', $attr));
324 break;
325 case "recipient_map":
326 process_add_return(recipient_map('add', $attr));
327 break;
328 case "tls-policy-map":
329 process_add_return(tls_policy_maps('add', $attr));
330 break;
331 case "app-passwd":
332 process_add_return(app_passwd('add', $attr));
333 break;
Matthias Andreas Benkard97f12022026-10-23 08:46:40 +0200334 case "mta-sts":
335 process_add_return(mailbox('add', 'mta_sts', $attr));
336 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100337 // return no route found if no case is matched
338 default:
339 http_response_code(404);
340 echo json_encode(array(
341 'type' => 'error',
342 'msg' => 'route not found'
343 ));
344 exit();
345 }
346 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100347 case "get":
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +0200348 function process_get_return($data, $object = true) {
349 if ($object === true) {
350 $ret_str = '{}';
351 }
352 else {
353 $ret_str = '[]';
354 }
355 echo (!isset($data) || empty($data)) ? $ret_str : json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100356 }
357 // only allow GET requests to GET API endpoints
358 if ($_SERVER['REQUEST_METHOD'] != 'GET') {
359 http_response_code(405);
360 echo json_encode(array(
361 'type' => 'error',
362 'msg' => 'only GET method is allowed'
363 ));
364 exit();
365 }
366 switch ($category) {
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100367 // fido2
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100368 case "fido2-registration":
369 header('Content-Type: application/json');
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +0200370 if (isset($_SESSION["mailcow_cc_role"])) {
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100371 // Exclude existing CredentialIds, if any
372 $excludeCredentialIds = fido2(array("action" => "get_user_cids"));
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100373 $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 +0100374 print(json_encode($createArgs));
375 $_SESSION['challenge'] = $WebAuthn->getChallenge();
376 return;
377 }
378 else {
379 return;
380 }
381 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100382 case "fido2-get-args":
383 header('Content-Type: application/json');
384 // Login without username, no ids!
385 // $ids = fido2(array("action" => "get_all_cids"));
386 // if (count($ids) == 0) {
387 // return;
388 // }
389 $ids = NULL;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100390
391 $getArgs = $WebAuthn->getGetArgs($ids, 30, false, false, false, false, $GLOBALS['FIDO2_UV_FLAG_LOGIN']);
392 print(json_encode($getArgs));
393 $_SESSION['challenge'] = $WebAuthn->getChallenge();
394 return;
395 break;
396 // webauthn two factor authentication
397 case "webauthn-tfa-registration":
398 if (isset($_SESSION["mailcow_cc_role"])) {
399 // Exclude existing CredentialIds, if any
400 $stmt = $pdo->prepare("SELECT `keyHandle` FROM `tfa` WHERE username = :username AND authmech = :authmech");
401 $stmt->execute(array(
402 ':username' => $_SESSION['mailcow_cc_username'],
403 ':authmech' => 'webauthn'
404 ));
405 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
406 while($row = array_shift($rows)) {
407 $excludeCredentialIds[] = base64_decode($row['keyHandle']);
408 }
409 // getCreateArgs($userId, $userName, $userDisplayName, $timeout=20, $requireResidentKey=false, $requireUserVerification=false, $crossPlatformAttachment=null, $excludeCredentialIds=array())
410 // cross-platform: true, if type internal is not allowed
411 // false, if only internal is allowed
412 // null, if internal and cross-platform is allowed
413 $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 +0100414
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100415 print(json_encode($createArgs));
416 $_SESSION['challenge'] = $WebAuthn->getChallenge();
417 return;
418
419 }
420 else {
421 return;
422 }
423 break;
424 case "webauthn-tfa-get-args":
425 $stmt = $pdo->prepare("SELECT `keyHandle` FROM `tfa` WHERE username = :username AND authmech = :authmech");
426 $stmt->execute(array(
427 ':username' => $_SESSION['pending_mailcow_cc_username'],
428 ':authmech' => 'webauthn'
429 ));
430 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
431 if (count($rows) == 0) {
432 print(json_encode(array(
433 'type' => 'error',
434 'msg' => 'Cannot find matching credentialIds'
435 )));
436 exit;
437 }
438 while($row = array_shift($rows)) {
439 $cids[] = base64_decode($row['keyHandle']);
440 }
441
442 $getArgs = $WebAuthn->getGetArgs($cids, 30, false, false, false, false, $GLOBALS['WEBAUTHN_UV_FLAG_LOGIN']);
443 $getArgs->publicKey->extensions = array('appid' => "https://".$getArgs->publicKey->rpId);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100444 print(json_encode($getArgs));
445 $_SESSION['challenge'] = $WebAuthn->getChallenge();
446 return;
447 break;
448 }
449 if (isset($_SESSION['mailcow_cc_role'])) {
450 switch ($category) {
451 case "rspamd":
452 switch ($object) {
453 case "actions":
454 $data = rspamd_actions();
455 if ($data) {
456 echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
457 }
458 else {
459 echo '{}';
460 }
461 break;
462 }
463 break;
464
465 case "domain":
466 switch ($object) {
467 case "all":
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100468 $tags = null;
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +0100469 if (isset($_GET['tags']) && $_GET['tags'] != '')
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100470 $tags = explode(',', $_GET['tags']);
471
472 $domains = mailbox('get', 'domains', null, $tags);
473
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100474 if (!empty($domains)) {
475 foreach ($domains as $domain) {
476 if ($details = mailbox('get', 'domain_details', $domain)) {
477 $data[] = $details;
478 }
479 else {
480 continue;
481 }
482 }
483 process_get_return($data);
484 }
485 else {
486 echo '{}';
487 }
488 break;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100489 case "template":
490 switch ($extra){
491 case "all":
492 process_get_return(mailbox('get', 'domain_templates'));
493 break;
494 default:
495 process_get_return(mailbox('get', 'domain_templates', $extra));
496 break;
497 }
498 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100499 default:
500 $data = mailbox('get', 'domain_details', $object);
501 process_get_return($data);
502 break;
503 }
504 break;
505
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +0200506 case "passwordpolicy":
507 switch ($object) {
508 case "html":
509 $password_complexity_rules = password_complexity('html');
510 if ($password_complexity_rules !== false) {
511 process_get_return($password_complexity_rules);
512 }
513 else {
514 echo '{}';
515 }
516 break;
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +0100517 default:
518 $password_complexity_rules = password_complexity('get');
519 if ($password_complexity_rules !== false) {
520 process_get_return($password_complexity_rules);
521 }
522 else {
523 echo '{}';
524 }
525 break;
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +0200526 }
527 break;
528
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100529 case "app-passwd":
530 switch ($object) {
531 case "all":
532 if (empty($extra)) {
533 $app_passwds = app_passwd('get');
534 }
535 else {
536 $app_passwds = app_passwd('get', array('username' => $extra));
537 }
538 if (!empty($app_passwds)) {
539 foreach ($app_passwds as $app_passwd) {
Matthias Andreas Benkardb4b5cc12021-12-28 18:02:04 +0100540 $details = app_passwd('details', $app_passwd['id']);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100541 if ($details !== false) {
542 $data[] = $details;
543 }
544 else {
545 continue;
546 }
547 }
548 process_get_return($data);
549 }
550 else {
551 echo '{}';
552 }
553 break;
554
555 default:
556 $data = app_passwd('details', array('id' => $object['id']));
557 process_get_return($data);
558 break;
559 }
560 break;
561
562 case "mailq":
563 switch ($object) {
564 case "all":
565 $mailq = mailq('get');
566 if (!empty($mailq)) {
567 echo $mailq;
568 }
569 else {
570 echo '[]';
571 }
572 break;
573 }
574 break;
Matthias Andreas Benkardb4b5cc12021-12-28 18:02:04 +0100575
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100576 case "postcat":
577 switch ($object) {
578 default:
579 $data = mailq('cat', array('qid' => $object));
580 echo $data;
581 break;
582 }
583 break;
584
585 case "global_filters":
586 $global_filters = mailbox('get', 'global_filter_details');
587 switch ($object) {
588 case "all":
589 if (!empty($global_filters)) {
590 process_get_return($global_filters);
591 }
592 else {
593 echo '{}';
594 }
595 break;
596 case "prefilter":
597 if (!empty($global_filters['prefilter'])) {
598 process_get_return($global_filters['prefilter']);
599 }
600 else {
601 echo '{}';
602 }
603 break;
604 case "postfilter":
605 if (!empty($global_filters['postfilter'])) {
606 process_get_return($global_filters['postfilter']);
607 }
608 else {
609 echo '{}';
610 }
611 break;
612 }
613 break;
614
615 case "rl-domain":
616 switch ($object) {
617 case "all":
618 $domains = array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains'));
619 if (!empty($domains)) {
620 foreach ($domains as $domain) {
621 if ($details = ratelimit('get', 'domain', $domain)) {
622 $details['domain'] = $domain;
623 $data[] = $details;
624 }
625 else {
626 continue;
627 }
628 }
629 process_get_return($data);
630 }
631 else {
632 echo '{}';
633 }
634 break;
635
636 default:
637 $data = ratelimit('get', 'domain', $object);
638 process_get_return($data);
639 break;
640 }
641 break;
642
643 case "rl-mbox":
644 switch ($object) {
645 case "all":
646 $domains = mailbox('get', 'domains');
647 if (!empty($domains)) {
648 foreach ($domains as $domain) {
649 $mailboxes = mailbox('get', 'mailboxes', $domain);
650 if (!empty($mailboxes)) {
651 foreach ($mailboxes as $mailbox) {
652 if ($details = ratelimit('get', 'mailbox', $mailbox)) {
653 $details['mailbox'] = $mailbox;
654 $data[] = $details;
655 }
656 else {
657 continue;
658 }
659 }
660 }
661 }
662 process_get_return($data);
663 }
664 else {
665 echo '{}';
666 }
667 break;
668
669 default:
670 $data = ratelimit('get', 'mailbox', $object);
671 process_get_return($data);
672 break;
673 }
674 break;
675
676 case "relayhost":
677 switch ($object) {
678 case "all":
679 $relayhosts = relayhost('get');
680 if (!empty($relayhosts)) {
681 foreach ($relayhosts as $relayhost) {
682 if ($details = relayhost('details', $relayhost['id'])) {
683 $data[] = $details;
684 }
685 else {
686 continue;
687 }
688 }
689 process_get_return($data);
690 }
691 else {
692 echo '{}';
693 }
694 break;
695
696 default:
697 $data = relayhost('details', $object);
698 process_get_return($data);
699 break;
700 }
701 break;
702
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +0200703 case "last-login":
704 if ($object) {
705 // extra == days
706 if (isset($extra) && intval($extra) >= 1) {
707 $data = last_login('get', $object, intval($extra));
708 }
709 else {
710 $data = last_login('get', $object);
711 }
712 process_get_return($data);
713 }
714 break;
715
716 // Todo: move to delete
717 case "reset-last-login":
718 if ($object) {
719 $data = last_login('reset', $object);
720 process_get_return($data);
721 }
722 break;
723
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100724 case "transport":
725 switch ($object) {
726 case "all":
727 $transports = transport('get');
728 if (!empty($transports)) {
729 foreach ($transports as $transport) {
730 if ($details = transport('details', $transport['id'])) {
731 $data[] = $details;
732 }
733 else {
734 continue;
735 }
736 }
737 process_get_return($data);
738 }
739 else {
740 echo '{}';
741 }
742 break;
743
744 default:
745 $data = transport('details', $object);
746 process_get_return($data);
747 break;
748 }
749 break;
750
751 case "rsetting":
752 switch ($object) {
753 case "all":
754 $rsettings = rsettings('get');
755 if (!empty($rsettings)) {
756 foreach ($rsettings as $rsetting) {
757 if ($details = rsettings('details', $rsetting['id'])) {
758 $data[] = $details;
759 }
760 else {
761 continue;
762 }
763 }
764 process_get_return($data);
765 }
766 else {
767 echo '{}';
768 }
769 break;
770
771 default:
772 $data = rsettings('details', $object);
773 process_get_return($data);
774 break;
775 }
776 break;
777
778 case "oauth2-client":
779 switch ($object) {
780 case "all":
781 $clients = oauth2('get', 'clients');
782 if (!empty($clients)) {
783 foreach ($clients as $client) {
784 if ($details = oauth2('details', 'client', $client)) {
785 $data[] = $details;
786 }
787 else {
788 continue;
789 }
790 }
791 process_get_return($data);
792 }
793 else {
794 echo '{}';
795 }
796 break;
797
798 default:
799 $data = oauth2('details', 'client', $object);
800 process_get_return($data);
801 break;
802 }
803 break;
804
805 case "logs":
806 switch ($object) {
807 case "dovecot":
808 // 0 is first record, so empty is fine
809 if (isset($extra)) {
810 $extra = preg_replace('/[^\d\-]/i', '', $extra);
811 $logs = get_logs('dovecot-mailcow', $extra);
812 }
813 else {
814 $logs = get_logs('dovecot-mailcow');
815 }
816 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
817 break;
818 case "ratelimited":
819 // 0 is first record, so empty is fine
820 if (isset($extra)) {
821 $extra = preg_replace('/[^\d\-]/i', '', $extra);
822 $logs = get_logs('ratelimited', $extra);
823 }
824 else {
825 $logs = get_logs('ratelimited');
826 }
827 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
828 break;
829 case "netfilter":
830 // 0 is first record, so empty is fine
831 if (isset($extra)) {
832 $extra = preg_replace('/[^\d\-]/i', '', $extra);
833 $logs = get_logs('netfilter-mailcow', $extra);
834 }
835 else {
836 $logs = get_logs('netfilter-mailcow');
837 }
838 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
839 break;
Matthias Andreas Benkard97f12022026-10-23 08:46:40 +0200840 case "cron":
841 // 0 is first record, so empty is fine
842 if (isset($extra)) {
843 $extra = preg_replace('/[^\d\-]/i', '', $extra);
844 $logs = get_logs('cron-mailcow', $extra);
845 }
846 else {
847 $logs = get_logs('cron-mailcow');
848 }
849 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
850 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100851 case "postfix":
852 // 0 is first record, so empty is fine
853 if (isset($extra)) {
854 $extra = preg_replace('/[^\d\-]/i', '', $extra);
855 $logs = get_logs('postfix-mailcow', $extra);
856 }
857 else {
858 $logs = get_logs('postfix-mailcow');
859 }
860 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
861 break;
862 case "autodiscover":
863 // 0 is first record, so empty is fine
864 if (isset($extra)) {
865 $extra = preg_replace('/[^\d\-]/i', '', $extra);
866 $logs = get_logs('autodiscover-mailcow', $extra);
867 }
868 else {
869 $logs = get_logs('autodiscover-mailcow');
870 }
871 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
872 break;
873 case "sogo":
874 // 0 is first record, so empty is fine
875 if (isset($extra)) {
876 $extra = preg_replace('/[^\d\-]/i', '', $extra);
877 $logs = get_logs('sogo-mailcow', $extra);
878 }
879 else {
880 $logs = get_logs('sogo-mailcow');
881 }
882 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
883 break;
884 case "ui":
885 // 0 is first record, so empty is fine
886 if (isset($extra)) {
887 $extra = preg_replace('/[^\d\-]/i', '', $extra);
888 $logs = get_logs('mailcow-ui', $extra);
889 }
890 else {
891 $logs = get_logs('mailcow-ui');
892 }
893 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
894 break;
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +0200895 case "sasl":
896 // 0 is first record, so empty is fine
897 if (isset($extra)) {
898 $extra = preg_replace('/[^\d\-]/i', '', $extra);
899 $logs = get_logs('sasl', $extra);
900 }
901 else {
902 $logs = get_logs('sasl');
903 }
904 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
905 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100906 case "watchdog":
907 // 0 is first record, so empty is fine
908 if (isset($extra)) {
909 $extra = preg_replace('/[^\d\-]/i', '', $extra);
910 $logs = get_logs('watchdog-mailcow', $extra);
911 }
912 else {
913 $logs = get_logs('watchdog-mailcow');
914 }
915 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
916 break;
917 case "acme":
918 // 0 is first record, so empty is fine
919 if (isset($extra)) {
920 $extra = preg_replace('/[^\d\-]/i', '', $extra);
921 $logs = get_logs('acme-mailcow', $extra);
922 }
923 else {
924 $logs = get_logs('acme-mailcow');
925 }
926 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
927 break;
928 case "api":
929 // 0 is first record, so empty is fine
930 if (isset($extra)) {
931 $extra = preg_replace('/[^\d\-]/i', '', $extra);
932 $logs = get_logs('api-mailcow', $extra);
933 }
934 else {
935 $logs = get_logs('api-mailcow');
936 }
937 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
938 break;
939 case "rspamd-history":
940 // 0 is first record, so empty is fine
941 if (isset($extra)) {
942 $extra = preg_replace('/[^\d\-]/i', '', $extra);
943 $logs = get_logs('rspamd-history', $extra);
944 }
945 else {
946 $logs = get_logs('rspamd-history');
947 }
948 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
949 break;
950 case "rspamd-stats":
951 $logs = get_logs('rspamd-stats');
952 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
953 break;
954 // return no route found if no case is matched
955 default:
956 http_response_code(404);
957 echo json_encode(array(
958 'type' => 'error',
959 'msg' => 'route not found'
960 ));
961 exit();
962 }
963 break;
964 case "mailbox":
965 switch ($object) {
966 case "all":
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +0200967 case "reduced":
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100968 $tags = null;
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +0100969 if (isset($_GET['tags']) && $_GET['tags'] != '')
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100970 $tags = explode(',', $_GET['tags']);
971
972 if (empty($extra)) $domains = mailbox('get', 'domains');
973 else $domains = explode(',', $extra);
974
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100975 if (!empty($domains)) {
976 foreach ($domains as $domain) {
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100977 $mailboxes = mailbox('get', 'mailboxes', $domain, $tags);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100978 if (!empty($mailboxes)) {
979 foreach ($mailboxes as $mailbox) {
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100980 if ($details = mailbox('get', 'mailbox_details', $mailbox, $object)) $data[] = $details;
981 else continue;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100982 }
983 }
984 }
985 process_get_return($data);
986 }
987 else {
988 echo '{}';
989 }
990 break;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100991 case "template":
992 switch ($extra){
993 case "all":
994 process_get_return(mailbox('get', 'mailbox_templates'));
995 break;
996 default:
997 process_get_return(mailbox('get', 'mailbox_templates', $extra));
998 break;
999 }
1000 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001001 default:
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001002 $tags = null;
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001003 if (isset($_GET['tags']) && $_GET['tags'] != '')
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001004 $tags = explode(',', $_GET['tags']);
1005
1006 if ($tags === null) {
1007 $data = mailbox('get', 'mailbox_details', $object);
1008 process_get_return($data);
1009 } else {
1010 $mailboxes = mailbox('get', 'mailboxes', $object, $tags);
1011 if (is_array($mailboxes)) {
1012 foreach ($mailboxes as $mailbox) {
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001013 if ($details = mailbox('get', 'mailbox_details', $mailbox))
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001014 $data[] = $details;
1015 }
1016 }
1017 process_get_return($data, false);
1018 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001019 break;
1020 }
1021 break;
Matthias Andreas Benkardb4b5cc12021-12-28 18:02:04 +01001022 case "bcc-destination-options":
1023 $domains = mailbox('get', 'domains');
1024 $alias_domains = mailbox('get', 'alias_domains');
1025 $data = array();
1026 if (!empty($domains)) {
1027 foreach ($domains as $domain) {
1028 $data['domains'][] = $domain;
1029 $mailboxes = mailbox('get', 'mailboxes', $domain);
1030 foreach ($mailboxes as $mailbox) {
1031 $data['mailboxes'][$mailbox][] = $mailbox;
1032 $user_alias_details = user_get_alias_details($mailbox);
1033 foreach ($user_alias_details['direct_aliases'] as $k => $v) {
1034 $data['mailboxes'][$mailbox][] = $k;
1035 }
1036 foreach ($user_alias_details['shared_aliases'] as $k => $v) {
1037 $data['mailboxes'][$mailbox][] = $k;
1038 }
1039 }
1040 }
1041 }
1042 if (!empty($alias_domains)) {
1043 foreach ($alias_domains as $alias_domain) {
1044 $data['alias_domains'][] = $alias_domain;
1045 }
1046 }
1047 process_get_return($data);
1048 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001049 case "syncjobs":
1050 switch ($object) {
1051 case "all":
1052 $domains = mailbox('get', 'domains');
1053 if (!empty($domains)) {
1054 foreach ($domains as $domain) {
1055 $mailboxes = mailbox('get', 'mailboxes', $domain);
1056 if (!empty($mailboxes)) {
1057 foreach ($mailboxes as $mailbox) {
1058 $syncjobs = mailbox('get', 'syncjobs', $mailbox);
1059 if (!empty($syncjobs)) {
1060 foreach ($syncjobs as $syncjob) {
1061 if (isset($extra)) {
1062 $details = mailbox('get', 'syncjob_details', $syncjob, explode(',', $extra));
1063 }
1064 else {
1065 $details = mailbox('get', 'syncjob_details', $syncjob);
1066 }
1067 if ($details) {
1068 $data[] = $details;
1069 }
1070 else {
1071 continue;
1072 }
1073 }
1074 }
1075 }
1076 }
1077 }
1078 process_get_return($data);
1079 }
1080 else {
1081 echo '{}';
1082 }
1083 break;
1084
1085 default:
1086 $syncjobs = mailbox('get', 'syncjobs', $object);
1087 if (!empty($syncjobs)) {
1088 foreach ($syncjobs as $syncjob) {
1089 if (isset($extra)) {
1090 $details = mailbox('get', 'syncjob_details', $syncjob, explode(',', $extra));
1091 }
1092 else {
1093 $details = mailbox('get', 'syncjob_details', $syncjob);
1094 }
1095 if ($details) {
1096 $data[] = $details;
1097 }
1098 else {
1099 continue;
1100 }
1101 }
1102 }
1103 process_get_return($data);
1104 break;
1105 }
1106 break;
1107 case "active-user-sieve":
1108 if (isset($object)) {
1109 $sieve_filter = mailbox('get', 'active_user_sieve', $object);
1110 if (!empty($sieve_filter)) {
1111 $data[] = $sieve_filter;
1112 }
1113 }
1114 process_get_return($data);
1115 break;
1116 case "filters":
1117 switch ($object) {
1118 case "all":
1119 $domains = mailbox('get', 'domains');
1120 if (!empty($domains)) {
1121 foreach ($domains as $domain) {
1122 $mailboxes = mailbox('get', 'mailboxes', $domain);
1123 if (!empty($mailboxes)) {
1124 foreach ($mailboxes as $mailbox) {
1125 $filters = mailbox('get', 'filters', $mailbox);
1126 if (!empty($filters)) {
1127 foreach ($filters as $filter) {
1128 if ($details = mailbox('get', 'filter_details', $filter)) {
1129 $data[] = $details;
1130 }
1131 else {
1132 continue;
1133 }
1134 }
1135 }
1136 }
1137 }
1138 }
1139 process_get_return($data);
1140 }
1141 else {
1142 echo '{}';
1143 }
1144 break;
1145
1146 default:
1147 $filters = mailbox('get', 'filters', $object);
1148 if (!empty($filters)) {
1149 foreach ($filters as $filter) {
1150 if ($details = mailbox('get', 'filter_details', $filter)) {
1151 $data[] = $details;
1152 }
1153 else {
1154 continue;
1155 }
1156 }
1157 }
1158 process_get_return($data);
1159 break;
1160 }
1161 break;
1162 case "bcc":
1163 switch ($object) {
1164 case "all":
1165 $bcc_items = bcc('get');
1166 if (!empty($bcc_items)) {
1167 foreach ($bcc_items as $bcc_item) {
1168 if ($details = bcc('details', $bcc_item)) {
1169 $data[] = $details;
1170 }
1171 else {
1172 continue;
1173 }
1174 }
1175 }
1176 process_get_return($data);
1177 break;
1178 default:
1179 $data = bcc('details', $object);
1180 if (!empty($data)) {
1181 $data[] = $details;
1182 }
1183 process_get_return($data);
1184 break;
1185 }
1186 break;
1187 case "recipient_map":
1188 switch ($object) {
1189 case "all":
1190 $recipient_map_items = recipient_map('get');
1191 if (!empty($recipient_map_items)) {
1192 foreach ($recipient_map_items as $recipient_map_item) {
1193 if ($details = recipient_map('details', $recipient_map_item)) {
1194 $data[] = $details;
1195 }
1196 else {
1197 continue;
1198 }
1199 }
1200 }
1201 process_get_return($data);
1202 break;
1203 default:
1204 $data = recipient_map('details', $object);
1205 if (!empty($data)) {
1206 $data[] = $details;
1207 }
1208 process_get_return($data);
1209 break;
1210 }
1211 break;
1212 case "tls-policy-map":
1213 switch ($object) {
1214 case "all":
1215 $tls_policy_maps_items = tls_policy_maps('get');
1216 if (!empty($tls_policy_maps_items)) {
1217 foreach ($tls_policy_maps_items as $tls_policy_maps_item) {
1218 if ($details = tls_policy_maps('details', $tls_policy_maps_item)) {
1219 $data[] = $details;
1220 }
1221 else {
1222 continue;
1223 }
1224 }
1225 }
1226 process_get_return($data);
1227 break;
1228 default:
1229 $data = tls_policy_maps('details', $object);
1230 if (!empty($data)) {
1231 $data[] = $details;
1232 }
1233 process_get_return($data);
1234 break;
1235 }
1236 break;
1237 case "policy_wl_mailbox":
1238 switch ($object) {
1239 default:
1240 $data = policy('get', 'mailbox', $object)['whitelist'];
1241 process_get_return($data);
1242 break;
1243 }
1244 break;
1245 case "policy_bl_mailbox":
1246 switch ($object) {
1247 default:
1248 $data = policy('get', 'mailbox', $object)['blacklist'];
1249 process_get_return($data);
1250 break;
1251 }
1252 break;
1253 case "policy_wl_domain":
1254 switch ($object) {
1255 default:
1256 $data = policy('get', 'domain', $object)['whitelist'];
1257 process_get_return($data);
1258 break;
1259 }
1260 break;
1261 case "policy_bl_domain":
1262 switch ($object) {
1263 default:
1264 $data = policy('get', 'domain', $object)['blacklist'];
1265 process_get_return($data);
1266 break;
1267 }
1268 break;
1269 case "time_limited_aliases":
1270 switch ($object) {
1271 default:
1272 $data = mailbox('get', 'time_limited_aliases', $object);
1273 process_get_return($data);
1274 break;
1275 }
1276 break;
1277 case "fail2ban":
1278 switch ($object) {
1279 default:
1280 $data = fail2ban('get');
1281 process_get_return($data);
1282 break;
1283 }
1284 break;
1285 case "resource":
1286 switch ($object) {
1287 case "all":
1288 $domains = mailbox('get', 'domains');
1289 if (!empty($domains)) {
1290 foreach ($domains as $domain) {
1291 $resources = mailbox('get', 'resources', $domain);
1292 if (!empty($resources)) {
1293 foreach ($resources as $resource) {
1294 if ($details = mailbox('get', 'resource_details', $resource)) {
1295 $data[] = $details;
1296 }
1297 else {
1298 continue;
1299 }
1300 }
1301 }
1302 }
1303 process_get_return($data);
1304 }
1305 else {
1306 echo '{}';
1307 }
1308 break;
1309 default:
1310 $data = mailbox('get', 'resource_details', $object);
1311 process_get_return($data);
1312 break;
1313 }
1314 break;
1315 case "fwdhost":
1316 switch ($object) {
1317 case "all":
1318 process_get_return(fwdhost('get'));
1319 break;
1320 default:
1321 process_get_return(fwdhost('details', $object));
1322 break;
1323 }
1324 break;
1325 case "quarantine":
1326 // "all" will not print details
1327 switch ($object) {
1328 case "all":
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02001329 process_get_return(quarantine('get'), false);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001330 break;
1331 default:
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02001332 process_get_return(quarantine('details', $object), false);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001333 break;
1334 }
1335 break;
1336 case "alias-domain":
1337 switch ($object) {
1338 case "all":
1339 $alias_domains = mailbox('get', 'alias_domains');
1340 if (!empty($alias_domains)) {
1341 foreach ($alias_domains as $alias_domain) {
1342 if ($details = mailbox('get', 'alias_domain_details', $alias_domain)) {
1343 $data[] = $details;
1344 }
1345 else {
1346 continue;
1347 }
1348 }
1349 }
1350 process_get_return($data);
1351 break;
1352 default:
1353 process_get_return(mailbox('get', 'alias_domain_details', $object));
1354 break;
1355 }
1356 break;
1357 case "alias":
1358 switch ($object) {
1359 case "all":
1360 if (empty($extra)) {
1361 $domains = array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains'));
1362 }
1363 else {
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02001364 $domains = explode(',', $extra);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001365 }
1366 if (!empty($domains)) {
1367 foreach ($domains as $domain) {
1368 $aliases = mailbox('get', 'aliases', $domain);
1369 if (!empty($aliases)) {
1370 foreach ($aliases as $alias) {
1371 if ($details = mailbox('get', 'alias_details', $alias)) {
1372 $data[] = $details;
1373 }
1374 else {
1375 continue;
1376 }
1377 }
1378 }
1379 }
1380 process_get_return($data);
1381 }
1382 else {
1383 echo '{}';
1384 }
1385 break;
1386
1387 default:
1388 process_get_return(mailbox('get', 'alias_details', $object));
1389 break;
1390 }
1391 break;
1392 case "domain-admin":
1393 switch ($object) {
1394 case "all":
1395 $domain_admins = domain_admin('get');
1396 if (!empty($domain_admins)) {
1397 foreach ($domain_admins as $domain_admin) {
1398 if ($details = domain_admin('details', $domain_admin)) {
1399 $data[] = $details;
1400 }
1401 else {
1402 continue;
1403 }
1404 }
1405 process_get_return($data);
1406 }
1407 else {
1408 echo '{}';
1409 }
1410 break;
1411
1412 default:
1413 process_get_return(domain_admin('details', $object));
1414 break;
1415 }
1416 break;
1417 case "admin":
1418 switch ($object) {
1419 case "all":
1420 $admins = admin('get');
1421 if (!empty($admins)) {
1422 foreach ($admins as $admin) {
1423 if ($details = admin('details', $admin)) {
1424 $data[] = $details;
1425 }
1426 else {
1427 continue;
1428 }
1429 }
1430 process_get_return($data);
1431 }
1432 else {
1433 echo '{}';
1434 }
1435 break;
1436
1437 default:
1438 process_get_return(admin('details', $object));
1439 break;
1440 }
1441 break;
1442 case "dkim":
1443 switch ($object) {
1444 default:
1445 $data = dkim('details', $object);
1446 process_get_return($data);
1447 break;
1448 }
1449 break;
1450 case "presets":
1451 switch ($object) {
1452 case "rspamd":
1453 process_get_return(presets('get', 'rspamd'));
1454 break;
1455 case "sieve":
1456 process_get_return(presets('get', 'sieve'));
1457 break;
1458 }
1459 break;
1460 case "status":
1461 if ($_SESSION['mailcow_cc_role'] == "admin") {
1462 switch ($object) {
1463 case "containers":
1464 $containers = (docker('info'));
1465 foreach ($containers as $container => $container_info) {
1466 $container . ' (' . $container_info['Config']['Image'] . ')';
1467 $containerstarttime = ($container_info['State']['StartedAt']);
1468 $containerstate = ($container_info['State']['Status']);
1469 $containerimage = ($container_info['Config']['Image']);
1470 $temp[$container] = array(
1471 'type' => 'info',
1472 'container' => $container,
1473 'state' => $containerstate,
1474 'started_at' => $containerstarttime,
1475 'image' => $containerimage
1476 );
1477 }
1478 echo json_encode($temp, JSON_UNESCAPED_SLASHES);
1479 break;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001480 case "container":
1481 $container_stats = docker('container_stats', $extra);
1482 echo json_encode($container_stats);
1483 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001484 case "vmail":
1485 $exec_fields_vmail = array('cmd' => 'system', 'task' => 'df', 'dir' => '/var/vmail');
1486 $vmail_df = explode(',', json_decode(docker('post', 'dovecot-mailcow', 'exec', $exec_fields_vmail), true));
1487 $temp = array(
1488 'type' => 'info',
1489 'disk' => $vmail_df[0],
1490 'used' => $vmail_df[2],
1491 'total'=> $vmail_df[1],
1492 'used_percent' => $vmail_df[4]
1493 );
1494 echo json_encode($temp, JSON_UNESCAPED_SLASHES);
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001495 break;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001496 case "host":
1497 if (!$extra){
1498 $stats = docker("host_stats");
1499 echo json_encode($stats);
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001500 }
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001501 else if ($extra == "ip") {
1502 // get public ips
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001503
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001504 $curl = curl_init();
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001505 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
1506 curl_setopt($curl, CURLOPT_POST, 0);
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01001507 curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);
1508 curl_setopt($curl, CURLOPT_TIMEOUT, 15);
1509 curl_setopt($curl, CURLOPT_URL, 'http://ipv4.mailcow.email');
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001510 $ipv4 = curl_exec($curl);
1511 curl_setopt($curl, CURLOPT_URL, 'http://ipv6.mailcow.email');
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001512 $ipv6 = curl_exec($curl);
1513 $ips = array(
1514 "ipv4" => $ipv4,
1515 "ipv6" => $ipv6
1516 );
1517 curl_close($curl);
1518 echo json_encode($ips);
1519 }
1520 break;
1521 case "version":
1522 echo json_encode(array(
1523 'version' => $GLOBALS['MAILCOW_GIT_VERSION']
1524 ));
1525 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001526 }
1527 }
1528 break;
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001529 case "spam-score":
1530 $score = mailbox('get', 'spam_score', $object);
1531 if ($score)
1532 $score = array("score" => preg_replace("/\s+/", "", $score));
1533 process_get_return($score);
1534 break;
Matthias Andreas Benkard97f12022026-10-23 08:46:40 +02001535 case "identity-provider":
1536 if($_SESSION['mailcow_cc_role'] === 'admin') {
1537 process_get_return($iam_settings);
1538 } else {
1539 process_get_return(null);
1540 }
1541 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001542 break;
1543 // return no route found if no case is matched
1544 default:
1545 http_response_code(404);
1546 echo json_encode(array(
1547 'type' => 'error',
1548 'msg' => 'route not found'
1549 ));
1550 exit();
1551 }
1552 }
1553 break;
Matthias Andreas Benkard97f12022026-10-23 08:46:40 +02001554 case "search":
1555 function process_search_return($return) {
1556 if ($return === false) {
1557 echo json_encode(array(
1558 'type' => 'error',
1559 'msg' => 'Cannot get item'
1560 ));
1561 }
1562 else {
1563 echo json_encode($return, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
1564 }
1565 }
1566 // only allow POST requests to SEARCH API endpoints
1567 if ($_SERVER['REQUEST_METHOD'] != 'POST') {
1568 http_response_code(405);
1569 echo json_encode(array(
1570 'type' => 'error',
1571 'msg' => 'only POST method is allowed'
1572 ));
1573 exit();
1574 }
1575
1576 // Load SSP class
1577 require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/lib/ssp.class.php';
1578 global $pdo;
1579
1580 switch ($category) {
1581 case "domain":
1582 $table = ['domain', 'd'];
1583 $primaryKey = 'domain';
1584 $columns = [
1585 ['db' => 'domain', 'dt' => 2],
1586 ['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`)"],
1587 ['db' => 'mailboxes', 'dt' => 4, 'order_subquery' => "SELECT COUNT(*) FROM `mailbox` WHERE `mailbox`.`domain` = `d`.`domain` AND (`mailbox`.`kind` = '' OR `mailbox`.`kind` = NULL)"],
1588 ['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)"],
1589 ['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`)"],
1590 ['db' => 'defquota', 'dt' => 7],
1591 ['db' => 'maxquota', 'dt' => 8],
1592 ['db' => 'backupmx', 'dt' => 10],
1593 ['db' => 'tags', 'dt' => 14, 'dummy' => true, 'search' => ['join' => 'LEFT JOIN `tags_domain` AS `td` ON `td`.`domain` = `d`.`domain`', 'where_column' => '`td`.`tag_name`']],
1594 ['db' => 'active', 'dt' => 15],
1595 ];
1596
1597 if($_SESSION['mailcow_cc_role'] === 'admin') {
1598 $data = SSP::simple($requestDecoded, $pdo, $table, $primaryKey, $columns);
1599 } elseif ($_SESSION['mailcow_cc_role'] === 'domainadmin') {
1600 $data = SSP::complex($requestDecoded, $pdo, $table, $primaryKey, $columns,
1601 'INNER JOIN domain_admins as da ON da.domain = d.domain',
1602 [
1603 'condition' => 'da.active = 1 and da.username = :username',
1604 'bindings' => ['username' => $_SESSION['mailcow_cc_username']]
1605 ]);
1606 } else {
1607 http_response_code(403);
1608 echo json_encode(array(
1609 'type' => 'error',
1610 'msg' => 'Insufficient permissions'
1611 ));
1612 exit();
1613 }
1614
1615 if (!empty($data['data'])) {
1616 $domainsData = [];
1617 foreach ($data['data'] as $domain) {
1618 if ($details = mailbox('get', 'domain_details', $domain[2])) {
1619 $domainsData[] = $details;
1620 }
1621 }
1622 $data['data'] = $domainsData;
1623 }
1624
1625 process_search_return($data);
1626 break;
1627
1628 case "mailbox":
1629 $table = ['mailbox', 'm'];
1630 $primaryKey = 'username';
1631 $columns = [
1632 ['db' => 'username', 'dt' => 2],
1633 ['db' => 'quota', 'dt' => 3],
1634 ['db' => 'last_mail_login', 'dt' => 4, 'dummy' => true, 'order_subquery' => "SELECT MAX(`datetime`) FROM `sasl_log` WHERE `service` != 'SSO' AND `username` = `m`.`username`"],
1635 ['db' => 'last_pw_change', 'dt' => 5, 'dummy' => true, 'order_subquery' => "JSON_EXTRACT(attributes, '$.passwd_update')"],
1636 ['db' => 'in_use', 'dt' => 6, 'dummy' => true, 'order_subquery' => "(SELECT SUM(bytes) FROM `quota2` WHERE `quota2`.`username` = `m`.`username`) / `m`.`quota`"],
1637 ['db' => 'name', 'dt' => 7],
1638 ['db' => 'messages', 'dt' => 20, 'dummy' => true, 'order_subquery' => "SELECT SUM(messages) FROM `quota2` WHERE `quota2`.`username` = `m`.`username`"],
1639 ['db' => 'tags', 'dt' => 23, 'dummy' => true, 'search' => ['join' => 'LEFT JOIN `tags_mailbox` AS `tm` ON `tm`.`username` = `m`.`username`', 'where_column' => '`tm`.`tag_name`']],
1640 ['db' => 'active', 'dt' => 24],
1641 ];
1642
1643 if($_SESSION['mailcow_cc_role'] === 'admin') {
1644 $data = SSP::complex($requestDecoded, $pdo, $table, $primaryKey, $columns, null,
1645 "(`m`.`kind` = '' OR `m`.`kind` = NULL)");
1646 } elseif ($_SESSION['mailcow_cc_role'] === 'domainadmin') {
1647 $data = SSP::complex($requestDecoded, $pdo, $table, $primaryKey, $columns,
1648 'INNER JOIN domain_admins as da ON da.domain = m.domain',
1649 [
1650 'condition' => "(`m`.`kind` = '' OR `m`.`kind` = NULL) AND `da`.`active` = 1 AND `da`.`username` = :username",
1651 'bindings' => ['username' => $_SESSION['mailcow_cc_username']]
1652 ]);
1653 } else {
1654 http_response_code(403);
1655 echo json_encode(array(
1656 'type' => 'error',
1657 'msg' => 'Insufficient permissions'
1658 ));
1659 exit();
1660 }
1661
1662 if (!empty($data['data'])) {
1663 $mailboxData = [];
1664 foreach ($data['data'] as $mailbox) {
1665 if ($details = mailbox('get', 'mailbox_details', $mailbox[2])) {
1666 $mailboxData[] = $details;
1667 }
1668 }
1669 $data['data'] = $mailboxData;
1670 }
1671
1672 process_search_return($data);
1673 break;
1674
1675 default:
1676 http_response_code(404);
1677 echo json_encode(array(
1678 'type' => 'error',
1679 'msg' => 'Invalid search category'
1680 ));
1681 break;
1682 }
1683 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001684 case "delete":
1685 if ($_SESSION['mailcow_cc_api_access'] == 'ro' || isset($_SESSION['pending_mailcow_cc_username']) || !isset($_SESSION["mailcow_cc_username"])) {
1686 http_response_code(403);
1687 echo json_encode(array(
1688 'type' => 'error',
1689 'msg' => 'API read/write access denied'
1690 ));
1691 exit();
1692 }
1693 function process_delete_return($return) {
1694 $generic_failure = json_encode(array(
1695 'type' => 'error',
1696 'msg' => 'Cannot delete item'
1697 ));
1698 $generic_success = json_encode(array(
1699 'type' => 'success',
1700 'msg' => 'Task completed'
1701 ));
1702 if ($return === false) {
1703 echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_failure;
1704 }
1705 else {
1706 echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_success;
1707 }
1708 }
1709 if (!isset($_POST['items'])) {
1710 echo $request_incomplete;
1711 exit;
1712 }
1713 else {
1714 $items = (array)json_decode($_POST['items'], true);
1715 }
1716 // only allow POST requests to POST API endpoints
1717 if ($_SERVER['REQUEST_METHOD'] != 'POST') {
1718 http_response_code(405);
1719 echo json_encode(array(
1720 'type' => 'error',
1721 'msg' => 'only POST method is allowed'
1722 ));
1723 exit();
1724 }
1725 switch ($category) {
1726 case "alias":
1727 process_delete_return(mailbox('delete', 'alias', array('id' => $items)));
1728 break;
1729 case "oauth2-client":
1730 process_delete_return(oauth2('delete', 'client', array('id' => $items)));
1731 break;
1732 case "app-passwd":
1733 process_delete_return(app_passwd('delete', array('id' => $items)));
1734 break;
1735 case "relayhost":
1736 process_delete_return(relayhost('delete', array('id' => $items)));
1737 break;
1738 case "transport":
1739 process_delete_return(transport('delete', array('id' => $items)));
1740 break;
1741 case "rsetting":
1742 process_delete_return(rsettings('delete', array('id' => $items)));
1743 break;
1744 case "syncjob":
1745 process_delete_return(mailbox('delete', 'syncjob', array('id' => $items)));
1746 break;
1747 case "filter":
1748 process_delete_return(mailbox('delete', 'filter', array('id' => $items)));
1749 break;
1750 case "mailq":
1751 process_delete_return(mailq('delete', array('qid' => $items)));
1752 break;
1753 case "qitem":
1754 process_delete_return(quarantine('delete', array('id' => $items)));
1755 break;
1756 case "bcc":
1757 process_delete_return(bcc('delete', array('id' => $items)));
1758 break;
1759 case "recipient_map":
1760 process_delete_return(recipient_map('delete', array('id' => $items)));
1761 break;
1762 case "tls-policy-map":
1763 process_delete_return(tls_policy_maps('delete', array('id' => $items)));
1764 break;
1765 case "fwdhost":
1766 process_delete_return(fwdhost('delete', array('forwardinghost' => $items)));
1767 break;
1768 case "dkim":
1769 process_delete_return(dkim('delete', array('domains' => $items)));
1770 break;
1771 case "domain":
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001772 switch ($object){
1773 case "tag":
1774 process_delete_return(mailbox('delete', 'tags_domain', array('tags' => $items, 'domain' => $extra)));
1775 break;
1776 case "template":
1777 process_delete_return(mailbox('delete', 'domain_templates', array('ids' => $items)));
1778 break;
1779 default:
1780 process_delete_return(mailbox('delete', 'domain', array('domain' => $items)));
1781 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001782 break;
1783 case "alias-domain":
1784 process_delete_return(mailbox('delete', 'alias_domain', array('alias_domain' => $items)));
1785 break;
1786 case "mailbox":
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001787 switch ($object){
1788 case "tag":
1789 process_delete_return(mailbox('delete', 'tags_mailbox', array('tags' => $items, 'username' => $extra)));
1790 break;
1791 case "template":
1792 process_delete_return(mailbox('delete', 'mailbox_templates', array('ids' => $items)));
1793 break;
1794 default:
1795 process_delete_return(mailbox('delete', 'mailbox', array('username' => $items)));
1796 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001797 break;
1798 case "resource":
1799 process_delete_return(mailbox('delete', 'resource', array('name' => $items)));
1800 break;
1801 case "mailbox-policy":
1802 process_delete_return(policy('delete', 'mailbox', array('prefid' => $items)));
1803 break;
1804 case "domain-policy":
1805 process_delete_return(policy('delete', 'domain', array('prefid' => $items)));
1806 break;
1807 case "time_limited_alias":
1808 process_delete_return(mailbox('delete', 'time_limited_alias', array('address' => $items)));
1809 break;
1810 case "eas_cache":
1811 process_delete_return(mailbox('delete', 'eas_cache', array('username' => $items)));
1812 break;
1813 case "sogo_profile":
1814 process_delete_return(mailbox('delete', 'sogo_profile', array('username' => $items)));
1815 break;
1816 case "domain-admin":
1817 process_delete_return(domain_admin('delete', array('username' => $items)));
1818 break;
1819 case "admin":
1820 process_delete_return(admin('delete', array('username' => $items)));
1821 break;
1822 case "rlhash":
1823 echo ratelimit('delete', null, implode($items));
1824 break;
Matthias Andreas Benkard97f12022026-10-23 08:46:40 +02001825 case "identity-provider":
1826 process_delete_return(identity_provider('delete'));
1827 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001828 // return no route found if no case is matched
1829 default:
1830 http_response_code(404);
1831 echo json_encode(array(
1832 'type' => 'error',
1833 'msg' => 'route not found'
1834 ));
1835 exit();
1836 }
1837 break;
1838 case "edit":
1839 if ($_SESSION['mailcow_cc_api_access'] == 'ro' || isset($_SESSION['pending_mailcow_cc_username']) || !isset($_SESSION["mailcow_cc_username"])) {
1840 http_response_code(403);
1841 echo json_encode(array(
1842 'type' => 'error',
1843 'msg' => 'API read/write access denied'
1844 ));
1845 exit();
1846 }
1847 function process_edit_return($return) {
1848 $generic_failure = json_encode(array(
1849 'type' => 'error',
1850 'msg' => 'Cannot edit item'
1851 ));
1852 $generic_success = json_encode(array(
1853 'type' => 'success',
1854 'msg' => 'Task completed'
1855 ));
1856 if ($return === false) {
1857 echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_failure;
1858 }
1859 else {
1860 echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_success;
1861 }
1862 }
1863 if (!isset($_POST['attr'])) {
1864 echo $request_incomplete;
1865 exit;
1866 }
1867 else {
1868 $attr = (array)json_decode($_POST['attr'], true);
1869 unset($attr['csrf_token']);
1870 $items = isset($_POST['items']) ? (array)json_decode($_POST['items'], true) : null;
1871 }
1872 // only allow POST requests to POST API endpoints
1873 if ($_SERVER['REQUEST_METHOD'] != 'POST') {
1874 http_response_code(405);
1875 echo json_encode(array(
1876 'type' => 'error',
1877 'msg' => 'only POST method is allowed'
1878 ));
1879 exit();
1880 }
1881 switch ($category) {
1882 case "bcc":
1883 process_edit_return(bcc('edit', array_merge(array('id' => $items), $attr)));
1884 break;
1885 case "pushover":
1886 process_edit_return(pushover('edit', array_merge(array('username' => $items), $attr)));
1887 break;
1888 case "pushover-test":
1889 process_edit_return(pushover('test', array_merge(array('username' => $items), $attr)));
1890 break;
1891 case "oauth2-client":
1892 process_edit_return(oauth2('edit', 'client', array_merge(array('id' => $items), $attr)));
1893 break;
1894 case "recipient_map":
1895 process_edit_return(recipient_map('edit', array_merge(array('id' => $items), $attr)));
1896 break;
1897 case "app-passwd":
1898 process_edit_return(app_passwd('edit', array_merge(array('id' => $items), $attr)));
1899 break;
1900 case "tls-policy-map":
1901 process_edit_return(tls_policy_maps('edit', array_merge(array('id' => $items), $attr)));
1902 break;
1903 case "alias":
1904 process_edit_return(mailbox('edit', 'alias', array_merge(array('id' => $items), $attr)));
1905 break;
1906 case "rspamd-map":
1907 process_edit_return(rspamd_maps('edit', array_merge(array('map' => $items), $attr)));
1908 break;
1909 case "fido2-fn":
1910 process_edit_return(fido2(array('action' => 'edit_fn', 'fido2_attrs' => $attr)));
1911 break;
1912 case "app_links":
1913 process_edit_return(customize('edit', 'app_links', $attr));
1914 break;
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02001915 case "passwordpolicy":
1916 process_edit_return(password_complexity('edit', $attr));
1917 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001918 case "relayhost":
1919 process_edit_return(relayhost('edit', array_merge(array('id' => $items), $attr)));
1920 break;
1921 case "transport":
1922 process_edit_return(transport('edit', array_merge(array('id' => $items), $attr)));
1923 break;
1924 case "rsetting":
1925 process_edit_return(rsettings('edit', array_merge(array('id' => $items), $attr)));
1926 break;
1927 case "delimiter_action":
1928 process_edit_return(mailbox('edit', 'delimiter_action', array_merge(array('username' => $items), $attr)));
1929 break;
1930 case "tls_policy":
1931 process_edit_return(mailbox('edit', 'tls_policy', array_merge(array('username' => $items), $attr)));
1932 break;
1933 case "quarantine_notification":
1934 process_edit_return(mailbox('edit', 'quarantine_notification', array_merge(array('username' => $items), $attr)));
1935 break;
1936 case "quarantine_category":
1937 process_edit_return(mailbox('edit', 'quarantine_category', array_merge(array('username' => $items), $attr)));
1938 break;
1939 case "qitem":
1940 process_edit_return(quarantine('edit', array_merge(array('id' => $items), $attr)));
1941 break;
1942 case "quarantine":
1943 process_edit_return(quarantine('edit', $attr));
1944 break;
1945 case "quota_notification":
1946 process_edit_return(quota_notification('edit', $attr));
1947 break;
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02001948 case "quota_notification_bcc":
1949 process_edit_return(quota_notification_bcc('edit', $attr));
1950 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001951 case "mailq":
1952 process_edit_return(mailq('edit', array_merge(array('qid' => $items), $attr)));
1953 break;
1954 case "time_limited_alias":
1955 process_edit_return(mailbox('edit', 'time_limited_alias', array_merge(array('address' => $items), $attr)));
1956 break;
1957 case "mailbox":
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001958 switch ($object) {
1959 case "template":
1960 process_edit_return(mailbox('edit', 'mailbox_templates', array_merge(array('ids' => $items), $attr)));
1961 break;
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001962 case "custom-attribute":
1963 process_edit_return(mailbox('edit', 'mailbox_custom_attribute', array_merge(array('mailboxes' => $items), $attr)));
1964 break;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001965 default:
1966 process_edit_return(mailbox('edit', 'mailbox', array_merge(array('username' => $items), $attr)));
1967 break;
1968 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001969 break;
1970 case "syncjob":
1971 process_edit_return(mailbox('edit', 'syncjob', array_merge(array('id' => $items), $attr)));
1972 break;
1973 case "filter":
1974 process_edit_return(mailbox('edit', 'filter', array_merge(array('id' => $items), $attr)));
1975 break;
1976 case "resource":
1977 process_edit_return(mailbox('edit', 'resource', array_merge(array('name' => $items), $attr)));
1978 break;
1979 case "domain":
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001980 switch ($object) {
1981 case "template":
1982 process_edit_return(mailbox('edit', 'domain_templates', array_merge(array('ids' => $items), $attr)));
1983 break;
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001984 case "footer":
1985 process_edit_return(mailbox('edit', 'domain_wide_footer', array_merge(array('domains' => $items), $attr)));
1986 break;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001987 default:
1988 process_edit_return(mailbox('edit', 'domain', array_merge(array('domain' => $items), $attr)));
1989 break;
1990 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001991 break;
1992 case "rl-domain":
1993 process_edit_return(ratelimit('edit', 'domain', array_merge(array('object' => $items), $attr)));
1994 break;
1995 case "rl-mbox":
1996 process_edit_return(ratelimit('edit', 'mailbox', array_merge(array('object' => $items), $attr)));
1997 break;
Matthias Andreas Benkard97f12022026-10-23 08:46:40 +02001998 case "rename-mbox":
1999 process_edit_return(mailbox('edit', 'mailbox_rename', array_merge(array('mailbox' => $items), $attr)));
2000 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002001 case "user-acl":
2002 process_edit_return(acl('edit', 'user', array_merge(array('username' => $items), $attr)));
2003 break;
2004 case "da-acl":
2005 process_edit_return(acl('edit', 'domainadmin', array_merge(array('username' => $items), $attr)));
2006 break;
2007 case "alias-domain":
2008 process_edit_return(mailbox('edit', 'alias_domain', array_merge(array('alias_domain' => $items), $attr)));
2009 break;
2010 case "spam-score":
2011 process_edit_return(mailbox('edit', 'spam_score', array_merge(array('username' => $items), $attr)));
2012 break;
2013 case "domain-admin":
2014 process_edit_return(domain_admin('edit', array_merge(array('username' => $items), $attr)));
2015 break;
2016 case "admin":
2017 process_edit_return(admin('edit', array_merge(array('username' => $items), $attr)));
2018 break;
2019 case "fwdhost":
2020 process_edit_return(fwdhost('edit', array_merge(array('fwdhost' => $items), $attr)));
2021 break;
2022 case "fail2ban":
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01002023 switch ($object) {
2024 case 'banlist':
2025 process_edit_return(fail2ban('banlist', 'refresh', $items));
2026 break;
2027 default:
2028 process_edit_return(fail2ban('edit', array_merge(array('network' => $items), $attr)));
2029 break;
2030 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002031 break;
2032 case "ui_texts":
2033 process_edit_return(customize('edit', 'ui_texts', $attr));
2034 break;
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01002035 case "ip_check":
2036 process_edit_return(customize('edit', 'ip_check', $attr));
2037 break;
Matthias Andreas Benkard97f12022026-10-23 08:46:40 +02002038 case "custom_login":
2039 process_edit_return(customize('edit', 'custom_login', $attr));
2040 break;
2041 case "ui_theme":
2042 process_edit_return(customize('edit', 'ui_theme', $attr));
2043 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002044 case "self":
2045 if ($_SESSION['mailcow_cc_role'] == "domainadmin") {
2046 process_edit_return(domain_admin('edit', $attr));
2047 }
2048 elseif ($_SESSION['mailcow_cc_role'] == "user") {
2049 process_edit_return(edit_user_account($attr));
2050 }
2051 break;
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01002052 case "cors":
2053 process_edit_return(cors('edit', $attr));
2054 break;
Matthias Andreas Benkard97f12022026-10-23 08:46:40 +02002055 case "identity-provider":
2056 process_edit_return(identity_provider('edit', $attr));
2057 break;
2058 case "identity-provider-test":
2059 process_edit_return(identity_provider('test', $attr));
2060 break;
2061 case "cors":
2062 process_edit_return(cors('edit', $attr));
2063 break;
2064 case "reset-password-notification":
2065 process_edit_return(reset_password('edit_notification', $attr));
2066 break;
2067 case "mta-sts":
2068 process_edit_return(mailbox('edit', 'mta_sts', array_merge(array('domains' => $items), $attr)));
2069 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002070 // return no route found if no case is matched
2071 default:
2072 http_response_code(404);
2073 echo json_encode(array(
2074 'type' => 'error',
2075 'msg' => 'route not found'
2076 ));
2077 exit();
2078 }
2079 break;
2080 // return no route found if no case is matched
2081 default:
2082 http_response_code(404);
2083 echo json_encode(array(
2084 'type' => 'error',
2085 'msg' => 'route not found'
2086 ));
2087 exit();
2088 }
2089}
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01002090if (array_key_exists('mailcow_cc_api', $_SESSION) && $_SESSION['mailcow_cc_api'] === true) {
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002091 if (isset($_SESSION['mailcow_cc_api']) && $_SESSION['mailcow_cc_api'] === true) {
2092 unset($_SESSION['return']);
2093 }
2094}