Skip to content

Commit

Permalink
fix(settings): generate user config per userId & handle guest users
Browse files Browse the repository at this point in the history
Signed-off-by: codewithvk <[email protected]>
  • Loading branch information
codewithvk committed Jan 29, 2025
1 parent 9c39ff0 commit 9e7c050
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 23 deletions.
2 changes: 1 addition & 1 deletion appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
['name' => 'settings#uploadFontFile', 'url' => 'settings/fonts', 'verb' => 'POST'],
[
'name' => 'settings#getSettingsFile',
'url' => 'settings/{type}/{category}/{name}',
'url' => 'settings/{type}/{token}/{category}/{name}',
'verb' => 'GET',
'requirements' => [
'type' => '[a-zA-Z0-9_\-]+',
Expand Down
10 changes: 9 additions & 1 deletion lib/Controller/SettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
use OCP\Util;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Output\NullOutput;
use OCA\Richdocuments\Db\WopiMapper;

class SettingsController extends Controller {
// TODO adapt overview generation if we add more font mimetypes
Expand All @@ -58,6 +59,7 @@ public function __construct(
private SettingsService $settingsService,
private LoggerInterface $logger,
private IURLGenerator $urlGenerator,
private WopiMapper $wopiMapper,
private ?string $userId,
) {
parent::__construct($appName, $request);
Expand Down Expand Up @@ -484,8 +486,14 @@ public function uploadFontFile(): JSONResponse {
* @PublicPage
* @NoCSRFRequired
**/
public function getSettingsFile(string $type, string $category, string $name) {
public function getSettingsFile(string $type, string $token, string $category, string $name) {
try {
$wopi = $this->wopiMapper->getWopiForToken($token);
if ($type === 'userconfig')
{
$userId = $wopi->getEditorUid() ?: $wopi->getOwnerUid();
$type = $type . '/' . $userId;
}
$systemFile = $this->settingsService->getSettingsFile($type, $category, $name);
return new DataDisplayResponse(
$systemFile->getContent(),
Expand Down
26 changes: 16 additions & 10 deletions lib/Controller/WopiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,9 @@ public function checkFileInfo(string $fileId, string $access_token): JSONRespons

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

$userSettings = $this->generateSettings($userId, 'userconfig');
if (!$isPublic) {
$userSettings = $this->generateSettings($userId, 'userconfig');
}
$sharedSettings = $this->generateSettings($userId, 'systemconfig');

$response = [
Expand Down Expand Up @@ -174,10 +176,13 @@ public function checkFileInfo(string $fileId, string $access_token): JSONRespons
'EnableRemoteAIContent' => $isTaskProcessingEnabled,
'HasContentRange' => true,
'ServerPrivateInfo' => [],
'UserSettings' => $userSettings,
'SharedSettings' => $sharedSettings,
];

if (!$isPublic) {
$response['UserSettings'] = $userSettings;
}

$enableZotero = $this->config->getAppValue(Application::APPNAME, 'zoteroEnabled', 'yes') === 'yes';
if (!$isPublic && $enableZotero) {
$zoteroAPIKey = $this->config->getUserValue($wopi->getEditorUid(), 'richdocuments', 'zoteroAPIKey', '');
Expand Down Expand Up @@ -406,13 +411,12 @@ public function getSettings(string $type, string $access_token): JSONResponse {
if ($wopi->getTokenType() !== Wopi::TOKEN_TYPE_SETTING_AUTH) {
return new JSONResponse(['error' => 'Invalid token type'], Http::STATUS_BAD_REQUEST);
}

$isPublic = empty($wopi->getEditorUid());
$guestUserId = 'Guest-' . \OC::$server->getSecureRandom()->generate(8);
$userId = !$isPublic ? $wopi->getEditorUid() : $guestUserId;

$user = $this->userManager->get($wopi->getOwnerUid());
if (!$user || !$this->groupManager->isAdmin($user->getUID())) {
return new JSONResponse(['error' => 'Access denied'], Http::STATUS_BAD_REQUEST);
}

$userConfig = $this->settingsService->generateSettingsConfig($type);
$userConfig = $this->settingsService->generateSettingsConfig($type, $userId);
return new JSONResponse($userConfig, Http::STATUS_OK);
} catch (UnknownTokenException|ExpiredTokenException $e) {
$this->logger->debug($e->getMessage(), ['exception' => $e]);
Expand All @@ -431,6 +435,7 @@ public function uploadSettingsFile(string $fileId, string $access_token): JSONRe
try {
$wopi = $this->wopiMapper->getWopiForToken($access_token);

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

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

return new JSONResponse([
'status' => 'success',
Expand Down Expand Up @@ -475,8 +480,9 @@ public function deleteSettingsFile(string $fileId, string $access_token): JSONRe
$type = $settingsUrl->getType();
$category = $settingsUrl->getCategory();
$fileName = $settingsUrl->getFileName();
$userId = $wopi->getEditorUid();

$this->settingsService->deleteSettingsFile($type, $category, $fileName);
$this->settingsService->deleteSettingsFile($type, $category, $fileName, $userId);

return new JSONResponse([
'status' => 'success',
Expand Down
1 change: 1 addition & 0 deletions lib/Db/WopiMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public function generateUserSettingsToken($fileId, $userId, $version, $serverHos
$wopi = Wopi::fromParams([
'fileid' => $fileId,
'ownerUid' => $userId,
'editorUid' => $userId,
'version' => $version,
'canwrite' => true,
'serverHost' => $serverHost,
Expand Down
52 changes: 41 additions & 11 deletions lib/Service/SettingsService.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public function __construct(
* @return ISimpleFolder
*/

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

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

if ($type === 'userconfig') {
try {
$baseFolder = $baseFolder->getFolder($userId);
} catch (NotFoundException $e) {
$baseFolder = $baseFolder->newFolder($userId);
}
}

try {
$categoryFolder = $baseFolder->getFolder($category);
} catch (NotFoundException $e) {
Expand All @@ -86,11 +94,11 @@ public function ensureDirectory(SettingsUrl $settingsUrl): ISimpleFolder {
* @return array ['stamp' => string, 'uri' => string]
*/

public function uploadFile(SettingsUrl $settingsUrl, string $fileData): array {
$categoryFolder = $this->ensureDirectory($settingsUrl);
public function uploadFile(SettingsUrl $settingsUrl, string $fileData, string $userId): array {
$categoryFolder = $this->ensureDirectory($settingsUrl, $userId);
$fileName = $settingsUrl->getFileName();
$newFile = $categoryFolder->newFile($fileName, $fileData);
$fileUri = $this->generateFileUri($settingsUrl->getType(), $settingsUrl->getCategory(), $fileName);
$fileUri = $this->generateFileUri($settingsUrl->getType(), $settingsUrl->getCategory(), $fileName, $userId);

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

$files = $categoryFolder->getDirectoryListing();

return array_map(function (ISimpleFile $file) use ($type, $category) {
return array_map(function (ISimpleFile $file) use ($type, $category, $userId) {
return [
'stamp' => $file->getETag(),
'uri' => $this->generateFileUri($type, $category, $file->getName()),
'uri' => $this->generateFileUri($type, $category, $file->getName(), $userId),
];
}, $files);
}
Expand Down Expand Up @@ -155,17 +163,21 @@ public function generateIframeToken(string $type, string $userId): array {
* @param string $type
* @return array
*/
public function generateSettingsConfig(string $type): array {
public function generateSettingsConfig(string $type, string $userId): array {
$kind = $type === 'userconfig' ? 'user' : 'shared';

$config = [
'kind' => $kind,
];

if ($type === "userconfig") {
$type = $type . '/' . $userId;
}

$categories = $this->getAllCategories($type);

foreach ($categories as $category) {
$files = $this->getCategoryFileList($type, $category);
$files = $this->getCategoryFileList($type, $category, $userId);
$config[$category] = $files;
}

Expand Down Expand Up @@ -220,11 +232,20 @@ private function getCategoryDirFolderList(string $type) : array {
* @param string $fileName
* @return string
*/
private function generateFileUri(string $type, string $category, string $fileName): string {
private function generateFileUri(string $type, string $category, string $fileName, string $userId): string {

// Passing userId is dangerous so we have to trim from url...
if (strpos($type, '/') !== false) {
$type = explode('/', $type)[0];
}

$token = $this->generateIframeToken($type, $userId);

return $this->urlGenerator->linkToRouteAbsolute(
'richdocuments.settings.getSettingsFile',
[
'type' => $type,
'token' => $token['token'],
'category' => $category,
'name' => $fileName,
]
Expand Down Expand Up @@ -266,12 +287,21 @@ public function getSettingsFile(string $type, string $category, string $name): I
* @param string $category
* @param string $name
*/
public function deleteSettingsFile(string $type, string $category, string $name): void {
public function deleteSettingsFile(string $type, string $category, string $name, string $userId): void {
try {
$baseFolder = $this->appData->getFolder($type);
} catch (NotFoundException $e) {
throw new NotFoundException("Type folder '{$type}' not found.");
}

if ($type === 'userconfig') {
try {
$baseFolder = $baseFolder->getFolder($userId);
} catch (NotFoundException $e)
{
throw new NotFoundException("User folder '{$userId}' not found.");
}
}

try {
$categoryFolder = $baseFolder->getFolder($category);
Expand Down

0 comments on commit 9e7c050

Please sign in to comment.