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
11 changes: 0 additions & 11 deletions .github/workflows/shared_workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ jobs:
nextcloudVersion: [ stable30 ]
phpVersion: [ 8.1, 8.2, 8.3 ]
include:
- nextcloudVersion: stable26
phpVersion: 8.0
- nextcloudVersion: stable27
phpVersion: 8.0
- nextcloudVersion: stable28
Expand Down Expand Up @@ -192,11 +190,6 @@ jobs:
phpVersionMajor: 8
phpVersionMinor: 1
database: pgsql
# Each oldServer with the oldest PHP version and one database
- nextcloudVersion: stable26
phpVersionMajor: 8
phpVersionMinor: 0
database: mysql
- nextcloudVersion: stable27
phpVersionMajor: 8
phpVersionMinor: 0
Expand Down Expand Up @@ -303,10 +296,6 @@ jobs:
- name: API Tests
env:
NEXTCLOUD_BASE_URL: http://nextcloud
BEHAT_FILTER_TAGS: ${{
matrix.nextcloudVersion == 'stable26' && '~@skipOnStable26' ||
''
}}
run: |
# The following if block can be removed once Nextcloud no longer supports PHP 8.0
if [ "${{matrix.phpVersionMajor}}" -eq 8 ] && [ "${{matrix.phpVersionMinor}}" -eq 0 ]; then
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Fix random deactivation of automatically managed project folder
- Fix avatar not found in openproject
- Enhance project search when creating workpackages from Nextcloud
- Drop application's support for Nextcloud 26
- Fix issue preventing direct uploading of resources in Nextcloud that are managed by app `Files Access Control`
- Hash or encrypt `client_secret` for different Nextcloud versions

## 2.6.4 - 2024-08-15
### Changed
Expand Down
2 changes: 1 addition & 1 deletion appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ For more information on how to set up and use the OpenProject application, pleas
<screenshot>https://github.com/nextcloud/integration_openproject/raw/master/img/screenshot1.png</screenshot>
<screenshot>https://github.com/nextcloud/integration_openproject/raw/master/img/screenshot2.png</screenshot>
<dependencies>
<nextcloud min-version="26" max-version="30" />
<nextcloud min-version="27" max-version="30" />
</dependencies>
<background-jobs>
<job>OCA\OpenProject\BackgroundJob\RemoveExpiredDirectUploadTokens</job>
Expand Down
38 changes: 26 additions & 12 deletions lib/Service/OauthService.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,29 @@ public function __construct(ClientMapper $clientMapper,
$this->crypto = $crypto;
}

/**
* @param string $secret
* @param string $nextcloudVersion
* @return string
*/
public function hashOrEncryptSecretBasedOnNextcloudVersion(string $secret, string $nextcloudVersion): string {
switch (true) {
case version_compare($nextcloudVersion, '30.0.0') >= 0:
case version_compare($nextcloudVersion, '29.0.7') >= 0 && version_compare($nextcloudVersion, '30.0.0') < 0:
case version_compare($nextcloudVersion, '28.0.10') >= 0 && version_compare($nextcloudVersion, '29.0.0') < 0:
case version_compare($nextcloudVersion, '27.1.11.8') >= 0 && version_compare($nextcloudVersion, '28.0.0') < 0:
$encryptedSecret = bin2hex($this->crypto->calculateHMAC($secret));
break;
case version_compare($nextcloudVersion, '27.0.0') === 0:
$encryptedSecret = $secret;
break;
default:
$encryptedSecret = $this->crypto->encrypt($secret);
break;
}
return $encryptedSecret;
}

/**
* @param string $name
* @param string $redirectUri
Expand All @@ -58,16 +81,8 @@ public function createNcOauthClient(string $name, string $redirectUri): array {
$client->setName($name);
$client->setRedirectUri(sprintf($redirectUri, $clientId));
$secret = $this->secureRandom->generate(64, self::validChars);
if (version_compare(OC_Util::getVersionString(), '27.0.1') >= 0) {
$encryptedSecret = $this->crypto->encrypt($secret);
} elseif (version_compare(OC_Util::getVersionString(), '26.0.4') >= 0 && version_compare(OC_Util::getVersionString(), '27.0.0') < 0) {
$encryptedSecret = $this->crypto->encrypt($secret);
} elseif (version_compare(OC_Util::getVersionString(), '25.0.8') >= 0 && version_compare(OC_Util::getVersionString(), '26.0.0') < 0) {
$encryptedSecret = $this->crypto->encrypt($secret);
} else {
$encryptedSecret = $secret;
}
$client->setSecret($encryptedSecret);
$nextcloudVersion = OC_Util::getVersionString();
$client->setSecret($this->hashOrEncryptSecretBasedOnNextcloudVersion($secret, $nextcloudVersion));
$client->setClientIdentifier($clientId);
$client = $this->clientMapper->insert($client);

Expand All @@ -91,8 +106,7 @@ public function getClientInfo(int $id): ?array {
'id' => $client->getId(),
'nextcloud_oauth_client_name' => $client->getName(),
'openproject_redirect_uri' => $client->getRedirectUri(),
'nextcloud_client_id' => $client->getClientIdentifier(),
'nextcloud_client_secret' => $this->crypto->decrypt($client->getSecret()),
'nextcloud_client_id' => $client->getClientIdentifier()
];
} catch (ClientNotFoundException $e) {
return null;
Expand Down
12 changes: 3 additions & 9 deletions tests/acceptance/features/api/setup.feature
Original file line number Diff line number Diff line change
Expand Up @@ -656,14 +656,12 @@ Feature: setup the integration through an API
"required": [
"nextcloud_oauth_client_name",
"openproject_redirect_uri",
"nextcloud_client_id",
"nextcloud_client_secret"
"nextcloud_client_id"
],
"properties": {
"nextcloud_oauth_client_name": {"type": "string", "pattern": "^OpenProject client$"},
"openproject_redirect_uri": {"type": "string", "pattern": "^http:\/\/some-host.de\/oauth_clients\/[A-Za-z0-9]+\/callback$"},
"nextcloud_client_id": {"type": "string", "pattern": "[A-Za-z0-9]+"},
"nextcloud_client_secret": {"type": "string", "pattern": "[A-Za-z0-9]+"},
"openproject_user_app_password": {"type": "string", "pattern": "[A-Za-z0-9]+"}
}
}
Expand All @@ -678,9 +676,7 @@ Feature: setup the integration through an API
When user "OpenProject" sends a "PROPFIND" request to "/remote.php/webdav" using old app password
Then the HTTP status code should be "401"

# to locally run this test the "project folder" needs to be setup already
# issue of group folder https://github.com/nextcloud/groupfolders/issues/2718
@skipOnStable25 @skipOnStable26

Scenario: check version of uploaded file inside a group folder
Given user "Carol" has been created
And user "Carol" has been added to the group "OpenProject"
Expand All @@ -693,9 +689,7 @@ Feature: setup the integration through an API
When user "Carol" deletes folder "/OpenProject/OpenProject/project-demo"
Then the HTTP status code should be 204

# to locally run this test the "project folder" needs to be setup already
# issue of group folder https://github.com/nextcloud/groupfolders/issues/2718
@skipOnStable25 @skipOnStable26

Scenario: check version of uploaded file after an update inside a group folder
Given user "Carol" has been created
And user "Carol" has been added to the group "OpenProject"
Expand Down
7 changes: 0 additions & 7 deletions tests/lib/Reference/WorkPackageReferenceProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
namespace OCA\OpenProject\Reference;

use OC\Collaboration\Reference\ReferenceManager;
use OC_Util;
use OCA\OpenProject\AppInfo\Application;
use OCA\OpenProject\Service\OpenProjectAPIService;
use OCP\IConfig;
Expand All @@ -34,12 +33,6 @@
use PHPUnit\Framework\TestCase;

class WorkPackageReferenceProviderTest extends TestCase {
protected function setUp(): void {
if (version_compare(OC_Util::getVersionString(), '26') < 0) {
$this->markTestSkipped('WorkPackageReferenceProvider is only available from nextcloud 26 so skip the tests on versions below');
}
}

/**
*
* @param array<string> $onlyMethods
Expand Down
123 changes: 123 additions & 0 deletions tests/lib/Service/OauthSeviceTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<?php
/**
* @copyright Copyright (c) 2024 Sagar Gurung <[email protected]>
*
* @author Your name <[email protected]>
*
* @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 <http://www.gnu.org/licenses/>.
*
*/

namespace OCA\OpenProject\Service;

use OCA\OAuth2\Db\ClientMapper;
use OCP\Security\ICrypto;
use OCP\Security\ISecureRandom;
use PHPUnit\Framework\TestCase;

class OauthServiceTest extends TestCase {
protected function getOauthServiceMock(
$clientMapperMock = null,
$iSecureRandomMock = null,
$iCryptoMock = null,
): OauthService {

if ($clientMapperMock === null) {
$clientMapperMock = $this->getMockBuilder(ClientMapper::class)->disableOriginalConstructor()->getMock();
}
if ($iSecureRandomMock === null) {
$iSecureRandomMock = $this->getMockBuilder(ISecureRandom::class)->getMock();
}
if ($iCryptoMock === null) {
$iCryptoMock = $this->getMockBuilder(ICrypto::class)->getMock();
}

return new OauthService(
$clientMapperMock,
$iSecureRandomMock,
$iCryptoMock
);
}


/**
* @return array<mixed>
*/
public function gethashOrEncryptSecretBasedOnNextcloudVersion(): array {
return [
[
"30.0.0",
"calculateHMAC"
],
[
"29.0.7",
"calculateHMAC"
],
[
"29.1.0",
"calculateHMAC"
],
[
"29.0.6",
"encrypt"
],
[
"28.0.10",
"calculateHMAC"
],
[
"28.2.0",
"calculateHMAC"
],
[
"28.0.0",
"encrypt"
],
[
"29.0.0",
"encrypt"
],
[
"27.1.11.8",
"calculateHMAC"
],
[
"27.1.12.0",
"calculateHMAC"
],
[
"27.1.1.0",
"encrypt"
]
];
}


/**
* @dataProvider gethashOrEncryptSecretBasedOnNextcloudVersion
* @param string $nextcloudVersion
* @param string $hashOrEncryptFunction
*
* @return void
*
*/
public function testGetHashedOrEncryptedClientSecretBasedOnNextcloudVersions(string $nextcloudVersion, string $hashOrEncryptFunction) {
$iCryptoMock = $this->getMockBuilder(ICrypto::class)->getMock();
$oAuthService = $this->getOauthServiceMock(null, null, $iCryptoMock);
$iCryptoMock->expects($this->once())->method($hashOrEncryptFunction);
$oAuthService->hashOrEncryptSecretBasedOnNextcloudVersion("client_secret", $nextcloudVersion);
}
}
75 changes: 29 additions & 46 deletions tests/lib/Service/OpenProjectAPIServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
use OC\Authentication\Token\IToken;
use OC\Avatar\GuestAvatar;
use OC\Http\Client\Client;
use OC_Util;
use OCA\GroupFolders\Folder\FolderManager;
use OCA\OpenProject\AppInfo\Application;
use OCA\OpenProject\Exception\OpenprojectErrorException;
Expand Down Expand Up @@ -639,53 +638,37 @@ private function getOpenProjectAPIService(
$ocClient = null;
$client = new GuzzleClient();
$clientConfigMock = $this->getMockBuilder(IConfig::class)->getMock();

if (version_compare(OC_Util::getVersionString(), '27') >= 0) {
$clientConfigMock
->method('getSystemValueBool')
->withConsecutive(
['allow_local_remote_servers', false],
['installed', false],
['allow_local_remote_servers', false],
['allow_local_remote_servers', false],
['installed', false],
['allow_local_remote_servers', false],
['allow_local_remote_servers', false],
['installed', false],
['allow_local_remote_servers', false]
)
->willReturnOnConsecutiveCalls(
true,
true,
true,
true,
true,
true,
true,
true,
true
);
//changed from nextcloud 26
$ocClient = new Client(
$clientConfigMock,
$certificateManager,
$client,
$this->createMock(IRemoteHostValidator::class),
$this->createMock(LoggerInterface::class));
} elseif (version_compare(OC_Util::getVersionString(), '26') >= 0) {
$clientConfigMock
$clientConfigMock
->method('getSystemValueBool')
->with('allow_local_remote_servers', false)
->willReturn(true);

//changed from nextcloud 26
$ocClient = new Client(
$clientConfigMock,
$certificateManager,
$client,
$this->createMock(IRemoteHostValidator::class)
->withConsecutive(
['allow_local_remote_servers', false],
['installed', false],
['allow_local_remote_servers', false],
['allow_local_remote_servers', false],
['installed', false],
['allow_local_remote_servers', false],
['allow_local_remote_servers', false],
['installed', false],
['allow_local_remote_servers', false]
)
->willReturnOnConsecutiveCalls(
true,
true,
true,
true,
true,
true,
true,
true,
true
);
}
//changed from nextcloud 26
$ocClient = new Client(
$clientConfigMock,
$certificateManager,
$client,
$this->createMock(IRemoteHostValidator::class),
$this->createMock(LoggerInterface::class));

$clientService = $this->getMockBuilder('\OCP\Http\Client\IClientService')->getMock();
$clientService->method('newClient')->willReturn($ocClient);
Expand Down