Allow fetching the initiator user data if needed

Signed-off-by: Julius Härtl <jus@bitgrid.net>
This commit is contained in:
Julius Härtl 2021-04-26 12:23:17 +02:00
Родитель a9b794a971
Коммит 49fd9ac1d6
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4C614C6ED2CDE6DF
7 изменённых файлов: 87 добавлений и 44 удалений

Просмотреть файл

@ -75,5 +75,6 @@ return [
['name' => 'Federation#index', 'url' => '/api/v1/federation', 'verb' => 'GET'],
['name' => 'Federation#remoteWopiToken', 'url' => '/api/v1/federation', 'verb' => 'POST'],
['name' => 'Federation#initiatorUser', 'url' => '/api/v1/federation/user', 'verb' => 'POST'],
],
];

Просмотреть файл

@ -30,6 +30,8 @@ use OCP\AppFramework\Http\DataResponse;
use OCP\IConfig;
use OCP\ILogger;
use OCP\IRequest;
use OCP\IURLGenerator;
use OCP\IUserManager;
class FederationController extends OCSController {
@ -42,17 +44,27 @@ class FederationController extends OCSController {
/** @var WopiMapper */
private $wopiMapper;
/** @var IUserManager */
private $userManager;
/** @var IURLGenerator */
private $urlGenerator;
public function __construct(
string $appName,
IRequest $request,
IConfig $config,
ILogger $logger,
WopiMapper $wopiMapper
WopiMapper $wopiMapper,
IUserManager $userManager,
IURLGenerator $urlGenerator
) {
parent::__construct($appName, $request);
$this->config = $config;
$this->logger = $logger;
$this->wopiMapper = $wopiMapper;
$this->userManager = $userManager;
$this->urlGenerator = $urlGenerator;
}
/**
@ -84,32 +96,54 @@ class FederationController extends OCSController {
*/
public function remoteWopiToken($token): DataResponse {
try {
$wopi = $this->wopiMapper->getWopiForToken($token);
$user = \OC::$server->getUserManager()->get($wopi->getEditorUid());
if($user !== null) {
$wopi->setGuestDisplayname($user->getDisplayName());
$initiatorWopi = $this->wopiMapper->getWopiForToken($token);
if (empty($initiatorWopi->getEditorUid()) && !empty($initiatorWopi->getRemoteServer()) && !empty($initiatorWopi->getRemoteServerToken())) {
$client = \OC::$server->getHTTPClientService()->newClient();
$response = $client->post(
rtrim($initiatorWopi->getRemoteServer(), '/') . '/ocs/v2.php/apps/richdocuments/api/v1/federation/user?format=json',
[ 'body' => [ 'token' => $initiatorWopi->getRemoteServerToken() ], 'timeout' => 10 ]
);
$initiatorUser = \json_decode($response->getBody(), true)['ocs']['data'];
$initiatorWopi->setGuestDisplayname($initiatorUser['displayName']);
} else {
$user = $this->userManager->get($initiatorWopi->getEditorUid());
if($user !== null) {
$initiatorWopi->setGuestDisplayname($user->getDisplayName());
}
}
$this->logger->debug('COOL-Federation-Initiator: Token ' . $token . ' returned');
return new DataResponse($wopi);
return new DataResponse($initiatorWopi);
} catch (DoesNotExistException $e) {
$this->logger->debug('COOL-Federation-Initiator: Token ' . $token . 'not found');
throw new OCSNotFoundException();
}
}
/**
* @PublicPage
* @NoCSRFRequired
* @OCSRoute POST /api/v1/federation/user
*
* Return user details for a initiator user that will be used by remote instances
* to provide Collabora with the users avatar/displayname for guests on share links
* if the session was created through a direct link of a public share
*
* @param $token
* @return DataResponse
* @throws DoesNotExistException
*/
public function initiatorUser($token): DataResponse {
try {
$wopi = $this->wopiMapper->getWopiForToken($token);
$user = \OC::$server->getUserManager()->get($wopi->getEditorUid());
$user = $this->userManager->get($wopi->getEditorUid());
if($user !== null) {
$wopi->setGuestDisplayname($user->getDisplayName());
}
$this->logger->debug('COOL-Federation-Initiator-User: Token ' . $token . ' returned');
return new DataResponse([
'initiatorHost' => '',
'userId' => '',
'displayName' => '',
'avatar' => ''
'userId' => $user->getUID(),
'displayName' => $user->getDisplayName(),
'avatar' => $this->urlGenerator->linkToRouteAbsolute('core.avatar.getAvatar', ['userId' => $wopi->getEditorUid(), 'size' => WopiController::WOPI_AVATAR_SIZE])
]);
} catch (DoesNotExistException $e) {
$this->logger->debug('COOL-Federation-Initiator-User: Token ' . $token . 'not found');

Просмотреть файл

@ -156,7 +156,7 @@ class OCSController extends \OCP\AppFramework\OCSController {
'path' => $path,
'password' => $password
],
'timeout' => 5
'timeout' => 30
]);
$url = \json_decode($response->getBody(), true)['ocs']['data']['url'];

Просмотреть файл

@ -85,6 +85,8 @@ class WopiController extends Controller {
// Signifies LOOL that document has been changed externally in this storage
const LOOL_STATUS_DOC_CHANGED = 1010;
const WOPI_AVATAR_SIZE = 32;
/**
* @param string $appName
* @param IRequest $request
@ -230,7 +232,7 @@ class WopiController extends Controller {
$user = $this->userManager->get($wopi->getEditorUid());
if($user !== null) {
$response['UserExtraInfo']['avatar'] = $this->urlGenerator->linkToRouteAbsolute('core.avatar.getAvatar', ['userId' => $wopi->getEditorUid(), 'size' => 32]);
$response['UserExtraInfo']['avatar'] = $this->urlGenerator->linkToRouteAbsolute('core.avatar.getAvatar', ['userId' => $wopi->getEditorUid(), 'size' => self::WOPI_AVATAR_SIZE]);
}
if ($wopi->isRemoteToken()) {
@ -242,12 +244,14 @@ class WopiController extends Controller {
private function setFederationFileInfo(Wopi $wopi, $response) {
$response['UserId'] = 'Guest-' . \OC::$server->getSecureRandom()->generate(8);
if ($wopi->getTokenType() === Wopi::TOKEN_TYPE_REMOTE_USER) {
$remoteUserId = $wopi->getGuestDisplayname();
$cloudID = \OC::$server->getCloudIdManager()->resolveCloudId($remoteUserId);
$response['UserId'] = $cloudID->getDisplayId();
$response['UserFriendlyName'] = $cloudID->getDisplayId();
$response['UserExtraInfo']['avatar'] = $this->urlGenerator->linkToRouteAbsolute('core.avatar.getAvatar', ['userId' => explode('@', $remoteUserId)[0], 'size' => 32]);
$response['UserExtraInfo']['avatar'] = $this->urlGenerator->linkToRouteAbsolute('core.avatar.getAvatar', ['userId' => explode('@', $remoteUserId)[0], 'size' => self::WOPI_AVATAR_SIZE]);
$cleanCloudId = str_replace(['http://', 'https://'], '', $cloudID->getId());
$addressBookEntries = \OC::$server->getContactsManager()->search($cleanCloudId, ['CLOUD']);
foreach ($addressBookEntries as $entry) {
@ -260,24 +264,20 @@ class WopiController extends Controller {
}
}
}
} else if ($wopi->getTokenType() === Wopi::TOKEN_TYPE_REMOTE_GUEST) {
$response['UserId'] = 'Guest-' . \OC::$server->getSecureRandom()->generate(8);
}
$initiator = $this->federationService->getRemoteFileDetails($wopi->getRemoteServer(), $wopi->getRemoteServerToken());
if ($initiator !== null) {
if ($initiator->hasTemplateId()) {
$templateUrl = $wopi->getRemoteServer() . '/index.php/apps/richdocuments/wopi/template/' . $initiator->getTemplateId() . '?access_token=' . $initiator->getToken();
$response['TemplateSource'] = $templateUrl;
}
if ($wopi->getTokenType() === Wopi::TOKEN_TYPE_REMOTE_USER) {
$response['UserExtraInfo']['avatar'] = $wopi->getRemoteServer() . '/index.php/avatar/' . $initiator->getEditorUid() . '/32';
}
if ($wopi->getTokenType() === Wopi::TOKEN_TYPE_REMOTE_GUEST && $initiator->getEditorUid()) {
$response['UserFriendlyName'] = $initiator->getGuestDisplayname() . ' (Guest)';
$response['UserExtraInfo']['avatar'] = $wopi->getRemoteServer() . '/index.php/avatar/' . $initiator->getEditorUid() . '/32';
}
if ($initiator === null) {
return $response;
}
$response['UserFriendlyName'] = $initiator->getGuestDisplayname() . ' (Guest)';
if ($initiator->hasTemplateId()) {
$templateUrl = $wopi->getRemoteServer() . '/index.php/apps/richdocuments/wopi/template/' . $initiator->getTemplateId() . '?access_token=' . $initiator->getToken();
$response['TemplateSource'] = $templateUrl;
}
if ($wopi->getTokenType() === Wopi::TOKEN_TYPE_REMOTE_USER || ($wopi->getTokenType() === Wopi::TOKEN_TYPE_REMOTE_GUEST && $initiator->getEditorUid())) {
$response['UserExtraInfo']['avatar'] = $wopi->getRemoteServer() . '/index.php/avatar/' . $initiator->getEditorUid() . '/'. self::WOPI_AVATAR_SIZE;
}
return $response;

Просмотреть файл

@ -28,6 +28,7 @@ use OCA\Federation\TrustedServers;
use OCA\Files_Sharing\External\Storage as SharingExternalStorage;
use OCA\Richdocuments\Db\Direct;
use OCA\Richdocuments\Db\Wopi;
use OCA\Richdocuments\Db\WopiMapper;
use OCA\Richdocuments\TokenManager;
use OCP\AppFramework\Http\RedirectResponse;
use OCP\AppFramework\QueryException;
@ -91,7 +92,7 @@ class FederationService {
}
try {
$client = $this->clientService->newClient();
$response = $client->get($remote . '/ocs/v2.php/apps/richdocuments/api/v1/federation?format=json', ['timeout' => 5]);
$response = $client->get($remote . '/ocs/v2.php/apps/richdocuments/api/v1/federation?format=json', ['timeout' => 30]);
$data = \json_decode($response->getBody(), true);
$remoteCollabora = $data['ocs']['data']['wopi_url'];
$this->cache->set('richdocuments_remote/' . $remote, $remoteCollabora, 3600);
@ -168,7 +169,7 @@ class FederationService {
$this->logger->debug('COOL-Federation-Source: Fetching remote file details from ' . $remote . ' for token ' . $remoteToken);
$client = $this->clientService->newClient();
$response = $client->post($remote . '/ocs/v2.php/apps/richdocuments/api/v1/federation?format=json', [
'timeout' => 5,
'timeout' => 30,
'body' => [
'token' => $remoteToken
]
@ -179,7 +180,7 @@ class FederationService {
$this->cache->set($cacheKey, $data['ocs']['data']);
return Wopi::fromParams($data['ocs']['data']);
} catch (\Throwable $e) {
$this->logger->error('COOL-Federation-Source: Unable to fetch remote file details for ' . $remoteToken . ' from ' . $remote, ['exception' => $e]);
$this->logger->logException($e, ['message' => 'COOL-Federation-Source: Unable to fetch remote file details for ' . $remoteToken . ' from ' . $remote ]);
}
return null;
}
@ -204,12 +205,12 @@ class FederationService {
$initiatorServer = $wopi->getServerHost();
$initiatorToken = $wopi->getToken();
if ($direct) {
//$wopi->setRemoteServer($direct->getInitiatorHost());
//$wopi->setRemoteServerToken($direct->getInitiatorToken());
// FIXME: the direct token might have a different originator when a share link originating on a federated stoarge is opened
// editor uid is null since we don't fetch it from the initiator of direct so @{link remoteWopiToken()} fails
// Currently there is no mapping from the initiator user data to the source then
/**
* If the request to open a file originates from a direct token we might need to fetch the initiator user details when the initiator wopi token is accessed
* as the user might origin on a 3rd instance
*/
if ($direct && !empty($direct->getInitiatorHost()) && !empty($direct->getInitiatorToken())) {
$this->tokenManager->extendWithInitiatorUserToken($wopi, $direct->getInitiatorHost(), $direct->getInitiatorToken());
}
$url = rtrim($remote, '/') . '/index.php/apps/richdocuments/remote?shareToken=' . $item->getStorage()->getToken() .

Просмотреть файл

@ -225,9 +225,11 @@ class TokenManager {
$remoteTokenType = $remoteWopi->getEditorUid() !== null ? Wopi::TOKEN_TYPE_REMOTE_USER : Wopi::TOKEN_TYPE_REMOTE_GUEST;
$wopi->setTokenType($remoteTokenType);
if ($remoteTokenType === Wopi::TOKEN_TYPE_REMOTE_USER) {
$wopi->setGuestDisplayname($remoteWopi->getEditorUid() . '@' . $remoteServer);
}
$wopi->setGuestDisplayname(
$remoteTokenType === Wopi::TOKEN_TYPE_REMOTE_USER ?
$remoteWopi->getEditorUid() . '@' . $remoteServer :
$remoteWopi->getGuestDisplayname()
);
$wopi->setShare($shareToken);
$wopi->setCanwrite($wopi->getCanwrite() && $remoteWopi->getCanwrite());
$wopi->setHideDownload($wopi->getHideDownload() || $remoteWopi->getHideDownload());
@ -302,4 +304,11 @@ class TokenManager {
return $this->wopiMapper->generateInitiatorToken($this->userId, $sourceServer);
}
public function extendWithInitiatorUserToken(Wopi $wopi, string $initiatorUserHost, string $initiatorUserToken): Wopi {
$wopi->setRemoteServer($initiatorUserHost);
$wopi->setRemoteServerToken($initiatorUserToken);
$this->wopiMapper->update($wopi);
return $wopi;
}
}

Просмотреть файл

@ -207,9 +207,7 @@ Feature: Direct editing
And Collabora fetches checkFileInfo
And Collabora fetches and receives the following in the checkFileInfo response
| BaseFileName | document-reshare-fed-link.odt |
| UserFriendlyName | Anonymous guest |
# FIXME: Known issue as of right now as we do not fetch the initiator user yet
# | UserFriendlyName | user3-displayname (Guest) |
| UserFriendlyName | user3-displayname (Guest) |
And checkFileInfo "UserId" matches "/Guest-/"
And checkFileInfo "UserCanWrite" is false
And both Collabora files used the same file id