Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@

return ['routes' => [
['name' => 'display#showPdfViewer', 'url' => '/', 'verb' => 'GET'],
['name' => 'settings#getSettings', 'url' => '/settings', 'verb' => 'GET'],
['name' => 'settings#setSettings', 'url' => '/settings', 'verb' => 'POST'],
]];
3 changes: 3 additions & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

use OCA\Files_PDFViewer\Listeners\CSPListener;
use OCA\Files_PDFViewer\Listeners\LoadViewerListener;
use OCA\Files_PDFViewer\Settings\AdminSettings;

use OCA\Viewer\Event\LoadViewer;

Expand All @@ -17,6 +18,7 @@
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
use OCP\Security\CSP\AddContentSecurityPolicyEvent;
use OCP\Settings\ISettings;

class Application extends App implements IBootstrap {
public const APP_ID = 'files_pdfviewer';
Expand All @@ -28,6 +30,7 @@ public function __construct() {
public function register(IRegistrationContext $context): void {
$context->registerEventListener(LoadViewer::class, LoadViewerListener::class);
$context->registerEventListener(AddContentSecurityPolicyEvent::class, CSPListener::class);
$context->registerSettings(ISettings::class, AdminSettings::class);
}

public function boot(IBootContext $context): void {
Expand Down
63 changes: 63 additions & 0 deletions lib/Controller/SettingsController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Files_PDFViewer\Controller;

use OCA\Files_PDFViewer\AppInfo\Application;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Attribute\AuthorizedAdminSetting;
use OCP\AppFramework\Http\JSONResponse;
use OCP\IConfig;
use OCP\IRequest;

class SettingsController extends Controller {

private IConfig $config;

public function __construct(
IRequest $request,
IConfig $config
) {
parent::__construct(Application::APP_ID, $request);
$this->config = $config;
}

/**
* Get current PDF scripting setting
*/
#[AuthorizedAdminSetting(settings: \OCA\Files_PDFViewer\Settings\AdminSettings::class)]
public function getSettings(): JSONResponse {
$enableScripting = $this->config->getAppValue(
Application::APP_ID,
'enable_scripting',
'no'
) === 'yes';

return new JSONResponse([
'enableScripting' => $enableScripting,
]);
}


/**
* Update PDF scripting setting
*/
#[AuthorizedAdminSetting(settings: \OCA\Files_PDFViewer\Settings\AdminSettings::class)]
public function setSettings(bool $enableScripting): JSONResponse {
$this->config->setAppValue(
Application::APP_ID,
'enable_scripting',
$enableScripting ? 'yes' : 'no'
);

return new JSONResponse([
'enableScripting' => $enableScripting,
]);
}
}
36 changes: 36 additions & 0 deletions lib/Settings/AdminSettings.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Files_PDFViewer\Settings;

use OCA\Files_PDFViewer\AppInfo\Application;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\IConfig;
use OCP\Settings\ISettings;

class AdminSettings implements ISettings {

private IConfig $config;

public function __construct(IConfig $config) {
$this->config = $config;
}

public function getForm(): TemplateResponse {
return new TemplateResponse(Application::APP_ID, 'admin', []);
}

public function getSection(): string {
return 'server';
}

public function getPriority(): int {
return 50;
}
}
12 changes: 12 additions & 0 deletions src/admin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import Vue from 'vue'
import AdminSettings from './components/AdminSettings.vue'

Vue.prototype.t = t
Vue.prototype.n = n

const View = Vue.extend(AdminSettings)
new View().$mount('#files_pdfviewer-admin-settings')
79 changes: 79 additions & 0 deletions src/components/AdminSettings.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<!--
- SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<NcSettingsSection
:name="t('files_pdfviewer', 'PDF Viewer')"
:description="t('files_pdfviewer', 'Configure PDF viewer settings')">
<NcCheckboxRadioSwitch
:checked="enableScripting"
:loading="loading"
@update:checked="setEnableScripting">
{{ t('files_pdfviewer', 'Enable PDF form scripting') }}
</NcCheckboxRadioSwitch>
<NcNoteCard type="warning">
{{ t('files_pdfviewer', 'Enabling PDF scripting allows JavaScript execution within PDF documents. This enables form calculations and dynamic content, but may pose security risks with untrusted PDFs. PDF scripts run in a sandboxed environment.') }}
</NcNoteCard>
</NcSettingsSection>
</template>

<script>
import axios from '@nextcloud/axios'
import { showError, showSuccess } from '@nextcloud/dialogs'
import { generateUrl } from '@nextcloud/router'
import { NcCheckboxRadioSwitch, NcNoteCard, NcSettingsSection } from '@nextcloud/vue'
import logger from '../services/logger.js'

export default {
name: 'AdminSettings',

components: {
NcCheckboxRadioSwitch,
NcNoteCard,
NcSettingsSection,
},

data() {
return {
enableScripting: false,
loading: true,
}
},

async mounted() {
await this.loadSettings()
},

methods: {
async loadSettings() {
this.loading = true
try {
const response = await axios.get(generateUrl('/apps/files_pdfviewer/settings'))
this.enableScripting = response.data.enableScripting
} catch (error) {
showError(t('files_pdfviewer', 'Failed to load settings'))
logger.error('Failed to load PDF viewer settings:', { error })
} finally {
this.loading = false
}
},

async setEnableScripting(value) {
this.loading = true
try {
await axios.post(generateUrl('/apps/files_pdfviewer/settings'), {
enableScripting: value,
})
this.enableScripting = value
showSuccess(t('files_pdfviewer', 'Settings saved'))
} catch (error) {
showError(t('files_pdfviewer', 'Failed to save settings'))
logger.error('Failed to save PDF viewer settings:', { error })
} finally {
this.loading = false
}
},
},
}
</script>
2 changes: 1 addition & 1 deletion src/views/PDFView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ export default {
PDFViewerApplicationOptions.set('sandboxBundleSrc', this.getViewerTemplateParameter('sandbox'))
PDFViewerApplicationOptions.set('enablePermissions', true)
PDFViewerApplicationOptions.set('imageResourcesPath', this.getViewerTemplateParameter('imageresourcespath'))
PDFViewerApplicationOptions.set('enableScripting', this.getViewerTemplateParameter('enableScripting') === true)
PDFViewerApplicationOptions.set('enableScripting', this.getViewerTemplateParameter('enableScripting') === '1')

const language = getLanguage()
const supportedLanguages = SUPPORTED_LANGUAGES
Expand Down
10 changes: 10 additions & 0 deletions templates/admin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

\OCP\Util::addScript('files_pdfviewer', 'files_pdfviewer-admin');
?>

<div id="files_pdfviewer-admin-settings"></div>
1 change: 1 addition & 0 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const { readdirSync } = require('fs')
const l10nContent = readdirSync(path.resolve(__dirname, 'js', 'pdfjs', 'web', 'locale'))

webpackConfig.entry.workersrc = path.resolve(path.join('src', 'workersrc.js'))
webpackConfig.entry.admin = path.resolve(path.join('src', 'admin.js'))

// keep pdfjs vendor in the js folder
webpackConfig.output.clean = false
Expand Down