Skip to content

Commit 9e7c050

Browse files
committed
fix(settings): generate user config per userId & handle guest users
Signed-off-by: codewithvk <[email protected]>
1 parent 9c39ff0 commit 9e7c050

File tree

5 files changed

+68
-23
lines changed

5 files changed

+68
-23
lines changed

appinfo/routes.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
['name' => 'settings#uploadFontFile', 'url' => 'settings/fonts', 'verb' => 'POST'],
3939
[
4040
'name' => 'settings#getSettingsFile',
41-
'url' => 'settings/{type}/{category}/{name}',
41+
'url' => 'settings/{type}/{token}/{category}/{name}',
4242
'verb' => 'GET',
4343
'requirements' => [
4444
'type' => '[a-zA-Z0-9_\-]+',

lib/Controller/SettingsController.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
use OCP\Util;
3333
use Psr\Log\LoggerInterface;
3434
use Symfony\Component\Console\Output\NullOutput;
35+
use OCA\Richdocuments\Db\WopiMapper;
3536

3637
class SettingsController extends Controller {
3738
// TODO adapt overview generation if we add more font mimetypes
@@ -58,6 +59,7 @@ public function __construct(
5859
private SettingsService $settingsService,
5960
private LoggerInterface $logger,
6061
private IURLGenerator $urlGenerator,
62+
private WopiMapper $wopiMapper,
6163
private ?string $userId,
6264
) {
6365
parent::__construct($appName, $request);
@@ -484,8 +486,14 @@ public function uploadFontFile(): JSONResponse {
484486
* @PublicPage
485487
* @NoCSRFRequired
486488
**/
487-
public function getSettingsFile(string $type, string $category, string $name) {
489+
public function getSettingsFile(string $type, string $token, string $category, string $name) {
488490
try {
491+
$wopi = $this->wopiMapper->getWopiForToken($token);
492+
if ($type === 'userconfig')
493+
{
494+
$userId = $wopi->getEditorUid() ?: $wopi->getOwnerUid();
495+
$type = $type . '/' . $userId;
496+
}
489497
$systemFile = $this->settingsService->getSettingsFile($type, $category, $name);
490498
return new DataDisplayResponse(
491499
$systemFile->getContent(),

lib/Controller/WopiController.php

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,9 @@ public function checkFileInfo(string $fileId, string $access_token): JSONRespons
139139

140140
$userId = !$isPublic ? $wopi->getEditorUid() : $guestUserId;
141141

142-
$userSettings = $this->generateSettings($userId, 'userconfig');
142+
if (!$isPublic) {
143+
$userSettings = $this->generateSettings($userId, 'userconfig');
144+
}
143145
$sharedSettings = $this->generateSettings($userId, 'systemconfig');
144146

145147
$response = [
@@ -174,10 +176,13 @@ public function checkFileInfo(string $fileId, string $access_token): JSONRespons
174176
'EnableRemoteAIContent' => $isTaskProcessingEnabled,
175177
'HasContentRange' => true,
176178
'ServerPrivateInfo' => [],
177-
'UserSettings' => $userSettings,
178179
'SharedSettings' => $sharedSettings,
179180
];
180181

182+
if (!$isPublic) {
183+
$response['UserSettings'] = $userSettings;
184+
}
185+
181186
$enableZotero = $this->config->getAppValue(Application::APPNAME, 'zoteroEnabled', 'yes') === 'yes';
182187
if (!$isPublic && $enableZotero) {
183188
$zoteroAPIKey = $this->config->getUserValue($wopi->getEditorUid(), 'richdocuments', 'zoteroAPIKey', '');
@@ -406,13 +411,12 @@ public function getSettings(string $type, string $access_token): JSONResponse {
406411
if ($wopi->getTokenType() !== Wopi::TOKEN_TYPE_SETTING_AUTH) {
407412
return new JSONResponse(['error' => 'Invalid token type'], Http::STATUS_BAD_REQUEST);
408413
}
414+
415+
$isPublic = empty($wopi->getEditorUid());
416+
$guestUserId = 'Guest-' . \OC::$server->getSecureRandom()->generate(8);
417+
$userId = !$isPublic ? $wopi->getEditorUid() : $guestUserId;
409418

410-
$user = $this->userManager->get($wopi->getOwnerUid());
411-
if (!$user || !$this->groupManager->isAdmin($user->getUID())) {
412-
return new JSONResponse(['error' => 'Access denied'], Http::STATUS_BAD_REQUEST);
413-
}
414-
415-
$userConfig = $this->settingsService->generateSettingsConfig($type);
419+
$userConfig = $this->settingsService->generateSettingsConfig($type, $userId);
416420
return new JSONResponse($userConfig, Http::STATUS_OK);
417421
} catch (UnknownTokenException|ExpiredTokenException $e) {
418422
$this->logger->debug($e->getMessage(), ['exception' => $e]);
@@ -431,6 +435,7 @@ public function uploadSettingsFile(string $fileId, string $access_token): JSONRe
431435
try {
432436
$wopi = $this->wopiMapper->getWopiForToken($access_token);
433437

438+
$userId = $wopi->getEditorUid();
434439
// TODO: auth - for admin??
435440
$content = fopen('php://input', 'rb');
436441
if (!$content) {
@@ -442,7 +447,7 @@ public function uploadSettingsFile(string $fileId, string $access_token): JSONRe
442447

443448
// Use the fileId as a file path URL (e.g., "/settings/systemconfig/wordbook/en_US%20(1).dic")
444449
$settingsUrl = new SettingsUrl($fileId);
445-
$result = $this->settingsService->uploadFile($settingsUrl, $fileContent);
450+
$result = $this->settingsService->uploadFile($settingsUrl, $fileContent, $userId);
446451

447452
return new JSONResponse([
448453
'status' => 'success',
@@ -475,8 +480,9 @@ public function deleteSettingsFile(string $fileId, string $access_token): JSONRe
475480
$type = $settingsUrl->getType();
476481
$category = $settingsUrl->getCategory();
477482
$fileName = $settingsUrl->getFileName();
483+
$userId = $wopi->getEditorUid();
478484

479-
$this->settingsService->deleteSettingsFile($type, $category, $fileName);
485+
$this->settingsService->deleteSettingsFile($type, $category, $fileName, $userId);
480486

481487
return new JSONResponse([
482488
'status' => 'success',

lib/Db/WopiMapper.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ public function generateUserSettingsToken($fileId, $userId, $version, $serverHos
7272
$wopi = Wopi::fromParams([
7373
'fileid' => $fileId,
7474
'ownerUid' => $userId,
75+
'editorUid' => $userId,
7576
'version' => $version,
7677
'canwrite' => true,
7778
'serverHost' => $serverHost,

lib/Service/SettingsService.php

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public function __construct(
5858
* @return ISimpleFolder
5959
*/
6060

61-
public function ensureDirectory(SettingsUrl $settingsUrl): ISimpleFolder {
61+
public function ensureDirectory(SettingsUrl $settingsUrl, string $userId): ISimpleFolder {
6262
$type = $settingsUrl->getType();
6363
$category = $settingsUrl->getCategory();
6464

@@ -68,6 +68,14 @@ public function ensureDirectory(SettingsUrl $settingsUrl): ISimpleFolder {
6868
$baseFolder = $this->appData->newFolder($type);
6969
}
7070

71+
if ($type === 'userconfig') {
72+
try {
73+
$baseFolder = $baseFolder->getFolder($userId);
74+
} catch (NotFoundException $e) {
75+
$baseFolder = $baseFolder->newFolder($userId);
76+
}
77+
}
78+
7179
try {
7280
$categoryFolder = $baseFolder->getFolder($category);
7381
} catch (NotFoundException $e) {
@@ -86,11 +94,11 @@ public function ensureDirectory(SettingsUrl $settingsUrl): ISimpleFolder {
8694
* @return array ['stamp' => string, 'uri' => string]
8795
*/
8896

89-
public function uploadFile(SettingsUrl $settingsUrl, string $fileData): array {
90-
$categoryFolder = $this->ensureDirectory($settingsUrl);
97+
public function uploadFile(SettingsUrl $settingsUrl, string $fileData, string $userId): array {
98+
$categoryFolder = $this->ensureDirectory($settingsUrl, $userId);
9199
$fileName = $settingsUrl->getFileName();
92100
$newFile = $categoryFolder->newFile($fileName, $fileData);
93-
$fileUri = $this->generateFileUri($settingsUrl->getType(), $settingsUrl->getCategory(), $fileName);
101+
$fileUri = $this->generateFileUri($settingsUrl->getType(), $settingsUrl->getCategory(), $fileName, $userId);
94102

95103
return [
96104
'stamp' => $newFile->getETag(),
@@ -105,7 +113,7 @@ public function uploadFile(SettingsUrl $settingsUrl, string $fileData): array {
105113
* @param string $category
106114
* @return array Each item has 'stamp' and 'uri'.
107115
*/
108-
public function getCategoryFileList(string $type, string $category): array {
116+
public function getCategoryFileList(string $type, string $category, string $userId): array {
109117
try {
110118
$categoryFolder = $this->appData->getFolder($type . '/' . $category);
111119
} catch (NotFoundException $e) {
@@ -114,10 +122,10 @@ public function getCategoryFileList(string $type, string $category): array {
114122

115123
$files = $categoryFolder->getDirectoryListing();
116124

117-
return array_map(function (ISimpleFile $file) use ($type, $category) {
125+
return array_map(function (ISimpleFile $file) use ($type, $category, $userId) {
118126
return [
119127
'stamp' => $file->getETag(),
120-
'uri' => $this->generateFileUri($type, $category, $file->getName()),
128+
'uri' => $this->generateFileUri($type, $category, $file->getName(), $userId),
121129
];
122130
}, $files);
123131
}
@@ -155,17 +163,21 @@ public function generateIframeToken(string $type, string $userId): array {
155163
* @param string $type
156164
* @return array
157165
*/
158-
public function generateSettingsConfig(string $type): array {
166+
public function generateSettingsConfig(string $type, string $userId): array {
159167
$kind = $type === 'userconfig' ? 'user' : 'shared';
160168

161169
$config = [
162170
'kind' => $kind,
163171
];
164172

173+
if ($type === "userconfig") {
174+
$type = $type . '/' . $userId;
175+
}
176+
165177
$categories = $this->getAllCategories($type);
166178

167179
foreach ($categories as $category) {
168-
$files = $this->getCategoryFileList($type, $category);
180+
$files = $this->getCategoryFileList($type, $category, $userId);
169181
$config[$category] = $files;
170182
}
171183

@@ -220,11 +232,20 @@ private function getCategoryDirFolderList(string $type) : array {
220232
* @param string $fileName
221233
* @return string
222234
*/
223-
private function generateFileUri(string $type, string $category, string $fileName): string {
235+
private function generateFileUri(string $type, string $category, string $fileName, string $userId): string {
236+
237+
// Passing userId is dangerous so we have to trim from url...
238+
if (strpos($type, '/') !== false) {
239+
$type = explode('/', $type)[0];
240+
}
241+
242+
$token = $this->generateIframeToken($type, $userId);
243+
224244
return $this->urlGenerator->linkToRouteAbsolute(
225245
'richdocuments.settings.getSettingsFile',
226246
[
227247
'type' => $type,
248+
'token' => $token['token'],
228249
'category' => $category,
229250
'name' => $fileName,
230251
]
@@ -266,12 +287,21 @@ public function getSettingsFile(string $type, string $category, string $name): I
266287
* @param string $category
267288
* @param string $name
268289
*/
269-
public function deleteSettingsFile(string $type, string $category, string $name): void {
290+
public function deleteSettingsFile(string $type, string $category, string $name, string $userId): void {
270291
try {
271292
$baseFolder = $this->appData->getFolder($type);
272293
} catch (NotFoundException $e) {
273294
throw new NotFoundException("Type folder '{$type}' not found.");
274295
}
296+
297+
if ($type === 'userconfig') {
298+
try {
299+
$baseFolder = $baseFolder->getFolder($userId);
300+
} catch (NotFoundException $e)
301+
{
302+
throw new NotFoundException("User folder '{$userId}' not found.");
303+
}
304+
}
275305

276306
try {
277307
$categoryFolder = $baseFolder->getFolder($category);

0 commit comments

Comments
 (0)