import { DAVNamespace } from 'tsdav' import config from '../lib/config' import { default as WebDAV, DAVInverse } from '../lib/WebDAV' import TestUtility from '../lib/utilities' /** * NOTE * * To pass the following tests, make sure "username" and "subscriber_username" don't have * additional calendars. */ describe('Apple iCal', function() { const webdav = new WebDAV(config.username, config.password) const webdav_su = new WebDAV(config.superuser, config.superuser_password) const utility = new TestUtility(webdav_su) const iCal4UserAgent = 'DAVKit/4.0.1 (730); CalendarStore/4.0.1 (973); iCal/4.0.1 (1374); Mac OS X/10.6.2 (10C540)' const _setMemberSet = async function(owner, members, perm) { const resource = `/SOGo/dav/${owner}/calendar-proxy-${perm}` const headers = { 'User-Agent': iCal4UserAgent } const membersHref = members.map(m => { return `/SOGo/dav/${m}` }) const properties = { 'group-member-set': membersHref.length ? { href: membersHref } : '' } const results = await webdav_su.proppatchWebdav(resource, properties, DAVNamespace.DAV, headers) expect(results.length) .withContext(`Number of responses from PROPPATCH on group-member-set for ${owner}`) .toBe(1) expect(results[0].status) .withContext(`HTTP status code when setting group member on calendar-proxy-${perm} for ${owner}`) .toBe(207) } const _getMembership = async function(user) { const resource = `/SOGo/dav/${user}/` const headers = { 'User-Agent': iCal4UserAgent } const results = await webdav_su.propfindWebdav(resource, ['group-membership'], DAVNamespace.DAV, headers) expect(results.length) .withContext(`Number of responses from PROPFIND on group-membership for ${user}`) .toBe(1) expect(results[0].status) .withContext(`HTTP status code when getting group membership for ${user}`) .toBe(207) const { props: { groupMembership: { href = [] } = {} } = {} } = results[0] return Array.isArray(href) ? href : [href] // always return an array } const _getProxyFor = async function(user, perm) { const resource = `/SOGo/dav/${user}/` const headers = { 'User-Agent': iCal4UserAgent } const results = await webdav_su.propfindWebdav(resource, [`calendar-proxy-${perm}-for`], DAVNamespace.CALENDAR_SERVER, headers) expect(results.length) .withContext(`Number of responses from PROPFIND on group-membership for ${user}`) .toBe(1) expect(results[0].status) .withContext(`HTTP status code when getting group membership for ${user}`) .toBe(207) const { props = {} } = results[0] const users = props[`calendarProxy${perm.replace(/^\w/, (c) => c.toUpperCase())}For`] const { href = [] } = users return Array.isArray(href) ? href : [href] // always return an array } const _testMapping = async function(perm, resource, rights) { const results = await utility.setupCalendarRights(resource, config.subscriber_username, rights) expect(results.length).toBe(1) expect(results[0].status).toBe(204) const membership = await _getMembership(config.subscriber_username) expect(membership) .withContext(`${perm.replace(/^\w/, (c) => c.toUpperCase())} access to /SOGo/dav/${config.subscriber_username}/`) .toContain(`/SOGo/dav/${config.username}/calendar-proxy-${perm}/`) const proxyFor = await _getProxyFor(config.subscriber_username, perm) expect(proxyFor) .withContext(`Proxy ${perm} on /SOGo/dav/${config.subscriber_username}/`) .toContain(`/SOGo/dav/${config.username}/`) } // iCalTest it(`principal-collection-set: 'DAV' header must be returned with iCal 4`, async function() { const resource = `/SOGo/dav/${config.username}/` const expectedDAVClasses = ['1', '2', 'access-control', 'calendar-access', 'calendar-schedule', 'calendar-auto-schedule', 'calendar-proxy'] let headers, response, davClasses, davClass headers = { Depth: new String(0) } // NOT iCal4 response = await webdav.propfindWebdavRaw(resource, ['principal-collection-set'], headers) expect(response.status) .withContext(`HTTP status code when fetching principal-collection-set`) .toBe(207) expect(response.headers.get('dav')) .withContext(`DAV header must NOT be returned when user-agent is NOT iCal 4`) .toBeFalsy() // iCal4 headers['User-Agent'] = iCal4UserAgent response = await webdav.propfindWebdavRaw(resource, ['principal-collection-set'], headers) expect(response.status) .withContext(`HTTP status code when fetching principal-collection-set`) .toBe(207) expect(response.headers.get('dav')) .withContext(`DAV header must be returned when user-agent is iCal 4`) .toBeTruthy() davClasses = response.headers.get('dav').split(', ') for (davClass of expectedDAVClasses) { expect(davClasses.includes(davClass)) .withContext(`DAV header includes class ${davClass}`) .toBeTrue() } }) it(`calendar-proxy as used from iCal`, async function() { let membership, perm, users, proxyFor await _setMemberSet(config.username, [], 'read') await _setMemberSet(config.username, [], 'write') await _setMemberSet(config.subscriber_username, [], 'read') await _setMemberSet(config.subscriber_username, [], 'write') membership = await _getMembership(config.username) expect(membership.length) .toBe(0) membership = await _getMembership(config.subscriber_username) expect(membership.length) .toBe(0) users = await _getProxyFor(config.username, 'read') expect(users.length) .withContext(`Proxy read for /SOGo/dav/${config.username}`) .toBe(0) users = await _getProxyFor(config.username, 'write') expect(users.length) .withContext(`Proxy write for /SOGo/dav/${config.username}`) .toBe(0) users = await _getProxyFor(config.subscriber_username, 'read') expect(users.length) .withContext(`Proxy read for /SOGo/dav/${config.subscriber_username}`) .toBe(0) users = await _getProxyFor(config.subscriber_username, 'write') expect(users.length) .withContext(`Proxy write for /SOGo/dav/${config.subscriber_username}`) .toBe(0) for (perm of ['read', 'write']) { for (users of [[config.username, config.subscriber_username], [config.subscriber_username, config.username]]) { const [owner, member] = users await _setMemberSet(owner, [member], perm) let [ membership ] = await _getMembership(member) expect(membership) .toBe(`/SOGo/dav/${owner}/calendar-proxy-${perm}/`) proxyFor = await _getProxyFor(member, perm) expect(proxyFor.length).toBe(1) expect(proxyFor).toContain(`/SOGo/dav/${owner}/`) } } }) it('calendar-proxy as used from SOGo', async function() { const personalResource = `/SOGo/dav/${config.username}/Calendar/personal/` const otherResource = `/SOGo/dav/${config.username}/Calendar/test-calendar-proxy2/` let response, membership // Remove rights on personal calendar await utility.setupRights(personalResource, config.subscriber_username); [response] = await utility.subscribe(personalResource, [config.subscriber_username]) expect(response.status) .toBe(200) await webdav_su.deleteObject(otherResource) await webdav_su.makeCalendar(otherResource) await utility.setupRights(otherResource, config.subscriber_username); [response] = await utility.subscribe(otherResource, [config.subscriber_username]) expect(response.status) .toBe(200) // we test the rights mapping // write: write on 'personal', none on 'test-calendar-proxy2' await _testMapping('write', personalResource, { c: true, d: false, pu: 'v' }) await _testMapping('write', personalResource, { c: false, d: true, pu: 'v' }) await _testMapping('write', personalResource, { c: false, d: false, pu: 'm' }) await _testMapping('write', personalResource, { c: false, d: false, pu: 'r' }) // read: read on 'personal', none on 'test-calendar-proxy2' await _testMapping('read', personalResource, { c: false, d: false, pu: 'd' }) await _testMapping('read', personalResource, { c: false, d: false, pu: 'v' }) // write: read on 'personal', write on 'test-calendar-proxy2' await _testMapping('write', otherResource, { c: false, d: false, pu: 'r' }); // we test the unsubscription // unsubscribed from personal, subscribed to 'test-calendar-proxy2' [response] = await utility.unsubscribe(personalResource, [config.subscriber_username]) expect(response.status) .toBe(200) membership = await _getMembership(config.subscriber_username) expect(membership) .withContext(`Proxy write to /SOGo/dav/${config.subscriber_username}/`) .toContain(`/SOGo/dav/${config.username}/calendar-proxy-write/`); // unsubscribed from personal, unsubscribed from 'test-calendar-proxy2' [response] = await utility.unsubscribe(otherResource, [config.subscriber_username]) expect(response.status) .toBe(200) membership = await _getMembership(config.subscriber_username) expect(membership.length) .withContext(`No more access to /SOGo/dav/${config.subscriber_username}/`) .toBe(0) await webdav_su.deleteObject(otherResource) }) })