Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117769706
D3989.1775236432.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
19 KB
Referenced Files
None
Subscribers
None
D3989.1775236432.diff
View Options
diff --git a/src/tests/Infrastructure/ActivesyncTest.php b/src/tests/Infrastructure/ActivesyncTest.php
new file mode 100644
--- /dev/null
+++ b/src/tests/Infrastructure/ActivesyncTest.php
@@ -0,0 +1,150 @@
+<?php
+
+namespace Tests\Infrastructure;
+
+use Tests\TestCase;
+
+class ActivesyncTest extends TestCase
+{
+ private \GuzzleHttp\Client $client;
+
+ private static function toWbxml($xml)
+ {
+ $outputStream = fopen("php://temp", 'r+');
+ $encoder = new \Syncroton_Wbxml_Encoder($outputStream, 'UTF-8', 3);
+ $dom = new \DOMDocument();
+ $dom->loadXML($xml);
+ $encoder->encode($dom);
+ rewind($outputStream);
+ return stream_get_contents($outputStream);
+ }
+
+ private static function fromWbxml($binary)
+ {
+ $stream = fopen('php://memory', 'r+');
+ fwrite($stream, $binary);
+ rewind($stream);
+ $decoder = new \Syncroton_Wbxml_Decoder($stream);
+ return $decoder->decode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function setUp(): void
+ {
+ parent::setUp();
+
+ //FIXME test users are probably not created in imap,
+ //which is why this fails. So we're using john@kolab.org for now.
+ // $user = $this->getTestUser('jane@kolabnow.com');
+ // $user->password = "simple123";
+ // $user->save();
+
+ $this->client = new \GuzzleHttp\Client([
+ 'http_errors' => false, // No exceptions
+ 'base_uri' => "http://roundcube/Microsoft-Server-ActiveSync/",
+ 'verify' => false,
+ // 'auth' => [$user->email, $user->password],
+ 'auth' => ['john@kolab.org', 'simple123'],
+ 'connect_timeout' => 10,
+ 'timeout' => 10,
+ 'headers' => [
+ "Content-Type" => "application/xml; charset=utf-8"
+ ]
+ ]);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function tearDown(): void
+ {
+ // $this->deleteTestUser('jane@kolabnow.com');
+ parent::tearDown();
+ }
+
+ public function testOptions()
+ {
+ $response = $this->client->request('OPTIONS', '');
+ $this->assertEquals(200, $response->getStatusCode());
+ $this->assertTrue(str_contains($response->getHeader('MS-Server-ActiveSync')[0], '14'));
+ $this->assertTrue(str_contains($response->getHeader('MS-ASProtocolVersions')[0], '14.1'));
+ $this->assertTrue(str_contains($response->getHeader('MS-ASProtocolCommands')[0], 'FolderSync'));
+ }
+
+ public function testFolderList()
+ {
+ $request = <<<EOF
+ <?xml version="1.0" encoding="utf-8"?>
+ <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/">
+ <FolderSync xmlns="uri:FolderHierarchy">
+ <SyncKey>0</SyncKey>
+ </FolderSync>
+ EOF;
+ $body = self::toWbxml($request);
+ $response = $this->client->request('POST', '?Cmd=FolderSync&User=john@kolab.org&DeviceId=v140Device&DeviceType=iphone', [
+ 'headers' => [
+ "Content-Type" => "application/vnd.ms-sync.wbxml",
+ 'MS-ASProtocolVersion' => "14.0"
+ ],
+ 'body' => $body
+ ]);
+ $this->assertEquals(200, $response->getStatusCode());
+ $result = self::fromWbxml($response->getBody())->saveXML();
+ $this->assertTrue(str_contains($result, 'INBOX'));
+ $this->assertTrue(str_contains($result, 'Drafts'));
+ $this->assertTrue(str_contains($result, 'Sent'));
+ $this->assertTrue(str_contains($result, 'Trash'));
+ $this->assertTrue(str_contains($result, 'Calendar'));
+ $this->assertTrue(str_contains($result, 'Contacts'));
+
+ //TODO extract the collectionid for the next step
+ }
+
+ public function testInitialSync()
+ {
+ $request = <<<EOF
+ <?xml version="1.0" encoding="utf-8"?>
+ <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/">
+ <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase">
+ <Collections>
+ <Collection>
+ <SyncKey>0</SyncKey>
+ <CollectionId>cca1b81c734abbcd669bea90d23e08ae</CollectionId>
+ <DeletesAsMoves>0</DeletesAsMoves>
+ <GetChanges>0</GetChanges>
+ <WindowSize>512</WindowSize>
+ <Options>
+ <FilterType>0</FilterType>
+ <BodyPreference xmlns="uri:AirSyncBase">
+ <Type>1</Type>
+ <AllOrNone>1</AllOrNone>
+ </BodyPreference>
+ </Options>
+ </Collection>
+ </Collections>
+ <WindowSize>16</WindowSize>
+ </Sync>
+ EOF;
+ $body = self::toWbxml($request);
+ $response = $this->client->request('POST', '?Cmd=Sync&User=john@kolab.org&DeviceId=v140Device&DeviceType=iphone', [
+ 'headers' => [
+ "Content-Type" => "application/vnd.ms-sync.wbxml",
+ 'MS-ASProtocolVersion' => "14.0"
+ ],
+ 'body' => $body
+ ]);
+ $this->assertEquals(200, $response->getStatusCode());
+ $dom = self::fromWbxml($response->getBody());
+ $collections = $dom->getElementsByTagName('Collection');
+ $this->assertEquals(1, $collections->length);
+ $collection = $collections->item(0);
+ $this->assertEquals("Class", $collection->childNodes->item(0)->nodeName);
+ $this->assertEquals("Calendar", $collection->childNodes->item(0)->nodeValue);
+ $this->assertEquals("SyncKey", $collection->childNodes->item(1)->nodeName);
+ $this->assertEquals("1", $collection->childNodes->item(1)->nodeValue);
+ $this->assertEquals("Status", $collection->childNodes->item(3)->nodeName);
+ $this->assertEquals("1", $collection->childNodes->item(3)->nodeValue);
+ }
+}
diff --git a/src/tests/Infrastructure/AutodiscoverTest.php b/src/tests/Infrastructure/AutodiscoverTest.php
new file mode 100644
--- /dev/null
+++ b/src/tests/Infrastructure/AutodiscoverTest.php
@@ -0,0 +1,86 @@
+<?php
+
+namespace Tests\Infrastructure;
+
+use Tests\TestCase;
+
+class AutodiscoverTest extends TestCase
+{
+ private \GuzzleHttp\Client $client;
+ /**
+ * {@inheritDoc}
+ */
+ public function setUp(): void
+ {
+ parent::setUp();
+ $this->client = new \GuzzleHttp\Client([
+ 'http_errors' => false, // No exceptions
+ 'base_uri' => "http://roundcube/",
+ 'verify' => false,
+ 'connect_timeout' => 10,
+ 'timeout' => 10,
+ ]);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function tearDown(): void
+ {
+ parent::tearDown();
+ }
+
+ public function testWellKnownOutlook()
+ {
+ $body = <<<EOF
+ <Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006">
+ <Request>
+ <EMailAddress>admin@example.local</EMailAddress>
+ <AcceptableResponseSchema>
+ http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a
+ </AcceptableResponseSchema>
+ </Request>
+ </Autodiscover>
+ EOF;
+ $response = $this->client->request('POST', 'autodiscover/autodiscover.xml', [
+ 'headers' => [
+ "Content-Type" => "text/xml; charset=utf-8"
+ ],
+ 'body' => $body
+ ]);
+ $this->assertEquals($response->getStatusCode(), 200);
+ $data = $response->getBody();
+ $this->assertTrue(str_contains($data, '<Server>example.local</Server>'));
+ $this->assertTrue(str_contains($data, 'admin@example.local'));
+ }
+
+ public function testWellKnownActivesync()
+ {
+ $body = <<<EOF
+ <Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/mobilesync/requestschema/2006">
+ <Request>
+ <EMailAddress>admin@example.local</EMailAddress>
+ <AcceptableResponseSchema>
+ http://schemas.microsoft.com/exchange/autodiscover/mobilesync/responseschema/2006
+ </AcceptableResponseSchema>
+ </Request>
+ </Autodiscover>
+ EOF;
+ $response = $this->client->request('POST', 'autodiscover/autodiscover.xml', [
+ 'headers' => [
+ "Content-Type" => "text/xml; charset=utf-8"
+ ],
+ 'body' => $body
+ ]);
+ $this->assertEquals($response->getStatusCode(), 200);
+ $data = $response->getBody();
+ $this->assertTrue(str_contains($data, '<Url>https://example.local/Microsoft-Server-ActiveSync</Url>'));
+ $this->assertTrue(str_contains($data, 'admin@example.local'));
+ }
+
+ public function testWellKnownMail()
+ {
+ $response = $this->client->request('GET', '.well-known/autoconfig/mail/config-v1.1.xml?emailaddress=fred@example.com');
+ $this->assertEquals($response->getStatusCode(), 200);
+ }
+}
diff --git a/src/tests/Infrastructure/ChwalaTest.php b/src/tests/Infrastructure/ChwalaTest.php
new file mode 100644
--- /dev/null
+++ b/src/tests/Infrastructure/ChwalaTest.php
@@ -0,0 +1,70 @@
+<?php
+
+namespace Tests\Infrastructure;
+
+use Tests\TestCase;
+
+class ChwalaTest extends TestCase
+{
+ private \GuzzleHttp\Client $client;
+ /**
+ * {@inheritDoc}
+ */
+ public function setUp(): void
+ {
+ parent::setUp();
+
+ //FIXME test users are probably not created in imap,
+ //which is why this fails. So we're using john@kolab.org for now.
+ // $user = $this->getTestUser('jane@kolabnow.com');
+ // $user->password = "simple123";
+ // $user->save();
+
+ $this->client = new \GuzzleHttp\Client([
+ 'base_uri' => "http://roundcube/chwala/",
+ 'verify' => false,
+ // 'auth' => [$user->email, $user->password],
+ 'auth' => ['john@kolab.org', 'simple123'],
+ 'connect_timeout' => 10,
+ 'timeout' => 10
+ ]);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function tearDown(): void
+ {
+ $this->deleteTestUser('jane@kolabnow.com');
+
+ parent::tearDown();
+ }
+
+ public function testAccess()
+ {
+ //FIXME IF we use this application as a proxy this would look neater and could swap the implementation without anyone noticing.
+ //What other benefits could there be?
+ //Performance is the drawback
+
+ $response = $this->client->request('GET', 'api/?method=authenticate&version=4');
+ $this->assertEquals($response->getStatusCode(), 200);
+ $json = json_decode($response->getBody(), true);
+
+ $this->assertEquals('OK', $json['status']);
+ $token = $json['result']['token'];
+ $this->assertTrue(!empty($token));
+
+ //FIXME the session token doesn't seem to be required
+ $response = $this->client->request('GET', 'api/?method=mimetypes', [
+ 'headers' => [
+ 'X-Session_token' => $token
+ ]
+ ]);
+ $this->assertEquals($response->getStatusCode(), 200);
+ $json = json_decode($response->getBody(), true);
+ $this->assertEquals('OK', $json['status']);
+ $this->assertEquals('OK', $json['status']);
+ $this->assertContains('image/png', $json['result']['view']);
+ $this->assertArrayHasKey('text/plain', $json['result']['edit']);
+ }
+}
diff --git a/src/tests/Infrastructure/DavTest.php b/src/tests/Infrastructure/DavTest.php
new file mode 100644
--- /dev/null
+++ b/src/tests/Infrastructure/DavTest.php
@@ -0,0 +1,227 @@
+<?php
+
+namespace Tests\Infrastructure;
+
+use Tests\TestCase;
+
+class DavTest extends TestCase
+{
+ private \GuzzleHttp\Client $client;
+ /**
+ * {@inheritDoc}
+ */
+ public function setUp(): void
+ {
+ parent::setUp();
+
+ //FIXME test users are probably not created in imap,
+ //which is why this fails. So we're using john@kolab.org for now.
+ // $user = $this->getTestUser('jane@kolabnow.com');
+ // $user->password = "simple123";
+ // $user->save();
+
+ $this->client = new \GuzzleHttp\Client([
+ 'http_errors' => false, // No exceptions
+ 'base_uri' => "http://roundcube/",
+ 'verify' => false,
+ // 'auth' => [$user->email, $user->password],
+ 'auth' => ['john@kolab.org', 'simple123'],
+ 'connect_timeout' => 10,
+ 'timeout' => 10,
+ 'headers' => [
+ "Content-Type" => "application/xml; charset=utf-8",
+ "Depth" => "1",
+ ]
+ ]);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function tearDown(): void
+ {
+ // $this->deleteTestUser('jane@kolabnow.com');
+
+ parent::tearDown();
+ }
+
+ public function testDiscoverPrincipal()
+ {
+
+ $body = "<d:propfind xmlns:d='DAV:'><d:prop><d:current-user-principal/></d:prop></d:propfind>";
+ $response = $this->client->request('PROPFIND', '/iRony/', ['body' => $body]);
+ $this->assertEquals(207, $response->getStatusCode());
+ $data = $response->getBody();
+ $this->assertTrue(str_contains($data, '<d:href>/iRony/principals/john@kolab.org/</d:href>'));
+ $this->assertTrue(str_contains($data, '<d:href>/iRony/calendars/</d:href>'));
+ $this->assertTrue(str_contains($data, '<d:href>/iRony/addressbooks/</d:href>'));
+ }
+
+ /**
+ *
+ * This codepath is triggerd by MacOS CalDAV when it tries to login.
+ * Verify we don't crash and end up with a 500 status code.
+ */
+ public function testFailingLogin()
+ {
+ $body = "<d:propfind xmlns:d='DAV:'><d:prop><d:current-user-principal/></d:prop></d:propfind>";
+ $headers = [
+ "Content-Type" => "application/xml; charset=utf-8",
+ "Depth" => "1",
+ 'body' => $body,
+ 'auth' => ['invaliduser@kolab.org', 'invalid']
+ ];
+
+ $response = $this->client->request('PROPFIND', '/iRony/', $headers);
+ $this->assertEquals(401, $response->getStatusCode());
+ }
+
+ /**
+ * This codepath is triggerd by MacOS CardDAV when it tries to login.
+ * NOTE: This depends on the username_domain roundcube config option.
+ */
+ public function testShortlogin()
+ {
+ $body = "<d:propfind xmlns:d='DAV:'><d:prop><d:current-user-principal/></d:prop></d:propfind>";
+ $response = $this->client->request('PROPFIND', '/iRony/', [
+ 'body' => $body,
+ 'auth' => ['john', 'simple123']
+ ]);
+ $this->assertEquals(207, $response->getStatusCode());
+ }
+
+ public function testDiscoverCalendarHomeset()
+ {
+ $body = <<<EOF
+ <d:propfind xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
+ <d:prop>
+ <c:calendar-home-set />
+ </d:prop>
+ </d:propfind>
+ EOF;
+
+ $response = $this->client->request('PROPFIND', '/iRony/', ['body' => $body]);
+ $this->assertEquals(207, $response->getStatusCode());
+ $data = $response->getBody();
+ $this->assertTrue(str_contains($data, '<d:href>/iRony/calendars/john@kolab.org/</d:href>'));
+ }
+
+ public function testDiscoverCalendars()
+ {
+ $body = <<<EOF
+ <d:propfind xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/" xmlns:c="urn:ietf:params:xml:ns:caldav">
+ <d:prop>
+ <d:resourcetype />
+ <d:displayname />
+ <cs:getctag />
+ <c:supported-calendar-component-set />
+ </d:prop>
+ </d:propfind>
+ EOF;
+
+ $response = $this->client->request('PROPFIND', '/iRony/calendars/john@kolab.org', [
+ 'headers' => [
+ "Depth" => "infinity",
+ ],
+ 'body' => $body
+ ]);
+ $this->assertEquals(207, $response->getStatusCode());
+ $data = $response->getBody();
+ $this->assertTrue(str_contains($data, '<d:href>/iRony/calendars/john@kolab.org/</d:href>'));
+
+ $doc = new \DOMDocument('1.0', 'UTF-8');
+ $doc->loadXML($data);
+ $response = $doc->getElementsByTagName('response')->item(1);
+ $doc->getElementsByTagName('href')->item(0);
+
+ $this->assertEquals("d:href", $response->childNodes->item(0)->nodeName);
+ $href = $response->childNodes->item(0)->nodeValue;
+ return $href;
+ }
+
+ /**
+ * @depends testDiscoverCalendars
+ */
+ public function testPropfindCalendar($href)
+ {
+ $body = <<<EOF
+ <d:propfind xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/" xmlns:c="urn:ietf:params:xml:ns:caldav">
+ <d:prop>
+ <d:resourcetype />
+ <d:owner/>
+ <d:current-user-principal/>
+ <d:current-user-privilege-set/>
+ <d:supported-report-set/>
+ <cs:getctag />
+ <c:supported-calendar-component-set />
+ </d:prop>
+ </d:propfind>
+ EOF;
+
+ $response = $this->client->request('PROPFIND', $href, [
+ 'headers' => [
+ "Depth" => "0",
+ ],
+ 'body' => $body,
+ ]);
+ $this->assertEquals(207, $response->getStatusCode());
+ $data = $response->getBody();
+ $this->assertTrue(str_contains($data, "<d:href>$href</d:href>"));
+ }
+
+ /**
+ * Thunderbird does this and relies on the WWW-Authenticate header response to
+ * start sending authenticated requests.
+ *
+ * @depends testDiscoverCalendars
+ */
+ public function testPropfindCalendarWithoutAuth($href)
+ {
+ $body = <<<EOF
+ <d:propfind xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/" xmlns:c="urn:ietf:params:xml:ns:caldav">
+ <d:prop>
+ <d:resourcetype />
+ <d:owner/>
+ <d:current-user-principal/>
+ <d:current-user-privilege-set/>
+ <d:supported-report-set/>
+ <cs:getctag />
+ <c:supported-calendar-component-set />
+ </d:prop>
+ </d:propfind>
+ EOF;
+
+ $response = $this->client->request('PROPFIND', $href, [
+ 'headers' => [
+ "Depth" => "0",
+ ],
+ 'body' => $body,
+ 'auth' => []
+ ]);
+ $this->assertEquals(401, $response->getStatusCode());
+ $this->assertTrue(str_contains($response->getHeader('WWW-Authenticate')[0], 'Basic realm='));
+ $data = $response->getBody();
+ $this->assertTrue(str_contains($data, "<s:exception>Sabre\DAV\Exception\NotAuthenticated</s:exception>"));
+ }
+
+ /**
+ * Required for MacOS autoconfig
+ */
+ public function testOptions()
+ {
+ $body = <<<EOF
+ <d:propfind xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/" xmlns:c="urn:ietf:params:xml:ns:caldav">
+ <d:prop>
+ <d:resourcetype />
+ <d:displayname />
+ <cs:getctag />
+ <c:supported-calendar-component-set />
+ </d:prop>
+ </d:propfind>
+ EOF;
+
+ $response = $this->client->request('OPTIONS', '/iRony/principals/john@kolab.org/', ['body' => $body]);
+ $this->assertEquals(200, $response->getStatusCode());
+ $this->assertTrue(str_contains($response->getHeader('Allow')[0], 'PROPFIND'));
+ }
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Apr 3, 5:13 PM (1 d, 2 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18823737
Default Alt Text
D3989.1775236432.diff (19 KB)
Attached To
Mode
D3989: Added infrastructure tests for Activesync/CalDav/WOPI/Roundcube & fixed the well-known redirect for caldav.
Attached
Detach File
Event Timeline