Merge pull request #15104 from nextcloud/enh/remote_wipe
Remote wipe support
This commit is contained in:
commit
50dbdeea46
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -28,6 +28,7 @@
|
|||
|
||||
namespace OC\Core;
|
||||
|
||||
use OC\Authentication\Notifications\Notifier as AuthenticationNotifier;
|
||||
use OC\Core\Notification\RemoveLinkSharesNotifier;
|
||||
use OC\DB\MissingIndexInformation;
|
||||
use OC\DB\SchemaWrapper;
|
||||
|
@ -60,12 +61,20 @@ class Application extends App {
|
|||
return new RemoveLinkSharesNotifier(
|
||||
$server->getL10NFactory()
|
||||
);
|
||||
}, function() use ($server) {
|
||||
}, function() {
|
||||
return [
|
||||
'id' => 'core',
|
||||
'name' => 'core',
|
||||
];
|
||||
});
|
||||
$notificationManager->registerNotifier(function() use ($server) {
|
||||
return $server->query(AuthenticationNotifier::class);
|
||||
}, function() {
|
||||
return [
|
||||
'id' => 'auth',
|
||||
'name' => 'authentication notifier',
|
||||
];
|
||||
});
|
||||
|
||||
$eventDispatcher->addListener(IDBConnection::CHECK_MISSING_INDEXES_EVENT,
|
||||
function(GenericEvent $event) use ($container) {
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright Copyright (c) 2019, 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OC\Core\Controller;
|
||||
|
||||
use OC\Authentication\Exceptions\InvalidTokenException;
|
||||
use OC\Authentication\Token\RemoteWipe;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\AppFramework\Http\JSONResponse;
|
||||
use OCP\IRequest;
|
||||
|
||||
class WipeController extends Controller {
|
||||
|
||||
/** @var RemoteWipe */
|
||||
private $remoteWipe;
|
||||
|
||||
public function __construct(string $appName,
|
||||
IRequest $request,
|
||||
RemoteWipe $remoteWipe) {
|
||||
parent::__construct($appName, $request);
|
||||
|
||||
$this->remoteWipe = $remoteWipe;
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
* @NoCSRFRequired
|
||||
* @PublicPage
|
||||
*
|
||||
* @AnonRateThrottle(limit=10, period=300)
|
||||
*
|
||||
* @param string $token
|
||||
*
|
||||
* @return JSONResponse
|
||||
*/
|
||||
public function checkWipe(string $token): JSONResponse {
|
||||
try {
|
||||
if ($this->remoteWipe->start($token)) {
|
||||
return new JSONResponse([
|
||||
'wipe' => true
|
||||
]);
|
||||
}
|
||||
|
||||
return new JSONResponse([], Http::STATUS_NOT_FOUND);
|
||||
} catch (InvalidTokenException $e) {
|
||||
return new JSONResponse([], Http::STATUS_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
* @NoCSRFRequired
|
||||
* @PublicPage
|
||||
*
|
||||
* @AnonRateThrottle(limit=10, period=300)
|
||||
*
|
||||
* @param string $token
|
||||
*
|
||||
* @return JSONResponse
|
||||
*/
|
||||
public function wipeDone(string $token): JSONResponse {
|
||||
try {
|
||||
if ($this->remoteWipe->finish($token)) {
|
||||
return new JSONResponse([]);
|
||||
}
|
||||
|
||||
return new JSONResponse([], Http::STATUS_NOT_FOUND);
|
||||
} catch (InvalidTokenException $e) {
|
||||
return new JSONResponse([], Http::STATUS_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -81,6 +81,8 @@ $application->registerRoutes($this, [
|
|||
['name' => 'contactsMenu#findOne', 'url' => '/contactsmenu/findOne', 'verb' => 'POST'],
|
||||
['name' => 'WalledGarden#get', 'url' => '/204', 'verb' => 'GET'],
|
||||
['name' => 'Search#search', 'url' => '/core/search', 'verb' => 'GET'],
|
||||
['name' => 'Wipe#checkWipe', 'url' => '/core/wipe/check', 'verb' => 'POST'],
|
||||
['name' => 'Wipe#wipeDone', 'url' => '/core/wipe/success', 'verb' => 'POST'],
|
||||
|
||||
// Legacy routes that need to be globally available while they are handled by an app
|
||||
['name' => 'viewcontroller#showFile', 'url' => '/f/{fileid}', 'verb' => 'GET', 'app' => 'files'],
|
||||
|
|
|
@ -512,6 +512,7 @@ return array(
|
|||
'OC\\Authentication\\Exceptions\\PasswordlessTokenException' => $baseDir . '/lib/private/Authentication/Exceptions/PasswordlessTokenException.php',
|
||||
'OC\\Authentication\\Exceptions\\TwoFactorAuthRequiredException' => $baseDir . '/lib/private/Authentication/Exceptions/TwoFactorAuthRequiredException.php',
|
||||
'OC\\Authentication\\Exceptions\\UserAlreadyLoggedInException' => $baseDir . '/lib/private/Authentication/Exceptions/UserAlreadyLoggedInException.php',
|
||||
'OC\\Authentication\\Exceptions\\WipeTokenException' => $baseDir . '/lib/private/Authentication/Exceptions/WipeTokenException.php',
|
||||
'OC\\Authentication\\LoginCredentials\\Credentials' => $baseDir . '/lib/private/Authentication/LoginCredentials/Credentials.php',
|
||||
'OC\\Authentication\\LoginCredentials\\Store' => $baseDir . '/lib/private/Authentication/LoginCredentials/Store.php',
|
||||
'OC\\Authentication\\Login\\ALoginCommand' => $baseDir . '/lib/private/Authentication/Login/ALoginCommand.php',
|
||||
|
@ -530,6 +531,7 @@ return array(
|
|||
'OC\\Authentication\\Login\\UidLoginCommand' => $baseDir . '/lib/private/Authentication/Login/UidLoginCommand.php',
|
||||
'OC\\Authentication\\Login\\UpdateLastPasswordConfirmCommand' => $baseDir . '/lib/private/Authentication/Login/UpdateLastPasswordConfirmCommand.php',
|
||||
'OC\\Authentication\\Login\\UserDisabledCheckCommand' => $baseDir . '/lib/private/Authentication/Login/UserDisabledCheckCommand.php',
|
||||
'OC\\Authentication\\Notifications\\Notifier' => $baseDir . '/lib/private/Authentication/Notifications/Notifier.php',
|
||||
'OC\\Authentication\\Token\\DefaultToken' => $baseDir . '/lib/private/Authentication/Token/DefaultToken.php',
|
||||
'OC\\Authentication\\Token\\DefaultTokenCleanupJob' => $baseDir . '/lib/private/Authentication/Token/DefaultTokenCleanupJob.php',
|
||||
'OC\\Authentication\\Token\\DefaultTokenMapper' => $baseDir . '/lib/private/Authentication/Token/DefaultTokenMapper.php',
|
||||
|
@ -537,10 +539,12 @@ return array(
|
|||
'OC\\Authentication\\Token\\INamedToken' => $baseDir . '/lib/private/Authentication/Token/INamedToken.php',
|
||||
'OC\\Authentication\\Token\\IProvider' => $baseDir . '/lib/private/Authentication/Token/IProvider.php',
|
||||
'OC\\Authentication\\Token\\IToken' => $baseDir . '/lib/private/Authentication/Token/IToken.php',
|
||||
'OC\\Authentication\\Token\\IWipeableToken' => $baseDir . '/lib/private/Authentication/Token/IWipeableToken.php',
|
||||
'OC\\Authentication\\Token\\Manager' => $baseDir . '/lib/private/Authentication/Token/Manager.php',
|
||||
'OC\\Authentication\\Token\\PublicKeyToken' => $baseDir . '/lib/private/Authentication/Token/PublicKeyToken.php',
|
||||
'OC\\Authentication\\Token\\PublicKeyTokenMapper' => $baseDir . '/lib/private/Authentication/Token/PublicKeyTokenMapper.php',
|
||||
'OC\\Authentication\\Token\\PublicKeyTokenProvider' => $baseDir . '/lib/private/Authentication/Token/PublicKeyTokenProvider.php',
|
||||
'OC\\Authentication\\Token\\RemoteWipe' => $baseDir . '/lib/private/Authentication/Token/RemoteWipe.php',
|
||||
'OC\\Authentication\\TwoFactorAuth\\Db\\ProviderUserAssignmentDao' => $baseDir . '/lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php',
|
||||
'OC\\Authentication\\TwoFactorAuth\\EnforcementState' => $baseDir . '/lib/private/Authentication/TwoFactorAuth/EnforcementState.php',
|
||||
'OC\\Authentication\\TwoFactorAuth\\Manager' => $baseDir . '/lib/private/Authentication/TwoFactorAuth/Manager.php',
|
||||
|
@ -711,6 +715,7 @@ return array(
|
|||
'OC\\Core\\Controller\\UserController' => $baseDir . '/core/Controller/UserController.php',
|
||||
'OC\\Core\\Controller\\WalledGardenController' => $baseDir . '/core/Controller/WalledGardenController.php',
|
||||
'OC\\Core\\Controller\\WhatsNewController' => $baseDir . '/core/Controller/WhatsNewController.php',
|
||||
'OC\\Core\\Controller\\WipeController' => $baseDir . '/core/Controller/WipeController.php',
|
||||
'OC\\Core\\Data\\LoginFlowV2Credentials' => $baseDir . '/core/Data/LoginFlowV2Credentials.php',
|
||||
'OC\\Core\\Data\\LoginFlowV2Tokens' => $baseDir . '/core/Data/LoginFlowV2Tokens.php',
|
||||
'OC\\Core\\Db\\LoginFlowV2' => $baseDir . '/core/Db/LoginFlowV2.php',
|
||||
|
|
|
@ -542,6 +542,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
|
|||
'OC\\Authentication\\Exceptions\\PasswordlessTokenException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/PasswordlessTokenException.php',
|
||||
'OC\\Authentication\\Exceptions\\TwoFactorAuthRequiredException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/TwoFactorAuthRequiredException.php',
|
||||
'OC\\Authentication\\Exceptions\\UserAlreadyLoggedInException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/UserAlreadyLoggedInException.php',
|
||||
'OC\\Authentication\\Exceptions\\WipeTokenException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/WipeTokenException.php',
|
||||
'OC\\Authentication\\LoginCredentials\\Credentials' => __DIR__ . '/../../..' . '/lib/private/Authentication/LoginCredentials/Credentials.php',
|
||||
'OC\\Authentication\\LoginCredentials\\Store' => __DIR__ . '/../../..' . '/lib/private/Authentication/LoginCredentials/Store.php',
|
||||
'OC\\Authentication\\Login\\ALoginCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/ALoginCommand.php',
|
||||
|
@ -560,6 +561,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
|
|||
'OC\\Authentication\\Login\\UidLoginCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/UidLoginCommand.php',
|
||||
'OC\\Authentication\\Login\\UpdateLastPasswordConfirmCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/UpdateLastPasswordConfirmCommand.php',
|
||||
'OC\\Authentication\\Login\\UserDisabledCheckCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/UserDisabledCheckCommand.php',
|
||||
'OC\\Authentication\\Notifications\\Notifier' => __DIR__ . '/../../..' . '/lib/private/Authentication/Notifications/Notifier.php',
|
||||
'OC\\Authentication\\Token\\DefaultToken' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/DefaultToken.php',
|
||||
'OC\\Authentication\\Token\\DefaultTokenCleanupJob' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/DefaultTokenCleanupJob.php',
|
||||
'OC\\Authentication\\Token\\DefaultTokenMapper' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/DefaultTokenMapper.php',
|
||||
|
@ -567,10 +569,12 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
|
|||
'OC\\Authentication\\Token\\INamedToken' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/INamedToken.php',
|
||||
'OC\\Authentication\\Token\\IProvider' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/IProvider.php',
|
||||
'OC\\Authentication\\Token\\IToken' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/IToken.php',
|
||||
'OC\\Authentication\\Token\\IWipeableToken' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/IWipeableToken.php',
|
||||
'OC\\Authentication\\Token\\Manager' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/Manager.php',
|
||||
'OC\\Authentication\\Token\\PublicKeyToken' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/PublicKeyToken.php',
|
||||
'OC\\Authentication\\Token\\PublicKeyTokenMapper' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/PublicKeyTokenMapper.php',
|
||||
'OC\\Authentication\\Token\\PublicKeyTokenProvider' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/PublicKeyTokenProvider.php',
|
||||
'OC\\Authentication\\Token\\RemoteWipe' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/RemoteWipe.php',
|
||||
'OC\\Authentication\\TwoFactorAuth\\Db\\ProviderUserAssignmentDao' => __DIR__ . '/../../..' . '/lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php',
|
||||
'OC\\Authentication\\TwoFactorAuth\\EnforcementState' => __DIR__ . '/../../..' . '/lib/private/Authentication/TwoFactorAuth/EnforcementState.php',
|
||||
'OC\\Authentication\\TwoFactorAuth\\Manager' => __DIR__ . '/../../..' . '/lib/private/Authentication/TwoFactorAuth/Manager.php',
|
||||
|
@ -741,6 +745,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
|
|||
'OC\\Core\\Controller\\UserController' => __DIR__ . '/../../..' . '/core/Controller/UserController.php',
|
||||
'OC\\Core\\Controller\\WalledGardenController' => __DIR__ . '/../../..' . '/core/Controller/WalledGardenController.php',
|
||||
'OC\\Core\\Controller\\WhatsNewController' => __DIR__ . '/../../..' . '/core/Controller/WhatsNewController.php',
|
||||
'OC\\Core\\Controller\\WipeController' => __DIR__ . '/../../..' . '/core/Controller/WipeController.php',
|
||||
'OC\\Core\\Data\\LoginFlowV2Credentials' => __DIR__ . '/../../..' . '/core/Data/LoginFlowV2Credentials.php',
|
||||
'OC\\Core\\Data\\LoginFlowV2Tokens' => __DIR__ . '/../../..' . '/core/Data/LoginFlowV2Tokens.php',
|
||||
'OC\\Core\\Db\\LoginFlowV2' => __DIR__ . '/../../..' . '/core/Db/LoginFlowV2.php',
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright Copyright (c) 2019, 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
namespace OC\Authentication\Exceptions;
|
||||
|
||||
use OC\Authentication\Token\IToken;
|
||||
|
||||
class WipeTokenException extends InvalidTokenException {
|
||||
/** @var IToken */
|
||||
private $token;
|
||||
|
||||
public function __construct(IToken $token) {
|
||||
parent::__construct();
|
||||
|
||||
$this->token = $token;
|
||||
}
|
||||
|
||||
public function getToken(): IToken {
|
||||
return $this->token;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace OC\Authentication\Notifications;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use OCP\L10N\IFactory as IL10nFactory;
|
||||
use OCP\Notification\INotification;
|
||||
use OCP\Notification\INotifier;
|
||||
|
||||
class Notifier implements INotifier {
|
||||
|
||||
/** @var IL10nFactory */
|
||||
private $factory;
|
||||
|
||||
public function __construct(IL10nFactory $l10nFactory) {
|
||||
$this->factory = $l10nFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function prepare(INotification $notification, $languageCode) {
|
||||
if ($notification->getApp() !== 'auth') {
|
||||
// Not my app => throw
|
||||
throw new InvalidArgumentException();
|
||||
}
|
||||
|
||||
// Read the language from the notification
|
||||
$l = $this->factory->get('lib', $languageCode);
|
||||
|
||||
switch ($notification->getSubject()) {
|
||||
case 'remote_wipe_start':
|
||||
$notification->setParsedSubject(
|
||||
$l->t('Remote wipe started')
|
||||
)->setParsedMessage(
|
||||
$l->t('A remote wipe was started on device %s', $notification->getSubjectParameters())
|
||||
);
|
||||
|
||||
return $notification;
|
||||
case 'remote_wipe_finish':
|
||||
$notification->setParsedSubject(
|
||||
$l->t('Remote wipe finished')
|
||||
)->setParsedMessage(
|
||||
$l->t('The remote wipe on %s has finished', $notification->getSubjectParameters())
|
||||
);
|
||||
|
||||
return $notification;
|
||||
default:
|
||||
// Unknown subject => Unknown notification => throw
|
||||
throw new InvalidArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -29,6 +29,7 @@ namespace OC\Authentication\Token;
|
|||
use OC\Authentication\Exceptions\ExpiredTokenException;
|
||||
use OC\Authentication\Exceptions\InvalidTokenException;
|
||||
use OC\Authentication\Exceptions\PasswordlessTokenException;
|
||||
use OC\Authentication\Exceptions\WipeTokenException;
|
||||
|
||||
interface IProvider {
|
||||
|
||||
|
@ -59,6 +60,7 @@ interface IProvider {
|
|||
* @param string $tokenId
|
||||
* @throws InvalidTokenException
|
||||
* @throws ExpiredTokenException
|
||||
* @throws WipeTokenException
|
||||
* @return IToken
|
||||
*/
|
||||
public function getToken(string $tokenId): IToken;
|
||||
|
@ -69,6 +71,7 @@ interface IProvider {
|
|||
* @param int $tokenId
|
||||
* @throws InvalidTokenException
|
||||
* @throws ExpiredTokenException
|
||||
* @throws WipeTokenException
|
||||
* @return IToken
|
||||
*/
|
||||
public function getTokenById(int $tokenId): IToken;
|
||||
|
|
|
@ -30,6 +30,7 @@ interface IToken extends JsonSerializable {
|
|||
|
||||
const TEMPORARY_TOKEN = 0;
|
||||
const PERMANENT_TOKEN = 1;
|
||||
const WIPE_TOKEN = 2;
|
||||
const DO_NOT_REMEMBER = 0;
|
||||
const REMEMBER = 1;
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright Copyright (c) 2019, 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OC\Authentication\Token;
|
||||
|
||||
interface IWipeableToken {
|
||||
public function wipe(): void;
|
||||
}
|
|
@ -26,6 +26,7 @@ namespace OC\Authentication\Token;
|
|||
use OC\Authentication\Exceptions\ExpiredTokenException;
|
||||
use OC\Authentication\Exceptions\InvalidTokenException;
|
||||
use OC\Authentication\Exceptions\PasswordlessTokenException;
|
||||
use OC\Authentication\Exceptions\WipeTokenException;
|
||||
|
||||
class Manager implements IProvider {
|
||||
|
||||
|
@ -113,6 +114,8 @@ class Manager implements IProvider {
|
|||
public function getToken(string $tokenId): IToken {
|
||||
try {
|
||||
return $this->publicKeyTokenProvider->getToken($tokenId);
|
||||
} catch (WipeTokenException $e) {
|
||||
throw $e;
|
||||
} catch (ExpiredTokenException $e) {
|
||||
throw $e;
|
||||
} catch(InvalidTokenException $e) {
|
||||
|
@ -143,6 +146,8 @@ class Manager implements IProvider {
|
|||
return $this->publicKeyTokenProvider->getTokenById($tokenId);
|
||||
} catch (ExpiredTokenException $e) {
|
||||
throw $e;
|
||||
} catch (WipeTokenException $e) {
|
||||
throw $e;
|
||||
} catch (InvalidTokenException $e) {
|
||||
return $this->defaultTokenProvider->getTokenById($tokenId);
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ use OCP\AppFramework\Db\Entity;
|
|||
* @method void setVersion(int $version)
|
||||
* @method bool getPasswordInvalid()
|
||||
*/
|
||||
class PublicKeyToken extends Entity implements INamedToken {
|
||||
class PublicKeyToken extends Entity implements INamedToken, IWipeableToken {
|
||||
|
||||
const VERSION = 2;
|
||||
|
||||
|
@ -226,4 +226,8 @@ class PublicKeyToken extends Entity implements INamedToken {
|
|||
public function setPasswordInvalid(bool $invalid) {
|
||||
parent::setPasswordInvalid($invalid);
|
||||
}
|
||||
|
||||
public function wipe(): void {
|
||||
parent::setType(IToken::WIPE_TOKEN);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace OC\Authentication\Token;
|
|||
use OC\Authentication\Exceptions\ExpiredTokenException;
|
||||
use OC\Authentication\Exceptions\InvalidTokenException;
|
||||
use OC\Authentication\Exceptions\PasswordlessTokenException;
|
||||
use OC\Authentication\Exceptions\WipeTokenException;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\AppFramework\Utility\ITimeFactory;
|
||||
use OCP\IConfig;
|
||||
|
@ -85,6 +86,10 @@ class PublicKeyTokenProvider implements IProvider {
|
|||
throw new ExpiredTokenException($token);
|
||||
}
|
||||
|
||||
if ($token->getType() === IToken::WIPE_TOKEN) {
|
||||
throw new WipeTokenException($token);
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
|
@ -99,6 +104,10 @@ class PublicKeyTokenProvider implements IProvider {
|
|||
throw new ExpiredTokenException($token);
|
||||
}
|
||||
|
||||
if ($token->getType() === IToken::WIPE_TOKEN) {
|
||||
throw new WipeTokenException($token);
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace OC\Authentication\Token;
|
||||
|
||||
use BadMethodCallException;
|
||||
use OC\Authentication\Exceptions\InvalidTokenException;
|
||||
use OC\Authentication\Exceptions\WipeTokenException;
|
||||
use OCP\Activity\IManager as IActivityManager;
|
||||
use OCP\AppFramework\Utility\ITimeFactory;
|
||||
use OCP\ILogger;
|
||||
use OCP\Notification\IManager as INotificationManager;
|
||||
|
||||
class RemoteWipe {
|
||||
|
||||
/** @var IProvider */
|
||||
private $tokenProvider;
|
||||
|
||||
/** @var IActivityManager */
|
||||
private $activityManager;
|
||||
|
||||
/** @var INotificationManager */
|
||||
private $notificationManager;
|
||||
|
||||
/** @var ITimeFactory */
|
||||
private $timeFactory;
|
||||
|
||||
/** @var ILogger */
|
||||
private $logger;
|
||||
|
||||
public function __construct(IProvider $tokenProvider,
|
||||
IActivityManager $activityManager,
|
||||
INotificationManager $notificationManager,
|
||||
ITimeFactory $timeFactory,
|
||||
ILogger $logger) {
|
||||
$this->tokenProvider = $tokenProvider;
|
||||
$this->activityManager = $activityManager;
|
||||
$this->notificationManager = $notificationManager;
|
||||
$this->timeFactory = $timeFactory;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $token
|
||||
*
|
||||
* @return bool whether wiping was started
|
||||
* @throws InvalidTokenException
|
||||
*
|
||||
*/
|
||||
public function start(string $token): bool {
|
||||
try {
|
||||
$this->tokenProvider->getToken($token);
|
||||
|
||||
// We expect a WipedTokenException here. If we reach this point this
|
||||
// is an ordinary token
|
||||
return false;
|
||||
} catch (WipeTokenException $e) {
|
||||
// Expected -> continue below
|
||||
}
|
||||
|
||||
$dbToken = $e->getToken();
|
||||
|
||||
$this->logger->info("user " . $dbToken->getUID() . " started a remote wipe");
|
||||
$this->sendNotification('remote_wipe_start', $e->getToken());
|
||||
$this->publishActivity('remote_wipe_start', $e->getToken());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $token
|
||||
*
|
||||
* @return bool whether wiping could be finished
|
||||
* @throws InvalidTokenException
|
||||
*/
|
||||
public function finish(string $token): bool {
|
||||
try {
|
||||
$this->tokenProvider->getToken($token);
|
||||
|
||||
// We expect a WipedTokenException here. If we reach this point this
|
||||
// is an ordinary token
|
||||
return false;
|
||||
} catch (WipeTokenException $e) {
|
||||
// Expected -> continue below
|
||||
}
|
||||
|
||||
$dbToken = $e->getToken();
|
||||
|
||||
$this->tokenProvider->invalidateToken($token);
|
||||
|
||||
$this->logger->info("user " . $dbToken->getUID() . " finished a remote wipe");
|
||||
$this->sendNotification('remote_wipe_finish', $e->getToken());
|
||||
$this->publishActivity('remote_wipe_finish', $e->getToken());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function publishActivity(string $event, IToken $token): void {
|
||||
$activity = $this->activityManager->generateEvent();
|
||||
$activity->setApp('core')
|
||||
->setType('security')
|
||||
->setAuthor($token->getUID())
|
||||
->setAffectedUser($token->getUID())
|
||||
->setSubject($event, [
|
||||
'name' => $token->getName(),
|
||||
]);
|
||||
try {
|
||||
$this->activityManager->publish($activity);
|
||||
} catch (BadMethodCallException $e) {
|
||||
$this->logger->warning('could not publish activity', ['app' => 'core']);
|
||||
$this->logger->logException($e, ['app' => 'core']);
|
||||
}
|
||||
}
|
||||
|
||||
private function sendNotification(string $event, IToken $token): void {
|
||||
$notification = $this->notificationManager->createNotification();
|
||||
$notification->setApp('auth')
|
||||
->setUser($token->getUID())
|
||||
->setDateTime($this->timeFactory->getDateTime())
|
||||
->setObject('token', $token->getId())
|
||||
->setSubject($event, [
|
||||
'name' => $token->getName(),
|
||||
]);
|
||||
$this->notificationManager->notify($notification);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright Copyright (c) 2016 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
|
@ -78,6 +81,28 @@ class SecurityProvider implements IProvider {
|
|||
$event->setIcon($this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'actions/password.svg')));
|
||||
}
|
||||
break;
|
||||
case 'remote_wipe_start':
|
||||
$params = $event->getSubjectParameters();
|
||||
$event->setParsedSubject($l->t('Remote wipe was started on %1$s', [
|
||||
$params['name'],
|
||||
]));
|
||||
if ($this->activityManager->getRequirePNG()) {
|
||||
$event->setIcon($this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'actions/delete.png')));
|
||||
} else {
|
||||
$event->setIcon($this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'actions/delete.svg')));
|
||||
}
|
||||
break;
|
||||
case 'remote_wipe_finish':
|
||||
$params = $event->getSubjectParameters();
|
||||
$event->setParsedSubject($l->t('Remote wipe has finished on %1$s', [
|
||||
$params['name'],
|
||||
]));
|
||||
if ($this->activityManager->getRequirePNG()) {
|
||||
$event->setIcon($this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'actions/delete.png')));
|
||||
} else {
|
||||
$event->setIcon($this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'actions/delete.svg')));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new InvalidArgumentException();
|
||||
}
|
||||
|
|
|
@ -28,16 +28,17 @@
|
|||
namespace OC\Settings\Controller;
|
||||
|
||||
use BadMethodCallException;
|
||||
use OC\AppFramework\Http;
|
||||
use OC\Authentication\Exceptions\InvalidTokenException;
|
||||
use OC\Authentication\Exceptions\PasswordlessTokenException;
|
||||
use OC\Authentication\Exceptions\WipeTokenException;
|
||||
use OC\Authentication\Token\INamedToken;
|
||||
use OC\Authentication\Token\IProvider;
|
||||
use OC\Authentication\Token\IToken;
|
||||
use OC\Authentication\Token\IWipeableToken;
|
||||
use OC\Settings\Activity\Provider;
|
||||
use OCP\Activity\IManager;
|
||||
use OC\Authentication\Token\PublicKeyToken;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\AppFramework\Http\JSONResponse;
|
||||
use OCP\ILogger;
|
||||
use OCP\IRequest;
|
||||
|
@ -168,6 +169,9 @@ class AuthSettingsController extends Controller {
|
|||
public function destroy($id) {
|
||||
try {
|
||||
$token = $this->findTokenByIdAndUser($id);
|
||||
} catch (WipeTokenException $e) {
|
||||
//continue as we can destroy tokens in wipe
|
||||
$token = $e->getToken();
|
||||
} catch (InvalidTokenException $e) {
|
||||
return new JSONResponse([], Http::STATUS_NOT_FOUND);
|
||||
}
|
||||
|
@ -246,4 +250,27 @@ class AuthSettingsController extends Controller {
|
|||
}
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
* @NoSubadminRequired
|
||||
* @PasswordConfirmationRequired
|
||||
*
|
||||
* @param int $id
|
||||
* @return JSONResponse
|
||||
* @throws InvalidTokenException
|
||||
* @throws \OC\Authentication\Exceptions\ExpiredTokenException
|
||||
*/
|
||||
public function wipe(int $id): JSONResponse {
|
||||
$token = $this->tokenProvider->getTokenById($id);
|
||||
|
||||
if (!($token instanceof IWipeableToken)) {
|
||||
return new JSONResponse([], Http::STATUS_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$token->wipe();
|
||||
$this->tokenProvider->updateToken($token);
|
||||
|
||||
return new JSONResponse([]);
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -42,6 +42,8 @@ $application->registerRoutes($this, [
|
|||
'AuthSettings' => ['url' => '/settings/personal/authtokens'],
|
||||
],
|
||||
'routes' => [
|
||||
['name' => 'AuthSettings#wipe', 'url' => '/settings/personal/authtokens/wipe/{id}', 'verb' => 'POST'],
|
||||
|
||||
['name' => 'MailSettings#setMailSettings', 'url' => '/settings/admin/mailsettings', 'verb' => 'POST'],
|
||||
['name' => 'MailSettings#storeCredentials', 'url' => '/settings/admin/mailsettings/credentials', 'verb' => 'POST'],
|
||||
['name' => 'MailSettings#sendTestMail', 'url' => '/settings/admin/mailtest', 'verb' => 'POST'],
|
||||
|
|
|
@ -20,7 +20,8 @@
|
|||
-->
|
||||
|
||||
<template>
|
||||
<tr :data-id="token.id">
|
||||
<tr :data-id="token.id"
|
||||
:class="{wiping}">
|
||||
<td class="client">
|
||||
<div :class="iconName.icon"></div>
|
||||
</td>
|
||||
|
@ -33,6 +34,8 @@
|
|||
@blur="cancelRename"
|
||||
@keyup.esc="cancelRename">
|
||||
<span v-else>{{iconName.name}}</span>
|
||||
<span v-if="wiping"
|
||||
class="wiping-warning">({{ t('settings', 'Marked for remote wipe') }})</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="last-activity" v-tooltip="lastActivity">{{lastActivityRelative}}</span>
|
||||
|
@ -142,13 +145,25 @@
|
|||
text: t('settings', 'Rename'),
|
||||
});
|
||||
}
|
||||
if (this.token.canDelete) {
|
||||
if (this.token.canDelete && this.token.type !== 2) {
|
||||
// TODO: add text/longtext with some description
|
||||
actions.push({
|
||||
icon: 'icon-delete',
|
||||
action: () => this.$emit('delete', this.token),
|
||||
text: t('settings', 'Revoke'),
|
||||
});
|
||||
actions.push({
|
||||
icon: 'icon-delete',
|
||||
action: this.wipe,
|
||||
text: t('settings', 'Wipe device'),
|
||||
});
|
||||
} else if (this.token.canDelete && this.token.type === 2) {
|
||||
actions.push({
|
||||
icon: 'icon-delete',
|
||||
action: () => this.$emit('delete', this.token),
|
||||
text: t('settings', 'Revoke'),
|
||||
longtext: t('settings', 'Revoking this token might prevent the wiping of your device if it hasn\'t started the wipe yet.'),
|
||||
});
|
||||
}
|
||||
|
||||
return actions;
|
||||
|
@ -197,6 +212,9 @@
|
|||
name,
|
||||
};
|
||||
},
|
||||
wiping() {
|
||||
return this.token.type === 2;
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
@ -224,11 +242,20 @@
|
|||
this.renaming = false;
|
||||
this.$emit('rename', this.token, this.newName);
|
||||
},
|
||||
wipe () {
|
||||
this.actionOpen = false;
|
||||
|
||||
this.$emit('wipe', this.token);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.wiping {
|
||||
background-color: var(--color-background-darker);
|
||||
}
|
||||
|
||||
td {
|
||||
border-top: 1px solid var(--color-border);
|
||||
max-width: 200px;
|
||||
|
@ -254,6 +281,9 @@
|
|||
margin: 0;
|
||||
}
|
||||
}
|
||||
&.token-name .wiping-warning {
|
||||
color: var(--color-text-lighter);
|
||||
}
|
||||
|
||||
&.more {
|
||||
@extend %icon;
|
||||
|
|
|
@ -35,7 +35,8 @@
|
|||
:token="token"
|
||||
@toggleScope="toggleScope"
|
||||
@rename="rename"
|
||||
@delete="onDelete"/>
|
||||
@delete="onDelete"
|
||||
@wipe="onWipe" />
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
@ -75,6 +76,10 @@
|
|||
onDelete (token) {
|
||||
// Just pass it on
|
||||
this.$emit('delete', token);
|
||||
},
|
||||
onWipe(token) {
|
||||
// Just pass it on
|
||||
this.$emit('wipe', token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,13 +26,15 @@
|
|||
<AuthTokenList :tokens="tokens"
|
||||
@toggleScope="toggleTokenScope"
|
||||
@rename="rename"
|
||||
@delete="deleteToken"/>
|
||||
@delete="deleteToken"
|
||||
@wipe="wipeToken" />
|
||||
<AuthTokenSetupDialogue :add="addNewToken" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Axios from 'nextcloud-axios';
|
||||
import confirmPassword from 'nextcloud-password-confirmation';
|
||||
|
||||
import AuthTokenList from './AuthTokenList';
|
||||
import AuthTokenSetupDialogue from './AuthTokenSetupDialogue';
|
||||
|
@ -132,6 +134,23 @@
|
|||
// Restore
|
||||
this.tokens.push(token);
|
||||
})
|
||||
},
|
||||
wipeToken(token) {
|
||||
console.debug('wiping app token', token);
|
||||
|
||||
confirmPassword()
|
||||
.then(() => Axios.post(this.baseUrl + '/wipe/' + token.id))
|
||||
.then(tap(() => {
|
||||
console.debug('app token marked for wipe')
|
||||
|
||||
// Update the type
|
||||
// TODO: refactor the server-side code to return the updated token
|
||||
token.type = 2;
|
||||
}))
|
||||
.catch(err => {
|
||||
console.error.bind('could not wipe app token', err);
|
||||
OC.Notification.showTemporary(t('core', 'Error while wiping the device with the token'));
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright Copyright (c) 2019, 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Tests\Core\Controller;
|
||||
|
||||
use OC\Authentication\Exceptions\InvalidTokenException;
|
||||
use OC\Authentication\Token\RemoteWipe;
|
||||
use OC\Core\Controller\WipeController;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\IRequest;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Test\TestCase;
|
||||
|
||||
class WipeControllerTest extends TestCase {
|
||||
|
||||
/** @var RemoteWipe|MockObject */
|
||||
private $remoteWipe;
|
||||
|
||||
/** @var WipeController */
|
||||
private $controller;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->remoteWipe = $this->createMock(RemoteWipe::class);
|
||||
$this->controller = new WipeController(
|
||||
'core',
|
||||
$this->createMock(IRequest::class),
|
||||
$this->remoteWipe);
|
||||
}
|
||||
|
||||
public function dataTest() {
|
||||
return [
|
||||
// valid token, could perform operation, valid result
|
||||
[ true, true, true],
|
||||
[ true, false, false],
|
||||
[false, true, false],
|
||||
[false, false, false],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $valid
|
||||
* @param bool $couldPerform
|
||||
* @param bool $result
|
||||
*
|
||||
* @dataProvider dataTest
|
||||
*/
|
||||
public function testCheckWipe(bool $valid, bool $couldPerform, bool $result) {
|
||||
if (!$valid) {
|
||||
$this->remoteWipe->method('start')
|
||||
->with('mytoken')
|
||||
->willThrowException(new InvalidTokenException());
|
||||
} else {
|
||||
$this->remoteWipe->method('start')
|
||||
->with('mytoken')
|
||||
->willReturn($couldPerform);
|
||||
}
|
||||
|
||||
$result = $this->controller->checkWipe('mytoken');
|
||||
|
||||
if (!$valid || !$couldPerform) {
|
||||
$this->assertSame(Http::STATUS_NOT_FOUND, $result->getStatus());
|
||||
$this->assertSame([], $result->getData());
|
||||
} else {
|
||||
$this->assertSame(Http::STATUS_OK, $result->getStatus());
|
||||
$this->assertSame(['wipe' => true], $result->getData());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $valid
|
||||
* @param bool $couldPerform
|
||||
* @param bool $result
|
||||
*
|
||||
* @dataProvider dataTest
|
||||
*/
|
||||
public function testWipeDone(bool $valid, bool $couldPerform, bool $result) {
|
||||
if (!$valid) {
|
||||
$this->remoteWipe->method('finish')
|
||||
->with('mytoken')
|
||||
->willThrowException(new InvalidTokenException());
|
||||
} else {
|
||||
$this->remoteWipe->method('finish')
|
||||
->with('mytoken')
|
||||
->willReturn($couldPerform);
|
||||
}
|
||||
|
||||
$result = $this->controller->wipeDone('mytoken');
|
||||
|
||||
if (!$valid || !$couldPerform) {
|
||||
$this->assertSame(Http::STATUS_NOT_FOUND, $result->getStatus());
|
||||
$this->assertSame([], $result->getData());
|
||||
} else {
|
||||
$this->assertSame(Http::STATUS_OK, $result->getStatus());
|
||||
$this->assertSame([], $result->getData());
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue