ApiController.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. <?php
  2. namespace Opentalent\OtAdmin\Http;
  3. use Opentalent\OtAdmin\Controller\ScanController;
  4. use Opentalent\OtAdmin\Controller\SiteController;
  5. use Psr\Log\LoggerAwareInterface;
  6. use Psr\Log\LoggerAwareTrait;
  7. use TYPO3\CMS\Core\Http\JsonResponse;
  8. use TYPO3\CMS\Core\Http\ServerRequest;
  9. use TYPO3\CMS\Core\Utility\GeneralUtility;
  10. use TYPO3\CMS\Extbase\Object\ObjectManager;
  11. /**
  12. * Actions for Http API calls
  13. *
  14. * @package Opentalent\OtAdmin\Http
  15. */
  16. class ApiController implements LoggerAwareInterface
  17. {
  18. use LoggerAwareTrait;
  19. const ALLOWED_IPS = [
  20. '/^127\.0\.0\.[0-1]$/', // Localhost
  21. '/^localhost$/', // Localhost
  22. '/^10\.8\.0\.\d{1,3}$/', // 10.8.0.[0-255] - VPN
  23. '/^141\.94\.117\.((3[3-9])|(4\d)|(5\d)|(6[0-1]))$/', // 141.94.117.[33-61] - Opentalent hosts public ips
  24. '/^172\.16\.0.\d{1,3}$/', // 172.16.0.[0-255] - Opentalent hosts private ips
  25. '/^172\.20\.\d{1,3}\.\d{1,3}$/', // 172.20.[0-255].[0-255] - Docker
  26. ];
  27. /**
  28. * Returns true if the client Ip is allowed
  29. *
  30. * @param string $clientIp
  31. * @return bool
  32. */
  33. public static function isIpAllowed(string $clientIp): bool
  34. {
  35. foreach (self::ALLOWED_IPS as $ipRule) {
  36. if (preg_match($ipRule, $clientIp)) {
  37. return true;
  38. }
  39. }
  40. return false;
  41. }
  42. /**
  43. * Check that the client Ip is allowed, else throw a Runtime error
  44. *
  45. * @return bool
  46. */
  47. private function assertIpAllowed(): bool
  48. {
  49. $clientIp = $_SERVER['REMOTE_ADDR'];
  50. if (!self::isIpAllowed($clientIp)){
  51. $route = $_REQUEST['route'];
  52. $this->logger->error(sprintf(
  53. "OtAdmin API: an attempt was made to call the route " .
  54. $route . " from an non-allowed IP (" . $clientIp . ")"));
  55. throw new \RuntimeException("Not allowed");
  56. }
  57. return true;
  58. }
  59. /**
  60. * Retrieve the organization's id from the given request parameters
  61. *
  62. * @param ServerRequest $request
  63. * @return int
  64. */
  65. private function getOrganizationId(ServerRequest $request): int
  66. {
  67. $params = $request->getQueryParams();
  68. $organizationId = $params['organization-id'];
  69. if (!$organizationId) {
  70. throw new \RuntimeException("Missing parameter: 'organization-id'");
  71. }
  72. return (int)$organizationId;
  73. }
  74. /**
  75. * -- Target of the route 'site_infos' --
  76. *
  77. * Return the main informations about the organization's website
  78. *
  79. * @param ServerRequest $request
  80. * @return JsonResponse
  81. * @throws \Exception
  82. */
  83. public function getSiteInfosAction(ServerRequest $request): JsonResponse
  84. {
  85. $this->assertIpAllowed();
  86. $organizationId = $this->getOrganizationId($request);
  87. $controller = GeneralUtility::makeInstance(ObjectManager::class)->get(SiteController::class);
  88. $infos = $controller->getSiteInfosAction($organizationId);
  89. return new JsonResponse($infos);
  90. }
  91. /**
  92. * -- Target of the route 'site_create' --
  93. * >> Requires a query param named 'organization-id' (int)
  94. *
  95. * Create the organization's website
  96. *
  97. * @param ServerRequest $request
  98. * @return JsonResponse
  99. * @throws \Exception
  100. */
  101. public function createSiteAction(ServerRequest $request): JsonResponse
  102. {
  103. $this->assertIpAllowed();
  104. $organizationId = $this->getOrganizationId($request);
  105. $controller = GeneralUtility::makeInstance(ObjectManager::class)->get(SiteController::class);
  106. $rootUid = $controller->createSiteAction($organizationId);
  107. $this->logger->info(sprintf(
  108. "OtAdmin API: A new website has been created with root page uid=" . $rootUid .
  109. " for the organization " . $organizationId));
  110. return new JsonResponse(
  111. [
  112. 'organization_id' => $organizationId,
  113. 'msg' => "A new website has been created with root page uid=" . $rootUid,
  114. 'root_uid' => $rootUid
  115. ]
  116. );
  117. }
  118. /**
  119. * -- Target of the route 'site_update' --
  120. * >> Requires a query param named 'organization-id' (int)
  121. *
  122. * Update the settings of the organization's website
  123. *
  124. * @param ServerRequest $request
  125. * @return JsonResponse
  126. * @throws \Exception
  127. */
  128. public function updateSiteConstantsAction(ServerRequest $request): JsonResponse
  129. {
  130. $this->assertIpAllowed();
  131. $organizationId = $this->getOrganizationId($request);
  132. $deep = (isset($queryParams['deep']) && $queryParams['deep']);
  133. $controller = GeneralUtility::makeInstance(ObjectManager::class)->get(SiteController::class);
  134. $rootUid = $controller->updateSiteAction($organizationId, $deep);
  135. $this->logger->info(sprintf(
  136. "OtAdmin API: The website with root uid " . $rootUid . " has been updated " .
  137. " (organization: " . $organizationId . ")"));
  138. return new JsonResponse(
  139. [
  140. 'organization_id' => $organizationId,
  141. 'msg' => "The website with root uid " . $rootUid . " has been updated",
  142. 'root_uid' => $rootUid
  143. ]
  144. );
  145. }
  146. /**
  147. * -- Target of the route 'redirect_add' --
  148. * >> Requires query params named 'from-domain' (string) and 'to-domain' (string)
  149. *
  150. * Add or update a redirection from 'from-domain' to 'to-domain'
  151. *
  152. * @param ServerRequest $request
  153. * @return JsonResponse
  154. * @throws \Exception
  155. */
  156. public function addRedirectionAction(ServerRequest $request): JsonResponse
  157. {
  158. $this->assertIpAllowed();
  159. $fromDomain = (isset($queryParams['from-domain']) && $queryParams['from-domain']);
  160. $toDomain = (isset($queryParams['to-domain']) && $queryParams['to-domain']);
  161. $controller = GeneralUtility::makeInstance(ObjectManager::class)->get(SiteController::class);
  162. $res = $controller->addRedirection($fromDomain, $toDomain);
  163. if ($res === SiteController::REDIRECTION_UPDATED) {
  164. $msg = "An existing redirection has been updated ";
  165. } elseif ($res === SiteController::REDIRECTION_CREATED) {
  166. $msg = "A redirection has been added ";
  167. }
  168. $this->logger->info(sprintf(
  169. "OtAdmin API: " . $msg . " from " . $fromDomain . " to " . $toDomain
  170. ));
  171. return new JsonResponse(
  172. [
  173. 'msg' => $msg . " from " . $fromDomain . " to " . $toDomain,
  174. ]
  175. );
  176. }
  177. /**
  178. * -- Target of the route 'site_delete' --
  179. * >> Requires a query param named 'organization-id' (int)
  180. *
  181. * Proceeds to a soft-deletion of the organization's website
  182. *
  183. * @param ServerRequest $request
  184. * @return JsonResponse
  185. * @throws \Exception
  186. */
  187. public function deleteSiteAction(ServerRequest $request): JsonResponse
  188. {
  189. $this->assertIpAllowed();
  190. $organizationId = $this->getOrganizationId($request);
  191. $params = $request->getQueryParams();
  192. $controller = GeneralUtility::makeInstance(ObjectManager::class)->get(SiteController::class);
  193. $rootUid = $controller->deleteSiteAction($organizationId);
  194. $this->logger->info(sprintf(
  195. "OtAdmin API: The website with root uid " . $rootUid . " has been soft-deleted " .
  196. " (organization: " . $organizationId . ")"));
  197. return new JsonResponse(
  198. [
  199. 'organization_id' => $organizationId,
  200. 'msg' => "The website with root uid " . $rootUid . " has been soft-deleted. Use the /site/undelete route to restore it.",
  201. 'root_uid' => $rootUid
  202. ]
  203. );
  204. }
  205. /**
  206. * -- Target of the route 'site_undelete' --
  207. * >> Requires a query param named 'organization-id' (int)
  208. *
  209. * Restore a soft-deleted organization's website
  210. *
  211. * @param ServerRequest $request
  212. * @return JsonResponse
  213. * @throws \Exception
  214. */
  215. public function undeleteSiteAction(ServerRequest $request): JsonResponse
  216. {
  217. $this->assertIpAllowed();
  218. $organizationId = $this->getOrganizationId($request);
  219. $controller = GeneralUtility::makeInstance(ObjectManager::class)->get(SiteController::class);
  220. $rootUid = $controller->undeleteSiteAction($organizationId);
  221. $this->logger->info(sprintf(
  222. "OtAdmin API: The website with root uid " . $rootUid . " has been restored " .
  223. " (organization: " . $organizationId . ")"));
  224. return new JsonResponse(
  225. [
  226. 'organization_id' => $organizationId,
  227. 'msg' => "The website with root uid " . $rootUid . " has been restored",
  228. 'root_uid' => $rootUid
  229. ]
  230. );
  231. }
  232. /**
  233. * -- Target of the route 'site_clearcache' --
  234. * >> Requires a query param named 'organization-id' (int)
  235. *
  236. * Clear the cache of the organization's website
  237. *
  238. * @param ServerRequest $request
  239. * @return JsonResponse
  240. * @throws \Exception
  241. */
  242. public function clearSiteCacheAction(ServerRequest $request): JsonResponse
  243. {
  244. $this->assertIpAllowed();
  245. $organizationId = $this->getOrganizationId($request);
  246. $queryParams = $request->getQueryParams();
  247. $clearAll = (isset($queryParams['all']) && $queryParams['all']);;
  248. $controller = GeneralUtility::makeInstance(ObjectManager::class)->get(SiteController::class);
  249. $rootUid = $controller->clearSiteCacheAction($organizationId, $clearAll);
  250. return new JsonResponse(
  251. [
  252. 'organization_id' => $organizationId,
  253. 'msg' => "The cache has been cleared for the website with root uid " . $rootUid . "",
  254. 'root_uid' => $rootUid
  255. ]
  256. );
  257. }
  258. /**
  259. * -- Target of the route 'site_setdomain' --
  260. * >> Requires a query param named 'organization-id' (int)
  261. * and a parameter named 'domain' (string)
  262. *
  263. * Set a new domain for the organization website
  264. *
  265. * @param ServerRequest $request
  266. * @return JsonResponse
  267. * @throws \Exception
  268. */
  269. public function setSiteCustomDomainAction(ServerRequest $request): JsonResponse
  270. {
  271. $this->assertIpAllowed();
  272. $organizationId = $this->getOrganizationId($request);
  273. $queryParams = $request->getQueryParams();
  274. $domain = $queryParams['domain'];
  275. if (!$domain) {
  276. throw new \RuntimeException("Missing 'domain' parameter");
  277. }
  278. $redirect = (isset($queryParams['redirect']) && $queryParams['redirect']);
  279. $controller = GeneralUtility::makeInstance(ObjectManager::class)->get(SiteController::class);
  280. $rootUid = $controller->setSiteCustomDomainAction($organizationId, $domain, $redirect);
  281. return new JsonResponse(
  282. [
  283. 'organization_id' => $organizationId,
  284. 'msg' => "The cache has been cleared for the website with root uid " . $rootUid . "",
  285. 'root_uid' => $rootUid
  286. ]
  287. );
  288. }
  289. /**
  290. * -- Target of the route 'site_resetperms' --
  291. * >> Requires a query param named 'organization-id' (int)
  292. *
  293. * Reset the permissions of the website be users (admin, editors...)
  294. *
  295. * @param ServerRequest $request
  296. * @return JsonResponse
  297. * @throws \Exception
  298. */
  299. public function resetBeUserPermsAction(ServerRequest $request): JsonResponse
  300. {
  301. $this->assertIpAllowed();
  302. $organizationId = $this->getOrganizationId($request);
  303. $controller = GeneralUtility::makeInstance(ObjectManager::class)->get(SiteController::class);
  304. $rootUid = $controller->resetBeUserPermsAction($organizationId);
  305. return new JsonResponse(
  306. [
  307. 'organization_id' => $organizationId,
  308. 'msg' => "The website with root uid " . $rootUid . " had its be users permissions reset",
  309. 'root_uid' => $rootUid
  310. ]
  311. );
  312. }
  313. /**
  314. * -- Target of the route 'site_status' --
  315. * >> Requires a query param named 'organization-id' (int)
  316. *
  317. * Returns the current status of the website
  318. *
  319. * @param ServerRequest $request
  320. * @return JsonResponse
  321. * @throws \Exception
  322. */
  323. public function getSiteStatusAction(ServerRequest $request): JsonResponse
  324. {
  325. $this->assertIpAllowed();
  326. $organizationId = $this->getOrganizationId($request);
  327. $controller = GeneralUtility::makeInstance(ObjectManager::class)->get(SiteController::class);
  328. $queryParams = $request->getQueryParams();
  329. $full = (isset($queryParams['full']) && $queryParams['full']);
  330. $status = $controller->getSiteStatusAction($organizationId, $full);
  331. return new JsonResponse($status->toArray());
  332. }
  333. /**
  334. * -- Target of the route 'scan' --
  335. *
  336. * Scan the whole Typo3 database and return the results
  337. *
  338. * @param ServerRequest $request
  339. * @return JsonResponse
  340. * @throws \Exception
  341. */
  342. public function scanAllAction(ServerRequest $request): JsonResponse
  343. {
  344. $this->assertIpAllowed();
  345. $controller = GeneralUtility::makeInstance(ObjectManager::class)->get(ScanController::class);
  346. $queryParams = $request->getQueryParams();
  347. $full = (isset($queryParams['full']) && $queryParams['full']);
  348. $results = $controller->scanAllAction($full);
  349. return new JsonResponse($results);
  350. }
  351. }