mc-cms-namelessmc/modules/Core/includes/endpoints/CreateWebhooksEndpoint.php
Sam 6009c81aff
fix: validate webhook urls via create webhooks endpoint (#3736)
Co-authored-by: Sam <samerton@users.noreply.github.com>
2026-06-27 13:09:43 +01:00

100 lines
3.2 KiB
PHP

<?php
/**
* @param string $name The name of the webhook
* @param string $url The url of the webhook
* @param string $type The webhook type
* @param array $events A list of events the webhook should receive
*
* @return string JSON Array
*/
class CreateWebhooksEndpoint extends KeyAuthEndpoint {
public function __construct() {
$this->_route = 'webhooks/create';
$this->_module = 'Core';
$this->_description = 'Create a new webhook';
$this->_method = 'POST';
}
public function execute(Nameless2API $api): void {
// Validation
$validation = Validate::check($_POST, [
'name' => [
Validate::REQUIRED => true,
Validate::MIN => 3,
Validate::MAX => 128
],
'url' => [
Validate::REQUIRED => true,
Validate::MIN => 10,
Validate::MAX => 2048
],
'type' => [
Validate::REQUIRED => true,
]
])->messages([
'name' => CoreApiErrors::ERROR_WEBHOOK_NAME_INCORRECT_LENGTH,
'url' => CoreApiErrors::ERROR_WEBHOOK_URL_INCORRECT_LENGTH
]);
// If it didn't pass, throw the errors
if (!$validation->passed()) {
$api->throwError($validation->errors()[0]);
}
// Insert into database
$name = $_POST['name'];
$url = $_POST['url'];
$type = $_POST['type'];
// Validate URL to prevent SSRF
if (!filter_var($url, FILTER_VALIDATE_URL)) {
$api->throwError(CoreApiErrors::ERROR_WEBHOOK_INVALID_URL);
}
$scheme = parse_url($url, PHP_URL_SCHEME);
if (!in_array($scheme, ['http', 'https'], true)) {
$api->throwError(CoreApiErrors::ERROR_WEBHOOK_INVALID_URL);
}
$host = parse_url($url, PHP_URL_HOST);
$ip = filter_var($host, FILTER_VALIDATE_IP) ? $host : gethostbyname($host);
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false) {
$api->throwError(CoreApiErrors::ERROR_WEBHOOK_INVALID_URL);
}
$events = $_POST['events'];
if (!in_array($type, ['1', '2'])) {
$api->throwError(CoreApiErrors::ERROR_WEBHOOK_INVALID_TYPE);
}
if (!array_reduce($events, static function ($prev, $curr) {
if (!array_key_exists($curr, EventHandler::getEvents())) {
$prev = false;
}
return $prev;
}, true)) {
$api->throwError(CoreApiErrors::ERROR_WEBHOOK_INVALID_EVENT);
}
DB::getInstance()->insert('hooks', [
'name' => $name,
'action' => $type,
'url' => $url,
'events' => json_encode($events)
]);
// Clear cache so the webhooks are refreshed
$cache = new Cache(['name' => 'nameless', 'extension' => '.cache', 'path' => ROOT_PATH . '/cache/']);
$cache->setCache('hooks');
if ($cache->isCached('hooks')) {
$cache->erase('hooks');
}
// Return status message
$api->returnArray(['message' => $api->getLanguage()->get('api', 'webhook_added')]);
}
}