diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 53e037ce..251c7cb5 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -23,11 +23,8 @@ // Use 'postCreateCommand' to run commands after the container is created. "postCreateCommand": "make build && composer install", "features": { - "ghcr.io/devcontainers/features/node:1": { - "nodeGypDependencies": true, - "version": "lts", - "nvmVersion": "latest" - } + "ghcr.io/devcontainers/features/node:1": {}, + "ghcr.io/edouard-lopez/devcontainer-features/bats:0": {} } // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. // "remoteUser": "root" diff --git a/.github/workflows/release-app.yml b/.github/workflows/release-app.yml index 0dac18a3..84deafaa 100644 --- a/.github/workflows/release-app.yml +++ b/.github/workflows/release-app.yml @@ -8,51 +8,50 @@ on: branches: ["main"] jobs: - # test: - # runs-on: ubuntu-latest - # steps: - # - uses: actions/checkout@v4 - # - uses: actions/setup-node@v4 - # name: setup node - # with: - # node-version: 20 - # - name: Setup BATS - # uses: mig4/setup-bats@v1 - # with: - # bats-version: 1.11.0 - # - uses: docker-practice/actions-setup-docker@master - # - name: install nextcloud - # env: - # CLIENT_ID: ${{ secrets.VAAS_CLIENT_ID }} - # CLIENT_SECRET: ${{ secrets.VAAS_CLIENT_SECRET }} - # run: ./install.sh + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + name: setup node + with: + node-version: 20 + + - name: Setup BATS + uses: mig4/setup-bats@v1 + with: + bats-version: 1.11.0 + + - uses: docker-practice/actions-setup-docker@master + - name: install nextcloud + env: + CLIENT_ID: ${{ secrets.VAAS_CLIENT_ID }} + CLIENT_SECRET: ${{ secrets.VAAS_CLIENT_SECRET }} + run: ./install.sh - # - name: run tests - # env: - # CLIENT_ID: ${{ secrets.VAAS_CLIENT_ID }} - # CLIENT_SECRET: ${{ secrets.VAAS_CLIENT_SECRET }} - # run: bats --no-parallelize-across-files --jobs 3 ./tests + - name: run tests + env: + CLIENT_ID: ${{ secrets.VAAS_CLIENT_ID }} + CLIENT_SECRET: ${{ secrets.VAAS_CLIENT_SECRET }} + run: bats --no-parallelize-across-files --jobs 2 ./tests - # - uses: actions/upload-artifact@master - # with: - # name: build-dir - # path: build/ + - uses: actions/upload-artifact@master + with: + name: build-dir + path: build/ release: - # needs: - # - test + needs: + - test runs-on: ubuntu-latest if: startsWith(github.ref, 'refs/tags/') steps: - uses: actions/checkout@v4 - # - uses: actions/download-artifact@master - # with: - # name: build-dir - # path: build/ - - - name: Build for appstore - run: make appstore + - uses: actions/download-artifact@master + with: + name: build-dir + path: build/ - name: replace version id: replace-version diff --git a/.gitignore b/.gitignore index 2b2abba8..437beb64 100644 --- a/.gitignore +++ b/.gitignore @@ -62,3 +62,5 @@ dev-environment*/ js/ *.cache .uuid +eicar.com.txt +tmp/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index cd9babd7..74ae131a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,5 +2,8 @@ "php-cs-fixer.executablePath": "/workspaces/nextcloud-gdata-antivirus/vendor/bin/php-cs-fixer", "php-cs-fixer.onsave": true, "php-cs-fixer.autoFixByBracket": true, - "php-cs-fixer.autoFixBySemicolon": true + "php-cs-fixer.autoFixBySemicolon": true, + "[php]": { + "editor.defaultFormatter": "junstyle.php-cs-fixer" + }, } \ No newline at end of file diff --git a/Makefile b/Makefile index 57792894..647a126f 100644 --- a/Makefile +++ b/Makefile @@ -82,10 +82,18 @@ endif .PHONY: npm npm: ifeq (,$(wildcard $(CURDIR)/package.json)) - npm install +ifeq (,$(wildcard $(CURDIR)/package-lock.json)) + npm install --no-audit --progress=false +else + npm ci +endif cd js && $(npm) run build else - npm install +ifeq (,$(wildcard $(CURDIR)/package-lock.json)) + npm install --no-audit --progress=false +else + npm ci +endif npm run build endif diff --git a/appinfo/info.xml b/appinfo/info.xml index 116b4592..da271bd9 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -35,6 +35,10 @@ If you have any questions about scanning, usage or similar, please feel free to OCA\GDataVaas\Settings\VaasAdminSection OCA\GDataVaas\Settings\VaasAdmin + + OCA\GDataVaas\Command\ScanCommand + OCA\GDataVaas\Command\TagUnscannedCommand + diff --git a/composer.json b/composer.json index a4d5e279..9ffd3b09 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,8 @@ "require-dev": { "nextcloud/ocp": "dev-stable28", "psalm/phar": "^5.17.0", - "nextcloud/coding-standard": "^v1.1.1" + "nextcloud/coding-standard": "^v1.1.1", + "symfony/console": "^6.4" }, "scripts": { "lint": "find lib -name \\*.php -not -path './vendor/*' -print0 | xargs -0 -n1 php -l", diff --git a/foobar.json b/foobar.json new file mode 100644 index 00000000..e6d24064 --- /dev/null +++ b/foobar.json @@ -0,0 +1,1266 @@ +{ + "reqId": "0TSnmtl1Nt4QzQ4GjMpx", + "level": 3, + "time": "2024-06-12T09:06:27+00:00", + "remoteAddr": "172.26.0.1", + "user": "admin", + "app": "webdav", + "method": "PUT", + "url": "/remote.php/dav/files/admin/functionality-parallel.eicar.com.txt", + "message": "An exception occurred while executing a query: SQLSTATE[23000]: Integrity constraint violation: 19 UNIQUE constraint failed: oc_accounts.uid", + "userAgent": "curl/7.84.0", + "version": "28.0.6.1", + "exception": { + "Exception": "OC\\DB\\Exceptions\\DbalException", + "Message": "An exception occurred while executing a query: SQLSTATE[23000]: Integrity constraint violation: 19 UNIQUE constraint failed: oc_accounts.uid", + "Code": 19, + "Trace": [ + { + "file": "/var/www/html/lib/private/DB/QueryBuilder/QueryBuilder.php", + "line": 328, + "function": "wrap", + "class": "OC\\DB\\Exceptions\\DbalException", + "type": "::", + "args": [ + [ + "Doctrine\\DBAL\\Exception\\UniqueConstraintViolationException" + ] + ] + }, + { + "file": "/var/www/html/lib/private/Accounts/AccountManager.php", + "line": 510, + "function": "executeStatement", + "class": "OC\\DB\\QueryBuilder\\QueryBuilder", + "type": "->", + "args": [] + }, + { + "file": "/var/www/html/lib/private/Accounts/AccountManager.php", + "line": 304, + "function": "insertNewUser", + "class": "OC\\Accounts\\AccountManager", + "type": "->", + "args": [ + [ + "OC\\User\\User" + ], + [ + [ + "displayname", + "admin", + "v2-federated", + "0" + ], + [ + "address", + "", + "v2-local", + "0" + ], + [ + "website", + "", + "v2-local", + "0" + ], + [ + "email", + null, + "v2-federated", + "0" + ], + [ + "avatar", + "v2-federated" + ], + [ + "phone", + "", + "v2-local", + "0" + ], + [ + "twitter", + "", + "v2-local", + "0" + ], + [ + "fediverse", + "", + "v2-local", + "0" + ], + [ + "organisation", + "", + "v2-local" + ], + [ + "role", + "", + "v2-local" + ], + [ + "headline", + "", + "v2-local" + ], + [ + "biography", + "", + "v2-local" + ], + [ + "profile_enabled", + "1" + ] + ] + ] + }, + { + "file": "/var/www/html/lib/private/Accounts/AccountManager.php", + "line": 742, + "function": "getUser", + "class": "OC\\Accounts\\AccountManager", + "type": "->", + "args": [ + [ + "OC\\User\\User" + ] + ] + }, + { + "file": "/var/www/html/apps/dav/lib/Connector/Sabre/Principal.php", + "line": 534, + "function": "getAccount", + "class": "OC\\Accounts\\AccountManager", + "type": "->", + "args": [ + [ + "OC\\User\\User" + ] + ] + }, + { + "file": "/var/www/html/apps/dav/lib/Connector/Sabre/Principal.php", + "line": 191, + "function": "userToPrincipal", + "class": "OCA\\DAV\\Connector\\Sabre\\Principal", + "type": "->", + "args": [ + [ + "OC\\User\\User" + ] + ] + }, + { + "file": "/var/www/html/3rdparty/sabre/dav/lib/DAVACL/AbstractPrincipalCollection.php", + "line": 114, + "function": "getPrincipalByPath", + "class": "OCA\\DAV\\Connector\\Sabre\\Principal", + "type": "->", + "args": [ + "principals/users/admin" + ] + }, + { + "file": "/var/www/html/3rdparty/sabre/dav/lib/DAV/Tree.php", + "line": 95, + "function": "getChild", + "class": "Sabre\\DAVACL\\AbstractPrincipalCollection", + "type": "->", + "args": [ + "admin" + ] + }, + { + "file": "/var/www/html/apps/dav/lib/Connector/Sabre/LockPlugin.php", + "line": 68, + "function": "getNodeForPath", + "class": "Sabre\\DAV\\Tree", + "type": "->", + "args": [ + "files/admin/functionality-parallel.eicar.com.txt" + ] + }, + { + "file": "/var/www/html/3rdparty/sabre/event/lib/WildcardEmitterTrait.php", + "line": 89, + "function": "getLock", + "class": "OCA\\DAV\\Connector\\Sabre\\LockPlugin", + "type": "->", + "args": [ + [ + "Sabre\\HTTP\\Request" + ], + [ + "Sabre\\HTTP\\Response" + ] + ] + }, + { + "file": "/var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php", + "line": 456, + "function": "emit", + "class": "Sabre\\DAV\\Server", + "type": "->", + "args": [ + "beforeMethod:PUT", + [ + [ + "Sabre\\HTTP\\Request" + ], + [ + "Sabre\\HTTP\\Response" + ] + ] + ] + }, + { + "file": "/var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php", + "line": 253, + "function": "invokeMethod", + "class": "Sabre\\DAV\\Server", + "type": "->", + "args": [ + [ + "Sabre\\HTTP\\Request" + ], + [ + "Sabre\\HTTP\\Response" + ] + ] + }, + { + "file": "/var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php", + "line": 321, + "function": "start", + "class": "Sabre\\DAV\\Server", + "type": "->", + "args": [] + }, + { + "file": "/var/www/html/apps/dav/lib/Server.php", + "line": 373, + "function": "exec", + "class": "Sabre\\DAV\\Server", + "type": "->", + "args": [] + }, + { + "file": "/var/www/html/apps/dav/appinfo/v2/remote.php", + "line": 35, + "function": "exec", + "class": "OCA\\DAV\\Server", + "type": "->", + "args": [] + }, + { + "file": "/var/www/html/remote.php", + "line": 172, + "args": [ + "/var/www/html/apps/dav/appinfo/v2/remote.php" + ], + "function": "require_once" + } + ], + "File": "/var/www/html/lib/private/DB/Exceptions/DbalException.php", + "Line": 71, + "Previous": { + "Exception": "Doctrine\\DBAL\\Exception\\UniqueConstraintViolationException", + "Message": "An exception occurred while executing a query: SQLSTATE[23000]: Integrity constraint violation: 19 UNIQUE constraint failed: oc_accounts.uid", + "Code": 19, + "Trace": [ + { + "file": "/var/www/html/3rdparty/doctrine/dbal/src/Connection.php", + "line": 1938, + "function": "convert", + "class": "Doctrine\\DBAL\\Driver\\API\\SQLite\\ExceptionConverter", + "type": "->", + "args": [ + [ + "Doctrine\\DBAL\\Driver\\PDO\\Exception" + ], + [ + "Doctrine\\DBAL\\Query" + ] + ] + }, + { + "file": "/var/www/html/3rdparty/doctrine/dbal/src/Connection.php", + "line": 1880, + "function": "handleDriverException", + "class": "Doctrine\\DBAL\\Connection", + "type": "->", + "args": [ + [ + "Doctrine\\DBAL\\Driver\\PDO\\Exception" + ], + [ + "Doctrine\\DBAL\\Query" + ] + ] + }, + { + "file": "/var/www/html/3rdparty/doctrine/dbal/src/Connection.php", + "line": 1208, + "function": "convertExceptionDuringQuery", + "class": "Doctrine\\DBAL\\Connection", + "type": "->", + "args": [ + [ + "Doctrine\\DBAL\\Driver\\PDO\\Exception" + ], + "INSERT INTO \"oc_accounts\" (\"uid\", \"data\") VALUES(?, ?)", + [ + "admin", + "{\"displayname\":{\"value\":\"admin\",\"scope\":\"v2-federated\",\"verified\":\"0\"},\"address\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"website\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"email\":{\"value\":null,\"scope\":\"v2-federated\",\"verified\":\"0\"},\"avatar\":{\"scope\":\"v2-federated\"},\"phone\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"twitter\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"fediverse\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"organisation\":{\"value\":\"\",\"scope\":\"v2-local\"},\"role\":{\"value\":\"\",\"scope\":\"v2-local\"},\"headline\":{\"value\":\"\",\"scope\":\"v2-local\"},\"biography\":{\"value\":\"\",\"scope\":\"v2-local\"},\"profile_enabled\":{\"value\":\"1\"}}" + ], + [ + 2, + 2 + ] + ] + }, + { + "file": "/var/www/html/lib/private/DB/Connection.php", + "line": 294, + "function": "executeStatement", + "class": "Doctrine\\DBAL\\Connection", + "type": "->", + "args": [ + "INSERT INTO \"oc_accounts\" (\"uid\", \"data\") VALUES(?, ?)", + [ + "admin", + "{\"displayname\":{\"value\":\"admin\",\"scope\":\"v2-federated\",\"verified\":\"0\"},\"address\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"website\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"email\":{\"value\":null,\"scope\":\"v2-federated\",\"verified\":\"0\"},\"avatar\":{\"scope\":\"v2-federated\"},\"phone\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"twitter\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"fediverse\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"organisation\":{\"value\":\"\",\"scope\":\"v2-local\"},\"role\":{\"value\":\"\",\"scope\":\"v2-local\"},\"headline\":{\"value\":\"\",\"scope\":\"v2-local\"},\"biography\":{\"value\":\"\",\"scope\":\"v2-local\"},\"profile_enabled\":{\"value\":\"1\"}}" + ], + [ + 2, + 2 + ] + ] + }, + { + "file": "/var/www/html/3rdparty/doctrine/dbal/src/Query/QueryBuilder.php", + "line": 386, + "function": "executeStatement", + "class": "OC\\DB\\Connection", + "type": "->", + "args": [ + "INSERT INTO \"oc_accounts\" (\"uid\", \"data\") VALUES(:dcValue1, :dcValue2)", + [ + "admin", + "{\"displayname\":{\"value\":\"admin\",\"scope\":\"v2-federated\",\"verified\":\"0\"},\"address\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"website\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"email\":{\"value\":null,\"scope\":\"v2-federated\",\"verified\":\"0\"},\"avatar\":{\"scope\":\"v2-federated\"},\"phone\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"twitter\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"fediverse\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"organisation\":{\"value\":\"\",\"scope\":\"v2-local\"},\"role\":{\"value\":\"\",\"scope\":\"v2-local\"},\"headline\":{\"value\":\"\",\"scope\":\"v2-local\"},\"biography\":{\"value\":\"\",\"scope\":\"v2-local\"},\"profile_enabled\":{\"value\":\"1\"}}" + ], + [ + 2, + 2 + ] + ] + }, + { + "file": "/var/www/html/lib/private/DB/QueryBuilder/QueryBuilder.php", + "line": 280, + "function": "execute", + "class": "Doctrine\\DBAL\\Query\\QueryBuilder", + "type": "->", + "args": [] + }, + { + "file": "/var/www/html/lib/private/DB/QueryBuilder/QueryBuilder.php", + "line": 326, + "function": "execute", + "class": "OC\\DB\\QueryBuilder\\QueryBuilder", + "type": "->", + "args": [] + }, + { + "file": "/var/www/html/lib/private/Accounts/AccountManager.php", + "line": 510, + "function": "executeStatement", + "class": "OC\\DB\\QueryBuilder\\QueryBuilder", + "type": "->", + "args": [] + }, + { + "file": "/var/www/html/lib/private/Accounts/AccountManager.php", + "line": 304, + "function": "insertNewUser", + "class": "OC\\Accounts\\AccountManager", + "type": "->", + "args": [ + [ + "OC\\User\\User" + ], + [ + [ + "displayname", + "admin", + "v2-federated", + "0" + ], + [ + "address", + "", + "v2-local", + "0" + ], + [ + "website", + "", + "v2-local", + "0" + ], + [ + "email", + null, + "v2-federated", + "0" + ], + [ + "avatar", + "v2-federated" + ], + [ + "phone", + "", + "v2-local", + "0" + ], + [ + "twitter", + "", + "v2-local", + "0" + ], + [ + "fediverse", + "", + "v2-local", + "0" + ], + [ + "organisation", + "", + "v2-local" + ], + [ + "role", + "", + "v2-local" + ], + [ + "headline", + "", + "v2-local" + ], + [ + "biography", + "", + "v2-local" + ], + [ + "profile_enabled", + "1" + ] + ] + ] + }, + { + "file": "/var/www/html/lib/private/Accounts/AccountManager.php", + "line": 742, + "function": "getUser", + "class": "OC\\Accounts\\AccountManager", + "type": "->", + "args": [ + [ + "OC\\User\\User" + ] + ] + }, + { + "file": "/var/www/html/apps/dav/lib/Connector/Sabre/Principal.php", + "line": 534, + "function": "getAccount", + "class": "OC\\Accounts\\AccountManager", + "type": "->", + "args": [ + [ + "OC\\User\\User" + ] + ] + }, + { + "file": "/var/www/html/apps/dav/lib/Connector/Sabre/Principal.php", + "line": 191, + "function": "userToPrincipal", + "class": "OCA\\DAV\\Connector\\Sabre\\Principal", + "type": "->", + "args": [ + [ + "OC\\User\\User" + ] + ] + }, + { + "file": "/var/www/html/3rdparty/sabre/dav/lib/DAVACL/AbstractPrincipalCollection.php", + "line": 114, + "function": "getPrincipalByPath", + "class": "OCA\\DAV\\Connector\\Sabre\\Principal", + "type": "->", + "args": [ + "principals/users/admin" + ] + }, + { + "file": "/var/www/html/3rdparty/sabre/dav/lib/DAV/Tree.php", + "line": 95, + "function": "getChild", + "class": "Sabre\\DAVACL\\AbstractPrincipalCollection", + "type": "->", + "args": [ + "admin" + ] + }, + { + "file": "/var/www/html/apps/dav/lib/Connector/Sabre/LockPlugin.php", + "line": 68, + "function": "getNodeForPath", + "class": "Sabre\\DAV\\Tree", + "type": "->", + "args": [ + "files/admin/functionality-parallel.eicar.com.txt" + ] + }, + { + "file": "/var/www/html/3rdparty/sabre/event/lib/WildcardEmitterTrait.php", + "line": 89, + "function": "getLock", + "class": "OCA\\DAV\\Connector\\Sabre\\LockPlugin", + "type": "->", + "args": [ + [ + "Sabre\\HTTP\\Request" + ], + [ + "Sabre\\HTTP\\Response" + ] + ] + }, + { + "file": "/var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php", + "line": 456, + "function": "emit", + "class": "Sabre\\DAV\\Server", + "type": "->", + "args": [ + "beforeMethod:PUT", + [ + [ + "Sabre\\HTTP\\Request" + ], + [ + "Sabre\\HTTP\\Response" + ] + ] + ] + }, + { + "file": "/var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php", + "line": 253, + "function": "invokeMethod", + "class": "Sabre\\DAV\\Server", + "type": "->", + "args": [ + [ + "Sabre\\HTTP\\Request" + ], + [ + "Sabre\\HTTP\\Response" + ] + ] + }, + { + "file": "/var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php", + "line": 321, + "function": "start", + "class": "Sabre\\DAV\\Server", + "type": "->", + "args": [] + }, + { + "file": "/var/www/html/apps/dav/lib/Server.php", + "line": 373, + "function": "exec", + "class": "Sabre\\DAV\\Server", + "type": "->", + "args": [] + }, + { + "file": "/var/www/html/apps/dav/appinfo/v2/remote.php", + "line": 35, + "function": "exec", + "class": "OCA\\DAV\\Server", + "type": "->", + "args": [] + }, + { + "file": "/var/www/html/remote.php", + "line": 172, + "args": [ + "/var/www/html/apps/dav/appinfo/v2/remote.php" + ], + "function": "require_once" + } + ], + "File": "/var/www/html/3rdparty/doctrine/dbal/src/Driver/API/SQLite/ExceptionConverter.php", + "Line": 41, + "Previous": { + "Exception": "Doctrine\\DBAL\\Driver\\PDO\\Exception", + "Message": "SQLSTATE[23000]: Integrity constraint violation: 19 UNIQUE constraint failed: oc_accounts.uid", + "Code": 19, + "Trace": [ + { + "file": "/var/www/html/3rdparty/doctrine/dbal/src/Driver/PDO/Statement.php", + "line": 132, + "function": "new", + "class": "Doctrine\\DBAL\\Driver\\PDO\\Exception", + "type": "::", + "args": [ + [ + "PDOException", + [ + "23000", + 19, + "UNIQUE constraint failed: oc_accounts.uid" + ] + ] + ] + }, + { + "file": "/var/www/html/3rdparty/doctrine/dbal/src/Connection.php", + "line": 1202, + "function": "execute", + "class": "Doctrine\\DBAL\\Driver\\PDO\\Statement", + "type": "->", + "args": [] + }, + { + "file": "/var/www/html/lib/private/DB/Connection.php", + "line": 294, + "function": "executeStatement", + "class": "Doctrine\\DBAL\\Connection", + "type": "->", + "args": [ + "INSERT INTO \"oc_accounts\" (\"uid\", \"data\") VALUES(?, ?)", + [ + "admin", + "{\"displayname\":{\"value\":\"admin\",\"scope\":\"v2-federated\",\"verified\":\"0\"},\"address\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"website\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"email\":{\"value\":null,\"scope\":\"v2-federated\",\"verified\":\"0\"},\"avatar\":{\"scope\":\"v2-federated\"},\"phone\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"twitter\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"fediverse\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"organisation\":{\"value\":\"\",\"scope\":\"v2-local\"},\"role\":{\"value\":\"\",\"scope\":\"v2-local\"},\"headline\":{\"value\":\"\",\"scope\":\"v2-local\"},\"biography\":{\"value\":\"\",\"scope\":\"v2-local\"},\"profile_enabled\":{\"value\":\"1\"}}" + ], + [ + 2, + 2 + ] + ] + }, + { + "file": "/var/www/html/3rdparty/doctrine/dbal/src/Query/QueryBuilder.php", + "line": 386, + "function": "executeStatement", + "class": "OC\\DB\\Connection", + "type": "->", + "args": [ + "INSERT INTO \"oc_accounts\" (\"uid\", \"data\") VALUES(:dcValue1, :dcValue2)", + [ + "admin", + "{\"displayname\":{\"value\":\"admin\",\"scope\":\"v2-federated\",\"verified\":\"0\"},\"address\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"website\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"email\":{\"value\":null,\"scope\":\"v2-federated\",\"verified\":\"0\"},\"avatar\":{\"scope\":\"v2-federated\"},\"phone\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"twitter\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"fediverse\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"organisation\":{\"value\":\"\",\"scope\":\"v2-local\"},\"role\":{\"value\":\"\",\"scope\":\"v2-local\"},\"headline\":{\"value\":\"\",\"scope\":\"v2-local\"},\"biography\":{\"value\":\"\",\"scope\":\"v2-local\"},\"profile_enabled\":{\"value\":\"1\"}}" + ], + [ + 2, + 2 + ] + ] + }, + { + "file": "/var/www/html/lib/private/DB/QueryBuilder/QueryBuilder.php", + "line": 280, + "function": "execute", + "class": "Doctrine\\DBAL\\Query\\QueryBuilder", + "type": "->", + "args": [] + }, + { + "file": "/var/www/html/lib/private/DB/QueryBuilder/QueryBuilder.php", + "line": 326, + "function": "execute", + "class": "OC\\DB\\QueryBuilder\\QueryBuilder", + "type": "->", + "args": [] + }, + { + "file": "/var/www/html/lib/private/Accounts/AccountManager.php", + "line": 510, + "function": "executeStatement", + "class": "OC\\DB\\QueryBuilder\\QueryBuilder", + "type": "->", + "args": [] + }, + { + "file": "/var/www/html/lib/private/Accounts/AccountManager.php", + "line": 304, + "function": "insertNewUser", + "class": "OC\\Accounts\\AccountManager", + "type": "->", + "args": [ + [ + "OC\\User\\User" + ], + [ + [ + "displayname", + "admin", + "v2-federated", + "0" + ], + [ + "address", + "", + "v2-local", + "0" + ], + [ + "website", + "", + "v2-local", + "0" + ], + [ + "email", + null, + "v2-federated", + "0" + ], + [ + "avatar", + "v2-federated" + ], + [ + "phone", + "", + "v2-local", + "0" + ], + [ + "twitter", + "", + "v2-local", + "0" + ], + [ + "fediverse", + "", + "v2-local", + "0" + ], + [ + "organisation", + "", + "v2-local" + ], + [ + "role", + "", + "v2-local" + ], + [ + "headline", + "", + "v2-local" + ], + [ + "biography", + "", + "v2-local" + ], + [ + "profile_enabled", + "1" + ] + ] + ] + }, + { + "file": "/var/www/html/lib/private/Accounts/AccountManager.php", + "line": 742, + "function": "getUser", + "class": "OC\\Accounts\\AccountManager", + "type": "->", + "args": [ + [ + "OC\\User\\User" + ] + ] + }, + { + "file": "/var/www/html/apps/dav/lib/Connector/Sabre/Principal.php", + "line": 534, + "function": "getAccount", + "class": "OC\\Accounts\\AccountManager", + "type": "->", + "args": [ + [ + "OC\\User\\User" + ] + ] + }, + { + "file": "/var/www/html/apps/dav/lib/Connector/Sabre/Principal.php", + "line": 191, + "function": "userToPrincipal", + "class": "OCA\\DAV\\Connector\\Sabre\\Principal", + "type": "->", + "args": [ + [ + "OC\\User\\User" + ] + ] + }, + { + "file": "/var/www/html/3rdparty/sabre/dav/lib/DAVACL/AbstractPrincipalCollection.php", + "line": 114, + "function": "getPrincipalByPath", + "class": "OCA\\DAV\\Connector\\Sabre\\Principal", + "type": "->", + "args": [ + "principals/users/admin" + ] + }, + { + "file": "/var/www/html/3rdparty/sabre/dav/lib/DAV/Tree.php", + "line": 95, + "function": "getChild", + "class": "Sabre\\DAVACL\\AbstractPrincipalCollection", + "type": "->", + "args": [ + "admin" + ] + }, + { + "file": "/var/www/html/apps/dav/lib/Connector/Sabre/LockPlugin.php", + "line": 68, + "function": "getNodeForPath", + "class": "Sabre\\DAV\\Tree", + "type": "->", + "args": [ + "files/admin/functionality-parallel.eicar.com.txt" + ] + }, + { + "file": "/var/www/html/3rdparty/sabre/event/lib/WildcardEmitterTrait.php", + "line": 89, + "function": "getLock", + "class": "OCA\\DAV\\Connector\\Sabre\\LockPlugin", + "type": "->", + "args": [ + [ + "Sabre\\HTTP\\Request" + ], + [ + "Sabre\\HTTP\\Response" + ] + ] + }, + { + "file": "/var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php", + "line": 456, + "function": "emit", + "class": "Sabre\\DAV\\Server", + "type": "->", + "args": [ + "beforeMethod:PUT", + [ + [ + "Sabre\\HTTP\\Request" + ], + [ + "Sabre\\HTTP\\Response" + ] + ] + ] + }, + { + "file": "/var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php", + "line": 253, + "function": "invokeMethod", + "class": "Sabre\\DAV\\Server", + "type": "->", + "args": [ + [ + "Sabre\\HTTP\\Request" + ], + [ + "Sabre\\HTTP\\Response" + ] + ] + }, + { + "file": "/var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php", + "line": 321, + "function": "start", + "class": "Sabre\\DAV\\Server", + "type": "->", + "args": [] + }, + { + "file": "/var/www/html/apps/dav/lib/Server.php", + "line": 373, + "function": "exec", + "class": "Sabre\\DAV\\Server", + "type": "->", + "args": [] + }, + { + "file": "/var/www/html/apps/dav/appinfo/v2/remote.php", + "line": 35, + "function": "exec", + "class": "OCA\\DAV\\Server", + "type": "->", + "args": [] + }, + { + "file": "/var/www/html/remote.php", + "line": 172, + "args": [ + "/var/www/html/apps/dav/appinfo/v2/remote.php" + ], + "function": "require_once" + } + ], + "File": "/var/www/html/3rdparty/doctrine/dbal/src/Driver/PDO/Exception.php", + "Line": 28, + "Previous": { + "Exception": "PDOException", + "Message": "SQLSTATE[23000]: Integrity constraint violation: 19 UNIQUE constraint failed: oc_accounts.uid", + "Code": "23000", + "Trace": [ + { + "file": "/var/www/html/3rdparty/doctrine/dbal/src/Driver/PDO/Statement.php", + "line": 130, + "function": "execute", + "class": "PDOStatement", + "type": "->", + "args": [ + null + ] + }, + { + "file": "/var/www/html/3rdparty/doctrine/dbal/src/Connection.php", + "line": 1202, + "function": "execute", + "class": "Doctrine\\DBAL\\Driver\\PDO\\Statement", + "type": "->", + "args": [] + }, + { + "file": "/var/www/html/lib/private/DB/Connection.php", + "line": 294, + "function": "executeStatement", + "class": "Doctrine\\DBAL\\Connection", + "type": "->", + "args": [ + "INSERT INTO \"oc_accounts\" (\"uid\", \"data\") VALUES(?, ?)", + [ + "admin", + "{\"displayname\":{\"value\":\"admin\",\"scope\":\"v2-federated\",\"verified\":\"0\"},\"address\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"website\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"email\":{\"value\":null,\"scope\":\"v2-federated\",\"verified\":\"0\"},\"avatar\":{\"scope\":\"v2-federated\"},\"phone\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"twitter\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"fediverse\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"organisation\":{\"value\":\"\",\"scope\":\"v2-local\"},\"role\":{\"value\":\"\",\"scope\":\"v2-local\"},\"headline\":{\"value\":\"\",\"scope\":\"v2-local\"},\"biography\":{\"value\":\"\",\"scope\":\"v2-local\"},\"profile_enabled\":{\"value\":\"1\"}}" + ], + [ + 2, + 2 + ] + ] + }, + { + "file": "/var/www/html/3rdparty/doctrine/dbal/src/Query/QueryBuilder.php", + "line": 386, + "function": "executeStatement", + "class": "OC\\DB\\Connection", + "type": "->", + "args": [ + "INSERT INTO \"oc_accounts\" (\"uid\", \"data\") VALUES(:dcValue1, :dcValue2)", + [ + "admin", + "{\"displayname\":{\"value\":\"admin\",\"scope\":\"v2-federated\",\"verified\":\"0\"},\"address\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"website\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"email\":{\"value\":null,\"scope\":\"v2-federated\",\"verified\":\"0\"},\"avatar\":{\"scope\":\"v2-federated\"},\"phone\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"twitter\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"fediverse\":{\"value\":\"\",\"scope\":\"v2-local\",\"verified\":\"0\"},\"organisation\":{\"value\":\"\",\"scope\":\"v2-local\"},\"role\":{\"value\":\"\",\"scope\":\"v2-local\"},\"headline\":{\"value\":\"\",\"scope\":\"v2-local\"},\"biography\":{\"value\":\"\",\"scope\":\"v2-local\"},\"profile_enabled\":{\"value\":\"1\"}}" + ], + [ + 2, + 2 + ] + ] + }, + { + "file": "/var/www/html/lib/private/DB/QueryBuilder/QueryBuilder.php", + "line": 280, + "function": "execute", + "class": "Doctrine\\DBAL\\Query\\QueryBuilder", + "type": "->", + "args": [] + }, + { + "file": "/var/www/html/lib/private/DB/QueryBuilder/QueryBuilder.php", + "line": 326, + "function": "execute", + "class": "OC\\DB\\QueryBuilder\\QueryBuilder", + "type": "->", + "args": [] + }, + { + "file": "/var/www/html/lib/private/Accounts/AccountManager.php", + "line": 510, + "function": "executeStatement", + "class": "OC\\DB\\QueryBuilder\\QueryBuilder", + "type": "->", + "args": [] + }, + { + "file": "/var/www/html/lib/private/Accounts/AccountManager.php", + "line": 304, + "function": "insertNewUser", + "class": "OC\\Accounts\\AccountManager", + "type": "->", + "args": [ + [ + "OC\\User\\User" + ], + [ + [ + "displayname", + "admin", + "v2-federated", + "0" + ], + [ + "address", + "", + "v2-local", + "0" + ], + [ + "website", + "", + "v2-local", + "0" + ], + [ + "email", + null, + "v2-federated", + "0" + ], + [ + "avatar", + "v2-federated" + ], + [ + "phone", + "", + "v2-local", + "0" + ], + [ + "twitter", + "", + "v2-local", + "0" + ], + [ + "fediverse", + "", + "v2-local", + "0" + ], + [ + "organisation", + "", + "v2-local" + ], + [ + "role", + "", + "v2-local" + ], + [ + "headline", + "", + "v2-local" + ], + [ + "biography", + "", + "v2-local" + ], + [ + "profile_enabled", + "1" + ] + ] + ] + }, + { + "file": "/var/www/html/lib/private/Accounts/AccountManager.php", + "line": 742, + "function": "getUser", + "class": "OC\\Accounts\\AccountManager", + "type": "->", + "args": [ + [ + "OC\\User\\User" + ] + ] + }, + { + "file": "/var/www/html/apps/dav/lib/Connector/Sabre/Principal.php", + "line": 534, + "function": "getAccount", + "class": "OC\\Accounts\\AccountManager", + "type": "->", + "args": [ + [ + "OC\\User\\User" + ] + ] + }, + { + "file": "/var/www/html/apps/dav/lib/Connector/Sabre/Principal.php", + "line": 191, + "function": "userToPrincipal", + "class": "OCA\\DAV\\Connector\\Sabre\\Principal", + "type": "->", + "args": [ + [ + "OC\\User\\User" + ] + ] + }, + { + "file": "/var/www/html/3rdparty/sabre/dav/lib/DAVACL/AbstractPrincipalCollection.php", + "line": 114, + "function": "getPrincipalByPath", + "class": "OCA\\DAV\\Connector\\Sabre\\Principal", + "type": "->", + "args": [ + "principals/users/admin" + ] + }, + { + "file": "/var/www/html/3rdparty/sabre/dav/lib/DAV/Tree.php", + "line": 95, + "function": "getChild", + "class": "Sabre\\DAVACL\\AbstractPrincipalCollection", + "type": "->", + "args": [ + "admin" + ] + }, + { + "file": "/var/www/html/apps/dav/lib/Connector/Sabre/LockPlugin.php", + "line": 68, + "function": "getNodeForPath", + "class": "Sabre\\DAV\\Tree", + "type": "->", + "args": [ + "files/admin/functionality-parallel.eicar.com.txt" + ] + }, + { + "file": "/var/www/html/3rdparty/sabre/event/lib/WildcardEmitterTrait.php", + "line": 89, + "function": "getLock", + "class": "OCA\\DAV\\Connector\\Sabre\\LockPlugin", + "type": "->", + "args": [ + [ + "Sabre\\HTTP\\Request" + ], + [ + "Sabre\\HTTP\\Response" + ] + ] + }, + { + "file": "/var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php", + "line": 456, + "function": "emit", + "class": "Sabre\\DAV\\Server", + "type": "->", + "args": [ + "beforeMethod:PUT", + [ + [ + "Sabre\\HTTP\\Request" + ], + [ + "Sabre\\HTTP\\Response" + ] + ] + ] + }, + { + "file": "/var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php", + "line": 253, + "function": "invokeMethod", + "class": "Sabre\\DAV\\Server", + "type": "->", + "args": [ + [ + "Sabre\\HTTP\\Request" + ], + [ + "Sabre\\HTTP\\Response" + ] + ] + }, + { + "file": "/var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php", + "line": 321, + "function": "start", + "class": "Sabre\\DAV\\Server", + "type": "->", + "args": [] + }, + { + "file": "/var/www/html/apps/dav/lib/Server.php", + "line": 373, + "function": "exec", + "class": "Sabre\\DAV\\Server", + "type": "->", + "args": [] + }, + { + "file": "/var/www/html/apps/dav/appinfo/v2/remote.php", + "line": 35, + "function": "exec", + "class": "OCA\\DAV\\Server", + "type": "->", + "args": [] + }, + { + "file": "/var/www/html/remote.php", + "line": 172, + "args": [ + "/var/www/html/apps/dav/appinfo/v2/remote.php" + ], + "function": "require_once" + } + ], + "File": "/var/www/html/3rdparty/doctrine/dbal/src/Driver/PDO/Statement.php", + "Line": 130 + } + } + }, + "message": "An exception occurred while executing a query: SQLSTATE[23000]: Integrity constraint violation: 19 UNIQUE constraint failed: oc_accounts.uid", + "exception": {}, + "CustomMessage": "An exception occurred while executing a query: SQLSTATE[23000]: Integrity constraint violation: 19 UNIQUE constraint failed: oc_accounts.uid" + } +} \ No newline at end of file diff --git a/install.sh b/install.sh index 7fcff8fe..3eb24ba3 100755 --- a/install.sh +++ b/install.sh @@ -2,42 +2,52 @@ source .env-local || echo "No .env-local file found." +setup_nextcloud () { + echo "setup nextcloud" + docker stop nextcloud-container || echo "No container to stop" + sleep 1 + docker run -d --name nextcloud-container --rm --publish 80:80 nextcloud:28 + + until docker exec --user www-data -i nextcloud-container php occ maintenance:install --admin-user=admin --admin-pass=admin | grep "Nextcloud was successfully installed" + do + echo "Trying installation" + sleep 2 + done + echo "setup nextcloud finished" +} + +build_app () { + echo "build app" + make appstore + tar -xf ./build/artifacts/gdatavaas.tar.gz -C ./build/artifacts + echo "build app finished" +} + if [ -z "$CLIENT_ID" ] || [ -z "$CLIENT_SECRET" ]; then echo "Please set CLIENT_ID and CLIENT_SECRET" exit 1 fi -docker stop nextcloud-container || echo "No container to stop" -sleep 1 -docker run -d --name nextcloud-container --rm --publish 80:80 nextcloud:28 - -until docker exec --user www-data -it nextcloud-container php occ maintenance:install --admin-user=admin --admin-pass=admin >/dev/null -do - echo "Trying installation" - sleep 2 -done +setup_nextcloud & +build_app & +wait -make appstore -tar -xf ./build/artifacts/gdatavaas.tar.gz -C ./build/artifacts docker cp ./build/artifacts/gdatavaas nextcloud-container:/var/www/html/apps/ -docker exec -it nextcloud-container chown -R www-data:www-data /var/www/html/apps/gdatavaas +docker exec -i nextcloud-container chown -R www-data:www-data /var/www/html/apps/gdatavaas -until docker exec --user www-data -it nextcloud-container php occ app:update --all +until docker exec --user www-data -i nextcloud-container php occ app:enable gdatavaas do - echo "Trying app update" + echo "Trying app enable" sleep 2 done -docker exec --user www-data -it nextcloud-container php occ app:enable gdatavaas - -docker exec --user www-data -it nextcloud-container php occ config:app:set gdatavaas clientId --value="$CLIENT_ID" -docker exec --user www-data -it nextcloud-container php occ config:app:set gdatavaas clientSecret --value="$CLIENT_SECRET" -docker exec --user www-data -it nextcloud-container php occ config:app:set gdatavaas authMethod --value=ClientCredentials -docker exec --user www-data -it nextcloud-container php occ config:app:set gdatavaas autoScanFiles --value=true -docker exec --user www-data -it nextcloud-container php occ config:app:set gdatavaas scanQueueLength --value=100 +docker exec --user www-data -i nextcloud-container php occ config:app:set gdatavaas clientId --value="$CLIENT_ID" +docker exec --user www-data -i nextcloud-container php occ config:app:set gdatavaas clientSecret --value="$CLIENT_SECRET" +docker exec --user www-data -i nextcloud-container php occ config:app:set gdatavaas authMethod --value=ClientCredentials +docker exec --user www-data -i nextcloud-container php occ config:app:set gdatavaas autoScanFiles --value=true +docker exec --user www-data -i nextcloud-container php occ config:app:set gdatavaas scanQueueLength --value=100 -docker exec --user www-data -it nextcloud-container php occ log:manage --level DEBUG -docker exec --user www-data -it nextcloud-container php occ app:disable firstrunwizard +docker exec --user www-data -i nextcloud-container php occ log:manage --level DEBUG +docker exec --user www-data -i nextcloud-container php occ app:disable firstrunwizard source install.local || echo "No additional install script found." -# docker exec --user www-data -it nextcloud-container php cron.php diff --git a/lib/BackgroundJobs/ScanJob.php b/lib/BackgroundJobs/ScanJob.php index b87317a4..8f06f4bb 100644 --- a/lib/BackgroundJobs/ScanJob.php +++ b/lib/BackgroundJobs/ScanJob.php @@ -2,7 +2,8 @@ namespace OCA\GDataVaas\BackgroundJobs; -use Exception; +use OCA\GDataVaas\AppInfo\Application; +use OCA\GDataVaas\Service\ScanService; use OCA\GDataVaas\Service\TagService; use OCA\GDataVaas\Service\VerdictService; use OCP\AppFramework\Utility\ITimeFactory; @@ -11,20 +12,12 @@ use Psr\Log\LoggerInterface; class ScanJob extends TimedJob { - private const APP_ID = "gdatavaas"; - - private TagService $tagService; - private VerdictService $scanService; - private IConfig $appConfig; - private LoggerInterface $logger; + private ScanService $scanService; public function __construct(LoggerInterface $logger, ITimeFactory $time, TagService $tagService, VerdictService $scanService, IConfig $appConfig) { parent::__construct($time); - $this->logger = $logger; - $this->tagService = $tagService; - $this->scanService = $scanService; - $this->appConfig = $appConfig; + $this->scanService = new ScanService($logger, $tagService, $scanService, $appConfig); $this->setInterval(60); $this->setAllowParallelRuns(false); @@ -37,41 +30,10 @@ public function __construct(LoggerInterface $logger, ITimeFactory $time, TagServ * @throws \OCP\DB\Exception if the database platform is not supported */ protected function run($argument): void { - $autoScan = $this->appConfig->getAppValue(self::APP_ID, 'autoScanFiles'); + $autoScan = $this->appConfig->getAppValue(Application::APP_ID, 'autoScanFiles'); if (!$autoScan) { return; } - $unscannedTagIsDisabled = $this->appConfig->getAppValue(self::APP_ID, 'disableUnscannedTag'); - $quantity = $this->appConfig->getAppValue(self::APP_ID, 'scanQueueLength'); - try { - $quantity = intval($quantity); - } catch (Exception) { - $quantity = 5; - } - - $maliciousTag = $this->tagService->getTag(TagService::MALICIOUS); - $pupTag = $this->tagService->getTag(TagService::PUP); - $cleanTag = $this->tagService->getTag(TagService::CLEAN); - $unscannedTag = $this->tagService->getTag(TagService::UNSCANNED); - $wontScanTag = $this->tagService->getTag(TagService::WONT_SCAN); - - if ($unscannedTagIsDisabled) { - $excludedTagIds = [$unscannedTag->getId(), $maliciousTag->getId(), $cleanTag->getId(), $pupTag->getId(), $wontScanTag->getId()]; - $fileIds = $this->tagService->getFileIdsWithoutTags($excludedTagIds, $quantity); - } else { - $fileIds = $this->tagService->getFileIdsWithTag(TagService::UNSCANNED, $quantity, 0); - } - - $this->logger->debug("Scanning files"); - - foreach ($fileIds as $fileId) { - try { - $this->scanService->scanFileById($fileId); - } catch (Exception $e) { - $this->logger->error("Failed to scan file with id " . $fileId . ": " . $e->getMessage()); - } - } - - $this->logger->debug("Scanned " . count($fileIds) . " files"); + $this->scanService->run(); } } diff --git a/lib/BackgroundJobs/TagUnscannedJob.php b/lib/BackgroundJobs/TagUnscannedJob.php index bc59d039..0c8e8f3b 100644 --- a/lib/BackgroundJobs/TagUnscannedJob.php +++ b/lib/BackgroundJobs/TagUnscannedJob.php @@ -3,6 +3,7 @@ namespace OCA\GDataVaas\BackgroundJobs; use OCA\GDataVaas\Service\TagService; +use OCA\GDataVaas\Service\TagUnscannedService; use OCP\AppFramework\Utility\ITimeFactory; use OCP\BackgroundJob\TimedJob; use OCP\DB\Exception; @@ -10,18 +11,11 @@ use Psr\Log\LoggerInterface; class TagUnscannedJob extends TimedJob { - private const APP_ID = "gdatavaas"; - - private TagService $tagService; - private IConfig $appConfig; - private LoggerInterface $logger; - + private TagUnscannedService $tagUnscannedService; public function __construct(ITimeFactory $time, IConfig $appConfig, TagService $tagService, LoggerInterface $logger) { parent::__construct($time); - $this->appConfig = $appConfig; - $this->tagService = $tagService; - $this->logger = $logger; + $this->tagUnscannedService = new TagUnscannedService($logger, $tagService, $appConfig); $this->setInterval(60); $this->setAllowParallelRuns(false); @@ -34,31 +28,6 @@ public function __construct(ITimeFactory $time, IConfig $appConfig, TagService $ * @throws Exception if the database platform is not supported */ protected function run($argument): void { - $unscannedTagIsDisabled = $this->appConfig->getAppValue(self::APP_ID, 'disableUnscannedTag'); - if ($unscannedTagIsDisabled) { - $this->tagService->removeTag(TagService::UNSCANNED); - return; - } - - $this->logger->debug("Tagging unscanned files"); - - $unscannedTag = $this->tagService->getTag(TagService::UNSCANNED); - $maliciousTag = $this->tagService->getTag(TagService::MALICIOUS); - $pupTag = $this->tagService->getTag(TagService::PUP); - $cleanTag = $this->tagService->getTag(TagService::CLEAN); - $wontScanTag = $this->tagService->getTag(TagService::WONT_SCAN); - - $excludedTagIds = [$unscannedTag->getId(), $maliciousTag->getId(), $cleanTag->getId(), $pupTag->getId(), $wontScanTag->getId()]; - - $fileIds = $this->tagService->getFileIdsWithoutTags($excludedTagIds, 10000); - - foreach ($fileIds as $fileId) { - if ($this->tagService->hasAnyButUnscannedTag($fileId)) { - continue; - } - $this->tagService->setTag($fileId, TagService::UNSCANNED); - } - - $this->logger->debug("Tagged " . count($fileIds) . " unscanned files"); + $this->tagUnscannedService->run(); } } diff --git a/lib/Command/ScanCommand.php b/lib/Command/ScanCommand.php new file mode 100644 index 00000000..5d2d812f --- /dev/null +++ b/lib/Command/ScanCommand.php @@ -0,0 +1,44 @@ +logger = $logger; + $this->scanService = new ScanService($logger, $tagService, $scanService, $appConfig); + } + + /** + * @return void + */ + protected function configure() { + $this->setName('gdatavaas:scan'); + $this->setDescription('scan files for malware'); + } + + /** + * @param $argument + * @return void + * @throws \OCP\DB\Exception if the database platform is not supported + */ + protected function execute(InputInterface $input, OutputInterface $output): int { + $this->scanService->setLogger(new ConsoleCommandLogger($this->logger, $output)); + $this->scanService->run(); + return 0; + } +} diff --git a/lib/Command/TagUnscannedCommand.php b/lib/Command/TagUnscannedCommand.php new file mode 100644 index 00000000..e2f15273 --- /dev/null +++ b/lib/Command/TagUnscannedCommand.php @@ -0,0 +1,38 @@ +logger = $logger; + + $this->tagUnscannedService = new TagUnscannedService($logger, $tagService, $appConfig); + } + + /** + * @return void + */ + protected function configure() { + $this->setName('gdatavaas:tag-unscanned'); + $this->setDescription('tags all files without tag from this app as unscanned'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int { + $this->tagUnscannedService->setLogger(new ConsoleCommandLogger($this->logger, $output)); + $this->tagUnscannedService->run(); + return 0; + } +} diff --git a/lib/Logging/ConsoleCommandLogger.php b/lib/Logging/ConsoleCommandLogger.php new file mode 100644 index 00000000..81b52128 --- /dev/null +++ b/lib/Logging/ConsoleCommandLogger.php @@ -0,0 +1,75 @@ +inner = $inner; + $this->consoleOutput = $consoleOutput; + } + + public function emergency($message, array $context = []) { + $this->consoleOutput->writeln("[emergency] $message"); + + $this->inner->emergency($message, $context); + } + + public function alert($message, array $context = []) { + $this->consoleOutput->writeln("[alert] $message"); + + $this->inner->alert($message, $context); + } + + public function critical($message, array $context = []) { + $this->consoleOutput->writeln("[critical] $message"); + + $this->inner->critical($message, $context); + } + + public function error($message, array $context = []) { + $this->consoleOutput->writeln("[error] $message"); + + $this->inner->error($message, $context); + } + + public function warning($message, array $context = []) { + $this->consoleOutput->writeln("[warning] $message"); + + $this->inner->warning($message, $context); + } + + public function notice($message, array $context = []) { + $this->consoleOutput->writeln("[notice] $message"); + + $this->inner->notice($message, $context); + } + + public function info($message, array $context = []) { + $this->consoleOutput->writeln("[info] $message"); + + $this->inner->info($message, $context); + } + + public function debug($message, array $context = []) { + if ($this->consoleOutput->getVerbosity() < OutputInterface::VERBOSITY_DEBUG) { + return; + } + + $this->consoleOutput->writeln("[debug] $message"); + + $this->inner->debug($message, $context); + } + + public function log($level, $message, array $context = []) { + $this->consoleOutput->writeln("[log] $message"); + + $this->inner->log($level, $message, $context); + } +} diff --git a/lib/Service/FileService.php b/lib/Service/FileService.php index 71a778da..2e002b7c 100644 --- a/lib/Service/FileService.php +++ b/lib/Service/FileService.php @@ -2,6 +2,7 @@ namespace OCA\GDataVaas\Service; +use OCA\GDataVaas\AppInfo\Application; use OCP\Files\Config\IUserMountCache; use OCP\Files\InvalidPathException; use OCP\Files\IRootFolder; @@ -13,7 +14,6 @@ use Psr\Log\LoggerInterface; class FileService { - private const APP_ID = "gdatavaas"; private IUserMountCache $userMountCache; private IRootFolder $rootFolder; @@ -37,7 +37,7 @@ public function __construct(LoggerInterface $logger, IUserMountCache $userMountC * @throws LockedException */ public function setMaliciousPrefixIfActivated(int $fileId): void { - if ($this->appConfig->getAppValue(self::APP_ID, 'prefixMalicious')) { + if ($this->appConfig->getAppValue(Application::APP_ID, 'prefixMalicious')) { $file = $this->getNodeFromFileId($fileId); if (!str_starts_with($file->getName(), '[MALICIOUS] ')) { $newFileName = "[MALICIOUS] " . $file->getName(); @@ -85,7 +85,7 @@ private function findNodeInMount(\OCP\Files\Config\ICachedMountFileInfo $mount, * @throws NotPermittedException */ public function moveFileToQuarantineFolderIfDefined(int $fileId): void { - $quarantineFolderPath = $this->appConfig->getAppValue(self::APP_ID, 'quarantineFolder'); + $quarantineFolderPath = $this->appConfig->getAppValue(Application::APP_ID, 'quarantineFolder'); if (empty($quarantineFolderPath)) { throw new InvalidPathException('Quarantine folder path is not defined'); } diff --git a/lib/Service/ScanService.php b/lib/Service/ScanService.php new file mode 100644 index 00000000..de4c0771 --- /dev/null +++ b/lib/Service/ScanService.php @@ -0,0 +1,60 @@ +logger = $logger; + $this->tagService = $tagService; + $this->verdictService = $verdictService; + $this->appConfig = $appConfig; + } + + public function setLogger(LoggerInterface $logger) { + $this->logger = $logger; + } + + public function run() { + $unscannedTagIsDisabled = $this->appConfig->getAppValue(Application::APP_ID, 'disableUnscannedTag'); + $quantity = $this->appConfig->getAppValue(Application::APP_ID, 'scanQueueLength'); + try { + $quantity = intval($quantity); + } catch (\Exception) { + $quantity = 5; + } + + $maliciousTag = $this->tagService->getTag(TagService::MALICIOUS); + $pupTag = $this->tagService->getTag(TagService::PUP); + $cleanTag = $this->tagService->getTag(TagService::CLEAN); + $unscannedTag = $this->tagService->getTag(TagService::UNSCANNED); + $wontScanTag = $this->tagService->getTag(TagService::WONT_SCAN); + + if ($unscannedTagIsDisabled) { + $excludedTagIds = [$unscannedTag->getId(), $maliciousTag->getId(), $cleanTag->getId(), $pupTag->getId(), $wontScanTag->getId()]; + $fileIds = $this->tagService->getFileIdsWithoutTags($excludedTagIds, $quantity); + } else { + $fileIds = $this->tagService->getFileIdsWithTag(TagService::UNSCANNED, $quantity, 0); + } + + $this->logger->debug("Scanning files"); + + foreach ($fileIds as $fileId) { + try { + $this->verdictService->scanFileById($fileId); + } catch (\Exception $e) { + $this->logger->error("Failed to scan file with id " . $fileId . ": " . $e->getMessage()); + } + } + + $this->logger->debug("Scanned " . count($fileIds) . " files"); + } +} diff --git a/lib/Service/TagUnscannedService.php b/lib/Service/TagUnscannedService.php new file mode 100644 index 00000000..22154be4 --- /dev/null +++ b/lib/Service/TagUnscannedService.php @@ -0,0 +1,53 @@ +logger = $logger; + $this->tagService = $tagService; + $this->appConfig = $appConfig; + } + + public function setLogger(LoggerInterface $logger) { + $this->logger = $logger; + } + + public function run() { + $unscannedTagIsDisabled = $this->appConfig->getAppValue(Application::APP_ID, 'disableUnscannedTag'); + if ($unscannedTagIsDisabled) { + $this->tagService->removeTag(TagService::UNSCANNED); + return; + } + + $this->logger->debug("Tagging unscanned files"); + + $unscannedTag = $this->tagService->getTag(TagService::UNSCANNED); + $maliciousTag = $this->tagService->getTag(TagService::MALICIOUS); + $pupTag = $this->tagService->getTag(TagService::PUP); + $cleanTag = $this->tagService->getTag(TagService::CLEAN); + $wontScanTag = $this->tagService->getTag(TagService::WONT_SCAN); + + $excludedTagIds = [$unscannedTag->getId(), $maliciousTag->getId(), $cleanTag->getId(), $pupTag->getId(), $wontScanTag->getId()]; + + $fileIds = $this->tagService->getFileIdsWithoutTags($excludedTagIds, 10000); + + foreach ($fileIds as $fileId) { + if ($this->tagService->hasAnyButUnscannedTag($fileId)) { + continue; + } + $this->tagService->setTag($fileId, TagService::UNSCANNED); + } + + $this->logger->debug("Tagged " . count($fileIds) . " unscanned files"); + } + +} diff --git a/lib/Service/VerdictService.php b/lib/Service/VerdictService.php index 874c33c7..fc87441a 100644 --- a/lib/Service/VerdictService.php +++ b/lib/Service/VerdictService.php @@ -3,6 +3,7 @@ namespace OCA\GDataVaas\Service; use Exception; +use OCA\GDataVaas\AppInfo\Application; use OCP\Files\EntityTooLargeException; use OCP\Files\InvalidPathException; use OCP\Files\NotFoundException; @@ -22,7 +23,6 @@ class VerdictService { public const MAX_FILE_SIZE = 268435456; - private const APP_ID = "gdatavaas"; private string $username; private string $password; @@ -44,13 +44,13 @@ public function __construct(LoggerInterface $logger, IConfig $appConfig, FileSer $this->fileService = $fileService; $this->tagService = $tagService; - $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'); - $this->clientSecret = $this->appConfig->getAppValue(self::APP_ID, 'clientSecret'); - $this->username = $this->appConfig->getAppValue(self::APP_ID, 'username'); - $this->password = $this->appConfig->getAppValue(self::APP_ID, 'password'); + $this->authMethod = $this->appConfig->getAppValue(Application::APP_ID, 'authMethod', 'ClientCredentials'); + $this->tokenEndpoint = $this->appConfig->getAppValue(Application::APP_ID, 'tokenEndpoint', 'https://account-staging.gdata.de/realms/vaas-staging/protocol/openid-connect/token'); + $this->vaasUrl = $this->appConfig->getAppValue(Application::APP_ID, 'vaasUrl', 'wss://gateway.staging.vaas.gdatasecurity.de'); + $this->clientId = $this->appConfig->getAppValue(Application::APP_ID, 'clientId'); + $this->clientSecret = $this->appConfig->getAppValue(Application::APP_ID, 'clientSecret'); + $this->username = $this->appConfig->getAppValue(Application::APP_ID, 'username'); + $this->password = $this->appConfig->getAppValue(Application::APP_ID, 'password'); } /** @@ -146,7 +146,7 @@ public function scan(string $filePath): VaasVerdict { * @return array */ private function getAllowlist(): array { - $allowlist = $this->appConfig->getAppValue(self::APP_ID, 'allowlist'); + $allowlist = $this->appConfig->getAppValue(Application::APP_ID, 'allowlist'); $allowlist = preg_replace('/\s+/', '', $allowlist); if (empty($allowlist)) { return []; @@ -159,7 +159,7 @@ private function getAllowlist(): array { * @return array */ private function getBlocklist(): array { - $blocklist = $this->appConfig->getAppValue(self::APP_ID, 'blocklist'); + $blocklist = $this->appConfig->getAppValue(Application::APP_ID, 'blocklist'); $blocklist = preg_replace('/\s+/', '', $blocklist); if (empty($blocklist)) { return []; diff --git a/lib/Settings/VaasAdmin.php b/lib/Settings/VaasAdmin.php index 15c3f8a5..dd505764 100644 --- a/lib/Settings/VaasAdmin.php +++ b/lib/Settings/VaasAdmin.php @@ -2,12 +2,12 @@ namespace OCA\GDataVaas\Settings; +use OCA\GDataVaas\AppInfo\Application; use OCP\AppFramework\Http\TemplateResponse; use OCP\IConfig; use OCP\Settings\ISettings; class VaasAdmin implements ISettings { - private const APP_ID = 'gdatavaas'; private IConfig $config; @@ -17,24 +17,24 @@ public function __construct(IConfig $config) { public function getForm(): TemplateResponse { $params = [ - 'username' => $this->config->getAppValue(self::APP_ID, 'username'), - 'password' => $this->config->getAppValue(self::APP_ID, 'password'), - 'clientId' => $this->config->getAppValue(self::APP_ID, 'clientId'), - 'clientSecret' => $this->config->getAppValue(self::APP_ID, 'clientSecret'), - 'authMethod' => $this->config->getAppValue(self::APP_ID, 'authMethod', 'ClientCredentials'), - 'tokenEndpoint' => $this->config->getAppValue(self::APP_ID, 'tokenEndpoint', 'https://account-staging.gdata.de/realms/vaas-staging/protocol/openid-connect/token'), - 'vaasUrl' => $this->config->getAppValue(self::APP_ID, 'vaasUrl', 'wss://gateway.staging.vaas.gdatasecurity.de'), - 'quarantineFolder' => $this->config->getAppValue(self::APP_ID, 'quarantineFolder', 'Quarantine'), - 'autoScanFiles' => $this->config->getAppValue(self::APP_ID, 'autoScanFiles', false), - 'scanOnlyNewFiles' => $this->config->getAppValue(self::APP_ID, 'scanOnlyNewFiles', true), - 'prefixMalicious' => $this->config->getAppValue(self::APP_ID, 'prefixMalicious', true), - 'disableUnscannedTag' => $this->config->getAppValue(self::APP_ID, 'disableUnscannedTag', false), - 'allowlist' => $this->config->getAppValue(self::APP_ID, 'allowlist'), - 'blocklist' => $this->config->getAppValue(self::APP_ID, 'blocklist'), - 'scanQueueLength' => $this->config->getAppValue(self::APP_ID, 'scanQueueLength', 5), + 'username' => $this->config->getAppValue(Application::APP_ID, 'username'), + 'password' => $this->config->getAppValue(Application::APP_ID, 'password'), + 'clientId' => $this->config->getAppValue(Application::APP_ID, 'clientId'), + 'clientSecret' => $this->config->getAppValue(Application::APP_ID, 'clientSecret'), + 'authMethod' => $this->config->getAppValue(Application::APP_ID, 'authMethod', 'ClientCredentials'), + 'tokenEndpoint' => $this->config->getAppValue(Application::APP_ID, 'tokenEndpoint', 'https://account-staging.gdata.de/realms/vaas-staging/protocol/openid-connect/token'), + 'vaasUrl' => $this->config->getAppValue(Application::APP_ID, 'vaasUrl', 'wss://gateway.staging.vaas.gdatasecurity.de'), + 'quarantineFolder' => $this->config->getAppValue(Application::APP_ID, 'quarantineFolder', 'Quarantine'), + 'autoScanFiles' => $this->config->getAppValue(Application::APP_ID, 'autoScanFiles', false), + 'scanOnlyNewFiles' => $this->config->getAppValue(Application::APP_ID, 'scanOnlyNewFiles', true), + 'prefixMalicious' => $this->config->getAppValue(Application::APP_ID, 'prefixMalicious', true), + 'disableUnscannedTag' => $this->config->getAppValue(Application::APP_ID, 'disableUnscannedTag', false), + 'allowlist' => $this->config->getAppValue(Application::APP_ID, 'allowlist'), + 'blocklist' => $this->config->getAppValue(Application::APP_ID, 'blocklist'), + 'scanQueueLength' => $this->config->getAppValue(Application::APP_ID, 'scanQueueLength', 5), ]; - return new TemplateResponse(self::APP_ID, 'admin', $params); + return new TemplateResponse(Application::APP_ID, 'admin', $params); } public function getSection(): string { diff --git a/tests/functionality-parallel.bats b/tests/functionality-parallel.bats new file mode 100755 index 00000000..17f3b361 --- /dev/null +++ b/tests/functionality-parallel.bats @@ -0,0 +1,63 @@ +#!/usr/bin/env bats + +FOLDER_PREFIX=./tmp/functionality-parallel +TESTUSER=testuser +TESTUSER_PASSWORD=myfancysecurepassword234 +EICAR_STRING='X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' +CLEAN_STRING='nothingwronghere' + +setup_file() { + mkdir -p $FOLDER_PREFIX + curl --output $FOLDER_PREFIX/pup.exe http://amtso.eicar.org/PotentiallyUnwanted.exe + docker exec --env OC_PASS=$TESTUSER_PASSWORD --user www-data nextcloud-container php occ user:add $TESTUSER --password-from-env || echo "already exists" + docker exec --user www-data -i nextcloud-container php occ config:app:set gdatavaas clientSecret --value="$CLIENT_SECRET" + sleep 2 +} + +@test "test admin eicar Upload" { + RESULT=$(echo $EICAR_STRING | curl --silent -w "%{http_code}" -u admin:admin -T - http://127.0.0.1/remote.php/dav/files/admin/functionality-parallel.eicar.com.txt) + echo "Actual: $RESULT" + curl --silent -q -u admin:admin -X DELETE http://127.0.0.1/remote.php/dav/files/admin/functionality-parallel.eicar.com.txt || echo "file not found" + [[ "$RESULT" =~ "Upload cannot be completed." ]] +} + +@test "test admin clean upload" { + RESULT=$(echo $CLEAN_STRING | curl -w "%{http_code}" -u admin:admin -T - http://127.0.0.1/remote.php/dav/files/admin/functionality-parallel.clean.txt) + echo "Actual: $RESULT" + curl --silent -q -u admin:admin -X DELETE http://127.0.0.1/remote.php/dav/files/admin/functionality-parallel.clean.txt || echo "file not found" + [[ $RESULT -ge 200 && $RESULT -lt 300 ]] +} + +@test "test admin pup Upload" { + RESULT=$(curl --silent -w "%{http_code}" -u admin:admin -T $FOLDER_PREFIX/pup.exe http://127.0.0.1/remote.php/dav/files/admin/functionality-parallel.pup.exe) + echo "Actual: $RESULT" + curl --silent -q -u admin:admin -X DELETE http://127.0.0.1/remote.php/dav/files/admin/functionality-parallel.pup.exe || echo "file not found" + [[ $RESULT -ge 200 && $RESULT -lt 300 ]] +} + +@test "test testuser eicar Upload" { + RESULT=$(echo $EICAR_STRING | curl --silent -w "%{http_code}" -u $TESTUSER:$TESTUSER_PASSWORD -T - http://127.0.0.1/remote.php/dav/files/$TESTUSER/functionality-parallel.eicar.com.txt) + echo "Actual: $RESULT" + docker exec --user www-data -i nextcloud-container php occ config:app:get gdatavaas clientSecret + curl --silent -q -u $TESTUSER:$TESTUSER_PASSWORD -X DELETE http://127.0.0.1/remote.php/dav/files/$TESTUSER/functionality-parallel.eicar.com.txt || echo "file not found" + [[ "$RESULT" =~ "Upload cannot be completed." ]] +} + +@test "test testuser clean Upload" { + STATUS_CODE=$(echo $CLEAN_STRING | curl --silent -w "%{http_code}" -u $TESTUSER:$TESTUSER_PASSWORD -T - http://127.0.0.1/remote.php/dav/files/$TESTUSER/functionality-parallel.clean.txt) + echo "Actual: $RESULT" + curl --silent -q -u $TESTUSER:$TESTUSER_PASSWORD -X DELETE http://127.0.0.1/remote.php/dav/files/$TESTUSER/functionality-parallel.clean.txt || echo "file not found" + [[ $STATUS_CODE -ge 200 && $STATUS_CODE -lt 300 ]] || exit 1 +} + +@test "test testuser pup Upload" { + RESULT=$(curl --silent -w "%{http_code}" -u $TESTUSER:$TESTUSER_PASSWORD -T $FOLDER_PREFIX/pup.exe http://127.0.0.1/remote.php/dav/files/$TESTUSER/functionality-parallel.pup.exe) + echo "Actual: $RESULT" + curl --silent -q -u $TESTUSER:$TESTUSER_PASSWORD -X DELETE http://127.0.0.1/remote.php/dav/files/$TESTUSER/functionality-parallel.pup.exe || echo "file not found" + [[ $RESULT -ge 200 && $RESULT -lt 300 ]] || exit 1 +} + +@tearddown_file() { + rm -rf $FOLDER_PREFIX/ +} + \ No newline at end of file diff --git a/tests/functionality-sequential.bats b/tests/functionality-sequential.bats new file mode 100644 index 00000000..195e91f7 --- /dev/null +++ b/tests/functionality-sequential.bats @@ -0,0 +1,68 @@ +#!/usr/bin/env bats + +FOLDER_PREFIX=./tmp/functionality-sequential +TESTUSER=testuser +TESTUSER_PASSWORD=myfancysecurepassword234 +EICAR_STRING='X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' + +setup_file() { + mkdir -p $FOLDER_PREFIX/ + curl --output $FOLDER_PREFIX/pup.exe http://amtso.eicar.org/PotentiallyUnwanted.exe + docker exec --env OC_PASS=$TESTUSER_PASSWORD --user www-data nextcloud-container php occ user:add $TESTUSER --password-from-env || echo "already exists" + BATS_NO_PARALLELIZE_WITHIN_FILE=true +} + +@test "test upload when vaas does not function" { + docker exec --user www-data -i nextcloud-container php occ config:app:set gdatavaas clientSecret --value="WRONG_PASSWORD" + RESULT=$(echo $EICAR_STRING | curl --silent -w "%{http_code}" -u admin:admin -T - http://127.0.0.1/remote.php/dav/files/admin/functionality-sequential.eicar.com.txt) + docker exec --user www-data -i nextcloud-container php occ config:app:set gdatavaas clientSecret --value="$CLIENT_SECRET" + curl --silent -q -u admin:admin -X DELETE http://127.0.0.1/remote.php/dav/files/admin/functionality-sequential.eicar.com.txt + + echo "Actual: $RESULT" + [[ $RESULT -ge 200 && $RESULT -lt 300 ]] +} + +@test "test croned scan for admin files" { + docker exec --user www-data -i nextcloud-container php occ config:app:set gdatavaas clientSecret --value="WRONG_PASSWORD" + echo $EICAR_STRING | curl --silent -w "%{http_code}" -u admin:admin -T - http://127.0.0.1/remote.php/dav/files/admin/admin.functionality-sequential.eicar.com.txt + curl --silent -w "%{http_code}" -u admin:admin -T $FOLDER_PREFIX/pup.exe http://127.0.0.1/remote.php/dav/files/admin/admin.pup.exe + + docker exec --user www-data -i nextcloud-container php occ config:app:set gdatavaas clientSecret --value="$CLIENT_SECRET" + + docker exec -i --user www-data nextcloud-container php occ gdatavaas:tag-unscanned + docker exec -i --user www-data nextcloud-container php occ gdatavaas:scan + + LOGS=$(docker exec --user www-data -i nextcloud-container cat data/nextcloud.log | egrep "admin.functionality-sequential.eicar.com.txt|Readme.md|admin.pup.exe" ) + + curl --silent -q -u admin:admin -X DELETE http://127.0.0.1/remote.php/dav/files/admin/admin.functionality-sequential.eicar.com.txt + curl --silent -q -u admin:admin -X DELETE http://127.0.0.1/remote.php/dav/files/admin/admin.pup.exe + + [[ $LOGS =~ ^.*admin.functionality-sequential.eicar.com.txt.*Verdict:.*Malicious ]] + [[ $LOGS =~ ^.*admin.pup.exe.*Verdict:.*Pup ]] + [[ $LOGS =~ ^.*Readme.md.*Verdict:.*Clean ]] +} + +@test "test croned scan for testuser files" { + docker exec --user www-data -i nextcloud-container php occ config:app:set gdatavaas clientSecret --value="WRONG_PASSWORD" + + echo $EICAR_STRING |curl --silent -w "%{http_code}" -u $TESTUSER:$TESTUSER_PASSWORD -T - http://127.0.0.1/remote.php/dav/files/$TESTUSER/$TESTUSER.functionality-sequential.eicar.com.txt + curl --silent -w "%{http_code}" -u $TESTUSER:$TESTUSER_PASSWORD -T $FOLDER_PREFIX/pup.exe http://127.0.0.1/remote.php/dav/files/$TESTUSER/$TESTUSER.pup.exe + + docker exec --user www-data -i nextcloud-container php occ config:app:set gdatavaas clientSecret --value="$CLIENT_SECRET" + + docker exec -i --user www-data nextcloud-container php occ gdatavaas:tag-unscanned + docker exec -i --user www-data nextcloud-container php occ gdatavaas:scan + + LOGS=$(docker exec --user www-data -i nextcloud-container cat data/nextcloud.log | egrep "$TESTUSER.functionality-sequential.eicar.com.txt|$TESTUSER.pup.exe") + + curl --silent -q -u $TESTUSER:$TESTUSER_PASSWORD -X DELETE http://127.0.0.1/remote.php/dav/files/$TESTUSER/$TESTUSER.functionality-sequential.eicar.com.txt + curl --silent -q -u $TESTUSER:$TESTUSER_PASSWORD -X DELETE http://127.0.0.1/remote.php/dav/files/$TESTUSER/$TESTUSER.pup.exe + + [[ $LOGS =~ ^.*$TESTUSER.functionality-sequential.eicar.com.txt.*Verdict:.*Malicious ]] + [[ $LOGS =~ ^.*$TESTUSER.pup.exe.*Verdict:.*Pup ]] +} + +tearddown_file() { + sleep 2 + rm -rf $FOLDER_PREFIX/ +} \ No newline at end of file