Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>tags/v16.0.0alpha1
@@ -27,13 +27,20 @@ namespace OC\Settings\Personal; | |||
use function array_filter; | |||
use function array_map; | |||
use function is_null; | |||
use OC\Authentication\Exceptions\InvalidTokenException; | |||
use OC\Authentication\Token\INamedToken; | |||
use OC\Authentication\Token\IProvider as IAuthTokenProvider; | |||
use OC\Authentication\Token\IToken; | |||
use OC\Authentication\TwoFactorAuth\Manager as TwoFactorManager; | |||
use OC\Authentication\TwoFactorAuth\ProviderLoader; | |||
use OCP\AppFramework\Http\TemplateResponse; | |||
use OCP\Authentication\TwoFactorAuth\IProvider; | |||
use OCP\Authentication\TwoFactorAuth\IProvidesPersonalSettings; | |||
use OCP\IInitialStateService; | |||
use OCP\ISession; | |||
use OCP\IUserManager; | |||
use OCP\IUserSession; | |||
use OCP\Session\Exceptions\SessionNotAvailableException; | |||
use OCP\Settings\ISettings; | |||
class Security implements ISettings { | |||
@@ -44,21 +51,41 @@ class Security implements ISettings { | |||
/** @var TwoFactorManager */ | |||
private $twoFactorManager; | |||
/** @var IAuthTokenProvider */ | |||
private $tokenProvider; | |||
/** @var ProviderLoader */ | |||
private $providerLoader; | |||
/** @var IUserSession */ | |||
private $userSession; | |||
/** @var ISession */ | |||
private $session; | |||
/** @var IInitialStateService */ | |||
private $initialStateService; | |||
/** | |||
* @var string|null | |||
*/ | |||
private $uid; | |||
public function __construct(IUserManager $userManager, | |||
TwoFactorManager $providerManager, | |||
IAuthTokenProvider $tokenProvider, | |||
ProviderLoader $providerLoader, | |||
IUserSession $userSession) { | |||
IUserSession $userSession, | |||
ISession $session, | |||
IInitialStateService $initialStateService, | |||
?string $UserId) { | |||
$this->userManager = $userManager; | |||
$this->twoFactorManager = $providerManager; | |||
$this->tokenProvider = $tokenProvider; | |||
$this->providerLoader = $providerLoader; | |||
$this->userSession = $userSession; | |||
$this->session = $session; | |||
$this->initialStateService = $initialStateService; | |||
$this->uid = $UserId; | |||
} | |||
/** | |||
@@ -66,12 +93,18 @@ class Security implements ISettings { | |||
* @since 9.1 | |||
*/ | |||
public function getForm() { | |||
$user = $this->userManager->get(\OC_User::getUser()); | |||
$user = $this->userManager->get($this->uid); | |||
$passwordChangeSupported = false; | |||
if ($user !== null) { | |||
$passwordChangeSupported = $user->canChangePassword(); | |||
} | |||
$this->initialStateService->provideInitialState( | |||
'settings', | |||
'app_tokens', | |||
$this->getAppTokens() | |||
); | |||
return new TemplateResponse('settings', 'settings/personal/security', [ | |||
'passwordChangeSupported' => $passwordChangeSupported, | |||
'twoFactorProviderData' => $this->getTwoFactorProviderData(), | |||
@@ -116,4 +149,32 @@ class Security implements ISettings { | |||
})) | |||
]; | |||
} | |||
private function getAppTokens(): array { | |||
$tokens = $this->tokenProvider->getTokenByUser($this->uid); | |||
try { | |||
$sessionId = $this->session->getId(); | |||
} catch (SessionNotAvailableException $ex) { | |||
return []; | |||
} | |||
try { | |||
$sessionToken = $this->tokenProvider->getToken($sessionId); | |||
} catch (InvalidTokenException $ex) { | |||
return []; | |||
} | |||
return array_map(function (IToken $token) use ($sessionToken) { | |||
$data = $token->jsonSerialize(); | |||
$data['canDelete'] = true; | |||
$data['canRename'] = $token instanceof INamedToken; | |||
if ($sessionToken->getId() === $token->getId()) { | |||
$data['canDelete'] = false; | |||
$data['canRename'] = false; | |||
$data['current'] = true; | |||
} | |||
return $data; | |||
}, $tokens); | |||
} | |||
} |
@@ -44,6 +44,21 @@ | |||
"ms": "^2.1.1" | |||
} | |||
}, | |||
"json5": { | |||
"version": "2.1.0", | |||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", | |||
"integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", | |||
"dev": true, | |||
"requires": { | |||
"minimist": "^1.2.0" | |||
} | |||
}, | |||
"minimist": { | |||
"version": "1.2.0", | |||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", | |||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", | |||
"dev": true | |||
}, | |||
"source-map": { | |||
"version": "0.5.7", | |||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", | |||
@@ -1046,7 +1061,8 @@ | |||
"ansi-regex": { | |||
"version": "2.1.1", | |||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", | |||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" | |||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", | |||
"dev": true | |||
}, | |||
"ansi-styles": { | |||
"version": "3.2.1", | |||
@@ -1161,7 +1177,7 @@ | |||
}, | |||
"util": { | |||
"version": "0.10.3", | |||
"resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", | |||
"resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz", | |||
"integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", | |||
"dev": true, | |||
"requires": { | |||
@@ -1182,14 +1198,6 @@ | |||
"integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", | |||
"dev": true | |||
}, | |||
"async": { | |||
"version": "2.6.2", | |||
"resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", | |||
"integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", | |||
"requires": { | |||
"lodash": "^4.17.11" | |||
} | |||
}, | |||
"async-each": { | |||
"version": "1.0.1", | |||
"resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", | |||
@@ -2033,13 +2041,13 @@ | |||
"dependencies": { | |||
"jsesc": { | |||
"version": "0.5.0", | |||
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", | |||
"resolved": "http://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", | |||
"integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", | |||
"dev": true | |||
}, | |||
"regexpu-core": { | |||
"version": "1.0.0", | |||
"resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", | |||
"resolved": "http://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", | |||
"integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=", | |||
"dev": true, | |||
"requires": { | |||
@@ -2050,13 +2058,13 @@ | |||
}, | |||
"regjsgen": { | |||
"version": "0.2.0", | |||
"resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", | |||
"resolved": "http://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", | |||
"integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", | |||
"dev": true | |||
}, | |||
"regjsparser": { | |||
"version": "0.1.5", | |||
"resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", | |||
"resolved": "http://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", | |||
"integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", | |||
"dev": true, | |||
"requires": { | |||
@@ -2531,7 +2539,7 @@ | |||
"dependencies": { | |||
"source-map": { | |||
"version": "0.5.0", | |||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.0.tgz", | |||
"resolved": "http://registry.npmjs.org/source-map/-/source-map-0.5.0.tgz", | |||
"integrity": "sha1-D+llA6yGpa213mP05BKuSHLNvoY=", | |||
"dev": true | |||
} | |||
@@ -3621,6 +3629,21 @@ | |||
"optimist": "^0.6.1", | |||
"source-map": "^0.6.1", | |||
"uglify-js": "^3.1.4" | |||
}, | |||
"dependencies": { | |||
"async": { | |||
"version": "2.6.1", | |||
"resolved": "http://registry.npmjs.org/async/-/async-2.6.1.tgz", | |||
"integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", | |||
"requires": { | |||
"lodash": "^4.17.10" | |||
} | |||
}, | |||
"source-map": { | |||
"version": "0.6.1", | |||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", | |||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" | |||
} | |||
} | |||
}, | |||
"handlebars-loader": { | |||
@@ -4078,6 +4101,7 @@ | |||
"version": "1.0.0", | |||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", | |||
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", | |||
"dev": true, | |||
"requires": { | |||
"number-is-nan": "^1.0.0" | |||
} | |||
@@ -4261,23 +4285,6 @@ | |||
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", | |||
"dev": true | |||
}, | |||
"json5": { | |||
"version": "2.1.0", | |||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", | |||
"integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", | |||
"dev": true, | |||
"requires": { | |||
"minimist": "^1.2.0" | |||
}, | |||
"dependencies": { | |||
"minimist": { | |||
"version": "1.2.0", | |||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", | |||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", | |||
"dev": true | |||
} | |||
} | |||
}, | |||
"jsprim": { | |||
"version": "1.4.1", | |||
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", | |||
@@ -4640,9 +4647,9 @@ | |||
} | |||
}, | |||
"minimist": { | |||
"version": "0.0.10", | |||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", | |||
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" | |||
"version": "0.0.8", | |||
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", | |||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" | |||
}, | |||
"mississippi": { | |||
"version": "3.0.0", | |||
@@ -5882,7 +5889,7 @@ | |||
"dependencies": { | |||
"jsesc": { | |||
"version": "0.5.0", | |||
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", | |||
"resolved": "http://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", | |||
"integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", | |||
"dev": true | |||
} | |||
@@ -6538,6 +6545,7 @@ | |||
"version": "1.0.2", | |||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", | |||
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", | |||
"dev": true, | |||
"requires": { | |||
"code-point-at": "^1.0.0", | |||
"is-fullwidth-code-point": "^1.0.0", | |||
@@ -6557,6 +6565,7 @@ | |||
"version": "3.0.1", | |||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", | |||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", | |||
"dev": true, | |||
"requires": { | |||
"ansi-regex": "^2.0.0" | |||
} | |||
@@ -7454,6 +7463,39 @@ | |||
"requires": { | |||
"string-width": "^1.0.1", | |||
"strip-ansi": "^3.0.1" | |||
}, | |||
"dependencies": { | |||
"ansi-regex": { | |||
"version": "2.1.1", | |||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", | |||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" | |||
}, | |||
"is-fullwidth-code-point": { | |||
"version": "1.0.0", | |||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", | |||
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", | |||
"requires": { | |||
"number-is-nan": "^1.0.0" | |||
} | |||
}, | |||
"string-width": { | |||
"version": "1.0.2", | |||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", | |||
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", | |||
"requires": { | |||
"code-point-at": "^1.0.0", | |||
"is-fullwidth-code-point": "^1.0.0", | |||
"strip-ansi": "^3.0.0" | |||
} | |||
}, | |||
"strip-ansi": { | |||
"version": "3.0.1", | |||
"resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", | |||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", | |||
"requires": { | |||
"ansi-regex": "^2.0.0" | |||
} | |||
} | |||
} | |||
}, | |||
"wrappy": { |
@@ -92,39 +92,6 @@ class AuthSettingsController extends Controller { | |||
$this->logger = $logger; | |||
} | |||
/** | |||
* @NoAdminRequired | |||
* @NoSubadminRequired | |||
* | |||
* @return JSONResponse|array | |||
*/ | |||
public function index() { | |||
$tokens = $this->tokenProvider->getTokenByUser($this->uid); | |||
try { | |||
$sessionId = $this->session->getId(); | |||
} catch (SessionNotAvailableException $ex) { | |||
return $this->getServiceNotAvailableResponse(); | |||
} | |||
try { | |||
$sessionToken = $this->tokenProvider->getToken($sessionId); | |||
} catch (InvalidTokenException $ex) { | |||
return $this->getServiceNotAvailableResponse(); | |||
} | |||
return array_map(function (IToken $token) use ($sessionToken) { | |||
$data = $token->jsonSerialize(); | |||
$data['canDelete'] = true; | |||
$data['canRename'] = $token instanceof INamedToken; | |||
if ($sessionToken->getId() === $token->getId()) { | |||
$data['canDelete'] = false; | |||
$data['canRename'] = false; | |||
$data['current'] = true; | |||
} | |||
return $data; | |||
}, $tokens); | |||
} | |||
/** | |||
* @NoAdminRequired | |||
* @NoSubadminRequired |
@@ -20,7 +20,7 @@ | |||
--> | |||
<template> | |||
<table id="app-tokens-table" :class="{ 'icon-loading' : loading }"> | |||
<table id="app-tokens-table"> | |||
<thead v-if="tokens.length"> | |||
<tr> | |||
<th></th> | |||
@@ -52,10 +52,6 @@ | |||
tokens: { | |||
type: Array, | |||
required: true, | |||
}, | |||
loading: { | |||
type: Boolean, | |||
required: true, | |||
} | |||
}, | |||
computed: { |
@@ -24,7 +24,6 @@ | |||
<h2>{{ t('settings', 'Devices & sessions') }}</h2> | |||
<p class="settings-hint hidden-when-empty">{{ t('settings', 'Web, desktop and mobile clients currently logged in to your account.') }}</p> | |||
<AuthTokenList :tokens="tokens" | |||
:loading="loading" | |||
@toggleScope="toggleTokenScope" | |||
@rename="rename" | |||
@delete="deleteToken"/> | |||
@@ -48,31 +47,21 @@ | |||
export default { | |||
name: "AuthTokenSection", | |||
props: { | |||
tokens: { | |||
type: Array, | |||
requried: true, | |||
}, | |||
}, | |||
components: { | |||
AuthTokenSetupDialogue, | |||
AuthTokenList | |||
}, | |||
data() { | |||
return { | |||
loading: true, | |||
baseUrl: OC.generateUrl('/settings/personal/authtokens'), | |||
tokens: [], | |||
} | |||
}, | |||
mounted() { | |||
Axios.get(this.baseUrl) | |||
.then(resp => resp.data) | |||
.then(tokens => { | |||
console.debug('loaded app tokens', tokens); | |||
this.loading = false; | |||
this.tokens = tokens; | |||
}) | |||
.catch(err => { | |||
OC.Notification.showTemporary(t('core', 'Error while loading browser sessions and device tokens')); | |||
console.error('could not load app tokens', err); | |||
throw err; | |||
}); | |||
}, | |||
methods: { | |||
addNewToken (name) { | |||
console.debug('creating a new app token', name); |
@@ -32,4 +32,8 @@ Vue.use(VTooltip); | |||
Vue.prototype.t = t; | |||
const View = Vue.extend(AuthTokenSection); | |||
new View().$mount('#security'); | |||
new View({ | |||
propsData: { | |||
tokens: OCP.InitialState.loadState('settings', 'app_tokens'), | |||
} | |||
}).$mount('#security'); |
@@ -76,53 +76,6 @@ class AuthSettingsControllerTest extends TestCase { | |||
); | |||
} | |||
public function testIndex() { | |||
$token1 = new DefaultToken(); | |||
$token1->setId(100); | |||
$token2 = new DefaultToken(); | |||
$token2->setId(200); | |||
$tokens = [ | |||
$token1, | |||
$token2, | |||
]; | |||
$sessionToken = new DefaultToken(); | |||
$sessionToken->setId(100); | |||
$this->tokenProvider->expects($this->once()) | |||
->method('getTokenByUser') | |||
->with($this->uid) | |||
->willReturn($tokens); | |||
$this->session->expects($this->once()) | |||
->method('getId') | |||
->willReturn('session123'); | |||
$this->tokenProvider->expects($this->once()) | |||
->method('getToken') | |||
->with('session123') | |||
->willReturn($sessionToken); | |||
$this->assertEquals([ | |||
[ | |||
'id' => 100, | |||
'name' => null, | |||
'lastActivity' => 0, | |||
'type' => 0, | |||
'canDelete' => false, | |||
'current' => true, | |||
'scope' => ['filesystem' => true], | |||
'canRename' => false, | |||
], | |||
[ | |||
'id' => 200, | |||
'name' => null, | |||
'lastActivity' => 0, | |||
'type' => 0, | |||
'canDelete' => true, | |||
'scope' => ['filesystem' => true], | |||
'canRename' => true, | |||
] | |||
], $this->controller->index()); | |||
} | |||
public function testCreate() { | |||
$name = 'Nexus 4'; | |||
$sessionToken = $this->createMock(IToken::class); |
@@ -0,0 +1,167 @@ | |||
<?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 Test\Settings\Personal; | |||
use OC\Authentication\Token\DefaultToken; | |||
use OC\Authentication\Token\IProvider as IAuthTokenProvider; | |||
use OC\Authentication\TwoFactorAuth\Manager as TwoFactorManager; | |||
use OC\Authentication\TwoFactorAuth\ProviderLoader; | |||
use OC\Settings\Personal\Security; | |||
use OCP\AppFramework\Http\TemplateResponse; | |||
use OCP\IInitialStateService; | |||
use OCP\ISession; | |||
use OCP\IUser; | |||
use OCP\IUserManager; | |||
use OCP\IUserSession; | |||
use PHPUnit\Framework\MockObject\MockObject; | |||
use Test\TestCase; | |||
class SecurityTest extends TestCase { | |||
/** @var IUserManager|MockObject */ | |||
private $userManager; | |||
/** @var TwoFactorManager|MockObject */ | |||
private $twoFactorManager; | |||
/** @var IAuthTokenProvider|MockObject */ | |||
private $authTokenProvider; | |||
/** @var ProviderLoader|MockObject */ | |||
private $providerLoader; | |||
/** @var IUserSession|MockObject */ | |||
private $userSession; | |||
/** @var ISession|MockObject */ | |||
private $session; | |||
/** @var IInitialStateService|MockObject */ | |||
private $initialStateService; | |||
/** @var string */ | |||
private $uid; | |||
/** @var Security */ | |||
private $section; | |||
public function setUp() { | |||
parent::setUp(); | |||
$this->userManager = $this->createMock(IUserManager::class); | |||
$this->twoFactorManager = $this->createMock(TwoFactorManager::class); | |||
$this->authTokenProvider = $this->createMock(IAuthTokenProvider::class); | |||
$this->providerLoader = $this->createMock(ProviderLoader::class); | |||
$this->userSession = $this->createMock(IUserSession::class); | |||
$this->session = $this->createMock(ISession::class); | |||
$this->initialStateService = $this->createMock(IInitialStateService::class); | |||
$this->uid = 'test123'; | |||
$this->section = new Security( | |||
$this->userManager, | |||
$this->twoFactorManager, | |||
$this->authTokenProvider, | |||
$this->providerLoader, | |||
$this->userSession, | |||
$this->session, | |||
$this->initialStateService, | |||
$this->uid | |||
); | |||
} | |||
public function testGetForm() { | |||
$token1 = new DefaultToken(); | |||
$token1->setId(100); | |||
$token2 = new DefaultToken(); | |||
$token2->setId(200); | |||
$tokens = [ | |||
$token1, | |||
$token2, | |||
]; | |||
$sessionToken = new DefaultToken(); | |||
$sessionToken->setId(100); | |||
$user = $this->createMock(IUser::class); | |||
$this->userManager->expects($this->once()) | |||
->method('get') | |||
->with($this->uid) | |||
->willReturn($user); | |||
$user->expects($this->once()) | |||
->method('canChangePassword') | |||
->willReturn(true); | |||
$this->authTokenProvider->expects($this->once()) | |||
->method('getTokenByUser') | |||
->with($this->uid) | |||
->willReturn($tokens); | |||
$this->session->expects($this->once()) | |||
->method('getId') | |||
->willReturn('session123'); | |||
$this->authTokenProvider->expects($this->once()) | |||
->method('getToken') | |||
->with('session123') | |||
->willReturn($sessionToken); | |||
$this->initialStateService->expects($this->once()) | |||
->method('provideInitialState') | |||
->with('settings', 'app_tokens', [ | |||
[ | |||
'id' => 100, | |||
'name' => null, | |||
'lastActivity' => 0, | |||
'type' => 0, | |||
'canDelete' => false, | |||
'current' => true, | |||
'scope' => ['filesystem' => true], | |||
'canRename' => false, | |||
], | |||
[ | |||
'id' => 200, | |||
'name' => null, | |||
'lastActivity' => 0, | |||
'type' => 0, | |||
'canDelete' => true, | |||
'scope' => ['filesystem' => true], | |||
'canRename' => true, | |||
], | |||
]); | |||
$this->userSession->expects($this->once()) | |||
->method('getUser') | |||
->willReturn($user); | |||
$this->providerLoader->expects($this->once()) | |||
->method('getProviders') | |||
->with($user) | |||
->willReturn([]); | |||
$form = $this->section->getForm(); | |||
$expected = new TemplateResponse('settings', 'settings/personal/security', [ | |||
'passwordChangeSupported' => true, | |||
'twoFactorProviderData' => [ | |||
'providers' => [], | |||
], | |||
]); | |||
$this->assertEquals($expected, $form); | |||
} | |||
} |