2018-05-18 13:28:52 +03:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* @copyright 2018, Roeland Jago Douma <roeland@famdouma.nl>
|
|
|
|
*
|
|
|
|
* @author Roeland Jago Douma <roeland@famdouma.nl>
|
|
|
|
*
|
|
|
|
* @license GNU AGPL version 3 or any later version
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Affero General Public License as
|
|
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Affero General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
2019-12-03 21:57:53 +03:00
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2018-05-18 13:28:52 +03:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
namespace OCP\AppFramework;
|
|
|
|
|
|
|
|
use OCP\AppFramework\Http\RedirectResponse;
|
|
|
|
use OCP\AppFramework\Http\TemplateResponse;
|
|
|
|
use OCP\IRequest;
|
|
|
|
use OCP\ISession;
|
|
|
|
use OCP\IURLGenerator;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Base controller for interactive public shares
|
|
|
|
*
|
|
|
|
* It will verify if the user is properly authenticated to the share. If not the
|
|
|
|
* user will be redirected to an authentication page.
|
|
|
|
*
|
|
|
|
* Use this for a controller that is to be called directly by a user. So the
|
|
|
|
* normal public share page for files/calendars etc.
|
|
|
|
*
|
|
|
|
* @since 14.0.0
|
|
|
|
*/
|
|
|
|
abstract class AuthPublicShareController extends PublicShareController {
|
|
|
|
|
|
|
|
/** @var IURLGenerator */
|
|
|
|
protected $urlGenerator;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @since 14.0.0
|
|
|
|
*/
|
|
|
|
public function __construct(string $appName,
|
|
|
|
IRequest $request,
|
|
|
|
ISession $session,
|
|
|
|
IURLGenerator $urlGenerator) {
|
|
|
|
parent::__construct($appName, $request, $session);
|
|
|
|
|
|
|
|
$this->urlGenerator = $urlGenerator;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @PublicPage
|
|
|
|
* @NoCSRFRequired
|
|
|
|
*
|
|
|
|
* Show the authentication page
|
|
|
|
* The form has to submit to the authenticate method route
|
|
|
|
*
|
|
|
|
* @since 14.0.0
|
|
|
|
*/
|
2018-06-11 15:15:03 +03:00
|
|
|
public function showAuthenticate(): TemplateResponse {
|
|
|
|
return new TemplateResponse('core', 'publicshareauth', [], 'guest');
|
|
|
|
}
|
2018-05-18 13:28:52 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The template to show when authentication failed
|
|
|
|
*
|
|
|
|
* @since 14.0.0
|
|
|
|
*/
|
2018-06-11 15:15:03 +03:00
|
|
|
protected function showAuthFailed(): TemplateResponse {
|
|
|
|
return new TemplateResponse('core', 'publicshareauth', ['wrongpw' => true], 'guest');
|
|
|
|
}
|
2018-05-18 13:28:52 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Verify the password
|
|
|
|
*
|
|
|
|
* @since 14.0.0
|
|
|
|
*/
|
|
|
|
abstract protected function verifyPassword(string $password): bool;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function called after failed authentication
|
|
|
|
*
|
|
|
|
* You can use this to do some logging for example
|
|
|
|
*
|
|
|
|
* @since 14.0.0
|
|
|
|
*/
|
|
|
|
protected function authFailed() {
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function called after successfull authentication
|
|
|
|
*
|
|
|
|
* You can use this to do some logging for example
|
|
|
|
*
|
|
|
|
* @since 14.0.0
|
|
|
|
*/
|
|
|
|
protected function authSucceeded() {
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @UseSession
|
|
|
|
* @PublicPage
|
|
|
|
* @BruteForceProtection(action=publicLinkAuth)
|
|
|
|
*
|
|
|
|
* Authenticate the share
|
|
|
|
*
|
|
|
|
* @since 14.0.0
|
|
|
|
*/
|
|
|
|
final public function authenticate(string $password = '') {
|
|
|
|
// Already authenticated
|
|
|
|
if ($this->isAuthenticated()) {
|
|
|
|
return $this->getRedirect();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$this->verifyPassword($password)) {
|
|
|
|
$this->authFailed();
|
|
|
|
$response = $this->showAuthFailed();
|
|
|
|
$response->throttle();
|
|
|
|
return $response;
|
|
|
|
}
|
|
|
|
|
2018-06-19 12:45:18 +03:00
|
|
|
$this->session->regenerateId(true, true);
|
2018-05-18 13:28:52 +03:00
|
|
|
$response = $this->getRedirect();
|
|
|
|
|
|
|
|
$this->session->set('public_link_authenticated_token', $this->getToken());
|
|
|
|
$this->session->set('public_link_authenticated_password_hash', $this->getPasswordHash());
|
|
|
|
|
|
|
|
$this->authSucceeded();
|
|
|
|
|
|
|
|
return $response;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Default landing page
|
|
|
|
*
|
|
|
|
* @since 14.0.0
|
|
|
|
*/
|
|
|
|
abstract public function showShare(): TemplateResponse;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @since 14.0.0
|
|
|
|
*/
|
|
|
|
final public function getAuthenticationRedirect(string $redirect): RedirectResponse {
|
|
|
|
return new RedirectResponse(
|
|
|
|
$this->urlGenerator->linkToRoute($this->getRoute('showAuthenticate'), ['token' => $this->getToken(), 'redirect' => $redirect])
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-02-14 14:12:04 +03:00
|
|
|
/**
|
|
|
|
* @param $string
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
private function camelCaseToLowerCaseUnderscored($string)
|
|
|
|
{
|
|
|
|
$value = preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $string);
|
|
|
|
return mb_strtolower($value, 'utf-8');
|
|
|
|
}
|
|
|
|
|
2018-05-18 13:28:52 +03:00
|
|
|
/**
|
|
|
|
* @since 14.0.0
|
|
|
|
*/
|
|
|
|
private function getRoute(string $function): string {
|
|
|
|
$app = strtolower($this->appName);
|
2020-02-14 14:12:04 +03:00
|
|
|
$class = (new \ReflectionClass($this))->getShortName();
|
|
|
|
// $class = $this->camelCaseToLowerCaseUnderscored(substr($class, 0, strpos($class, 'Controller')));
|
|
|
|
return $app .'.'. $class .'.'. $function;
|
2018-05-18 13:28:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @since 14.0.0
|
|
|
|
*/
|
|
|
|
private function getRedirect(): RedirectResponse {
|
|
|
|
//Get all the stored redirect parameters:
|
|
|
|
$params = $this->session->get('public_link_authenticate_redirect');
|
|
|
|
|
|
|
|
$route = $this->getRoute('showShare');
|
|
|
|
|
|
|
|
if ($params === null) {
|
2018-06-19 22:40:45 +03:00
|
|
|
$params = [
|
|
|
|
'token' => $this->getToken(),
|
|
|
|
];
|
2018-05-18 13:28:52 +03:00
|
|
|
} else {
|
|
|
|
$params = json_decode($params, true);
|
|
|
|
if (isset($params['_route'])) {
|
|
|
|
$route = $params['_route'];
|
|
|
|
unset($params['_route']);
|
|
|
|
}
|
2019-05-23 14:42:59 +03:00
|
|
|
|
|
|
|
// If the token doesn't match the rest of the arguments can't be trusted either
|
|
|
|
if (isset($params['token']) && $params['token'] !== $this->getToken()) {
|
|
|
|
$params = [
|
|
|
|
'token' => $this->getToken(),
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
// We need a token
|
|
|
|
if (!isset($params['token'])) {
|
|
|
|
$params = [
|
|
|
|
'token' => $this->getToken(),
|
|
|
|
];
|
|
|
|
}
|
2018-05-18 13:28:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return new RedirectResponse($this->urlGenerator->linkToRoute($route, $params));
|
|
|
|
}
|
|
|
|
}
|