mirror of
https://github.com/nextcloud/server.git
synced 2026-03-01 13:00:44 -05:00
Merge pull request #49973 from nextcloud/feat/auto-accept-trusted-server
This commit is contained in:
commit
e346cf63eb
44 changed files with 2473 additions and 389 deletions
|
|
@ -39,9 +39,6 @@ use Psr\Log\LoggerInterface;
|
|||
#[OpenAPI(scope: OpenAPI::SCOPE_FEDERATION)]
|
||||
class RequestHandlerController extends OCSController {
|
||||
|
||||
/** @var string */
|
||||
private $shareTable = 'share';
|
||||
|
||||
public function __construct(
|
||||
string $appName,
|
||||
IRequest $request,
|
||||
|
|
|
|||
|
|
@ -909,99 +909,90 @@ class FederatedShareProvider implements IShareProvider {
|
|||
}
|
||||
|
||||
/**
|
||||
* check if users from other Nextcloud instances are allowed to mount public links share by this instance
|
||||
*
|
||||
* @return bool
|
||||
* Check if users from other Nextcloud instances are allowed to mount public links share by this instance
|
||||
*/
|
||||
public function isOutgoingServer2serverShareEnabled() {
|
||||
public function isOutgoingServer2serverShareEnabled(): bool {
|
||||
if ($this->gsConfig->onlyInternalFederation()) {
|
||||
return false;
|
||||
}
|
||||
$result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes');
|
||||
return ($result === 'yes');
|
||||
return $result === 'yes';
|
||||
}
|
||||
|
||||
/**
|
||||
* check if users are allowed to mount public links from other Nextclouds
|
||||
*
|
||||
* @return bool
|
||||
* Check if users are allowed to mount public links from other Nextclouds
|
||||
*/
|
||||
public function isIncomingServer2serverShareEnabled() {
|
||||
public function isIncomingServer2serverShareEnabled(): bool {
|
||||
if ($this->gsConfig->onlyInternalFederation()) {
|
||||
return false;
|
||||
}
|
||||
$result = $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes');
|
||||
return ($result === 'yes');
|
||||
return $result === 'yes';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* check if users from other Nextcloud instances are allowed to send federated group shares
|
||||
*
|
||||
* @return bool
|
||||
* Check if users from other Nextcloud instances are allowed to send federated group shares
|
||||
*/
|
||||
public function isOutgoingServer2serverGroupShareEnabled() {
|
||||
public function isOutgoingServer2serverGroupShareEnabled(): bool {
|
||||
if ($this->gsConfig->onlyInternalFederation()) {
|
||||
return false;
|
||||
}
|
||||
$result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_group_share_enabled', 'no');
|
||||
return ($result === 'yes');
|
||||
return $result === 'yes';
|
||||
}
|
||||
|
||||
/**
|
||||
* check if users are allowed to receive federated group shares
|
||||
*
|
||||
* @return bool
|
||||
* Check if users are allowed to receive federated group shares
|
||||
*/
|
||||
public function isIncomingServer2serverGroupShareEnabled() {
|
||||
public function isIncomingServer2serverGroupShareEnabled(): bool {
|
||||
if ($this->gsConfig->onlyInternalFederation()) {
|
||||
return false;
|
||||
}
|
||||
$result = $this->config->getAppValue('files_sharing', 'incoming_server2server_group_share_enabled', 'no');
|
||||
return ($result === 'yes');
|
||||
return $result === 'yes';
|
||||
}
|
||||
|
||||
/**
|
||||
* check if federated group sharing is supported, therefore the OCM API need to be enabled
|
||||
*
|
||||
* @return bool
|
||||
* Check if federated group sharing is supported, therefore the OCM API need to be enabled
|
||||
*/
|
||||
public function isFederatedGroupSharingSupported() {
|
||||
public function isFederatedGroupSharingSupported(): bool {
|
||||
return $this->cloudFederationProviderManager->isReady();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if querying sharees on the lookup server is enabled
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isLookupServerQueriesEnabled() {
|
||||
public function isLookupServerQueriesEnabled(): bool {
|
||||
// in a global scale setup we should always query the lookup server
|
||||
if ($this->gsConfig->isGlobalScaleEnabled()) {
|
||||
return true;
|
||||
}
|
||||
$result = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'yes');
|
||||
return ($result === 'yes');
|
||||
return $result === 'yes';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if it is allowed to publish user specific data to the lookup server
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isLookupServerUploadEnabled() {
|
||||
public function isLookupServerUploadEnabled(): bool {
|
||||
// in a global scale setup the admin is responsible to keep the lookup server up-to-date
|
||||
if ($this->gsConfig->isGlobalScaleEnabled()) {
|
||||
return false;
|
||||
}
|
||||
$result = $this->config->getAppValue('files_sharing', 'lookupServerUploadEnabled', 'yes');
|
||||
return ($result === 'yes');
|
||||
return $result === 'yes';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
* Check if auto accepting incoming shares from trusted servers is enabled
|
||||
*/
|
||||
public function isFederatedTrustedShareAutoAccept(): bool {
|
||||
$result = $this->config->getAppValue('files_sharing', 'federatedTrustedShareAutoAccept', 'yes');
|
||||
return $result === 'yes';
|
||||
}
|
||||
|
||||
public function getAccessList($nodes, $currentAccess) {
|
||||
$ids = [];
|
||||
foreach ($nodes as $node) {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use OC\AppFramework\Http;
|
|||
use OC\Files\Filesystem;
|
||||
use OCA\FederatedFileSharing\AddressHandler;
|
||||
use OCA\FederatedFileSharing\FederatedShareProvider;
|
||||
use OCA\Federation\TrustedServers;
|
||||
use OCA\Files_Sharing\Activity\Providers\RemoteShares;
|
||||
use OCA\Files_Sharing\External\Manager;
|
||||
use OCA\GlobalSiteSelector\Service\SlaveService;
|
||||
|
|
@ -66,6 +67,7 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
|
|||
private LoggerInterface $logger,
|
||||
private IFilenameValidator $filenameValidator,
|
||||
private readonly IProviderFactory $shareProviderFactory,
|
||||
private TrustedServers $trustedServers,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -163,6 +165,11 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
|
|||
->setObject('remote_share', $shareId, $name);
|
||||
\OC::$server->getActivityManager()->publish($event);
|
||||
$this->notifyAboutNewShare($shareWith, $shareId, $ownerFederatedId, $sharedByFederatedId, $name, $ownerDisplayName);
|
||||
|
||||
// If auto-accept is enabled, accept the share
|
||||
if ($this->federatedShareProvider->isFederatedTrustedShareAutoAccept() && $this->trustedServers->isTrustedServer($remote)) {
|
||||
$this->externalShareManager->acceptShare($shareId, $shareWith);
|
||||
}
|
||||
} else {
|
||||
$groupMembers = $this->groupManager->get($shareWith)->getUsers();
|
||||
foreach ($groupMembers as $user) {
|
||||
|
|
@ -174,8 +181,14 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
|
|||
->setObject('remote_share', $shareId, $name);
|
||||
\OC::$server->getActivityManager()->publish($event);
|
||||
$this->notifyAboutNewShare($user->getUID(), $shareId, $ownerFederatedId, $sharedByFederatedId, $name, $ownerDisplayName);
|
||||
|
||||
// If auto-accept is enabled, accept the share
|
||||
if ($this->federatedShareProvider->isFederatedTrustedShareAutoAccept() && $this->trustedServers->isTrustedServer($remote)) {
|
||||
$this->externalShareManager->acceptShare($shareId, $user->getUID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $shareId;
|
||||
} catch (\Exception $e) {
|
||||
$this->logger->error('Server can not add remote share.', [
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ class Admin implements IDelegatedSettings {
|
|||
$this->initialState->provideInitialState('incomingServer2serverGroupShareEnabled', $this->fedShareProvider->isIncomingServer2serverGroupShareEnabled());
|
||||
$this->initialState->provideInitialState('lookupServerEnabled', $this->fedShareProvider->isLookupServerQueriesEnabled());
|
||||
$this->initialState->provideInitialState('lookupServerUploadEnabled', $this->fedShareProvider->isLookupServerUploadEnabled());
|
||||
$this->initialState->provideInitialState('federatedTrustedShareAutoAccept', $this->fedShareProvider->isFederatedTrustedShareAutoAccept());
|
||||
|
||||
return new TemplateResponse('federatedfilesharing', 'settings-admin', [], '');
|
||||
}
|
||||
|
|
@ -76,6 +77,7 @@ class Admin implements IDelegatedSettings {
|
|||
'incomingServer2serverGroupShareEnabled',
|
||||
'lookupServerEnabled',
|
||||
'lookupServerUploadEnabled',
|
||||
'federatedTrustedShareAutoAccept',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,18 @@
|
|||
@update:checked="update('lookupServerUploadEnabled', lookupServerUploadEnabled)">
|
||||
{{ t('federatedfilesharing', 'Allow people to publish their data to a global and public address book') }}
|
||||
</NcCheckboxRadioSwitch>
|
||||
|
||||
<!-- Trusted server handling -->
|
||||
<div class="settings-subsection">
|
||||
<h3 class="settings-subsection__name">
|
||||
{{ t('federatedfilesharing', 'Trusted federation') }}
|
||||
</h3>
|
||||
<NcCheckboxRadioSwitch type="switch"
|
||||
:checked.sync="federatedTrustedShareAutoAccept"
|
||||
@update:checked="update('federatedTrustedShareAutoAccept', federatedTrustedShareAutoAccept)">
|
||||
{{ t('federatedfilesharing', 'Automatically accept shares from trusted federated accounts and groups by default') }}
|
||||
</NcCheckboxRadioSwitch>
|
||||
</div>
|
||||
</NcSettingsSection>
|
||||
</template>
|
||||
|
||||
|
|
@ -74,6 +86,7 @@ export default {
|
|||
federatedGroupSharingSupported: loadState('federatedfilesharing', 'federatedGroupSharingSupported'),
|
||||
lookupServerEnabled: loadState('federatedfilesharing', 'lookupServerEnabled'),
|
||||
lookupServerUploadEnabled: loadState('federatedfilesharing', 'lookupServerUploadEnabled'),
|
||||
federatedTrustedShareAutoAccept: loadState('federatedfilesharing', 'federatedTrustedShareAutoAccept'),
|
||||
internalOnly: loadState('federatedfilesharing', 'internalOnly'),
|
||||
sharingFederatedDocUrl: loadState('federatedfilesharing', 'sharingFederatedDocUrl'),
|
||||
}
|
||||
|
|
@ -111,3 +124,18 @@ export default {
|
|||
},
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.settings-subsection {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.settings-subsection__name {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
max-width: 900px;
|
||||
margin-top: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -91,10 +91,14 @@ class AdminTest extends TestCase {
|
|||
->expects($this->once())
|
||||
->method('isIncomingServer2serverGroupShareEnabled')
|
||||
->willReturn($state);
|
||||
$this->federatedShareProvider
|
||||
->expects($this->once())
|
||||
->method('isFederatedTrustedShareAutoAccept')
|
||||
->willReturn($state);
|
||||
$this->gsConfig->expects($this->once())->method('onlyInternalFederation')
|
||||
->willReturn($state);
|
||||
|
||||
$this->initialState->expects($this->exactly(9))
|
||||
$this->initialState->expects($this->exactly(10))
|
||||
->method('provideInitialState')
|
||||
->withConsecutive(
|
||||
['internalOnly', $state],
|
||||
|
|
@ -106,6 +110,7 @@ class AdminTest extends TestCase {
|
|||
['incomingServer2serverGroupShareEnabled', $state],
|
||||
['lookupServerEnabled', $state],
|
||||
['lookupServerUploadEnabled', $state],
|
||||
['federatedTrustedShareAutoAccept', $state]
|
||||
);
|
||||
|
||||
$expected = new TemplateResponse('federatedfilesharing', 'settings-admin', [], '');
|
||||
|
|
|
|||
|
|
@ -6,18 +6,6 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
return [
|
||||
'routes' => [
|
||||
[
|
||||
'name' => 'Settings#addServer',
|
||||
'url' => '/trusted-servers',
|
||||
'verb' => 'POST'
|
||||
],
|
||||
[
|
||||
'name' => 'Settings#removeServer',
|
||||
'url' => '/trusted-servers/{id}',
|
||||
'verb' => 'DELETE'
|
||||
],
|
||||
],
|
||||
'ocs' => [
|
||||
// old endpoints, only used by Nextcloud and ownCloud
|
||||
[
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ return array(
|
|||
'OCA\\Federation\\DAV\\FedAuth' => $baseDir . '/../lib/DAV/FedAuth.php',
|
||||
'OCA\\Federation\\DbHandler' => $baseDir . '/../lib/DbHandler.php',
|
||||
'OCA\\Federation\\Listener\\SabrePluginAuthInitListener' => $baseDir . '/../lib/Listener/SabrePluginAuthInitListener.php',
|
||||
'OCA\\Federation\\Middleware\\AddServerMiddleware' => $baseDir . '/../lib/Middleware/AddServerMiddleware.php',
|
||||
'OCA\\Federation\\Migration\\Version1010Date20200630191302' => $baseDir . '/../lib/Migration/Version1010Date20200630191302.php',
|
||||
'OCA\\Federation\\Settings\\Admin' => $baseDir . '/../lib/Settings/Admin.php',
|
||||
'OCA\\Federation\\SyncFederationAddressBooks' => $baseDir . '/../lib/SyncFederationAddressBooks.php',
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ class ComposerStaticInitFederation
|
|||
'OCA\\Federation\\DAV\\FedAuth' => __DIR__ . '/..' . '/../lib/DAV/FedAuth.php',
|
||||
'OCA\\Federation\\DbHandler' => __DIR__ . '/..' . '/../lib/DbHandler.php',
|
||||
'OCA\\Federation\\Listener\\SabrePluginAuthInitListener' => __DIR__ . '/..' . '/../lib/Listener/SabrePluginAuthInitListener.php',
|
||||
'OCA\\Federation\\Middleware\\AddServerMiddleware' => __DIR__ . '/..' . '/../lib/Middleware/AddServerMiddleware.php',
|
||||
'OCA\\Federation\\Migration\\Version1010Date20200630191302' => __DIR__ . '/..' . '/../lib/Migration/Version1010Date20200630191302.php',
|
||||
'OCA\\Federation\\Settings\\Admin' => __DIR__ . '/..' . '/../lib/Settings/Admin.php',
|
||||
'OCA\\Federation\\SyncFederationAddressBooks' => __DIR__ . '/..' . '/../lib/SyncFederationAddressBooks.php',
|
||||
|
|
|
|||
|
|
@ -9,11 +9,13 @@
|
|||
|
||||
#listOfTrustedServers li {
|
||||
padding-bottom: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.removeTrustedServer {
|
||||
display: none;
|
||||
vertical-align:middle;
|
||||
vertical-align: middle;
|
||||
padding-inline-start: 10px;
|
||||
}
|
||||
|
||||
|
|
@ -26,20 +28,20 @@
|
|||
}
|
||||
|
||||
#listOfTrustedServers .icon {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
margin-inline-start: 10px;
|
||||
}
|
||||
|
||||
#ocFederationAddServer #serverUrl {
|
||||
width: 270px;
|
||||
.serverUrl-block {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.serverUrl-block {
|
||||
max-width: 310px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
.serverUrl-block input {
|
||||
width: 270px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,9 +51,6 @@
|
|||
});
|
||||
|
||||
$inpServerUrl.on("change keyup", function (e) {
|
||||
|
||||
console.log("typing away");
|
||||
|
||||
var url = $(this).val();
|
||||
|
||||
// toggle add-button visibility based on input length
|
||||
|
|
@ -79,11 +76,14 @@
|
|||
OC.msg.startSaving('#ocFederationAddServer .msg');
|
||||
|
||||
$.post(
|
||||
OC.generateUrl('/apps/federation/trusted-servers'),
|
||||
OC.getRootPath() + '/ocs/v2.php/apps/federation/trusted-servers',
|
||||
{
|
||||
url: url
|
||||
}
|
||||
).done(function (data) {
|
||||
},
|
||||
null,
|
||||
'json'
|
||||
).done(function({ ocs }) {
|
||||
var data = ocs.data;
|
||||
$("#serverUrl").attr('value', '');
|
||||
$("#listOfTrustedServers").prepend(
|
||||
$('<li>')
|
||||
|
|
@ -95,13 +95,13 @@
|
|||
OC.msg.finishedSuccess('#ocFederationAddServer .msg', data.message);
|
||||
})
|
||||
.fail(function (jqXHR) {
|
||||
OC.msg.finishedError('#ocFederationAddServer .msg', JSON.parse(jqXHR.responseText).message);
|
||||
OC.msg.finishedError('#ocFederationAddServer .msg', JSON.parse(jqXHR.responseText).ocs.meta.message);
|
||||
});
|
||||
};
|
||||
|
||||
function removeServer( id ) {
|
||||
$.ajax({
|
||||
url: OC.generateUrl('/apps/federation/trusted-servers/' + id),
|
||||
url: OC.getRootPath() + '/ocs/v2.php/apps/federation/trusted-servers/' + id,
|
||||
type: 'DELETE',
|
||||
success: function(response) {
|
||||
$("#ocFederationSettings").find("#" + id).remove();
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ namespace OCA\Federation\AppInfo;
|
|||
|
||||
use OCA\DAV\Events\SabrePluginAuthInitEvent;
|
||||
use OCA\Federation\Listener\SabrePluginAuthInitListener;
|
||||
use OCA\Federation\Middleware\AddServerMiddleware;
|
||||
use OCP\AppFramework\App;
|
||||
use OCP\AppFramework\Bootstrap\IBootContext;
|
||||
use OCP\AppFramework\Bootstrap\IBootstrap;
|
||||
|
|
@ -25,8 +24,6 @@ class Application extends App implements IBootstrap {
|
|||
}
|
||||
|
||||
public function register(IRegistrationContext $context): void {
|
||||
$context->registerMiddleware(AddServerMiddleware::class);
|
||||
|
||||
$context->registerEventListener(SabrePluginAuthInitEvent::class, SabrePluginAuthInitListener::class);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ use OCP\BackgroundJob\Job;
|
|||
use OCP\Http\Client\IClient;
|
||||
use OCP\Http\Client\IClientService;
|
||||
use OCP\Http\Client\IResponse;
|
||||
use OCP\IConfig;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\OCS\IDiscoveryService;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
|
@ -43,6 +44,7 @@ class GetSharedSecret extends Job {
|
|||
private LoggerInterface $logger,
|
||||
private IDiscoveryService $ocsDiscoveryService,
|
||||
ITimeFactory $timeFactory,
|
||||
private IConfig $config,
|
||||
) {
|
||||
parent::__construct($timeFactory);
|
||||
$this->httpClient = $httpClientService->newClient();
|
||||
|
|
@ -105,6 +107,7 @@ class GetSharedSecret extends Job {
|
|||
],
|
||||
'timeout' => 3,
|
||||
'connect_timeout' => 3,
|
||||
'verify' => !$this->config->getSystemValue('sharing.federation.allowSelfSignedCertificates', false),
|
||||
]
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use OCP\BackgroundJob\IJobList;
|
|||
use OCP\BackgroundJob\Job;
|
||||
use OCP\Http\Client\IClient;
|
||||
use OCP\Http\Client\IClientService;
|
||||
use OCP\IConfig;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\OCS\IDiscoveryService;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
|
@ -47,6 +48,7 @@ class RequestSharedSecret extends Job {
|
|||
private IDiscoveryService $ocsDiscoveryService,
|
||||
private LoggerInterface $logger,
|
||||
ITimeFactory $timeFactory,
|
||||
private IConfig $config,
|
||||
) {
|
||||
parent::__construct($timeFactory);
|
||||
$this->httpClient = $httpClientService->newClient();
|
||||
|
|
@ -116,6 +118,7 @@ class RequestSharedSecret extends Job {
|
|||
],
|
||||
'timeout' => 3,
|
||||
'connect_timeout' => 3,
|
||||
'verify' => !$this->config->getSystemValue('sharing.federation.allowSelfSignedCertificates', false),
|
||||
]
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -9,34 +9,46 @@ namespace OCA\Federation\Controller;
|
|||
|
||||
use OCA\Federation\Settings\Admin;
|
||||
use OCA\Federation\TrustedServers;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\AppFramework\Http\Attribute\ApiRoute;
|
||||
use OCP\AppFramework\Http\Attribute\AuthorizedAdminSetting;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\HintException;
|
||||
use OCP\AppFramework\OCS\OCSException;
|
||||
use OCP\AppFramework\OCS\OCSNotFoundException;
|
||||
use OCP\AppFramework\OCSController;
|
||||
use OCP\IL10N;
|
||||
use OCP\IRequest;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class SettingsController extends Controller {
|
||||
class SettingsController extends OCSController {
|
||||
public function __construct(
|
||||
string $AppName,
|
||||
IRequest $request,
|
||||
private IL10N $l,
|
||||
private TrustedServers $trustedServers,
|
||||
private LoggerInterface $logger,
|
||||
) {
|
||||
parent::__construct($AppName, $request);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add server to the list of trusted Nextclouds.
|
||||
* Add server to the list of trusted Nextcloud servers
|
||||
*
|
||||
* @throws HintException
|
||||
* @param string $url The URL of the server to add
|
||||
* @return DataResponse<Http::STATUS_OK, array{id: int, message: string, url: string}, array{}>|DataResponse<Http::STATUS_NOT_FOUND|Http::STATUS_CONFLICT, array{message: string}, array{}>
|
||||
*
|
||||
* 200: Server added successfully
|
||||
* 404: Server not found at the given URL
|
||||
* 409: Server is already in the list of trusted servers
|
||||
*/
|
||||
#[AuthorizedAdminSetting(settings: Admin::class)]
|
||||
#[ApiRoute(verb: 'POST', url: '/trusted-servers')]
|
||||
public function addServer(string $url): DataResponse {
|
||||
$this->checkServer($url);
|
||||
$id = $this->trustedServers->addServer($url);
|
||||
$this->checkServer(trim($url));
|
||||
|
||||
// Add the server to the list of trusted servers, all is well
|
||||
$id = $this->trustedServers->addServer(trim($url));
|
||||
return new DataResponse([
|
||||
'url' => $url,
|
||||
'id' => $id,
|
||||
|
|
@ -45,33 +57,69 @@ class SettingsController extends Controller {
|
|||
}
|
||||
|
||||
/**
|
||||
* Add server to the list of trusted Nextclouds.
|
||||
* Add server to the list of trusted Nextcloud servers
|
||||
*
|
||||
* @param int $id The ID of the trusted server to remove
|
||||
* @return DataResponse<Http::STATUS_OK, array{id: int}, array{}>|DataResponse<Http::STATUS_NOT_FOUND, array{message: string}, array{}>
|
||||
*
|
||||
* 200: Server removed successfully
|
||||
* 404: Server not found at the given ID
|
||||
*/
|
||||
#[AuthorizedAdminSetting(settings: Admin::class)]
|
||||
#[ApiRoute(verb: 'DELETE', url: '/trusted-servers/{id}', requirements: ['id' => '\d+'])]
|
||||
public function removeServer(int $id): DataResponse {
|
||||
$this->trustedServers->removeServer($id);
|
||||
return new DataResponse();
|
||||
try {
|
||||
$this->trustedServers->getServer($id);
|
||||
} catch (\Exception $e) {
|
||||
throw new OCSNotFoundException($this->l->t('No server found with ID: %s', [$id]));
|
||||
}
|
||||
|
||||
try {
|
||||
$this->trustedServers->removeServer($id);
|
||||
return new DataResponse(['id' => $id]);
|
||||
} catch (\Exception $e) {
|
||||
$this->logger->error($e->getMessage(), ['e' => $e]);
|
||||
throw new OCSException($this->l->t('Could not remove server'), Http::STATUS_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the server should be added to the list of trusted servers or not.
|
||||
* List all trusted servers
|
||||
*
|
||||
* @throws HintException
|
||||
* @return DataResponse<Http::STATUS_OK, list<array{id: int, status: int, url: string}>, array{}>
|
||||
*
|
||||
* 200: List of trusted servers
|
||||
*/
|
||||
#[AuthorizedAdminSetting(settings: Admin::class)]
|
||||
protected function checkServer(string $url): bool {
|
||||
#[ApiRoute(verb: 'GET', url: '/trusted-servers')]
|
||||
public function getServers(): DataResponse {
|
||||
$servers = $this->trustedServers->getServers();
|
||||
|
||||
// obfuscate the shared secret
|
||||
$servers = array_map(function ($server) {
|
||||
return [
|
||||
'url' => $server['url'],
|
||||
'id' => $server['id'],
|
||||
'status' => $server['status'],
|
||||
];
|
||||
}, $servers);
|
||||
|
||||
// return the list of trusted servers
|
||||
return new DataResponse($servers);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if the server should be added to the list of trusted servers or not.
|
||||
*/
|
||||
#[AuthorizedAdminSetting(settings: Admin::class)]
|
||||
protected function checkServer(string $url): void {
|
||||
if ($this->trustedServers->isTrustedServer($url) === true) {
|
||||
$message = 'Server is already in the list of trusted servers.';
|
||||
$hint = $this->l->t('Server is already in the list of trusted servers.');
|
||||
throw new HintException($message, $hint);
|
||||
throw new OCSException($this->l->t('Server is already in the list of trusted servers.'), Http::STATUS_CONFLICT);
|
||||
}
|
||||
|
||||
if ($this->trustedServers->isNextcloudServer($url) === false) {
|
||||
$message = 'No server to federate with found';
|
||||
$hint = $this->l->t('No server to federate with found');
|
||||
throw new HintException($message, $hint);
|
||||
throw new OCSNotFoundException($this->l->t('No server to federate with found'));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,55 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
namespace OCA\Federation\Middleware;
|
||||
|
||||
use OCA\Federation\Controller\SettingsController;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\AppFramework\Http\JSONResponse;
|
||||
use OCP\AppFramework\Middleware;
|
||||
use OCP\HintException;
|
||||
use OCP\IL10N;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class AddServerMiddleware extends Middleware {
|
||||
public function __construct(
|
||||
protected string $appName,
|
||||
protected IL10N $l,
|
||||
protected LoggerInterface $logger,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Log error message and return a response which can be displayed to the user
|
||||
*
|
||||
* @param Controller $controller
|
||||
* @param string $methodName
|
||||
* @param \Exception $exception
|
||||
* @return JSONResponse
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function afterException($controller, $methodName, \Exception $exception) {
|
||||
if (($controller instanceof SettingsController) === false) {
|
||||
throw $exception;
|
||||
}
|
||||
$this->logger->error($exception->getMessage(), [
|
||||
'app' => $this->appName,
|
||||
'exception' => $exception,
|
||||
]);
|
||||
if ($exception instanceof HintException) {
|
||||
$message = $exception->getHint();
|
||||
} else {
|
||||
$message = $exception->getMessage();
|
||||
}
|
||||
|
||||
return new JSONResponse(
|
||||
['message' => $message],
|
||||
Http::STATUS_BAD_REQUEST
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -96,15 +96,34 @@ class TrustedServers {
|
|||
* Get all trusted servers
|
||||
*
|
||||
* @return list<array{id: int, url: string, url_hash: string, shared_secret: ?string, status: int, sync_token: ?string}>
|
||||
* @throws Exception
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getServers() {
|
||||
public function getServers(): ?array {
|
||||
if ($this->trustedServersCache === null) {
|
||||
$this->trustedServersCache = $this->dbHandler->getAllServer();
|
||||
}
|
||||
return $this->trustedServersCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a trusted server
|
||||
*
|
||||
* @return array{id: int, url: string, url_hash: string, shared_secret: ?string, status: int, sync_token: ?string}
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getServer(int $id): ?array {
|
||||
if ($this->trustedServersCache === null) {
|
||||
$this->trustedServersCache = $this->dbHandler->getAllServer();
|
||||
}
|
||||
|
||||
$server = array_filter($this->trustedServersCache, fn ($server) => $server['id'] === $id);
|
||||
if (empty($server)) {
|
||||
throw new \Exception('No server found with ID: ' . $id);
|
||||
}
|
||||
|
||||
return $server[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given server is a trusted Nextcloud server
|
||||
*/
|
||||
|
|
@ -138,6 +157,7 @@ class TrustedServers {
|
|||
[
|
||||
'timeout' => 3,
|
||||
'connect_timeout' => 3,
|
||||
'verify' => !$this->config->getSystemValue('sharing.federation.allowSelfSignedCertificates', false),
|
||||
]
|
||||
);
|
||||
if ($result->getStatusCode() === Http::STATUS_OK) {
|
||||
|
|
|
|||
431
apps/federation/openapi-administration.json
Normal file
431
apps/federation/openapi-administration.json
Normal file
|
|
@ -0,0 +1,431 @@
|
|||
{
|
||||
"openapi": "3.0.3",
|
||||
"info": {
|
||||
"title": "federation-administration",
|
||||
"version": "0.0.1",
|
||||
"description": "Federation allows you to connect with other trusted servers to exchange the account directory.",
|
||||
"license": {
|
||||
"name": "agpl"
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"securitySchemes": {
|
||||
"basic_auth": {
|
||||
"type": "http",
|
||||
"scheme": "basic"
|
||||
},
|
||||
"bearer_auth": {
|
||||
"type": "http",
|
||||
"scheme": "bearer"
|
||||
}
|
||||
},
|
||||
"schemas": {
|
||||
"OCSMeta": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"status",
|
||||
"statuscode"
|
||||
],
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"statuscode": {
|
||||
"type": "integer"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"totalitems": {
|
||||
"type": "string"
|
||||
},
|
||||
"itemsperpage": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"paths": {
|
||||
"/ocs/v2.php/apps/federation/trusted-servers": {
|
||||
"post": {
|
||||
"operationId": "settings-add-server",
|
||||
"summary": "Add server to the list of trusted Nextcloud servers",
|
||||
"description": "This endpoint requires admin access",
|
||||
"tags": [
|
||||
"settings"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"url"
|
||||
],
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "The URL of the server to add"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Server added successfully",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"message",
|
||||
"url"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Server not found at the given URL",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"message"
|
||||
],
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"409": {
|
||||
"description": "Server is already in the list of trusted servers",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"message"
|
||||
],
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"get": {
|
||||
"operationId": "settings-get-servers",
|
||||
"summary": "List all trusted servers",
|
||||
"description": "This endpoint requires admin access",
|
||||
"tags": [
|
||||
"settings"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "List of trusted servers",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"status",
|
||||
"url"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"status": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/apps/federation/trusted-servers/{id}": {
|
||||
"delete": {
|
||||
"operationId": "settings-remove-server",
|
||||
"summary": "Add server to the list of trusted Nextcloud servers",
|
||||
"description": "This endpoint requires admin access",
|
||||
"tags": [
|
||||
"settings"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"description": "The ID of the trusted server to remove",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Server removed successfully",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Server not found at the given ID",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"message"
|
||||
],
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
{
|
||||
"name": "ocs_authapi",
|
||||
"description": "Class OCSAuthAPI\nOCS API end-points to exchange shared secret between two connected Nextclouds"
|
||||
}
|
||||
]
|
||||
}
|
||||
2
apps/federation/openapi-administration.json.license
Normal file
2
apps/federation/openapi-administration.json.license
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
511
apps/federation/openapi-federation.json
Normal file
511
apps/federation/openapi-federation.json
Normal file
|
|
@ -0,0 +1,511 @@
|
|||
{
|
||||
"openapi": "3.0.3",
|
||||
"info": {
|
||||
"title": "federation-federation",
|
||||
"version": "0.0.1",
|
||||
"description": "Federation allows you to connect with other trusted servers to exchange the account directory.",
|
||||
"license": {
|
||||
"name": "agpl"
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"securitySchemes": {
|
||||
"basic_auth": {
|
||||
"type": "http",
|
||||
"scheme": "basic"
|
||||
},
|
||||
"bearer_auth": {
|
||||
"type": "http",
|
||||
"scheme": "bearer"
|
||||
}
|
||||
},
|
||||
"schemas": {
|
||||
"OCSMeta": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"status",
|
||||
"statuscode"
|
||||
],
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"statuscode": {
|
||||
"type": "integer"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"totalitems": {
|
||||
"type": "string"
|
||||
},
|
||||
"itemsperpage": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"paths": {
|
||||
"/ocs/v2.php/apps/federation/api/v1/shared-secret": {
|
||||
"get": {
|
||||
"operationId": "ocs_authapi-get-shared-secret-legacy",
|
||||
"summary": "Create shared secret and return it, for legacy end-points",
|
||||
"tags": [
|
||||
"ocs_authapi"
|
||||
],
|
||||
"security": [
|
||||
{},
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "url",
|
||||
"in": "query",
|
||||
"description": "URL of the server",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "token",
|
||||
"in": "query",
|
||||
"description": "Token of the server",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Shared secret returned",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"sharedSecret"
|
||||
],
|
||||
"properties": {
|
||||
"sharedSecret": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Getting shared secret is not allowed",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/apps/federation/api/v1/request-shared-secret": {
|
||||
"post": {
|
||||
"operationId": "ocs_authapi-request-shared-secret-legacy",
|
||||
"summary": "Request received to ask remote server for a shared secret, for legacy end-points",
|
||||
"tags": [
|
||||
"ocs_authapi"
|
||||
],
|
||||
"security": [
|
||||
{},
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"url",
|
||||
"token"
|
||||
],
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "URL of the server"
|
||||
},
|
||||
"token": {
|
||||
"type": "string",
|
||||
"description": "Token of the server"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Shared secret requested successfully",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Requesting shared secret is not allowed",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/cloud/shared-secret": {
|
||||
"get": {
|
||||
"operationId": "ocs_authapi-get-shared-secret",
|
||||
"summary": "Create shared secret and return it",
|
||||
"tags": [
|
||||
"ocs_authapi"
|
||||
],
|
||||
"security": [
|
||||
{},
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "url",
|
||||
"in": "query",
|
||||
"description": "URL of the server",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "token",
|
||||
"in": "query",
|
||||
"description": "Token of the server",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Shared secret returned",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"sharedSecret"
|
||||
],
|
||||
"properties": {
|
||||
"sharedSecret": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Getting shared secret is not allowed",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"operationId": "ocs_authapi-request-shared-secret",
|
||||
"summary": "Request received to ask remote server for a shared secret",
|
||||
"tags": [
|
||||
"ocs_authapi"
|
||||
],
|
||||
"security": [
|
||||
{},
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"url",
|
||||
"token"
|
||||
],
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "URL of the server"
|
||||
},
|
||||
"token": {
|
||||
"type": "string",
|
||||
"description": "Token of the server"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Shared secret requested successfully",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Requesting shared secret is not allowed",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
{
|
||||
"name": "ocs_authapi",
|
||||
"description": "Class OCSAuthAPI\nOCS API end-points to exchange shared secret between two connected Nextclouds"
|
||||
}
|
||||
]
|
||||
}
|
||||
2
apps/federation/openapi-federation.json.license
Normal file
2
apps/federation/openapi-federation.json.license
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
885
apps/federation/openapi-full.json
Normal file
885
apps/federation/openapi-full.json
Normal file
|
|
@ -0,0 +1,885 @@
|
|||
{
|
||||
"openapi": "3.0.3",
|
||||
"info": {
|
||||
"title": "federation-full",
|
||||
"version": "0.0.1",
|
||||
"description": "Federation allows you to connect with other trusted servers to exchange the account directory.",
|
||||
"license": {
|
||||
"name": "agpl"
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"securitySchemes": {
|
||||
"basic_auth": {
|
||||
"type": "http",
|
||||
"scheme": "basic"
|
||||
},
|
||||
"bearer_auth": {
|
||||
"type": "http",
|
||||
"scheme": "bearer"
|
||||
}
|
||||
},
|
||||
"schemas": {
|
||||
"OCSMeta": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"status",
|
||||
"statuscode"
|
||||
],
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"statuscode": {
|
||||
"type": "integer"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"totalitems": {
|
||||
"type": "string"
|
||||
},
|
||||
"itemsperpage": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"paths": {
|
||||
"/ocs/v2.php/apps/federation/api/v1/shared-secret": {
|
||||
"get": {
|
||||
"operationId": "ocs_authapi-get-shared-secret-legacy",
|
||||
"summary": "Create shared secret and return it, for legacy end-points",
|
||||
"tags": [
|
||||
"ocs_authapi"
|
||||
],
|
||||
"security": [
|
||||
{},
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "url",
|
||||
"in": "query",
|
||||
"description": "URL of the server",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "token",
|
||||
"in": "query",
|
||||
"description": "Token of the server",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Shared secret returned",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"sharedSecret"
|
||||
],
|
||||
"properties": {
|
||||
"sharedSecret": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Getting shared secret is not allowed",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/apps/federation/api/v1/request-shared-secret": {
|
||||
"post": {
|
||||
"operationId": "ocs_authapi-request-shared-secret-legacy",
|
||||
"summary": "Request received to ask remote server for a shared secret, for legacy end-points",
|
||||
"tags": [
|
||||
"ocs_authapi"
|
||||
],
|
||||
"security": [
|
||||
{},
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"url",
|
||||
"token"
|
||||
],
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "URL of the server"
|
||||
},
|
||||
"token": {
|
||||
"type": "string",
|
||||
"description": "Token of the server"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Shared secret requested successfully",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Requesting shared secret is not allowed",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/cloud/shared-secret": {
|
||||
"get": {
|
||||
"operationId": "ocs_authapi-get-shared-secret",
|
||||
"summary": "Create shared secret and return it",
|
||||
"tags": [
|
||||
"ocs_authapi"
|
||||
],
|
||||
"security": [
|
||||
{},
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "url",
|
||||
"in": "query",
|
||||
"description": "URL of the server",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "token",
|
||||
"in": "query",
|
||||
"description": "Token of the server",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Shared secret returned",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"sharedSecret"
|
||||
],
|
||||
"properties": {
|
||||
"sharedSecret": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Getting shared secret is not allowed",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"operationId": "ocs_authapi-request-shared-secret",
|
||||
"summary": "Request received to ask remote server for a shared secret",
|
||||
"tags": [
|
||||
"ocs_authapi"
|
||||
],
|
||||
"security": [
|
||||
{},
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"url",
|
||||
"token"
|
||||
],
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "URL of the server"
|
||||
},
|
||||
"token": {
|
||||
"type": "string",
|
||||
"description": "Token of the server"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Shared secret requested successfully",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Requesting shared secret is not allowed",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/apps/federation/trusted-servers": {
|
||||
"post": {
|
||||
"operationId": "settings-add-server",
|
||||
"summary": "Add server to the list of trusted Nextcloud servers",
|
||||
"description": "This endpoint requires admin access",
|
||||
"tags": [
|
||||
"settings"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"url"
|
||||
],
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "The URL of the server to add"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Server added successfully",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"message",
|
||||
"url"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Server not found at the given URL",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"message"
|
||||
],
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"409": {
|
||||
"description": "Server is already in the list of trusted servers",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"message"
|
||||
],
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"get": {
|
||||
"operationId": "settings-get-servers",
|
||||
"summary": "List all trusted servers",
|
||||
"description": "This endpoint requires admin access",
|
||||
"tags": [
|
||||
"settings"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "List of trusted servers",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"status",
|
||||
"url"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"status": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/apps/federation/trusted-servers/{id}": {
|
||||
"delete": {
|
||||
"operationId": "settings-remove-server",
|
||||
"summary": "Add server to the list of trusted Nextcloud servers",
|
||||
"description": "This endpoint requires admin access",
|
||||
"tags": [
|
||||
"settings"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"description": "The ID of the trusted server to remove",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Server removed successfully",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Server not found at the given ID",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"message"
|
||||
],
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
{
|
||||
"name": "ocs_authapi",
|
||||
"description": "Class OCSAuthAPI\nOCS API end-points to exchange shared secret between two connected Nextclouds"
|
||||
}
|
||||
]
|
||||
}
|
||||
2
apps/federation/openapi-full.json.license
Normal file
2
apps/federation/openapi-full.json.license
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
|
@ -1,20 +1,34 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-FileCopyrightText: 2015-2016 ownCloud, Inc.
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
/** @var array $_ */
|
||||
use OCA\Federation\TrustedServers;
|
||||
|
||||
/** @var \OCP\IL10N $l */
|
||||
script('federation', 'settings-admin');
|
||||
style('federation', 'settings-admin')
|
||||
use OCA\Federation\TrustedServers;
|
||||
use OCP\IL10N;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\Server;
|
||||
use OCP\Util;
|
||||
|
||||
/** @var IL10N $l */
|
||||
|
||||
Util::addScript('federation', 'settings-admin');
|
||||
Util::addStyle('federation', 'settings-admin');
|
||||
|
||||
$urlGenerator = Server::get(IURLGenerator::class);
|
||||
$documentationLink = $urlGenerator->linkToDocs('admin-sharing-federated') . '#configuring-trusted-nextcloud-servers';
|
||||
$documentationLabel = $l->t('External documentation for Federated Cloud Sharing');
|
||||
?>
|
||||
<div id="ocFederationSettings" class="section">
|
||||
<h2><?php p($l->t('Trusted servers')); ?></h2>
|
||||
<h2>
|
||||
<?php p($l->t('Trusted servers')); ?>
|
||||
<a target="_blank" rel="noreferrer noopener" class="icon-info"
|
||||
title="<?php p($documentationLabel);?>"
|
||||
href="<?php p($documentationLink); ?>"></a>
|
||||
</h2>
|
||||
<p class="settings-hint"><?php p($l->t('Federation allows you to connect with other trusted servers to exchange the account directory. For example this will be used to auto-complete external accounts for federated sharing. It is not necessary to add a server as trusted server in order to create a federated share.')); ?></p>
|
||||
<p class="settings-hint"><?php p($l->t('Each server must validate the other. This process may require a few cron cycles.')); ?></p>
|
||||
|
||||
<ul id="listOfTrustedServers">
|
||||
<?php foreach ($_['trustedServers'] as $trustedServer) { ?>
|
||||
|
|
@ -35,8 +49,9 @@ style('federation', 'settings-admin')
|
|||
</li>
|
||||
<?php } ?>
|
||||
</ul>
|
||||
<p id="ocFederationAddServer">
|
||||
<button id="ocFederationAddServerButton" class=""><?php p($l->t('+ Add trusted server')); ?></button>
|
||||
|
||||
<div id="ocFederationAddServer">
|
||||
<button id="ocFederationAddServerButton"><?php p($l->t('+ Add trusted server')); ?></button>
|
||||
<div class="serverUrl hidden">
|
||||
<div class="serverUrl-block">
|
||||
<label for="serverUrl"><?php p($l->t('Trusted server')); ?></label>
|
||||
|
|
@ -45,6 +60,5 @@ style('federation', 'settings-admin')
|
|||
</div>
|
||||
<span class="msg"></span>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -17,8 +17,10 @@ use OCP\BackgroundJob\IJobList;
|
|||
use OCP\Http\Client\IClient;
|
||||
use OCP\Http\Client\IClientService;
|
||||
use OCP\Http\Client\IResponse;
|
||||
use OCP\IConfig;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\OCS\IDiscoveryService;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
|
|
@ -30,32 +32,16 @@ use Psr\Log\LoggerInterface;
|
|||
*/
|
||||
class GetSharedSecretTest extends TestCase {
|
||||
|
||||
/** @var \PHPUnit\Framework\MockObject\MockObject|IClient */
|
||||
private $httpClient;
|
||||
|
||||
/** @var \PHPUnit\Framework\MockObject\MockObject|IClientService */
|
||||
private $httpClientService;
|
||||
|
||||
/** @var \PHPUnit\Framework\MockObject\MockObject|IJobList */
|
||||
private $jobList;
|
||||
|
||||
/** @var \PHPUnit\Framework\MockObject\MockObject|IURLGenerator */
|
||||
private $urlGenerator;
|
||||
|
||||
/** @var \PHPUnit\Framework\MockObject\MockObject|TrustedServers */
|
||||
private $trustedServers;
|
||||
|
||||
/** @var \PHPUnit\Framework\MockObject\MockObject|LoggerInterface */
|
||||
private $logger;
|
||||
|
||||
/** @var \PHPUnit\Framework\MockObject\MockObject|IResponse */
|
||||
private $response;
|
||||
|
||||
/** @var \PHPUnit\Framework\MockObject\MockObject|IDiscoveryService */
|
||||
private $discoverService;
|
||||
|
||||
/** @var \PHPUnit\Framework\MockObject\MockObject|ITimeFactory */
|
||||
private $timeFactory;
|
||||
private MockObject&IClient $httpClient;
|
||||
private MockObject&IClientService $httpClientService;
|
||||
private MockObject&IJobList $jobList;
|
||||
private MockObject&IURLGenerator $urlGenerator;
|
||||
private MockObject&TrustedServers $trustedServers;
|
||||
private MockObject&LoggerInterface $logger;
|
||||
private MockObject&IResponse $response;
|
||||
private MockObject&IDiscoveryService $discoverService;
|
||||
private MockObject&ITimeFactory $timeFactory;
|
||||
private MockObject&IConfig $config;
|
||||
|
||||
private GetSharedSecret $getSharedSecret;
|
||||
|
||||
|
|
@ -72,6 +58,7 @@ class GetSharedSecretTest extends TestCase {
|
|||
$this->response = $this->getMockBuilder(IResponse::class)->getMock();
|
||||
$this->discoverService = $this->getMockBuilder(IDiscoveryService::class)->getMock();
|
||||
$this->timeFactory = $this->createMock(ITimeFactory::class);
|
||||
$this->config = $this->createMock(IConfig::class);
|
||||
|
||||
$this->discoverService->expects($this->any())->method('discover')->willReturn([]);
|
||||
$this->httpClientService->expects($this->any())->method('newClient')->willReturn($this->httpClient);
|
||||
|
|
@ -83,7 +70,8 @@ class GetSharedSecretTest extends TestCase {
|
|||
$this->trustedServers,
|
||||
$this->logger,
|
||||
$this->discoverService,
|
||||
$this->timeFactory
|
||||
$this->timeFactory,
|
||||
$this->config,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -104,7 +92,8 @@ class GetSharedSecretTest extends TestCase {
|
|||
$this->trustedServers,
|
||||
$this->logger,
|
||||
$this->discoverService,
|
||||
$this->timeFactory
|
||||
$this->timeFactory,
|
||||
$this->config,
|
||||
]
|
||||
)->setMethods(['parentStart'])->getMock();
|
||||
$this->invokePrivate($getSharedSecret, 'argument', [['url' => 'url', 'token' => 'token']]);
|
||||
|
|
@ -176,6 +165,7 @@ class GetSharedSecretTest extends TestCase {
|
|||
],
|
||||
'timeout' => 3,
|
||||
'connect_timeout' => 3,
|
||||
'verify' => true,
|
||||
]
|
||||
)->willReturn($this->response);
|
||||
|
||||
|
|
@ -267,6 +257,7 @@ class GetSharedSecretTest extends TestCase {
|
|||
],
|
||||
'timeout' => 3,
|
||||
'connect_timeout' => 3,
|
||||
'verify' => true,
|
||||
]
|
||||
)->willThrowException($this->createMock(ConnectException::class));
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ use OCP\BackgroundJob\IJobList;
|
|||
use OCP\Http\Client\IClient;
|
||||
use OCP\Http\Client\IClientService;
|
||||
use OCP\Http\Client\IResponse;
|
||||
use OCP\IConfig;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\OCS\IDiscoveryService;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
|
|
@ -50,6 +51,9 @@ class RequestSharedSecretTest extends TestCase {
|
|||
/** @var MockObject|ITimeFactory */
|
||||
private $timeFactory;
|
||||
|
||||
/** @var MockObject|IConfig */
|
||||
private $config;
|
||||
|
||||
/** @var RequestSharedSecret */
|
||||
private $requestSharedSecret;
|
||||
|
||||
|
|
@ -66,6 +70,7 @@ class RequestSharedSecretTest extends TestCase {
|
|||
$this->discoveryService = $this->getMockBuilder(IDiscoveryService::class)->getMock();
|
||||
$this->logger = $this->createMock(LoggerInterface::class);
|
||||
$this->timeFactory = $this->createMock(ITimeFactory::class);
|
||||
$this->config = $this->createMock(IConfig::class);
|
||||
|
||||
$this->discoveryService->expects($this->any())->method('discover')->willReturn([]);
|
||||
$this->httpClientService->expects($this->any())->method('newClient')->willReturn($this->httpClient);
|
||||
|
|
@ -77,7 +82,8 @@ class RequestSharedSecretTest extends TestCase {
|
|||
$this->trustedServers,
|
||||
$this->discoveryService,
|
||||
$this->logger,
|
||||
$this->timeFactory
|
||||
$this->timeFactory,
|
||||
$this->config,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -98,7 +104,8 @@ class RequestSharedSecretTest extends TestCase {
|
|||
$this->trustedServers,
|
||||
$this->discoveryService,
|
||||
$this->logger,
|
||||
$this->timeFactory
|
||||
$this->timeFactory,
|
||||
$this->config,
|
||||
]
|
||||
)->setMethods(['parentStart'])->getMock();
|
||||
$this->invokePrivate($requestSharedSecret, 'argument', [['url' => 'url', 'token' => 'token']]);
|
||||
|
|
@ -170,6 +177,7 @@ class RequestSharedSecretTest extends TestCase {
|
|||
],
|
||||
'timeout' => 3,
|
||||
'connect_timeout' => 3,
|
||||
'verify' => true,
|
||||
]
|
||||
)->willReturn($this->response);
|
||||
|
||||
|
|
@ -255,6 +263,7 @@ class RequestSharedSecretTest extends TestCase {
|
|||
],
|
||||
'timeout' => 3,
|
||||
'connect_timeout' => 3,
|
||||
'verify' => true,
|
||||
]
|
||||
)->willThrowException($this->createMock(ConnectException::class));
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
|
||||
|
|
@ -10,22 +9,21 @@ namespace OCA\Federation\Tests\Controller;
|
|||
use OCA\Federation\Controller\SettingsController;
|
||||
use OCA\Federation\TrustedServers;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\HintException;
|
||||
use OCP\AppFramework\OCS\OCSException;
|
||||
use OCP\AppFramework\OCS\OCSNotFoundException;
|
||||
use OCP\IL10N;
|
||||
use OCP\IRequest;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Test\TestCase;
|
||||
|
||||
class SettingsControllerTest extends TestCase {
|
||||
private SettingsController $controller;
|
||||
|
||||
/** @var \PHPUnit\Framework\MockObject\MockObject|IRequest */
|
||||
private $request;
|
||||
|
||||
/** @var \PHPUnit\Framework\MockObject\MockObject|IL10N */
|
||||
private $l10n;
|
||||
|
||||
/** @var \PHPUnit\Framework\MockObject\MockObject|TrustedServers */
|
||||
private $trustedServers;
|
||||
private MockObject&IRequest $request;
|
||||
private MockObject&IL10N $l10n;
|
||||
private MockObject&TrustedServers $trustedServers;
|
||||
private MockObject&LoggerInterface $logger;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
|
@ -34,12 +32,14 @@ class SettingsControllerTest extends TestCase {
|
|||
$this->l10n = $this->getMockBuilder(IL10N::class)->getMock();
|
||||
$this->trustedServers = $this->getMockBuilder(TrustedServers::class)
|
||||
->disableOriginalConstructor()->getMock();
|
||||
$this->logger = $this->getMockBuilder(LoggerInterface::class)->getMock();
|
||||
|
||||
$this->controller = new SettingsController(
|
||||
'SettingsControllerTest',
|
||||
$this->request,
|
||||
$this->l10n,
|
||||
$this->trustedServers
|
||||
$this->trustedServers,
|
||||
$this->logger,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -68,8 +68,6 @@ class SettingsControllerTest extends TestCase {
|
|||
* @dataProvider checkServerFails
|
||||
*/
|
||||
public function testAddServerFail(bool $isTrustedServer, bool $isNextcloud): void {
|
||||
$this->expectException(HintException::class);
|
||||
|
||||
$this->trustedServers
|
||||
->expects($this->any())
|
||||
->method('isTrustedServer')
|
||||
|
|
@ -81,6 +79,12 @@ class SettingsControllerTest extends TestCase {
|
|||
->with('url')
|
||||
->willReturn($isNextcloud);
|
||||
|
||||
if ($isTrustedServer) {
|
||||
$this->expectException(OCSException::class);
|
||||
} else {
|
||||
$this->expectException(OCSNotFoundException::class);
|
||||
}
|
||||
|
||||
$this->controller->addServer('url');
|
||||
}
|
||||
|
||||
|
|
@ -105,7 +109,7 @@ class SettingsControllerTest extends TestCase {
|
|||
->with('url')
|
||||
->willReturn(true);
|
||||
|
||||
$this->assertTrue(
|
||||
$this->assertNull(
|
||||
$this->invokePrivate($this->controller, 'checkServer', ['url'])
|
||||
);
|
||||
}
|
||||
|
|
@ -114,8 +118,6 @@ class SettingsControllerTest extends TestCase {
|
|||
* @dataProvider checkServerFails
|
||||
*/
|
||||
public function testCheckServerFail(bool $isTrustedServer, bool $isNextcloud): void {
|
||||
$this->expectException(HintException::class);
|
||||
|
||||
$this->trustedServers
|
||||
->expects($this->any())
|
||||
->method('isTrustedServer')
|
||||
|
|
@ -127,6 +129,12 @@ class SettingsControllerTest extends TestCase {
|
|||
->with('url')
|
||||
->willReturn($isNextcloud);
|
||||
|
||||
if ($isTrustedServer) {
|
||||
$this->expectException(OCSException::class);
|
||||
} else {
|
||||
$this->expectException(OCSNotFoundException::class);
|
||||
}
|
||||
|
||||
$this->assertTrue(
|
||||
$this->invokePrivate($this->controller, 'checkServer', ['url'])
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,81 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
namespace OCA\Federation\Tests\Middleware;
|
||||
|
||||
use OCA\Federation\Controller\SettingsController;
|
||||
use OCA\Federation\Middleware\AddServerMiddleware;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\HintException;
|
||||
use OCP\IL10N;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Test\TestCase;
|
||||
|
||||
class AddServerMiddlewareTest extends TestCase {
|
||||
|
||||
/** @var \PHPUnit\Framework\MockObject\MockObject | LoggerInterface */
|
||||
private $logger;
|
||||
|
||||
/** @var \PHPUnit\Framework\MockObject\MockObject|IL10N */
|
||||
private $l10n;
|
||||
|
||||
private AddServerMiddleware $middleware;
|
||||
|
||||
/** @var \PHPUnit\Framework\MockObject\MockObject | SettingsController */
|
||||
private $controller;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->logger = $this->getMockBuilder(LoggerInterface::class)->getMock();
|
||||
$this->l10n = $this->getMockBuilder(IL10N::class)->getMock();
|
||||
$this->controller = $this->getMockBuilder(SettingsController::class)
|
||||
->disableOriginalConstructor()->getMock();
|
||||
|
||||
$this->middleware = new AddServerMiddleware(
|
||||
'AddServerMiddlewareTest',
|
||||
$this->l10n,
|
||||
$this->logger
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataTestAfterException
|
||||
*
|
||||
* @param \Exception $exception
|
||||
* @param string $hint
|
||||
*/
|
||||
public function testAfterException($exception, $hint): void {
|
||||
$this->logger->expects($this->once())->method('error');
|
||||
|
||||
$this->l10n->expects($this->any())->method('t')
|
||||
->willReturnCallback(
|
||||
function (string $message): string {
|
||||
return $message;
|
||||
}
|
||||
);
|
||||
|
||||
$result = $this->middleware->afterException($this->controller, 'method', $exception);
|
||||
|
||||
$this->assertSame(Http::STATUS_BAD_REQUEST,
|
||||
$result->getStatus()
|
||||
);
|
||||
|
||||
$data = $result->getData();
|
||||
|
||||
$this->assertSame($hint,
|
||||
$data['message']
|
||||
);
|
||||
}
|
||||
|
||||
public function dataTestAfterException() {
|
||||
return [
|
||||
[new HintException('message', 'hint'), 'hint'],
|
||||
[new \Exception('message'), 'message'],
|
||||
];
|
||||
}
|
||||
}
|
||||
89
apps/files_sharing/lib/External/Manager.php
vendored
89
apps/files_sharing/lib/External/Manager.php
vendored
|
|
@ -129,7 +129,7 @@ class Manager {
|
|||
'mountpoint' => $mountPoint,
|
||||
'owner' => $owner
|
||||
];
|
||||
return $this->mountShare($options);
|
||||
return $this->mountShare($options, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -214,11 +214,12 @@ class Manager {
|
|||
* @param int $id share id
|
||||
* @return mixed share of false
|
||||
*/
|
||||
public function getShare($id) {
|
||||
public function getShare(int $id, ?string $user = null): array|false {
|
||||
$user = $user ?? $this->uid;
|
||||
$share = $this->fetchShare($id);
|
||||
|
||||
// check if the user is allowed to access it
|
||||
if ($this->canAccessShare($share)) {
|
||||
if ($this->canAccessShare($share, $user)) {
|
||||
return $share;
|
||||
}
|
||||
|
||||
|
|
@ -243,7 +244,7 @@ class Manager {
|
|||
return $share;
|
||||
}
|
||||
|
||||
private function canAccessShare(array $share): bool {
|
||||
private function canAccessShare(array $share, string $user): bool {
|
||||
$validShare = isset($share['share_type']) && isset($share['user']);
|
||||
|
||||
if (!$validShare) {
|
||||
|
|
@ -252,7 +253,7 @@ class Manager {
|
|||
|
||||
// If the share is a user share, check if the user is the recipient
|
||||
if ((int)$share['share_type'] === IShare::TYPE_USER
|
||||
&& $share['user'] === $this->uid) {
|
||||
&& $share['user'] === $user) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -266,7 +267,7 @@ class Manager {
|
|||
$groupShare = $share;
|
||||
}
|
||||
|
||||
$user = $this->userManager->get($this->uid);
|
||||
$user = $this->userManager->get($user);
|
||||
if ($this->groupManager->get($groupShare['user'])->inGroup($user)) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -295,13 +296,22 @@ class Manager {
|
|||
* @param int $id
|
||||
* @return bool True if the share could be accepted, false otherwise
|
||||
*/
|
||||
public function acceptShare($id) {
|
||||
$share = $this->getShare($id);
|
||||
public function acceptShare(int $id, ?string $user = null) {
|
||||
// If we're auto-accepting a share, we need to know the user id
|
||||
// as there is no session available while processing the share
|
||||
// from the remote server request.
|
||||
$user = $user ?? $this->uid;
|
||||
if ($user === null) {
|
||||
$this->logger->error('No user specified for accepting share');
|
||||
return false;
|
||||
}
|
||||
|
||||
$share = $this->getShare($id, $user);
|
||||
$result = false;
|
||||
|
||||
if ($share) {
|
||||
\OC_Util::setupFS($this->uid);
|
||||
$shareFolder = Helper::getShareFolder(null, $this->uid);
|
||||
\OC_Util::setupFS($user);
|
||||
$shareFolder = Helper::getShareFolder(null, $user);
|
||||
$mountPoint = Files::buildNotExistingFileName($shareFolder, $share['name']);
|
||||
$mountPoint = Filesystem::normalizePath($mountPoint);
|
||||
$hash = md5($mountPoint);
|
||||
|
|
@ -314,14 +324,14 @@ class Manager {
|
|||
`mountpoint` = ?,
|
||||
`mountpoint_hash` = ?
|
||||
WHERE `id` = ? AND `user` = ?');
|
||||
$userShareAccepted = $acceptShare->execute([1, $mountPoint, $hash, $id, $this->uid]);
|
||||
$userShareAccepted = $acceptShare->execute([1, $mountPoint, $hash, $id, $user]);
|
||||
} else {
|
||||
$parentId = (int)$share['parent'];
|
||||
if ($parentId !== -1) {
|
||||
// this is the sub-share
|
||||
$subshare = $share;
|
||||
} else {
|
||||
$subshare = $this->fetchUserShare($id, $this->uid);
|
||||
$subshare = $this->fetchUserShare($id, $user);
|
||||
}
|
||||
|
||||
if ($subshare !== null) {
|
||||
|
|
@ -332,7 +342,7 @@ class Manager {
|
|||
`mountpoint` = ?,
|
||||
`mountpoint_hash` = ?
|
||||
WHERE `id` = ? AND `user` = ?');
|
||||
$acceptShare->execute([1, $mountPoint, $hash, $subshare['id'], $this->uid]);
|
||||
$acceptShare->execute([1, $mountPoint, $hash, $subshare['id'], $user]);
|
||||
$result = true;
|
||||
} catch (Exception $e) {
|
||||
$this->logger->emergency('Could not update share', ['exception' => $e]);
|
||||
|
|
@ -346,7 +356,7 @@ class Manager {
|
|||
$share['password'],
|
||||
$share['name'],
|
||||
$share['owner'],
|
||||
$this->uid,
|
||||
$user,
|
||||
$mountPoint, $hash, 1,
|
||||
$share['remote_id'],
|
||||
$id,
|
||||
|
|
@ -358,17 +368,18 @@ class Manager {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($userShareAccepted !== false) {
|
||||
$this->sendFeedbackToRemote($share['remote'], $share['share_token'], $share['remote_id'], 'accept');
|
||||
$event = new FederatedShareAddedEvent($share['remote']);
|
||||
$this->eventDispatcher->dispatchTyped($event);
|
||||
$this->eventDispatcher->dispatchTyped(new InvalidateMountCacheEvent($this->userManager->get($this->uid)));
|
||||
$this->eventDispatcher->dispatchTyped(new InvalidateMountCacheEvent($this->userManager->get($user)));
|
||||
$result = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the user has no notification for something that does not exist anymore.
|
||||
$this->processNotification($id);
|
||||
$this->processNotification($id, $user);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
|
@ -379,17 +390,23 @@ class Manager {
|
|||
* @param int $id
|
||||
* @return bool True if the share could be declined, false otherwise
|
||||
*/
|
||||
public function declineShare($id) {
|
||||
$share = $this->getShare($id);
|
||||
public function declineShare(int $id, ?string $user = null) {
|
||||
$user = $user ?? $this->uid;
|
||||
if ($user === null) {
|
||||
$this->logger->error('No user specified for declining share');
|
||||
return false;
|
||||
}
|
||||
|
||||
$share = $this->getShare($id, $user);
|
||||
$result = false;
|
||||
|
||||
if ($share && (int)$share['share_type'] === IShare::TYPE_USER) {
|
||||
$removeShare = $this->connection->prepare('
|
||||
DELETE FROM `*PREFIX*share_external` WHERE `id` = ? AND `user` = ?');
|
||||
$removeShare->execute([$id, $this->uid]);
|
||||
$removeShare->execute([$id, $user]);
|
||||
$this->sendFeedbackToRemote($share['remote'], $share['share_token'], $share['remote_id'], 'decline');
|
||||
|
||||
$this->processNotification($id);
|
||||
$this->processNotification($id, $user);
|
||||
$result = true;
|
||||
} elseif ($share && (int)$share['share_type'] === IShare::TYPE_GROUP) {
|
||||
$parentId = (int)$share['parent'];
|
||||
|
|
@ -397,7 +414,7 @@ class Manager {
|
|||
// this is the sub-share
|
||||
$subshare = $share;
|
||||
} else {
|
||||
$subshare = $this->fetchUserShare($id, $this->uid);
|
||||
$subshare = $this->fetchUserShare($id, $user);
|
||||
}
|
||||
|
||||
if ($subshare !== null) {
|
||||
|
|
@ -416,7 +433,7 @@ class Manager {
|
|||
$share['password'],
|
||||
$share['name'],
|
||||
$share['owner'],
|
||||
$this->uid,
|
||||
$user,
|
||||
$share['mountpoint'],
|
||||
$share['mountpoint_hash'],
|
||||
0,
|
||||
|
|
@ -429,16 +446,27 @@ class Manager {
|
|||
$result = false;
|
||||
}
|
||||
}
|
||||
$this->processNotification($id);
|
||||
$this->processNotification($id, $user);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function processNotification(int $remoteShare): void {
|
||||
public function processNotification(int $remoteShare, ?string $user = null): void {
|
||||
$user = $user ?? $this->uid;
|
||||
if ($user === null) {
|
||||
$this->logger->error('No user specified for processing notification');
|
||||
return;
|
||||
}
|
||||
|
||||
$share = $this->fetchShare($remoteShare);
|
||||
if ($share === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$filter = $this->notificationManager->createNotification();
|
||||
$filter->setApp('files_sharing')
|
||||
->setUser($this->uid)
|
||||
->setUser($user)
|
||||
->setObject('remote_share', (string)$remoteShare);
|
||||
$this->notificationManager->markProcessed($filter);
|
||||
}
|
||||
|
|
@ -538,9 +566,10 @@ class Manager {
|
|||
return rtrim(substr($path, strlen($prefix)), '/');
|
||||
}
|
||||
|
||||
public function getMount($data) {
|
||||
public function getMount($data, ?string $user = null) {
|
||||
$user = $user ?? $this->uid;
|
||||
$data['manager'] = $this;
|
||||
$mountPoint = '/' . $this->uid . '/files' . $data['mountpoint'];
|
||||
$mountPoint = '/' . $user . '/files' . $data['mountpoint'];
|
||||
$data['mountpoint'] = $mountPoint;
|
||||
$data['certificateManager'] = \OC::$server->getCertificateManager();
|
||||
return new Mount(self::STORAGE, $mountPoint, $data, $this, $this->storageLoader);
|
||||
|
|
@ -550,8 +579,8 @@ class Manager {
|
|||
* @param array $data
|
||||
* @return Mount
|
||||
*/
|
||||
protected function mountShare($data) {
|
||||
$mount = $this->getMount($data);
|
||||
protected function mountShare($data, ?string $user = null) {
|
||||
$mount = $this->getMount($data, $user);
|
||||
$this->mountManager->addMount($mount);
|
||||
return $mount;
|
||||
}
|
||||
|
|
@ -768,6 +797,8 @@ class Manager {
|
|||
* @return list<Files_SharingRemoteShare> list of open server-to-server shares
|
||||
*/
|
||||
private function getShares($accepted) {
|
||||
// Not allowing providing a user here,
|
||||
// as we only want to retrieve shares for the current user.
|
||||
$user = $this->userManager->get($this->uid);
|
||||
$groups = $this->groupManager->getUserGroups($user);
|
||||
$userGroups = [];
|
||||
|
|
|
|||
|
|
@ -294,6 +294,20 @@ describe('SharingService share to Node mapping', () => {
|
|||
accepted: true,
|
||||
}
|
||||
|
||||
const tempExternalFile = {
|
||||
id: 65,
|
||||
share_type: 0,
|
||||
parent: -1,
|
||||
remote: 'http://nextcloud1.local/',
|
||||
remote_id: '71',
|
||||
share_token: '9GpiAmTIjayclrE',
|
||||
name: '/test.md',
|
||||
owner: 'owner-uid',
|
||||
user: 'sharee-uid',
|
||||
mountpoint: '{{TemporaryMountPointName#/test.md}}',
|
||||
accepted: 0,
|
||||
}
|
||||
|
||||
beforeEach(() => { vi.resetAllMocks() })
|
||||
|
||||
test('File', async () => {
|
||||
|
|
@ -384,6 +398,35 @@ describe('SharingService share to Node mapping', () => {
|
|||
expect(file.attributes.favorite).toBe(0)
|
||||
})
|
||||
|
||||
test('External temp file', async () => {
|
||||
axios.get.mockReturnValueOnce(Promise.resolve({
|
||||
data: {
|
||||
ocs: {
|
||||
data: [tempExternalFile],
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
const shares = await getContents(false, true, false, false)
|
||||
|
||||
expect(axios.get).toHaveBeenCalledTimes(1)
|
||||
expect(shares.contents).toHaveLength(1)
|
||||
|
||||
const file = shares.contents[0] as File
|
||||
expect(file).toBeInstanceOf(File)
|
||||
expect(file.fileid).toBe(65)
|
||||
expect(file.source).toBe('http://nextcloud.local/remote.php/dav/files/test/test.md')
|
||||
expect(file.owner).toBe('owner-uid')
|
||||
expect(file.mime).toBe('text/markdown')
|
||||
expect(file.mtime?.getTime()).toBe(undefined)
|
||||
// not available for remote shares
|
||||
expect(file.size).toBe(undefined)
|
||||
expect(file.permissions).toBe(0)
|
||||
expect(file.root).toBe('/files/test')
|
||||
expect(file.attributes).toBeInstanceOf(Object)
|
||||
expect(file.attributes.favorite).toBe(0)
|
||||
})
|
||||
|
||||
test('Empty', async () => {
|
||||
vi.spyOn(logger, 'error').mockImplementationOnce(() => {})
|
||||
axios.get.mockReturnValueOnce(Promise.resolve({
|
||||
|
|
|
|||
|
|
@ -36,6 +36,10 @@ const ocsEntryToNode = async function(ocsEntry: any): Promise<Folder | File | nu
|
|||
ocsEntry.item_mtime = ocsEntry.mtime
|
||||
ocsEntry.file_target = ocsEntry.file_target || ocsEntry.mountpoint
|
||||
|
||||
if (ocsEntry.file_target.includes('TemporaryMountPointName')) {
|
||||
ocsEntry.file_target = ocsEntry.name
|
||||
}
|
||||
|
||||
// Need to set permissions to NONE for federated shares
|
||||
ocsEntry.item_permissions = Permission.NONE
|
||||
ocsEntry.permissions = Permission.NONE
|
||||
|
|
|
|||
|
|
@ -645,10 +645,10 @@ class ManagerTest extends TestCase {
|
|||
'user' => 'user2',
|
||||
'remoteId' => '2342'
|
||||
];
|
||||
$this->assertSame(null, call_user_func_array([$manager2, 'addShare'], $shareData2));
|
||||
|
||||
$user2Shares = $manager2->getOpenShares();
|
||||
$this->assertCount(2, $user2Shares);
|
||||
$this->assertCount(1, $manager2->getOpenShares());
|
||||
$this->assertSame(null, call_user_func_array([$manager2, 'addShare'], $shareData2));
|
||||
$this->assertCount(2, $manager2->getOpenShares());
|
||||
|
||||
$this->manager->expects($this->once())->method('tryOCMEndPoint')->with('http://localhost', 'token1', '2342', 'decline')->willReturn([]);
|
||||
$this->manager->removeUserShares($this->uid);
|
||||
|
|
@ -690,10 +690,10 @@ class ManagerTest extends TestCase {
|
|||
'user' => 'user2',
|
||||
'remoteId' => '2342'
|
||||
];
|
||||
$this->assertSame(null, call_user_func_array([$manager2, 'addShare'], $shareData2));
|
||||
|
||||
$user2Shares = $manager2->getOpenShares();
|
||||
$this->assertCount(2, $user2Shares);
|
||||
$this->assertCount(1, $manager2->getOpenShares());
|
||||
$this->assertSame(null, call_user_func_array([$manager2, 'addShare'], $shareData2));
|
||||
$this->assertCount(2, $manager2->getOpenShares());
|
||||
|
||||
$this->manager->expects($this->never())->method('tryOCMEndPoint');
|
||||
$this->manager->removeGroupShares('group1');
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1 +1 @@
|
|||
{"version":3,"sourceRoot":"","sources":["settings.scss","../../../core/css/variables.scss","../../../core/css/functions.scss"],"names":[],"mappings":"AAAA;AAAA;AAAA;AAAA;AAAA,GCEA;AAAA;AAAA;AAAA,GCFA;AAAA;AAAA;AAAA,GFUC,0BACC,WAKF,OACC,WAID,4BE2BC,2CFvBD,mBEuBC,kDFnBD,qBEmBC,yCFfD,0BEeC,wCFXD,oEEWC,2CFPD,oCACC,oBACA,0BACA,+BACA,mBAGD,4BACC,oBACA,kCAGD,yBACC,WAIA,wCACC,kBACA,yDACC,gBAIA,mOACC,WAKH,uCACC,aAGD,sCACC,WAED,uDACC,WAKD,gBACC,WAIF,mBACC,aACA,aACA,iBACA,uEACA,qBAEA,4BACC,kBACA,SAEA,+BACC,mBAIA,qCACC,iBAKH,kCACC,sBACA,mBACA,gBAGD,mGACC,4BACA,0BACA,WAMF,oBACC,kBACA,wCACC,0BAIF,aACC,oBACA,4CACA,kFACA,8CACA,wCACA,2CACA,8CACA,6CACA,mBACA,yCAEA,sCAEC,oDAGD,+CAEC,6DACA,oDAGD,6BACC,qCACA,WACA,YAIF,6BACC,oBACA,kCAEA,mCACC,WAIA,oCACC,kBACA,oBACA,iBACA,2BACA,WACA,mBACA,QAEA,0CACC,mBACA,uBACA,gBAKD,gIACC,kBACA,qBACA,UACA,oBACA,YAKH,qCACC,kBACA,wBACA,MACA,SAEA,yCACC,qBAIF,4CACC,eAGD,4CACC,sBACA,WACA,YACA,YAMF,qBACC,aACA,sBACA,SACA,YAEA,uBACC,aAGD,uCACC,sBACA,cACA,yBAIF,iBACC,kBACA,eACA,oCACA,qCACA,6CACA,SACA,gBACA,YAEA,8CAEC,+CACA,2CAEA,0FACC,WAIF,uCACC,0BACA,qBACA,gCACA,WACA,eAEA,wDACC,qBACA,sBACA,eAIF,sCACC,kCAGC,4DAEC,iBACA,kBAEA,kFACC,YAGD,mEACC,oDAEA,kFACC,iBAIF,qEACC,WAEA,eAEA,uEACC,eAQN,gBACC,YAIA,2BACC,kCAGD,mBACC,YAIF,sCAEC,aAGD,eACC,WAGD,YACC,qBAIA,aACC,WACA,yBACA,YAGD,WACC,WACA,yBACA,YAMD,oBACC,sBAGD,iBACC,eAKD,iCACC,aACA,eACA,sBACA,SACA,gDACC,aACA,eACA,sBACA,sDACC,oBAIF,kGACC,cACA,YACA,gBAKA,iEACC,kBACA,UAED,+EACC,oBACA,oBACA,wBACA,qBAIF,wCACC,WAGD,iDACC,qBAGD,sDACC,kBACA,qBACA,WACA,0BACA,eACA,gBACA,WAQF,oBACC,gBAGD,wBACC,yBAGD,oDACC,WACA,YACA,wCAOD,oBACC,UACA,cACA,gBACA,uBAGD,2BACC,UAKD,oCAEC,cAKD,wEAEC,aAIF,gBACC,kBACA,QACA,mBAEA,sBACC,YAGD,sBACC,iBAKF,WACC,WAEA,cACC,WACA,UACA,uBACA,4CACA,iBACA,mBAGD,cACC,4CACA,UACA,uBACA,iBACA,mBAKD,gBACC,0BACA,cACA,eACA,uBACA,gBAGD,wBACC,0BAEA,gCACC,kBAIF,sCACC,kBAGD,sDAEC,cACA,eACA,eAEA,0EACC,UACA,qBACA,uBACA,gBAIF,8BACC,eAGD,kCACC,wBACA,cAIF,2BACC,mBAMA,oBACC,mBACA,sBACA,WAGD,gCACC,0BAIA,gGACC,cAMH,SACC,gBAEA,0BACC,4CAID,YACC,mBAEA,uBACC,iBACA,2BACA,qBAMH,KACC,mBACA,mBAGD,SACC,aAGD,mBACC,mBAGD,eACC,gBAOA,+IACC,sBAEA,+KACC,aAGD,mKACC,WACA,YACA,kCACA,qBACA,kBAGD,mOACC,sCAGD,mNACC,sCAGD,mNACC,oCAMF,sBACC,aAGD,YACC,oBAGD,kBACC,0BAGD,yBACC,0BAGD,sBACC,0BAGD,oCACC,uBAIF,yCACC,uBAGD,wBACC,qBAGD,2BACC,wBAEA,gBACA,aACA,yBACA,sBAKD,WACC,kBACA,2BACA,WAGD,2DAGC,qBAIA,mCACC,qBACA,YACA,eAGD,+EAEC,YAIF,yBACC,mCACC,YACA,iBACA,cACA,iDAIF,eACC,WAGD,SACC,yBAGD,QACC,qBACA,YACA,WACA,2BAEA,gBACC,kBAIF,qBACC,sBACA,qBACA,YACA,iBAGD,kBACC,qBACA,gBAIA,aACC,sCACA,mCAGD,WACC,oCAGD,mBACC,sCACA,oBAMF,8CACC,yBACA,YAGD,wBACC,WACA,YACA,mBACA,kBACA,+DAIA,oBACC,yBACA,gBAEA,uBACC,cAGD,uBACC,kBAIF,0BACC,YACA,gCAGD,oDACC,yBAGD,wDACC,2BAGD,uBACC,cAKD,oBACC,0BAGD,oCACC,gBAIF,2BACC,aACA,eACA,mDAEA,8BACC,kBAGD,6BACC,WAIF,eACC,mBAEA,iBACC,qBACA,cAIF,SACC,UAGD,eACC,iBACA,mBACA,WAGD,UACI,+CAGJ,2BACE,GACE,YAGJ,mCACE,GACE","file":"settings.css"}
|
||||
{"version":3,"sourceRoot":"","sources":["settings.scss","../../../core/css/variables.scss","../../../core/css/functions.scss"],"names":[],"mappings":"AAAA;AAAA;AAAA;AAAA;AAAA,GCEA;AAAA;AAAA;AAAA,GCFA;AAAA;AAAA;AAAA,GFUC,0BACC,WAKF,OACC,WAID,4BE2BC,2CFvBD,mBEuBC,kDFnBD,qBEmBC,yCFfD,0BEeC,wCFXD,oEEWC,2CFPD,oCACC,oBACA,0BACA,+BACA,mBAGD,4BACC,oBACA,kCAGD,yBACC,WAIA,wCACC,kBACA,yDACC,gBAIA,mOACC,WAKH,uCACC,aAGD,sCACC,WAED,uDACC,WAKD,gBACC,WAIF,mBACC,aACA,aACA,iBACA,uEACA,qBAEA,4BACC,kBACA,SAEA,+BACC,mBAIA,qCACC,iBAKH,kCACC,sBACA,mBACA,gBAGD,mGACC,4BACA,0BACA,WAMF,oBACC,kBACA,wCACC,0BAIF,aACC,oBACA,4CACA,kFACA,8CACA,wCACA,2CACA,8CACA,6CACA,mBACA,yCAEA,sCAEC,oDAGD,+CAEC,6DACA,oDAGD,6BACC,qCACA,WACA,YAIF,6BACC,oBACA,kCAEA,mCACC,WAIA,oCACC,kBACA,oBACA,iBACA,2BACA,WACA,mBACA,QAEA,0CACC,mBACA,uBACA,gBAKD,gIACC,kBACA,qBACA,UACA,oBACA,YAKH,qCACC,kBACA,wBACA,MACA,SAEA,yCACC,qBAIF,4CACC,eAGD,4CACC,sBACA,WACA,YACA,YAMF,qBACC,aACA,sBACA,SACA,YAEA,uBACC,aAGD,uCACC,sBACA,cACA,yBAIF,iBACC,kBACA,eACA,oCACA,qCACA,6CACA,SACA,gBACA,YAEA,8CAEC,+CACA,2CAEA,0FACC,WAIF,uCACC,0BACA,qBACA,gCACA,WACA,eAEA,wDACC,qBACA,sBACA,eAIF,sCACC,kCAGC,4DAEC,iBACA,kBAEA,kFACC,YAGD,mEACC,oDAEA,kFACC,iBAIF,qEACC,WAEA,eAEA,uEACC,eAQN,gBACC,YAIA,2BACC,kCAGD,mBACC,YAIF,sCAEC,aAGD,eACC,WAGD,YACC,qBAIA,aACC,WACA,yBACA,YAGD,WACC,WACA,yBACA,YAMD,oBACC,sBAGD,iBACC,eAKD,iCACC,aACA,eACA,sBACA,SACA,gDACC,aACA,eACA,sBACA,sDACC,oBAIF,kGACC,cACA,YACA,gBAKA,iEACC,kBACA,UAED,+EACC,oBACA,oBACA,wBACA,qBAIF,wCACC,WAGD,iDACC,qBAGD,sDACC,kBACA,qBACA,WACA,0BACA,eACA,gBACA,WAQF,oBACC,gBAGD,wBACC,yBAGD,oDACC,WACA,YACA,wCAOD,oBACC,UACA,cACA,gBACA,uBAGD,2BACC,UAKD,oCAEC,cAKD,wEAEC,aAIF,gBACC,kBACA,QACA,mBAEA,sBACC,YAGD,sBACC,iBAKF,WACC,WAEA,cACC,WACA,UACA,uBACA,4CACA,iBACA,mBAGD,cACC,4CACA,UACA,uBACA,iBACA,mBAKD,gBACC,0BACA,cACA,eACA,uBACA,gBAGD,wBACC,0BAEA,gCACC,kBAIF,sCACC,kBAGD,sDAEC,cACA,eACA,eAEA,0EACC,UACA,qBACA,uBACA,gBAIF,8BACC,eAGD,kCACC,wBACA,cAIF,2BACC,mBAMA,oBACC,mBACA,sBACA,WAGD,gCACC,0BAIA,gGACC,cAOH,SACC,gBAEA,0BACC,4CAID,YACC,oBACA,mBACA,uBACA,eACA,iBACA,gBACA,aAEA,uBACC,aACA,mBACA,uBACA,oCACA,qCACA,yDACA,sBACA,oCAKF,WACC,kBACA,kBACA,oCACA,gBAKF,KACC,mBACA,mBAGD,SACC,aAGD,mBACC,mBAGD,eACC,gBAOA,+IACC,sBAEA,+KACC,aAGD,mKACC,WACA,YACA,kCACA,qBACA,kBAGD,mOACC,sCAGD,mNACC,sCAGD,mNACC,oCAMF,sBACC,aAGD,YACC,oBAGD,kBACC,0BAGD,yBACC,0BAGD,sBACC,0BAGD,oCACC,uBAIF,yCACC,uBAGD,wBACC,qBAGD,2BACC,wBAEA,gBACA,aACA,yBACA,sBAKD,WACC,kBACA,2BACA,WAGD,2DAGC,qBAIA,mCACC,qBACA,YACA,eAGD,+EAEC,YAIF,yBACC,mCACC,YACA,iBACA,cACA,iDAIF,eACC,WAGD,SACC,yBAGD,QACC,qBACA,YACA,WACA,2BAEA,gBACC,kBAIF,qBACC,sBACA,qBACA,YACA,iBAGD,kBACC,qBACA,gBAIA,aACC,sCACA,mCAGD,WACC,oCAGD,mBACC,sCACA,oBAMF,8CACC,yBACA,YAGD,wBACC,WACA,YACA,mBACA,kBACA,+DAIA,oBACC,yBACA,gBAEA,uBACC,cAGD,uBACC,kBAIF,0BACC,YACA,gCAGD,oDACC,yBAGD,wDACC,2BAGD,uBACC,cAKD,oBACC,0BAGD,oCACC,gBAIF,2BACC,aACA,eACA,mDAEA,8BACC,kBAGD,6BACC,WAIF,eACC,mBAEA,iBACC,qBACA,cAIF,SACC,UAGD,eACC,iBACA,mBACA,WAGD,UACI,+CAGJ,2BACE,GACE,YAGJ,mCACE,GACE","file":"settings.css"}
|
||||
|
|
@ -568,6 +568,7 @@ span.usersLastLoginTooltip {
|
|||
}
|
||||
|
||||
/* SETTINGS SECTIONS */
|
||||
// to match with NcSettingsSection component
|
||||
.section {
|
||||
margin-bottom: 0;
|
||||
/* section divider lines, none needed for last one */
|
||||
|
|
@ -577,13 +578,32 @@ span.usersLastLoginTooltip {
|
|||
|
||||
/* correctly display help icons next to headings */
|
||||
h2 {
|
||||
margin-bottom: 22px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
max-width: 900px;
|
||||
margin-top: 0;
|
||||
|
||||
.icon-info {
|
||||
padding: 6px 20px;
|
||||
vertical-align: text-bottom;
|
||||
display: inline-block;
|
||||
.icon-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: var(--default-clickable-area);
|
||||
height: var(--default-clickable-area);
|
||||
margin: calc((var(--default-clickable-area) - 16px) / 2 * -1);
|
||||
margin-inline-start: 0;
|
||||
color: var(--color-text-maxcontrast);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: -0.2em;
|
||||
margin-bottom: 1em;
|
||||
color: var(--color-text-maxcontrast);
|
||||
max-width: 900px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
use Behat\Behat\Context\Context;
|
||||
use Behat\Behat\Context\SnippetAcceptingContext;
|
||||
use Behat\Gherkin\Node\TableNode;
|
||||
use PHPUnit\Framework\Assert;
|
||||
|
||||
require __DIR__ . '/../../vendor/autoload.php';
|
||||
|
||||
|
|
@ -168,8 +169,52 @@ class FederationContext implements Context, SnippetAcceptingContext {
|
|||
self::$phpFederatedServerPid = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @BeforeScenario @TrustedFederation
|
||||
*/
|
||||
public function theServersAreTrustingEachOther() {
|
||||
$this->asAn('admin');
|
||||
// Trust the remote server on the local server
|
||||
$this->usingServer('LOCAL');
|
||||
$this->sendRequestForJSON('POST', '/apps/federation/trusted-servers', ['url' => 'http://localhost:' . getenv('PORT')]);
|
||||
Assert::assertTrue(($this->response->getStatusCode() === 200 || $this->response->getStatusCode() === 409));
|
||||
|
||||
// Trust the local server on the remote server
|
||||
$this->usingServer('REMOTE');
|
||||
$this->sendRequestForJSON('POST', '/apps/federation/trusted-servers', ['url' => 'http://localhost:' . getenv('PORT_FED')]);
|
||||
// If the server is already trusted, we expect a 409
|
||||
Assert::assertTrue(($this->response->getStatusCode() === 200 || $this->response->getStatusCode() === 409));
|
||||
}
|
||||
|
||||
/**
|
||||
* @AfterScenario @TrustedFederation
|
||||
*/
|
||||
public function theServersAreNoLongerTrustingEachOther() {
|
||||
$this->asAn('admin');
|
||||
// Untrust the remote servers on the local server
|
||||
$this->usingServer('LOCAL');
|
||||
$this->sendRequestForJSON('GET', '/apps/federation/trusted-servers');
|
||||
$this->theHTTPStatusCodeShouldBe('200');
|
||||
$trustedServersIDs = array_map(fn ($server) => $server->id, json_decode($this->response->getBody())->ocs->data);
|
||||
foreach ($trustedServersIDs as $id) {
|
||||
$this->sendRequestForJSON('DELETE', '/apps/federation/trusted-servers/' . $id);
|
||||
$this->theHTTPStatusCodeShouldBe('200');
|
||||
}
|
||||
|
||||
// Untrust the local server on the remote server
|
||||
$this->usingServer('REMOTE');
|
||||
$this->sendRequestForJSON('GET', '/apps/federation/trusted-servers');
|
||||
$this->theHTTPStatusCodeShouldBe('200');
|
||||
$trustedServersIDs = array_map(fn ($server) => $server->id, json_decode($this->response->getBody())->ocs->data);
|
||||
foreach ($trustedServersIDs as $id) {
|
||||
$this->sendRequestForJSON('DELETE', '/apps/federation/trusted-servers/' . $id);
|
||||
$this->theHTTPStatusCodeShouldBe('200');
|
||||
}
|
||||
}
|
||||
|
||||
protected function resetAppConfigs() {
|
||||
$this->deleteServerConfig('files_sharing', 'incoming_server2server_group_share_enabled');
|
||||
$this->deleteServerConfig('files_sharing', 'outgoing_server2server_group_share_enabled');
|
||||
$this->deleteServerConfig('files_sharing', 'federated_trusted_share_auto_accept');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ Feature: federated
|
|||
Scenario: Federate share a file with another server
|
||||
Given Using server "REMOTE"
|
||||
And user "user1" exists
|
||||
And Using server "LOCAL"
|
||||
Given Using server "LOCAL"
|
||||
And user "user0" exists
|
||||
When User "user0" from server "LOCAL" shares "/textfile0.txt" with user "user1" from server "REMOTE"
|
||||
Then the OCS status code should be "100"
|
||||
|
|
@ -30,6 +30,12 @@ Feature: federated
|
|||
| displayname_owner | user0 |
|
||||
| share_with | user1@REMOTE |
|
||||
| share_with_displayname | user1 |
|
||||
Given Using server "REMOTE"
|
||||
And As an "user1"
|
||||
And sending "GET" to "/apps/files_sharing/api/v1/remote_shares"
|
||||
And the list of returned shares has 0 shares
|
||||
When sending "GET" to "/apps/files_sharing/api/v1/remote_shares/pending"
|
||||
Then the list of returned shares has 1 shares
|
||||
|
||||
Scenario: Federated group share a file with another server
|
||||
Given Using server "REMOTE"
|
||||
|
|
@ -40,7 +46,7 @@ Feature: federated
|
|||
And As an "admin"
|
||||
And Add user "gs-user1" to the group "group1"
|
||||
And Add user "gs-user2" to the group "group1"
|
||||
And Using server "LOCAL"
|
||||
Given Using server "LOCAL"
|
||||
And parameter "outgoing_server2server_group_share_enabled" of app "files_sharing" is set to "yes"
|
||||
And user "gs-user0" exists
|
||||
When User "gs-user0" from server "LOCAL" shares "/textfile0.txt" with group "group1" from server "REMOTE"
|
||||
|
|
@ -64,11 +70,10 @@ Feature: federated
|
|||
| share_with | group1@REMOTE |
|
||||
| share_with_displayname | group1@REMOTE |
|
||||
|
||||
|
||||
Scenario: Federate share a file with local server
|
||||
Given Using server "LOCAL"
|
||||
And user "user0" exists
|
||||
And Using server "REMOTE"
|
||||
Given Using server "REMOTE"
|
||||
And user "user1" exists
|
||||
When User "user1" from server "REMOTE" shares "/textfile0.txt" with user "user0" from server "LOCAL"
|
||||
Then the OCS status code should be "100"
|
||||
|
|
@ -94,10 +99,10 @@ Feature: federated
|
|||
Scenario: Remote sharee can see the pending share
|
||||
Given Using server "REMOTE"
|
||||
And user "user1" exists
|
||||
And Using server "LOCAL"
|
||||
Given Using server "LOCAL"
|
||||
And user "user0" exists
|
||||
And User "user0" from server "LOCAL" shares "/textfile0.txt" with user "user1" from server "REMOTE"
|
||||
And Using server "REMOTE"
|
||||
Given Using server "REMOTE"
|
||||
And As an "user1"
|
||||
When sending "GET" to "/apps/files_sharing/api/v1/remote_shares/pending"
|
||||
Then the OCS status code should be "100"
|
||||
|
|
@ -122,11 +127,11 @@ Feature: federated
|
|||
And As an "admin"
|
||||
And Add user "gs-user1" to the group "group1"
|
||||
And Add user "gs-user2" to the group "group1"
|
||||
And Using server "LOCAL"
|
||||
Given Using server "LOCAL"
|
||||
And parameter "outgoing_server2server_group_share_enabled" of app "files_sharing" is set to "yes"
|
||||
And user "gs-user0" exists
|
||||
When User "gs-user0" from server "LOCAL" shares "/textfile0.txt" with group "group1" from server "REMOTE"
|
||||
And Using server "REMOTE"
|
||||
Given Using server "REMOTE"
|
||||
And As an "gs-user1"
|
||||
When sending "GET" to "/apps/files_sharing/api/v1/remote_shares/pending"
|
||||
Then the OCS status code should be "100"
|
||||
|
|
@ -159,7 +164,7 @@ Feature: federated
|
|||
Scenario: accept a pending remote share
|
||||
Given Using server "REMOTE"
|
||||
And user "user1" exists
|
||||
And Using server "LOCAL"
|
||||
Given Using server "LOCAL"
|
||||
And user "user0" exists
|
||||
And User "user0" from server "LOCAL" shares "/textfile0.txt" with user "user1" from server "REMOTE"
|
||||
When User "user1" from server "REMOTE" accepts last pending share
|
||||
|
|
@ -175,7 +180,7 @@ Feature: federated
|
|||
And As an "admin"
|
||||
And Add user "gs-user1" to the group "group1"
|
||||
And Add user "gs-user2" to the group "group1"
|
||||
And Using server "LOCAL"
|
||||
Given Using server "LOCAL"
|
||||
And parameter "outgoing_server2server_group_share_enabled" of app "files_sharing" is set to "yes"
|
||||
And user "gs-user0" exists
|
||||
When User "gs-user0" from server "LOCAL" shares "/textfile0.txt" with group "group1" from server "REMOTE"
|
||||
|
|
@ -187,45 +192,45 @@ Feature: federated
|
|||
Given Using server "REMOTE"
|
||||
And user "user1" exists
|
||||
And user "user2" exists
|
||||
And Using server "LOCAL"
|
||||
Given Using server "LOCAL"
|
||||
And user "user0" exists
|
||||
And User "user0" from server "LOCAL" shares "/textfile0.txt" with user "user1" from server "REMOTE"
|
||||
And User "user1" from server "REMOTE" accepts last pending share
|
||||
And Using server "REMOTE"
|
||||
Given Using server "REMOTE"
|
||||
And As an "user1"
|
||||
When creating a share with
|
||||
| path | /textfile0 (2).txt |
|
||||
| shareType | 0 |
|
||||
| shareWith | user2 |
|
||||
| permissions | 19 |
|
||||
#Then the OCS status code should be "100"
|
||||
#And the HTTP status code should be "200"
|
||||
#And Share fields of last share match with
|
||||
# | id | A_NUMBER |
|
||||
# | item_type | file |
|
||||
# | item_source | A_NUMBER |
|
||||
# | share_type | 0 |
|
||||
# | file_source | A_NUMBER |
|
||||
# | path | /textfile0 (2).txt |
|
||||
# | permissions | 19 |
|
||||
# | stime | A_NUMBER |
|
||||
# | storage | A_NUMBER |
|
||||
# | mail_send | 1 |
|
||||
# | uid_owner | user1 |
|
||||
# | file_parent | A_NUMBER |
|
||||
# | displayname_owner | user1 |
|
||||
# | share_with | user2 |
|
||||
# | share_with_displayname | user2 |
|
||||
# Then the OCS status code should be "100"
|
||||
# And the HTTP status code should be "200"
|
||||
# And Share fields of last share match with
|
||||
# | id | A_NUMBER |
|
||||
# | item_type | file |
|
||||
# | item_source | A_NUMBER |
|
||||
# | share_type | 0 |
|
||||
# | file_source | A_NUMBER |
|
||||
# | path | /textfile0 (2).txt |
|
||||
# | permissions | 19 |
|
||||
# | stime | A_NUMBER |
|
||||
# | storage | A_NUMBER |
|
||||
# | mail_send | 1 |
|
||||
# | uid_owner | user1 |
|
||||
# | file_parent | A_NUMBER |
|
||||
# | displayname_owner | user1 |
|
||||
# | share_with | user2 |
|
||||
# | share_with_displayname | user2 |
|
||||
|
||||
Scenario: Overwrite a federated shared file as recipient
|
||||
Given Using server "REMOTE"
|
||||
And user "user1" exists
|
||||
And user "user2" exists
|
||||
And Using server "LOCAL"
|
||||
Given Using server "LOCAL"
|
||||
And user "user0" exists
|
||||
And User "user0" from server "LOCAL" shares "/textfile0.txt" with user "user1" from server "REMOTE"
|
||||
And User "user1" from server "REMOTE" accepts last pending share
|
||||
And Using server "REMOTE"
|
||||
Given Using server "REMOTE"
|
||||
And As an "user1"
|
||||
And User "user1" modifies text of "/textfile0.txt" with text "BLABLABLA"
|
||||
When User "user1" uploads file "../../data/user1/files/textfile0.txt" to "/textfile0 (2).txt"
|
||||
|
|
@ -236,16 +241,16 @@ Feature: federated
|
|||
Given Using server "REMOTE"
|
||||
And user "user1" exists
|
||||
And user "user2" exists
|
||||
And Using server "LOCAL"
|
||||
Given Using server "LOCAL"
|
||||
And user "user0" exists
|
||||
And User "user0" from server "LOCAL" shares "/PARENT" with user "user1" from server "REMOTE"
|
||||
And User "user1" from server "REMOTE" accepts last pending share
|
||||
And Using server "REMOTE"
|
||||
Given Using server "REMOTE"
|
||||
And As an "user1"
|
||||
And User "user1" modifies text of "/textfile0.txt" with text "BLABLABLA"
|
||||
#When User "user1" uploads file "../../data/user1/files/textfile0.txt" to "/PARENT (2)/textfile0.txt"
|
||||
#And Downloading file "/PARENT (2)/textfile0.txt" with range "bytes=0-8"
|
||||
#Then Downloaded content should be "BLABLABLA"
|
||||
When User "user1" uploads file "../../data/user1/files/textfile0.txt" to "/PARENT (2)/textfile0.txt"
|
||||
And Downloading file "/PARENT (2)/textfile0.txt" with range "bytes=0-8"
|
||||
Then Downloaded content should be "BLABLABLA"
|
||||
|
||||
Scenario: List federated share from another server not accepted yet
|
||||
Given Using server "LOCAL"
|
||||
|
|
@ -256,7 +261,7 @@ Feature: federated
|
|||
# server may have its own /textfile0.txt" file)
|
||||
And User "user1" copies file "/textfile0.txt" to "/remote-share.txt"
|
||||
And User "user1" from server "REMOTE" shares "/remote-share.txt" with user "user0" from server "LOCAL"
|
||||
And Using server "LOCAL"
|
||||
Given Using server "LOCAL"
|
||||
When As an "user0"
|
||||
And sending "GET" to "/apps/files_sharing/api/v1/remote_shares"
|
||||
Then the list of returned shares has 0 shares
|
||||
|
|
@ -270,7 +275,7 @@ Feature: federated
|
|||
# server may have its own /textfile0.txt" file)
|
||||
And User "user1" copies file "/textfile0.txt" to "/remote-share.txt"
|
||||
And User "user1" from server "REMOTE" shares "/remote-share.txt" with user "user0" from server "LOCAL"
|
||||
And Using server "LOCAL"
|
||||
Given Using server "LOCAL"
|
||||
And User "user0" from server "LOCAL" accepts last pending share
|
||||
When As an "user0"
|
||||
And sending "GET" to "/apps/files_sharing/api/v1/remote_shares"
|
||||
|
|
@ -296,7 +301,7 @@ Feature: federated
|
|||
# server may have its own /textfile0.txt" file)
|
||||
And User "user1" copies file "/textfile0.txt" to "/remote-share.txt"
|
||||
And User "user1" from server "REMOTE" shares "/remote-share.txt" with user "user0" from server "LOCAL"
|
||||
And Using server "LOCAL"
|
||||
Given Using server "LOCAL"
|
||||
And User "user0" from server "LOCAL" accepts last pending share
|
||||
And remote server is stopped
|
||||
When As an "user0"
|
||||
|
|
@ -318,7 +323,7 @@ Feature: federated
|
|||
# server may have its own /textfile0.txt" file)
|
||||
And User "user1" copies file "/textfile0.txt" to "/remote-share.txt"
|
||||
And User "user1" from server "REMOTE" shares "/remote-share.txt" with user "user0" from server "LOCAL"
|
||||
And Using server "LOCAL"
|
||||
Given Using server "LOCAL"
|
||||
And User "user0" from server "LOCAL" accepts last pending share
|
||||
# Checking that the file exists caches the file entry, which causes an
|
||||
# exception to be thrown when getting the file info if the remote server is
|
||||
|
|
@ -335,8 +340,6 @@ Feature: federated
|
|||
| user | user0 |
|
||||
| mountpoint | /remote-share.txt |
|
||||
|
||||
|
||||
|
||||
Scenario: Delete federated share with another server
|
||||
Given Using server "LOCAL"
|
||||
And user "user0" exists
|
||||
|
|
@ -349,13 +352,13 @@ Feature: federated
|
|||
And As an "user1"
|
||||
And sending "GET" to "/apps/files_sharing/api/v1/shares"
|
||||
And the list of returned shares has 1 shares
|
||||
And Using server "LOCAL"
|
||||
Given Using server "LOCAL"
|
||||
And User "user0" from server "LOCAL" accepts last pending share
|
||||
And as "user0" the file "/remote-share.txt" exists
|
||||
And As an "user0"
|
||||
And sending "GET" to "/apps/files_sharing/api/v1/remote_shares"
|
||||
And the list of returned shares has 1 shares
|
||||
And Using server "REMOTE"
|
||||
Given Using server "REMOTE"
|
||||
When As an "user1"
|
||||
And Deleting last share
|
||||
Then the OCS status code should be "100"
|
||||
|
|
@ -363,7 +366,7 @@ Feature: federated
|
|||
And As an "user1"
|
||||
And sending "GET" to "/apps/files_sharing/api/v1/shares"
|
||||
And the list of returned shares has 0 shares
|
||||
And Using server "LOCAL"
|
||||
Given Using server "LOCAL"
|
||||
And as "user0" the file "/remote-share.txt" does not exist
|
||||
And As an "user0"
|
||||
And sending "GET" to "/apps/files_sharing/api/v1/remote_shares"
|
||||
|
|
@ -381,7 +384,7 @@ Feature: federated
|
|||
And As an "user1"
|
||||
And sending "GET" to "/apps/files_sharing/api/v1/shares"
|
||||
And the list of returned shares has 1 shares
|
||||
And Using server "LOCAL"
|
||||
Given Using server "LOCAL"
|
||||
And User "user0" from server "LOCAL" accepts last pending share
|
||||
And as "user0" the file "/remote-share.txt" exists
|
||||
And As an "user0"
|
||||
|
|
@ -394,7 +397,7 @@ Feature: federated
|
|||
And As an "user0"
|
||||
And sending "GET" to "/apps/files_sharing/api/v1/remote_shares"
|
||||
And the list of returned shares has 0 shares
|
||||
And Using server "REMOTE"
|
||||
Given Using server "REMOTE"
|
||||
And As an "user1"
|
||||
And sending "GET" to "/apps/files_sharing/api/v1/shares"
|
||||
And the list of returned shares has 0 shares
|
||||
|
|
@ -408,7 +411,7 @@ Feature: federated
|
|||
# server may have its own /textfile0.txt" file)
|
||||
And User "user1" copies file "/textfile0.txt" to "/remote-share.txt"
|
||||
And User "user1" from server "REMOTE" shares "/remote-share.txt" with user "user0" from server "LOCAL"
|
||||
And Using server "LOCAL"
|
||||
Given Using server "LOCAL"
|
||||
And User "user0" from server "LOCAL" accepts last pending share
|
||||
And as "user0" the file "/remote-share.txt" exists
|
||||
And As an "user0"
|
||||
|
|
@ -435,7 +438,7 @@ Feature: federated
|
|||
And As an "user1"
|
||||
And sending "GET" to "/apps/files_sharing/api/v1/shares"
|
||||
And the list of returned shares has 1 shares
|
||||
And Using server "LOCAL"
|
||||
Given Using server "LOCAL"
|
||||
And User "user0" from server "LOCAL" accepts last pending share
|
||||
And as "user0" the file "/remote-share.txt" exists
|
||||
And As an "user0"
|
||||
|
|
@ -447,7 +450,7 @@ Feature: federated
|
|||
And As an "user0"
|
||||
And sending "GET" to "/apps/files_sharing/api/v1/remote_shares"
|
||||
And the list of returned shares has 0 shares
|
||||
And Using server "REMOTE"
|
||||
Given Using server "REMOTE"
|
||||
And As an "user1"
|
||||
And sending "GET" to "/apps/files_sharing/api/v1/shares"
|
||||
And the list of returned shares has 0 shares
|
||||
|
|
@ -461,7 +464,7 @@ Feature: federated
|
|||
# server may have its own /textfile0.txt" file)
|
||||
And User "user1" copies file "/textfile0.txt" to "/remote-share.txt"
|
||||
And User "user1" from server "REMOTE" shares "/remote-share.txt" with user "user0" from server "LOCAL"
|
||||
And Using server "LOCAL"
|
||||
Given Using server "LOCAL"
|
||||
And User "user0" from server "LOCAL" accepts last pending share
|
||||
And as "user0" the file "/remote-share.txt" exists
|
||||
And As an "user0"
|
||||
|
|
@ -474,3 +477,115 @@ Feature: federated
|
|||
And As an "user0"
|
||||
And sending "GET" to "/apps/files_sharing/api/v1/remote_shares"
|
||||
And the list of returned shares has 0 shares
|
||||
|
||||
Scenario: Share to a non-trusted server will NOT auto accept
|
||||
Given Using server "LOCAL"
|
||||
And user "user0" exists
|
||||
Given Using server "REMOTE"
|
||||
And user "userfed2" exists
|
||||
And parameter "federated_trusted_share_auto_accept" of app "files_sharing" is set to "yes"
|
||||
When As an "user0"
|
||||
When User "user0" from server "LOCAL" shares "/textfile0.txt" with user "userfed2" from server "REMOTE"
|
||||
Then the OCS status code should be "100"
|
||||
And the HTTP status code should be "200"
|
||||
And sending "GET" to "/apps/files_sharing/api/v1/shares?shared_with_me=false"
|
||||
And the list of returned shares has 1 shares
|
||||
Given Using server "REMOTE"
|
||||
And using new dav path
|
||||
And As an "userfed2"
|
||||
And sending "GET" to "/apps/files_sharing/api/v1/remote_shares"
|
||||
And the list of returned shares has 0 shares
|
||||
When sending "GET" to "/apps/files_sharing/api/v1/remote_shares/pending"
|
||||
And the list of returned shares has 1 shares
|
||||
And as "userfed2" the file "/textfile0 (2).txt" does not exist
|
||||
|
||||
Scenario: Share to a non-trusted server group will NOT auto accept
|
||||
Given Using server "REMOTE"
|
||||
And parameter "incoming_server2server_group_share_enabled" of app "files_sharing" is set to "yes"
|
||||
And parameter "federated_trusted_share_auto_accept" of app "files_sharing" is set to "yes"
|
||||
And user "gs-userfed3" exists
|
||||
And user "gs-userfed4" exists
|
||||
And group "groupfed2" exists
|
||||
And As an "admin"
|
||||
And Add user "gs-userfed3" to the group "groupfed2"
|
||||
And Add user "gs-userfed4" to the group "groupfed2"
|
||||
Given Using server "LOCAL"
|
||||
And parameter "outgoing_server2server_group_share_enabled" of app "files_sharing" is set to "yes"
|
||||
And user "gs-user0" exists
|
||||
When As an "gs-user0"
|
||||
When User "gs-user0" from server "LOCAL" shares "/textfile0.txt" with group "groupfed2" from server "REMOTE"
|
||||
Then the OCS status code should be "100"
|
||||
And the HTTP status code should be "200"
|
||||
And sending "GET" to "/apps/files_sharing/api/v1/shares?shared_with_me=false"
|
||||
And the list of returned shares has 1 shares
|
||||
Given Using server "REMOTE"
|
||||
And using new dav path
|
||||
And As an "gs-userfed3"
|
||||
And sending "GET" to "/apps/files_sharing/api/v1/remote_shares"
|
||||
And the list of returned shares has 0 shares
|
||||
When sending "GET" to "/apps/files_sharing/api/v1/remote_shares/pending"
|
||||
And the list of returned shares has 1 shares
|
||||
And as "gs-userfed3" the file "/textfile0 (2).txt" does not exist
|
||||
And As an "gs-userfed4"
|
||||
And sending "GET" to "/apps/files_sharing/api/v1/remote_shares"
|
||||
And the list of returned shares has 0 shares
|
||||
When sending "GET" to "/apps/files_sharing/api/v1/remote_shares/pending"
|
||||
And the list of returned shares has 1 shares
|
||||
And as "gs-userfed4" the file "/textfile0 (2).txt" does not exist
|
||||
|
||||
@TrustedFederation
|
||||
Scenario: Share to a trusted server auto accept
|
||||
Given Using server "LOCAL"
|
||||
And user "user0" exists
|
||||
Given Using server "REMOTE"
|
||||
And user "userfed1" exists
|
||||
And parameter "federated_trusted_share_auto_accept" of app "files_sharing" is set to "yes"
|
||||
When As an "user0"
|
||||
When User "user0" from server "LOCAL" shares "/textfile0.txt" with user "userfed1" from server "REMOTE"
|
||||
Then the OCS status code should be "100"
|
||||
And the HTTP status code should be "200"
|
||||
And sending "GET" to "/apps/files_sharing/api/v1/shares?shared_with_me=false"
|
||||
And the list of returned shares has 1 shares
|
||||
Given Using server "REMOTE"
|
||||
And using new dav path
|
||||
And As an "userfed1"
|
||||
And sending "GET" to "/apps/files_sharing/api/v1/remote_shares"
|
||||
And the list of returned shares has 1 shares
|
||||
When sending "GET" to "/apps/files_sharing/api/v1/remote_shares/pending"
|
||||
And the list of returned shares has 0 shares
|
||||
And as "userfed1" the file "/textfile0 (2).txt" exists
|
||||
|
||||
@TrustedFederation
|
||||
Scenario: Share to a trusted server group auto accept
|
||||
Given Using server "REMOTE"
|
||||
And parameter "incoming_server2server_group_share_enabled" of app "files_sharing" is set to "yes"
|
||||
And parameter "federated_trusted_share_auto_accept" of app "files_sharing" is set to "yes"
|
||||
And user "gs-userfed1" exists
|
||||
And user "gs-userfed2" exists
|
||||
And group "groupfed1" exists
|
||||
And As an "admin"
|
||||
And Add user "gs-userfed1" to the group "groupfed1"
|
||||
And Add user "gs-userfed2" to the group "groupfed1"
|
||||
Given Using server "LOCAL"
|
||||
And parameter "outgoing_server2server_group_share_enabled" of app "files_sharing" is set to "yes"
|
||||
And user "gs-user0" exists
|
||||
When As an "gs-user0"
|
||||
When User "gs-user0" from server "LOCAL" shares "/textfile0.txt" with group "groupfed1" from server "REMOTE"
|
||||
Then the OCS status code should be "100"
|
||||
And the HTTP status code should be "200"
|
||||
And sending "GET" to "/apps/files_sharing/api/v1/shares?shared_with_me=false"
|
||||
And the list of returned shares has 1 shares
|
||||
Given Using server "REMOTE"
|
||||
And using new dav path
|
||||
And As an "gs-userfed1"
|
||||
And sending "GET" to "/apps/files_sharing/api/v1/remote_shares"
|
||||
And the list of returned shares has 1 shares
|
||||
When sending "GET" to "/apps/files_sharing/api/v1/remote_shares/pending"
|
||||
And the list of returned shares has 0 shares
|
||||
And as "gs-userfed1" the file "/textfile0 (2).txt" exists
|
||||
And As an "gs-userfed2"
|
||||
And sending "GET" to "/apps/files_sharing/api/v1/remote_shares"
|
||||
And the list of returned shares has 1 shares
|
||||
When sending "GET" to "/apps/files_sharing/api/v1/remote_shares/pending"
|
||||
And the list of returned shares has 0 shares
|
||||
And as "gs-userfed2" the file "/textfile0 (2).txt" exists
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ if [ "$INSTALLED" == "true" ]; then
|
|||
$OCC config:system:set auth.bruteforce.protection.enabled --value false --type bool
|
||||
# Allow local remote urls otherwise we can not share
|
||||
$OCC config:system:set allow_local_remote_servers --value true --type bool
|
||||
# Allow self signed certificates
|
||||
$OCC config:system:set sharing.federation.allowSelfSignedCertificates --value true --type bool
|
||||
else
|
||||
if [ "$SCENARIO_TO_RUN" != "setup_features/setup.feature" ]; then
|
||||
echo "Nextcloud instance needs to be installed" >&2
|
||||
|
|
@ -38,6 +40,7 @@ if [ -z "$EXECUTOR_NUMBER" ]; then
|
|||
fi
|
||||
PORT=$((8080 + $EXECUTOR_NUMBER))
|
||||
echo $PORT
|
||||
export PORT
|
||||
|
||||
echo "" > "${NC_DATADIR}/nextcloud.log"
|
||||
echo "" > phpserver.log
|
||||
|
|
|
|||
|
|
@ -1880,6 +1880,15 @@ $CONFIG = [
|
|||
*/
|
||||
'transferIncomingShares' => false,
|
||||
|
||||
/**
|
||||
* Federated Cloud Sharing
|
||||
*/
|
||||
|
||||
/**
|
||||
* Allow self-signed certificates for federated shares
|
||||
*/
|
||||
'sharing.federation.allowSelfSignedCertificates' => false,
|
||||
|
||||
/**
|
||||
* Hashing
|
||||
*/
|
||||
|
|
|
|||
2
dist/9701-9701.js.map
vendored
2
dist/9701-9701.js.map
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4
dist/files_sharing-init.js
vendored
4
dist/files_sharing-init.js
vendored
File diff suppressed because one or more lines are too long
2
dist/files_sharing-init.js.map
vendored
2
dist/files_sharing-init.js.map
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue