Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 51 additions & 40 deletions lib/CurrentUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@
protected $sessionUser = false;

public function __construct(
protected IUserSession $userSession,
protected IRequest $request,
protected IManager $shareManager,
protected IFactory $l10nFactory,
protected readonly IUserSession $userSession,
protected readonly IRequest $request,
protected readonly IManager $shareManager,
protected readonly IFactory $l10nFactory,
) {
}

Expand All @@ -38,15 +38,14 @@

/**
* Get an identifier for the user, session or token
* @return string
*/
public function getUserIdentifier() {
public function getUserIdentifier(): string {
if ($this->identifier !== null) {
return $this->identifier;
}

$uid = $this->getUID();
if ($uid !== null) {

Check failure on line 48 in lib/CurrentUser.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

RedundantCondition

lib/CurrentUser.php:48:7: RedundantCondition: string can never contain null (see https://psalm.dev/122)
$this->identifier = $uid;
return $this->identifier;
}
Expand All @@ -70,9 +69,8 @@

/**
* Get the current user id from the session
* @return string|null
*/
public function getUID() {
public function getUID(): string {

Check failure on line 73 in lib/CurrentUser.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

InvalidNullableReturnType

lib/CurrentUser.php:73:28: InvalidNullableReturnType: The declared return type 'string' for OCA\Activity\CurrentUser::getUID is not nullable, but 'null|string' contains null (see https://psalm.dev/144)
if ($this->sessionUser === false) {
$user = $this->userSession->getUser();
if ($user instanceof IUser) {
Expand All @@ -82,14 +80,13 @@
}
}

return $this->sessionUser;

Check failure on line 83 in lib/CurrentUser.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

NullableReturnStatement

lib/CurrentUser.php:83:10: NullableReturnStatement: The declared return type 'string' for OCA\Activity\CurrentUser::getUID is not nullable, but the function returns 'null|string' (see https://psalm.dev/139)
}

/**
* Get the current user cloud id from the session
* @return string|null
*/
public function getCloudId() {
public function getCloudId(): string {

Check failure on line 89 in lib/CurrentUser.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

InvalidNullableReturnType

lib/CurrentUser.php:89:32: InvalidNullableReturnType: The declared return type 'string' for OCA\Activity\CurrentUser::getCloudId is not nullable, but 'null|string' contains null (see https://psalm.dev/144)
if ($this->cloudId === false) {
$user = $this->userSession->getUser();
if ($user instanceof IUser) {
Expand All @@ -99,50 +96,64 @@
}
}

return $this->cloudId;

Check failure on line 99 in lib/CurrentUser.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

NullableReturnStatement

lib/CurrentUser.php:99:10: NullableReturnStatement: The declared return type 'string' for OCA\Activity\CurrentUser::getCloudId is not nullable, but the function returns 'null|string' (see https://psalm.dev/139)
}

/**
* Check if the current request is via a public share link
*/
public function isPublicShareToken(): bool {
/** @psalm-suppress NoInterfaceProperties */
if (!empty($this->request->server['PHP_AUTH_USER'])) {
$token = $this->request->server['PHP_AUTH_USER'];
try {
$share = $this->shareManager->getShareByToken($token);
return $share->getShareType() === IShare::TYPE_LINK
|| $share->getShareType() === IShare::TYPE_EMAIL;
} catch (ShareNotFound $e) {
// No share found for this token
}
}

return false;
return $this->getPublicShare() !== null;
}

/**
* Get the cloud ID from the sharing token
* @return string|null
*/
protected function getCloudIDFromToken() {
protected function getCloudIDFromToken(): ?string {
$share = $this->getPublicShare();

if ($share === null || $share->getShareType() !== IShare::TYPE_REMOTE) {
return null;
}

return $share->getSharedWith();
}

protected function getPublicShare(): ?IShare {
if (basename($this->request->getScriptName()) !== 'public.php') {
return null;
}

$token = $this->getShareToken();
if ($token === null) {
return null;
}

try {
return $this->shareManager->getShareByToken($token);
} catch (ShareNotFound $e) {
return null;
}
}

protected function getShareToken(): ?string {
// The legacy public endpoint receive the share token in the HTTP basic auth header.
/** @psalm-suppress NoInterfaceProperties */
if (!empty($this->request->server['PHP_AUTH_USER'])) {
$token = $this->request->server['PHP_AUTH_USER'];
/**
* Until https://github.com/nextcloud/server/pull/26681 is merged
* @psalm-suppress InvalidCatch
*/
try {
$share = $this->shareManager->getShareByToken($token);
if ($share->getShareType() === IShare::TYPE_REMOTE) {
return $share->getSharedWith();
}
} catch (ShareNotFound $e) {
// No share, use the fallback
}
$authUser = (string)($this->request->server['PHP_AUTH_USER'] ?? '');
if ($authUser !== '') {
return $authUser;
}

// The current public endpoint receives the share token in the path.
// Copied from apps/dav/lib/Connector/Sabre/PublicAuth::getToken()
$path = $this->request->getPathInfo() ?: '';
// ['', 'dav', 'files', 'token']
$splittedPath = explode('/', $path);

if (count($splittedPath) < 4 || $splittedPath[3] === '') {
return null;
}

return null;
return $splittedPath[3];
}
}
8 changes: 5 additions & 3 deletions tests/CurrentUserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ protected function setUp(): void {
$this->userSession = $this->createMock(IUserSession::class);
$this->shareManager = $this->createMock(IManager::class);
$this->l10nFactory = $this->createMock(IFactory::class);

$this->request->method('getScriptName')->willReturn('/public.php');
}

protected function getInstance(array $methods = []): CurrentUser|MockObject {
Expand All @@ -83,14 +85,14 @@ protected function getInstance(array $methods = []): CurrentUser|MockObject {
public static function dataGetUserIdentifier(): array {
return [
[null, null, null, ''],
[null, 'uid', -1, 'uid'],
[null, 'uid', '-1', 'uid'],
[null, null, 'token', 'token'],
['cached', -1, -1, 'cached'],
];
}

#[DataProvider('dataGetUserIdentifier')]
public function testGetUserIdentifier(?string $cachedIdentifier, string|int|null $uidResult, string|int|null $tokenResult, string $expected): void {
public function testGetUserIdentifier(?string $cachedIdentifier, string|int|null $uidResult, ?string $tokenResult, string $expected): void {
$instance = $this->getInstance([
'getUID',
'getCloudIDFromToken',
Expand All @@ -102,7 +104,7 @@ public function testGetUserIdentifier(?string $cachedIdentifier, string|int|null
->method('getUID')
->willReturn($uidResult);

$instance->expects($tokenResult !== -1 ? $this->once() : $this->never())
$instance->expects($tokenResult !== '-1' ? $this->once() : $this->never())
->method('getCloudIDFromToken')
->willReturn($tokenResult);

Expand Down
Loading