blob: cdefb83ae7693bbcfec746451d9e27bd904b91c5 [file] [log] [blame]
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001<?php
2/*
3 see /api
4*/
5
6header('Content-Type: application/json');
7require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
8error_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 }
17 if ($value = json_decode($value, true)) {
18 unset($value["csrf_token"]);
19 foreach ($value as $key => &$val) {
20 if(preg_match("/pass/i", $key)) {
21 $val = '*';
22 }
23 }
24 $value = json_encode($value);
25 }
26 $data_var[] = $data . "='" . $value . "'";
27 }
28 try {
29 $log_line = array(
30 'time' => time(),
31 'uri' => $_SERVER['REQUEST_URI'],
32 'method' => $_SERVER['REQUEST_METHOD'],
33 'remote' => get_remote_ip(),
34 'data' => implode(', ', $data_var)
35 );
36 $redis->lPush('API_LOG', json_encode($log_line));
37 }
38 catch (RedisException $e) {
39 $_SESSION['return'][] = array(
40 'type' => 'danger',
41 'msg' => 'Redis: '.$e
42 );
43 return false;
44 }
45}
46
47if (isset($_GET['query'])) {
48
49 $query = explode('/', $_GET['query']);
50 $action = (isset($query[0])) ? $query[0] : null;
51 $category = (isset($query[1])) ? $query[1] : null;
52 $object = (isset($query[2])) ? $query[2] : null;
53 $extra = (isset($query[3])) ? $query[3] : null;
54
55 // accept json in request body
56 if(strpos($_SERVER['HTTP_CONTENT_TYPE'], 'application/json') !== false) {
57 $request = file_get_contents('php://input');
58 $requestDecoded = json_decode($request, true);
59
60 // check for valid json
61 if ($action != 'get' && $requestDecoded === null) {
62 http_response_code(400);
63 echo json_encode(array(
64 'type' => 'error',
65 'msg' => 'Request body doesn\'t contain valid json!'
66 ));
67 exit;
68 }
69
70 // add
71 if ($action == 'add') {
72 $_POST['attr'] = $request;
73 }
74
75 // edit
76 if ($action == 'edit') {
77 $_POST['attr'] = json_encode($requestDecoded['attr']);
78 $_POST['items'] = json_encode($requestDecoded['items']);
79 }
80
81 // delete
82 if ($action == 'delete') {
83 $_POST['items'] = $request;
84 }
85
86 }
87 api_log($_POST);
88
89 $request_incomplete = json_encode(array(
90 'type' => 'error',
91 'msg' => 'Cannot find attributes in post data'
92 ));
93
94 switch ($action) {
95 case "add":
96 if ($_SESSION['mailcow_cc_api_access'] == 'ro' || isset($_SESSION['pending_mailcow_cc_username'])) {
97 http_response_code(403);
98 echo json_encode(array(
99 'type' => 'error',
100 'msg' => 'API read/write access denied'
101 ));
102 exit();
103 }
104 function process_add_return($return) {
105 $generic_failure = json_encode(array(
106 'type' => 'error',
107 'msg' => 'Cannot add item'
108 ));
109 $generic_success = json_encode(array(
110 'type' => 'success',
111 'msg' => 'Task completed'
112 ));
113 if ($return === false) {
114 echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_failure;
115 }
116 else {
117 echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_success;
118 }
119 }
120 if (!isset($_POST['attr']) && $category != "fido2-registration") {
121 echo $request_incomplete;
122 exit;
123 }
124 else {
125 if ($category != "fido2-registration") {
126 $attr = (array)json_decode($_POST['attr'], true);
127 }
128 unset($attr['csrf_token']);
129 }
130 // only allow POST requests to POST API endpoints
131 if ($_SERVER['REQUEST_METHOD'] != 'POST') {
132 http_response_code(405);
133 echo json_encode(array(
134 'type' => 'error',
135 'msg' => 'only POST method is allowed'
136 ));
137 exit();
138 }
139
140 switch ($category) {
141 // fido2-registration via POST
142 case "fido2-registration":
143 header('Content-Type: application/json');
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200144 if (isset($_SESSION["mailcow_cc_role"])) {
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100145 $post = trim(file_get_contents('php://input'));
146 if ($post) {
147 $post = json_decode($post);
148 }
149 $clientDataJSON = base64_decode($post->clientDataJSON);
150 $attestationObject = base64_decode($post->attestationObject);
151 $challenge = $_SESSION['challenge'];
152 try {
153 $data = $WebAuthn->processCreate($clientDataJSON, $attestationObject, $challenge, $GLOBALS['FIDO2_UV_FLAG_REGISTER'], $GLOBALS['FIDO2_USER_PRESENT_FLAG']);
154 }
155 catch (Throwable $ex) {
156 $return = new stdClass();
157 $return->success = false;
158 $return->msg = $ex->getMessage();
159 echo json_encode($return);
160 exit;
161 }
162 fido2(array("action" => "register", "registration" => $data));
163 $return = new stdClass();
164 $return->success = true;
165 echo json_encode($return);
166 exit;
167 }
168 else {
169 echo $request_incomplete;
170 exit;
171 }
172 break;
173 case "time_limited_alias":
174 process_add_return(mailbox('add', 'time_limited_alias', $attr));
175 break;
176 case "relayhost":
177 process_add_return(relayhost('add', $attr));
178 break;
179 case "transport":
180 process_add_return(transport('add', $attr));
181 break;
182 case "rsetting":
183 process_add_return(rsettings('add', $attr));
184 break;
185 case "mailbox":
186 process_add_return(mailbox('add', 'mailbox', $attr));
187 break;
188 case "oauth2-client":
189 process_add_return(oauth2('add', 'client', $attr));
190 break;
191 case "domain":
192 process_add_return(mailbox('add', 'domain', $attr));
193 break;
194 case "resource":
195 process_add_return(mailbox('add', 'resource', $attr));
196 break;
197 case "alias":
198 process_add_return(mailbox('add', 'alias', $attr));
199 break;
200 case "filter":
201 process_add_return(mailbox('add', 'filter', $attr));
202 break;
203 case "global-filter":
204 process_add_return(mailbox('add', 'global_filter', $attr));
205 break;
206 case "domain-policy":
207 process_add_return(policy('add', 'domain', $attr));
208 break;
209 case "mailbox-policy":
210 process_add_return(policy('add', 'mailbox', $attr));
211 break;
212 case "alias-domain":
213 process_add_return(mailbox('add', 'alias_domain', $attr));
214 break;
215 case "fwdhost":
216 process_add_return(fwdhost('add', $attr));
217 break;
218 case "dkim":
219 process_add_return(dkim('add', $attr));
220 break;
221 case "dkim_duplicate":
222 process_add_return(dkim('duplicate', $attr));
223 break;
224 case "dkim_import":
225 process_add_return(dkim('import', $attr));
226 break;
227 case "domain-admin":
228 process_add_return(domain_admin('add', $attr));
229 break;
230 case "admin":
231 process_add_return(admin('add', $attr));
232 break;
233 case "syncjob":
234 process_add_return(mailbox('add', 'syncjob', $attr));
235 break;
236 case "bcc":
237 process_add_return(bcc('add', $attr));
238 break;
239 case "recipient_map":
240 process_add_return(recipient_map('add', $attr));
241 break;
242 case "tls-policy-map":
243 process_add_return(tls_policy_maps('add', $attr));
244 break;
245 case "app-passwd":
246 process_add_return(app_passwd('add', $attr));
247 break;
248 // return no route found if no case is matched
249 default:
250 http_response_code(404);
251 echo json_encode(array(
252 'type' => 'error',
253 'msg' => 'route not found'
254 ));
255 exit();
256 }
257 break;
258 case "process":
259 // only allow POST requests to process API endpoints
260 if ($_SERVER['REQUEST_METHOD'] != 'POST') {
261 http_response_code(405);
262 echo json_encode(array(
263 'type' => 'error',
264 'msg' => 'only POST method is allowed'
265 ));
266 exit();
267 }
268 switch ($category) {
269 case "fido2-args":
270 header('Content-Type: application/json');
271 $post = trim(file_get_contents('php://input'));
272 if ($post) {
273 $post = json_decode($post);
274 }
275 $clientDataJSON = base64_decode($post->clientDataJSON);
276 $authenticatorData = base64_decode($post->authenticatorData);
277 $signature = base64_decode($post->signature);
278 $id = base64_decode($post->id);
279 $challenge = $_SESSION['challenge'];
280 $process_fido2 = fido2(array("action" => "get_by_b64cid", "cid" => $post->id));
281 if ($process_fido2['pub_key'] === false) {
282 $return = new stdClass();
283 $return->success = false;
284 echo json_encode($return);
285 exit;
286 }
287 try {
288 $WebAuthn->processGet($clientDataJSON, $authenticatorData, $signature, $process_fido2['pub_key'], $challenge, null, $GLOBALS['FIDO2_UV_FLAG_LOGIN'], $GLOBALS['FIDO2_USER_PRESENT_FLAG']);
289 }
290 catch (Throwable $ex) {
291 unset($process_fido2);
292 $return = new stdClass();
293 $return->success = false;
294 echo json_encode($return);
295 exit;
296 }
297 $return = new stdClass();
298 $return->success = true;
299 $stmt = $pdo->prepare("SELECT `superadmin` FROM `admin` WHERE `username` = :username");
300 $stmt->execute(array(':username' => $process_fido2['username']));
301 $obj_props = $stmt->fetch(PDO::FETCH_ASSOC);
302 if ($obj_props['superadmin'] === 1) {
303 $_SESSION["mailcow_cc_role"] = "admin";
304 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200305 elseif ($obj_props['superadmin'] === 0) {
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100306 $_SESSION["mailcow_cc_role"] = "domainadmin";
307 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200308 else {
309 $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :username");
310 $stmt->execute(array(':username' => $process_fido2['username']));
311 $row = $stmt->fetch(PDO::FETCH_ASSOC);
312 if ($row['username'] == $process_fido2['username']) {
313 $_SESSION["mailcow_cc_role"] = "user";
314 }
315 }
316 if (empty($_SESSION["mailcow_cc_role"])) {
317 session_unset();
318 session_destroy();
319 exit;
320 }
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100321 $_SESSION["mailcow_cc_username"] = $process_fido2['username'];
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100322 $_SESSION["fido2_cid"] = $process_fido2['cid'];
323 unset($_SESSION["challenge"]);
324 $_SESSION['return'][] = array(
325 'type' => 'success',
326 'log' => array("fido2_login"),
327 'msg' => array('logged_in_as', $process_fido2['username'])
328 );
329 echo json_encode($return);
330 break;
331 }
332 break;
333 case "get":
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200334 function process_get_return($data, $object = true) {
335 if ($object === true) {
336 $ret_str = '{}';
337 }
338 else {
339 $ret_str = '[]';
340 }
341 echo (!isset($data) || empty($data)) ? $ret_str : json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100342 }
343 // only allow GET requests to GET API endpoints
344 if ($_SERVER['REQUEST_METHOD'] != 'GET') {
345 http_response_code(405);
346 echo json_encode(array(
347 'type' => 'error',
348 'msg' => 'only GET method is allowed'
349 ));
350 exit();
351 }
352 switch ($category) {
353 case "u2f-registration":
354 header('Content-Type: application/javascript');
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200355 if (isset($_SESSION["mailcow_cc_role"]) && $_SESSION["mailcow_cc_username"] == $object) {
356 list($req, $sigs) = $u2f->getRegisterData(get_u2f_registrations($object));
357 $_SESSION['regReq'] = json_encode($req);
358 $_SESSION['regSigs'] = json_encode($sigs);
359 echo 'var req = ' . json_encode($req) . ';';
360 echo 'var registeredKeys = ' . json_encode($sigs) . ';';
361 echo 'var appId = req.appId;';
362 echo 'var registerRequests = [{version: req.version, challenge: req.challenge}];';
363 return;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100364 }
365 else {
366 return;
367 }
368 break;
369 // fido2-registration via GET
370 case "fido2-registration":
371 header('Content-Type: application/json');
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200372 if (isset($_SESSION["mailcow_cc_role"])) {
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100373 // Exclude existing CredentialIds, if any
374 $excludeCredentialIds = fido2(array("action" => "get_user_cids"));
375 $createArgs = $WebAuthn->getCreateArgs($_SESSION["mailcow_cc_username"], $_SESSION["mailcow_cc_username"], $_SESSION["mailcow_cc_username"], 30, true, $GLOBALS['FIDO2_UV_FLAG_REGISTER'], $excludeCredentialIds);
376 print(json_encode($createArgs));
377 $_SESSION['challenge'] = $WebAuthn->getChallenge();
378 return;
379 }
380 else {
381 return;
382 }
383 break;
384 case "u2f-authentication":
385 header('Content-Type: application/javascript');
386 if (isset($_SESSION['pending_mailcow_cc_username']) && $_SESSION['pending_mailcow_cc_username'] == $object) {
387 $auth_data = $u2f->getAuthenticateData(get_u2f_registrations($object));
388 $challenge = $auth_data[0]->challenge;
389 $appId = $auth_data[0]->appId;
390 foreach ($auth_data as $each) {
391 $key = array(); // Empty array
392 $key['version'] = $each->version;
393 $key['keyHandle'] = $each->keyHandle;
394 $registeredKey[] = $key;
395 }
396 $_SESSION['authReq'] = json_encode($auth_data);
397 echo 'var appId = "' . $appId . '";';
398 echo 'var challenge = ' . json_encode($challenge) . ';';
399 echo 'var registeredKeys = ' . json_encode($registeredKey) . ';';
400 return;
401 }
402 else {
403 return;
404 }
405 break;
406 case "fido2-get-args":
407 header('Content-Type: application/json');
408 // Login without username, no ids!
409 // $ids = fido2(array("action" => "get_all_cids"));
410 // if (count($ids) == 0) {
411 // return;
412 // }
413 $ids = NULL;
414 $getArgs = $WebAuthn->getGetArgs($ids, 30, true, true, true, true, $GLOBALS['FIDO2_UV_FLAG_LOGIN']);
415 print(json_encode($getArgs));
416 $_SESSION['challenge'] = $WebAuthn->getChallenge();
417 return;
418 break;
419 }
420 if (isset($_SESSION['mailcow_cc_role'])) {
421 switch ($category) {
422 case "rspamd":
423 switch ($object) {
424 case "actions":
425 $data = rspamd_actions();
426 if ($data) {
427 echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
428 }
429 else {
430 echo '{}';
431 }
432 break;
433 }
434 break;
435
436 case "domain":
437 switch ($object) {
438 case "all":
439 $domains = mailbox('get', 'domains');
440 if (!empty($domains)) {
441 foreach ($domains as $domain) {
442 if ($details = mailbox('get', 'domain_details', $domain)) {
443 $data[] = $details;
444 }
445 else {
446 continue;
447 }
448 }
449 process_get_return($data);
450 }
451 else {
452 echo '{}';
453 }
454 break;
455
456 default:
457 $data = mailbox('get', 'domain_details', $object);
458 process_get_return($data);
459 break;
460 }
461 break;
462
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200463 case "passwordpolicy":
464 switch ($object) {
465 case "html":
466 $password_complexity_rules = password_complexity('html');
467 if ($password_complexity_rules !== false) {
468 process_get_return($password_complexity_rules);
469 }
470 else {
471 echo '{}';
472 }
473 break;
474 }
475 break;
476
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100477 case "app-passwd":
478 switch ($object) {
479 case "all":
480 if (empty($extra)) {
481 $app_passwds = app_passwd('get');
482 }
483 else {
484 $app_passwds = app_passwd('get', array('username' => $extra));
485 }
486 if (!empty($app_passwds)) {
487 foreach ($app_passwds as $app_passwd) {
488 $details = app_passwd('details', array('id' => $app_passwd['id']));
489 if ($details !== false) {
490 $data[] = $details;
491 }
492 else {
493 continue;
494 }
495 }
496 process_get_return($data);
497 }
498 else {
499 echo '{}';
500 }
501 break;
502
503 default:
504 $data = app_passwd('details', array('id' => $object['id']));
505 process_get_return($data);
506 break;
507 }
508 break;
509
510 case "mailq":
511 switch ($object) {
512 case "all":
513 $mailq = mailq('get');
514 if (!empty($mailq)) {
515 echo $mailq;
516 }
517 else {
518 echo '[]';
519 }
520 break;
521 }
522 break;
523
524 case "postcat":
525 switch ($object) {
526 default:
527 $data = mailq('cat', array('qid' => $object));
528 echo $data;
529 break;
530 }
531 break;
532
533 case "global_filters":
534 $global_filters = mailbox('get', 'global_filter_details');
535 switch ($object) {
536 case "all":
537 if (!empty($global_filters)) {
538 process_get_return($global_filters);
539 }
540 else {
541 echo '{}';
542 }
543 break;
544 case "prefilter":
545 if (!empty($global_filters['prefilter'])) {
546 process_get_return($global_filters['prefilter']);
547 }
548 else {
549 echo '{}';
550 }
551 break;
552 case "postfilter":
553 if (!empty($global_filters['postfilter'])) {
554 process_get_return($global_filters['postfilter']);
555 }
556 else {
557 echo '{}';
558 }
559 break;
560 }
561 break;
562
563 case "rl-domain":
564 switch ($object) {
565 case "all":
566 $domains = array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains'));
567 if (!empty($domains)) {
568 foreach ($domains as $domain) {
569 if ($details = ratelimit('get', 'domain', $domain)) {
570 $details['domain'] = $domain;
571 $data[] = $details;
572 }
573 else {
574 continue;
575 }
576 }
577 process_get_return($data);
578 }
579 else {
580 echo '{}';
581 }
582 break;
583
584 default:
585 $data = ratelimit('get', 'domain', $object);
586 process_get_return($data);
587 break;
588 }
589 break;
590
591 case "rl-mbox":
592 switch ($object) {
593 case "all":
594 $domains = mailbox('get', 'domains');
595 if (!empty($domains)) {
596 foreach ($domains as $domain) {
597 $mailboxes = mailbox('get', 'mailboxes', $domain);
598 if (!empty($mailboxes)) {
599 foreach ($mailboxes as $mailbox) {
600 if ($details = ratelimit('get', 'mailbox', $mailbox)) {
601 $details['mailbox'] = $mailbox;
602 $data[] = $details;
603 }
604 else {
605 continue;
606 }
607 }
608 }
609 }
610 process_get_return($data);
611 }
612 else {
613 echo '{}';
614 }
615 break;
616
617 default:
618 $data = ratelimit('get', 'mailbox', $object);
619 process_get_return($data);
620 break;
621 }
622 break;
623
624 case "relayhost":
625 switch ($object) {
626 case "all":
627 $relayhosts = relayhost('get');
628 if (!empty($relayhosts)) {
629 foreach ($relayhosts as $relayhost) {
630 if ($details = relayhost('details', $relayhost['id'])) {
631 $data[] = $details;
632 }
633 else {
634 continue;
635 }
636 }
637 process_get_return($data);
638 }
639 else {
640 echo '{}';
641 }
642 break;
643
644 default:
645 $data = relayhost('details', $object);
646 process_get_return($data);
647 break;
648 }
649 break;
650
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200651 case "last-login":
652 if ($object) {
653 // extra == days
654 if (isset($extra) && intval($extra) >= 1) {
655 $data = last_login('get', $object, intval($extra));
656 }
657 else {
658 $data = last_login('get', $object);
659 }
660 process_get_return($data);
661 }
662 break;
663
664 // Todo: move to delete
665 case "reset-last-login":
666 if ($object) {
667 $data = last_login('reset', $object);
668 process_get_return($data);
669 }
670 break;
671
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100672 case "transport":
673 switch ($object) {
674 case "all":
675 $transports = transport('get');
676 if (!empty($transports)) {
677 foreach ($transports as $transport) {
678 if ($details = transport('details', $transport['id'])) {
679 $data[] = $details;
680 }
681 else {
682 continue;
683 }
684 }
685 process_get_return($data);
686 }
687 else {
688 echo '{}';
689 }
690 break;
691
692 default:
693 $data = transport('details', $object);
694 process_get_return($data);
695 break;
696 }
697 break;
698
699 case "rsetting":
700 switch ($object) {
701 case "all":
702 $rsettings = rsettings('get');
703 if (!empty($rsettings)) {
704 foreach ($rsettings as $rsetting) {
705 if ($details = rsettings('details', $rsetting['id'])) {
706 $data[] = $details;
707 }
708 else {
709 continue;
710 }
711 }
712 process_get_return($data);
713 }
714 else {
715 echo '{}';
716 }
717 break;
718
719 default:
720 $data = rsettings('details', $object);
721 process_get_return($data);
722 break;
723 }
724 break;
725
726 case "oauth2-client":
727 switch ($object) {
728 case "all":
729 $clients = oauth2('get', 'clients');
730 if (!empty($clients)) {
731 foreach ($clients as $client) {
732 if ($details = oauth2('details', 'client', $client)) {
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 = oauth2('details', 'client', $object);
748 process_get_return($data);
749 break;
750 }
751 break;
752
753 case "logs":
754 switch ($object) {
755 case "dovecot":
756 // 0 is first record, so empty is fine
757 if (isset($extra)) {
758 $extra = preg_replace('/[^\d\-]/i', '', $extra);
759 $logs = get_logs('dovecot-mailcow', $extra);
760 }
761 else {
762 $logs = get_logs('dovecot-mailcow');
763 }
764 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
765 break;
766 case "ratelimited":
767 // 0 is first record, so empty is fine
768 if (isset($extra)) {
769 $extra = preg_replace('/[^\d\-]/i', '', $extra);
770 $logs = get_logs('ratelimited', $extra);
771 }
772 else {
773 $logs = get_logs('ratelimited');
774 }
775 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
776 break;
777 case "netfilter":
778 // 0 is first record, so empty is fine
779 if (isset($extra)) {
780 $extra = preg_replace('/[^\d\-]/i', '', $extra);
781 $logs = get_logs('netfilter-mailcow', $extra);
782 }
783 else {
784 $logs = get_logs('netfilter-mailcow');
785 }
786 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
787 break;
788 case "postfix":
789 // 0 is first record, so empty is fine
790 if (isset($extra)) {
791 $extra = preg_replace('/[^\d\-]/i', '', $extra);
792 $logs = get_logs('postfix-mailcow', $extra);
793 }
794 else {
795 $logs = get_logs('postfix-mailcow');
796 }
797 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
798 break;
799 case "autodiscover":
800 // 0 is first record, so empty is fine
801 if (isset($extra)) {
802 $extra = preg_replace('/[^\d\-]/i', '', $extra);
803 $logs = get_logs('autodiscover-mailcow', $extra);
804 }
805 else {
806 $logs = get_logs('autodiscover-mailcow');
807 }
808 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
809 break;
810 case "sogo":
811 // 0 is first record, so empty is fine
812 if (isset($extra)) {
813 $extra = preg_replace('/[^\d\-]/i', '', $extra);
814 $logs = get_logs('sogo-mailcow', $extra);
815 }
816 else {
817 $logs = get_logs('sogo-mailcow');
818 }
819 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
820 break;
821 case "ui":
822 // 0 is first record, so empty is fine
823 if (isset($extra)) {
824 $extra = preg_replace('/[^\d\-]/i', '', $extra);
825 $logs = get_logs('mailcow-ui', $extra);
826 }
827 else {
828 $logs = get_logs('mailcow-ui');
829 }
830 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
831 break;
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200832 case "sasl":
833 // 0 is first record, so empty is fine
834 if (isset($extra)) {
835 $extra = preg_replace('/[^\d\-]/i', '', $extra);
836 $logs = get_logs('sasl', $extra);
837 }
838 else {
839 $logs = get_logs('sasl');
840 }
841 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
842 break;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100843 case "watchdog":
844 // 0 is first record, so empty is fine
845 if (isset($extra)) {
846 $extra = preg_replace('/[^\d\-]/i', '', $extra);
847 $logs = get_logs('watchdog-mailcow', $extra);
848 }
849 else {
850 $logs = get_logs('watchdog-mailcow');
851 }
852 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
853 break;
854 case "acme":
855 // 0 is first record, so empty is fine
856 if (isset($extra)) {
857 $extra = preg_replace('/[^\d\-]/i', '', $extra);
858 $logs = get_logs('acme-mailcow', $extra);
859 }
860 else {
861 $logs = get_logs('acme-mailcow');
862 }
863 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
864 break;
865 case "api":
866 // 0 is first record, so empty is fine
867 if (isset($extra)) {
868 $extra = preg_replace('/[^\d\-]/i', '', $extra);
869 $logs = get_logs('api-mailcow', $extra);
870 }
871 else {
872 $logs = get_logs('api-mailcow');
873 }
874 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
875 break;
876 case "rspamd-history":
877 // 0 is first record, so empty is fine
878 if (isset($extra)) {
879 $extra = preg_replace('/[^\d\-]/i', '', $extra);
880 $logs = get_logs('rspamd-history', $extra);
881 }
882 else {
883 $logs = get_logs('rspamd-history');
884 }
885 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
886 break;
887 case "rspamd-stats":
888 $logs = get_logs('rspamd-stats');
889 echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
890 break;
891 // return no route found if no case is matched
892 default:
893 http_response_code(404);
894 echo json_encode(array(
895 'type' => 'error',
896 'msg' => 'route not found'
897 ));
898 exit();
899 }
900 break;
901 case "mailbox":
902 switch ($object) {
903 case "all":
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200904 case "reduced":
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100905 if (empty($extra)) {
906 $domains = mailbox('get', 'domains');
907 }
908 else {
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200909 $domains = explode(',', $extra);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100910 }
911 if (!empty($domains)) {
912 foreach ($domains as $domain) {
913 $mailboxes = mailbox('get', 'mailboxes', $domain);
914 if (!empty($mailboxes)) {
915 foreach ($mailboxes as $mailbox) {
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200916 if ($details = mailbox('get', 'mailbox_details', $mailbox, $object)) {
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100917 $data[] = $details;
918 }
919 else {
920 continue;
921 }
922 }
923 }
924 }
925 process_get_return($data);
926 }
927 else {
928 echo '{}';
929 }
930 break;
931
932 default:
933 $data = mailbox('get', 'mailbox_details', $object);
934 process_get_return($data);
935 break;
936 }
937 break;
938 case "syncjobs":
939 switch ($object) {
940 case "all":
941 $domains = mailbox('get', 'domains');
942 if (!empty($domains)) {
943 foreach ($domains as $domain) {
944 $mailboxes = mailbox('get', 'mailboxes', $domain);
945 if (!empty($mailboxes)) {
946 foreach ($mailboxes as $mailbox) {
947 $syncjobs = mailbox('get', 'syncjobs', $mailbox);
948 if (!empty($syncjobs)) {
949 foreach ($syncjobs as $syncjob) {
950 if (isset($extra)) {
951 $details = mailbox('get', 'syncjob_details', $syncjob, explode(',', $extra));
952 }
953 else {
954 $details = mailbox('get', 'syncjob_details', $syncjob);
955 }
956 if ($details) {
957 $data[] = $details;
958 }
959 else {
960 continue;
961 }
962 }
963 }
964 }
965 }
966 }
967 process_get_return($data);
968 }
969 else {
970 echo '{}';
971 }
972 break;
973
974 default:
975 $syncjobs = mailbox('get', 'syncjobs', $object);
976 if (!empty($syncjobs)) {
977 foreach ($syncjobs as $syncjob) {
978 if (isset($extra)) {
979 $details = mailbox('get', 'syncjob_details', $syncjob, explode(',', $extra));
980 }
981 else {
982 $details = mailbox('get', 'syncjob_details', $syncjob);
983 }
984 if ($details) {
985 $data[] = $details;
986 }
987 else {
988 continue;
989 }
990 }
991 }
992 process_get_return($data);
993 break;
994 }
995 break;
996 case "active-user-sieve":
997 if (isset($object)) {
998 $sieve_filter = mailbox('get', 'active_user_sieve', $object);
999 if (!empty($sieve_filter)) {
1000 $data[] = $sieve_filter;
1001 }
1002 }
1003 process_get_return($data);
1004 break;
1005 case "filters":
1006 switch ($object) {
1007 case "all":
1008 $domains = mailbox('get', 'domains');
1009 if (!empty($domains)) {
1010 foreach ($domains as $domain) {
1011 $mailboxes = mailbox('get', 'mailboxes', $domain);
1012 if (!empty($mailboxes)) {
1013 foreach ($mailboxes as $mailbox) {
1014 $filters = mailbox('get', 'filters', $mailbox);
1015 if (!empty($filters)) {
1016 foreach ($filters as $filter) {
1017 if ($details = mailbox('get', 'filter_details', $filter)) {
1018 $data[] = $details;
1019 }
1020 else {
1021 continue;
1022 }
1023 }
1024 }
1025 }
1026 }
1027 }
1028 process_get_return($data);
1029 }
1030 else {
1031 echo '{}';
1032 }
1033 break;
1034
1035 default:
1036 $filters = mailbox('get', 'filters', $object);
1037 if (!empty($filters)) {
1038 foreach ($filters as $filter) {
1039 if ($details = mailbox('get', 'filter_details', $filter)) {
1040 $data[] = $details;
1041 }
1042 else {
1043 continue;
1044 }
1045 }
1046 }
1047 process_get_return($data);
1048 break;
1049 }
1050 break;
1051 case "bcc":
1052 switch ($object) {
1053 case "all":
1054 $bcc_items = bcc('get');
1055 if (!empty($bcc_items)) {
1056 foreach ($bcc_items as $bcc_item) {
1057 if ($details = bcc('details', $bcc_item)) {
1058 $data[] = $details;
1059 }
1060 else {
1061 continue;
1062 }
1063 }
1064 }
1065 process_get_return($data);
1066 break;
1067 default:
1068 $data = bcc('details', $object);
1069 if (!empty($data)) {
1070 $data[] = $details;
1071 }
1072 process_get_return($data);
1073 break;
1074 }
1075 break;
1076 case "recipient_map":
1077 switch ($object) {
1078 case "all":
1079 $recipient_map_items = recipient_map('get');
1080 if (!empty($recipient_map_items)) {
1081 foreach ($recipient_map_items as $recipient_map_item) {
1082 if ($details = recipient_map('details', $recipient_map_item)) {
1083 $data[] = $details;
1084 }
1085 else {
1086 continue;
1087 }
1088 }
1089 }
1090 process_get_return($data);
1091 break;
1092 default:
1093 $data = recipient_map('details', $object);
1094 if (!empty($data)) {
1095 $data[] = $details;
1096 }
1097 process_get_return($data);
1098 break;
1099 }
1100 break;
1101 case "tls-policy-map":
1102 switch ($object) {
1103 case "all":
1104 $tls_policy_maps_items = tls_policy_maps('get');
1105 if (!empty($tls_policy_maps_items)) {
1106 foreach ($tls_policy_maps_items as $tls_policy_maps_item) {
1107 if ($details = tls_policy_maps('details', $tls_policy_maps_item)) {
1108 $data[] = $details;
1109 }
1110 else {
1111 continue;
1112 }
1113 }
1114 }
1115 process_get_return($data);
1116 break;
1117 default:
1118 $data = tls_policy_maps('details', $object);
1119 if (!empty($data)) {
1120 $data[] = $details;
1121 }
1122 process_get_return($data);
1123 break;
1124 }
1125 break;
1126 case "policy_wl_mailbox":
1127 switch ($object) {
1128 default:
1129 $data = policy('get', 'mailbox', $object)['whitelist'];
1130 process_get_return($data);
1131 break;
1132 }
1133 break;
1134 case "policy_bl_mailbox":
1135 switch ($object) {
1136 default:
1137 $data = policy('get', 'mailbox', $object)['blacklist'];
1138 process_get_return($data);
1139 break;
1140 }
1141 break;
1142 case "policy_wl_domain":
1143 switch ($object) {
1144 default:
1145 $data = policy('get', 'domain', $object)['whitelist'];
1146 process_get_return($data);
1147 break;
1148 }
1149 break;
1150 case "policy_bl_domain":
1151 switch ($object) {
1152 default:
1153 $data = policy('get', 'domain', $object)['blacklist'];
1154 process_get_return($data);
1155 break;
1156 }
1157 break;
1158 case "time_limited_aliases":
1159 switch ($object) {
1160 default:
1161 $data = mailbox('get', 'time_limited_aliases', $object);
1162 process_get_return($data);
1163 break;
1164 }
1165 break;
1166 case "fail2ban":
1167 switch ($object) {
1168 default:
1169 $data = fail2ban('get');
1170 process_get_return($data);
1171 break;
1172 }
1173 break;
1174 case "resource":
1175 switch ($object) {
1176 case "all":
1177 $domains = mailbox('get', 'domains');
1178 if (!empty($domains)) {
1179 foreach ($domains as $domain) {
1180 $resources = mailbox('get', 'resources', $domain);
1181 if (!empty($resources)) {
1182 foreach ($resources as $resource) {
1183 if ($details = mailbox('get', 'resource_details', $resource)) {
1184 $data[] = $details;
1185 }
1186 else {
1187 continue;
1188 }
1189 }
1190 }
1191 }
1192 process_get_return($data);
1193 }
1194 else {
1195 echo '{}';
1196 }
1197 break;
1198 default:
1199 $data = mailbox('get', 'resource_details', $object);
1200 process_get_return($data);
1201 break;
1202 }
1203 break;
1204 case "fwdhost":
1205 switch ($object) {
1206 case "all":
1207 process_get_return(fwdhost('get'));
1208 break;
1209 default:
1210 process_get_return(fwdhost('details', $object));
1211 break;
1212 }
1213 break;
1214 case "quarantine":
1215 // "all" will not print details
1216 switch ($object) {
1217 case "all":
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001218 process_get_return(quarantine('get'), false);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001219 break;
1220 default:
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001221 process_get_return(quarantine('details', $object), false);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001222 break;
1223 }
1224 break;
1225 case "alias-domain":
1226 switch ($object) {
1227 case "all":
1228 $alias_domains = mailbox('get', 'alias_domains');
1229 if (!empty($alias_domains)) {
1230 foreach ($alias_domains as $alias_domain) {
1231 if ($details = mailbox('get', 'alias_domain_details', $alias_domain)) {
1232 $data[] = $details;
1233 }
1234 else {
1235 continue;
1236 }
1237 }
1238 }
1239 process_get_return($data);
1240 break;
1241 default:
1242 process_get_return(mailbox('get', 'alias_domain_details', $object));
1243 break;
1244 }
1245 break;
1246 case "alias":
1247 switch ($object) {
1248 case "all":
1249 if (empty($extra)) {
1250 $domains = array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains'));
1251 }
1252 else {
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001253 $domains = explode(',', $extra);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001254 }
1255 if (!empty($domains)) {
1256 foreach ($domains as $domain) {
1257 $aliases = mailbox('get', 'aliases', $domain);
1258 if (!empty($aliases)) {
1259 foreach ($aliases as $alias) {
1260 if ($details = mailbox('get', 'alias_details', $alias)) {
1261 $data[] = $details;
1262 }
1263 else {
1264 continue;
1265 }
1266 }
1267 }
1268 }
1269 process_get_return($data);
1270 }
1271 else {
1272 echo '{}';
1273 }
1274 break;
1275
1276 default:
1277 process_get_return(mailbox('get', 'alias_details', $object));
1278 break;
1279 }
1280 break;
1281 case "domain-admin":
1282 switch ($object) {
1283 case "all":
1284 $domain_admins = domain_admin('get');
1285 if (!empty($domain_admins)) {
1286 foreach ($domain_admins as $domain_admin) {
1287 if ($details = domain_admin('details', $domain_admin)) {
1288 $data[] = $details;
1289 }
1290 else {
1291 continue;
1292 }
1293 }
1294 process_get_return($data);
1295 }
1296 else {
1297 echo '{}';
1298 }
1299 break;
1300
1301 default:
1302 process_get_return(domain_admin('details', $object));
1303 break;
1304 }
1305 break;
1306 case "admin":
1307 switch ($object) {
1308 case "all":
1309 $admins = admin('get');
1310 if (!empty($admins)) {
1311 foreach ($admins as $admin) {
1312 if ($details = admin('details', $admin)) {
1313 $data[] = $details;
1314 }
1315 else {
1316 continue;
1317 }
1318 }
1319 process_get_return($data);
1320 }
1321 else {
1322 echo '{}';
1323 }
1324 break;
1325
1326 default:
1327 process_get_return(admin('details', $object));
1328 break;
1329 }
1330 break;
1331 case "dkim":
1332 switch ($object) {
1333 default:
1334 $data = dkim('details', $object);
1335 process_get_return($data);
1336 break;
1337 }
1338 break;
1339 case "presets":
1340 switch ($object) {
1341 case "rspamd":
1342 process_get_return(presets('get', 'rspamd'));
1343 break;
1344 case "sieve":
1345 process_get_return(presets('get', 'sieve'));
1346 break;
1347 }
1348 break;
1349 case "status":
1350 if ($_SESSION['mailcow_cc_role'] == "admin") {
1351 switch ($object) {
1352 case "containers":
1353 $containers = (docker('info'));
1354 foreach ($containers as $container => $container_info) {
1355 $container . ' (' . $container_info['Config']['Image'] . ')';
1356 $containerstarttime = ($container_info['State']['StartedAt']);
1357 $containerstate = ($container_info['State']['Status']);
1358 $containerimage = ($container_info['Config']['Image']);
1359 $temp[$container] = array(
1360 'type' => 'info',
1361 'container' => $container,
1362 'state' => $containerstate,
1363 'started_at' => $containerstarttime,
1364 'image' => $containerimage
1365 );
1366 }
1367 echo json_encode($temp, JSON_UNESCAPED_SLASHES);
1368 break;
1369 case "vmail":
1370 $exec_fields_vmail = array('cmd' => 'system', 'task' => 'df', 'dir' => '/var/vmail');
1371 $vmail_df = explode(',', json_decode(docker('post', 'dovecot-mailcow', 'exec', $exec_fields_vmail), true));
1372 $temp = array(
1373 'type' => 'info',
1374 'disk' => $vmail_df[0],
1375 'used' => $vmail_df[2],
1376 'total'=> $vmail_df[1],
1377 'used_percent' => $vmail_df[4]
1378 );
1379 echo json_encode($temp, JSON_UNESCAPED_SLASHES);
1380 break;
1381 case "solr":
1382 $solr_status = solr_status();
1383 $solr_size = ($solr_status['status']['dovecot-fts']['index']['size']);
1384 $solr_documents = ($solr_status['status']['dovecot-fts']['index']['numDocs']);
1385 if (strtolower(getenv('SKIP_SOLR')) != 'n') {
1386 $solr_enabled = false;
1387 }
1388 else {
1389 $solr_enabled = true;
1390 }
1391 echo json_encode(array(
1392 'type' => 'info',
1393 'solr_enabled' => $solr_enabled,
1394 'solr_size' => $solr_size,
1395 'solr_documents' => $solr_documents
1396 ));
1397 break;
1398 }
1399 }
1400 break;
1401 break;
1402 // return no route found if no case is matched
1403 default:
1404 http_response_code(404);
1405 echo json_encode(array(
1406 'type' => 'error',
1407 'msg' => 'route not found'
1408 ));
1409 exit();
1410 }
1411 }
1412 break;
1413 case "delete":
1414 if ($_SESSION['mailcow_cc_api_access'] == 'ro' || isset($_SESSION['pending_mailcow_cc_username']) || !isset($_SESSION["mailcow_cc_username"])) {
1415 http_response_code(403);
1416 echo json_encode(array(
1417 'type' => 'error',
1418 'msg' => 'API read/write access denied'
1419 ));
1420 exit();
1421 }
1422 function process_delete_return($return) {
1423 $generic_failure = json_encode(array(
1424 'type' => 'error',
1425 'msg' => 'Cannot delete item'
1426 ));
1427 $generic_success = json_encode(array(
1428 'type' => 'success',
1429 'msg' => 'Task completed'
1430 ));
1431 if ($return === false) {
1432 echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_failure;
1433 }
1434 else {
1435 echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_success;
1436 }
1437 }
1438 if (!isset($_POST['items'])) {
1439 echo $request_incomplete;
1440 exit;
1441 }
1442 else {
1443 $items = (array)json_decode($_POST['items'], true);
1444 }
1445 // only allow POST requests to POST API endpoints
1446 if ($_SERVER['REQUEST_METHOD'] != 'POST') {
1447 http_response_code(405);
1448 echo json_encode(array(
1449 'type' => 'error',
1450 'msg' => 'only POST method is allowed'
1451 ));
1452 exit();
1453 }
1454 switch ($category) {
1455 case "alias":
1456 process_delete_return(mailbox('delete', 'alias', array('id' => $items)));
1457 break;
1458 case "oauth2-client":
1459 process_delete_return(oauth2('delete', 'client', array('id' => $items)));
1460 break;
1461 case "app-passwd":
1462 process_delete_return(app_passwd('delete', array('id' => $items)));
1463 break;
1464 case "relayhost":
1465 process_delete_return(relayhost('delete', array('id' => $items)));
1466 break;
1467 case "transport":
1468 process_delete_return(transport('delete', array('id' => $items)));
1469 break;
1470 case "rsetting":
1471 process_delete_return(rsettings('delete', array('id' => $items)));
1472 break;
1473 case "syncjob":
1474 process_delete_return(mailbox('delete', 'syncjob', array('id' => $items)));
1475 break;
1476 case "filter":
1477 process_delete_return(mailbox('delete', 'filter', array('id' => $items)));
1478 break;
1479 case "mailq":
1480 process_delete_return(mailq('delete', array('qid' => $items)));
1481 break;
1482 case "qitem":
1483 process_delete_return(quarantine('delete', array('id' => $items)));
1484 break;
1485 case "bcc":
1486 process_delete_return(bcc('delete', array('id' => $items)));
1487 break;
1488 case "recipient_map":
1489 process_delete_return(recipient_map('delete', array('id' => $items)));
1490 break;
1491 case "tls-policy-map":
1492 process_delete_return(tls_policy_maps('delete', array('id' => $items)));
1493 break;
1494 case "fwdhost":
1495 process_delete_return(fwdhost('delete', array('forwardinghost' => $items)));
1496 break;
1497 case "dkim":
1498 process_delete_return(dkim('delete', array('domains' => $items)));
1499 break;
1500 case "domain":
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001501 process_delete_return(mailbox('delete', 'domain', array('domain' => $items)));
1502 break;
1503 case "alias-domain":
1504 process_delete_return(mailbox('delete', 'alias_domain', array('alias_domain' => $items)));
1505 break;
1506 case "mailbox":
1507 process_delete_return(mailbox('delete', 'mailbox', array('username' => $items)));
1508 break;
1509 case "resource":
1510 process_delete_return(mailbox('delete', 'resource', array('name' => $items)));
1511 break;
1512 case "mailbox-policy":
1513 process_delete_return(policy('delete', 'mailbox', array('prefid' => $items)));
1514 break;
1515 case "domain-policy":
1516 process_delete_return(policy('delete', 'domain', array('prefid' => $items)));
1517 break;
1518 case "time_limited_alias":
1519 process_delete_return(mailbox('delete', 'time_limited_alias', array('address' => $items)));
1520 break;
1521 case "eas_cache":
1522 process_delete_return(mailbox('delete', 'eas_cache', array('username' => $items)));
1523 break;
1524 case "sogo_profile":
1525 process_delete_return(mailbox('delete', 'sogo_profile', array('username' => $items)));
1526 break;
1527 case "domain-admin":
1528 process_delete_return(domain_admin('delete', array('username' => $items)));
1529 break;
1530 case "admin":
1531 process_delete_return(admin('delete', array('username' => $items)));
1532 break;
1533 case "rlhash":
1534 echo ratelimit('delete', null, implode($items));
1535 break;
1536 // return no route found if no case is matched
1537 default:
1538 http_response_code(404);
1539 echo json_encode(array(
1540 'type' => 'error',
1541 'msg' => 'route not found'
1542 ));
1543 exit();
1544 }
1545 break;
1546 case "edit":
1547 if ($_SESSION['mailcow_cc_api_access'] == 'ro' || isset($_SESSION['pending_mailcow_cc_username']) || !isset($_SESSION["mailcow_cc_username"])) {
1548 http_response_code(403);
1549 echo json_encode(array(
1550 'type' => 'error',
1551 'msg' => 'API read/write access denied'
1552 ));
1553 exit();
1554 }
1555 function process_edit_return($return) {
1556 $generic_failure = json_encode(array(
1557 'type' => 'error',
1558 'msg' => 'Cannot edit item'
1559 ));
1560 $generic_success = json_encode(array(
1561 'type' => 'success',
1562 'msg' => 'Task completed'
1563 ));
1564 if ($return === false) {
1565 echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_failure;
1566 }
1567 else {
1568 echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_success;
1569 }
1570 }
1571 if (!isset($_POST['attr'])) {
1572 echo $request_incomplete;
1573 exit;
1574 }
1575 else {
1576 $attr = (array)json_decode($_POST['attr'], true);
1577 unset($attr['csrf_token']);
1578 $items = isset($_POST['items']) ? (array)json_decode($_POST['items'], true) : null;
1579 }
1580 // only allow POST requests to POST API endpoints
1581 if ($_SERVER['REQUEST_METHOD'] != 'POST') {
1582 http_response_code(405);
1583 echo json_encode(array(
1584 'type' => 'error',
1585 'msg' => 'only POST method is allowed'
1586 ));
1587 exit();
1588 }
1589 switch ($category) {
1590 case "bcc":
1591 process_edit_return(bcc('edit', array_merge(array('id' => $items), $attr)));
1592 break;
1593 case "pushover":
1594 process_edit_return(pushover('edit', array_merge(array('username' => $items), $attr)));
1595 break;
1596 case "pushover-test":
1597 process_edit_return(pushover('test', array_merge(array('username' => $items), $attr)));
1598 break;
1599 case "oauth2-client":
1600 process_edit_return(oauth2('edit', 'client', array_merge(array('id' => $items), $attr)));
1601 break;
1602 case "recipient_map":
1603 process_edit_return(recipient_map('edit', array_merge(array('id' => $items), $attr)));
1604 break;
1605 case "app-passwd":
1606 process_edit_return(app_passwd('edit', array_merge(array('id' => $items), $attr)));
1607 break;
1608 case "tls-policy-map":
1609 process_edit_return(tls_policy_maps('edit', array_merge(array('id' => $items), $attr)));
1610 break;
1611 case "alias":
1612 process_edit_return(mailbox('edit', 'alias', array_merge(array('id' => $items), $attr)));
1613 break;
1614 case "rspamd-map":
1615 process_edit_return(rspamd_maps('edit', array_merge(array('map' => $items), $attr)));
1616 break;
1617 case "fido2-fn":
1618 process_edit_return(fido2(array('action' => 'edit_fn', 'fido2_attrs' => $attr)));
1619 break;
1620 case "app_links":
1621 process_edit_return(customize('edit', 'app_links', $attr));
1622 break;
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001623 case "passwordpolicy":
1624 process_edit_return(password_complexity('edit', $attr));
1625 break;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001626 case "relayhost":
1627 process_edit_return(relayhost('edit', array_merge(array('id' => $items), $attr)));
1628 break;
1629 case "transport":
1630 process_edit_return(transport('edit', array_merge(array('id' => $items), $attr)));
1631 break;
1632 case "rsetting":
1633 process_edit_return(rsettings('edit', array_merge(array('id' => $items), $attr)));
1634 break;
1635 case "delimiter_action":
1636 process_edit_return(mailbox('edit', 'delimiter_action', array_merge(array('username' => $items), $attr)));
1637 break;
1638 case "tls_policy":
1639 process_edit_return(mailbox('edit', 'tls_policy', array_merge(array('username' => $items), $attr)));
1640 break;
1641 case "quarantine_notification":
1642 process_edit_return(mailbox('edit', 'quarantine_notification', array_merge(array('username' => $items), $attr)));
1643 break;
1644 case "quarantine_category":
1645 process_edit_return(mailbox('edit', 'quarantine_category', array_merge(array('username' => $items), $attr)));
1646 break;
1647 case "qitem":
1648 process_edit_return(quarantine('edit', array_merge(array('id' => $items), $attr)));
1649 break;
1650 case "quarantine":
1651 process_edit_return(quarantine('edit', $attr));
1652 break;
1653 case "quota_notification":
1654 process_edit_return(quota_notification('edit', $attr));
1655 break;
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001656 case "quota_notification_bcc":
1657 process_edit_return(quota_notification_bcc('edit', $attr));
1658 break;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001659 case "mailq":
1660 process_edit_return(mailq('edit', array_merge(array('qid' => $items), $attr)));
1661 break;
1662 case "time_limited_alias":
1663 process_edit_return(mailbox('edit', 'time_limited_alias', array_merge(array('address' => $items), $attr)));
1664 break;
1665 case "mailbox":
1666 process_edit_return(mailbox('edit', 'mailbox', array_merge(array('username' => $items), $attr)));
1667 break;
1668 case "syncjob":
1669 process_edit_return(mailbox('edit', 'syncjob', array_merge(array('id' => $items), $attr)));
1670 break;
1671 case "filter":
1672 process_edit_return(mailbox('edit', 'filter', array_merge(array('id' => $items), $attr)));
1673 break;
1674 case "resource":
1675 process_edit_return(mailbox('edit', 'resource', array_merge(array('name' => $items), $attr)));
1676 break;
1677 case "domain":
1678 process_edit_return(mailbox('edit', 'domain', array_merge(array('domain' => $items), $attr)));
1679 break;
1680 case "rl-domain":
1681 process_edit_return(ratelimit('edit', 'domain', array_merge(array('object' => $items), $attr)));
1682 break;
1683 case "rl-mbox":
1684 process_edit_return(ratelimit('edit', 'mailbox', array_merge(array('object' => $items), $attr)));
1685 break;
1686 case "user-acl":
1687 process_edit_return(acl('edit', 'user', array_merge(array('username' => $items), $attr)));
1688 break;
1689 case "da-acl":
1690 process_edit_return(acl('edit', 'domainadmin', array_merge(array('username' => $items), $attr)));
1691 break;
1692 case "alias-domain":
1693 process_edit_return(mailbox('edit', 'alias_domain', array_merge(array('alias_domain' => $items), $attr)));
1694 break;
1695 case "spam-score":
1696 process_edit_return(mailbox('edit', 'spam_score', array_merge(array('username' => $items), $attr)));
1697 break;
1698 case "domain-admin":
1699 process_edit_return(domain_admin('edit', array_merge(array('username' => $items), $attr)));
1700 break;
1701 case "admin":
1702 process_edit_return(admin('edit', array_merge(array('username' => $items), $attr)));
1703 break;
1704 case "fwdhost":
1705 process_edit_return(fwdhost('edit', array_merge(array('fwdhost' => $items), $attr)));
1706 break;
1707 case "fail2ban":
1708 process_edit_return(fail2ban('edit', array_merge(array('network' => $items), $attr)));
1709 break;
1710 case "ui_texts":
1711 process_edit_return(customize('edit', 'ui_texts', $attr));
1712 break;
1713 case "self":
1714 if ($_SESSION['mailcow_cc_role'] == "domainadmin") {
1715 process_edit_return(domain_admin('edit', $attr));
1716 }
1717 elseif ($_SESSION['mailcow_cc_role'] == "user") {
1718 process_edit_return(edit_user_account($attr));
1719 }
1720 break;
1721 // return no route found if no case is matched
1722 default:
1723 http_response_code(404);
1724 echo json_encode(array(
1725 'type' => 'error',
1726 'msg' => 'route not found'
1727 ));
1728 exit();
1729 }
1730 break;
1731 // return no route found if no case is matched
1732 default:
1733 http_response_code(404);
1734 echo json_encode(array(
1735 'type' => 'error',
1736 'msg' => 'route not found'
1737 ));
1738 exit();
1739 }
1740}
1741if ($_SESSION['mailcow_cc_api'] === true) {
1742 if (isset($_SESSION['mailcow_cc_api']) && $_SESSION['mailcow_cc_api'] === true) {
1743 unset($_SESSION['return']);
1744 }
1745}