Issues (3627)

bundles/ApiBundle/EventListener/ApiSubscriber.php (1 issue)

1
<?php
2
3
/*
4
 * @copyright   2014 Mautic Contributors. All rights reserved
5
 * @author      Mautic
6
 *
7
 * @link        http://mautic.org
8
 *
9
 * @license     GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
10
 */
11
12
namespace Mautic\ApiBundle\EventListener;
13
14
use Mautic\ApiBundle\Helper\RequestHelper;
15
use Mautic\CoreBundle\Helper\CoreParametersHelper;
16
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
17
use Symfony\Component\HttpFoundation\JsonResponse;
18
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
19
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
20
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
21
use Symfony\Component\HttpKernel\KernelEvents;
22
use Symfony\Component\Translation\TranslatorInterface;
23
24
class ApiSubscriber implements EventSubscriberInterface
25
{
26
    /**
27
     * @var CoreParametersHelper
28
     */
29
    private $coreParametersHelper;
30
31
    /**
32
     * @var TranslatorInterface
33
     */
34
    private $translator;
35
36
    public function __construct(
37
        CoreParametersHelper $coreParametersHelper,
38
        TranslatorInterface $translator
39
    ) {
40
        $this->coreParametersHelper = $coreParametersHelper;
41
        $this->translator           = $translator;
42
    }
43
44
    /**
45
     * {@inheritdoc}
46
     */
47
    public static function getSubscribedEvents()
48
    {
49
        return [
50
            KernelEvents::REQUEST  => ['onKernelRequest', 255],
51
            KernelEvents::RESPONSE => ['onKernelResponse', 0],
52
        ];
53
    }
54
55
    /**
56
     * Check for API requests and throw denied access if API is disabled.
57
     *
58
     * @throws AccessDeniedHttpException
59
     */
60
    public function onKernelRequest(GetResponseEvent $event)
61
    {
62
        if (!$event->isMasterRequest()) {
63
            return;
64
        }
65
66
        $request = $event->getRequest();
67
68
        // Ignore if not an API request
69
        if (!RequestHelper::isApiRequest($request)) {
70
            return;
71
        }
72
73
        // Prevent access to API if disabled
74
        $apiEnabled = $this->coreParametersHelper->get('api_enabled');
75
        if (!$apiEnabled) {
76
            $response   = new JsonResponse(
77
                [
78
                    'errors' => [
79
                        [
80
                            'message' => $this->translator->trans('mautic.api.error.api.disabled'),
81
                            'code'    => 403,
82
                            'type'    => 'api_disabled',
83
                        ],
84
                    ],
85
                ],
86
                403
87
            );
88
89
            $event->setResponse($response);
90
91
            return;
92
        }
93
94
        // Prevent access via basic auth if it is disabled
95
        $hasBasicAuth     = RequestHelper::hasBasicAuth($request);
96
        $basicAuthEnabled = $this->coreParametersHelper->get('api_enable_basic_auth');
97
98
        if ($hasBasicAuth && !$basicAuthEnabled) {
99
            $response   = new JsonResponse(
100
                [
101
                    'errors' => [
102
                        [
103
                            'message' => $this->translator->trans('mautic.api.error.basic.auth.disabled'),
104
                            'code'    => 403,
105
                            'type'    => 'access_denied',
106
                        ],
107
                    ],
108
                ],
109
                403
110
            );
111
112
            $event->setResponse($response);
113
        }
114
    }
115
116
    public function onKernelResponse(FilterResponseEvent $event)
117
    {
118
        $request      = $event->getRequest();
119
        $isApiRequest = RequestHelper::isApiRequest($request);
120
        $hasBasicAuth = RequestHelper::hasBasicAuth($event->getRequest());
121
122
        // Ignore if this is not an API request
123
        if (!$isApiRequest) {
124
            return;
125
        }
126
127
        // Ignore if this does not contain an error response
128
        $response = $event->getResponse();
129
        $content  = $response->getContent();
130
        if (false === strpos($content, 'error')) {
131
            return;
132
        }
133
134
        // Ignore if content is not json
135
        if (!$data = json_decode($content, true)) {
136
            return;
137
        }
138
139
        // Ignore if an error was not found in the JSON response
140
        if (!isset($data['error'])) {
141
            return;
142
        }
143
144
        // Override api messages with something useful
145
        $type  = null;
146
        $error = $data['error'];
147
        if (is_array($error)) {
148
            if (!isset($error['message'])) {
149
                return;
150
            }
151
152
            // Catch useless oauth1a errors
153
            $error = $error['message'];
154
        }
155
156
        switch ($error) {
157
            case 'access_denied':
158
                $type    = $error;
159
                $message = $this->translator->trans('mautic.api.auth.error.accessdenied');
160
161
                if ($hasBasicAuth) {
162
                    if ($this->coreParametersHelper->get('api_enable_basic_auth')) {
163
                        $message = $this->translator->trans('mautic.api.error.basic.auth.invalid.credentials');
164
                    } else {
165
                        $message = $this->translator->trans('mautic.api.error.basic.auth.disabled');
166
                    }
167
                }
168
169
                break;
170
            default:
171
                if (isset($data['error_description'])) {
172
                    $message = $data['error_description'];
173
                    $type    = $error;
174
                } elseif ($this->translator->hasId('mautic.api.auth.error.'.$error)) {
0 ignored issues
show
The method hasId() does not exist on Symfony\Component\Translation\TranslatorInterface. It seems like you code against a sub-type of Symfony\Component\Translation\TranslatorInterface such as Symfony\Component\Transl...DataCollectorTranslator or Symfony\Component\Translation\LoggingTranslator or Mautic\CoreBundle\Translation\Translator. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

174
                } elseif ($this->translator->/** @scrutinizer ignore-call */ hasId('mautic.api.auth.error.'.$error)) {
Loading history...
175
                    $message = $this->translator->trans('mautic.api.auth.error.'.$error);
176
                    $type    = $error;
177
                }
178
        }
179
180
        // Message was not overriden so leave as is
181
        if (!isset($message)) {
182
            return;
183
        }
184
185
        $statusCode = $response->getStatusCode();
186
        $response   = new JsonResponse(
187
            [
188
                'errors' => [
189
                    [
190
                        'message' => $message,
191
                        'code'    => $response->getStatusCode(),
192
                        'type'    => $type,
193
                    ],
194
                ],
195
            ],
196
            $statusCode
197
        );
198
199
        $event->setResponse($response);
200
    }
201
}
202