Skip to content

Commit

Permalink
Merge branch 'master' into fix/issue-48079-windows-time-zones
Browse files Browse the repository at this point in the history
  • Loading branch information
SebastianKrupinski authored Nov 26, 2024
2 parents d17895e + 01b2ae4 commit 4fad4d8
Show file tree
Hide file tree
Showing 120 changed files with 962 additions and 331 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/cypress.yml
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ jobs:

- name: Create data dir archive
if: failure() && matrix.containers != 'component'
run: docker exec nextcloud-cypress-tests-server tar -cvjf - data > data.tar
run: docker exec nextcloud-cypress-tests_server tar -cvjf - data > data.tar

- name: Upload data dir archive
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/files-external-smb-kerberos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ jobs:
repository: nextcloud/user_saml
path: apps/user_saml

- name: Install user_saml
run: |
cd apps/user_saml
composer i
cd ../..
- name: Pull images
run: |
docker pull ghcr.io/icewind1991/samba-krb-test-dc
Expand Down
2 changes: 1 addition & 1 deletion apps/dav/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@
'OCA\\DAV\\Events\\SubscriptionUpdatedEvent' => $baseDir . '/../lib/Events/SubscriptionUpdatedEvent.php',
'OCA\\DAV\\Exception\\ServerMaintenanceMode' => $baseDir . '/../lib/Exception/ServerMaintenanceMode.php',
'OCA\\DAV\\Exception\\UnsupportedLimitOnInitialSyncException' => $baseDir . '/../lib/Exception/UnsupportedLimitOnInitialSyncException.php',
'OCA\\DAV\\Files\\ErrorPagePlugin' => $baseDir . '/../lib/Files/ErrorPagePlugin.php',
'OCA\\DAV\\Files\\BrowserErrorPagePlugin' => $baseDir . '/../lib/Files/BrowserErrorPagePlugin.php',
'OCA\\DAV\\Files\\FileSearchBackend' => $baseDir . '/../lib/Files/FileSearchBackend.php',
'OCA\\DAV\\Files\\FilesHome' => $baseDir . '/../lib/Files/FilesHome.php',
'OCA\\DAV\\Files\\LazySearchBackend' => $baseDir . '/../lib/Files/LazySearchBackend.php',
Expand Down
2 changes: 1 addition & 1 deletion apps/dav/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ class ComposerStaticInitDAV
'OCA\\DAV\\Events\\SubscriptionUpdatedEvent' => __DIR__ . '/..' . '/../lib/Events/SubscriptionUpdatedEvent.php',
'OCA\\DAV\\Exception\\ServerMaintenanceMode' => __DIR__ . '/..' . '/../lib/Exception/ServerMaintenanceMode.php',
'OCA\\DAV\\Exception\\UnsupportedLimitOnInitialSyncException' => __DIR__ . '/..' . '/../lib/Exception/UnsupportedLimitOnInitialSyncException.php',
'OCA\\DAV\\Files\\ErrorPagePlugin' => __DIR__ . '/..' . '/../lib/Files/ErrorPagePlugin.php',
'OCA\\DAV\\Files\\BrowserErrorPagePlugin' => __DIR__ . '/..' . '/../lib/Files/BrowserErrorPagePlugin.php',
'OCA\\DAV\\Files\\FileSearchBackend' => __DIR__ . '/..' . '/../lib/Files/FileSearchBackend.php',
'OCA\\DAV\\Files\\FilesHome' => __DIR__ . '/..' . '/../lib/Files/FilesHome.php',
'OCA\\DAV\\Files\\LazySearchBackend' => __DIR__ . '/..' . '/../lib/Files/LazySearchBackend.php',
Expand Down
8 changes: 4 additions & 4 deletions apps/dav/lib/CalDAV/CalDavBackend.php
Original file line number Diff line number Diff line change
Expand Up @@ -3569,9 +3569,9 @@ protected function purgeCalendarInvitations(int $calendarId): void {
// delete all links that match object uid's
$cmd = $this->db->getQueryBuilder();
$cmd->delete($this->dbObjectInvitationsTable)
->where($cmd->expr()->in('uid', $cmd->createNamedParameter('uids'), IQueryBuilder::PARAM_STR_ARRAY));
foreach (array_chunk($allIds, 1000) as $chunckIds) {
$cmd->setParameter('uids', $chunckIds, IQueryBuilder::PARAM_INT_ARRAY);
->where($cmd->expr()->in('uid', $cmd->createParameter('uids'), IQueryBuilder::PARAM_STR_ARRAY));
foreach (array_chunk($allIds, 1000) as $chunkIds) {
$cmd->setParameter('uids', $chunkIds, IQueryBuilder::PARAM_STR_ARRAY);
$cmd->executeStatement();
}
}
Expand All @@ -3588,7 +3588,7 @@ protected function purgeCalendarInvitations(int $calendarId): void {
protected function purgeObjectInvitations(string $eventId): void {
$cmd = $this->db->getQueryBuilder();
$cmd->delete($this->dbObjectInvitationsTable)
->where($cmd->expr()->eq('uid', $cmd->createNamedParameter($eventId)));
->where($cmd->expr()->eq('uid', $cmd->createNamedParameter($eventId, IQueryBuilder::PARAM_STR), IQueryBuilder::PARAM_STR));
$cmd->executeStatement();
}
}
75 changes: 72 additions & 3 deletions apps/dav/lib/Connector/Sabre/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
*/
namespace OCA\DAV\Connector\Sabre;

use Sabre\DAV\Exception;
use Sabre\DAV\Version;

/**
* Class \OCA\DAV\Connector\Sabre\Server
*
Expand All @@ -26,9 +29,11 @@ public function __construct($treeOrNode = null) {
$this->enablePropfindDepthInfinity = true;
}

// Copied from 3rdparty/sabre/dav/lib/DAV/Server.php
// Should be them exact same without the exception output.
public function start(): void {
/**
*
* @return void
*/
public function start() {
try {
// If nginx (pre-1.2) is used as a proxy server, and SabreDAV as an
// origin, we must make sure we send back HTTP/1.0 if this was
Expand All @@ -42,10 +47,74 @@ public function start(): void {
$this->httpRequest->setBaseUrl($this->getBaseUri());
$this->invokeMethod($this->httpRequest, $this->httpResponse);
} catch (\Throwable $e) {
if ($e instanceof \TypeError) {
/*
* The TypeError includes the file path where the error occurred,
* potentially revealing the installation directory.
*
* By re-throwing the exception, we ensure that the
* default exception handler processes it.
*/
throw $e;
}

try {
$this->emit('exception', [$e]);
} catch (\Exception $ignore) {
}

$DOM = new \DOMDocument('1.0', 'utf-8');
$DOM->formatOutput = true;

$error = $DOM->createElementNS('DAV:', 'd:error');
$error->setAttribute('xmlns:s', self::NS_SABREDAV);
$DOM->appendChild($error);

$h = function ($v) {
return htmlspecialchars((string)$v, ENT_NOQUOTES, 'UTF-8');
};

if (self::$exposeVersion) {
$error->appendChild($DOM->createElement('s:sabredav-version', $h(Version::VERSION)));
}

$error->appendChild($DOM->createElement('s:exception', $h(get_class($e))));
$error->appendChild($DOM->createElement('s:message', $h($e->getMessage())));
if ($this->debugExceptions) {
$error->appendChild($DOM->createElement('s:file', $h($e->getFile())));
$error->appendChild($DOM->createElement('s:line', $h($e->getLine())));
$error->appendChild($DOM->createElement('s:code', $h($e->getCode())));
$error->appendChild($DOM->createElement('s:stacktrace', $h($e->getTraceAsString())));
}

if ($this->debugExceptions) {
$previous = $e;
while ($previous = $previous->getPrevious()) {
$xPrevious = $DOM->createElement('s:previous-exception');
$xPrevious->appendChild($DOM->createElement('s:exception', $h(get_class($previous))));
$xPrevious->appendChild($DOM->createElement('s:message', $h($previous->getMessage())));
$xPrevious->appendChild($DOM->createElement('s:file', $h($previous->getFile())));
$xPrevious->appendChild($DOM->createElement('s:line', $h($previous->getLine())));
$xPrevious->appendChild($DOM->createElement('s:code', $h($previous->getCode())));
$xPrevious->appendChild($DOM->createElement('s:stacktrace', $h($previous->getTraceAsString())));
$error->appendChild($xPrevious);
}
}

if ($e instanceof Exception) {
$httpCode = $e->getHTTPCode();
$e->serialize($this, $error);
$headers = $e->getHTTPHeaders($this);
} else {
$httpCode = 500;
$headers = [];
}
$headers['Content-Type'] = 'application/xml; charset=utf-8';

$this->httpResponse->setStatus($httpCode);
$this->httpResponse->setHeaders($headers);
$this->httpResponse->setBody($DOM->saveXML());
$this->sapi->sendResponse($this->httpResponse);
}
}
}
6 changes: 4 additions & 2 deletions apps/dav/lib/Connector/Sabre/ServerFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
use OCA\DAV\CalDAV\DefaultCalendarValidator;
use OCA\DAV\DAV\CustomPropertiesBackend;
use OCA\DAV\DAV\ViewOnlyPlugin;
use OCA\DAV\Files\ErrorPagePlugin;
use OCA\DAV\Files\BrowserErrorPagePlugin;
use OCA\Theming\ThemingDefaults;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\Folder;
Expand Down Expand Up @@ -90,7 +90,9 @@ public function createServer(string $baseUri,
$server->addPlugin(new FakeLockerPlugin());
}

$server->addPlugin(new ErrorPagePlugin($this->request, $this->config));
if (BrowserErrorPagePlugin::isBrowserRequest($this->request)) {
$server->addPlugin(new BrowserErrorPagePlugin());
}

// wait with registering these until auth is handled and the filesystem is setup
$server->on('beforeMethod:*', function () use ($server, $objectTree, $viewCallBack): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,17 @@
*/
namespace OCA\DAV\Files;

use OC\AppFramework\Http\Request;
use OC_Template;
use OCP\AppFramework\Http\ContentSecurityPolicy;
use OCP\IConfig;
use OCP\IRequest;
use Sabre\DAV\Exception;
use Sabre\DAV\Server;
use Sabre\DAV\ServerPlugin;

class ErrorPagePlugin extends ServerPlugin {
private ?Server $server = null;

public function __construct(
private IRequest $request,
private IConfig $config,
) {
}
class BrowserErrorPagePlugin extends ServerPlugin {
/** @var Server */
private $server;

/**
* This initializes the plugin.
Expand All @@ -31,12 +26,35 @@ public function __construct(
* addPlugin is called.
*
* This method should set up the required event subscriptions.
*
* @param Server $server
* @return void
*/
public function initialize(Server $server): void {
public function initialize(Server $server) {
$this->server = $server;
$server->on('exception', [$this, 'logException'], 1000);
}

/**
* @param IRequest $request
* @return bool
*/
public static function isBrowserRequest(IRequest $request) {
if ($request->getMethod() !== 'GET') {
return false;
}
return $request->isUserAgent([
Request::USER_AGENT_IE,
Request::USER_AGENT_MS_EDGE,
Request::USER_AGENT_CHROME,
Request::USER_AGENT_FIREFOX,
Request::USER_AGENT_SAFARI,
]);
}

/**
* @param \Throwable $ex
*/
public function logException(\Throwable $ex): void {
if ($ex instanceof Exception) {
$httpCode = $ex->getHTTPCode();
Expand All @@ -47,7 +65,7 @@ public function logException(\Throwable $ex): void {
}
$this->server->httpResponse->addHeaders($headers);
$this->server->httpResponse->setStatus($httpCode);
$body = $this->generateBody($ex, $httpCode);
$body = $this->generateBody($httpCode);
$this->server->httpResponse->setBody($body);
$csp = new ContentSecurityPolicy();
$this->server->httpResponse->addHeader('Content-Security-Policy', $csp->buildPolicy());
Expand All @@ -58,32 +76,18 @@ public function logException(\Throwable $ex): void {
* @codeCoverageIgnore
* @return bool|string
*/
public function generateBody(\Throwable $ex, int $httpCode): mixed {
if ($this->acceptHtml()) {
$templateName = 'exception';
$renderAs = 'guest';
if ($httpCode === 403 || $httpCode === 404) {
$templateName = (string)$httpCode;
}
} else {
$templateName = 'xml_exception';
$renderAs = null;
$this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8');
}
public function generateBody(int $httpCode) {
$request = \OC::$server->getRequest();

$debug = $this->config->getSystemValueBool('debug', false);
$templateName = 'exception';
if ($httpCode === 403 || $httpCode === 404) {
$templateName = (string)$httpCode;
}

$content = new OC_Template('core', $templateName, $renderAs);
$content = new OC_Template('core', $templateName, 'guest');
$content->assign('title', $this->server->httpResponse->getStatusText());
$content->assign('remoteAddr', $this->request->getRemoteAddress());
$content->assign('requestID', $this->request->getId());
$content->assign('debugMode', $debug);
$content->assign('errorClass', get_class($ex));
$content->assign('errorMsg', $ex->getMessage());
$content->assign('errorCode', $ex->getCode());
$content->assign('file', $ex->getFile());
$content->assign('line', $ex->getLine());
$content->assign('exception', $ex);
$content->assign('remoteAddr', $request->getRemoteAddress());
$content->assign('requestID', $request->getId());
return $content->fetchPage();
}

Expand All @@ -92,15 +96,6 @@ public function generateBody(\Throwable $ex, int $httpCode): mixed {
*/
public function sendResponse() {
$this->server->sapi->sendResponse($this->server->httpResponse);
}

private function acceptHtml(): bool {
foreach (explode(',', $this->request->getHeader('Accept')) as $part) {
$subparts = explode(';', $part);
if (str_ends_with($subparts[0], '/html')) {
return true;
}
}
return false;
exit();
}
}
6 changes: 4 additions & 2 deletions apps/dav/lib/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
use OCA\DAV\DAV\ViewOnlyPlugin;
use OCA\DAV\Events\SabrePluginAddEvent;
use OCA\DAV\Events\SabrePluginAuthInitEvent;
use OCA\DAV\Files\ErrorPagePlugin;
use OCA\DAV\Files\BrowserErrorPagePlugin;
use OCA\DAV\Files\FileSearchBackend;
use OCA\DAV\Files\LazySearchBackend;
use OCA\DAV\Profiler\ProfilerPlugin;
Expand Down Expand Up @@ -244,7 +244,9 @@ public function __construct(
$this->server->addPlugin(new FakeLockerPlugin());
}

$this->server->addPlugin(new ErrorPagePlugin($this->request, \OC::$server->getConfig()));
if (BrowserErrorPagePlugin::isBrowserRequest($request)) {
$this->server->addPlugin(new BrowserErrorPagePlugin());
}

$lazySearchBackend = new LazySearchBackend();
$this->server->addPlugin(new SearchPlugin($lazySearchBackend));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2701,7 +2701,7 @@
<callback>prepostcondition</callback>
<arg>
<name>error</name>
<value>{http://sabredav.org/ns}exception</value>
<value>{DAV:}valid-sync-token</value>
</arg>
<arg>
<name>ignoreextras</name>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,20 @@
*/
namespace OCA\DAV\Tests\unit\DAV;

use OCA\DAV\Files\ErrorPagePlugin;
use OCA\DAV\Files\BrowserErrorPagePlugin;
use Sabre\DAV\Exception\NotFound;
use Sabre\HTTP\Response;

class ErrorPagePluginTest extends \Test\TestCase {
class BrowserErrorPagePluginTest extends \Test\TestCase {

/**
* @dataProvider providesExceptions
* @param $expectedCode
* @param $exception
*/
public function test($expectedCode, $exception): void {
/** @var ErrorPagePlugin | \PHPUnit\Framework\MockObject\MockObject $plugin */
$plugin = $this->getMockBuilder(ErrorPagePlugin::class)->disableOriginalConstructor()->setMethods(['sendResponse', 'generateBody'])->getMock();
/** @var BrowserErrorPagePlugin | \PHPUnit\Framework\MockObject\MockObject $plugin */
$plugin = $this->getMockBuilder(BrowserErrorPagePlugin::class)->setMethods(['sendResponse', 'generateBody'])->getMock();
$plugin->expects($this->once())->method('generateBody')->willReturn(':boom:');
$plugin->expects($this->once())->method('sendResponse');
/** @var \Sabre\DAV\Server | \PHPUnit\Framework\MockObject\MockObject $server */
Expand Down
4 changes: 2 additions & 2 deletions apps/files/l10n/ar.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ OC.L10N.register(
"Ownership transfer request sent" : "طلب نقل الملكية أرسل بنجاح",
"Cannot transfer ownership of a file or folder you do not own" : "لايمكنك نقل ملكية ملف أو مجلد لا تملكه",
"Select file or folder to link to" : "اختر ملف أو مجلد للربط معه",
"Choose {file}" : "إختَر {file}",
"Choose {file}" : "إختر {file}",
"New" : "جديد",
"Loading current folder" : "تحميل المجلد الحالي",
"Retry" : "أعِدِ المحاولة",
Expand Down Expand Up @@ -393,7 +393,7 @@ OC.L10N.register(
"Name cannot be empty" : "لا يمكن أن يكون الاسم فارغاً",
"Another entry with the same name already exists" : "إدخال آخر بنفس الاسم موجود بالفعل",
"Could not rename \"{oldName}\", it does not exist any more" : "تعذر إعادة تسمية \"{oldName}\"، لم يعد موجودًا",
"The name \"{newName}\" is already used in the folder \"{dir}\". Please choose a different name." : "الاسم \"{newName}\" مُستعمَلٌ سلفاً في المجلّد\"{dir}\". إختَر اسماً آخر رجاءً.",
"The name \"{newName}\" is already used in the folder \"{dir}\". Please choose a different name." : "الاسم \"{newName}\" مستعمل سلفاً في المجلد\"{dir}\". إختر اسماً آخر رجاءً.",
"Could not rename \"{oldName}\"" : "تعذرت إعادة تسمية \"{oldName}\"",
"Storage informations" : "معلومات التخزين",
"Choose file" : "حدد ملف",
Expand Down
Loading

0 comments on commit 4fad4d8

Please sign in to comment.