Test Failed
Push — master ( 53c877...bfb78e )
by MusikAnimal
19:13 queued 31s
created

DefaultController::oauthCallbackAction()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 32
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 7.096

Importance

Changes 0
Metric Value
cc 3
eloc 15
nc 3
nop 2
dl 0
loc 32
ccs 3
cts 13
cp 0.2308
crap 7.096
rs 9.7666
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file contains only the DefaultController class.
4
 */
5
6
declare(strict_types=1);
7
8
namespace AppBundle\Controller;
9
10
use AppBundle\Model\Edit;
11
use AppBundle\Repository\ProjectRepository;
12
use MediaWiki\OAuthClient\Client;
13
use MediaWiki\OAuthClient\ClientConfig;
14
use MediaWiki\OAuthClient\Consumer;
15
use MediaWiki\OAuthClient\Exception;
16
use MediaWiki\OAuthClient\Token;
17
use Symfony\Component\HttpFoundation\JsonResponse;
18
use Symfony\Component\HttpFoundation\RedirectResponse;
19
use Symfony\Component\HttpFoundation\Request;
20
use Symfony\Component\HttpFoundation\Response;
21
use Symfony\Component\HttpFoundation\Session\Session;
22
use Symfony\Component\HttpFoundation\Session\SessionInterface;
23
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
24
use Symfony\Component\Routing\Annotation\Route;
25
26
/**
27
 * The DefaultController handles the homepage, about pages, and user authentication.
28
 */
29
class DefaultController extends XtoolsController
30
{
31
    /** @var Client The Oauth HTTP client. */
32
    protected $oauthClient;
33
34
    /**
35
     * Required to be defined by XtoolsController, though here it is unused.
36
     * @return string
37
     * @codeCoverageIgnore
38
     */
39
    public function getIndexRoute(): string
40
    {
41
        return 'homepage';
42
    }
43
44
    /**
45
     * Display the homepage.
46
     * @Route("/", name="homepage")
47
     * @Route("/index.php", name="homepageIndexPhp")
48
     * @return Response
49 1
     */
50
    public function indexAction(): Response
51 1
    {
52 1
        return $this->render('default/index.html.twig', [
53
            'xtPage' => 'home',
54
        ]);
55
    }
56
57
    /**
58
     * Display some configuration details, when in development mode.
59
     * @Route("/config", name="configPage")
60
     * @return Response
61
     * @codeCoverageIgnore
62 1
     */
63
    public function configAction(): Response
64 1
    {
65 1
66
        if ('dev' !== $this->container->getParameter('kernel.environment')) {
67
            throw new NotFoundHttpException();
68
        }
69
70
        $params = $this->container->getParameterBag()->all();
0 ignored issues
show
Bug introduced by
The method getParameterBag() does not exist on Symfony\Component\Depend...tion\ContainerInterface. Did you maybe mean getParameter()? ( Ignorable by Annotation )

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

70
        $params = $this->container->/** @scrutinizer ignore-call */ getParameterBag()->all();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
71
72
        foreach (array_keys($params) as $key) {
73
            if (false !== strpos($key, 'password')) {
74
                $params[$key] = '<REDACTED>';
75
            }
76
        }
77
78
        // replace this example code with whatever you need
79
        return $this->render('default/config.html.twig', [
80
            'xtTitle' => 'Config',
81
            'xtPageTitle' => 'Config',
82
            'xtPage' => 'index',
83
            'dump' => print_r($params, true),
84
        ]);
85
    }
86
87
    /**
88
     * Redirect to the default project (or Meta) for Oauth authentication.
89
     * @Route("/login", name="login")
90
     * @param SessionInterface $session
91
     * @return RedirectResponse
92
     * @throws Exception If initialization fails.
93
     */
94
    public function loginAction(SessionInterface $session): RedirectResponse
95
    {
96
        try {
97
            [ $next, $token ] = $this->getOauthClient()->initiate();
98
        } catch (Exception $oauthException) {
99
            throw $oauthException;
100
            // @TODO Make this work.
101
            //$this->addFlash('error', $oauthException->getMessage());
102
            //return $this->redirectToRoute('homepage');
103
        }
104
105
        // Save the request token to the session.
106
        $session->set('oauth_request_token', $token);
107
        return new RedirectResponse($next);
108
    }
109
110
    /**
111
     * Receive authentication credentials back from the Oauth wiki.
112
     * @Route("/oauth_callback", name="oauth_callback")
113
     * @Route("/oauthredirector.php", name="old_oauth_callback")
114
     * @param Request $request The HTTP request.
115
     * @param SessionInterface $session
116
     * @return RedirectResponse
117
     */
118
    public function oauthCallbackAction(Request $request, SessionInterface $session): RedirectResponse
119
    {
120
        // Give up if the required GET params don't exist.
121
        if (!$request->get('oauth_verifier')) {
122
            throw $this->createNotFoundException('No OAuth verifier given.');
123
        }
124
125
        // Complete authentication.
126
        $client = $this->getOauthClient();
127
        $token = $session->get('oauth_request_token');
128
129
        if (!is_a($token, Token::class)) {
130 1
            $this->addFlashMessage('notice', 'error-login');
131
            return $this->redirectToRoute('homepage');
132
        }
133 1
134 1
        $verifier = $request->get('oauth_verifier');
135
        $accessToken = $client->complete($token, $verifier);
136
137
        // Store access token, and remove request token.
138
        $session->set('oauth_access_token', $accessToken);
139
        $session->remove('oauth_request_token');
140
141
        // Store user identity.
142
        $ident = $client->identify($accessToken);
143
        $session->set('logged_in_user', $ident);
144
145
        // Store reference to the client.
146
        $session->set('oauth_client', $this->oauthClient);
147
148
        // Send back to homepage.
149
        return $this->redirectToRoute('homepage');
150
    }
151
152
    /**
153
     * Get an OAuth client, configured to the default project.
154
     * (This shouldn't really be in this class, but oh well.)
155
     * @return Client
156
     * @codeCoverageIgnore
157
     */
158
    protected function getOauthClient(): Client
159
    {
160
        if ($this->oauthClient instanceof Client) {
0 ignored issues
show
introduced by
$this->oauthClient is always a sub-type of MediaWiki\OAuthClient\Client.
Loading history...
161
            return $this->oauthClient;
162
        }
163
        $defaultProject = ProjectRepository::getProject(
164
            $this->getParameter('central_auth_project'),
165
            $this->container
166
        );
167
        $endpoint = $defaultProject->getUrl(false)
168
                    . $defaultProject->getScript()
169
                    . '?title=Special:OAuth';
170
        $conf = new ClientConfig($endpoint);
171
        $consumerKey = $this->getParameter('oauth_key');
172
        $consumerSecret =  $this->getParameter('oauth_secret');
173
        $conf->setConsumer(new Consumer($consumerKey, $consumerSecret));
174
        $this->oauthClient = new Client($conf);
175
        // Callback URL is hardcoded in the consumer registration.
176
        $this->oauthClient->setCallback('oob');
177
        return $this->oauthClient;
178
    }
179
180
    /**
181
     * Log out the user and return to the homepage.
182
     * @Route("/logout", name="logout")
183
     * @return RedirectResponse
184
     */
185
    public function logoutAction(): RedirectResponse
186
    {
187
        $this->get('session')->invalidate();
188
        return $this->redirectToRoute('homepage');
189
    }
190
191
    /************************ API endpoints ************************/
192
193
    /**
194
     * Get domain name, URL, and API URL of the given project.
195
     * @Route("/api/project/normalize/{project}", name="ProjectApiNormalize")
196
     * @return JsonResponse
197
     */
198
    public function normalizeProjectApiAction(): JsonResponse
199
    {
200 1
        return $this->getFormattedApiResponse([
201
            'domain' => $this->project->getDomain(),
202 1
            'url' => $this->project->getUrl(),
203 1
            'api' => $this->project->getApiUrl(),
204
            'database' => $this->project->getDatabaseName(),
205
        ]);
206
    }
207
208
    /**
209
     * Get all namespaces of the given project. This endpoint also does the same thing
210
     * as the /project/normalize endpoint, returning other basic info about the project.
211
     * @Route("/api/project/namespaces/{project}", name="ProjectApiNamespaces")
212
     * @return JsonResponse
213
     */
214
    public function namespacesApiAction(): JsonResponse
215
    {
216
        return $this->getFormattedApiResponse([
217
            'domain' => $this->project->getDomain(),
218
            'url' => $this->project->getUrl(),
219
            'api' => $this->project->getApiUrl(),
220
            'database' => $this->project->getDatabaseName(),
221
            'namespaces' => $this->project->getNamespaces(),
222
        ]);
223
    }
224
225
    /**
226
     * Get assessment data for a given project.
227
     * @Route("/api/project/assessments/{project}", name="ProjectApiAssessments")
228
     * @return JsonResponse
229 1
     */
230
    public function projectAssessmentsApiAction(): JsonResponse
231 1
    {
232 1
        return $this->getFormattedApiResponse([
233 1
            'project' => $this->project->getDomain(),
234 1
            'assessments' => $this->project->getPageAssessments()->getConfig(),
235 1
        ]);
236 1
    }
237
238
    /**
239
     * Get assessment data for all projects.
240
     * @Route("/api/project/assessments", name="ApiAssessmentsConfig")
241
     * @return JsonResponse
242
     */
243
    public function assessmentsConfigApiAction(): JsonResponse
244
    {
245 1
        // Here there is no Project, so we don't use XtoolsController::getFormattedApiResponse().
246
        $response = new JsonResponse();
247 1
        $response->setEncodingOptions(JSON_NUMERIC_CHECK);
248 1
        $response->setStatusCode(Response::HTTP_OK);
249 1
        $response->setData([
250
            'projects' => array_keys($this->container->getParameter('assessments')),
0 ignored issues
show
Bug introduced by
It seems like $this->container->getParameter('assessments') can also be of type boolean and double and integer and null and string; however, parameter $array of array_keys() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

250
            'projects' => array_keys(/** @scrutinizer ignore-type */ $this->container->getParameter('assessments')),
Loading history...
251
            'config' => $this->container->getParameter('assessments'),
252
        ]);
253
254
        return $response;
255
    }
256
257
    /**
258
     * Transform given wikitext to HTML using the XTools parser. Wikitext must be passed in as the query 'wikitext'.
259
     * @Route("/api/project/parser/{project}")
260
     * @return JsonResponse Safe HTML.
261
     */
262
    public function wikifyApiAction(): JsonResponse
263
    {
264
        return new JsonResponse(
265
            Edit::wikifyString($this->request->query->get('wikitext', ''), $this->project)
266
        );
267
    }
268
}
269