From 7925dd0581f4f48b38f46a83649289c10698d012 Mon Sep 17 00:00:00 2001 From: PT-ATA No One Date: Fri, 24 May 2024 14:57:44 +0200 Subject: [PATCH 1/5] fix broken verdict --- appinfo/info.xml | 2 +- lib/AppInfo/Application.php | 5 ++- lib/AvirWrapper.php | 81 ++++++++++++++++++++-------------- lib/Service/VerdictService.php | 31 ++++++++----- 4 files changed, 72 insertions(+), 47 deletions(-) diff --git a/appinfo/info.xml b/appinfo/info.xml index 26168b84..b26336ce 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -7,7 +7,7 @@ gdatavaas G DATA Antivirus This app aims to provide an additional layer of security to your Nextcloud instance by enabling automatic and manual scanning of files for malicious content. - 0.0.0 + 0.0.1 agpl Lennart Dohmann GDataVaas diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index b1112c3a..5c1db204 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -6,6 +6,7 @@ use OC\Files\Filesystem; use OCA\GDataVaas\AvirWrapper; +use OCA\GDataVaas\Service\VerdictService; use OCP\Activity\IManager; use OCP\App\IAppManager; use OCP\Collaboration\Resources\LoadAdditionalScriptsEvent; @@ -71,7 +72,7 @@ function (string $mountPoint, IStorage $storage) { */ $container = $this->getContainer(); - // $scannerFactory = $container->query(ScannerFactory::class); + $verdictService = $container->get(VerdictService::class); // $l10n = $container->get(IL10N::class); $logger = $container->get(LoggerInterface::class); $activityManager = $container->get(IManager::class); @@ -79,7 +80,7 @@ function (string $mountPoint, IStorage $storage) { $appManager = $container->get(IAppManager::class); return new AvirWrapper([ 'storage' => $storage, - //'scannerFactory' => $scannerFactory, + 'verdictService' => $verdictService, //'l10n' => $l10n, 'logger' => $logger, 'activityManager' => $activityManager, diff --git a/lib/AvirWrapper.php b/lib/AvirWrapper.php index 94c10d95..771846a3 100644 --- a/lib/AvirWrapper.php +++ b/lib/AvirWrapper.php @@ -10,10 +10,12 @@ use OC\Files\Storage\Wrapper\Wrapper; use OCA\Files_Trashbin\Trash\ITrashManager; +use OCA\GDataVaas\Service\VerdictService; use OCP\Activity\IManager as ActivityManager; use OCP\EventDispatcher\IEventDispatcher; use OCP\IL10N; use Psr\Log\LoggerInterface; +use VaasSdk\Message\Verdict; class AvirWrapper extends Wrapper { /** @@ -22,8 +24,7 @@ class AvirWrapper extends Wrapper { */ private $writingModes = ['r+', 'w', 'w+', 'a', 'a+', 'x', 'x+', 'c', 'c+']; - /** @var ScannerFactory */ - protected $scannerFactory; + protected VerdictService $verdictService; /** @var IL10N */ protected $l10n; @@ -48,7 +49,7 @@ class AvirWrapper extends Wrapper { */ public function __construct($parameters) { parent::__construct($parameters); - //$this->scannerFactory = $parameters['scannerFactory']; + $this->verdictService = $parameters['verdictService']; //$this->l10n = $parameters['l10n']; $this->logger = $parameters['logger']; $this->activityManager = $parameters['activityManager']; @@ -66,7 +67,11 @@ public function __construct($parameters) { * @return resource | false */ public function fopen($path, $mode) { + $e = new \Exception; $this->logger->debug(var_export($e->getTraceAsString(), true)); $this->logger->debug("AvirWrapper::fopen " . $path); + $cache = $this->getCache($path); + $metadata = $cache->get($path); + $this->logger->debug(var_export($metadata, true)); $stream = $this->storage->fopen($path, $mode); /* @@ -84,6 +89,8 @@ public function fopen($path, $mode) { public function writeStream(string $path, $stream, int $size = null): int { if ($this->shouldWrap($path)) { + $e = new \Exception; $this->logger->debug(var_export($e->getTraceAsString(), true)); + $this->logger->debug("AvirWrapper::writeStream " . $path); $stream = $this->wrapSteam($path, $stream); } return parent::writeStream($path, $stream, $size); @@ -99,40 +106,50 @@ private function shouldWrap(string $path): bool { private function wrapSteam(string $path, $stream) { try { - //$scanner = $this->scannerFactory->getScanner(); - //$scanner->initScanner(); $logger = $this->logger; return CallbackReadDataWrapper::wrap( $stream, null, null, function () use ($path, $logger) { - $logger->debug("Closing " . $path); - sleep(20); -// $status = $scanner->completeAsyncScan(); -// if ($status->getNumericStatus() === Status::SCANRESULT_INFECTED) { -// //prevent from going to trashbin -// if ($this->trashEnabled) { -// /** @var ITrashManager $trashManager */ -// $trashManager = \OC::$server->query(ITrashManager::class); -// $trashManager->pauseTrash(); -// } -// -// $owner = $this->getOwner($path); -// $this->unlink($path); -// -// if ($this->trashEnabled) { -// /** @var ITrashManager $trashManager */ -// $trashManager = \OC::$server->query(ITrashManager::class); -// $trashManager->resumeTrash(); -// } -// -// $this->logger->warning( -// 'Infected file deleted. ' . $status->getDetails() -// . ' Account: ' . $owner . ' Path: ' . $path, -// ['app' => 'files_antivirus'] -// ); -// + $localPath = $this->getLocalFile($path); + $filesize = $this->filesize($path); + $logger->debug("Closing " . $localPath . " with size " . $filesize); + //$cache = $this->getCache($path); + //$logger->debug(print_r($cache, true)); + //$metadata = $cache->get($path); + //$logger->debug(var_export($metadata, true)); + //$metadata2 = $this->getMetaData($path); + //$logger->debug(var_export($metadata2, true)); + + $verdict = $this->verdictService->scan($localPath); + $logger->debug("Verdict for " . $localPath . " is " . $verdict->Verdict->value); + + if ($verdict->Verdict == Verdict::MALICIOUS) { + $logger->debug("Removing malicious file " . $localPath); + + //prevent from going to trashbin + if ($this->trashEnabled) { + /** @var ITrashManager $trashManager */ + $trashManager = \OC::$server->query(ITrashManager::class); + $trashManager->pauseTrash(); + } + + $owner = $this->getOwner($path); + $this->unlink($path); + + if ($this->trashEnabled) { + /** @var ITrashManager $trashManager */ + $trashManager = \OC::$server->query(ITrashManager::class); + $trashManager->resumeTrash(); + } + + $this->logger->warning( + 'Infected file deleted. ' . $verdict->Detection + . ' Account: ' . $owner . ' Path: ' . $path, + ['app' => 'gdatavaas'] + ); + // $activity = $this->activityManager->generateEvent(); // $activity->setApp(Application::APP_NAME) // ->setSubject(Provider::SUBJECT_VIRUS_DETECTED_UPLOAD, [$status->getDetails()]) @@ -151,7 +168,7 @@ function () use ($path, $logger) { // $status->getDetails() // ) // ); -// } + } } ); } catch (\Exception $e) { diff --git a/lib/Service/VerdictService.php b/lib/Service/VerdictService.php index 6263e503..537a67c2 100644 --- a/lib/Service/VerdictService.php +++ b/lib/Service/VerdictService.php @@ -45,7 +45,7 @@ public function __construct(LoggerInterface $logger, IConfig $appConfig, FileSer $this->fileService = $fileService; $this->tagService = $tagService; - $this->authMethod = $this->appConfig->getAppValue(self::APP_ID, 'authMethod', 'ResourceOwnerPassword'); + $this->authMethod = $this->appConfig->getAppValue(self::APP_ID, 'authMethod', 'ClientCredentials'); $this->tokenEndpoint = $this->appConfig->getAppValue(self::APP_ID, 'tokenEndpoint', 'https://account-staging.gdata.de/realms/vaas-staging/protocol/openid-connect/token'); $this->vaasUrl = $this->appConfig->getAppValue(self::APP_ID, 'vaasUrl', 'wss://gateway.staging.vaas.gdatasecurity.de'); $this->clientId = $this->appConfig->getAppValue(self::APP_ID, 'clientId'); @@ -94,17 +94,7 @@ public function scanFileById(int $fileId): VaasVerdict } } - if ($this->vaas == null) { - $this->vaas = $this->createAndConnectVaas(); - } - - try { - $verdict = $this->vaas->ForFile($filePath); - } catch (Exception $e) { - $this->logger->error("Vaas for file: " . $e->getMessage()); - $this->vaas = null; - throw $e; - } + $verdict = $this->scan($filePath); $this->logger->info("VaaS scan result for " . $node->getName() . " (" . $fileId . "): Verdict: " . $verdict->Verdict->value . ", Detection: " . $verdict->Detection . ", SHA256: " . $verdict->Sha256 . @@ -138,6 +128,23 @@ public function scanFileById(int $fileId): VaasVerdict return $verdict; } + public function scan(string $filePath): VaasVerdict + { + if ($this->vaas == null) { + $this->vaas = $this->createAndConnectVaas(); + } + + try { + $verdict = $this->vaas->ForFile($filePath); + + return $verdict; + } catch (Exception $e) { + $this->logger->error("Vaas for file: " . $e->getMessage()); + $this->vaas = null; + throw $e; + } + } + /** * Parses the allowlist from the app settings and returns it as an array. * @return array From df24abb687cb3b65c509b6ab5d0fcebf2a6da2cd Mon Sep 17 00:00:00 2001 From: PT-ATA No One Date: Tue, 4 Jun 2024 09:54:12 +0200 Subject: [PATCH 2/5] show activities in log --- .devcontainer/dev/devcontainer.json | 41 ------- .devcontainer/nextcloud/devcontainer.json | 40 ------- .github/dependabot.yml | 12 ++ appinfo/info.xml | 10 +- composer.json | 4 +- install.sh | 9 +- lib/Activity/Provider.php | 139 ++++++++++++++++++++++ lib/Activity/Setting.php | 59 +++++++++ lib/AvirWrapper.php | 49 +++----- lib/Service/TagService.php | 12 +- lib/Service/VerdictService.php | 4 +- lib/stacktrace.txt | 63 ++++++++++ 12 files changed, 320 insertions(+), 122 deletions(-) delete mode 100644 .devcontainer/dev/devcontainer.json delete mode 100644 .devcontainer/nextcloud/devcontainer.json create mode 100644 .github/dependabot.yml create mode 100644 lib/Activity/Provider.php create mode 100644 lib/Activity/Setting.php create mode 100644 lib/stacktrace.txt diff --git a/.devcontainer/dev/devcontainer.json b/.devcontainer/dev/devcontainer.json deleted file mode 100644 index 1638e2f9..00000000 --- a/.devcontainer/dev/devcontainer.json +++ /dev/null @@ -1,41 +0,0 @@ -// For format details, see https://aka.ms/devcontainer.json. For config options, see the -// README at: https://github.com/devcontainers/templates/tree/main/src/docker-existing-docker-compose -{ - "name": "php container", - // Update the 'dockerComposeFile' list if you have more compose files or use different names. - // The .devcontainer/docker-compose.yml file contains any overrides you need/want to make. - "dockerComposeFile": [ - "../../devcontainer.yaml" - ], - // The 'service' property is the name of the service for the container that VS Code should - // use. Update this value and .devcontainer/docker-compose.yml to the real service name. - "service": "dev", - // The optional 'workspaceFolder' property is the path VS Code should open by default when - // connected. This is typically a file mount in .devcontainer/docker-compose.yml - "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", - "features": { - "ghcr.io/devcontainers/features/php:1": {}, - "ghcr.io/devcontainers-contrib/features/node-asdf:0": {} - }, - "remoteUser": "www-data", - "remoteEnv": { - "LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}" - }, - "containerEnv": { - "SHELL": "/bin/bash" - } - // Features to add to the dev container. More info: https://containers.dev/features. - // "features": {}, - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], - // Uncomment the next line if you want start specific services in your Docker Compose config. - // "runServices": [], - // Uncomment the next line if you want to keep your containers running after VS Code shuts down. - // "shutdownAction": "none", - // Uncomment the next line to run commands after the container is created. - // "postCreateCommand": "cat /etc/os-release", - // Configure tool-specific properties. - // "customizations": {}, - // Uncomment to connect as an existing user other than the container default. More info: https://aka.ms/dev-containers-non-root. - // "remoteUser": "devcontainer" -} \ No newline at end of file diff --git a/.devcontainer/nextcloud/devcontainer.json b/.devcontainer/nextcloud/devcontainer.json deleted file mode 100644 index 0ae124b8..00000000 --- a/.devcontainer/nextcloud/devcontainer.json +++ /dev/null @@ -1,40 +0,0 @@ -// For format details, see https://aka.ms/devcontainer.json. For config options, see the -// README at: https://github.com/devcontainers/templates/tree/main/src/docker-existing-docker-compose -{ - "name": "nextcloud", - // Update the 'dockerComposeFile' list if you have more compose files or use different names. - // The .devcontainer/docker-compose.yml file contains any overrides you need/want to make. - "dockerComposeFile": [ - "../../devcontainer.yaml" - ], - // The 'service' property is the name of the service for the container that VS Code should - // use. Update this value and .devcontainer/docker-compose.yml to the real service name. - "service": "nextcloud", - // The optional 'workspaceFolder' property is the path VS Code should open by default when - // connected. This is typically a file mount in .devcontainer/docker-compose.yml - "features": { - "ghcr.io/devcontainers/features/php:1": {} - }, - "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", - "remoteEnv": { - "LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}" - }, - "remoteUser": "root", - "containerEnv": { - "SHELL": "/bin/bash" - } - // Features to add to the dev container. More info: https://containers.dev/features. - // "features": {}, - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], - // Uncomment the next line if you want start specific services in your Docker Compose config. - // "runServices": [], - // Uncomment the next line if you want to keep your containers running after VS Code shuts down. - // "shutdownAction": "none", - // Uncomment the next line to run commands after the container is created. - // "postCreateCommand": "cat /etc/os-release", - // Configure tool-specific properties. - // "customizations": {}, - // Uncomment to connect as an existing user other than the container default. More info: https://aka.ms/dev-containers-non-root. - // "remoteUser": "devcontainer" -} \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..f33a02cd --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for more information: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates +# https://containers.dev/guide/dependabot + +version: 2 +updates: + - package-ecosystem: "devcontainers" + directory: "/" + schedule: + interval: weekly diff --git a/appinfo/info.xml b/appinfo/info.xml index b26336ce..078ea436 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -7,7 +7,7 @@ gdatavaas G DATA Antivirus This app aims to provide an additional layer of security to your Nextcloud instance by enabling automatic and manual scanning of files for malicious content. - 0.0.1 + 0.0.0 agpl Lennart Dohmann GDataVaas @@ -27,4 +27,12 @@ pgsql mysql sqlite + + + OCA\GDataVaas\Activity\Setting + + + OCA\GDataVaas\Activity\Provider + + diff --git a/composer.json b/composer.json index 3d024c09..de0aab5e 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ } ], "require": { - "gdata/vaas": "^8.0.0" + "gdata/vaas": "^8.0.2" }, "require-dev": { "nextcloud/ocp": "dev-stable28", @@ -17,7 +17,7 @@ "nextcloud/coding-standard": "^v1.1.1" }, "scripts": { - "lint": "find . -name \\*.php -not -path './vendor/*' -print0 | xargs -0 -n1 php -l", + "lint": "find lib -name \\*.php -not -path './vendor/*' -print0 | xargs -0 -n1 php -l", "cs:check": "php-cs-fixer fix --dry-run --diff .", "cs:fix": "php-cs-fixer fix .", "psalm": "vendor/psalm/phar/psalm.phar --threads=1", diff --git a/install.sh b/install.sh index 781eed16..1bfbd50a 100755 --- a/install.sh +++ b/install.sh @@ -4,8 +4,13 @@ docker stop nextcloud-container sleep 1 docker run -d --name nextcloud-container --rm --publish 80:80 --publish 8080:8080 --publish 8443:8443 nextcloud:stable echo "Waiting for sunrise..." -sleep 5 -docker exec --user www-data -it nextcloud-container php occ maintenance:install --admin-user=admin --admin-pass=admin + +until docker exec --user www-data -it nextcloud-container php occ maintenance:install --admin-user=admin --admin-pass=admin >/dev/null +do + echo "Try again waiting 2 seconds" + sleep 2 +done + make appstore tar -xf ./build/artifacts/gdatavaas.tar.gz -C ./build/artifacts docker cp ./build/artifacts/gdatavaas nextcloud-container:/var/www/html/apps/ diff --git a/lib/Activity/Provider.php b/lib/Activity/Provider.php new file mode 100644 index 00000000..a6a223b9 --- /dev/null +++ b/lib/Activity/Provider.php @@ -0,0 +1,139 @@ + + * + * @author Roeland Jago Douma + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OCA\GDataVaas\Activity; + +use OCA\GDataVaas\AppInfo\Application; +use OCP\Activity\IEvent; +use OCP\Activity\IProvider; +use OCP\IURLGenerator; +use OCP\L10N\IFactory; +use Psr\Log\LoggerInterface; + +class Provider implements IProvider { + public const TYPE_VIRUS_DETECTED = 'virus_detected'; + + public const SUBJECT_VIRUS_DETECTED = 'virus_detected'; + public const SUBJECT_VIRUS_DETECTED_UPLOAD = 'virus_detected_upload'; + public const SUBJECT_VIRUS_DETECTED_SCAN = 'virus_detected_scan'; + + public const MESSAGE_FILE_DELETED = 'file_deleted'; + + /** @var IFactory */ + private $languageFactory; + + /** @var IURLGenerator */ + private $urlGenerator; + private LoggerInterface $logger; + + public function __construct(IFactory $languageFactory, IURLGenerator $urlGenerator, LoggerInterface $logger) { + $this->languageFactory = $languageFactory; + $this->urlGenerator = $urlGenerator; + $this->logger = $logger; + } + + public function parse($language, IEvent $event, IEvent $previousEvent = null) { + if ($event->getApp() !== Application::APP_ID || $event->getType() !== self::TYPE_VIRUS_DETECTED) { + throw new \InvalidArgumentException(); + } + + $parameters = []; + $subject = ''; + + if ($event->getSubject() === self::SUBJECT_VIRUS_DETECTED) { + $subject = 'File {file} is infected with {virus}'; + + $params = $event->getSubjectParameters(); + $parameters['virus'] = [ + 'type' => 'highlight', + 'id' => $params[1], + 'name' => $params[1], + ]; + + $parameters['file'] = [ + 'type' => 'highlight', + 'id' => $event->getObjectName(), + 'name' => basename($event->getObjectName()), + ]; + $event->setIcon($this->urlGenerator->imagePath('gdatavaas', 'gdatalogo.svg')); + + if ($event->getMessage() === self::MESSAGE_FILE_DELETED) { + $event->setParsedMessage('The file has been removed'); + } + } elseif ($event->getSubject() === self::SUBJECT_VIRUS_DETECTED_UPLOAD) { + $subject = 'File containing {virus} detected'; + + $params = $event->getSubjectParameters(); + $parameters['virus'] = [ + 'type' => 'highlight', + 'id' => $params[0], + 'name' => $params[0], + ]; + + $event->setParsedSubject($subject); + $event->setRichSubject($subject); + $event->setIcon($this->urlGenerator->imagePath('gdatavaas', 'gdatalogo.svg')); + + if ($event->getMessage() === self::MESSAGE_FILE_DELETED) { + $event->setParsedMessage('The file has been removed'); + } + } elseif ($event->getSubject() === self::SUBJECT_VIRUS_DETECTED_SCAN) { + $subject = 'File {file} is infected with {virus}'; + + $params = $event->getSubjectParameters(); + $parameters['virus'] = [ + 'type' => 'highlight', + 'id' => $params[0], + 'name' => $params[0], + ]; + $parameters['file'] = [ + 'type' => 'highlight', + 'id' => $event->getObjectName(), + 'name' => $event->getObjectName(), + ]; + $event->setIcon($this->urlGenerator->imagePath('gdatavaas', 'gdatalogo.svg')); + + if ($event->getMessage() === self::MESSAGE_FILE_DELETED) { + $event->setParsedMessage('The file has been removed'); + } + } + + $this->setSubjects($event, $subject, $parameters); + + return $event; + } + + private function setSubjects(IEvent $event, string $subject, array $parameters): void { + $placeholders = $replacements = []; + foreach ($parameters as $placeholder => $parameter) { + $placeholders[] = '{' . $placeholder . '}'; + if ($parameter['type'] === 'file') { + $replacements[] = $parameter['path']; + } else { + $replacements[] = $parameter['name']; + } + } + + $event->setParsedSubject(str_replace($placeholders, $replacements, $subject)) + ->setRichSubject($subject, $parameters); + } +} diff --git a/lib/Activity/Setting.php b/lib/Activity/Setting.php new file mode 100644 index 00000000..c07b1db8 --- /dev/null +++ b/lib/Activity/Setting.php @@ -0,0 +1,59 @@ + + * + * @author Roeland Jago Douma + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OCA\GDataVaas\Activity; + +use OCP\Activity\ISetting; + +class Setting implements ISetting { + + public function __construct() { + } + + public function getIdentifier() { + return Provider::TYPE_VIRUS_DETECTED; + } + + public function getName() { + return 'Antivirus detected a virus'; + } + + public function getPriority() { + return 70; + } + + public function canChangeStream() { + return false; + } + + public function isDefaultEnabledStream() { + return true; + } + + public function canChangeMail() { + return false; + } + + public function isDefaultEnabledMail() { + return false; + } +} diff --git a/lib/AvirWrapper.php b/lib/AvirWrapper.php index 771846a3..6c0c3031 100644 --- a/lib/AvirWrapper.php +++ b/lib/AvirWrapper.php @@ -10,9 +10,12 @@ use OC\Files\Storage\Wrapper\Wrapper; use OCA\Files_Trashbin\Trash\ITrashManager; +use OCA\GDataVaas\Activity\Provider; +use OCA\GDataVaas\AppInfo\Application; use OCA\GDataVaas\Service\VerdictService; use OCP\Activity\IManager as ActivityManager; use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\InvalidContentException; use OCP\IL10N; use Psr\Log\LoggerInterface; use VaasSdk\Message\Verdict; @@ -50,7 +53,6 @@ class AvirWrapper extends Wrapper { public function __construct($parameters) { parent::__construct($parameters); $this->verdictService = $parameters['verdictService']; - //$this->l10n = $parameters['l10n']; $this->logger = $parameters['logger']; $this->activityManager = $parameters['activityManager']; $this->isHomeStorage = $parameters['isHomeStorage']; @@ -67,8 +69,6 @@ public function __construct($parameters) { * @return resource | false */ public function fopen($path, $mode) { - $e = new \Exception; $this->logger->debug(var_export($e->getTraceAsString(), true)); - $this->logger->debug("AvirWrapper::fopen " . $path); $cache = $this->getCache($path); $metadata = $cache->get($path); $this->logger->debug(var_export($metadata, true)); @@ -89,8 +89,6 @@ public function fopen($path, $mode) { public function writeStream(string $path, $stream, int $size = null): int { if ($this->shouldWrap($path)) { - $e = new \Exception; $this->logger->debug(var_export($e->getTraceAsString(), true)); - $this->logger->debug("AvirWrapper::writeStream " . $path); $stream = $this->wrapSteam($path, $stream); } return parent::writeStream($path, $stream, $size); @@ -115,12 +113,6 @@ function () use ($path, $logger) { $localPath = $this->getLocalFile($path); $filesize = $this->filesize($path); $logger->debug("Closing " . $localPath . " with size " . $filesize); - //$cache = $this->getCache($path); - //$logger->debug(print_r($cache, true)); - //$metadata = $cache->get($path); - //$logger->debug(var_export($metadata, true)); - //$metadata2 = $this->getMetaData($path); - //$logger->debug(var_export($metadata2, true)); $verdict = $this->verdictService->scan($localPath); $logger->debug("Verdict for " . $localPath . " is " . $verdict->Verdict->value); @@ -149,25 +141,22 @@ function () use ($path, $logger) { . ' Account: ' . $owner . ' Path: ' . $path, ['app' => 'gdatavaas'] ); - -// $activity = $this->activityManager->generateEvent(); -// $activity->setApp(Application::APP_NAME) -// ->setSubject(Provider::SUBJECT_VIRUS_DETECTED_UPLOAD, [$status->getDetails()]) -// ->setMessage(Provider::MESSAGE_FILE_DELETED) -// ->setObject('', 0, $path) -// ->setAffectedUser($owner) -// ->setType(Provider::TYPE_VIRUS_DETECTED); -// $this->activityManager->publish($activity); -// -// $this->logger->error('Infected file deleted. ' . $status->getDetails() . -// ' File: ' . $path . ' Account: ' . $owner, ['app' => 'files_antivirus']); -// -// throw new InvalidContentException( -// $this->l10n->t( -// 'Virus %s is detected in the file. Upload cannot be completed.', -// $status->getDetails() -// ) -// ); + + $activity = $this->activityManager->generateEvent(); + $activity->setApp(Application::APP_ID) + ->setSubject(Provider::SUBJECT_VIRUS_DETECTED_UPLOAD, [$verdict->Detection ?? "no_detection_name"]) + ->setMessage(Provider::MESSAGE_FILE_DELETED) + ->setObject('', 0, $path) + ->setAffectedUser($owner) + ->setType(Provider::TYPE_VIRUS_DETECTED); + $this->activityManager->publish($activity); + + throw new InvalidContentException( + sprintf( + 'Virus %s is detected in the file. Upload cannot be completed.', + $verdict->Detection + ) + ); } } ); diff --git a/lib/Service/TagService.php b/lib/Service/TagService.php index 5b9b1b82..041de672 100644 --- a/lib/Service/TagService.php +++ b/lib/Service/TagService.php @@ -42,12 +42,12 @@ public function __construct(LoggerInterface $logger, ISystemTagManager $systemTa public function getTag(string $name, bool $create = true): ISystemTag { try { - $tag = $this->tagService->getTag($name, true, true); + $tag = $this->tagService->getTag($name, true, false); } catch (TagNotFoundException) { if (!$create) { throw new TagNotFoundException(); } - $tag = $this->tagService->createTag($name, true, true); + $tag = $this->tagService->createTag($name, true, false); $this->logger->debug("Tag created: " . $name); } return $tag; @@ -73,7 +73,7 @@ public function setTag(int $fileId, string $tagName): void public function removeTagFromFile(string $tagName, int $fileId): bool { try { - $tag = $this->tagService->getTag($tagName, true, true); + $tag = $this->tagService->getTag($tagName, true, false); $this->tagMapper->unassignTags(strval($fileId), 'files', [$tag->getId()]); $this->logger->debug("Tag removed: " . $tagName . " for file " . $fileId); return true; @@ -89,9 +89,11 @@ public function removeTagFromFile(string $tagName, int $fileId): bool */ public function hasCleanMaliciousOrPupTag(int $fileId): bool { - if ($this->tagMapper->haveTag([$fileId], 'files', $this->getTag(self::CLEAN)->getId()) || + if ( + $this->tagMapper->haveTag([$fileId], 'files', $this->getTag(self::CLEAN)->getId()) || $this->tagMapper->haveTag([$fileId], 'files', $this->getTag(self::MALICIOUS)->getId()) || - $this->tagMapper->haveTag([$fileId], 'files', $this->getTag(self::PUP)->getId())) { + $this->tagMapper->haveTag([$fileId], 'files', $this->getTag(self::PUP)->getId()) + ) { return true; } return false; diff --git a/lib/Service/VerdictService.php b/lib/Service/VerdictService.php index 537a67c2..3c467d96 100644 --- a/lib/Service/VerdictService.php +++ b/lib/Service/VerdictService.php @@ -18,6 +18,7 @@ use VaasSdk\Message\VaasVerdict; use VaasSdk\ResourceOwnerPasswordGrantAuthenticator; use VaasSdk\Vaas; +use VaasSdk\VaasOptions; class VerdictService { @@ -193,7 +194,8 @@ private function createAndConnectVaas(): Vaas ); } - $vaas = new Vaas($this->vaasUrl); + $options = new VaasOptions(false, false); + $vaas = new Vaas($this->vaasUrl, $this->logger, $options); $vaas->Connect($this->authenticator->getToken()); return $vaas; } diff --git a/lib/stacktrace.txt b/lib/stacktrace.txt new file mode 100644 index 00000000..98653ad9 --- /dev/null +++ b/lib/stacktrace.txt @@ -0,0 +1,63 @@ +"'#0 /var/www/html/lib/private/Files/Storage/Wrapper/Wrapper.php(307): OCA\\\\GDataVaas\\\\AvirWrapper->fopen(\\'files/Screensho...\\', \\'r\\') +#1 /var/www/html/lib/private/Files/View.php(1159): OC\\\\Files\\\\Storage\\\\Wrapper\\\\Wrapper->fopen(\\'files/Screensho...\\', \\'r\\') +#2 /var/www/html/lib/private/Files/View.php(987): OC\\\\Files\\\\View->basicOperation(\\'fopen\\', \\'/admin/files/Sc...\\', Array, \\'r\\') +#3 /var/www/html/lib/private/Files/Node/File.php(116): OC\\\\Files\\\\View->fopen(\\'/admin/files/Sc...\\', \\'r\\') +#4 /var/www/html/apps/photos/lib/Listener/ExifMetadataProvider.php(71): OC\\\\Files\\\ +ode\\\\File->fopen(\\'rb\\') +#5 /var/www/html/lib/private/EventDispatcher/ServiceEventListener.php(86): OCA\\\\Photos\\\\Listener\\\\ExifMetadataProvider->handle(Object(OCP\\\\FilesMetadata\\\\Event\\\\MetadataLiveEvent)) +#6 /var/www/html/3rdparty/symfony/event-dispatcher/EventDispatcher.php(230): OC\\\\EventDispatcher\\\\ServiceEventListener->__invoke(Object(OCP\\\\FilesMetadata\\\\Event\\\\MetadataLiveEvent), \\'OCP\\\\\\\\FilesMetada...\\', Object(Symfony\\\\Component\\\\EventDispatcher\\\\EventDispatcher)) +#7 /var/www/html/3rdparty/symfony/event-dispatcher/EventDispatcher.php(59): Symfony\\\\Component\\\\EventDispatcher\\\\EventDispatcher->callListeners(Array, \\'OCP\\\\\\\\FilesMetada...\\', Object(OCP\\\\FilesMetadata\\\\Event\\\\MetadataLiveEvent)) +#8 /var/www/html/lib/private/EventDispatcher/EventDispatcher.php(94): Symfony\\\\Component\\\\EventDispatcher\\\\EventDispatcher->dispatch(Object(OCP\\\\FilesMetadata\\\\Event\\\\MetadataLiveEvent), \\'OCP\\\\\\\\FilesMetada...\\') +#9 /var/www/html/lib/private/EventDispatcher/EventDispatcher.php(106): OC\\\\EventDispatcher\\\\EventDispatcher->dispatch(\\'OCP\\\\\\\\FilesMetada...\\', Object(OCP\\\\FilesMetadata\\\\Event\\\\MetadataLiveEvent)) +#10 /var/www/html/lib/private/FilesMetadata/FilesMetadataManager.php(115): OC\\\\EventDispatcher\\\\EventDispatcher->dispatchTyped(Object(OCP\\\\FilesMetadata\\\\Event\\\\MetadataLiveEvent)) +#11 /var/www/html/lib/private/FilesMetadata/Listener/MetadataUpdate.php(59): OC\\\\FilesMetadata\\\\FilesMetadataManager->refreshMetadata(Object(OC\\\\Files\\\ +ode\\\\File)) +#12 /var/www/html/lib/private/EventDispatcher/ServiceEventListener.php(86): OC\\\\FilesMetadata\\\\Listener\\\\MetadataUpdate->handle(Object(OCP\\\\Files\\\\Events\\\ +ode\\\ +odeWrittenEvent)) +#13 /var/www/html/3rdparty/symfony/event-dispatcher/EventDispatcher.php(230): OC\\\\EventDispatcher\\\\ServiceEventListener->__invoke(Object(OCP\\\\Files\\\\Events\\\ +ode\\\ +odeWrittenEvent), \\'OCP\\\\\\\\Files\\\\\\\\Event...\\', Object(Symfony\\\\Component\\\\EventDispatcher\\\\EventDispatcher)) +#14 /var/www/html/3rdparty/symfony/event-dispatcher/EventDispatcher.php(59): Symfony\\\\Component\\\\EventDispatcher\\\\EventDispatcher->callListeners(Array, \\'OCP\\\\\\\\Files\\\\\\\\Event...\\', Object(OCP\\\\Files\\\\Events\\\ +ode\\\ +odeWrittenEvent)) +#15 /var/www/html/lib/private/EventDispatcher/EventDispatcher.php(94): Symfony\\\\Component\\\\EventDispatcher\\\\EventDispatcher->dispatch(Object(OCP\\\\Files\\\\Events\\\ +ode\\\ +odeWrittenEvent), \\'OCP\\\\\\\\Files\\\\\\\\Event...\\') +#16 /var/www/html/lib/private/EventDispatcher/EventDispatcher.php(106): OC\\\\EventDispatcher\\\\EventDispatcher->dispatch(\\'OCP\\\\\\\\Files\\\\\\\\Event...\\', Object(OCP\\\\Files\\\\Events\\\ +ode\\\ +odeWrittenEvent)) +#17 /var/www/html/lib/private/Files/Node/HookConnector.php(109): OC\\\\EventDispatcher\\\\EventDispatcher->dispatchTyped(Object(OCP\\\\Files\\\\Events\\\ +ode\\\ +odeWrittenEvent)) +#18 /var/www/html/lib/private/legacy/OC_Hook.php(105): OC\\\\Files\\\ +ode\\\\HookConnector->postWrite(Array) +#19 /var/www/html/apps/dav/lib/Connector/Sabre/File.php(479): OC_Hook::emit(\\'OC_Filesystem\\', \\'post_write\\', Array) +#20 /var/www/html/apps/dav/lib/Connector/Sabre/File.php(404): OCA\\\\DAV\\\\Connector\\\\Sabre\\\\File->emitPostHooks(false) +#21 /var/www/html/apps/dav/lib/Connector/Sabre/Directory.php(148): OCA\\\\DAV\\\\Connector\\\\Sabre\\\\File->put(Resource id #15) +#22 /var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php(1098): OCA\\\\DAV\\\\Connector\\\\Sabre\\\\Directory->createFile(\\'Screenshot from...\\', Resource id #15) +#23 /var/www/html/3rdparty/sabre/dav/lib/DAV/CorePlugin.php(504): Sabre\\\\DAV\\\\Server->createFile(\\'files/admin/Scr...\\', Resource id #15, NULL) +#24 /var/www/html/3rdparty/sabre/event/lib/WildcardEmitterTrait.php(89): Sabre\\\\DAV\\\\CorePlugin->httpPut(Object(Sabre\\\\HTTP\\\\Request), Object(Sabre\\\\HTTP\\\\Response)) +#25 /var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php(472): Sabre\\\\DAV\\\\Server->emit(\\'method:PUT\\', Array) +#26 /var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php(253): Sabre\\\\DAV\\\\Server->invokeMethod(Object(Sabre\\\\HTTP\\\\Request), Object(Sabre\\\\HTTP\\\\Response)) +#27 /var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php(321): Sabre\\\\DAV\\\\Server->start() +#28 /var/www/html/apps/dav/lib/Server.php(373): Sabre\\\\DAV\\\\Server->exec() +#29 /var/www/html/apps/dav/appinfo/v2/remote.php(35): OCA\\\\DAV\\\\Server->exec() +#30 /var/www/html/remote.php(172): require_once(\\'/var/www/html/a...\\') +#31 {main}' + +writeStream: + +"'#0 /var/www/html/lib/private/Files/Storage/Wrapper/Wrapper.php(653): OCA\\\\GDataVaas\\\\AvirWrapper->writeStream(\\'files/JSON_desc...\\', Resource id #18, NULL) +#1 /var/www/html/apps/dav/lib/Connector/Sabre/File.php(250): OC\\\\Files\\\\Storage\\\\Wrapper\\\\Wrapper->writeStream(\\'files/JSON_desc...\\', Resource id #18) +#2 /var/www/html/apps/dav/lib/Connector/Sabre/Directory.php(148): OCA\\\\DAV\\\\Connector\\\\Sabre\\\\File->put(Resource id #15) +#3 /var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php(1098): OCA\\\\DAV\\\\Connector\\\\Sabre\\\\Directory->createFile(\\'JSON_desc.txt\\', Resource id #15) +#4 /var/www/html/3rdparty/sabre/dav/lib/DAV/CorePlugin.php(504): Sabre\\\\DAV\\\\Server->createFile(\\'files/admin/JSO...\\', Resource id #15, NULL) +#5 /var/www/html/3rdparty/sabre/event/lib/WildcardEmitterTrait.php(89): Sabre\\\\DAV\\\\CorePlugin->httpPut(Object(Sabre\\\\HTTP\\\\Request), Object(Sabre\\\\HTTP\\\\Response)) +#6 /var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php(472): Sabre\\\\DAV\\\\Server->emit(\\'method:PUT\\', Array) +#7 /var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php(253): Sabre\\\\DAV\\\\Server->invokeMethod(Object(Sabre\\\\HTTP\\\\Request), Object(Sabre\\\\HTTP\\\\Response)) +#8 /var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php(321): Sabre\\\\DAV\\\\Server->start() +#9 /var/www/html/apps/dav/lib/Server.php(373): Sabre\\\\DAV\\\\Server->exec() +#10 /var/www/html/apps/dav/appinfo/v2/remote.php(35): OCA\\\\DAV\\\\Server->exec() +#11 /var/www/html/remote.php(172): require_once(\\'/var/www/html/a...\\') +#12 {main}'" \ No newline at end of file From 90f893be48fe883ee15d8a3b5ca3ce588d29f236 Mon Sep 17 00:00:00 2001 From: Kevin Heise Date: Tue, 4 Jun 2024 10:40:29 +0200 Subject: [PATCH 3/5] update install script --- install.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/install.sh b/install.sh index 1bfbd50a..9eb637d7 100755 --- a/install.sh +++ b/install.sh @@ -2,7 +2,7 @@ docker stop nextcloud-container sleep 1 -docker run -d --name nextcloud-container --rm --publish 80:80 --publish 8080:8080 --publish 8443:8443 nextcloud:stable +docker run -d --name nextcloud-container --rm --publish 80:80 nextcloud:28 echo "Waiting for sunrise..." until docker exec --user www-data -it nextcloud-container php occ maintenance:install --admin-user=admin --admin-pass=admin >/dev/null @@ -11,6 +11,7 @@ do sleep 2 done +make build make appstore tar -xf ./build/artifacts/gdatavaas.tar.gz -C ./build/artifacts docker cp ./build/artifacts/gdatavaas nextcloud-container:/var/www/html/apps/ From ca2ebc6d2b5936e3b1aa6c9b84dc0675410d4557 Mon Sep 17 00:00:00 2001 From: PT-ATA No One Date: Tue, 4 Jun 2024 11:15:12 +0200 Subject: [PATCH 4/5] add better icon --- img/favicon.svg | 16 ++++++++++++++++ lib/Activity/Provider.php | 6 +++--- 2 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 img/favicon.svg diff --git a/img/favicon.svg b/img/favicon.svg new file mode 100644 index 00000000..3e369ff8 --- /dev/null +++ b/img/favicon.svg @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/lib/Activity/Provider.php b/lib/Activity/Provider.php index a6a223b9..05f8b7ea 100644 --- a/lib/Activity/Provider.php +++ b/lib/Activity/Provider.php @@ -74,7 +74,7 @@ public function parse($language, IEvent $event, IEvent $previousEvent = null) { 'id' => $event->getObjectName(), 'name' => basename($event->getObjectName()), ]; - $event->setIcon($this->urlGenerator->imagePath('gdatavaas', 'gdatalogo.svg')); + $event->setIcon($this->urlGenerator->imagePath('gdatavaas', 'favicon.svg')); if ($event->getMessage() === self::MESSAGE_FILE_DELETED) { $event->setParsedMessage('The file has been removed'); @@ -91,7 +91,7 @@ public function parse($language, IEvent $event, IEvent $previousEvent = null) { $event->setParsedSubject($subject); $event->setRichSubject($subject); - $event->setIcon($this->urlGenerator->imagePath('gdatavaas', 'gdatalogo.svg')); + $event->setIcon($this->urlGenerator->imagePath('gdatavaas', 'favicon.svg')); if ($event->getMessage() === self::MESSAGE_FILE_DELETED) { $event->setParsedMessage('The file has been removed'); @@ -110,7 +110,7 @@ public function parse($language, IEvent $event, IEvent $previousEvent = null) { 'id' => $event->getObjectName(), 'name' => $event->getObjectName(), ]; - $event->setIcon($this->urlGenerator->imagePath('gdatavaas', 'gdatalogo.svg')); + $event->setIcon($this->urlGenerator->imagePath('gdatavaas', 'favicon.svg')); if ($event->getMessage() === self::MESSAGE_FILE_DELETED) { $event->setParsedMessage('The file has been removed'); From 3c4dbb167ea0f1757ccd0862f1cb8ac244667e96 Mon Sep 17 00:00:00 2001 From: PT-ATA No One Date: Tue, 4 Jun 2024 11:19:39 +0200 Subject: [PATCH 5/5] remove unused files --- .github/dependabot.yml | 12 -------- lib/stacktrace.txt | 63 ------------------------------------------ 2 files changed, 75 deletions(-) delete mode 100644 .github/dependabot.yml delete mode 100644 lib/stacktrace.txt diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index f33a02cd..00000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,12 +0,0 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for more information: -# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates -# https://containers.dev/guide/dependabot - -version: 2 -updates: - - package-ecosystem: "devcontainers" - directory: "/" - schedule: - interval: weekly diff --git a/lib/stacktrace.txt b/lib/stacktrace.txt deleted file mode 100644 index 98653ad9..00000000 --- a/lib/stacktrace.txt +++ /dev/null @@ -1,63 +0,0 @@ -"'#0 /var/www/html/lib/private/Files/Storage/Wrapper/Wrapper.php(307): OCA\\\\GDataVaas\\\\AvirWrapper->fopen(\\'files/Screensho...\\', \\'r\\') -#1 /var/www/html/lib/private/Files/View.php(1159): OC\\\\Files\\\\Storage\\\\Wrapper\\\\Wrapper->fopen(\\'files/Screensho...\\', \\'r\\') -#2 /var/www/html/lib/private/Files/View.php(987): OC\\\\Files\\\\View->basicOperation(\\'fopen\\', \\'/admin/files/Sc...\\', Array, \\'r\\') -#3 /var/www/html/lib/private/Files/Node/File.php(116): OC\\\\Files\\\\View->fopen(\\'/admin/files/Sc...\\', \\'r\\') -#4 /var/www/html/apps/photos/lib/Listener/ExifMetadataProvider.php(71): OC\\\\Files\\\ -ode\\\\File->fopen(\\'rb\\') -#5 /var/www/html/lib/private/EventDispatcher/ServiceEventListener.php(86): OCA\\\\Photos\\\\Listener\\\\ExifMetadataProvider->handle(Object(OCP\\\\FilesMetadata\\\\Event\\\\MetadataLiveEvent)) -#6 /var/www/html/3rdparty/symfony/event-dispatcher/EventDispatcher.php(230): OC\\\\EventDispatcher\\\\ServiceEventListener->__invoke(Object(OCP\\\\FilesMetadata\\\\Event\\\\MetadataLiveEvent), \\'OCP\\\\\\\\FilesMetada...\\', Object(Symfony\\\\Component\\\\EventDispatcher\\\\EventDispatcher)) -#7 /var/www/html/3rdparty/symfony/event-dispatcher/EventDispatcher.php(59): Symfony\\\\Component\\\\EventDispatcher\\\\EventDispatcher->callListeners(Array, \\'OCP\\\\\\\\FilesMetada...\\', Object(OCP\\\\FilesMetadata\\\\Event\\\\MetadataLiveEvent)) -#8 /var/www/html/lib/private/EventDispatcher/EventDispatcher.php(94): Symfony\\\\Component\\\\EventDispatcher\\\\EventDispatcher->dispatch(Object(OCP\\\\FilesMetadata\\\\Event\\\\MetadataLiveEvent), \\'OCP\\\\\\\\FilesMetada...\\') -#9 /var/www/html/lib/private/EventDispatcher/EventDispatcher.php(106): OC\\\\EventDispatcher\\\\EventDispatcher->dispatch(\\'OCP\\\\\\\\FilesMetada...\\', Object(OCP\\\\FilesMetadata\\\\Event\\\\MetadataLiveEvent)) -#10 /var/www/html/lib/private/FilesMetadata/FilesMetadataManager.php(115): OC\\\\EventDispatcher\\\\EventDispatcher->dispatchTyped(Object(OCP\\\\FilesMetadata\\\\Event\\\\MetadataLiveEvent)) -#11 /var/www/html/lib/private/FilesMetadata/Listener/MetadataUpdate.php(59): OC\\\\FilesMetadata\\\\FilesMetadataManager->refreshMetadata(Object(OC\\\\Files\\\ -ode\\\\File)) -#12 /var/www/html/lib/private/EventDispatcher/ServiceEventListener.php(86): OC\\\\FilesMetadata\\\\Listener\\\\MetadataUpdate->handle(Object(OCP\\\\Files\\\\Events\\\ -ode\\\ -odeWrittenEvent)) -#13 /var/www/html/3rdparty/symfony/event-dispatcher/EventDispatcher.php(230): OC\\\\EventDispatcher\\\\ServiceEventListener->__invoke(Object(OCP\\\\Files\\\\Events\\\ -ode\\\ -odeWrittenEvent), \\'OCP\\\\\\\\Files\\\\\\\\Event...\\', Object(Symfony\\\\Component\\\\EventDispatcher\\\\EventDispatcher)) -#14 /var/www/html/3rdparty/symfony/event-dispatcher/EventDispatcher.php(59): Symfony\\\\Component\\\\EventDispatcher\\\\EventDispatcher->callListeners(Array, \\'OCP\\\\\\\\Files\\\\\\\\Event...\\', Object(OCP\\\\Files\\\\Events\\\ -ode\\\ -odeWrittenEvent)) -#15 /var/www/html/lib/private/EventDispatcher/EventDispatcher.php(94): Symfony\\\\Component\\\\EventDispatcher\\\\EventDispatcher->dispatch(Object(OCP\\\\Files\\\\Events\\\ -ode\\\ -odeWrittenEvent), \\'OCP\\\\\\\\Files\\\\\\\\Event...\\') -#16 /var/www/html/lib/private/EventDispatcher/EventDispatcher.php(106): OC\\\\EventDispatcher\\\\EventDispatcher->dispatch(\\'OCP\\\\\\\\Files\\\\\\\\Event...\\', Object(OCP\\\\Files\\\\Events\\\ -ode\\\ -odeWrittenEvent)) -#17 /var/www/html/lib/private/Files/Node/HookConnector.php(109): OC\\\\EventDispatcher\\\\EventDispatcher->dispatchTyped(Object(OCP\\\\Files\\\\Events\\\ -ode\\\ -odeWrittenEvent)) -#18 /var/www/html/lib/private/legacy/OC_Hook.php(105): OC\\\\Files\\\ -ode\\\\HookConnector->postWrite(Array) -#19 /var/www/html/apps/dav/lib/Connector/Sabre/File.php(479): OC_Hook::emit(\\'OC_Filesystem\\', \\'post_write\\', Array) -#20 /var/www/html/apps/dav/lib/Connector/Sabre/File.php(404): OCA\\\\DAV\\\\Connector\\\\Sabre\\\\File->emitPostHooks(false) -#21 /var/www/html/apps/dav/lib/Connector/Sabre/Directory.php(148): OCA\\\\DAV\\\\Connector\\\\Sabre\\\\File->put(Resource id #15) -#22 /var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php(1098): OCA\\\\DAV\\\\Connector\\\\Sabre\\\\Directory->createFile(\\'Screenshot from...\\', Resource id #15) -#23 /var/www/html/3rdparty/sabre/dav/lib/DAV/CorePlugin.php(504): Sabre\\\\DAV\\\\Server->createFile(\\'files/admin/Scr...\\', Resource id #15, NULL) -#24 /var/www/html/3rdparty/sabre/event/lib/WildcardEmitterTrait.php(89): Sabre\\\\DAV\\\\CorePlugin->httpPut(Object(Sabre\\\\HTTP\\\\Request), Object(Sabre\\\\HTTP\\\\Response)) -#25 /var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php(472): Sabre\\\\DAV\\\\Server->emit(\\'method:PUT\\', Array) -#26 /var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php(253): Sabre\\\\DAV\\\\Server->invokeMethod(Object(Sabre\\\\HTTP\\\\Request), Object(Sabre\\\\HTTP\\\\Response)) -#27 /var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php(321): Sabre\\\\DAV\\\\Server->start() -#28 /var/www/html/apps/dav/lib/Server.php(373): Sabre\\\\DAV\\\\Server->exec() -#29 /var/www/html/apps/dav/appinfo/v2/remote.php(35): OCA\\\\DAV\\\\Server->exec() -#30 /var/www/html/remote.php(172): require_once(\\'/var/www/html/a...\\') -#31 {main}' - -writeStream: - -"'#0 /var/www/html/lib/private/Files/Storage/Wrapper/Wrapper.php(653): OCA\\\\GDataVaas\\\\AvirWrapper->writeStream(\\'files/JSON_desc...\\', Resource id #18, NULL) -#1 /var/www/html/apps/dav/lib/Connector/Sabre/File.php(250): OC\\\\Files\\\\Storage\\\\Wrapper\\\\Wrapper->writeStream(\\'files/JSON_desc...\\', Resource id #18) -#2 /var/www/html/apps/dav/lib/Connector/Sabre/Directory.php(148): OCA\\\\DAV\\\\Connector\\\\Sabre\\\\File->put(Resource id #15) -#3 /var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php(1098): OCA\\\\DAV\\\\Connector\\\\Sabre\\\\Directory->createFile(\\'JSON_desc.txt\\', Resource id #15) -#4 /var/www/html/3rdparty/sabre/dav/lib/DAV/CorePlugin.php(504): Sabre\\\\DAV\\\\Server->createFile(\\'files/admin/JSO...\\', Resource id #15, NULL) -#5 /var/www/html/3rdparty/sabre/event/lib/WildcardEmitterTrait.php(89): Sabre\\\\DAV\\\\CorePlugin->httpPut(Object(Sabre\\\\HTTP\\\\Request), Object(Sabre\\\\HTTP\\\\Response)) -#6 /var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php(472): Sabre\\\\DAV\\\\Server->emit(\\'method:PUT\\', Array) -#7 /var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php(253): Sabre\\\\DAV\\\\Server->invokeMethod(Object(Sabre\\\\HTTP\\\\Request), Object(Sabre\\\\HTTP\\\\Response)) -#8 /var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php(321): Sabre\\\\DAV\\\\Server->start() -#9 /var/www/html/apps/dav/lib/Server.php(373): Sabre\\\\DAV\\\\Server->exec() -#10 /var/www/html/apps/dav/appinfo/v2/remote.php(35): OCA\\\\DAV\\\\Server->exec() -#11 /var/www/html/remote.php(172): require_once(\\'/var/www/html/a...\\') -#12 {main}'" \ No newline at end of file