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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@
"customizations": {
"vscode": {
"extensions": [
"junstyle.php-cs-fixer",
"stylelint.vscode-stylelint",
"jetmartin.bats",
"recca0120.vscode-phpunit"
"ms-azuretools.vscode-containers",
"github.vscode-github-actions",
"ms-vscode.makefile-tools",
"ms-vscode-remote.remote-containers",
"DEVSENSE.phptools-vscode",
"redhat.vscode-yaml"
]
}
},
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ local: build
docker stop nextcloud-container || true
docker container rm nextcloud-container || true
docker run --rm -d -p 8080:80 --name nextcloud-container -e SERVER_BRANCH="v31.0.8" -v .:/var/www/html/apps-extra/gdatavaas ghcr.io/juliusknorr/nextcloud-dev-php84:latest
composer install

# Builds the app for production and prepares it for the appstore under ./build/artifacts
.PHONY: appstore
Expand Down
4 changes: 3 additions & 1 deletion appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
=> '/getSendMailSummaryOfMaliciousFiles', 'verb' => 'GET'],
['name' => 'settings#setSendMailSummaryOfMaliciousFiles', 'url'
=> '/setSendMailSummaryOfMaliciousFiles', 'verb' => 'POST'],
['name' => 'settings#testsettings', 'url' => '/testsettings', 'verb' => 'POST']
['name' => 'settings#testsettings', 'url' => '/testsettings', 'verb' => 'POST'],
['name' => 'settings#getCache', 'url' => '/getCache', 'verb' => 'GET'],
['name' => 'settings#getHashlookup', 'url' => '/getHashlookup', 'verb' => 'GET']
]
];
4 changes: 4 additions & 0 deletions css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ select {
box-sizing: border-box;
}

.basic_settings_table .input_field input[type=checkbox] {
margin: 8px 0 8px 50px;
}

input.toggle-round {
display: none;
}
Expand Down
17 changes: 17 additions & 0 deletions lib/Controller/SettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ public function setconfig(
$doNotScanThis,
$notifyMails,
$maxScanSize,
$timeout,
bool $cache,
bool $hashlookup,
): JSONResponse {
if (!empty($notifyMails)) {
$mails = explode(',', preg_replace('/\s+/', '', $notifyMails));
Expand All @@ -63,6 +66,9 @@ public function setconfig(
if ((int)$maxScanSize < 1) {
return new JSONResponse(['status' => 'error', 'message' => 'Invalid max scan size: ' . $maxScanSize]);
}
if ((int)$timeout < 1) {
return new JSONResponse(['status' => 'error', 'message' => 'Invalid timeout: ' . $timeout]);
}
$this->config->setValueString($this->appName, 'username', $username);
$this->config->setValueString($this->appName, 'password', $password);
$this->config->setValueString($this->appName, 'clientId', $clientId);
Expand All @@ -73,6 +79,9 @@ public function setconfig(
$this->config->setValueString($this->appName, 'doNotScanThis', $doNotScanThis);
$this->config->setValueString($this->appName, 'notifyMails', $notifyMails);
$this->config->setValueInt($this->appName, 'maxScanSizeInMB', (int)$maxScanSize);
$this->config->setValueInt($this->appName, 'timeout', (int)$timeout);
$this->config->setValueBool($this->appName, 'cache', $cache);
$this->config->setValueBool($this->appName, 'hashlookup', $hashlookup);
return new JSONResponse(['status' => 'success']);
}

Expand Down Expand Up @@ -186,4 +195,12 @@ public function testSettings(string $tokenEndpoint, string $vaasUrl): JSONRespon
return new JSONResponse(['status' => 'error', 'message' => $e->getMessage()]);
}
}

public function getCache(): JSONResponse {
return new JSONResponse(['status' => $this->config->getValueBool($this->appName, 'cache', true)]);
}

public function getHashlookup(): JSONResponse {
return new JSONResponse(['status' => $this->config->getValueBool($this->appName, 'hashlookup', true)]);
}
}
7 changes: 6 additions & 1 deletion lib/Service/VerdictService.php
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,12 @@ public function createAndConnectVaas(): Vaas {
$this->vaasUrl = 'https://' . substr($this->vaasUrl, 6);
}
}
$options = new VaasOptions(true, true, $this->vaasUrl);
$options = new VaasOptions(
useHashLookup: $this->appConfig->getValueBool(Application::APP_ID, 'hashlookup', true),
useCache: $this->appConfig->getValueBool(Application::APP_ID, 'cache', true),
vaasUrl: $this->vaasUrl,
timeout: $this->appConfig->getValueInt(Application::APP_ID, 'timeout', 300)
);
return Vaas::builder()
->withAuthenticator($this->getAuthenticator($this->authMethod, $this->tokenEndpoint))
->withOptions($options)
Expand Down
5 changes: 4 additions & 1 deletion lib/Settings/VaasAdmin.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,10 @@ public function getForm(): TemplateResponse {
=> $this->config->getValueBool(Application::APP_ID, 'sendMailOnVirusUpload'),
'notifyAdminEnabled' => $this->config->getValueBool(Application::APP_ID, 'notifyAdminEnabled'),
'maxScanSizeInMB'
=> $this->config->getValueInt(Application::APP_ID, 'maxScanSizeInMB', 256)
=> $this->config->getValueInt(Application::APP_ID, 'maxScanSizeInMB', 256),
'timeout' => $this->config->getValueInt(Application::APP_ID, 'timeout', 300),
'cache' => $this->config->getValueBool(Application::APP_ID, 'cache', true),
'hashlookup' => $this->config->getValueBool(Application::APP_ID, 'hashlookup', true),
];

return new TemplateResponse(Application::APP_ID, 'admin', $params);
Expand Down
11 changes: 10 additions & 1 deletion src/admin-settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ document.addEventListener('DOMContentLoaded', async () => {
const doNotScanThis = document.querySelector('#doNotScanThis').value;
const notifyMails = document.querySelector('#notify_mails').value;
const maxScanSize = document.querySelector('#max-scan-size').value;
const timeout = document.querySelector('#timeout').value;
const cache = document.querySelector('#cache').checked;
const hashlookup = document.querySelector('#hashlookup').checked;

const response = await postData(OC.generateUrl('apps/gdatavaas/setconfig'), {
username: username,
Expand All @@ -77,7 +80,10 @@ document.addEventListener('DOMContentLoaded', async () => {
scanOnlyThis,
doNotScanThis,
notifyMails,
maxScanSize
maxScanSize,
timeout,
cache,
hashlookup
});
const msgElement = document.querySelector('#auth_save_msg');

Expand Down Expand Up @@ -203,4 +209,7 @@ document.addEventListener('DOMContentLoaded', async () => {
scanCounter.textContent = ' N/A';
console.log('Error getting files counter:', filesCounter['message']);
}

document.querySelector('#cache').checked = (await getData(OC.generateUrl('apps/gdatavaas/getCache'))).status;
document.querySelector('#hashlookup').checked = (await getData(OC.generateUrl('apps/gdatavaas/getHashlookup'))).status;
});
65 changes: 35 additions & 30 deletions src/files-action.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,37 +15,42 @@ registerFileAction(new FileAction({
},
iconSvgInline: () => Magnifier,
async exec(file) {
const fileId = file.fileid;
let response = await fetch(OC.generateUrl('/apps/gdatavaas/scan'), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'requesttoken': oc_requesttoken
},
body: JSON.stringify({
fileId: fileId
})
});
let vaasVerdict = await response.json();
if (response.status === 200) {
switch (vaasVerdict['verdict']) {
case 'Malicious':
showError(t('gdatavaas', 'The file "' + file.basename + '" has been scanned with G DATA as verdict Malicious'));
break;
case 'Clean':
showSuccess(t('gdatavaas', 'The file "' + file.basename + '" has been scanned with G DATA as verdict Clean'));
break;
case 'Pup':
showWarning(t('gdatavaas', 'The file "' + file.basename + '" has been scanned with G DATA as ' +
'verdict PUP (Potentially unwanted program)'));
break;
}
} else {
try {
showError(t('gdatavaas', vaasVerdict.error));
} catch (e) {
showError(t('gdatavaas', 'An unknown error occurred while scanning the file'));
try {
const fileId = file.fileid;
let response = await fetch(OC.generateUrl('/apps/gdatavaas/scan'), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'requesttoken': oc_requesttoken
},
body: JSON.stringify({
fileId: fileId
})
});
let vaasVerdict = await response.json();
if (response.status === 200) {
switch (vaasVerdict['verdict']) {
case 'Malicious':
showError(t('gdatavaas', 'The file "' + file.basename + '" has been scanned with G DATA as verdict Malicious'));
break;
case 'Clean':
showSuccess(t('gdatavaas', 'The file "' + file.basename + '" has been scanned with G DATA as verdict Clean'));
break;
case 'Pup':
showWarning(t('gdatavaas', 'The file "' + file.basename + '" has been scanned with G DATA as ' +
'verdict PUP (Potentially unwanted program)'));
break;
}
} else {
try {
showError(t('gdatavaas', vaasVerdict.error));
} catch (e) {
showError(t('gdatavaas', 'An unknown error occurred while scanning the file'));
}
}
}
catch (e) {
showError(t('gdatavaas', 'An error occurred while trying to scan the file: ') + e);
}
},
}))
18 changes: 17 additions & 1 deletion templates/admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<h6>You may use self registration and create a new username and password by yourself <a href="https://vaas.gdata.de/login" target="_blank">here</a> for free.</h6>
<table class="basic_settings_table">
<tr class="basic_settings">
<td><div title="<?php p($l->t('If you have registered yourself with your e-mail address and a password, select "Resource Owner Password Flow" here, if you have received a client id and a client secret from G DATA CyberDefense AG, use "Client Credentials Flow". You can ignore the other fields.'));?>" class="visible"><label for="auth_method"><?php p($l->t('Authentication Method'));?></label></div></td>
<td><div title="<?php p($l->t('If you have registered yourself with your e-mail address and a password, select "Resource Owner Password Flow" here, if you have received a client id and a client secret from G DATA CyberDefense AG, use "Client Credentials Flow". You can ignore the other fields.'));?>" class="visible"><label for="authMethod"><?php p($l->t('Authentication Method'));?></label></div></td>
<td class="input_field">
<select id="authMethod" name="authMethod">
<option value="ClientCredentials" <?php if ($_['authMethod'] === 'ClientCredentials') {
Expand Down Expand Up @@ -66,6 +66,22 @@
<td><div title="<?php p($l->t('The maximum scan size for files to be scanned in MB. Files above this limit are tagged as “Won\'t Scan”.'));?>" class="visible"><label for="max-scan-size"><?php p($l->t('Maximum scan size'));?></label></div></td>
<td class="input_field"><input id="max-scan-size" type="number" min="0" name="max-scan-size" value="<?php p($_['maxScanSizeInMB']); ?>"/></td>
</tr>
<tr class="timeout">
<td><div title="<?php p($l->t('The timeout determines how long a file scan may take in seconds before it is canceled. Please note: If the timeout is set too short, it will restrict the scanning of large files, which take a little longer.'));?>" class="visible"><label for="timeout"><?php p($l->t('Timeout'));?></label></div></td>
<td class="input_field"><input id="timeout" type="number" min="0" name="timeout" value="<?php p($_['timeout']); ?>"/></td>
</tr>
<tr class="cache">
<td><div title="<?php p($l->t('If this option is disabled, each file is always scanned again and no results are cached.'));?>" class="visible"><label for="cache"><?php p($l->t('Cache'));?></label></div></td>
<td class="input_field"><input id="cache" type="checkbox" name="cache" <?php if ($_['cache']) {
p('checked');
} ?>/></td>
</tr>
<tr class="hashlookup">
<td><div title="<?php p($l->t('During a hash lookup, the SHA256 checksum is transmitted to the G DATA Cloud before the scan to check whether a result is already available, thereby saving unnecessary network traffic, resource load, and time.'));?>" class="visible"><label for="hashlookup"><?php p($l->t('Hash lookup'));?></label></div></td>
<td class="input_field"><input id="hashlookup" type="checkbox" name="hashlookup" <?php if ($_['hashlookup']) {
p('checked');
} ?>/></td>
</tr>
</table>
<input class="submit-button" id="auth_submit" type="submit" value="<?php p($l->t('Save'));?>" />
<span id="auth_save_msg"></span>
Expand Down
3 changes: 1 addition & 2 deletions tests/bats/functionality-parallel.bats
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ setup_file() {
# this is cache busting
$DOCKER_EXEC_WITH_USER nextcloud-container php occ files:scan --all
sleep 2
$DOCKER_EXEC_WITH_USER nextcloud-container php occ app:enable gdatavaas
}

@test "test admin eicar Upload" {
Expand Down Expand Up @@ -68,7 +69,6 @@ setup_file() {
dd if=/dev/zero of=$FOLDER_PREFIX/too-large.dat bs=268435457 count=1

docker cp $FOLDER_PREFIX/too-large.dat nextcloud-container:/var/www/html/data/$TESTUSER/files/$TESTUSER.too-large.dat
docker exec -i nextcloud-container chown www-data:www-data /var/www/html/data/$TESTUSER/files/$TESTUSER.too-large.dat
$DOCKER_EXEC_WITH_USER nextcloud-container php occ files:scan --all
$DOCKER_EXEC_WITH_USER nextcloud-container php occ gdatavaas:scan

Expand All @@ -93,7 +93,6 @@ setup_file() {

@test "test unscanned job for testuser" {
docker cp $FOLDER_PREFIX/pup.exe nextcloud-container:/var/www/html/data/$TESTUSER/files/$TESTUSER.unscanned.pup.exe
docker exec -i nextcloud-container chown www-data:www-data /var/www/html/data/$TESTUSER/files/$TESTUSER.unscanned.pup.exe
$DOCKER_EXEC_WITH_USER nextcloud-container php occ files:scan $TESTUSER
$DOCKER_EXEC_WITH_USER nextcloud-container php occ gdatavaas:tag-unscanned

Expand Down
4 changes: 2 additions & 2 deletions tests/bats/functionality-sequential.bats
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

setup_file() {
source tests/bats/.env-test || return 1
source .env-local || echo "No .env-local file found."
source .env-local || source .env || echo "No .env files found."
mkdir -p $FOLDER_PREFIX/
curl --output $FOLDER_PREFIX/pup.exe http://amtso.eicar.org/PotentiallyUnwanted.exe
$DOCKER_EXEC_WITH_USER --env OC_PASS=$TESTUSER_PASSWORD nextcloud-container php occ user:add $TESTUSER --password-from-env || echo "already exists"
Expand All @@ -16,7 +16,7 @@ setup_file() {
BATS_NO_PARALLELIZE_WITHIN_FILE=true
# this is cache busting
$DOCKER_EXEC_WITH_USER nextcloud-container php occ files:scan --all
docker exec nextcloud-container chown -R www-data:www-data /var/www/html/
$DOCKER_EXEC_WITH_USER nextcloud-container php occ app:enable gdatavaas
}

@test "test upload when vaas does not function" {
Expand Down