GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

getRecoveryRequest()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
namespace SOG\Dashboard;
3
4
use Silex\Application;
5
use Silex\ControllerCollection;
6
use Silex\ControllerProviderInterface;
7
use Symfony\Component\HttpFoundation\Request;
8
use Symfony\Component\Routing\Generator\UrlGenerator;
9
10
/**
11
 * Implements password request/reset functionality, depends on Doctrine/DBAL with the sqlite interface for storing
12
 * and validating requests.
13
 *
14
 * Class PasswordRecoveryControllerProvider
15
 * @package SOG\Dashboard
16
 */
17
class PasswordRecoveryControllerProvider implements ControllerProviderInterface
18
{
19
    /**
20
     * @var Application Reference to the Silex app for easy access to the services etc.
21
     */
22
    private $app;
23
    /**
24
     * @var string The timeout of a reset request, as DateInterval https://secure.php.net/manual/en/class.dateinterval.php
25
     */
26
    private $request_timeout = 'P1W';
27
    /**
28
     * @var int The length of the generated token for validating requests
29
     */
30
    private $token_length = 32;
31
    /**
32
     * @var int The minimum length for a new user password
33
     */
34
    private $password_min_length = 8;
35
    /**
36
     * @var string Name of the route for reset, used with the UrlGenerator
37
     */
38
    private $reset_route = 'POST_GET_password_reset_token';
39
    /**
40
     * @var string Name of the route for request, used with the UrlGenerator
41
     */
42
    private $request_route = 'POST_GET_password_request';
43
44
    /**
45
     * Returns routes to connect to the given application.
46
     *
47
     * @param Application $app An Application instance
48
     *
49
     * @return ControllerCollection A ControllerCollection instance
50
     */
51
    public function connect(Application $app)
52
    {
53
        $this->app = $app;
54
55
        /** @var ControllerCollection $controllers */
56
        $controllers = $app['controllers_factory'];
57
58
        // handle the password reset form (display and saving)
59
        $controllers->match('/reset/{token}', function (Application $app, Request $request, $token) {
60
            $this->cleanupRequests();
61
62
            if ($this->validateRequest($token)) {
63
                if ($request->isMethod('GET')) {
64
                    return $app['twig']->render('reset_password.twig', [
65
                        'reset_route' => $this->reset_route,
66
                        'token' => $token
67
                    ]);
68
                } elseif ($request->isMethod('POST')) {
69
                    $password = $request->request->get('password');
70
                    $password_repeat = $request->request->get('password_repeat');
71
                    if ($this->validateNewPassword($password, $password_repeat) === false) {
72
                        $app['session']->getFlashBag()
73
                            ->add('error', sprintf('Fehler beim Zurücksetzen des Passworts. Das gewählte Passwort muss aus mindestens %s Zeichen (Buchstaben, Ziffern *und* Sonderzeichen) bestehen.', $this->password_min_length));
74
                        return $app->redirect($app['url_generator']->generate($this->reset_route, ['token' => $token]));
75
                    } else {
76
                        $details = $this->getRecoveryRequest($token);
77
                        $this->updatePassword($details['uid'], $password);
78
                        $this->closeRequest($token);
79
                        $app['session']->getFlashBag()
80
                            ->add('success', 'Dein Passwort wurde erfolgreich zurückgesetzt, du kannst dich jetzt einloggen.');
81
                    }
82
                }
83
            } else {
84
                $app['session']->getFlashBag()
85
                    ->add('error', 'Fehler beim Zurücksetzen des Passworts. Bitte versuche es noch einmal, oder benachrichtige das IT-Team.');
86
            }
87
            return $app->redirect('/login');
88
        })->method('POST|GET');
89
90
        // handle the password request form to initiate a reset process
91
        $controllers->match('/request', function (Application $app, Request $request) {
92
            if ($request->isMethod('GET')) {
93
                return $app['twig']->render('request_reset_password.twig', [
94
                    'request_route' => $this->request_route
95
                ]);
96
            }
97
            $email = $request->request->get('email');
98
            $member = $app['ldap']->getMemberByMail($email);
99
            if ($member !== false) {
100
                $token = $this->registerRequest($member['uid'][0], $email);
101
                $this->sendRecoveryMail($member, $token);
102
                $app['session']->getFlashBag()
103
                    ->add('success', 'Wir haben dir einen Link zum Zurücksetzen deines Passworts zugeschickt. Bitte klicke auf diesen Link.');
104
            } else {
105
                $app['session']->getFlashBag()
106
                    ->add('error', 'Diese Email-Adresse ist nicht vergeben.');
107
            }
108
            return $app->redirect('/login');
109
        })->method('POST|GET');
110
111
        return $controllers;
112
    }
113
114
    /**
115
     * Deletes all old requests from the database. A request is considered old,
116
     * if its registration happened before now - $timeout.
117
     */
118
    private function cleanupRequests()
119
    {
120
        // calculate the timeout, now minus a given interval
121
        $limit = (new \DateTime())->sub(new \DateInterval($this->request_timeout))->getTimestamp();
122
        // delete all entries which are older than the calculated limit, data type is UNIX timestamp
123
        $this->app['db']->executeUpdate('DELETE FROM `password_requests` WHERE `created` < ?', [$limit]);
124
    }
125
126
    /**
127
     * Validates the given $token by looking it up in the database.
128
     *
129
     * @param string $token
130
     * @return bool True if the token is valid, false otherwise.
131
     */
132
    private function validateRequest($token)
133
    {
134
        $result = $this->app['db']->fetchAll('SELECT * FROM `password_requests` WHERE `token` = ?', [$token]);
135
        return (count($result) === 1);
136
    }
137
138
    /**
139
     * Validates the given password.
140
     *
141
     * @param string $password
142
     * @param string $password_repeat
143
     * @return bool True on success, false otherwise.
144
     */
145
    private function validateNewPassword($password, $password_repeat)
146
    {
147
        if ($password !== $password_repeat) {
148
            return false;
149
        }
150
        return $this->app['check_password_policy']($password);
151
    }
152
153
    /**
154
     * Returns the recovery request from the database.
155
     *
156
     * @param $token
157
     * @return array
158
     */
159
    private function getRecoveryRequest($token)
160
    {
161
        return $this->app['db']->fetchAssoc('SELECT * FROM `password_requests` WHERE `token` = ?', [$token]);
162
    }
163
164
    /**
165
     * Finally updates the users password after a successful recovery.
166
     *
167
     * @param $uid
168
     * @param $password
169
     */
170
    private function updatePassword($uid, $password)
171
    {
172
        $dn = sprintf('uid=%s,ou=active,ou=people,o=sog-de,dc=sog', $uid);
173
        // force the password update
174
        $this->app['ldap']->forceUpdatePassword($dn, $password);
175
    }
176
177
    /**
178
     * Deletes the request associated with the given $token from the database.
179
     *
180
     * @param string $token
181
     */
182
    private function closeRequest($token)
183
    {
184
        $this->app['db']->delete('password_requests', ['token' => $token]);
185
    }
186
187
    /**
188
     * Registers the given $email by storing it in the database. The method
189
     * also generates and returns a random token associated with this request.
190
     *
191
     * @param string $uid
192
     * @param string $email
193
     * @return string The token associated with this request.
194
     */
195
    private function registerRequest($uid, $email)
196
    {
197
        // delete all existing requests first
198
        $this->app['db']->delete('password_requests', ['email' => $email]);
199
        $token = $this->app['random']($this->token_length);
200
        $this->app['db']->insert('password_requests',
201
            ['email' => $email, 'token' => $token, 'uid' => $uid, 'created' => time()]
202
        );
203
        return $token;
204
    }
205
206
    /**
207
     * Sends the recovery email containing a link with the $token to $email.
208
     *
209
     * @param array $member Array of attributes for the member as returned by \Zend\Ldap
210
     * @param string $token The random token which is passed to the reset URL for validation
211
     * @return int The number of successful mail deliveries.
212
     */
213
    private function sendRecoveryMail($member, $token)
214
    {
215
        $text = "<p>Hallo %s!</p>\n
216
        <p>Du hast über das SOG Dashboard das Zurücksetzen des Passworts für deinen SOG Account angefordert. Falls du diesen Vorgang nicht von dir aus gestartet hast, musst du nichts unternehmen.</p>\n
217
        <p>Das Passwort kannst du hier zurücksetzen: %s</p>\n
218
        <p>Dein Benutzername lautet: %s</p>\n
219
        <p>Bei Problemen kannst du einfach auf diese Mail antworten.</p>\n
220
        <p>Mit freundlichen Grüßen, dein SOG IT-Ressort</p>";
221
        $text = sprintf($text,
222
            $member['displayname'][0],
223
            $this->app['url_generator']->generate($this->reset_route, ['token' => $token], UrlGenerator::ABSOLUTE_URL),
224
            $member['uid'][0]
225
        );
226
        $message = \Swift_Message::newInstance()
227
            ->addTo($member['mail-alternative'][0], $member['displayname'][0])
228
            ->addFrom($this->app['mailer.from'])
229
            ->setSubject('[SOG Dashboard] Passwort zurücksetzen')
230
            ->setBody($text, 'text/html');
231
        return $this->app['mailer']->send($message);
232
    }
233
}
234