Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/richdocuments.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--appinfo/routes.php2
-rw-r--r--docs/mobile_editor.md7
-rw-r--r--lib/Controller/DocumentController.php8
-rw-r--r--lib/Controller/OCSController.php47
-rw-r--r--lib/Controller/WopiController.php2
-rw-r--r--lib/Db/Wopi.php2
-rw-r--r--lib/Helper.php2
-rw-r--r--lib/TokenManager.php48
-rw-r--r--src/document.js11
-rw-r--r--src/helpers/guestName.js13
-rw-r--r--tests/features/bootstrap/DirectContext.php60
-rw-r--r--tests/features/bootstrap/RichDocumentsContext.php10
-rw-r--r--tests/features/bootstrap/WopiContext.php4
-rw-r--r--tests/features/direct.feature87
14 files changed, 253 insertions, 50 deletions
diff --git a/appinfo/routes.php b/appinfo/routes.php
index 02c0baf8..877616dd 100644
--- a/appinfo/routes.php
+++ b/appinfo/routes.php
@@ -73,6 +73,8 @@ return [
['name' => 'OCS#getTemplates', 'url' => '/api/v1/templates/{type}', 'verb' => 'GET'],
['name' => 'OCS#createFromTemplate', 'url' => '/api/v1/templates/new', 'verb' => 'POST'],
+ ['name' => 'OCS#updateGuestName', 'url' => '/api/v1/wopi/guestname', 'verb' => 'POST'],
+
['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'],
diff --git a/docs/mobile_editor.md b/docs/mobile_editor.md
index 343d4e78..158192f3 100644
--- a/docs/mobile_editor.md
+++ b/docs/mobile_editor.md
@@ -35,6 +35,7 @@ document:
The returned xml or json will have an url to open in a webview.
-The user will join the session as a guest but with their user details provided by their own
-instance.
-
+The endpoint can be used with or without user credentials for the Nextcloud server.
+For anonymous requests the webview will ask the user for a guest name on writable
+files. When requesting a link as an authenticated user, the user will join the
+document as a guest but with their user details provided by their own instance.
diff --git a/lib/Controller/DocumentController.php b/lib/Controller/DocumentController.php
index 664d17a3..bca32ffa 100644
--- a/lib/Controller/DocumentController.php
+++ b/lib/Controller/DocumentController.php
@@ -360,11 +360,9 @@ class DocumentController extends Controller {
'userId' => $this->uid,
];
- if ($this->uid !== null || ($share->getPermissions() & \OCP\Constants::PERMISSION_UPDATE) === 0 || $this->helper->getGuestName() !== null) {
- list($urlSrc, $token) = $this->tokenManager->getToken($item->getId(), $shareToken, $this->uid);
- $params['token'] = $token;
- $params['urlsrc'] = $urlSrc;
- }
+ list($urlSrc, $token) = $this->tokenManager->getToken($item->getId(), $shareToken, $this->uid);
+ $params['token'] = $token;
+ $params['urlsrc'] = $urlSrc;
$response = new TemplateResponse('richdocuments', 'documents', $params, 'base');
$this->setupPolicy($response);
diff --git a/lib/Controller/OCSController.php b/lib/Controller/OCSController.php
index d1eb7181..52bcaa88 100644
--- a/lib/Controller/OCSController.php
+++ b/lib/Controller/OCSController.php
@@ -24,9 +24,12 @@
namespace OCA\Richdocuments\Controller;
use OCA\Richdocuments\Db\DirectMapper;
+use OCA\Richdocuments\Db\Wopi;
+use OCA\Richdocuments\Helper;
use OCA\Richdocuments\Service\FederationService;
use OCA\Richdocuments\TemplateManager;
use OCA\Richdocuments\TokenManager;
+use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCS\OCSBadRequestException;
@@ -150,16 +153,22 @@ class OCSController extends \OCP\AppFramework\OCSController {
$wopi = $this->tokenManager->newInitiatorToken($host, null, $shareToken, true, $this->userId);
$client = \OC::$server->getHTTPClientService()->newClient();
- $response = $client->post(rtrim($host, '/') . '/ocs/v2.php/apps/richdocuments/api/v1/direct/share/initiator?format=json', [
- 'body' => [
- 'initiatorServer' => \OC::$server->getURLGenerator()->getAbsoluteURL(''),
- 'initiatorToken' => $wopi->getToken(),
- 'shareToken' => $shareToken,
- 'path' => $path,
- 'password' => $password
- ],
- 'timeout' => 30
- ]);
+ try {
+ $response = $client->post(rtrim($host, '/') . '/ocs/v2.php/apps/richdocuments/api/v1/direct/share/initiator?format=json', [
+ 'body' => [
+ 'initiatorServer' => \OC::$server->getURLGenerator()->getAbsoluteURL(''),
+ 'initiatorToken' => $wopi->getToken(),
+ 'shareToken' => $shareToken,
+ 'path' => $path,
+ 'password' => $password
+ ],
+ 'timeout' => 30
+ ]);
+ } catch (\Exception $e) {
+ $response = new DataResponse([], HTTP::STATUS_FORBIDDEN);
+ $response->throttle();
+ return $response;
+ }
$url = \json_decode($response->getBody(), true)['ocs']['data']['url'];
return new DataResponse([
@@ -246,6 +255,24 @@ class OCSController extends \OCP\AppFramework\OCSController {
}
/**
+ * Generate a direct editing link for a file in a public share to open with the current user
+ *
+ * @NoAdminRequired
+ * @BruteForceProtection(action=richdocumentsCreatePublic)
+ * @PublicPage
+ */
+ public function updateGuestName(string $access_token, string $guestName): DataResponse {
+ try {
+ $this->tokenManager->updateGuestName($access_token, $guestName);
+ return new DataResponse([], Http::STATUS_OK);
+ } catch (DoesNotExistException $e) {
+ $response = new DataResponse([], Http::STATUS_FORBIDDEN);
+ $response->throttle();
+ return $response;
+ }
+ }
+
+ /**
* @NoAdminRequired
*
* @param string $type The template type
diff --git a/lib/Controller/WopiController.php b/lib/Controller/WopiController.php
index 20cec6d9..d01db98f 100644
--- a/lib/Controller/WopiController.php
+++ b/lib/Controller/WopiController.php
@@ -271,7 +271,7 @@ class WopiController extends Controller {
return $response;
}
- $response['UserFriendlyName'] = $initiator->getGuestDisplayname() . ' (Guest)';
+ $response['UserFriendlyName'] = $this->tokenManager->prepareGuestName($initiator->getGuestDisplayname());
if ($initiator->hasTemplateId()) {
$templateUrl = $wopi->getRemoteServer() . '/index.php/apps/richdocuments/wopi/template/' . $initiator->getTemplateId() . '?access_token=' . $initiator->getToken();
$response['TemplateSource'] = $templateUrl;
diff --git a/lib/Db/Wopi.php b/lib/Db/Wopi.php
index 11d7d4ed..31250603 100644
--- a/lib/Db/Wopi.php
+++ b/lib/Db/Wopi.php
@@ -51,7 +51,7 @@ use OCP\AppFramework\Db\Entity;
* @method string getRemoteServerToken()
* @method void setExpiry(int $expiry)
* @method int getExpiry()
- * @method void setGuestDisplayname(string $token)
+ * @method void setGuestDisplayname(string $guestDisplayName)
* @method string getGuestDisplayname()
* @method void setTemplateDestination(int $fileId)
* @method int getTemplateDestination()
diff --git a/lib/Helper.php b/lib/Helper.php
index aa48dc35..6b96d3a7 100644
--- a/lib/Helper.php
+++ b/lib/Helper.php
@@ -82,7 +82,7 @@ class Helper {
return $filename;
}
- public function getGuestName() {
+ public function getGuestNameFromCookie() {
if ($this->userId !== null || !isset($_COOKIE['guestUser']) || $_COOKIE['guestUser'] === '') {
return null;
}
diff --git a/lib/TokenManager.php b/lib/TokenManager.php
index 8c563f73..1ad20db8 100644
--- a/lib/TokenManager.php
+++ b/lib/TokenManager.php
@@ -21,11 +21,14 @@
namespace OCA\Richdocuments;
+use InvalidArgumentException;
use OCA\Richdocuments\Db\Direct;
use OCA\Richdocuments\Db\WopiMapper;
use OCA\Richdocuments\Db\Wopi;
use OCA\Richdocuments\Service\CapabilitiesService;
use OCA\Richdocuments\WOPI\Parser;
+use OCP\AppFramework\Db\DoesNotExistException;
+use OCP\AppFramework\Http\DataResponse;
use OCP\Constants;
use OCP\Files\File;
use OCP\Files\ForbiddenException;
@@ -192,22 +195,7 @@ class TokenManager {
fclose($fp);
$serverHost = $this->urlGenerator->getAbsoluteURL('/');
-
- $guestName = null;
- if ($this->userId === null) {
- if ($guestName = $this->helper->getGuestName()) {
- $guestName = $this->trans->t('%s (Guest)', Util::sanitizeHTML($guestName));
- $cut = 56;
- while (mb_strlen($guestName) >= 64) {
- $guestName = $this->trans->t('%s (Guest)', Util::sanitizeHTML(
- mb_substr($guestName, 0, $cut)
- ));
- $cut -= 5;
- }
- } else {
- $guestName = $this->trans->t('Anonymous guest');
- }
- }
+ $guestName = $this->userId === null ? $this->prepareGuestName($this->helper->getGuestNameFromCookie()) : null;
$wopi = $this->wopiMapper->generateFileToken($fileId, $owneruid, $editoruid, $version, $updatable, $serverHost, $guestName, 0, $hideDownload, $direct, 0, $shareToken);
return [
@@ -314,4 +302,32 @@ class TokenManager {
return $wopi;
}
+ public function prepareGuestName(string $guestName = null) {
+ if (empty($guestName)) {
+ return $this->trans->t('Anonymous guest');
+ }
+
+ $guestName = $this->trans->t('%s (Guest)', Util::sanitizeHTML($guestName));
+ $cut = 56;
+ while (mb_strlen($guestName) >= 64) {
+ $guestName = $this->trans->t('%s (Guest)', Util::sanitizeHTML(
+ mb_substr($guestName, 0, $cut)
+ ));
+ $cut -= 5;
+ }
+
+ return $guestName;
+ }
+
+ /**
+ * @param string $accessToken
+ * @param string $guestName
+ * @throws DoesNotExistException
+ */
+ public function updateGuestName(string $accessToken, string $guestName) {
+ $wopi = $this->wopiMapper->getWopiForToken($accessToken);
+ $wopi->setGuestDisplayname($this->prepareGuestName($guestName));
+ $this->wopiMapper->update($wopi);
+ }
+
}
diff --git a/src/document.js b/src/document.js
index 63e93a96..53c89be7 100644
--- a/src/document.js
+++ b/src/document.js
@@ -2,7 +2,7 @@ import { emit } from '@nextcloud/event-bus'
import { getRootUrl } from '@nextcloud/router'
import { getRequestToken } from '@nextcloud/auth'
import Config from './services/config.tsx'
-import { setGuestNameCookie, shouldAskForGuestName } from './helpers/guestName'
+import { setGuestName, shouldAskForGuestName } from './helpers/guestName'
import PostMessageService from './services/postMessage.tsx'
import {
@@ -139,8 +139,13 @@ $.widget('oc.guestNamePicker', {
$('#documents-content').prepend(text)
const setGuestNameSubmit = () => {
const username = $('#nickname').val()
- setGuestNameCookie(username)
- window.location.reload(true)
+ div.remove()
+ text.innerText = ''
+ text.classList.add('icon-loading')
+ setGuestName(username).then(() => {
+ $('#documents-content').remove()
+ documentsMain.initSession()
+ })
}
$('#nickname').keyup(function(event) {
diff --git a/src/helpers/guestName.js b/src/helpers/guestName.js
index b47a8e3c..d32a94e0 100644
--- a/src/helpers/guestName.js
+++ b/src/helpers/guestName.js
@@ -22,6 +22,8 @@
import Config from './../services/config.tsx'
import { getCurrentUser } from '@nextcloud/auth'
+import axios from '@nextcloud/axios'
+import { generateOcsUrl } from '@nextcloud/router'
import mobile from './mobile'
let guestName = ''
@@ -44,11 +46,16 @@ const getGuestNameCookie = function() {
return guestName
}
-const setGuestNameCookie = function(username) {
+const setGuestName = function(username) {
if (username !== '') {
- document.cookie = 'guestUser=' + encodeURIComponent(username) + '; path=/'
+ // document.cookie = 'guestUser=' + encodeURIComponent(username) + '; path=/'
guestName = username
}
+ const accessToken = encodeURIComponent(Config.get('token'))
+ return axios.post(generateOcsUrl('apps/richdocuments/api/v1/wopi', 2) + 'guestname', {
+ access_token: accessToken,
+ guestName,
+ })
}
const shouldAskForGuestName = () => {
@@ -61,6 +68,6 @@ const shouldAskForGuestName = () => {
export {
getGuestNameCookie,
- setGuestNameCookie,
+ setGuestName,
shouldAskForGuestName,
}
diff --git a/tests/features/bootstrap/DirectContext.php b/tests/features/bootstrap/DirectContext.php
index 4c17a0f4..4662d35d 100644
--- a/tests/features/bootstrap/DirectContext.php
+++ b/tests/features/bootstrap/DirectContext.php
@@ -83,6 +83,46 @@ class DirectContext implements Context {
$this->handleDirectEditingLink();
}
+ /**
+ * @When /^User "([^"]*)" opens the file "([^"]*)" in the last share link through direct editing from server "([^"]*)"$/
+ */
+ public function userOpensTheFileInTheLastShareLinkThroughDirectEditingFromServer($user, $path, $host) {
+ $shareToken = $this->sharingContext->getLastShareData()['token'];
+ $this->serverContext->usingWebAsUser($user);
+ $this->requestPublicDirectEditingLink($user, $shareToken, $path, null, $this->serverContext->getServer($host));
+ $this->handleDirectEditingLink();
+ }
+
+ /**
+ * @When /^User "([^"]*)" opens the file "([^"]*)" in the last share link through direct editing from server "([^"]*)" with password "([^"]*)"$/
+ */
+ public function userOpensTheFileInTheLastShareLinkThroughDirectEditingFromServerWithPassword($user, $path, $host, $password) {
+ $shareToken = $this->sharingContext->getLastShareData()['token'];
+ $this->serverContext->usingWebAsUser($user);
+ $this->requestPublicDirectEditingLink($user, $shareToken, $path, $password, $this->serverContext->getServer($host));
+ $this->handleDirectEditingLink();
+ }
+
+ /**
+ * @When /^User "([^"]*)" cannot open the file "([^"]*)" in the last share link through direct editing from server "([^"]*)" with password "([^"]*)"$/
+ */
+ public function userCannotOpenTheFileInTheLastShareLinkThroughDirectEditingFromServerWithPassword($user, $path, $host, $password) {
+ $shareToken = $this->sharingContext->getLastShareData()['token'];
+ $this->serverContext->usingWebAsUser($user);
+ $this->requestPublicDirectEditingLink($user, $shareToken, $path, $password, $this->serverContext->getServer($host));
+ $this->serverContext->assertHttpStatusCode(403);
+ }
+
+ /**
+ * @When /^A guest opens the file "([^"]*)" in the last share link through direct editing$/
+ */
+ public function aGuestOpensTheFileInTheLastShareLinkThroughDirectEditing($path) {
+ $shareToken = $this->sharingContext->getLastShareData()['token'];
+ $this->serverContext->usingWebasGuest();
+ $this->requestPublicDirectEditingLink(null, $shareToken, $path);
+ $this->handleDirectEditingLink();
+ }
+
private function handleDirectEditingLink() {
$this->serverContext->assertHttpStatusCode(200);
$data = $this->serverContext->getOCSResponseData();
@@ -152,13 +192,25 @@ class DirectContext implements Context {
$this->serverContext->sendOCSRequest('POST', 'apps/richdocuments/api/v1/document', [ 'fileId' => $fileId ]);
}
- private function requestPublicDirectEditingLink($user, $token, $filePath = null, $password = null) {
- $this->serverContext->sendOCSRequest('POST', 'apps/richdocuments/api/v1/share', [
- 'host' => $this->serverContext->getBaseUrl(),
+ /**
+ * @param $user
+ * @param $token
+ * @param null $filePath
+ * @param null $password
+ * @param null $host
+ */
+ private function requestPublicDirectEditingLink($user, $token, $filePath = null, $password = null, $host = null) {
+ // ServerContext currently does not support sending anonymous ocs requests
+ $options = $user ? [] : [ 'auth' => null ];
+ $data = [
'shareToken' => $token,
'path' => $filePath,
'password' => $password
- ]);
+ ];
+ if ($host) {
+ $data['host'] = $host;
+ }
+ $this->serverContext->sendOCSRequest('POST', 'apps/richdocuments/api/v1/share', $data, $options);
}
}
diff --git a/tests/features/bootstrap/RichDocumentsContext.php b/tests/features/bootstrap/RichDocumentsContext.php
index cea95325..20cf8bf4 100644
--- a/tests/features/bootstrap/RichDocumentsContext.php
+++ b/tests/features/bootstrap/RichDocumentsContext.php
@@ -215,4 +215,14 @@ class RichDocumentsContext implements Context
$this->wopiToken = $result['token'];
$this->wopiContext->setWopiParameters($this->currentServer, $this->fileId, $this->wopiToken);
}
+
+ /**
+ * @When /^the guest updates the display name to "([^"]*)"$/
+ */
+ public function updateTheGuestDisplayName($displayName) {
+ $this->serverContext->sendOCSRequest('POST', 'apps/richdocuments/api/v1/wopi/guestname', [
+ 'access_token' => $this->wopiContext->getWopiToken(),
+ 'guestName' => $displayName,
+ ], [ 'auth' => null ]);
+ }
}
diff --git a/tests/features/bootstrap/WopiContext.php b/tests/features/bootstrap/WopiContext.php
index 03ddda51..d115b884 100644
--- a/tests/features/bootstrap/WopiContext.php
+++ b/tests/features/bootstrap/WopiContext.php
@@ -66,6 +66,10 @@ class WopiContext implements Context {
return $this->serverContext->getBaseUrl();
}
+ public function getWopiToken() {
+ return $this->wopiToken;
+ }
+
public function setWopiParameters($server, $fileId, $accessToken) {
$this->currentServer = $server;
$this->fileId = $fileId;
diff --git a/tests/features/direct.feature b/tests/features/direct.feature
index 8359b020..b09103d1 100644
--- a/tests/features/direct.feature
+++ b/tests/features/direct.feature
@@ -129,7 +129,8 @@ Feature: Direct editing
And Collabora fetches and receives the following in the checkFileInfo response
| BaseFileName | document-share-link.odt |
| OwnerId | user1 |
- | UserFriendlyName | user2-displayname (Guest) |
+ | UserId | user2 |
+ | UserFriendlyName | user2-displayname |
And checkFileInfo "UserCanWrite" is true
And both Collabora files used the same file id
And Collabora can save the file with the content of "./../assets/template.ods"
@@ -151,8 +152,8 @@ Feature: Direct editing
And Collabora fetches and receives the following in the checkFileInfo response
| BaseFileName | document-share-link.odt |
| OwnerId | user1 |
- | UserFriendlyName | user2-displayname (Guest) |
- And checkFileInfo "UserId" matches "/Guest-/"
+ | UserId | user2 |
+ | UserFriendlyName | user2-displayname |
And both Collabora files used the same file id
And Collabora can not save the file with the content of "./../assets/template.ods"
Then Collabora downoads the file and it is equal to "./../assets/template.odt"
@@ -174,6 +175,57 @@ Feature: Direct editing
And Collabora fetches and receives the following in the checkFileInfo response
| BaseFileName | document-share-link.odt |
| OwnerId | user1 |
+ | UserId | user2 |
+ | UserFriendlyName | user2-displayname |
+ And checkFileInfo "UserCanWrite" is true
+ And both Collabora files used the same file id
+ And Collabora can save the file with the content of "./../assets/template.ods"
+ Then Collabora downoads the file and it is equal to "./../assets/template.ods"
+
+ Scenario: Open a file in a shared folder of a share link with direct editing as writable as a guest
+ Given on instance "serverA"
+ And as user "user1"
+ And User "user1" creates a folder "Folder"
+ And User "user1" uploads file "./../assets/template.odt" to "/Folder/document-share-link.odt"
+ When User "user1" opens "/Folder/document-share-link.odt" through direct editing
+ And Collabora fetches checkFileInfo
+ And as "user1" create a share with
+ | path | /Folder/ |
+ | shareType | 3 |
+ And Updating last share with
+ | permissions | 3 |
+ When A guest opens the file "/document-share-link.odt" in the last share link through direct editing
+ And Collabora fetches and receives the following in the checkFileInfo response
+ | BaseFileName | document-share-link.odt |
+ | OwnerId | user1 |
+ | UserFriendlyName | Anonymous guest |
+ When the guest updates the display name to "Random name"
+ And Collabora fetches checkFileInfo
+ And checkFileInfo "UserFriendlyName" is "Random name (Guest)"
+ And checkFileInfo "UserId" matches "/Guest-/"
+ And checkFileInfo "UserCanWrite" is true
+ And both Collabora files used the same file id
+ And Collabora can save the file with the content of "./../assets/template.ods"
+ Then Collabora downoads the file and it is equal to "./../assets/template.ods"
+
+ Scenario: Open a file in a shared folder of a share link with direct editing as writable as a remote user
+ Given on instance "serverA"
+ And as user "user1"
+ And User "user1" creates a folder "Folder"
+ And User "user1" uploads file "./../assets/template.odt" to "/Folder/document-share-link.odt"
+ When User "user1" opens "/Folder/document-share-link.odt" through direct editing
+ And Collabora fetches checkFileInfo
+ And as "user1" create a share with
+ | path | /Folder/ |
+ | shareType | 3 |
+ And Updating last share with
+ | permissions | 3 |
+ Given on instance "serverB"
+ And as user "user2"
+ When User "user2" opens the file "/document-share-link.odt" in the last share link through direct editing from server "serverA"
+ And Collabora fetches and receives the following in the checkFileInfo response
+ | BaseFileName | document-share-link.odt |
+ | OwnerId | user1 |
| UserFriendlyName | user2-displayname (Guest) |
And checkFileInfo "UserId" matches "/Guest-/"
And checkFileInfo "UserCanWrite" is true
@@ -181,6 +233,35 @@ Feature: Direct editing
And Collabora can save the file with the content of "./../assets/template.ods"
Then Collabora downoads the file and it is equal to "./../assets/template.ods"
+ Scenario: Open a file in a shared folder of a share link with direct editing as writable as a remote user with password
+ Given on instance "serverA"
+ And as user "user1"
+ And User "user1" creates a folder "Folder"
+ And User "user1" uploads file "./../assets/template.odt" to "/Folder/document-share-link.odt"
+ When User "user1" opens "/Folder/document-share-link.odt" through direct editing
+ And Collabora fetches checkFileInfo
+ And as "user1" create a share with
+ | path | /Folder/ |
+ | shareType | 3 |
+ | password | mysecret |
+ And Updating last share with
+ | permissions | 3 |
+ Given on instance "serverB"
+ And as user "user2"
+ When User "user2" opens the file "/document-share-link.odt" in the last share link through direct editing from server "serverA" with password "mysecret"
+ And Collabora fetches and receives the following in the checkFileInfo response
+ | BaseFileName | document-share-link.odt |
+ | OwnerId | user1 |
+ | UserFriendlyName | user2-displayname (Guest) |
+ And checkFileInfo "UserId" matches "/Guest-/"
+ And checkFileInfo "UserCanWrite" is true
+ And both Collabora files used the same file id
+ And Collabora can save the file with the content of "./../assets/template.ods"
+ Then Collabora downoads the file and it is equal to "./../assets/template.ods"
+
+ And as user "user2"
+ When User "user2" cannot open the file "/document-share-link.odt" in the last share link through direct editing from server "serverA" with password "wrongpassword"
+
@federation @known-failure-ci
Scenario: Open a link that originates on a federated share through direct editing
Given user "user3" exists