aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/dav/lib/CardDAV/Converter.php2
-rw-r--r--apps/dav/tests/unit/CardDAV/ConverterTest.php46
-rw-r--r--apps/encryption/lib/Crypto/Encryption.php8
-rw-r--r--apps/encryption/lib/Session.php10
-rw-r--r--apps/encryption/tests/Crypto/EncryptionTest.php15
-rw-r--r--apps/encryption/tests/SessionTest.php26
-rw-r--r--apps/files_sharing/lib/Activity/Providers/Downloads.php12
-rw-r--r--core/js/sharedialogview.js12
-rw-r--r--lib/base.php10
-rw-r--r--lib/private/AppFramework/Http/Request.php33
-rw-r--r--tests/lib/AppFramework/Http/RequestTest.php70
11 files changed, 222 insertions, 22 deletions
diff --git a/apps/dav/lib/CardDAV/Converter.php b/apps/dav/lib/CardDAV/Converter.php
index 065c5494ec3..ba0c4c2a2d5 100644
--- a/apps/dav/lib/CardDAV/Converter.php
+++ b/apps/dav/lib/CardDAV/Converter.php
@@ -71,7 +71,7 @@ class Converter {
break;
case AccountManager::PROPERTY_AVATAR:
if ($image !== null) {
- $vCard->add('PHOTO', $image->data(), ['ENCODING' => 'b', 'TYPE' => $image->mimeType()]);
+ $vCard->add('PHOTO', 'data:'.$image->mimeType().';base64,' . base64_encode($image->data()));
}
break;
case AccountManager::PROPERTY_EMAIL:
diff --git a/apps/dav/tests/unit/CardDAV/ConverterTest.php b/apps/dav/tests/unit/CardDAV/ConverterTest.php
index 737bbd96aaa..528b3aa9ef4 100644
--- a/apps/dav/tests/unit/CardDAV/ConverterTest.php
+++ b/apps/dav/tests/unit/CardDAV/ConverterTest.php
@@ -134,11 +134,45 @@ class ConverterTest extends TestCase {
public function providesNewUsers() {
return [
- [null],
- [null, null, 'foo@bar.net'],
- [['cloud' => 'foo@cloud.net', 'email' => 'foo@bar.net'], null, 'foo@bar.net', 'foo@cloud.net'],
- [['cloud' => 'foo@cloud.net', 'email' => 'foo@bar.net', 'fn' => 'Dr. Foo Bar'], "Dr. Foo Bar", "foo@bar.net", 'foo@cloud.net'],
- [['cloud' => 'foo@cloud.net', 'fn' => 'Dr. Foo Bar'], "Dr. Foo Bar", null, "foo@cloud.net"],
+ [
+ null
+ ],
+ [
+ null,
+ null,
+ 'foo@bar.net'
+ ],
+ [
+ [
+ 'cloud' => 'foo@cloud.net',
+ 'email' => 'foo@bar.net',
+ 'photo' => 'data:image/jpeg;base64,MTIzNDU2Nzg5',
+ ],
+ null,
+ 'foo@bar.net',
+ 'foo@cloud.net'
+ ],
+ [
+ [
+ 'cloud' => 'foo@cloud.net',
+ 'email' => 'foo@bar.net',
+ 'fn' => 'Dr. Foo Bar',
+ 'photo' => 'data:image/jpeg;base64,MTIzNDU2Nzg5',
+ ],
+ "Dr. Foo Bar",
+ "foo@bar.net",
+ 'foo@cloud.net'
+ ],
+ [
+ [
+ 'cloud' => 'foo@cloud.net',
+ 'fn' => 'Dr. Foo Bar',
+ 'photo' => 'data:image/jpeg;base64,MTIzNDU2Nzg5',
+ ],
+ "Dr. Foo Bar",
+ null,
+ "foo@cloud.net"
+ ],
];
}
@@ -171,7 +205,7 @@ class ConverterTest extends TestCase {
*/
protected function getUserMock($displayName, $eMailAddress, $cloudId) {
$image0 = $this->getMockBuilder(IImage::class)->disableOriginalConstructor()->getMock();
- $image0->method('mimeType')->willReturn('JPEG');
+ $image0->method('mimeType')->willReturn('image/jpeg');
$image0->method('data')->willReturn('123456789');
$user = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
$user->method('getUID')->willReturn('12345');
diff --git a/apps/encryption/lib/Crypto/Encryption.php b/apps/encryption/lib/Crypto/Encryption.php
index c71e25b6442..fdcbd41a09c 100644
--- a/apps/encryption/lib/Crypto/Encryption.php
+++ b/apps/encryption/lib/Crypto/Encryption.php
@@ -177,6 +177,14 @@ class Encryption implements IEncryptionModule {
$this->isWriteOperation = false;
$this->writeCache = '';
+ if($this->session->isReady() === false) {
+ // if the master key is enabled we can initialize encryption
+ // with a empty password and user name
+ if ($this->util->isMasterKeyEnabled()) {
+ $this->keyManager->init('', '');
+ }
+ }
+
if ($this->session->decryptAllModeActivated()) {
$encryptedFileKey = $this->keyManager->getEncryptedFileKey($this->path);
$shareKey = $this->keyManager->getShareKey($this->path, $this->session->getDecryptAllUid());
diff --git a/apps/encryption/lib/Session.php b/apps/encryption/lib/Session.php
index 92132d6080c..a61ee25fadb 100644
--- a/apps/encryption/lib/Session.php
+++ b/apps/encryption/lib/Session.php
@@ -68,6 +68,16 @@ class Session {
}
/**
+ * check if encryption was initialized successfully
+ *
+ * @return bool
+ */
+ public function isReady() {
+ $status = $this->getStatus();
+ return $status === self::INIT_SUCCESSFUL;
+ }
+
+ /**
* Gets user or public share private key from session
*
* @return string $privateKey The user's plaintext private key
diff --git a/apps/encryption/tests/Crypto/EncryptionTest.php b/apps/encryption/tests/Crypto/EncryptionTest.php
index 658f6275bb4..3525d2d4aec 100644
--- a/apps/encryption/tests/Crypto/EncryptionTest.php
+++ b/apps/encryption/tests/Crypto/EncryptionTest.php
@@ -280,6 +280,21 @@ class EncryptionTest extends TestCase {
}
/**
+ * test begin() if encryption is not initialized but the master key is enabled
+ * in this case we can initialize the encryption without a username/password
+ * and continue
+ */
+ public function testBeginInitMasterKey() {
+
+ $this->sessionMock->expects($this->once())->method('isReady')->willReturn(false);
+ $this->utilMock->expects($this->once())->method('isMasterKeyEnabled')
+ ->willReturn(true);
+ $this->keyManagerMock->expects($this->once())->method('init')->with('', '');
+
+ $this->instance->begin('/user/files/welcome.txt', 'user', 'r', [], []);
+ }
+
+ /**
* @dataProvider dataTestUpdate
*
* @param string $fileKey
diff --git a/apps/encryption/tests/SessionTest.php b/apps/encryption/tests/SessionTest.php
index 099acddbca1..3000fedf2c3 100644
--- a/apps/encryption/tests/SessionTest.php
+++ b/apps/encryption/tests/SessionTest.php
@@ -134,6 +134,32 @@ class SessionTest extends TestCase {
}
/**
+ * @dataProvider dataTestIsReady
+ *
+ * @param int $status
+ * @param bool $expected
+ */
+ public function testIsReady($status, $expected) {
+ /** @var Session | \PHPUnit_Framework_MockObject_MockObject $instance */
+ $instance = $this->getMockBuilder(Session::class)
+ ->setConstructorArgs([$this->sessionMock])
+ ->setMethods(['getStatus'])->getMock();
+
+ $instance->expects($this->once())->method('getStatus')
+ ->willReturn($status);
+
+ $this->assertSame($expected, $instance->isReady());
+ }
+
+ public function dataTestIsReady() {
+ return [
+ [Session::INIT_SUCCESSFUL, true],
+ [Session::INIT_EXECUTED, false],
+ [Session::NOT_INITIALIZED, false],
+ ];
+ }
+
+ /**
* @param $key
* @param $value
*/
diff --git a/apps/files_sharing/lib/Activity/Providers/Downloads.php b/apps/files_sharing/lib/Activity/Providers/Downloads.php
index 84ef5895dde..39e2a846b30 100644
--- a/apps/files_sharing/lib/Activity/Providers/Downloads.php
+++ b/apps/files_sharing/lib/Activity/Providers/Downloads.php
@@ -87,7 +87,7 @@ class Downloads implements IProvider {
public function parseShortVersion(IEvent $event) {
$parsedParameters = $this->getParsedParameters($event);
- if ($event->getSubject() === self::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED ||
+ if ($event->getSubject() === self::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED ||
$event->getSubject() === self::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED) {
$event->setParsedSubject($this->l->t('Downloaded via public link'))
->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'actions/download.svg')));
@@ -114,7 +114,7 @@ class Downloads implements IProvider {
public function parseLongVersion(IEvent $event) {
$parsedParameters = $this->getParsedParameters($event);
- if ($event->getSubject() === self::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED ||
+ if ($event->getSubject() === self::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED ||
$event->getSubject() === self::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED) {
$event->setParsedSubject($this->l->t('%1$s downloaded via public link', [
$parsedParameters['file']['path'],
@@ -150,6 +150,11 @@ class Downloads implements IProvider {
$parameters = $event->getSubjectParameters();
switch ($subject) {
+ case self::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED:
+ case self::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED:
+ return [
+ 'file' => $this->generateFileParameter($event->getObjectId(), $parameters[0]),
+ ];
case self::SUBJECT_SHARED_FILE_BY_EMAIL_DOWNLOADED:
case self::SUBJECT_SHARED_FOLDER_BY_EMAIL_DOWNLOADED:
return [
@@ -161,7 +166,8 @@ class Downloads implements IProvider {
],
];
}
- return [];
+
+ throw new \InvalidArgumentException();
}
/**
diff --git a/core/js/sharedialogview.js b/core/js/sharedialogview.js
index 6377d16dd4c..f83a2675958 100644
--- a/core/js/sharedialogview.js
+++ b/core/js/sharedialogview.js
@@ -265,17 +265,11 @@
var text = item.label;
if (item.value.shareType === OC.Share.SHARE_TYPE_GROUP) {
- text = t('core', '{sharee} (group)', {
- sharee: text
- });
+ text = t('core', '{sharee} (group)', { sharee: text }, undefined, { escape: false });
} else if (item.value.shareType === OC.Share.SHARE_TYPE_REMOTE) {
- text = t('core', '{sharee} (remote)', {
- sharee: text
- });
+ text = t('core', '{sharee} (remote)', { sharee: text }, undefined, { escape: false });
} else if (item.value.shareType === OC.Share.SHARE_TYPE_EMAIL) {
- text = t('core', '{sharee} (email)', {
- sharee: text
- });
+ text = t('core', '{sharee} (email)', { sharee: text }, undefined, { escape: false });
}
var insert = $("<div class='share-autocomplete-item'/>");
var avatar = $("<div class='avatardiv'></div>").appendTo(insert);
diff --git a/lib/base.php b/lib/base.php
index d6c6e17eff9..2f5517f4614 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -493,10 +493,18 @@ class OC {
'lax',
'strict',
];
+
+ // Append __Host to the cookie if it meets the requirements
+ $cookiePrefix = '';
+ if($cookieParams['secure'] === true && $cookieParams['path'] === '/') {
+ $cookiePrefix = '__Host-';
+ }
+
foreach($policies as $policy) {
header(
sprintf(
- 'Set-Cookie: nc_sameSiteCookie%s=true; path=%s; httponly;' . $secureCookie . 'expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=%s',
+ 'Set-Cookie: %snc_sameSiteCookie%s=true; path=%s; httponly;' . $secureCookie . 'expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=%s',
+ $cookiePrefix,
$policy,
$cookieParams['path'],
$policy
diff --git a/lib/private/AppFramework/Http/Request.php b/lib/private/AppFramework/Http/Request.php
index c7a3be163fe..62d7fc7ed30 100644
--- a/lib/private/AppFramework/Http/Request.php
+++ b/lib/private/AppFramework/Http/Request.php
@@ -498,6 +498,31 @@ class Request implements \ArrayAccess, \Countable, IRequest {
}
/**
+ * Wrapper around session_get_cookie_params
+ *
+ * @return array
+ */
+ protected function getCookieParams() {
+ return session_get_cookie_params();
+ }
+
+ /**
+ * Appends the __Host- prefix to the cookie if applicable
+ *
+ * @param string $name
+ * @return string
+ */
+ protected function getProtectedCookieName($name) {
+ $cookieParams = $this->getCookieParams();
+ $prefix = '';
+ if($cookieParams['secure'] === true && $cookieParams['path'] === '/') {
+ $prefix = '__Host-';
+ }
+
+ return $prefix.$name;
+ }
+
+ /**
* Checks if the strict cookie has been sent with the request if the request
* is including any cookies.
*
@@ -508,7 +533,9 @@ class Request implements \ArrayAccess, \Countable, IRequest {
if(!$this->cookieCheckRequired()) {
return true;
}
- if($this->getCookie('nc_sameSiteCookiestrict') === 'true'
+
+ $cookieName = $this->getProtectedCookieName('nc_sameSiteCookiestrict');
+ if($this->getCookie($cookieName) === 'true'
&& $this->passesLaxCookieCheck()) {
return true;
}
@@ -526,7 +553,9 @@ class Request implements \ArrayAccess, \Countable, IRequest {
if(!$this->cookieCheckRequired()) {
return true;
}
- if($this->getCookie('nc_sameSiteCookielax') === 'true') {
+
+ $cookieName = $this->getProtectedCookieName('nc_sameSiteCookielax');
+ if($this->getCookie($cookieName) === 'true') {
return true;
}
return false;
diff --git a/tests/lib/AppFramework/Http/RequestTest.php b/tests/lib/AppFramework/Http/RequestTest.php
index 1ba20869439..b1515b0efb5 100644
--- a/tests/lib/AppFramework/Http/RequestTest.php
+++ b/tests/lib/AppFramework/Http/RequestTest.php
@@ -1500,6 +1500,76 @@ class RequestTest extends \Test\TestCase {
$this->assertFalse($request->passesCSRFCheck());
}
+ public function testPassesStrictCookieCheckWithAllCookiesAndStrict() {
+ /** @var Request $request */
+ $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
+ ->setMethods(['getScriptName', 'getCookieParams'])
+ ->setConstructorArgs([
+ [
+ 'server' => [
+ 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
+ ],
+ 'cookies' => [
+ session_name() => 'asdf',
+ '__Host-nc_sameSiteCookiestrict' => 'true',
+ '__Host-nc_sameSiteCookielax' => 'true',
+ ],
+ ],
+ $this->secureRandom,
+ $this->config,
+ $this->csrfTokenManager,
+ $this->stream
+ ])
+ ->getMock();
+ $request
+ ->expects($this->any())
+ ->method('getCookieParams')
+ ->willReturn([
+ 'secure' => true,
+ 'path' => '/',
+ ]);
+
+ $this->assertTrue($request->passesStrictCookieCheck());
+ }
+
+ public function testFailsStrictCookieCheckWithAllCookiesAndMissingStrict() {
+ /** @var Request $request */
+ $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
+ ->setMethods(['getScriptName', 'getCookieParams'])
+ ->setConstructorArgs([
+ [
+ 'server' => [
+ 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
+ ],
+ 'cookies' => [
+ session_name() => 'asdf',
+ 'nc_sameSiteCookiestrict' => 'true',
+ 'nc_sameSiteCookielax' => 'true',
+ ],
+ ],
+ $this->secureRandom,
+ $this->config,
+ $this->csrfTokenManager,
+ $this->stream
+ ])
+ ->getMock();
+ $request
+ ->expects($this->any())
+ ->method('getCookieParams')
+ ->willReturn([
+ 'secure' => true,
+ 'path' => '/',
+ ]);
+
+ $this->assertFalse($request->passesStrictCookieCheck());
+ }
+
+ public function testGetCookieParams() {
+ $request = $this->createMock(Request::class);
+ $actual = $this->invokePrivate($request, 'getCookieParams');
+ $this->assertSame(session_get_cookie_params(), $actual);
+ }
+
public function testPassesStrictCookieCheckWithAllCookies() {
/** @var Request $request */
$request = $this->getMockBuilder('\OC\AppFramework\Http\Request')