Skip to content

Commit

Permalink
fix(Federation): Show some icon for federated users on shares
Browse files Browse the repository at this point in the history
Signed-off-by: fenn-cs <fenn25.fn@gmail.com>
  • Loading branch information
nfebe committed Sep 18, 2024
1 parent ad66160 commit 30aaefd
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 15 deletions.
6 changes: 6 additions & 0 deletions apps/dav/lib/Connector/Sabre/FilesPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ class FilesPlugin extends ServerPlugin {
public const MOUNT_TYPE_PROPERTYNAME = '{http://nextcloud.org/ns}mount-type';
public const MOUNT_ROOT_PROPERTYNAME = '{http://nextcloud.org/ns}is-mount-root';
public const IS_ENCRYPTED_PROPERTYNAME = '{http://nextcloud.org/ns}is-encrypted';
public const IS_FEDERATED_PROPERTYNAME = '{http://nextcloud.org/ns}is-federated';
public const METADATA_ETAG_PROPERTYNAME = '{http://nextcloud.org/ns}metadata_etag';
public const UPLOAD_TIME_PROPERTYNAME = '{http://nextcloud.org/ns}upload_time';
public const CREATION_TIME_PROPERTYNAME = '{http://nextcloud.org/ns}creation_time';
Expand Down Expand Up @@ -149,6 +150,7 @@ public function initialize(Server $server) {
$server->protectedProperties[] = self::HAS_PREVIEW_PROPERTYNAME;
$server->protectedProperties[] = self::MOUNT_TYPE_PROPERTYNAME;
$server->protectedProperties[] = self::IS_ENCRYPTED_PROPERTYNAME;
$server->protectedProperties[] = self::IS_FEDERATED_PROPERTYNAME;
$server->protectedProperties[] = self::SHARE_NOTE;

// normally these cannot be changed (RFC4918), but we want them modifiable through PROPPATCH
Expand Down Expand Up @@ -413,6 +415,10 @@ public function handleGetProperties(PropFind $propFind, \Sabre\DAV\INode $node)
$propFind->handle(self::DISPLAYNAME_PROPERTYNAME, function () use ($node) {
return $node->getName();
});

$propFind->handle(self::IS_FEDERATED_PROPERTYNAME, function () use ($node) {
return $node->getOwner()->isFederated() ? 'true' : 'false';
});
}

if ($node instanceof \OCA\DAV\Connector\Sabre\File) {
Expand Down
1 change: 1 addition & 0 deletions apps/files/src/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,6 @@ registerPreviewServiceWorker()

registerDavProperty('nc:hidden', { nc: 'http://nextcloud.org/ns' })
registerDavProperty('nc:is-mount-root', { nc: 'http://nextcloud.org/ns' })
registerDavProperty('nc:is-federated', { nc: 'http://nextcloud.org/ns' })

initLivePhotos()
19 changes: 4 additions & 15 deletions apps/files_sharing/src/actions/sharingStatusAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,13 @@ import LinkSvg from '@mdi/svg/svg/link.svg?raw'
import CircleSvg from '../../../../core/img/apps/circles.svg?raw'

import { action as sidebarAction } from '../../../files/src/actions/sidebarAction'
import { generateUrl } from '@nextcloud/router'
import { getCurrentUser } from '@nextcloud/auth'
import { generateAvatarSvg } from '../utils/AccountIcon.ts'

import './sharingStatusAction.scss'

const isDarkMode = window?.matchMedia?.('(prefers-color-scheme: dark)')?.matches === true
|| document.querySelector('[data-themes*=dark]') !== null

const generateAvatarSvg = (userId: string, isGuest = false) => {
const url = isDarkMode ? '/avatar/{userId}/32/dark' : '/avatar/{userId}/32'
const avatarUrl = generateUrl(isGuest ? url : url + '?guestFallback=true', { userId })
return `<svg width="32" height="32" viewBox="0 0 32 32"
xmlns="http://www.w3.org/2000/svg" class="sharing-status__avatar">
<image href="${avatarUrl}" height="32" width="32" />
</svg>`
}

const isExternal = (node: Node) => {
return node.attributes.remote_id !== undefined
return node.attributes?.['is-federated'] ?? false
}

export const action = new FileAction({
Expand Down Expand Up @@ -110,7 +98,8 @@ export const action = new FileAction({

const ownerId = node?.attributes?.['owner-id']
if (ownerId && (ownerId !== getCurrentUser()?.uid || isExternal(node))) {
return generateAvatarSvg(ownerId, isExternal(node))
const sanitizeId = (id: string) => id.replace(/[^a-zA-Z0-9._%+-@]+/g, '').replace(/\//g, '')

Check warning

Code scanning / CodeQL

Overly permissive regular expression range Medium

Suspicious character range that overlaps with 0-9 in the same character class, and is equivalent to \[+,\\-.\\/0-9:;<=>?@\].
return generateAvatarSvg(sanitizeId(ownerId), isExternal(node))
}

return AccountPlusSvg
Expand Down
18 changes: 18 additions & 0 deletions apps/files_sharing/src/utils/AccountIcon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*!
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { generateUrl } from '@nextcloud/router'

const isDarkMode = window?.matchMedia?.('(prefers-color-scheme: dark)')?.matches === true
|| document.querySelector('[data-themes*=dark]') !== null

export const generateAvatarSvg = (userId: string, isExternalUser = false) => {
console.log('User ID:', userId)
const url = isDarkMode ? '/avatar/{userId}/32/dark' : '/avatar/{userId}/32'
const avatarUrl = generateUrl(isExternalUser ? url + '?guestFallback=true' : url, { userId })
return `<svg width="32" height="32" viewBox="0 0 32 32"
xmlns="http://www.w3.org/2000/svg" class="sharing-status__avatar">
<image href="${avatarUrl}" height="32" width="32" />
</svg>`
}
17 changes: 17 additions & 0 deletions lib/private/User/LazyUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ private function getUser(): IUser {
$this->user = $this->userManager->get($this->uid);
}
}

if ($this->user === null) {
throw new \Exception('User not found');
}

/** @var IUser */
$user = $this->user;
return $user;
Expand Down Expand Up @@ -167,4 +172,16 @@ public function getManagerUids(): array {
public function setManagerUids(array $uids): void {
$this->getUser()->setManagerUids($uids);
}

public function isFederated(): bool {
try {
// If getUser succeeds then user is definitely not federated
// This could fail for other reasons (especially a race condition where a user is deleted)
// But it's what we have now
$this->getUser();
return false;
} catch (\Exception $e) {
return true;
}
}
}
6 changes: 6 additions & 0 deletions lib/private/User/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -618,4 +618,10 @@ public function triggerChange($feature, $value = null, $oldValue = null) {
$this->emitter->emit('\OC\User', 'changeUser', [$this, $feature, $value, $oldValue]);
}
}

public function isFederated(): bool {
// Federated users are instantiated via LazyUser
// DAV also only uses LazyUser
return false;
}
}
8 changes: 8 additions & 0 deletions lib/public/IUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -287,4 +287,12 @@ public function getManagerUids(): array;
* @since 27.0.0
*/
public function setManagerUids(array $uids): void;

/**
* Check if the user is federated (from another server)
*
* @return bool
* @since 28.0.11
*/
public function isFederated(): bool;
}

0 comments on commit 30aaefd

Please sign in to comment.