Passed
Push — master ( 9e08e4...46dcbd )
by Christoph
17:11 queued 18s
created
core/Controller/LoginController.php 1 patch
Indentation   +327 added lines, -327 removed lines patch added patch discarded remove patch
@@ -60,331 +60,331 @@
 block discarded – undo
60 60
 use OCP\Util;
61 61
 
62 62
 class LoginController extends Controller {
63
-	public const LOGIN_MSG_INVALIDPASSWORD = 'invalidpassword';
64
-	public const LOGIN_MSG_USERDISABLED = 'userdisabled';
65
-
66
-	private IUserManager $userManager;
67
-	private IConfig $config;
68
-	private ISession $session;
69
-	/** @var IUserSession|Session */
70
-	private $userSession;
71
-	private IURLGenerator $urlGenerator;
72
-	private Defaults $defaults;
73
-	private Throttler $throttler;
74
-	private IInitialStateService $initialStateService;
75
-	private WebAuthnManager $webAuthnManager;
76
-	private IManager $manager;
77
-	private IL10N $l10n;
78
-
79
-	public function __construct(?string $appName,
80
-								IRequest $request,
81
-								IUserManager $userManager,
82
-								IConfig $config,
83
-								ISession $session,
84
-								IUserSession $userSession,
85
-								IURLGenerator $urlGenerator,
86
-								Defaults $defaults,
87
-								Throttler $throttler,
88
-								IInitialStateService $initialStateService,
89
-								WebAuthnManager $webAuthnManager,
90
-								IManager $manager,
91
-								IL10N $l10n) {
92
-		parent::__construct($appName, $request);
93
-		$this->userManager = $userManager;
94
-		$this->config = $config;
95
-		$this->session = $session;
96
-		$this->userSession = $userSession;
97
-		$this->urlGenerator = $urlGenerator;
98
-		$this->defaults = $defaults;
99
-		$this->throttler = $throttler;
100
-		$this->initialStateService = $initialStateService;
101
-		$this->webAuthnManager = $webAuthnManager;
102
-		$this->manager = $manager;
103
-		$this->l10n = $l10n;
104
-	}
105
-
106
-	/**
107
-	 * @NoAdminRequired
108
-	 * @UseSession
109
-	 *
110
-	 * @return RedirectResponse
111
-	 */
112
-	public function logout() {
113
-		$loginToken = $this->request->getCookie('nc_token');
114
-		if (!is_null($loginToken)) {
115
-			$this->config->deleteUserValue($this->userSession->getUser()->getUID(), 'login_token', $loginToken);
116
-		}
117
-		$this->userSession->logout();
118
-
119
-		$response = new RedirectResponse($this->urlGenerator->linkToRouteAbsolute(
120
-			'core.login.showLoginForm',
121
-			['clear' => true] // this param the code in login.js may be removed when the "Clear-Site-Data" is working in the browsers
122
-		));
123
-
124
-		$this->session->set('clearingExecutionContexts', '1');
125
-		$this->session->close();
126
-
127
-		if (!$this->request->isUserAgent([Request::USER_AGENT_CHROME, Request::USER_AGENT_ANDROID_MOBILE_CHROME])) {
128
-			$response->addHeader('Clear-Site-Data', '"cache", "storage"');
129
-		}
130
-
131
-		return $response;
132
-	}
133
-
134
-	/**
135
-	 * @PublicPage
136
-	 * @NoCSRFRequired
137
-	 * @UseSession
138
-	 *
139
-	 * @param string $user
140
-	 * @param string $redirect_url
141
-	 *
142
-	 * @return TemplateResponse|RedirectResponse
143
-	 */
144
-	public function showLoginForm(string $user = null, string $redirect_url = null): Http\Response {
145
-		if ($this->userSession->isLoggedIn()) {
146
-			return new RedirectResponse($this->urlGenerator->linkToDefaultPageUrl());
147
-		}
148
-
149
-		$loginMessages = $this->session->get('loginMessages');
150
-		if (!$this->manager->isFairUseOfFreePushService()) {
151
-			if (!is_array($loginMessages)) {
152
-				$loginMessages = [[], []];
153
-			}
154
-			$loginMessages[1][] = $this->l10n->t('This community release of Nextcloud is unsupported and push notifications are limited.');
155
-		}
156
-		if (is_array($loginMessages)) {
157
-			[$errors, $messages] = $loginMessages;
158
-			$this->initialStateService->provideInitialState('core', 'loginMessages', $messages);
159
-			$this->initialStateService->provideInitialState('core', 'loginErrors', $errors);
160
-		}
161
-		$this->session->remove('loginMessages');
162
-
163
-		if ($user !== null && $user !== '') {
164
-			$this->initialStateService->provideInitialState('core', 'loginUsername', $user);
165
-		} else {
166
-			$this->initialStateService->provideInitialState('core', 'loginUsername', '');
167
-		}
168
-
169
-		$this->initialStateService->provideInitialState(
170
-			'core',
171
-			'loginAutocomplete',
172
-			$this->config->getSystemValue('login_form_autocomplete', true) === true
173
-		);
174
-
175
-		if (!empty($redirect_url)) {
176
-			[$url, ] = explode('?', $redirect_url);
177
-			if ($url !== $this->urlGenerator->linkToRoute('core.login.logout')) {
178
-				$this->initialStateService->provideInitialState('core', 'loginRedirectUrl', $redirect_url);
179
-			}
180
-		}
181
-
182
-		$this->initialStateService->provideInitialState(
183
-			'core',
184
-			'loginThrottleDelay',
185
-			$this->throttler->getDelay($this->request->getRemoteAddress())
186
-		);
187
-
188
-		$this->setPasswordResetInitialState($user);
189
-
190
-		$this->initialStateService->provideInitialState('core', 'webauthn-available', $this->webAuthnManager->isWebAuthnAvailable());
191
-
192
-		$this->initialStateService->provideInitialState('core', 'hideLoginForm', $this->config->getSystemValueBool('hide_login_form', false));
193
-
194
-		// OpenGraph Support: http://ogp.me/
195
-		Util::addHeader('meta', ['property' => 'og:title', 'content' => Util::sanitizeHTML($this->defaults->getName())]);
196
-		Util::addHeader('meta', ['property' => 'og:description', 'content' => Util::sanitizeHTML($this->defaults->getSlogan())]);
197
-		Util::addHeader('meta', ['property' => 'og:site_name', 'content' => Util::sanitizeHTML($this->defaults->getName())]);
198
-		Util::addHeader('meta', ['property' => 'og:url', 'content' => $this->urlGenerator->getAbsoluteURL('/')]);
199
-		Util::addHeader('meta', ['property' => 'og:type', 'content' => 'website']);
200
-		Util::addHeader('meta', ['property' => 'og:image', 'content' => $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'favicon-touch.png'))]);
201
-
202
-		$parameters = [
203
-			'alt_login' => OC_App::getAlternativeLogIns(),
204
-			'pageTitle' => $this->l10n->t('Login'),
205
-		];
206
-
207
-		$this->initialStateService->provideInitialState('core', 'countAlternativeLogins', count($parameters['alt_login']));
208
-		$this->initialStateService->provideInitialState('core', 'alternativeLogins', $parameters['alt_login']);
209
-
210
-		return new TemplateResponse(
211
-			$this->appName,
212
-			'login',
213
-			$parameters,
214
-			TemplateResponse::RENDER_AS_GUEST,
215
-		);
216
-	}
217
-
218
-	/**
219
-	 * Sets the password reset state
220
-	 *
221
-	 * @param string $username
222
-	 */
223
-	private function setPasswordResetInitialState(?string $username): void {
224
-		if ($username !== null && $username !== '') {
225
-			$user = $this->userManager->get($username);
226
-		} else {
227
-			$user = null;
228
-		}
229
-
230
-		$passwordLink = $this->config->getSystemValueString('lost_password_link', '');
231
-
232
-		$this->initialStateService->provideInitialState(
233
-			'core',
234
-			'loginResetPasswordLink',
235
-			$passwordLink
236
-		);
237
-
238
-		$this->initialStateService->provideInitialState(
239
-			'core',
240
-			'loginCanResetPassword',
241
-			$this->canResetPassword($passwordLink, $user)
242
-		);
243
-	}
244
-
245
-	/**
246
-	 * @param string|null $passwordLink
247
-	 * @param IUser|null $user
248
-	 *
249
-	 * Users may not change their passwords if:
250
-	 * - The account is disabled
251
-	 * - The backend doesn't support password resets
252
-	 * - The password reset function is disabled
253
-	 *
254
-	 * @return bool
255
-	 */
256
-	private function canResetPassword(?string $passwordLink, ?IUser $user): bool {
257
-		if ($passwordLink === 'disabled') {
258
-			return false;
259
-		}
260
-
261
-		if (!$passwordLink && $user !== null) {
262
-			return $user->canChangePassword();
263
-		}
264
-
265
-		if ($user !== null && $user->isEnabled() === false) {
266
-			return false;
267
-		}
268
-
269
-		return true;
270
-	}
271
-
272
-	private function generateRedirect(?string $redirectUrl): RedirectResponse {
273
-		if ($redirectUrl !== null && $this->userSession->isLoggedIn()) {
274
-			$location = $this->urlGenerator->getAbsoluteURL($redirectUrl);
275
-			// Deny the redirect if the URL contains a @
276
-			// This prevents unvalidated redirects like ?redirect_url=:[email protected]
277
-			if (strpos($location, '@') === false) {
278
-				return new RedirectResponse($location);
279
-			}
280
-		}
281
-		return new RedirectResponse($this->urlGenerator->linkToDefaultPageUrl());
282
-	}
283
-
284
-	/**
285
-	 * @PublicPage
286
-	 * @UseSession
287
-	 * @NoCSRFRequired
288
-	 * @BruteForceProtection(action=login)
289
-	 *
290
-	 * @return RedirectResponse
291
-	 */
292
-	public function tryLogin(Chain $loginChain,
293
-							 string $user,
294
-							 string $password,
295
-							 string $redirect_url = null,
296
-							 string $timezone = '',
297
-							 string $timezone_offset = ''): RedirectResponse {
298
-		if (!$this->request->passesCSRFCheck()) {
299
-			if ($this->userSession->isLoggedIn()) {
300
-				// If the user is already logged in and the CSRF check does not pass then
301
-				// simply redirect the user to the correct page as required. This is the
302
-				// case when a user has already logged-in, in another tab.
303
-				return $this->generateRedirect($redirect_url);
304
-			}
305
-
306
-			// Clear any auth remnants like cookies to ensure a clean login
307
-			// For the next attempt
308
-			$this->userSession->logout();
309
-			return $this->createLoginFailedResponse(
310
-				$user,
311
-				$user,
312
-				$redirect_url,
313
-				$this->l10n->t('Please try again')
314
-			);
315
-		}
316
-
317
-		$data = new LoginData(
318
-			$this->request,
319
-			trim($user),
320
-			$password,
321
-			$redirect_url,
322
-			$timezone,
323
-			$timezone_offset
324
-		);
325
-		$result = $loginChain->process($data);
326
-		if (!$result->isSuccess()) {
327
-			return $this->createLoginFailedResponse(
328
-				$data->getUsername(),
329
-				$user,
330
-				$redirect_url,
331
-				$result->getErrorMessage()
332
-			);
333
-		}
334
-
335
-		if ($result->getRedirectUrl() !== null) {
336
-			return new RedirectResponse($result->getRedirectUrl());
337
-		}
338
-		return $this->generateRedirect($redirect_url);
339
-	}
340
-
341
-	/**
342
-	 * Creates a login failed response.
343
-	 *
344
-	 * @param string $user
345
-	 * @param string $originalUser
346
-	 * @param string $redirect_url
347
-	 * @param string $loginMessage
348
-	 *
349
-	 * @return RedirectResponse
350
-	 */
351
-	private function createLoginFailedResponse(
352
-		$user, $originalUser, $redirect_url, string $loginMessage) {
353
-		// Read current user and append if possible we need to
354
-		// return the unmodified user otherwise we will leak the login name
355
-		$args = $user !== null ? ['user' => $originalUser, 'direct' => 1] : [];
356
-		if ($redirect_url !== null) {
357
-			$args['redirect_url'] = $redirect_url;
358
-		}
359
-		$response = new RedirectResponse(
360
-			$this->urlGenerator->linkToRoute('core.login.showLoginForm', $args)
361
-		);
362
-		$response->throttle(['user' => substr($user, 0, 64)]);
363
-		$this->session->set('loginMessages', [
364
-			[$loginMessage], []
365
-		]);
366
-		return $response;
367
-	}
368
-
369
-	/**
370
-	 * @NoAdminRequired
371
-	 * @UseSession
372
-	 * @BruteForceProtection(action=sudo)
373
-	 *
374
-	 * @license GNU AGPL version 3 or any later version
375
-	 *
376
-	 */
377
-	public function confirmPassword(string $password): DataResponse {
378
-		$loginName = $this->userSession->getLoginName();
379
-		$loginResult = $this->userManager->checkPassword($loginName, $password);
380
-		if ($loginResult === false) {
381
-			$response = new DataResponse([], Http::STATUS_FORBIDDEN);
382
-			$response->throttle();
383
-			return $response;
384
-		}
385
-
386
-		$confirmTimestamp = time();
387
-		$this->session->set('last-password-confirm', $confirmTimestamp);
388
-		return new DataResponse(['lastLogin' => $confirmTimestamp], Http::STATUS_OK);
389
-	}
63
+    public const LOGIN_MSG_INVALIDPASSWORD = 'invalidpassword';
64
+    public const LOGIN_MSG_USERDISABLED = 'userdisabled';
65
+
66
+    private IUserManager $userManager;
67
+    private IConfig $config;
68
+    private ISession $session;
69
+    /** @var IUserSession|Session */
70
+    private $userSession;
71
+    private IURLGenerator $urlGenerator;
72
+    private Defaults $defaults;
73
+    private Throttler $throttler;
74
+    private IInitialStateService $initialStateService;
75
+    private WebAuthnManager $webAuthnManager;
76
+    private IManager $manager;
77
+    private IL10N $l10n;
78
+
79
+    public function __construct(?string $appName,
80
+                                IRequest $request,
81
+                                IUserManager $userManager,
82
+                                IConfig $config,
83
+                                ISession $session,
84
+                                IUserSession $userSession,
85
+                                IURLGenerator $urlGenerator,
86
+                                Defaults $defaults,
87
+                                Throttler $throttler,
88
+                                IInitialStateService $initialStateService,
89
+                                WebAuthnManager $webAuthnManager,
90
+                                IManager $manager,
91
+                                IL10N $l10n) {
92
+        parent::__construct($appName, $request);
93
+        $this->userManager = $userManager;
94
+        $this->config = $config;
95
+        $this->session = $session;
96
+        $this->userSession = $userSession;
97
+        $this->urlGenerator = $urlGenerator;
98
+        $this->defaults = $defaults;
99
+        $this->throttler = $throttler;
100
+        $this->initialStateService = $initialStateService;
101
+        $this->webAuthnManager = $webAuthnManager;
102
+        $this->manager = $manager;
103
+        $this->l10n = $l10n;
104
+    }
105
+
106
+    /**
107
+     * @NoAdminRequired
108
+     * @UseSession
109
+     *
110
+     * @return RedirectResponse
111
+     */
112
+    public function logout() {
113
+        $loginToken = $this->request->getCookie('nc_token');
114
+        if (!is_null($loginToken)) {
115
+            $this->config->deleteUserValue($this->userSession->getUser()->getUID(), 'login_token', $loginToken);
116
+        }
117
+        $this->userSession->logout();
118
+
119
+        $response = new RedirectResponse($this->urlGenerator->linkToRouteAbsolute(
120
+            'core.login.showLoginForm',
121
+            ['clear' => true] // this param the code in login.js may be removed when the "Clear-Site-Data" is working in the browsers
122
+        ));
123
+
124
+        $this->session->set('clearingExecutionContexts', '1');
125
+        $this->session->close();
126
+
127
+        if (!$this->request->isUserAgent([Request::USER_AGENT_CHROME, Request::USER_AGENT_ANDROID_MOBILE_CHROME])) {
128
+            $response->addHeader('Clear-Site-Data', '"cache", "storage"');
129
+        }
130
+
131
+        return $response;
132
+    }
133
+
134
+    /**
135
+     * @PublicPage
136
+     * @NoCSRFRequired
137
+     * @UseSession
138
+     *
139
+     * @param string $user
140
+     * @param string $redirect_url
141
+     *
142
+     * @return TemplateResponse|RedirectResponse
143
+     */
144
+    public function showLoginForm(string $user = null, string $redirect_url = null): Http\Response {
145
+        if ($this->userSession->isLoggedIn()) {
146
+            return new RedirectResponse($this->urlGenerator->linkToDefaultPageUrl());
147
+        }
148
+
149
+        $loginMessages = $this->session->get('loginMessages');
150
+        if (!$this->manager->isFairUseOfFreePushService()) {
151
+            if (!is_array($loginMessages)) {
152
+                $loginMessages = [[], []];
153
+            }
154
+            $loginMessages[1][] = $this->l10n->t('This community release of Nextcloud is unsupported and push notifications are limited.');
155
+        }
156
+        if (is_array($loginMessages)) {
157
+            [$errors, $messages] = $loginMessages;
158
+            $this->initialStateService->provideInitialState('core', 'loginMessages', $messages);
159
+            $this->initialStateService->provideInitialState('core', 'loginErrors', $errors);
160
+        }
161
+        $this->session->remove('loginMessages');
162
+
163
+        if ($user !== null && $user !== '') {
164
+            $this->initialStateService->provideInitialState('core', 'loginUsername', $user);
165
+        } else {
166
+            $this->initialStateService->provideInitialState('core', 'loginUsername', '');
167
+        }
168
+
169
+        $this->initialStateService->provideInitialState(
170
+            'core',
171
+            'loginAutocomplete',
172
+            $this->config->getSystemValue('login_form_autocomplete', true) === true
173
+        );
174
+
175
+        if (!empty($redirect_url)) {
176
+            [$url, ] = explode('?', $redirect_url);
177
+            if ($url !== $this->urlGenerator->linkToRoute('core.login.logout')) {
178
+                $this->initialStateService->provideInitialState('core', 'loginRedirectUrl', $redirect_url);
179
+            }
180
+        }
181
+
182
+        $this->initialStateService->provideInitialState(
183
+            'core',
184
+            'loginThrottleDelay',
185
+            $this->throttler->getDelay($this->request->getRemoteAddress())
186
+        );
187
+
188
+        $this->setPasswordResetInitialState($user);
189
+
190
+        $this->initialStateService->provideInitialState('core', 'webauthn-available', $this->webAuthnManager->isWebAuthnAvailable());
191
+
192
+        $this->initialStateService->provideInitialState('core', 'hideLoginForm', $this->config->getSystemValueBool('hide_login_form', false));
193
+
194
+        // OpenGraph Support: http://ogp.me/
195
+        Util::addHeader('meta', ['property' => 'og:title', 'content' => Util::sanitizeHTML($this->defaults->getName())]);
196
+        Util::addHeader('meta', ['property' => 'og:description', 'content' => Util::sanitizeHTML($this->defaults->getSlogan())]);
197
+        Util::addHeader('meta', ['property' => 'og:site_name', 'content' => Util::sanitizeHTML($this->defaults->getName())]);
198
+        Util::addHeader('meta', ['property' => 'og:url', 'content' => $this->urlGenerator->getAbsoluteURL('/')]);
199
+        Util::addHeader('meta', ['property' => 'og:type', 'content' => 'website']);
200
+        Util::addHeader('meta', ['property' => 'og:image', 'content' => $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'favicon-touch.png'))]);
201
+
202
+        $parameters = [
203
+            'alt_login' => OC_App::getAlternativeLogIns(),
204
+            'pageTitle' => $this->l10n->t('Login'),
205
+        ];
206
+
207
+        $this->initialStateService->provideInitialState('core', 'countAlternativeLogins', count($parameters['alt_login']));
208
+        $this->initialStateService->provideInitialState('core', 'alternativeLogins', $parameters['alt_login']);
209
+
210
+        return new TemplateResponse(
211
+            $this->appName,
212
+            'login',
213
+            $parameters,
214
+            TemplateResponse::RENDER_AS_GUEST,
215
+        );
216
+    }
217
+
218
+    /**
219
+     * Sets the password reset state
220
+     *
221
+     * @param string $username
222
+     */
223
+    private function setPasswordResetInitialState(?string $username): void {
224
+        if ($username !== null && $username !== '') {
225
+            $user = $this->userManager->get($username);
226
+        } else {
227
+            $user = null;
228
+        }
229
+
230
+        $passwordLink = $this->config->getSystemValueString('lost_password_link', '');
231
+
232
+        $this->initialStateService->provideInitialState(
233
+            'core',
234
+            'loginResetPasswordLink',
235
+            $passwordLink
236
+        );
237
+
238
+        $this->initialStateService->provideInitialState(
239
+            'core',
240
+            'loginCanResetPassword',
241
+            $this->canResetPassword($passwordLink, $user)
242
+        );
243
+    }
244
+
245
+    /**
246
+     * @param string|null $passwordLink
247
+     * @param IUser|null $user
248
+     *
249
+     * Users may not change their passwords if:
250
+     * - The account is disabled
251
+     * - The backend doesn't support password resets
252
+     * - The password reset function is disabled
253
+     *
254
+     * @return bool
255
+     */
256
+    private function canResetPassword(?string $passwordLink, ?IUser $user): bool {
257
+        if ($passwordLink === 'disabled') {
258
+            return false;
259
+        }
260
+
261
+        if (!$passwordLink && $user !== null) {
262
+            return $user->canChangePassword();
263
+        }
264
+
265
+        if ($user !== null && $user->isEnabled() === false) {
266
+            return false;
267
+        }
268
+
269
+        return true;
270
+    }
271
+
272
+    private function generateRedirect(?string $redirectUrl): RedirectResponse {
273
+        if ($redirectUrl !== null && $this->userSession->isLoggedIn()) {
274
+            $location = $this->urlGenerator->getAbsoluteURL($redirectUrl);
275
+            // Deny the redirect if the URL contains a @
276
+            // This prevents unvalidated redirects like ?redirect_url=:[email protected]
277
+            if (strpos($location, '@') === false) {
278
+                return new RedirectResponse($location);
279
+            }
280
+        }
281
+        return new RedirectResponse($this->urlGenerator->linkToDefaultPageUrl());
282
+    }
283
+
284
+    /**
285
+     * @PublicPage
286
+     * @UseSession
287
+     * @NoCSRFRequired
288
+     * @BruteForceProtection(action=login)
289
+     *
290
+     * @return RedirectResponse
291
+     */
292
+    public function tryLogin(Chain $loginChain,
293
+                                string $user,
294
+                                string $password,
295
+                                string $redirect_url = null,
296
+                                string $timezone = '',
297
+                                string $timezone_offset = ''): RedirectResponse {
298
+        if (!$this->request->passesCSRFCheck()) {
299
+            if ($this->userSession->isLoggedIn()) {
300
+                // If the user is already logged in and the CSRF check does not pass then
301
+                // simply redirect the user to the correct page as required. This is the
302
+                // case when a user has already logged-in, in another tab.
303
+                return $this->generateRedirect($redirect_url);
304
+            }
305
+
306
+            // Clear any auth remnants like cookies to ensure a clean login
307
+            // For the next attempt
308
+            $this->userSession->logout();
309
+            return $this->createLoginFailedResponse(
310
+                $user,
311
+                $user,
312
+                $redirect_url,
313
+                $this->l10n->t('Please try again')
314
+            );
315
+        }
316
+
317
+        $data = new LoginData(
318
+            $this->request,
319
+            trim($user),
320
+            $password,
321
+            $redirect_url,
322
+            $timezone,
323
+            $timezone_offset
324
+        );
325
+        $result = $loginChain->process($data);
326
+        if (!$result->isSuccess()) {
327
+            return $this->createLoginFailedResponse(
328
+                $data->getUsername(),
329
+                $user,
330
+                $redirect_url,
331
+                $result->getErrorMessage()
332
+            );
333
+        }
334
+
335
+        if ($result->getRedirectUrl() !== null) {
336
+            return new RedirectResponse($result->getRedirectUrl());
337
+        }
338
+        return $this->generateRedirect($redirect_url);
339
+    }
340
+
341
+    /**
342
+     * Creates a login failed response.
343
+     *
344
+     * @param string $user
345
+     * @param string $originalUser
346
+     * @param string $redirect_url
347
+     * @param string $loginMessage
348
+     *
349
+     * @return RedirectResponse
350
+     */
351
+    private function createLoginFailedResponse(
352
+        $user, $originalUser, $redirect_url, string $loginMessage) {
353
+        // Read current user and append if possible we need to
354
+        // return the unmodified user otherwise we will leak the login name
355
+        $args = $user !== null ? ['user' => $originalUser, 'direct' => 1] : [];
356
+        if ($redirect_url !== null) {
357
+            $args['redirect_url'] = $redirect_url;
358
+        }
359
+        $response = new RedirectResponse(
360
+            $this->urlGenerator->linkToRoute('core.login.showLoginForm', $args)
361
+        );
362
+        $response->throttle(['user' => substr($user, 0, 64)]);
363
+        $this->session->set('loginMessages', [
364
+            [$loginMessage], []
365
+        ]);
366
+        return $response;
367
+    }
368
+
369
+    /**
370
+     * @NoAdminRequired
371
+     * @UseSession
372
+     * @BruteForceProtection(action=sudo)
373
+     *
374
+     * @license GNU AGPL version 3 or any later version
375
+     *
376
+     */
377
+    public function confirmPassword(string $password): DataResponse {
378
+        $loginName = $this->userSession->getLoginName();
379
+        $loginResult = $this->userManager->checkPassword($loginName, $password);
380
+        if ($loginResult === false) {
381
+            $response = new DataResponse([], Http::STATUS_FORBIDDEN);
382
+            $response->throttle();
383
+            return $response;
384
+        }
385
+
386
+        $confirmTimestamp = time();
387
+        $this->session->set('last-password-confirm', $confirmTimestamp);
388
+        return new DataResponse(['lastLogin' => $confirmTimestamp], Http::STATUS_OK);
389
+    }
390 390
 }
Please login to merge, or discard this patch.
lib/private/AppFramework/DependencyInjection/DIContainer.php 1 patch
Indentation   +405 added lines, -405 removed lines patch added patch discarded remove patch
@@ -79,409 +79,409 @@
 block discarded – undo
79 79
  * @deprecated 20.0.0
80 80
  */
81 81
 class DIContainer extends SimpleContainer implements IAppContainer {
82
-	private string $appName;
83
-
84
-	/**
85
-	 * @var array
86
-	 */
87
-	private $middleWares = [];
88
-
89
-	/** @var ServerContainer */
90
-	private $server;
91
-
92
-	/**
93
-	 * Put your class dependencies in here
94
-	 * @param string $appName the name of the app
95
-	 * @param array $urlParams
96
-	 * @param ServerContainer|null $server
97
-	 */
98
-	public function __construct(string $appName, array $urlParams = [], ServerContainer $server = null) {
99
-		parent::__construct();
100
-		$this->appName = $appName;
101
-		$this['appName'] = $appName;
102
-		$this['urlParams'] = $urlParams;
103
-
104
-		$this->registerAlias('Request', IRequest::class);
105
-
106
-		/** @var \OC\ServerContainer $server */
107
-		if ($server === null) {
108
-			$server = \OC::$server;
109
-		}
110
-		$this->server = $server;
111
-		$this->server->registerAppContainer($appName, $this);
112
-
113
-		// aliases
114
-		/** @deprecated inject $appName */
115
-		$this->registerAlias('AppName', 'appName');
116
-		/** @deprecated inject $webRoot*/
117
-		$this->registerAlias('WebRoot', 'webRoot');
118
-		/** @deprecated inject $userId */
119
-		$this->registerAlias('UserId', 'userId');
120
-
121
-		/**
122
-		 * Core services
123
-		 */
124
-		$this->registerService(IOutput::class, function () {
125
-			return new Output($this->getServer()->getWebRoot());
126
-		});
127
-
128
-		$this->registerService(Folder::class, function () {
129
-			return $this->getServer()->getUserFolder();
130
-		});
131
-
132
-		$this->registerService(IAppData::class, function (ContainerInterface $c) {
133
-			return $this->getServer()->getAppDataDir($c->get('AppName'));
134
-		});
135
-
136
-		$this->registerService(IL10N::class, function (ContainerInterface $c) {
137
-			return $this->getServer()->getL10N($c->get('AppName'));
138
-		});
139
-
140
-		// Log wrappers
141
-		$this->registerService(LoggerInterface::class, function (ContainerInterface $c) {
142
-			return new ScopedPsrLogger(
143
-				$c->get(PsrLoggerAdapter::class),
144
-				$c->get('AppName')
145
-			);
146
-		});
147
-		$this->registerService(ILogger::class, function (ContainerInterface $c) {
148
-			return new OC\AppFramework\Logger($this->server->query(ILogger::class), $c->get('AppName'));
149
-		});
150
-
151
-		$this->registerService(IServerContainer::class, function () {
152
-			return $this->getServer();
153
-		});
154
-		$this->registerAlias('ServerContainer', IServerContainer::class);
155
-
156
-		$this->registerService(\OCP\WorkflowEngine\IManager::class, function (ContainerInterface $c) {
157
-			return $c->get(Manager::class);
158
-		});
159
-
160
-		$this->registerService(ContainerInterface::class, function (ContainerInterface $c) {
161
-			return $c;
162
-		});
163
-		$this->registerAlias(IAppContainer::class, ContainerInterface::class);
164
-
165
-		// commonly used attributes
166
-		$this->registerService('userId', function (ContainerInterface $c) {
167
-			return $c->get(IUserSession::class)->getSession()->get('user_id');
168
-		});
169
-
170
-		$this->registerService('webRoot', function (ContainerInterface $c) {
171
-			return $c->get(IServerContainer::class)->getWebRoot();
172
-		});
173
-
174
-		$this->registerService('OC_Defaults', function (ContainerInterface $c) {
175
-			return $c->get(IServerContainer::class)->getThemingDefaults();
176
-		});
177
-
178
-		$this->registerService('Protocol', function (ContainerInterface $c) {
179
-			/** @var \OC\Server $server */
180
-			$server = $c->get(IServerContainer::class);
181
-			$protocol = $server->getRequest()->getHttpProtocol();
182
-			return new Http($_SERVER, $protocol);
183
-		});
184
-
185
-		$this->registerService('Dispatcher', function (ContainerInterface $c) {
186
-			return new Dispatcher(
187
-				$c->get('Protocol'),
188
-				$c->get(MiddlewareDispatcher::class),
189
-				$c->get(IControllerMethodReflector::class),
190
-				$c->get(IRequest::class),
191
-				$c->get(IConfig::class),
192
-				$c->get(IDBConnection::class),
193
-				$c->get(LoggerInterface::class),
194
-				$c->get(EventLogger::class),
195
-				$c,
196
-			);
197
-		});
198
-
199
-		/**
200
-		 * App Framework default arguments
201
-		 */
202
-		$this->registerParameter('corsMethods', 'PUT, POST, GET, DELETE, PATCH');
203
-		$this->registerParameter('corsAllowedHeaders', 'Authorization, Content-Type, Accept');
204
-		$this->registerParameter('corsMaxAge', 1728000);
205
-
206
-		/**
207
-		 * Middleware
208
-		 */
209
-		$this->registerAlias('MiddlewareDispatcher', MiddlewareDispatcher::class);
210
-		$this->registerService(MiddlewareDispatcher::class, function (ContainerInterface $c) {
211
-			$server = $this->getServer();
212
-
213
-			$dispatcher = new MiddlewareDispatcher();
214
-
215
-			$dispatcher->registerMiddleware(
216
-				$c->get(OC\AppFramework\Middleware\CompressionMiddleware::class)
217
-			);
218
-
219
-			$dispatcher->registerMiddleware($c->get(OC\AppFramework\Middleware\NotModifiedMiddleware::class));
220
-
221
-			$dispatcher->registerMiddleware(
222
-				$c->get(OC\AppFramework\Middleware\Security\ReloadExecutionMiddleware::class)
223
-			);
224
-
225
-			$dispatcher->registerMiddleware(
226
-				new OC\AppFramework\Middleware\Security\SameSiteCookieMiddleware(
227
-					$c->get(IRequest::class),
228
-					$c->get(IControllerMethodReflector::class)
229
-				)
230
-			);
231
-			$dispatcher->registerMiddleware(
232
-				new CORSMiddleware(
233
-					$c->get(IRequest::class),
234
-					$c->get(IControllerMethodReflector::class),
235
-					$c->get(IUserSession::class),
236
-					$c->get(OC\Security\Bruteforce\Throttler::class)
237
-				)
238
-			);
239
-			$dispatcher->registerMiddleware(
240
-				new OCSMiddleware(
241
-					$c->get(IRequest::class)
242
-				)
243
-			);
244
-
245
-
246
-
247
-			$securityMiddleware = new SecurityMiddleware(
248
-				$c->get(IRequest::class),
249
-				$c->get(IControllerMethodReflector::class),
250
-				$c->get(INavigationManager::class),
251
-				$c->get(IURLGenerator::class),
252
-				$server->get(LoggerInterface::class),
253
-				$c->get('AppName'),
254
-				$server->getUserSession()->isLoggedIn(),
255
-				$this->getUserId() !== null && $server->getGroupManager()->isAdmin($this->getUserId()),
256
-				$server->getUserSession()->getUser() !== null && $server->query(ISubAdmin::class)->isSubAdmin($server->getUserSession()->getUser()),
257
-				$server->getAppManager(),
258
-				$server->getL10N('lib'),
259
-				$c->get(AuthorizedGroupMapper::class),
260
-				$server->get(IUserSession::class)
261
-			);
262
-			$dispatcher->registerMiddleware($securityMiddleware);
263
-			$dispatcher->registerMiddleware(
264
-				new OC\AppFramework\Middleware\Security\CSPMiddleware(
265
-					$server->query(OC\Security\CSP\ContentSecurityPolicyManager::class),
266
-					$server->query(OC\Security\CSP\ContentSecurityPolicyNonceManager::class),
267
-					$server->query(OC\Security\CSRF\CsrfTokenManager::class)
268
-				)
269
-			);
270
-			$dispatcher->registerMiddleware(
271
-				$server->query(OC\AppFramework\Middleware\Security\FeaturePolicyMiddleware::class)
272
-			);
273
-			$dispatcher->registerMiddleware(
274
-				new OC\AppFramework\Middleware\Security\PasswordConfirmationMiddleware(
275
-					$c->get(IControllerMethodReflector::class),
276
-					$c->get(ISession::class),
277
-					$c->get(IUserSession::class),
278
-					$c->get(ITimeFactory::class)
279
-				)
280
-			);
281
-			$dispatcher->registerMiddleware(
282
-				new TwoFactorMiddleware(
283
-					$c->get(OC\Authentication\TwoFactorAuth\Manager::class),
284
-					$c->get(IUserSession::class),
285
-					$c->get(ISession::class),
286
-					$c->get(IURLGenerator::class),
287
-					$c->get(IControllerMethodReflector::class),
288
-					$c->get(IRequest::class)
289
-				)
290
-			);
291
-			$dispatcher->registerMiddleware(
292
-				new OC\AppFramework\Middleware\Security\BruteForceMiddleware(
293
-					$c->get(IControllerMethodReflector::class),
294
-					$c->get(OC\Security\Bruteforce\Throttler::class),
295
-					$c->get(IRequest::class)
296
-				)
297
-			);
298
-			$dispatcher->registerMiddleware(
299
-				new RateLimitingMiddleware(
300
-					$c->get(IRequest::class),
301
-					$c->get(IUserSession::class),
302
-					$c->get(IControllerMethodReflector::class),
303
-					$c->get(OC\Security\RateLimiting\Limiter::class)
304
-				)
305
-			);
306
-			$dispatcher->registerMiddleware(
307
-				new OC\AppFramework\Middleware\PublicShare\PublicShareMiddleware(
308
-					$c->get(IRequest::class),
309
-					$c->get(ISession::class),
310
-					$c->get(\OCP\IConfig::class),
311
-					$c->get(OC\Security\Bruteforce\Throttler::class)
312
-				)
313
-			);
314
-			$dispatcher->registerMiddleware(
315
-				$c->get(\OC\AppFramework\Middleware\AdditionalScriptsMiddleware::class)
316
-			);
317
-
318
-			foreach ($this->middleWares as $middleWare) {
319
-				$dispatcher->registerMiddleware($c->get($middleWare));
320
-			}
321
-
322
-			$dispatcher->registerMiddleware(
323
-				new SessionMiddleware(
324
-					$c->get(IControllerMethodReflector::class),
325
-					$c->get(ISession::class)
326
-				)
327
-			);
328
-			return $dispatcher;
329
-		});
330
-
331
-		$this->registerService(IAppConfig::class, function (ContainerInterface $c) {
332
-			return new OC\AppFramework\Services\AppConfig(
333
-				$c->get(IConfig::class),
334
-				$c->get('AppName')
335
-			);
336
-		});
337
-		$this->registerService(IInitialState::class, function (ContainerInterface $c) {
338
-			return new OC\AppFramework\Services\InitialState(
339
-				$c->get(IInitialStateService::class),
340
-				$c->get('AppName')
341
-			);
342
-		});
343
-	}
344
-
345
-	/**
346
-	 * @return \OCP\IServerContainer
347
-	 */
348
-	public function getServer() {
349
-		return $this->server;
350
-	}
351
-
352
-	/**
353
-	 * @param string $middleWare
354
-	 * @return boolean|null
355
-	 */
356
-	public function registerMiddleWare($middleWare) {
357
-		if (in_array($middleWare, $this->middleWares, true) !== false) {
358
-			return false;
359
-		}
360
-		$this->middleWares[] = $middleWare;
361
-	}
362
-
363
-	/**
364
-	 * used to return the appname of the set application
365
-	 * @return string the name of your application
366
-	 */
367
-	public function getAppName() {
368
-		return $this->query('AppName');
369
-	}
370
-
371
-	/**
372
-	 * @deprecated use IUserSession->isLoggedIn()
373
-	 * @return boolean
374
-	 */
375
-	public function isLoggedIn() {
376
-		return \OC::$server->getUserSession()->isLoggedIn();
377
-	}
378
-
379
-	/**
380
-	 * @deprecated use IGroupManager->isAdmin($userId)
381
-	 * @return boolean
382
-	 */
383
-	public function isAdminUser() {
384
-		$uid = $this->getUserId();
385
-		return \OC_User::isAdminUser($uid);
386
-	}
387
-
388
-	private function getUserId() {
389
-		return $this->getServer()->getSession()->get('user_id');
390
-	}
391
-
392
-	/**
393
-	 * @deprecated use the ILogger instead
394
-	 * @param string $message
395
-	 * @param string $level
396
-	 * @return mixed
397
-	 */
398
-	public function log($message, $level) {
399
-		switch ($level) {
400
-			case 'debug':
401
-				$level = ILogger::DEBUG;
402
-				break;
403
-			case 'info':
404
-				$level = ILogger::INFO;
405
-				break;
406
-			case 'warn':
407
-				$level = ILogger::WARN;
408
-				break;
409
-			case 'fatal':
410
-				$level = ILogger::FATAL;
411
-				break;
412
-			default:
413
-				$level = ILogger::ERROR;
414
-				break;
415
-		}
416
-		\OCP\Util::writeLog($this->getAppName(), $message, $level);
417
-	}
418
-
419
-	/**
420
-	 * Register a capability
421
-	 *
422
-	 * @param string $serviceName e.g. 'OCA\Files\Capabilities'
423
-	 */
424
-	public function registerCapability($serviceName) {
425
-		$this->query('OC\CapabilitiesManager')->registerCapability(function () use ($serviceName) {
426
-			return $this->query($serviceName);
427
-		});
428
-	}
429
-
430
-	public function has($id): bool {
431
-		if (parent::has($id)) {
432
-			return true;
433
-		}
434
-
435
-		if ($this->server->has($id, true)) {
436
-			return true;
437
-		}
438
-
439
-		return false;
440
-	}
441
-
442
-	public function query(string $name, bool $autoload = true) {
443
-		if ($name === 'AppName' || $name === 'appName') {
444
-			return $this->appName;
445
-		}
446
-
447
-		$isServerClass = str_starts_with($name, 'OCP\\') || str_starts_with($name, 'OC\\');
448
-		if ($isServerClass && !$this->has($name)) {
449
-			return $this->getServer()->query($name, $autoload);
450
-		}
451
-
452
-		try {
453
-			return $this->queryNoFallback($name);
454
-		} catch (QueryException $firstException) {
455
-			try {
456
-				return $this->getServer()->query($name, $autoload);
457
-			} catch (QueryException $secondException) {
458
-				if ($firstException->getCode() === 1) {
459
-					throw $secondException;
460
-				}
461
-				throw $firstException;
462
-			}
463
-		}
464
-	}
465
-
466
-	/**
467
-	 * @param string $name
468
-	 * @return mixed
469
-	 * @throws QueryException if the query could not be resolved
470
-	 */
471
-	public function queryNoFallback($name) {
472
-		$name = $this->sanitizeName($name);
473
-
474
-		if ($this->offsetExists($name)) {
475
-			return parent::query($name);
476
-		} elseif ($this->appName === 'settings' && str_starts_with($name, 'OC\\Settings\\')) {
477
-			return parent::query($name);
478
-		} elseif ($this->appName === 'core' && str_starts_with($name, 'OC\\Core\\')) {
479
-			return parent::query($name);
480
-		} elseif (str_starts_with($name, \OC\AppFramework\App::buildAppNamespace($this->appName) . '\\')) {
481
-			return parent::query($name);
482
-		}
483
-
484
-		throw new QueryException('Could not resolve ' . $name . '!' .
485
-			' Class can not be instantiated', 1);
486
-	}
82
+    private string $appName;
83
+
84
+    /**
85
+     * @var array
86
+     */
87
+    private $middleWares = [];
88
+
89
+    /** @var ServerContainer */
90
+    private $server;
91
+
92
+    /**
93
+     * Put your class dependencies in here
94
+     * @param string $appName the name of the app
95
+     * @param array $urlParams
96
+     * @param ServerContainer|null $server
97
+     */
98
+    public function __construct(string $appName, array $urlParams = [], ServerContainer $server = null) {
99
+        parent::__construct();
100
+        $this->appName = $appName;
101
+        $this['appName'] = $appName;
102
+        $this['urlParams'] = $urlParams;
103
+
104
+        $this->registerAlias('Request', IRequest::class);
105
+
106
+        /** @var \OC\ServerContainer $server */
107
+        if ($server === null) {
108
+            $server = \OC::$server;
109
+        }
110
+        $this->server = $server;
111
+        $this->server->registerAppContainer($appName, $this);
112
+
113
+        // aliases
114
+        /** @deprecated inject $appName */
115
+        $this->registerAlias('AppName', 'appName');
116
+        /** @deprecated inject $webRoot*/
117
+        $this->registerAlias('WebRoot', 'webRoot');
118
+        /** @deprecated inject $userId */
119
+        $this->registerAlias('UserId', 'userId');
120
+
121
+        /**
122
+         * Core services
123
+         */
124
+        $this->registerService(IOutput::class, function () {
125
+            return new Output($this->getServer()->getWebRoot());
126
+        });
127
+
128
+        $this->registerService(Folder::class, function () {
129
+            return $this->getServer()->getUserFolder();
130
+        });
131
+
132
+        $this->registerService(IAppData::class, function (ContainerInterface $c) {
133
+            return $this->getServer()->getAppDataDir($c->get('AppName'));
134
+        });
135
+
136
+        $this->registerService(IL10N::class, function (ContainerInterface $c) {
137
+            return $this->getServer()->getL10N($c->get('AppName'));
138
+        });
139
+
140
+        // Log wrappers
141
+        $this->registerService(LoggerInterface::class, function (ContainerInterface $c) {
142
+            return new ScopedPsrLogger(
143
+                $c->get(PsrLoggerAdapter::class),
144
+                $c->get('AppName')
145
+            );
146
+        });
147
+        $this->registerService(ILogger::class, function (ContainerInterface $c) {
148
+            return new OC\AppFramework\Logger($this->server->query(ILogger::class), $c->get('AppName'));
149
+        });
150
+
151
+        $this->registerService(IServerContainer::class, function () {
152
+            return $this->getServer();
153
+        });
154
+        $this->registerAlias('ServerContainer', IServerContainer::class);
155
+
156
+        $this->registerService(\OCP\WorkflowEngine\IManager::class, function (ContainerInterface $c) {
157
+            return $c->get(Manager::class);
158
+        });
159
+
160
+        $this->registerService(ContainerInterface::class, function (ContainerInterface $c) {
161
+            return $c;
162
+        });
163
+        $this->registerAlias(IAppContainer::class, ContainerInterface::class);
164
+
165
+        // commonly used attributes
166
+        $this->registerService('userId', function (ContainerInterface $c) {
167
+            return $c->get(IUserSession::class)->getSession()->get('user_id');
168
+        });
169
+
170
+        $this->registerService('webRoot', function (ContainerInterface $c) {
171
+            return $c->get(IServerContainer::class)->getWebRoot();
172
+        });
173
+
174
+        $this->registerService('OC_Defaults', function (ContainerInterface $c) {
175
+            return $c->get(IServerContainer::class)->getThemingDefaults();
176
+        });
177
+
178
+        $this->registerService('Protocol', function (ContainerInterface $c) {
179
+            /** @var \OC\Server $server */
180
+            $server = $c->get(IServerContainer::class);
181
+            $protocol = $server->getRequest()->getHttpProtocol();
182
+            return new Http($_SERVER, $protocol);
183
+        });
184
+
185
+        $this->registerService('Dispatcher', function (ContainerInterface $c) {
186
+            return new Dispatcher(
187
+                $c->get('Protocol'),
188
+                $c->get(MiddlewareDispatcher::class),
189
+                $c->get(IControllerMethodReflector::class),
190
+                $c->get(IRequest::class),
191
+                $c->get(IConfig::class),
192
+                $c->get(IDBConnection::class),
193
+                $c->get(LoggerInterface::class),
194
+                $c->get(EventLogger::class),
195
+                $c,
196
+            );
197
+        });
198
+
199
+        /**
200
+         * App Framework default arguments
201
+         */
202
+        $this->registerParameter('corsMethods', 'PUT, POST, GET, DELETE, PATCH');
203
+        $this->registerParameter('corsAllowedHeaders', 'Authorization, Content-Type, Accept');
204
+        $this->registerParameter('corsMaxAge', 1728000);
205
+
206
+        /**
207
+         * Middleware
208
+         */
209
+        $this->registerAlias('MiddlewareDispatcher', MiddlewareDispatcher::class);
210
+        $this->registerService(MiddlewareDispatcher::class, function (ContainerInterface $c) {
211
+            $server = $this->getServer();
212
+
213
+            $dispatcher = new MiddlewareDispatcher();
214
+
215
+            $dispatcher->registerMiddleware(
216
+                $c->get(OC\AppFramework\Middleware\CompressionMiddleware::class)
217
+            );
218
+
219
+            $dispatcher->registerMiddleware($c->get(OC\AppFramework\Middleware\NotModifiedMiddleware::class));
220
+
221
+            $dispatcher->registerMiddleware(
222
+                $c->get(OC\AppFramework\Middleware\Security\ReloadExecutionMiddleware::class)
223
+            );
224
+
225
+            $dispatcher->registerMiddleware(
226
+                new OC\AppFramework\Middleware\Security\SameSiteCookieMiddleware(
227
+                    $c->get(IRequest::class),
228
+                    $c->get(IControllerMethodReflector::class)
229
+                )
230
+            );
231
+            $dispatcher->registerMiddleware(
232
+                new CORSMiddleware(
233
+                    $c->get(IRequest::class),
234
+                    $c->get(IControllerMethodReflector::class),
235
+                    $c->get(IUserSession::class),
236
+                    $c->get(OC\Security\Bruteforce\Throttler::class)
237
+                )
238
+            );
239
+            $dispatcher->registerMiddleware(
240
+                new OCSMiddleware(
241
+                    $c->get(IRequest::class)
242
+                )
243
+            );
244
+
245
+
246
+
247
+            $securityMiddleware = new SecurityMiddleware(
248
+                $c->get(IRequest::class),
249
+                $c->get(IControllerMethodReflector::class),
250
+                $c->get(INavigationManager::class),
251
+                $c->get(IURLGenerator::class),
252
+                $server->get(LoggerInterface::class),
253
+                $c->get('AppName'),
254
+                $server->getUserSession()->isLoggedIn(),
255
+                $this->getUserId() !== null && $server->getGroupManager()->isAdmin($this->getUserId()),
256
+                $server->getUserSession()->getUser() !== null && $server->query(ISubAdmin::class)->isSubAdmin($server->getUserSession()->getUser()),
257
+                $server->getAppManager(),
258
+                $server->getL10N('lib'),
259
+                $c->get(AuthorizedGroupMapper::class),
260
+                $server->get(IUserSession::class)
261
+            );
262
+            $dispatcher->registerMiddleware($securityMiddleware);
263
+            $dispatcher->registerMiddleware(
264
+                new OC\AppFramework\Middleware\Security\CSPMiddleware(
265
+                    $server->query(OC\Security\CSP\ContentSecurityPolicyManager::class),
266
+                    $server->query(OC\Security\CSP\ContentSecurityPolicyNonceManager::class),
267
+                    $server->query(OC\Security\CSRF\CsrfTokenManager::class)
268
+                )
269
+            );
270
+            $dispatcher->registerMiddleware(
271
+                $server->query(OC\AppFramework\Middleware\Security\FeaturePolicyMiddleware::class)
272
+            );
273
+            $dispatcher->registerMiddleware(
274
+                new OC\AppFramework\Middleware\Security\PasswordConfirmationMiddleware(
275
+                    $c->get(IControllerMethodReflector::class),
276
+                    $c->get(ISession::class),
277
+                    $c->get(IUserSession::class),
278
+                    $c->get(ITimeFactory::class)
279
+                )
280
+            );
281
+            $dispatcher->registerMiddleware(
282
+                new TwoFactorMiddleware(
283
+                    $c->get(OC\Authentication\TwoFactorAuth\Manager::class),
284
+                    $c->get(IUserSession::class),
285
+                    $c->get(ISession::class),
286
+                    $c->get(IURLGenerator::class),
287
+                    $c->get(IControllerMethodReflector::class),
288
+                    $c->get(IRequest::class)
289
+                )
290
+            );
291
+            $dispatcher->registerMiddleware(
292
+                new OC\AppFramework\Middleware\Security\BruteForceMiddleware(
293
+                    $c->get(IControllerMethodReflector::class),
294
+                    $c->get(OC\Security\Bruteforce\Throttler::class),
295
+                    $c->get(IRequest::class)
296
+                )
297
+            );
298
+            $dispatcher->registerMiddleware(
299
+                new RateLimitingMiddleware(
300
+                    $c->get(IRequest::class),
301
+                    $c->get(IUserSession::class),
302
+                    $c->get(IControllerMethodReflector::class),
303
+                    $c->get(OC\Security\RateLimiting\Limiter::class)
304
+                )
305
+            );
306
+            $dispatcher->registerMiddleware(
307
+                new OC\AppFramework\Middleware\PublicShare\PublicShareMiddleware(
308
+                    $c->get(IRequest::class),
309
+                    $c->get(ISession::class),
310
+                    $c->get(\OCP\IConfig::class),
311
+                    $c->get(OC\Security\Bruteforce\Throttler::class)
312
+                )
313
+            );
314
+            $dispatcher->registerMiddleware(
315
+                $c->get(\OC\AppFramework\Middleware\AdditionalScriptsMiddleware::class)
316
+            );
317
+
318
+            foreach ($this->middleWares as $middleWare) {
319
+                $dispatcher->registerMiddleware($c->get($middleWare));
320
+            }
321
+
322
+            $dispatcher->registerMiddleware(
323
+                new SessionMiddleware(
324
+                    $c->get(IControllerMethodReflector::class),
325
+                    $c->get(ISession::class)
326
+                )
327
+            );
328
+            return $dispatcher;
329
+        });
330
+
331
+        $this->registerService(IAppConfig::class, function (ContainerInterface $c) {
332
+            return new OC\AppFramework\Services\AppConfig(
333
+                $c->get(IConfig::class),
334
+                $c->get('AppName')
335
+            );
336
+        });
337
+        $this->registerService(IInitialState::class, function (ContainerInterface $c) {
338
+            return new OC\AppFramework\Services\InitialState(
339
+                $c->get(IInitialStateService::class),
340
+                $c->get('AppName')
341
+            );
342
+        });
343
+    }
344
+
345
+    /**
346
+     * @return \OCP\IServerContainer
347
+     */
348
+    public function getServer() {
349
+        return $this->server;
350
+    }
351
+
352
+    /**
353
+     * @param string $middleWare
354
+     * @return boolean|null
355
+     */
356
+    public function registerMiddleWare($middleWare) {
357
+        if (in_array($middleWare, $this->middleWares, true) !== false) {
358
+            return false;
359
+        }
360
+        $this->middleWares[] = $middleWare;
361
+    }
362
+
363
+    /**
364
+     * used to return the appname of the set application
365
+     * @return string the name of your application
366
+     */
367
+    public function getAppName() {
368
+        return $this->query('AppName');
369
+    }
370
+
371
+    /**
372
+     * @deprecated use IUserSession->isLoggedIn()
373
+     * @return boolean
374
+     */
375
+    public function isLoggedIn() {
376
+        return \OC::$server->getUserSession()->isLoggedIn();
377
+    }
378
+
379
+    /**
380
+     * @deprecated use IGroupManager->isAdmin($userId)
381
+     * @return boolean
382
+     */
383
+    public function isAdminUser() {
384
+        $uid = $this->getUserId();
385
+        return \OC_User::isAdminUser($uid);
386
+    }
387
+
388
+    private function getUserId() {
389
+        return $this->getServer()->getSession()->get('user_id');
390
+    }
391
+
392
+    /**
393
+     * @deprecated use the ILogger instead
394
+     * @param string $message
395
+     * @param string $level
396
+     * @return mixed
397
+     */
398
+    public function log($message, $level) {
399
+        switch ($level) {
400
+            case 'debug':
401
+                $level = ILogger::DEBUG;
402
+                break;
403
+            case 'info':
404
+                $level = ILogger::INFO;
405
+                break;
406
+            case 'warn':
407
+                $level = ILogger::WARN;
408
+                break;
409
+            case 'fatal':
410
+                $level = ILogger::FATAL;
411
+                break;
412
+            default:
413
+                $level = ILogger::ERROR;
414
+                break;
415
+        }
416
+        \OCP\Util::writeLog($this->getAppName(), $message, $level);
417
+    }
418
+
419
+    /**
420
+     * Register a capability
421
+     *
422
+     * @param string $serviceName e.g. 'OCA\Files\Capabilities'
423
+     */
424
+    public function registerCapability($serviceName) {
425
+        $this->query('OC\CapabilitiesManager')->registerCapability(function () use ($serviceName) {
426
+            return $this->query($serviceName);
427
+        });
428
+    }
429
+
430
+    public function has($id): bool {
431
+        if (parent::has($id)) {
432
+            return true;
433
+        }
434
+
435
+        if ($this->server->has($id, true)) {
436
+            return true;
437
+        }
438
+
439
+        return false;
440
+    }
441
+
442
+    public function query(string $name, bool $autoload = true) {
443
+        if ($name === 'AppName' || $name === 'appName') {
444
+            return $this->appName;
445
+        }
446
+
447
+        $isServerClass = str_starts_with($name, 'OCP\\') || str_starts_with($name, 'OC\\');
448
+        if ($isServerClass && !$this->has($name)) {
449
+            return $this->getServer()->query($name, $autoload);
450
+        }
451
+
452
+        try {
453
+            return $this->queryNoFallback($name);
454
+        } catch (QueryException $firstException) {
455
+            try {
456
+                return $this->getServer()->query($name, $autoload);
457
+            } catch (QueryException $secondException) {
458
+                if ($firstException->getCode() === 1) {
459
+                    throw $secondException;
460
+                }
461
+                throw $firstException;
462
+            }
463
+        }
464
+    }
465
+
466
+    /**
467
+     * @param string $name
468
+     * @return mixed
469
+     * @throws QueryException if the query could not be resolved
470
+     */
471
+    public function queryNoFallback($name) {
472
+        $name = $this->sanitizeName($name);
473
+
474
+        if ($this->offsetExists($name)) {
475
+            return parent::query($name);
476
+        } elseif ($this->appName === 'settings' && str_starts_with($name, 'OC\\Settings\\')) {
477
+            return parent::query($name);
478
+        } elseif ($this->appName === 'core' && str_starts_with($name, 'OC\\Core\\')) {
479
+            return parent::query($name);
480
+        } elseif (str_starts_with($name, \OC\AppFramework\App::buildAppNamespace($this->appName) . '\\')) {
481
+            return parent::query($name);
482
+        }
483
+
484
+        throw new QueryException('Could not resolve ' . $name . '!' .
485
+            ' Class can not be instantiated', 1);
486
+    }
487 487
 }
Please login to merge, or discard this patch.
lib/private/AppFramework/Http/Dispatcher.php 1 patch
Indentation   +203 added lines, -203 removed lines patch added patch discarded remove patch
@@ -50,207 +50,207 @@
 block discarded – undo
50 50
  */
51 51
 class Dispatcher {
52 52
 
53
-	/** @var MiddlewareDispatcher */
54
-	private $middlewareDispatcher;
55
-
56
-	/** @var Http */
57
-	private $protocol;
58
-
59
-	/** @var ControllerMethodReflector */
60
-	private $reflector;
61
-
62
-	/** @var IRequest */
63
-	private $request;
64
-
65
-	/** @var IConfig */
66
-	private $config;
67
-
68
-	/** @var ConnectionAdapter */
69
-	private $connection;
70
-
71
-	/** @var LoggerInterface */
72
-	private $logger;
73
-
74
-	/** @var IEventLogger */
75
-	private $eventLogger;
76
-
77
-	private ContainerInterface $appContainer;
78
-
79
-	/**
80
-	 * @param Http $protocol the http protocol with contains all status headers
81
-	 * @param MiddlewareDispatcher $middlewareDispatcher the dispatcher which
82
-	 * runs the middleware
83
-	 * @param ControllerMethodReflector $reflector the reflector that is used to inject
84
-	 * the arguments for the controller
85
-	 * @param IRequest $request the incoming request
86
-	 * @param IConfig $config
87
-	 * @param ConnectionAdapter $connection
88
-	 * @param LoggerInterface $logger
89
-	 * @param IEventLogger $eventLogger
90
-	 */
91
-	public function __construct(Http $protocol,
92
-								MiddlewareDispatcher $middlewareDispatcher,
93
-								ControllerMethodReflector $reflector,
94
-								IRequest $request,
95
-								IConfig $config,
96
-								ConnectionAdapter $connection,
97
-								LoggerInterface $logger,
98
-								IEventLogger $eventLogger,
99
-								ContainerInterface $appContainer) {
100
-		$this->protocol = $protocol;
101
-		$this->middlewareDispatcher = $middlewareDispatcher;
102
-		$this->reflector = $reflector;
103
-		$this->request = $request;
104
-		$this->config = $config;
105
-		$this->connection = $connection;
106
-		$this->logger = $logger;
107
-		$this->eventLogger = $eventLogger;
108
-		$this->appContainer = $appContainer;
109
-	}
110
-
111
-
112
-	/**
113
-	 * Handles a request and calls the dispatcher on the controller
114
-	 * @param Controller $controller the controller which will be called
115
-	 * @param string $methodName the method name which will be called on
116
-	 * the controller
117
-	 * @return array $array[0] contains a string with the http main header,
118
-	 * $array[1] contains headers in the form: $key => value, $array[2] contains
119
-	 * the response output
120
-	 * @throws \Exception
121
-	 */
122
-	public function dispatch(Controller $controller, string $methodName): array {
123
-		$out = [null, [], null];
124
-
125
-		try {
126
-			// prefill reflector with everything that's needed for the
127
-			// middlewares
128
-			$this->reflector->reflect($controller, $methodName);
129
-
130
-			$this->middlewareDispatcher->beforeController($controller,
131
-				$methodName);
132
-
133
-			$databaseStatsBefore = [];
134
-			if ($this->config->getSystemValueBool('debug', false)) {
135
-				$databaseStatsBefore = $this->connection->getInner()->getStats();
136
-			}
137
-
138
-			$response = $this->executeController($controller, $methodName);
139
-
140
-			if (!empty($databaseStatsBefore)) {
141
-				$databaseStatsAfter = $this->connection->getInner()->getStats();
142
-				$numBuilt = $databaseStatsAfter['built'] - $databaseStatsBefore['built'];
143
-				$numExecuted = $databaseStatsAfter['executed'] - $databaseStatsBefore['executed'];
144
-
145
-				if ($numBuilt > 50) {
146
-					$this->logger->debug('Controller {class}::{method} created {count} QueryBuilder objects, please check if they are created inside a loop by accident.', [
147
-						'class' => get_class($controller),
148
-						'method' => $methodName,
149
-						'count' => $numBuilt,
150
-					]);
151
-				}
152
-
153
-				if ($numExecuted > 100) {
154
-					$this->logger->warning('Controller {class}::{method} executed {count} queries.', [
155
-						'class' => get_class($controller),
156
-						'method' => $methodName,
157
-						'count' => $numExecuted,
158
-					]);
159
-				}
160
-			}
161
-
162
-			// if an exception appears, the middleware checks if it can handle the
163
-			// exception and creates a response. If no response is created, it is
164
-			// assumed that there's no middleware who can handle it and the error is
165
-			// thrown again
166
-		} catch (\Exception $exception) {
167
-			$response = $this->middlewareDispatcher->afterException(
168
-				$controller, $methodName, $exception);
169
-		} catch (\Throwable $throwable) {
170
-			$exception = new \Exception($throwable->getMessage() . ' in file \'' . $throwable->getFile() . '\' line ' . $throwable->getLine(), $throwable->getCode(), $throwable);
171
-			$response = $this->middlewareDispatcher->afterException(
172
-			$controller, $methodName, $exception);
173
-		}
174
-
175
-		$response = $this->middlewareDispatcher->afterController(
176
-			$controller, $methodName, $response);
177
-
178
-		// depending on the cache object the headers need to be changed
179
-		$out[0] = $this->protocol->getStatusHeader($response->getStatus());
180
-		$out[1] = array_merge($response->getHeaders());
181
-		$out[2] = $response->getCookies();
182
-		$out[3] = $this->middlewareDispatcher->beforeOutput(
183
-			$controller, $methodName, $response->render()
184
-		);
185
-		$out[4] = $response;
186
-
187
-		return $out;
188
-	}
189
-
190
-
191
-	/**
192
-	 * Uses the reflected parameters, types and request parameters to execute
193
-	 * the controller
194
-	 * @param Controller $controller the controller to be executed
195
-	 * @param string $methodName the method on the controller that should be executed
196
-	 * @return Response
197
-	 */
198
-	private function executeController(Controller $controller, string $methodName): Response {
199
-		$arguments = [];
200
-
201
-		// valid types that will be casted
202
-		$types = ['int', 'integer', 'bool', 'boolean', 'float', 'double'];
203
-
204
-		foreach ($this->reflector->getParameters() as $param => $default) {
205
-
206
-			// try to get the parameter from the request object and cast
207
-			// it to the type annotated in the @param annotation
208
-			$value = $this->request->getParam($param, $default);
209
-			$type = $this->reflector->getType($param);
210
-
211
-			// if this is submitted using GET or a POST form, 'false' should be
212
-			// converted to false
213
-			if (($type === 'bool' || $type === 'boolean') &&
214
-				$value === 'false' &&
215
-				(
216
-					$this->request->method === 'GET' ||
217
-					strpos($this->request->getHeader('Content-Type'),
218
-						'application/x-www-form-urlencoded') !== false
219
-				)
220
-			) {
221
-				$value = false;
222
-			} elseif ($value !== null && \in_array($type, $types, true)) {
223
-				settype($value, $type);
224
-			} elseif ($value === null && $type !== null && $this->appContainer->has($type)) {
225
-				$value = $this->appContainer->get($type);
226
-			}
227
-
228
-			$arguments[] = $value;
229
-		}
230
-
231
-		$this->eventLogger->start('controller:' . get_class($controller) . '::' . $methodName, 'App framework controller execution');
232
-		$response = \call_user_func_array([$controller, $methodName], $arguments);
233
-		$this->eventLogger->end('controller:' . get_class($controller) . '::' . $methodName);
234
-
235
-		// format response
236
-		if ($response instanceof DataResponse || !($response instanceof Response)) {
237
-
238
-			// get format from the url format or request format parameter
239
-			$format = $this->request->getParam('format');
240
-
241
-			// if none is given try the first Accept header
242
-			if ($format === null) {
243
-				$headers = $this->request->getHeader('Accept');
244
-				$format = $controller->getResponderByHTTPHeader($headers, null);
245
-			}
246
-
247
-			if ($format !== null) {
248
-				$response = $controller->buildResponse($response, $format);
249
-			} else {
250
-				$response = $controller->buildResponse($response);
251
-			}
252
-		}
253
-
254
-		return $response;
255
-	}
53
+    /** @var MiddlewareDispatcher */
54
+    private $middlewareDispatcher;
55
+
56
+    /** @var Http */
57
+    private $protocol;
58
+
59
+    /** @var ControllerMethodReflector */
60
+    private $reflector;
61
+
62
+    /** @var IRequest */
63
+    private $request;
64
+
65
+    /** @var IConfig */
66
+    private $config;
67
+
68
+    /** @var ConnectionAdapter */
69
+    private $connection;
70
+
71
+    /** @var LoggerInterface */
72
+    private $logger;
73
+
74
+    /** @var IEventLogger */
75
+    private $eventLogger;
76
+
77
+    private ContainerInterface $appContainer;
78
+
79
+    /**
80
+     * @param Http $protocol the http protocol with contains all status headers
81
+     * @param MiddlewareDispatcher $middlewareDispatcher the dispatcher which
82
+     * runs the middleware
83
+     * @param ControllerMethodReflector $reflector the reflector that is used to inject
84
+     * the arguments for the controller
85
+     * @param IRequest $request the incoming request
86
+     * @param IConfig $config
87
+     * @param ConnectionAdapter $connection
88
+     * @param LoggerInterface $logger
89
+     * @param IEventLogger $eventLogger
90
+     */
91
+    public function __construct(Http $protocol,
92
+                                MiddlewareDispatcher $middlewareDispatcher,
93
+                                ControllerMethodReflector $reflector,
94
+                                IRequest $request,
95
+                                IConfig $config,
96
+                                ConnectionAdapter $connection,
97
+                                LoggerInterface $logger,
98
+                                IEventLogger $eventLogger,
99
+                                ContainerInterface $appContainer) {
100
+        $this->protocol = $protocol;
101
+        $this->middlewareDispatcher = $middlewareDispatcher;
102
+        $this->reflector = $reflector;
103
+        $this->request = $request;
104
+        $this->config = $config;
105
+        $this->connection = $connection;
106
+        $this->logger = $logger;
107
+        $this->eventLogger = $eventLogger;
108
+        $this->appContainer = $appContainer;
109
+    }
110
+
111
+
112
+    /**
113
+     * Handles a request and calls the dispatcher on the controller
114
+     * @param Controller $controller the controller which will be called
115
+     * @param string $methodName the method name which will be called on
116
+     * the controller
117
+     * @return array $array[0] contains a string with the http main header,
118
+     * $array[1] contains headers in the form: $key => value, $array[2] contains
119
+     * the response output
120
+     * @throws \Exception
121
+     */
122
+    public function dispatch(Controller $controller, string $methodName): array {
123
+        $out = [null, [], null];
124
+
125
+        try {
126
+            // prefill reflector with everything that's needed for the
127
+            // middlewares
128
+            $this->reflector->reflect($controller, $methodName);
129
+
130
+            $this->middlewareDispatcher->beforeController($controller,
131
+                $methodName);
132
+
133
+            $databaseStatsBefore = [];
134
+            if ($this->config->getSystemValueBool('debug', false)) {
135
+                $databaseStatsBefore = $this->connection->getInner()->getStats();
136
+            }
137
+
138
+            $response = $this->executeController($controller, $methodName);
139
+
140
+            if (!empty($databaseStatsBefore)) {
141
+                $databaseStatsAfter = $this->connection->getInner()->getStats();
142
+                $numBuilt = $databaseStatsAfter['built'] - $databaseStatsBefore['built'];
143
+                $numExecuted = $databaseStatsAfter['executed'] - $databaseStatsBefore['executed'];
144
+
145
+                if ($numBuilt > 50) {
146
+                    $this->logger->debug('Controller {class}::{method} created {count} QueryBuilder objects, please check if they are created inside a loop by accident.', [
147
+                        'class' => get_class($controller),
148
+                        'method' => $methodName,
149
+                        'count' => $numBuilt,
150
+                    ]);
151
+                }
152
+
153
+                if ($numExecuted > 100) {
154
+                    $this->logger->warning('Controller {class}::{method} executed {count} queries.', [
155
+                        'class' => get_class($controller),
156
+                        'method' => $methodName,
157
+                        'count' => $numExecuted,
158
+                    ]);
159
+                }
160
+            }
161
+
162
+            // if an exception appears, the middleware checks if it can handle the
163
+            // exception and creates a response. If no response is created, it is
164
+            // assumed that there's no middleware who can handle it and the error is
165
+            // thrown again
166
+        } catch (\Exception $exception) {
167
+            $response = $this->middlewareDispatcher->afterException(
168
+                $controller, $methodName, $exception);
169
+        } catch (\Throwable $throwable) {
170
+            $exception = new \Exception($throwable->getMessage() . ' in file \'' . $throwable->getFile() . '\' line ' . $throwable->getLine(), $throwable->getCode(), $throwable);
171
+            $response = $this->middlewareDispatcher->afterException(
172
+            $controller, $methodName, $exception);
173
+        }
174
+
175
+        $response = $this->middlewareDispatcher->afterController(
176
+            $controller, $methodName, $response);
177
+
178
+        // depending on the cache object the headers need to be changed
179
+        $out[0] = $this->protocol->getStatusHeader($response->getStatus());
180
+        $out[1] = array_merge($response->getHeaders());
181
+        $out[2] = $response->getCookies();
182
+        $out[3] = $this->middlewareDispatcher->beforeOutput(
183
+            $controller, $methodName, $response->render()
184
+        );
185
+        $out[4] = $response;
186
+
187
+        return $out;
188
+    }
189
+
190
+
191
+    /**
192
+     * Uses the reflected parameters, types and request parameters to execute
193
+     * the controller
194
+     * @param Controller $controller the controller to be executed
195
+     * @param string $methodName the method on the controller that should be executed
196
+     * @return Response
197
+     */
198
+    private function executeController(Controller $controller, string $methodName): Response {
199
+        $arguments = [];
200
+
201
+        // valid types that will be casted
202
+        $types = ['int', 'integer', 'bool', 'boolean', 'float', 'double'];
203
+
204
+        foreach ($this->reflector->getParameters() as $param => $default) {
205
+
206
+            // try to get the parameter from the request object and cast
207
+            // it to the type annotated in the @param annotation
208
+            $value = $this->request->getParam($param, $default);
209
+            $type = $this->reflector->getType($param);
210
+
211
+            // if this is submitted using GET or a POST form, 'false' should be
212
+            // converted to false
213
+            if (($type === 'bool' || $type === 'boolean') &&
214
+                $value === 'false' &&
215
+                (
216
+                    $this->request->method === 'GET' ||
217
+                    strpos($this->request->getHeader('Content-Type'),
218
+                        'application/x-www-form-urlencoded') !== false
219
+                )
220
+            ) {
221
+                $value = false;
222
+            } elseif ($value !== null && \in_array($type, $types, true)) {
223
+                settype($value, $type);
224
+            } elseif ($value === null && $type !== null && $this->appContainer->has($type)) {
225
+                $value = $this->appContainer->get($type);
226
+            }
227
+
228
+            $arguments[] = $value;
229
+        }
230
+
231
+        $this->eventLogger->start('controller:' . get_class($controller) . '::' . $methodName, 'App framework controller execution');
232
+        $response = \call_user_func_array([$controller, $methodName], $arguments);
233
+        $this->eventLogger->end('controller:' . get_class($controller) . '::' . $methodName);
234
+
235
+        // format response
236
+        if ($response instanceof DataResponse || !($response instanceof Response)) {
237
+
238
+            // get format from the url format or request format parameter
239
+            $format = $this->request->getParam('format');
240
+
241
+            // if none is given try the first Accept header
242
+            if ($format === null) {
243
+                $headers = $this->request->getHeader('Accept');
244
+                $format = $controller->getResponderByHTTPHeader($headers, null);
245
+            }
246
+
247
+            if ($format !== null) {
248
+                $response = $controller->buildResponse($response, $format);
249
+            } else {
250
+                $response = $controller->buildResponse($response);
251
+            }
252
+        }
253
+
254
+        return $response;
255
+    }
256 256
 }
Please login to merge, or discard this patch.