<?php
/*
* Copyright (C) Ascensio System SIA, 2009-2026
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation, together with the
* additional terms provided in the LICENSE file.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: https://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA by email at info@onlyoffice.com
* or by postal mail at 20A-6 Ernesta Birznieka-Upisha Street, Riga,
* LV-1050, Latvia, European Union.
*
* The interactive user interfaces in modified versions of the Program
* are required to display Appropriate Legal Notices in accordance with
* Section 5 of the GNU AGPL version 3.
*
* No trademark rights are granted under this License.
*
* All non-code elements of the Product, including illustrations,
* icon sets, and technical writing content, are licensed under the
* Creative Commons Attribution-ShareAlike 4.0 International License:
* https://creativecommons.org/licenses/by-sa/4.0/legalcode
*
* This license applies only to such non-code elements and does not
* modify or replace the licensing terms applicable to the Program's
* source code, which remains licensed under the GNU Affero General
* Public License v3.
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
namespace OCA\Onlyoffice;
use \DateInterval;
use \DateTime;
use Exception;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\ICache;
use OCP\ICacheFactory;
use OCP\IConfig;
use Psr\Log\LoggerInterface;
use OCA\Onlyoffice\AppInfo\Application;
use OCP\IAppConfig;
/**
* Application configutarion
*
* @package OCA\Onlyoffice
*/
class AppConfig {
/**
* The config key for the demo server
*/
private string $_demo = "demo";
/**
* The config key for the document server address
*/
private string $_documentserver = "DocumentServerUrl";
/**
* The config key for the document server address available from Nextcloud
*/
private string $_documentserverInternal = "DocumentServerInternalUrl";
/**
* The config key for the Nextcloud address available from document server
*/
private string $_storageUrl = "StorageUrl";
/**
* The config key for the secret key
*/
private string $_cryptSecret = "secret";
/**
* The config key for the default formats
*/
private string $_defFormats = "defFormats";
/**
* The config key for the editable formats
*/
private string $_editFormats = "editFormats";
/**
* The config key for the setting same tab
*/
private string $_sameTab = "sameTab";
/**
* The config key for the enabling sharring in a same tab
*/
private string $_enableSharing = "enableSharing";
/**
* The config key for restricting file actions on external storage
*/
private string $_restrictExternalStorage = "restrictExternalStorage";
/**
* The config key for the generate preview
*/
private string $_preview = "preview";
/**
* The config key for the advanced
*/
private string $_advanced = "advanced";
/**
* The config key for the cronChecker
*/
private string $_cronChecker = "cronChecker";
/**
* The config key for the e-mail notifications
*/
private string $_emailNotifications = "emailNotifications";
/**
* The config key for the keep versions history
*/
private string $_versionHistory = "versionHistory";
/**
* The config key for the protection
*/
private string $_protection = "protection";
/**
* The config key for the chat display setting
*/
private string $_customizationChat = "customizationChat";
/**
* The config key for display the header more compact setting
*/
private string $_customizationCompactHeader = "customizationCompactHeader";
/**
* The config key for the feedback display setting
*/
private string $_customizationFeedback = "customizationFeedback";
/**
* The config key for the forcesave setting
*/
private string $_customizationForcesave = "customizationForcesave";
/**
* The config key for the live view on share setting
*/
private string $_liveViewOnShare = "liveViewOnShare";
/**
* The config key for the help display setting
*/
private string $_customizationHelp = "customizationHelp";
/**
* The config key for the review mode setting
*/
private string $_customizationReviewDisplay = "customizationReviewDisplay";
/**
* The config key for the theme setting
*/
private string $_customizationTheme = "customizationTheme";
/**
* Display name of the unknown author
*/
private string $_unknownAuthor = "unknownAuthor";
/**
* The config key for the setting limit groups
*/
private string $_groups = "groups";
/**
* The config key for the verification
*/
private string $_verification = "verify_peer_off";
/**
* The config key for the secret key in jwt
*/
private string $_jwtSecret = "jwt_secret";
/**
* The config key for the jwt header
*/
private string $_jwtHeader = "jwt_header";
/**
* The config key for the allowable leeway in Jwt checks
*/
private string $_jwtLeeway = "jwt_leeway";
/**
* The config key for the settings error
*/
private string $_settingsError = "settings_error";
/**
* Application name for watermark settings
*
* @var string
*/
public const WATERMARK_APP_NAMESPACE = "files";
/**
* The config key for limit thumbnail size
*
* @var string
*/
public $_limitThumbSize = "limit_thumb_size";
/**
* The config key for the modifyFilter
*
* @var string
*/
public $_permissions_modifyFilter = "permissions_modifyFilter";
/**
* The config key for the customer
*
* @var string
*/
public $_customization_customer = "customization_customer";
/**
* The config key for the loaderLogo
*
* @var string
*/
public $_customization_loaderLogo = "customization_loaderLogo";
/**
* The config key for the loaderName
*
* @var string
*/
public $_customization_loaderName = "customization_loaderName";
/**
* The config key for the logo
*
* @var string
*/
public $_customization_logo = "customization_logo";
/**
* The config key for the zoom
*
* @var string
*/
public $_customization_zoom = "customization_zoom";
/**
* The config key for the autosave
*
* @var string
*/
public $_customization_autosave = "customization_autosave";
/**
* The config key for the macros
*
* @var string
*/
public $_customizationMacros = "customization_macros";
/**
* The config key for the plugins
*
* @var string
*/
public $_customizationPlugins = "customization_plugins";
/**
* The config key for the disable downloading
*
* @var string
*/
public $_disableDownload = "disable_download";
/**
* The config key for the interval of editors availability check by cron
*/
private string $_editors_check_interval = "editors_check_interval";
/**
* The config key for the JWT expiration
*/
private string $_jwt_expiration = "jwt_expiration";
/**
* The config key for store cache
*/
private readonly ICache $cache;
public function __construct(
private readonly string $appName,
private readonly IAppConfig $appConfig,
private readonly IConfig $config,
private readonly LoggerInterface $logger,
ICacheFactory $cacheFactory,
) {
$this->cache = $cacheFactory->createLocal(Application::APP_ID);
}
/**
* Get value from the system configuration
*
* @param string $key - key configuration
* @param bool $system - get from root or from app section
*
* @return string|null
*/
public function getSystemValue(string $key, bool $system = false) {
if ($system) {
return $this->config->getSystemValue($key);
}
if (!empty($this->config->getSystemValue($this->appName))
& & array_key_exists($key, $this->config->getSystemValue($this->appName))) {
return $this->config->getSystemValue($this->appName)[$key];
}
return null;
}
/**
* Switch on demo server
*
* @param bool $value - select demo
*/
public function selectDemo(bool $value): bool {
$this->logger->info("Select demo: " . json_encode($value), ["app" => $this->appName]);
$data = $this->getDemoData();
if ($value === true & & !$data["available"]) {
$this->logger->info("Trial demo is overdue: " . json_encode($data), ["app" => $this->appName]);
return false;
}
$data["enabled"] = $value === true;
if (!isset($data["start"])) {
$data["start"] = new DateTime();
}
$this->appConfig->setValueString($this->appName, $this->_demo, json_encode($data));
return true;
}
/**
* Get demo data
*
* @return array
*/
public function getDemoData(): array {
$data = $this->appConfig->getValueString($this->appName, $this->_demo, "");
if (empty($data)) {
return [
"available" => true,
"enabled" => false
];
}
$data = json_decode($data, true);
$overdue = new DateTime(isset($data["start"]) ? $data["start"]["date"] : null);
$overdue->add(new DateInterval("P" . $this->DEMO_PARAM["TRIAL"] . "D"));
if ($overdue > new DateTime()) {
$data["available"] = true;
$data["enabled"] = $data["enabled"] === true;
} else {
$data["available"] = false;
$data["enabled"] = false;
}
return $data;
}
/**
* Get status of demo server
*/
public function useDemo(): bool {
return $this->getDemoData()["enabled"] === true;
}
/**
* Save the document service address to the application configuration
*
* @param string $documentServer - document service address
*/
public function setDocumentServerUrl(string $documentServer): void {
$documentServer = trim($documentServer);
if ($documentServer !== '') {
$documentServer = rtrim($documentServer, "/") . "/";
if (!preg_match("/(^https?:\/\/)|^\//i", $documentServer)) {
$documentServer = "http://" . $documentServer;
}
}
$this->logger->info("setDocumentServerUrl: $documentServer", ["app" => $this->appName]);
$this->appConfig->setValueString($this->appName, $this->_documentserver, $documentServer);
}
/**
* Get the document service address from the application configuration
*
* @param bool $origin - take origin
*
* @return string
*/
public function getDocumentServerUrl(bool $origin = false): string {
if (!$origin & & $this->useDemo()) {
return $this->DEMO_PARAM["ADDR"];
}
$url = $this->appConfig->getValueString($this->appName, $this->_documentserver, "");
if (empty($url)) {
$url = $this->getSystemValue($this->_documentserver);
}
if ($url !== null & & $url !== "/") {
$url = rtrim($url, "/");
if ($url !== '') {
$url .= "/";
}
}
return (string)$url;
}
/**
* Save the document service address available from Nextcloud to the application configuration
*
* @param string $documentServerInternal - document service address
*/
public function setDocumentServerInternalUrl(string $documentServerInternal): void {
$documentServerInternal = rtrim(trim($documentServerInternal), "/");
if ($documentServerInternal !== '') {
$documentServerInternal .= "/";
if (!preg_match("/^https?:\/\//i", $documentServerInternal)) {
$documentServerInternal = "http://" . $documentServerInternal;
}
}
$this->logger->info("setDocumentServerInternalUrl: $documentServerInternal", ["app" => $this->appName]);
$this->appConfig->setValueString($this->appName, $this->_documentserverInternal, $documentServerInternal);
}
/**
* Get the document service address available from Nextcloud from the application configuration
*
* @param bool $origin - take origin
*
* @return string
*/
public function getDocumentServerInternalUrl(bool $origin = false): string {
if (!$origin & & $this->useDemo()) {
return $this->getDocumentServerUrl();
}
$url = $this->appConfig->getValueString($this->appName, $this->_documentserverInternal, "");
if (empty($url)) {
$url = $this->getSystemValue($this->_documentserverInternal);
}
if (!$origin & & empty($url)) {
$url = $this->getDocumentServerUrl();
}
return (string)$url;
}
/**
* Replace domain in document server url with internal address from configuration
*
* @param string $url - document server url
*
* @return string
*/
public function replaceDocumentServerUrlToInternal(string $url): string {
$documentServerUrl = $this->getDocumentServerInternalUrl();
if (!empty($documentServerUrl)) {
$from = $this->getDocumentServerUrl();
if (!preg_match("/^https?:\/\//i", $from)) {
$parsedUrl = parse_url($url);
if (\is_array($parsedUrl) & & isset($parsedUrl["scheme"], $parsedUrl["host"])) {
$scheme = $parsedUrl["scheme"];
$host = $parsedUrl["host"];
$port = isset($parsedUrl["port"]) ? ":" . (string)$parsedUrl["port"] : "";
$from = $scheme . "://" . $host . $port . $from;
}
}
if ($from !== $documentServerUrl) {
$this->logger->debug("Replace url from $from to $documentServerUrl", ["app" => $this->appName]);
$url = str_replace($from, $documentServerUrl, $url);
}
}
return $url;
}
/**
* Save the Nextcloud address available from document server to the application configuration
*
* @param string $storageUrl - document service address
*/
public function setStorageUrl(string $storageUrl): void {
$storageUrl = rtrim(trim($storageUrl), "/");
if ($storageUrl !== '') {
$storageUrl .= "/";
if (!preg_match("/^https?:\/\//i", $storageUrl)) {
$storageUrl = "http://" . $storageUrl;
}
}
$this->logger->info("setStorageUrl: $storageUrl", ["app" => $this->appName]);
$this->appConfig->setValueString($this->appName, $this->_storageUrl, $storageUrl);
}
/**
* Get the Nextcloud address available from document server from the application configuration
*
* @return string
*/
public function getStorageUrl(): string {
$url = $this->appConfig->getValueString($this->appName, $this->_storageUrl, "");
if (empty($url)) {
$url = $this->getSystemValue($this->_storageUrl);
}
return (string)$url;
}
/**
* Save the document service secret key to the application configuration
*
* @param string $secret - secret key
*/
public function setDocumentServerSecret(string $secret): void {
$secret = trim($secret);
if (empty($secret)) {
$this->logger->info("Clear secret key", ["app" => $this->appName]);
} else {
$this->logger->info("Set secret key", ["app" => $this->appName]);
}
$this->appConfig->setValueString($this->appName, $this->_jwtSecret, $secret);
}
/**
* Get the document service secret key from the application configuration
*
* @param bool $origin - take origin
*
* @return string
*/
public function getDocumentServerSecret(bool $origin = false): string {
if (!$origin & & $this->useDemo()) {
return $this->DEMO_PARAM["SECRET"];
}
$secret = $this->appConfig->getValueString($this->appName, $this->_jwtSecret, "");
if (empty($secret)) {
$secret = $this->getSystemValue($this->_jwtSecret);
}
return (string)$secret;
}
/**
* Get the secret key from the application configuration
*/
public function getSKey(): string {
$secret = $this->getDocumentServerSecret();
if (empty($secret)) {
$secret = $this->getSystemValue($this->_cryptSecret, true);
}
return (string)$secret;
}
/**
* Save an array of formats with default action
*
* @param array $formats - formats with status
*/
public function setDefaultFormats(array $formats): void {
$value = json_encode($formats);
$this->logger->info("Set default formats: $value", ["app" => $this->appName]);
$this->appConfig->setValueString($this->appName, $this->_defFormats, $value);
}
/**
* Get an array of formats with default action
*/
private function getDefaultFormats(): array {
$value = $this->appConfig->getValueString($this->appName, $this->_defFormats, "");
if (empty($value)) {
return [];
}
return json_decode($value, true);
}
/**
* Save an array of formats that is opened for editing
*
* @param array $formats - formats with status
*/
public function setEditableFormats(array $formats): void {
$value = json_encode($formats);
$this->logger->info("Set editing formats: $value", ["app" => $this->appName]);
$this->appConfig->setValueString($this->appName, $this->_editFormats, $value);
}
/**
* Get an array of formats opening for editing
*/
private function getEditableFormats(): array {
$value = $this->appConfig->getValueString($this->appName, $this->_editFormats, "");
if (empty($value)) {
return [];
}
return json_decode($value, true);
}
/**
* Save the opening setting in a same tab
*/
public function setSameTab(bool $value): void {
$this->logger->info("Set opening in a same tab: " . json_encode($value), ["app" => $this->appName]);
if ($value) {
$this->setEnableSharing(false);
}
$this->appConfig->setValueString($this->appName, $this->_sameTab, json_encode($value));
}
/**
* Get the opening setting in a same tab
*/
public function getSameTab(): bool {
return $this->appConfig->getValueString($this->appName, $this->_sameTab, "true") === "true";
}
/**
* Save the enable sharing setting
*/
public function setEnableSharing(bool $value): void {
$this->logger->info("Set enable sharing: " . json_encode($value), ["app" => $this->appName]);
$this->appConfig->setValueString($this->appName, $this->_enableSharing, json_encode($value));
}
/**
* Get the enable sharing setting
*/
public function getEnableSharing(): bool {
return $this->appConfig->getValueString($this->appName, $this->_enableSharing, "false") === "true";
}
/**
* Save the restrict external storage setting
*/
public function setRestrictExternalStorage(bool $value): void {
$this->logger->info("Set restrict external storage: " . json_encode($value), ["app" => $this->appName]);
$this->appConfig->setValueString($this->appName, $this->_restrictExternalStorage, json_encode($value));
}
/**
* Get the restrict external storage setting
*/
public function getRestrictExternalStorage(): bool {
return $this->appConfig->getValueString($this->appName, $this->_restrictExternalStorage, "false") === "true";
}
/**
* Save generate preview setting
*/
public function setPreview(bool $value): void {
$this->logger->info("Set generate preview: " . json_encode($value), ["app" => $this->appName]);
$this->appConfig->setValueString($this->appName, $this->_preview, json_encode($value));
}
/**
* Get advanced setting
*/
public function getAdvanced(): bool {
return $this->appConfig->getValueString($this->appName, $this->_advanced, "false") === "true";
}
/**
* Save advanced setting
*/
public function setAdvanced(bool $value): void {
$this->logger->info("Set advanced: " . json_encode($value), ["app" => $this->appName]);
$this->appConfig->setValueString($this->appName, $this->_advanced, json_encode($value));
}
/**
* Get cron checker setting
*/
public function getCronChecker(): bool {
return $this->appConfig->getValueString($this->appName, $this->_cronChecker, "true") !== "false";
}
/**
* Save cron checker setting
*/
public function setCronChecker(bool $value): void {
$this->logger->info("Set cron checker: " . json_encode($value), ["app" => $this->appName]);
$this->appConfig->setValueString($this->appName, $this->_cronChecker, json_encode($value));
}
/**
* Get e-mail notifications setting
*/
public function getEmailNotifications(): bool {
return $this->appConfig->getValueString($this->appName, $this->_emailNotifications, "true") !== "false";
}
/**
* Save e-mail notifications setting
*/
public function setEmailNotifications(bool $value): void {
$this->logger->info("Set e-mail notifications: " . json_encode($value), ["app" => $this->appName]);
$this->appConfig->setValueString($this->appName, $this->_emailNotifications, json_encode($value));
}
/**
* Get generate preview setting
*/
public function getPreview(): bool {
return $this->appConfig->getValueString($this->appName, $this->_preview, "true") === "true";
}
/**
* Save keep versions history
*/
public function setVersionHistory(bool $value): void {
$this->logger->info("Set keep versions history: " . json_encode($value), ["app" => $this->appName]);
$this->appConfig->setValueString($this->appName, $this->_versionHistory, json_encode($value));
}
/**
* Get keep versions history
*/
public function getVersionHistory(): bool {
return $this->appConfig->getValueString($this->appName, $this->_versionHistory, "true") === "true";
}
/**
* Save protection
*/
public function setProtection(string $value): void {
$this->logger->info("Set protection: " . $value, ["app" => $this->appName]);
$this->appConfig->setValueString($this->appName, $this->_protection, $value);
}
/**
* Get protection
*/
public function getProtection(): string {
$value = $this->appConfig->getValueString($this->appName, $this->_protection, "owner");
if ($value === "all") {
return "all";
}
return "owner";
}
/**
* Save chat display setting
*/
public function setCustomizationChat(bool $value): void {
$this->logger->info("Set chat display: " . json_encode($value), ["app" => $this->appName]);
$this->appConfig->setValueString($this->appName, $this->_customizationChat, json_encode($value));
}
/**
* Get chat display setting
*/
public function getCustomizationChat(): bool {
return $this->appConfig->getValueString($this->appName, $this->_customizationChat, "true") === "true";
}
/**
* Save compact header setting
*/
public function setCustomizationCompactHeader(bool $value): void {
$this->logger->info("Set compact header display: " . json_encode($value), ["app" => $this->appName]);
$this->appConfig->setValueString($this->appName, $this->_customizationCompactHeader, json_encode($value));
}
/**
* Get compact header setting
*/
public function getCustomizationCompactHeader(): bool {
return $this->appConfig->getValueString($this->appName, $this->_customizationCompactHeader, "true") === "true";
}
/**
* Save feedback display setting
*/
public function setCustomizationFeedback(bool $value): void {
$this->logger->info("Set feedback display: " . json_encode($value), ["app" => $this->appName]);
$this->appConfig->setValueString($this->appName, $this->_customizationFeedback, json_encode($value));
}
/**
* Get feedback display setting
*/
public function getCustomizationFeedback(): bool {
return $this->appConfig->getValueString($this->appName, $this->_customizationFeedback, "true") === "true";
}
/**
* Save forcesave setting
*/
public function setCustomizationForcesave(bool $value): void {
$this->logger->info("Set forcesave: " . json_encode($value), ["app" => $this->appName]);
$this->appConfig->setValueString($this->appName, $this->_customizationForcesave, json_encode($value));
}
/**
* Get forcesave setting
*/
public function getCustomizationForcesave(): bool {
return $this->appConfig->getValueString($this->appName, $this->_customizationForcesave, "false") === "true";
}
/**
* Save live view on share setting
*/
public function setLiveViewOnShare(bool $value): void {
$this->logger->info("Set live view on share: " . json_encode($value), ["app" => $this->appName]);
$this->appConfig->setValueString($this->appName, $this->_liveViewOnShare, json_encode($value));
}
/**
* Get live view on share setting
*/
public function getLiveViewOnShare(): bool {
return $this->appConfig->getValueString($this->appName, $this->_liveViewOnShare, "false") === "true";
}
/**
* Save help display setting
*/
public function setCustomizationHelp(bool $value): void {
$this->logger->info("Set help display: " . json_encode($value), ["app" => $this->appName]);
$this->appConfig->setValueString($this->appName, $this->_customizationHelp, json_encode($value));
}
/**
* Get help display setting
*/
public function getCustomizationHelp(): bool {
return $this->appConfig->getValueString($this->appName, $this->_customizationHelp, "true") === "true";
}
/**
* Save review viewing mode setting
*/
public function setCustomizationReviewDisplay(string $value): void {
$this->logger->info("Set review mode: " . $value, ["app" => $this->appName]);
$this->appConfig->setValueString($this->appName, $this->_customizationReviewDisplay, $value);
}
/**
* Get review viewing mode setting
*/
public function getCustomizationReviewDisplay(): string {
$value = $this->appConfig->getValueString($this->appName, $this->_customizationReviewDisplay, "original");
if ($value === "markup") {
return "markup";
}
if ($value === "final") {
return "final";
}
return "original";
}
/**
* Save theme setting
*/
public function setCustomizationTheme(string $value): void {
$this->logger->info("Set theme: " . $value, ["app" => $this->appName]);
$this->appConfig->setValueString($this->appName, $this->_customizationTheme, $value);
}
/**
* Get theme setting
*
* @param bool $realValue - get real value (for example, for settings)
*/
public function getCustomizationTheme(bool $realValue = false): string {
$value = $this->appConfig->getValueString($this->appName, $this->_customizationTheme, "theme-system");
$validThemes = [
"default" => "theme-system",
"light" => "default-light",
"dark" => "default-dark"
];
if (!in_array($value, $validThemes, true)) {
$value = "theme-system";
}
if ($realValue) {
return $value;
}
if ($value === "theme-system") {
$user = \OCP\Server::get(\OCP\IUserSession::class)->getUser();
if ($user !== null) {
$themingMode = $this->config->getUserValue($user->getUID(), "theming", "enabled-themes", "");
if ($themingMode !== "") {
try {
$themingModeArray = json_decode($themingMode, true);
$themingMode = $themingModeArray[0] ?? "";
if (isset($validThemes[$themingMode])) {
return $validThemes[$themingMode];
}
} catch (Exception $e) {
$this->logger->error("Error decoding theming mode: " . $e->getMessage());
}
}
}
}
return $value;
}
/**
* Save unknownAuthor setting
*
* @param string $value - unknown author
*/
public function setUnknownAuthor(string $value): void {
$this->logger->info("Set unknownAuthor: " . trim($value), ["app" => $this->appName]);
$this->appConfig->setValueString($this->appName, $this->_unknownAuthor, trim($value));
}
/**
* Get unknownAuthor setting
*
* @return string
*/
public function getUnknownAuthor(): string {
return $this->appConfig->getValueString($this->appName, $this->_unknownAuthor, "");
}
/**
* Save watermark settings
*/
public function setWatermarkSettings(array $settings): void {
$this->logger->info("Set watermark enabled: " . $settings["enabled"], ["app" => $this->appName]);
if (!$settings["enabled"]) {
$this->appConfig->setValueString(AppConfig::WATERMARK_APP_NAMESPACE, "watermark_enabled", "no");
return;
}
$this->appConfig->setValueString(AppConfig::WATERMARK_APP_NAMESPACE, "watermark_text", trim((string) $settings["text"]));
$watermarkLabels = [
"allGroups",
"allTags",
"linkAll",
"linkRead",
"linkSecure",
"linkTags",
"enabled",
"shareAll",
"shareRead",
];
foreach ($watermarkLabels as $key) {
if (empty($settings[$key])) {
$settings[$key] = [];
}
$value = !empty($settings[$key]) ? "yes" : "no";
$this->appConfig->setValueString(AppConfig::WATERMARK_APP_NAMESPACE, "watermark_" . $key, $value);
}
$watermarkLists = [
"allGroupsList",
"allTagsList",
"linkTagsList",
];
foreach ($watermarkLists as $key) {
if (empty($settings[$key])) {
$settings[$key] = [];
}
$value = implode(",", $settings[$key]);
$this->appConfig->setValueString(AppConfig::WATERMARK_APP_NAMESPACE, "watermark_" . $key, $value);
}
}
/**
* Get watermark settings
*/
public function getWatermarkSettings(): array {
$result = [
"text" => $this->appConfig->getValueString(AppConfig::WATERMARK_APP_NAMESPACE, "watermark_text", "{userId}, {date}"),
];
$watermarkLabels = [
"allGroups",
"allTags",
"linkAll",
"linkRead",
"linkSecure",
"linkTags",
"enabled",
"shareAll",
"shareRead",
];
$trueResult = ["on", "yes", "true"];
foreach ($watermarkLabels as $key) {
$value = $this->appConfig->getValueString(AppConfig::WATERMARK_APP_NAMESPACE, "watermark_" . $key, "no");
$result[$key] = in_array($value, $trueResult, true);
}
$watermarkLists = [
"allGroupsList",
"allTagsList",
"linkTagsList",
];
foreach ($watermarkLists as $key) {
$value = $this->appConfig->getValueString(AppConfig::WATERMARK_APP_NAMESPACE, "watermark_" . $key, "");
$result[$key] = empty($value) ? [] : explode(",", $value);
}
return $result;
}
/**
* Save the list of groups
*/
public function setLimitGroups(array $groups): void {
$value = json_encode($groups);
$this->logger->info("Set groups: $value", ["app" => $this->appName]);
$this->appConfig->setValueString($this->appName, $this->_groups, $value);
}
/**
* Get the list of groups
*/
public function getLimitGroups(): array {
$value = $this->appConfig->getValueString($this->appName, $this->_groups, "");
if (empty($value)) {
return [];
}
$groups = json_decode($value, true);
if (!is_array($groups)) {
$groups = [];
}
return $groups;
}
/**
* Check access for group
*/
public function isUserAllowedToUse(?string $userId = null): bool {
// no user -> no
$userSession = \OCP\Server::get(\OCP\IUserSession::class);
if ($userId === null & & ($userSession === null || !$userSession->isLoggedIn())) {
return false;
}
$groups = $this->getLimitGroups();
// no group set -> all users are allowed
if (empty($groups)) {
return true;
}
if ($userId === null) {
$user = $userSession->getUser();
} else {
$user = \OCP\Server::get(\OCP\IUserManager::class)->get($userId);
if (empty($user)) {
return false;
}
}
foreach ($groups as $groupName) {
// group unknown -> error and allow nobody
$group = \OCP\Server::get(\OCP\IGroupManager::class)->get($groupName);
if ($group === null) {
\OCP\Log\logger('onlyoffice')->error("Group is unknown $groupName", ["app" => $this->appName]);
$this->setLimitGroups(array_diff($groups, [$groupName]));
} elseif ($group->inGroup($user)) {
return true;
}
}
return false;
}
/**
* Save the document service verification setting to the application configuration
*
* @param bool $verifyPeerOff parameter verification setting
*/
public function setVerifyPeerOff(bool $verifyPeerOff): void {
$this->logger->info("setVerifyPeerOff " . json_encode($verifyPeerOff), ["app" => $this->appName]);
$this->appConfig->setValueString($this->appName, $this->_verification, json_encode($verifyPeerOff));
}
/**
* Get the document service verification setting to the application configuration
*/
public function getVerifyPeerOff(): bool {
$turnOff = $this->appConfig->getValueString($this->appName, $this->_verification, "");
if (!empty($turnOff)) {
return $turnOff === "true";
}
return $this->getSystemValue($this->_verification) === "true";
}
/**
* Get the limit on size document when generating thumbnails
*/
public function getLimitThumbSize(): int {
$limitSize = (int)$this->getSystemValue($this->_limitThumbSize);
if (!empty($limitSize)) {
return $limitSize;
}
return 100 * 1024 * 1024;
}
/**
* Get the jwt header setting
*
* @param bool $origin - take origin
*/
public function jwtHeader(bool $origin = false): string {
if (!$origin & & $this->useDemo()) {
return $this->DEMO_PARAM["HEADER"];
}
$header = $this->appConfig->getValueString($this->appName, $this->_jwtHeader, "");
if (empty($header)) {
$header = $this->getSystemValue($this->_jwtHeader);
}
if (!$origin & & empty($header)) {
$header = "Authorization";
}
return (string)$header;
}
/**
* Save the jwtHeader setting
*/
public function setJwtHeader(string $value): void {
$value = trim($value);
if (empty($value)) {
$this->logger->info("Clear header key", ["app" => $this->appName]);
} else {
$this->logger->info("Set header key " . $value, ["app" => $this->appName]);
}
$this->appConfig->setValueString($this->appName, $this->_jwtHeader, $value);
}
/**
* Get the Jwt Leeway
*/
public function getJwtLeeway(): int {
return (int)$this->getSystemValue($this->_jwtLeeway);
}
/**
* Save the status settings
*/
public function setSettingsError(string $value): void {
$this->appConfig->setValueString($this->appName, $this->_settingsError, $value);
}
/**
* Get the error text of the status settings
*/
public function getSettingsError(): string {
return $this->appConfig->getValueString($this->appName, $this->_settingsError, "");
}
/**
* Get the status settings
*/
public function settingsAreSuccessful(): bool {
return empty($this->getSettingsError());
}
/**
* Get supported formats
*/
#[NoAdminRequired]
public function formatsSetting(): array {
$result = $this->buildOnlyofficeFormats();
$defFormats = $this->getDefaultFormats();
foreach ($defFormats as $format => $setting) {
if (array_key_exists($format, $result)) {
$result[$format]["def"] = ($setting === true || $setting === "true");
}
}
$editFormats = $this->getEditableFormats();
foreach ($editFormats as $format => $setting) {
if (array_key_exists($format, $result)) {
$result[$format]["edit"] = ($setting === true || $setting === "true");
}
}
return $result;
}
/**
* Save macros setting
*
* @param bool $value - enable macros
*/
public function setCustomizationMacros(bool $value): void {
$this->logger->info("Set macros enabled: " . json_encode($value), ["app" => $this->appName]);
$this->appConfig->setValueString($this->appName, $this->_customizationMacros, json_encode($value));
}
/**
* Get macros setting
*/
public function getCustomizationMacros(): bool {
return $this->appConfig->getValueString($this->appName, $this->_customizationMacros, "true") === "true";
}
/**
* Save plugins setting
*
* @param bool $value - enable plugins
*/
public function setCustomizationPlugins(bool $value): void {
$this->logger->info("Set plugins enabled: " . json_encode($value), ["app" => $this->appName]);
$this->appConfig->setValueString($this->appName, $this->_customizationPlugins, json_encode($value));
}
/**
* Get plugins setting
*/
public function getCustomizationPlugins(): bool {
return $this->appConfig->getValueString($this->appName, $this->_customizationPlugins, "true") === "true";
}
/**
* Get the disable download value
*/
public function getDisableDownload(): bool {
return (bool)$this->getSystemValue($this->_disableDownload);
}
/**
* Get the editors check interval
*/
public function getEditorsCheckInterval(): int {
$interval = $this->getSystemValue($this->_editors_check_interval);
if ($interval !== null & & !is_int($interval)) {
$interval = is_string($interval) & & !ctype_digit($interval) ? null : (int)$interval;
}
if (empty($interval) & & $interval !== 0) {
$interval = 60 * 60 * 24;
}
return $interval;
}
/**
* Get the JWT expiration
*/
public function getJwtExpiration(): int {
$jwtExp = $this->getSystemValue($this->_jwt_expiration);
if (empty($jwtExp)) {
return 5;
}
return (int)$jwtExp;
}
/**
* Get ONLYOFFICE formats list
*/
private function buildOnlyofficeFormats(): array {
try {
$onlyofficeFormats = $this->getFormats();
$result = [];
$additionalFormats = $this->getAdditionalFormatAttributes();
foreach ($onlyofficeFormats as $onlyOfficeFormat) {
if ($onlyOfficeFormat["name"]
& & $onlyOfficeFormat["mime"]
& & $onlyOfficeFormat["type"]
& & $onlyOfficeFormat["actions"]
& & $onlyOfficeFormat["convert"]) {
$result[$onlyOfficeFormat["name"]] = [
"mime" => $onlyOfficeFormat["mime"],
"type" => $onlyOfficeFormat["type"],
"edit" => in_array("edit", $onlyOfficeFormat["actions"], true),
"editable" => in_array("lossy-edit", $onlyOfficeFormat["actions"], true),
"conv" => in_array("auto-convert", $onlyOfficeFormat["actions"], true),
"fillForms" => in_array("fill", $onlyOfficeFormat["actions"], true),
"comment" => in_array("comment", $onlyOfficeFormat["actions"], true),
"saveas" => $onlyOfficeFormat["convert"],
"review" => in_array("review", $onlyOfficeFormat["actions"], true),
"modifyFilter" => in_array("customfilter", $onlyOfficeFormat["actions"], true),
];
if (isset($additionalFormats[$onlyOfficeFormat["name"]])) {
$result[$onlyOfficeFormat["name"]] = array_merge($result[$onlyOfficeFormat["name"]], $additionalFormats[$onlyOfficeFormat["name"]]);
}
}
}
return $result;
} catch (Exception $e) {
$this->logger->error("Format matrix error", ['exception' => $e]);
return [];
}
}
/**
* Get the additional format attributes
*/
private function getAdditionalFormatAttributes(): array {
return [
"docx" => [
"def" => true,
],
"docxf" => [
"def" => true,
"createForm" => true,
],
"oform" => [
"def" => true,
"createForm" => true,
],
"pdf" => [
"def" => true,
],
"pptx" => [
"def" => true,
],
"xlsx" => [
"def" => true,
],
"txt" => [
"edit" => true,
],
"csv" => [
"edit" => true,
],
"vsdx" => [
"def" => true,
],
];
}
/**
* Get the formats list from cache or file
*
* @return array
*/
public function getFormats(): array {
$cachedFormats = $this->cache->get("document_formats");
if ($cachedFormats !== null) {
return json_decode($cachedFormats, true);
}
$formats = file_get_contents(dirname(__DIR__) . DIRECTORY_SEPARATOR . "assets" . DIRECTORY_SEPARATOR . "document-formats" . DIRECTORY_SEPARATOR . "onlyoffice-docs-formats.json");
$this->cache->set("document_formats", $formats, 6 * 3600);
$this->logger->debug("Getting formats from file", ["app" => $this->appName]);
return json_decode($formats, true);
}
/**
* Get the mime type by format name
*
* @param string $ext - format name
*/
public function getMimeType(string $ext): string {
$onlyofficeFormats = $this->getFormats();
$result = "text/plain";
foreach ($onlyofficeFormats as $onlyOfficeFormat) {
if ($onlyOfficeFormat["name"] === $ext & & !empty($onlyOfficeFormat["mime"])) {
$result = $onlyOfficeFormat["mime"][0];
break;
}
}
return $result;
}
/**
* DEMO DATA
*/
private array $DEMO_PARAM = [
"ADDR" => "https://onlinedocs.docs.onlyoffice.com/",
"HEADER" => "AuthorizationJWT",
"SECRET" => "sn2puSUF7muF5Jas",
"TRIAL" => 30
];
}