diff --git a/.env.example b/.env.example index ec2b4a8762..cca8d4531f 100644 --- a/.env.example +++ b/.env.example @@ -195,6 +195,16 @@ MAP_DEFAULT_LAT=51.983333 MAP_DEFAULT_LONG=5.916667 MAP_DEFAULT_ZOOM=6 +# +# Some objects have room for an URL, like transactions and webhooks. +# By default, the following protocols are allowed: +# http, https, ftp, ftps, mailto +# +# To change this, set your preferred comma separated set below. +# Be sure to include http, https and other default ones if you need to. +# +VALID_URL_PROTOCOLS= + # # Firefly III authentication settings # diff --git a/app/Api/V1/Requests/Models/Transaction/StoreRequest.php b/app/Api/V1/Requests/Models/Transaction/StoreRequest.php index 932d3061cf..3b26c259c3 100644 --- a/app/Api/V1/Requests/Models/Transaction/StoreRequest.php +++ b/app/Api/V1/Requests/Models/Transaction/StoreRequest.php @@ -174,7 +174,7 @@ class StoreRequest extends FormRequest public function rules(): array { Log::debug('Collect rules of TransactionStoreRequest'); - + $validProtocols = config('firefly.valid_url_protocols'); return [ // basic fields for group: 'group_title' => 'between:1,1000|nullable', @@ -233,7 +233,7 @@ class StoreRequest extends FormRequest 'transactions.*.external_id' => 'min:1|max:255|nullable', 'transactions.*.recurrence_id' => 'min:1|max:255|nullable', 'transactions.*.bunq_payment_id' => 'min:1|max:255|nullable', - 'transactions.*.external_url' => 'min:1|max:255|nullable|url', + 'transactions.*.external_url' => sprintf('min:1|max:255|nullable|url:%s', $validProtocols), // SEPA fields: 'transactions.*.sepa_cc' => 'min:1|max:255|nullable', diff --git a/app/Api/V1/Requests/Models/Transaction/UpdateRequest.php b/app/Api/V1/Requests/Models/Transaction/UpdateRequest.php index e3d9660b02..d8b19ab5d0 100644 --- a/app/Api/V1/Requests/Models/Transaction/UpdateRequest.php +++ b/app/Api/V1/Requests/Models/Transaction/UpdateRequest.php @@ -321,7 +321,7 @@ class UpdateRequest extends FormRequest public function rules(): array { Log::debug(sprintf('Now in %s', __METHOD__)); - + $validProtocols = config('firefly.valid_url_protocols'); return [ // basic fields for group: 'group_title' => 'between:1,1000|nullable', @@ -375,7 +375,7 @@ class UpdateRequest extends FormRequest 'transactions.*.external_id' => 'min:1|max:255|nullable', 'transactions.*.recurrence_id' => 'min:1|max:255|nullable', 'transactions.*.bunq_payment_id' => 'min:1|max:255|nullable', - 'transactions.*.external_url' => 'min:1|max:255|nullable|url', + 'transactions.*.external_url' => sprintf('min:1|max:255|nullable|url:%s', $validProtocols), // SEPA fields: 'transactions.*.sepa_cc' => 'min:1|max:255|nullable', diff --git a/app/Api/V1/Requests/Models/Webhook/CreateRequest.php b/app/Api/V1/Requests/Models/Webhook/CreateRequest.php index 24c4084bf0..85969756fe 100644 --- a/app/Api/V1/Requests/Models/Webhook/CreateRequest.php +++ b/app/Api/V1/Requests/Models/Webhook/CreateRequest.php @@ -74,14 +74,14 @@ class CreateRequest extends FormRequest $triggers = implode(',', array_keys(Webhook::getTriggersForValidation())); $responses = implode(',', array_keys(Webhook::getResponsesForValidation())); $deliveries = implode(',', array_keys(Webhook::getDeliveriesForValidation())); - + $validProtocols = config('firefly.valid_url_protocols'); return [ 'title' => 'required|between:1,512|uniqueObjectForUser:webhooks,title', 'active' => [new IsBoolean()], 'trigger' => sprintf('required|in:%s', $triggers), 'response' => sprintf('required|in:%s', $responses), 'delivery' => sprintf('required|in:%s', $deliveries), - 'url' => ['required', 'url', 'uniqueWebhook'], + 'url' => ['required', sprintf('url:%s', $validProtocols), 'uniqueWebhook'], ]; } } diff --git a/app/Api/V1/Requests/Models/Webhook/UpdateRequest.php b/app/Api/V1/Requests/Models/Webhook/UpdateRequest.php index 157c2f5716..b2b8187031 100644 --- a/app/Api/V1/Requests/Models/Webhook/UpdateRequest.php +++ b/app/Api/V1/Requests/Models/Webhook/UpdateRequest.php @@ -81,10 +81,10 @@ class UpdateRequest extends FormRequest */ public function rules(): array { - $triggers = implode(',', array_keys(Webhook::getTriggersForValidation())); - $responses = implode(',', array_keys(Webhook::getResponsesForValidation())); - $deliveries = implode(',', array_keys(Webhook::getDeliveriesForValidation())); - + $triggers = implode(',', array_keys(Webhook::getTriggersForValidation())); + $responses = implode(',', array_keys(Webhook::getResponsesForValidation())); + $deliveries = implode(',', array_keys(Webhook::getDeliveriesForValidation())); + $validProtocols = config('firefly.valid_url_protocols'); /** @var Webhook $webhook */ $webhook = $this->route()->parameter('webhook'); @@ -94,7 +94,7 @@ class UpdateRequest extends FormRequest 'trigger' => sprintf('in:%s', $triggers), 'response' => sprintf('in:%s', $responses), 'delivery' => sprintf('in:%s', $deliveries), - 'url' => ['url', sprintf('uniqueExistingWebhook:%d', $webhook->id)], + 'url' => [sprintf('url:%s', $validProtocols), sprintf('uniqueExistingWebhook:%d', $webhook->id)], ]; } } diff --git a/config/firefly.php b/config/firefly.php index c0f55e1dcf..9f4c726108 100644 --- a/config/firefly.php +++ b/config/firefly.php @@ -251,6 +251,7 @@ return [ 'available_dark_modes' => ['light', 'dark', 'browser'], 'bill_reminder_periods' => [90, 30, 14, 7, 0], 'valid_view_ranges' => ['1D', '1W', '1M', '3M', '6M', '1Y',], + 'valid_url_protocols' => envNonEmpty('VALID_URL_PROTOCOLS', 'http,https,ftp,ftps,mailto'), 'allowedMimes' => [ /* plain files */ 'text/plain',