diff --git a/lib/Command/CirclesCheck.php b/lib/Command/CirclesCheck.php
index 019c55643..890c210d4 100644
--- a/lib/Command/CirclesCheck.php
+++ b/lib/Command/CirclesCheck.php
@@ -32,6 +32,7 @@
namespace OCA\Circles\Command;
use ArtificialOwl\MySmallPhpTools\Exceptions\RequestNetworkException;
+use ArtificialOwl\MySmallPhpTools\Exceptions\SignatoryException;
use ArtificialOwl\MySmallPhpTools\Model\Nextcloud\nc22\NC22Request;
use ArtificialOwl\MySmallPhpTools\Model\Request;
use ArtificialOwl\MySmallPhpTools\Model\SimpleDataStore;
@@ -39,6 +40,8 @@
use ArtificialOwl\MySmallPhpTools\Traits\TArrayTools;
use ArtificialOwl\MySmallPhpTools\Traits\TStringTools;
use Exception;
+use OC;
+use OC\AppConfig;
use OC\Core\Command\Base;
use OCA\Circles\AppInfo\Application;
use OCA\Circles\AppInfo\Capabilities;
@@ -50,11 +53,13 @@
use OCA\Circles\Exceptions\RemoteNotFoundException;
use OCA\Circles\Exceptions\RemoteResourceNotFoundException;
use OCA\Circles\Exceptions\RequestBuilderException;
+use OCA\Circles\Exceptions\UnknownInterfaceException;
use OCA\Circles\Exceptions\UnknownRemoteException;
use OCA\Circles\FederatedItems\LoopbackTest;
use OCA\Circles\Model\Federated\FederatedEvent;
use OCA\Circles\Service\ConfigService;
use OCA\Circles\Service\FederatedEventService;
+use OCA\Circles\Service\InterfaceService;
use OCA\Circles\Service\RemoteService;
use OCA\Circles\Service\RemoteStreamService;
use OCA\Circles\Service\RemoteUpstreamService;
@@ -84,6 +89,9 @@ class CirclesCheck extends Base {
/** @var Capabilities */
private $capabilities;
+ /** @var InterfaceService */
+ private $interfaceService;
+
/** @var FederatedEventService */
private $federatedEventService;
@@ -100,9 +108,6 @@ class CirclesCheck extends Base {
private $configService;
- /** @var int */
- private $delay = 5;
-
/** @var array */
private $sessions = [];
@@ -111,7 +116,8 @@ class CirclesCheck extends Base {
* CirclesCheck constructor.
*
* @param Capabilities $capabilities
- * @param FederatedEvent $federatedEventService
+ * @param InterfaceService $interfaceService
+ * @param FederatedEventService $federatedEventService
* @param RemoteService $remoteService
* @param RemoteStreamService $remoteStreamService
* @param RemoteUpstreamService $remoteUpstreamService
@@ -119,6 +125,7 @@ class CirclesCheck extends Base {
*/
public function __construct(
Capabilities $capabilities,
+ InterfaceService $interfaceService,
FederatedEventService $federatedEventService,
RemoteService $remoteService,
RemoteStreamService $remoteStreamService,
@@ -128,6 +135,7 @@ public function __construct(
parent::__construct();
$this->capabilities = $capabilities;
+ $this->interfaceService = $interfaceService;
$this->federatedEventService = $federatedEventService;
$this->remoteService = $remoteService;
$this->remoteStreamService = $remoteStreamService;
@@ -140,9 +148,9 @@ protected function configure() {
parent::configure();
$this->setName('circles:check')
->setDescription('Checking your configuration')
- ->addOption('delay', 'd', InputOption::VALUE_REQUIRED, 'delay before checking result')
->addOption('capabilities', '', InputOption::VALUE_NONE, 'listing app\'s capabilities')
->addOption('type', '', InputOption::VALUE_REQUIRED, 'configuration to check', '')
+ ->addOption('alpha', '', InputOption::VALUE_NONE, 'allow ALPHA features')
->addOption('test', '', InputOption::VALUE_REQUIRED, 'specify an url to test', '');
}
@@ -162,10 +170,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int
return 0;
}
- if ($input->getOption('delay')) {
- $this->delay = (int)$input->getOption('delay');
- }
-
$this->configService->setAppValue(ConfigService::TEST_NC_BASE, '');
$test = $input->getOption('test');
$type = $input->getOption('type');
@@ -184,72 +188,25 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$output->writeln('');
$output->writeln('');
}
+
+
if ($type === '' || $type === 'internal') {
$output->writeln('### Testing internal address.');
$this->checkInternal($input, $output, $test);
$output->writeln('');
$output->writeln('');
}
+
+ if (!$input->getOption('alpha')) {
+ return 0;
+ }
+
if ($type === '' || $type === 'frontal') {
$output->writeln('### Testing frontal address.');
$this->checkFrontal($input, $output, $test);
$output->writeln('');
}
-
-//
-// if (!$this->testRequest($output, 'GET', 'core.CSRFToken.index')) {
-// $this->configService->setAppValue(ConfigService::TEST_NC_BASE, '');
-//
-// return 0;
-// }
-//
-// if (!$this->testRequest(
-// $output, 'POST', 'circles.EventWrapper.asyncBroadcast',
-// ['token' => 'test-dummy-token']
-// )) {
-// $this->configService->setAppValue(ConfigService::TEST_NC_BASE, '');
-//
-// return 0;
-// }
-//
-// $test = new GSEvent(GSEvent::TEST, true, true);
-// $test->setAsync(true);
-// $token = $this->gsUpstreamService->newEvent($test);
-//
-// $output->writeln('- Async request is sent, now waiting ' . $this->delay . ' seconds');
-// sleep($this->delay);
-// $output->writeln('- Pause is over, checking results for ' . $token);
-//
-// $wrappers = $this->gsUpstreamService->getEventsByToken($token);
-//
-// $result = [];
-// $instances = array_merge($this->globalScaleService->getInstances(true));
-// foreach ($wrappers as $wrapper) {
-// $result[$wrapper->getInstance()] = $wrapper->getEvent();
-// }
-//
-// $localLooksGood = false;
-// foreach ($instances as $instance) {
-// $output->write($instance . ' ');
-// if (array_key_exists($instance, $result)
-// && $result[$instance]->getResult()
-// ->gInt('status') === 1) {
-// $output->writeln('ok');
-// if ($this->configService->isLocalInstance($instance)) {
-// $localLooksGood = true;
-// }
-// } else {
-// $output->writeln('fail');
-// }
-// }
-//
-// $this->configService->setAppValue(ConfigService::TEST_NC_BASE, '');
-//
-// if ($localLooksGood) {
-// $this->saveUrl($input, $output, $input->getOption('url'));
-// }
-
return 0;
}
@@ -308,20 +265,22 @@ private function checkLoopback(InputInterface $input, OutputInterface $output, s
}
try {
- [$scheme, $cloudId] = $this->parseAddress($loopback);
+ [$scheme, $cloudId, $path] = $this->parseAddress($loopback);
} catch (Exception $e) {
- $output->writeln('format must be http[s]://domain.name[:post]');
+ $output->writeln('format must be http[s]://domain.name[:post][/path]');
continue;
}
- $loopback = $scheme . '://' . $cloudId;
- $output->write('* testing address: ' . $loopback . ' ');
+ $loopback = rtrim($scheme . '://' . $cloudId . $path, '/');
+ $output->writeln('* testing address: ' . $loopback . ' ');
- if ($this->testLoopback($input, $output, $loopback)) {
- $output->writeln('* Loopback address looks good');
+ try {
+ $this->setupLoopback($input, $output, $loopback);
$this->saveLoopback($input, $output, $loopback);
return;
+ } catch (Exception $e) {
+ $output->writeln('');
}
}
}
@@ -333,11 +292,12 @@ private function checkLoopback(InputInterface $input, OutputInterface $output, s
private function setupLoopback(InputInterface $input, OutputInterface $output, string $address): void {
$e = null;
try {
- [$scheme, $cloudId] = $this->parseAddress($address);
+ [$scheme, $cloudId, $path] = $this->parseAddress($address);
$this->configService->setAppValue(ConfigService::LOOPBACK_TMP_SCHEME, $scheme);
$this->configService->setAppValue(ConfigService::LOOPBACK_TMP_ID, $cloudId);
- if (!$this->testLoopback($input, $output, $address)) {
+ $this->configService->setAppValue(ConfigService::LOOPBACK_TMP_PATH, $path);
+ if (!$this->testLoopback($input, $output)) {
throw new Exception();
}
} catch (Exception $e) {
@@ -345,6 +305,7 @@ private function setupLoopback(InputInterface $input, OutputInterface $output, s
$this->configService->setAppValue(ConfigService::LOOPBACK_TMP_SCHEME, '');
$this->configService->setAppValue(ConfigService::LOOPBACK_TMP_ID, '');
+ $this->configService->setAppValue(ConfigService::LOOPBACK_TMP_PATH, '');
if (!is_null($e)) {
throw $e;
@@ -355,10 +316,8 @@ private function setupLoopback(InputInterface $input, OutputInterface $output, s
/**
* @param InputInterface $input
* @param OutputInterface $output
- * @param string $address
*
* @return bool
- * @throws RequestNetworkException
* @throws FederatedEventException
* @throws FederatedItemException
* @throws InitiatorNotConfirmedException
@@ -366,10 +325,10 @@ private function setupLoopback(InputInterface $input, OutputInterface $output, s
* @throws RemoteInstanceException
* @throws RemoteNotFoundException
* @throws RemoteResourceNotFoundException
- * @throws UnknownRemoteException
* @throws RequestBuilderException
+ * @throws UnknownRemoteException
*/
- private function testLoopback(InputInterface $input, OutputInterface $output, string $address): bool {
+ private function testLoopback(InputInterface $input, OutputInterface $output): bool {
if (!$this->testRequest($output, 'GET', 'core.CSRFToken.index')) {
return false;
}
@@ -387,14 +346,13 @@ private function testLoopback(InputInterface $input, OutputInterface $output, st
$output->writeln('' . $test->getWrapperToken() . '');
- $output->writeln('- Waiting for async process to finish (' . $this->delay . 's)');
- sleep($this->delay);
+ $output->writeln('- Waiting for async process to finish (5s)');
+ sleep(5);
$output->write('- Checking status on FederatedEvent ');
$wrappers = $this->remoteUpstreamService->getEventsByToken($test->getWrapperToken());
if (count($wrappers) !== 1) {
$output->writeln('Event created too many Wrappers');
- $output->writeln('Event created too many Wrappers');
}
$wrapper = array_shift($wrappers);
@@ -431,10 +389,11 @@ private function testLoopback(InputInterface $input, OutputInterface $output, st
* @throws Exception
*/
private function saveLoopback(InputInterface $input, OutputInterface $output, string $loopback): void {
- [$scheme, $cloudId] = $this->parseAddress($loopback);
+ [$scheme, $cloudId, $path] = $this->parseAddress($loopback);
$question = new ConfirmationQuestion(
- '- Do you want to save '. $loopback . ' as your loopback address ? (y/N) ', false, '/^(y|Y)/i'
+ '- Do you want to save ' . $loopback
+ . ' as your loopback address ? (y/N) ', false, '/^(y|Y)/i'
);
$helper = $this->getHelper('question');
@@ -446,6 +405,7 @@ private function saveLoopback(InputInterface $input, OutputInterface $output, st
$this->configService->setAppValue(ConfigService::LOOPBACK_CLOUD_SCHEME, $scheme);
$this->configService->setAppValue(ConfigService::LOOPBACK_CLOUD_ID, $cloudId);
+ $this->configService->setAppValue(ConfigService::LOOPBACK_CLOUD_PATH, $path);
$output->writeln(
'- Address ' . $loopback . ' is now used as loopback'
);
@@ -455,6 +415,10 @@ private function saveLoopback(InputInterface $input, OutputInterface $output, st
* @param InputInterface $input
* @param OutputInterface $output
* @param string $test
+ *
+ * @throws SignatoryException
+ * @throws UnknownInterfaceException
+ * @throws Exception
*/
private function checkInternal(InputInterface $input, OutputInterface $output, string $test): void {
$output->writeln(
@@ -463,6 +427,170 @@ private function checkInternal(InputInterface $input, OutputInterface $output, s
$output->writeln(
'. The address you need to define here is the local address of your Nextcloud, reachable by all other instances of our GlobalScale.'
);
+
+ $question = new ConfirmationQuestion(
+ '- Do you want to enable this feature ? (y/N) ', false, '/^(y|Y)/i'
+ );
+
+ $helper = $this->getHelper('question');
+ if (!$helper->ask($input, $output, $question)) {
+ $output->writeln('skipping.');
+
+ return;
+ }
+
+ while (true) {
+ $output->writeln('');
+ $question = new Question(
+ 'Please write down a new internal address to test: ', ''
+ );
+
+ $internal = $helper->ask($input, $output, $question);
+ if (is_null($internal) || $internal === '') {
+ $output->writeln('skipping.');
+
+ return;
+ }
+
+ try {
+ [$scheme, $cloudId, $path] = $this->parseAddress($internal);
+ } catch (Exception $e) {
+ $output->writeln('format must be http[s]://domain.name[:post][/path]');
+ continue;
+ }
+
+ $internal = rtrim($scheme . '://' . $cloudId, '/');
+ $fullInternal = rtrim($scheme . '://' . $cloudId . $path, '/');
+
+ $question = new ConfirmationQuestion(
+ 'Do you want to check the validity of this internal address? (Y/n) ', true,
+ '/^(y|Y)/i'
+ );
+
+ if ($helper->ask($input, $output, $question)) {
+ $testToken = $this->token();
+ $this->configService->setAppValue(ConfigService::IFACE_TEST_ID, $cloudId);
+ $this->configService->setAppValue(ConfigService::IFACE_TEST_SCHEME, $scheme);
+ $this->configService->setAppValue(ConfigService::IFACE_TEST_PATH, $path);
+ $this->configService->setAppValue(ConfigService::IFACE_TEST_TOKEN, $testToken);
+
+ $output->writeln('');
+ $output->writeln(
+ 'You will need to run this curl command from a terminal on your local network and paste its result: '
+ );
+ $output->writeln(
+ ' curl -L "' . $internal
+ . '/.well-known/webfinger?resource=http://nextcloud.com/&test='
+ . $testToken . '"'
+ );
+
+ $output->writeln('paste the result here: ');
+ $question = new Question('', '');
+ $pastedWebfinger = new SimpleDataStore();
+ $pastedWebfinger->json(trim($helper->ask($input, $output, $question)));
+
+ if ($pastedWebfinger->g('subject') !== Application::APP_SUBJECT) {
+ $output->writeln('Cannot extract SUBJECT from the pasted data');
+ continue;
+ }
+
+ $pastedHref = '';
+ foreach ($pastedWebfinger->gArray('links') as $link) {
+ $entry = new SimpleDataStore($link);
+ if ($entry->g('rel') === Application::APP_REL) {
+ $pastedHref = $entry->g('href');
+ }
+ }
+
+ if ($pastedHref === '') {
+ $output->writeln('Cannot retrieve HREF from the pasted data');
+ continue;
+ }
+
+ $href = $this->interfaceService->getCloudPath(
+ 'circles.Remote.appService',
+ [],
+ InterfaceService::IFACE_TEST
+ );
+
+ if ($pastedHref !== $href) {
+ $output->writeln(
+ 'The returned data (' . $pastedHref . ') are not the one expected: '
+ . $href
+ );
+ continue;
+ }
+
+ $output->writeln('');
+ $output->writeln('First step seems fine.');
+ $output->writeln(
+ 'Now, please run this curl command from a terminal on your local network and paste its result: '
+ );
+ $output->writeln(
+ ' curl -L "' . $pastedHref . '?test=' . $testToken . '" -H "Accept: application/json"'
+ );
+
+ $output->writeln('paste the result here: ');
+ $question = new Question('', '');
+ $pastedSignatory = new SimpleDataStore();
+ $pastedSignatory->json(trim($helper->ask($input, $output, $question)));
+
+ // small hack to refresh the cached config
+ OC::$server->get(AppConfig::class)->clearCachedConfig();
+ $this->interfaceService->setCurrentInterface(InterfaceService::IFACE_TEST);
+ $appSignatory = $this->remoteStreamService->getAppSignatory(false);
+
+ if ($appSignatory->getUid(true) !== $pastedSignatory->g('uid')
+ || $appSignatory->getRoot() !== $pastedSignatory->g('root')) {
+ $output->writeln(
+ 'The returned data ('
+ . $pastedSignatory->g('uid') . '/' . $pastedSignatory->g('root')
+ . ') are not the one expected: '
+ . $appSignatory->getUid(true) . '/' . $appSignatory->getRoot()
+ );
+ continue;
+ }
+
+ $output->writeln('* Internal address looks good');
+ }
+
+ $this->saveInternal($input, $output, $fullInternal);
+
+ return;
+ }
+ }
+
+
+ /**
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ * @param string $internal
+ *
+ * @throws Exception
+ */
+ private function saveInternal(InputInterface $input, OutputInterface $output, string $internal): void {
+ [$scheme, $cloudId, $path] = $this->parseAddress($internal);
+
+ $output->writeln('');
+ $question = new ConfirmationQuestion(
+ '- Do you want to save ' . $internal
+ . ' as your internal address ? (y/N) ', false, '/^(y|Y)/i'
+ );
+
+ $helper = $this->getHelper('question');
+ if (!$helper->ask($input, $output, $question)) {
+ $output->writeln('skipping.');
+
+ return;
+ }
+
+ $this->configService->setAppValue(ConfigService::INTERNAL_CLOUD_SCHEME, $scheme);
+ $this->configService->setAppValue(ConfigService::INTERNAL_CLOUD_ID, $cloudId);
+ $this->configService->setAppValue(ConfigService::INTERNAL_CLOUD_PATH, $path);
+
+ $output->writeln(
+ '- Address ' . $internal . ' is now used as internal'
+ );
}
@@ -508,13 +636,13 @@ private function checkFrontal(InputInterface $input, OutputInterface $output, st
}
try {
- [$scheme, $cloudId] = $this->parseAddress($frontal);
+ [$scheme, $cloudId, $path] = $this->parseAddress($frontal);
} catch (Exception $e) {
- $output->writeln('format must be http[s]://domain.name[:post]');
+ $output->writeln('format must be http[s]://domain.name[:post][/path]');
continue;
}
- $frontal = $scheme . '://' . $cloudId;
+ $frontal = rtrim($scheme . '://' . $cloudId . $path, '/');
break;
}
@@ -729,15 +857,22 @@ private function parseAddress(string $test): array {
$scheme = parse_url($test, PHP_URL_SCHEME);
$cloudId = parse_url($test, PHP_URL_HOST);
$cloudIdPort = parse_url($test, PHP_URL_PORT);
+ $path = parse_url($test, PHP_URL_PATH);
- if (is_null($scheme) || is_null($cloudId)) {
+ if (is_bool($scheme) || is_bool($cloudId) || is_null($scheme) || is_null($cloudId)) {
throw new Exception();
}
+ if (is_null($path) || is_bool($path)) {
+ $path = '';
+ }
+
+ $path = rtrim($path, '/');
+
if (!is_null($cloudIdPort)) {
$cloudId = $cloudId . ':' . $cloudIdPort;
}
- return [$scheme, $cloudId];
+ return [$scheme, $cloudId, $path];
}
}
diff --git a/lib/Controller/RemoteController.php b/lib/Controller/RemoteController.php
index 8d270ce9f..a1cabb253 100644
--- a/lib/Controller/RemoteController.php
+++ b/lib/Controller/RemoteController.php
@@ -157,19 +157,21 @@ public function __construct(
* @PublicPage
* @NoCSRFRequired
*
+ * @param string $test
+ *
* @return DataResponse
* @throws NotLoggedInException
* @throws SignatoryException
* @throws UnknownInterfaceException
*/
- public function appService(): DataResponse {
+ public function appService(string $test = ''): DataResponse {
try {
$this->publicPageJsonLimited();
} catch (JsonNotRequestedException $e) {
return new DataResponse();
}
- $this->interfaceService->setCurrentInterfaceFromRequest($this->request);
+ $this->interfaceService->setCurrentInterfaceFromRequest($this->request, $test);
$signatory = $this->remoteStreamService->getAppSignatory(false, $this->request->getParam('auth', ''));
return new DataResponse($signatory);
diff --git a/lib/Handlers/WebfingerHandler.php b/lib/Handlers/WebfingerHandler.php
index b75c1dcb6..d3449db6d 100644
--- a/lib/Handlers/WebfingerHandler.php
+++ b/lib/Handlers/WebfingerHandler.php
@@ -111,7 +111,7 @@ public function handle(string $service, IRequestContext $context, ?IResponse $re
}
try {
- $this->interfaceService->setCurrentInterfaceFromRequest($request, $request->getParam('check', ''));
+ $this->interfaceService->setCurrentInterfaceFromRequest($request, $request->getParam('test', ''));
$this->remoteStreamService->getAppSignatory();
$href = $this->interfaceService->getCloudPath('circles.Remote.appService');
$info = [
diff --git a/lib/Service/ConfigService.php b/lib/Service/ConfigService.php
index e0b74a15f..c2cbc73ae 100644
--- a/lib/Service/ConfigService.php
+++ b/lib/Service/ConfigService.php
@@ -32,8 +32,10 @@
namespace OCA\Circles\Service;
use ArtificialOwl\MySmallPhpTools\Model\Nextcloud\nc22\NC22Request;
+use ArtificialOwl\MySmallPhpTools\Traits\Nextcloud\nc22\TNC22Logger;
use ArtificialOwl\MySmallPhpTools\Traits\TArrayTools;
use ArtificialOwl\MySmallPhpTools\Traits\TStringTools;
+use OC;
use OCA\Circles\AppInfo\Application;
use OCA\Circles\Exceptions\GSStatusException;
use OCA\Circles\IFederatedUser;
@@ -51,33 +53,46 @@
class ConfigService {
use TStringTools;
use TArrayTools;
+ use TNC22Logger;
public const FRONTAL_CLOUD_BASE = 'frontal_cloud_base';
public const FRONTAL_CLOUD_ID = 'frontal_cloud_id';
public const FRONTAL_CLOUD_SCHEME = 'frontal_cloud_scheme';
+ public const FRONTAL_CLOUD_PATH = 'frontal_cloud_path';
public const INTERNAL_CLOUD_ID = 'internal_cloud_id';
public const INTERNAL_CLOUD_SCHEME = 'internal_cloud_scheme';
+ public const INTERNAL_CLOUD_PATH = 'internal_cloud_path';
public const LOOPBACK_CLOUD_ID = 'loopback_cloud_id';
public const LOOPBACK_CLOUD_SCHEME = 'loopback_cloud_scheme';
+ public const LOOPBACK_CLOUD_PATH = 'loopback_cloud_path';
public const IFACE0_CLOUD_ID = 'iface0_cloud_id';
public const IFACE0_CLOUD_SCHEME = 'iface0_cloud_scheme';
+ public const IFACE0_CLOUD_PATH = 'iface0_cloud_path';
public const IFACE0_INTERNAL = 'iface0_internal';
public const IFACE1_CLOUD_ID = 'iface1_cloud_id';
public const IFACE1_CLOUD_SCHEME = 'iface1_cloud_scheme';
+ public const IFACE1_CLOUD_PATH = 'iface1_cloud_path';
public const IFACE1_INTERNAL = 'iface1_internal';
public const IFACE2_CLOUD_ID = 'iface2_cloud_id';
public const IFACE2_CLOUD_SCHEME = 'iface2_cloud_scheme';
+ public const IFACE2_CLOUD_PATH = 'iface2_cloud_path';
public const IFACE2_INTERNAL = 'iface2_internal';
public const IFACE3_CLOUD_ID = 'iface3_cloud_id';
public const IFACE3_CLOUD_SCHEME = 'iface3_cloud_scheme';
+ public const IFACE3_CLOUD_PATH = 'iface3_cloud_path';
public const IFACE3_INTERNAL = 'iface3_internal';
public const IFACE4_CLOUD_ID = 'iface4_cloud_id';
public const IFACE4_CLOUD_SCHEME = 'iface4_cloud_scheme';
+ public const IFACE4_CLOUD_PATH = 'iface4_cloud_path';
public const IFACE4_INTERNAL = 'iface4_internal';
public const IFACE_TEST_ID = 'iface_test_id';
public const IFACE_TEST_SCHEME = 'iface_test_scheme';
+ public const IFACE_TEST_PATH = 'iface_test_path';
public const IFACE_TEST_TOKEN = 'iface_test_token';
+ public const LOOPBACK_TMP_ID = 'loopback_tmp_id';
+ public const LOOPBACK_TMP_SCHEME = 'loopback_tmp_scheme';
+ public const LOOPBACK_TMP_PATH = 'loopback_tmp_path';
public const HARD_MODERATION = 'hard_moderation';
public const FRONTEND_ENABLED = 'frontend_enabled';
@@ -96,9 +111,6 @@ class ConfigService {
public const MAINTENANCE_UPDATE = 'maintenance_update';
public const MAINTENANCE_RUN = 'maintenance_run';
- public const LOOPBACK_TMP_ID = 'loopback_tmp_id';
- public const LOOPBACK_TMP_SCHEME = 'loopback_tmp_scheme';
-
public const GS_MODE = 'mode';
public const GS_KEY = 'key';
@@ -119,30 +131,40 @@ class ConfigService {
self::FRONTAL_CLOUD_BASE => '',
self::FRONTAL_CLOUD_ID => '',
self::FRONTAL_CLOUD_SCHEME => 'https',
+ self::FRONTAL_CLOUD_PATH => '',
self::INTERNAL_CLOUD_ID => '',
self::INTERNAL_CLOUD_SCHEME => 'https',
+ self::INTERNAL_CLOUD_PATH => '',
self::LOOPBACK_CLOUD_ID => '',
self::LOOPBACK_CLOUD_SCHEME => 'https',
- self::LOOPBACK_TMP_ID => '',
- self::LOOPBACK_TMP_SCHEME => '',
+ self::LOOPBACK_CLOUD_PATH => '',
self::IFACE0_CLOUD_ID => '',
self::IFACE0_CLOUD_SCHEME => 'https',
+ self::IFACE0_CLOUD_PATH => '',
self::IFACE0_INTERNAL => '0',
self::IFACE1_CLOUD_ID => '',
self::IFACE1_CLOUD_SCHEME => 'https',
+ self::IFACE1_CLOUD_PATH => '',
self::IFACE1_INTERNAL => '0',
self::IFACE2_CLOUD_ID => '',
self::IFACE2_CLOUD_SCHEME => 'https',
+ self::IFACE2_CLOUD_PATH => '',
self::IFACE2_INTERNAL => '0',
self::IFACE3_CLOUD_ID => '',
self::IFACE3_CLOUD_SCHEME => 'https',
+ self::IFACE3_CLOUD_PATH => '',
self::IFACE3_INTERNAL => '0',
self::IFACE4_CLOUD_ID => '',
self::IFACE4_CLOUD_SCHEME => 'https',
+ self::IFACE4_CLOUD_PATH => '',
self::IFACE4_INTERNAL => '0',
self::IFACE_TEST_ID => '',
self::IFACE_TEST_SCHEME => 'https',
+ self::IFACE_TEST_PATH => '',
self::IFACE_TEST_TOKEN => '',
+ self::LOOPBACK_TMP_ID => '',
+ self::LOOPBACK_TMP_SCHEME => '',
+ self::LOOPBACK_TMP_PATH => '',
self::FRONTEND_ENABLED => '1',
self::HARD_MODERATION => '0',
@@ -184,6 +206,8 @@ class ConfigService {
public function __construct(IConfig $config, IURLGenerator $urlGenerator) {
$this->config = $config;
$this->urlGenerator = $urlGenerator;
+
+ $this->setup('app', Application::APP_ID);
}
@@ -464,6 +488,11 @@ public function getLoopbackInstance(): string {
$this->setAppValue(self::LOOPBACK_TMP_SCHEME, $loopback['scheme']);
}
+ if (array_key_exists('path', $loopback)
+ && $this->getAppValue(self::LOOPBACK_TMP_PATH) !== $loopback['path']) {
+ $this->setAppValue(self::LOOPBACK_TMP_PATH, $loopback['path']);
+ }
+
return $loopbackCloudId;
}
@@ -483,12 +512,18 @@ public function getLoopbackPath(string $route = '', array $args = []): string {
$scheme = $this->getAppValue(self::LOOPBACK_CLOUD_SCHEME);
}
- $base = $scheme . '://' . $instance;
+ $path = $this->getAppValue(self::LOOPBACK_TMP_PATH);
+ if ($path === '') {
+ $path = $this->getAppValue(self::LOOPBACK_CLOUD_PATH);
+ }
+
+ $base = $scheme . '://' . $instance . $path;
+
if ($route === '') {
return $base;
}
- return $base . $this->urlGenerator->linkToRoute($route, $args);
+ return rtrim($base, '/') . $this->linkToRoute($route, $args);
}
@@ -640,4 +675,33 @@ public function configureRequest(NC22Request $request): void {
$request->setFollowLocation(true);
$request->setTimeout(5);
}
+
+
+ /**
+ * @param string $route
+ * @param array $args
+ *
+ * @return string
+ */
+ public function linkToRoute(string $route, array $args): string {
+ $path = $this->urlGenerator->linkToRoute($route, $args);
+
+ if (OC::$CLI) {
+ $knownPath = parse_url($this->config->getSystemValue('overwrite.cli.url'), PHP_URL_PATH);
+ } else {
+ $knownPath = OC::$WEBROOT;
+ }
+
+ $knownPath = rtrim($knownPath, '/');
+ if ($knownPath === '') {
+ return $path;
+ }
+
+ $pos = strpos($path, $knownPath);
+ if ($pos === 0) {
+ return substr($path, strlen($knownPath));
+ }
+
+ return $path;
+ }
}
diff --git a/lib/Service/InterfaceService.php b/lib/Service/InterfaceService.php
index 7e556be90..33eac4b24 100644
--- a/lib/Service/InterfaceService.php
+++ b/lib/Service/InterfaceService.php
@@ -369,31 +369,39 @@ public function getCloudPath(string $route = '', array $args = [], int $interfac
$interface = $this->getCurrentInterface();
}
- $scheme = '';
+ $scheme = $path = '';
switch ($interface) {
case self::IFACE_INTERNAL:
$scheme = $this->configService->getAppValue(ConfigService::INTERNAL_CLOUD_SCHEME);
+ $path = $this->configService->getAppValue(ConfigService::INTERNAL_CLOUD_PATH);
break;
case self::IFACE_FRONTAL:
$scheme = $this->configService->getAppValue(ConfigService::FRONTAL_CLOUD_SCHEME);
+ $path = $this->configService->getAppValue(ConfigService::FRONTAL_CLOUD_PATH);
break;
case self::IFACE0:
$scheme = $this->configService->getAppValue(ConfigService::IFACE0_CLOUD_SCHEME);
+ $path = $this->configService->getAppValue(ConfigService::IFACE0_CLOUD_PATH);
break;
case self::IFACE1:
$scheme = $this->configService->getAppValue(ConfigService::IFACE1_CLOUD_SCHEME);
+ $path = $this->configService->getAppValue(ConfigService::IFACE1_CLOUD_PATH);
break;
case self::IFACE2:
$scheme = $this->configService->getAppValue(ConfigService::IFACE2_CLOUD_SCHEME);
+ $path = $this->configService->getAppValue(ConfigService::IFACE2_CLOUD_PATH);
break;
case self::IFACE3:
$scheme = $this->configService->getAppValue(ConfigService::IFACE3_CLOUD_SCHEME);
+ $path = $this->configService->getAppValue(ConfigService::IFACE3_CLOUD_PATH);
break;
case self::IFACE4:
$scheme = $this->configService->getAppValue(ConfigService::IFACE4_CLOUD_SCHEME);
+ $path = $this->configService->getAppValue(ConfigService::IFACE4_CLOUD_PATH);
break;
case self::IFACE_TEST:
$scheme = $this->configService->getAppValue(ConfigService::IFACE_TEST_SCHEME);
+ $path = $this->configService->getAppValue(ConfigService::IFACE_TEST_PATH);
break;
}
@@ -401,13 +409,12 @@ public function getCloudPath(string $route = '', array $args = [], int $interfac
throw new UnknownInterfaceException('misconfigured scheme');
}
- $base = $scheme . '://' . $this->getCloudInstance();
-
+ $base = $scheme . '://' . $this->getCloudInstance($interface) . $path;
if ($route === '') {
return $base;
}
- return $base . $this->urlGenerator->linkToRoute($route, $args);
+ return $base . $this->configService->linkToRoute($route, $args);
}
@@ -440,7 +447,7 @@ public function getLocalPath(string $route, array $args): string {
return $this->configService->getLoopbackPath($route, $args);
}
- return rtrim($base, '/') . $this->urlGenerator->linkToRoute($route, $args);
+ return rtrim($base, '/') . $this->configService->linkToRoute($route, $args);
}