mirror of
https://gitlab.com/davical-project/davical.git
synced 2026-01-27 00:33:34 +00:00
First (untested) cut at MKTICKET implementation.
This commit is contained in:
parent
567ff944a0
commit
0fffd0e417
@ -306,11 +306,13 @@ CREATE INDEX sync_processing_index ON sync_changes( collection_id, dav_id, sync_
|
||||
|
||||
CREATE TABLE access_ticket (
|
||||
ticket_id TEXT PRIMARY KEY,
|
||||
dav_owner_id INT8 NOT NULL REFERENCES principal(principal_id) ON UPDATE CASCADE ON DELETE CASCADE,
|
||||
is_public BOOLEAN,
|
||||
privileges BIT(24),
|
||||
target_collection_id INT8 NOT NULL REFERENCES collection(collection_id) ON UPDATE CASCADE ON DELETE CASCADE,
|
||||
target_resource_id INT8 REFERENCES caldav_data(dav_id) ON UPDATE CASCADE ON DELETE CASCADE,
|
||||
expires TIMESTAMP
|
||||
expires TIMESTAMP,
|
||||
visits INT8
|
||||
);
|
||||
|
||||
|
||||
|
||||
@ -11,11 +11,13 @@ ALTER TABLE caldav_data ADD COLUMN weak_etag TEXT DEFAULT NULL;
|
||||
|
||||
CREATE TABLE access_ticket (
|
||||
ticket_id TEXT PRIMARY KEY,
|
||||
dav_owner_id INT8 NOT NULL REFERENCES principal(principal_id) ON UPDATE CASCADE ON DELETE CASCADE,
|
||||
is_public BOOLEAN,
|
||||
privileges BIT(24),
|
||||
target_collection_id INT8 NOT NULL REFERENCES collection(collection_id) ON UPDATE CASCADE ON DELETE CASCADE,
|
||||
target_resource_id INT8 REFERENCES caldav_data(dav_id) ON UPDATE CASCADE ON DELETE CASCADE,
|
||||
expires TIMESTAMP
|
||||
expires TIMESTAMP,
|
||||
visits INT8
|
||||
);
|
||||
|
||||
|
||||
|
||||
@ -59,23 +59,24 @@ if ( ! ($request->IsPrincipal() || isset($request->collection) || $request->meth
|
||||
}
|
||||
|
||||
switch ( $request->method ) {
|
||||
case 'OPTIONS': include_once('caldav-OPTIONS.php'); break;
|
||||
case 'REPORT': include_once('caldav-REPORT.php'); break;
|
||||
case 'PROPFIND': include('caldav-PROPFIND.php'); break;
|
||||
case 'PUT': include('caldav-PUT.php'); break;
|
||||
case 'GET': include('caldav-GET.php'); break;
|
||||
case 'HEAD': include('caldav-GET.php'); break;
|
||||
case 'PROPPATCH': include('caldav-PROPPATCH.php'); break;
|
||||
case 'MKCALENDAR': include('caldav-MKCOL.php'); break;
|
||||
case 'MKCOL': include('caldav-MKCOL.php'); break;
|
||||
case 'DELETE': include('caldav-DELETE.php'); break;
|
||||
case 'POST': include('caldav-POST.php'); break;
|
||||
case 'MOVE': include('caldav-MOVE.php'); break;
|
||||
case 'ACL': include('caldav-ACL.php'); break;
|
||||
case 'LOCK': include('caldav-LOCK.php'); break;
|
||||
case 'UNLOCK': include('caldav-LOCK.php'); break;
|
||||
case 'OPTIONS': include_once('caldav-OPTIONS.php'); break;
|
||||
case 'REPORT': include_once('caldav-REPORT.php'); break;
|
||||
case 'PROPFIND': include('caldav-PROPFIND.php'); break;
|
||||
case 'PUT': include('caldav-PUT.php'); break;
|
||||
case 'GET': include('caldav-GET.php'); break;
|
||||
case 'HEAD': include('caldav-GET.php'); break;
|
||||
case 'PROPPATCH': include('caldav-PROPPATCH.php'); break;
|
||||
case 'MKCALENDAR': include('caldav-MKCOL.php'); break;
|
||||
case 'MKCOL': include('caldav-MKCOL.php'); break;
|
||||
case 'DELETE': include('caldav-DELETE.php'); break;
|
||||
case 'POST': include('caldav-POST.php'); break;
|
||||
case 'MOVE': include('caldav-MOVE.php'); break;
|
||||
case 'ACL': include('caldav-ACL.php'); break;
|
||||
case 'LOCK': include('caldav-LOCK.php'); break;
|
||||
case 'UNLOCK': include('caldav-LOCK.php'); break;
|
||||
case 'MKTICKET': include('caldav-MKTICKET.php'); break;
|
||||
|
||||
case 'TESTRRULE': include('test-RRULE-v2.php'); break;
|
||||
case 'TESTRRULE': include('test-RRULE-v2.php'); break;
|
||||
|
||||
default:
|
||||
dbg_error_log( 'caldav', 'Unhandled request method >>%s<<', $request->method );
|
||||
|
||||
@ -534,18 +534,7 @@ EOQRY;
|
||||
if ( !isset($this->privileges) ) $this->FetchPrivileges();
|
||||
$privilege_names = bits_to_privilege($this->privileges);
|
||||
}
|
||||
if ( !isset($xmldoc) && isset($GLOBALS['reply']) ) $xmldoc = $GLOBALS['reply'];
|
||||
$privileges = array();
|
||||
foreach( $privilege_names AS $k ) {
|
||||
// dbg_error_log( 'DAVResource', 'Adding privilege "%s".', $k );
|
||||
$privilege = new XMLElement('privilege');
|
||||
if ( isset($xmldoc) )
|
||||
$xmldoc->NSElement($privilege,$k);
|
||||
else
|
||||
$privilege->NewElement($k);
|
||||
$privileges[] = $privilege;
|
||||
}
|
||||
return $privileges;
|
||||
return privileges_to_XML( $privilege_names, $xmldoc);
|
||||
}
|
||||
|
||||
|
||||
@ -592,6 +581,7 @@ EOQRY;
|
||||
$this->supported_methods['GET'] = '';
|
||||
$this->supported_methods['PUT'] = '';
|
||||
$this->supported_methods['HEAD'] = '';
|
||||
$this->supported_methods['MKTICKET'] = '';
|
||||
break;
|
||||
case 'collection':
|
||||
case 'principal':
|
||||
@ -610,7 +600,8 @@ EOQRY;
|
||||
array(
|
||||
'GET' => '',
|
||||
'HEAD' => '',
|
||||
'PUT' => ''
|
||||
'PUT' => '',
|
||||
'MKTICKET' => ''
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@ -469,3 +469,22 @@ function bits_to_privilege( $raw_bits ) {
|
||||
|
||||
return $out_priv;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the array of privilege names converted into XMLElements
|
||||
*/
|
||||
function privileges_to_XML( $privilege_names, &$xmldoc=null ) {
|
||||
if ( !isset($xmldoc) && isset($GLOBALS['reply']) ) $xmldoc = $GLOBALS['reply'];
|
||||
$privileges = array();
|
||||
foreach( $privilege_names AS $k ) {
|
||||
$privilege = new XMLElement('privilege');
|
||||
if ( isset($xmldoc) )
|
||||
$xmldoc->NSElement($privilege,$k);
|
||||
else
|
||||
$privilege->NewElement($k);
|
||||
$privileges[] = $privilege;
|
||||
}
|
||||
return $privileges;
|
||||
}
|
||||
|
||||
|
||||
@ -469,3 +469,22 @@ function bits_to_privilege( $raw_bits ) {
|
||||
|
||||
return $out_priv;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the array of privilege names converted into XMLElements
|
||||
*/
|
||||
function privileges_to_XML( $privilege_names, &$xmldoc=null ) {
|
||||
if ( !isset($xmldoc) && isset($GLOBALS['reply']) ) $xmldoc = $GLOBALS['reply'];
|
||||
$privileges = array();
|
||||
foreach( $privilege_names AS $k ) {
|
||||
$privilege = new XMLElement('privilege');
|
||||
if ( isset($xmldoc) )
|
||||
$xmldoc->NSElement($privilege,$k);
|
||||
else
|
||||
$privilege->NewElement($k);
|
||||
$privileges[] = $privilege;
|
||||
}
|
||||
return $privileges;
|
||||
}
|
||||
|
||||
|
||||
123
inc/caldav-MKTICKET.php
Normal file
123
inc/caldav-MKTICKET.php
Normal file
@ -0,0 +1,123 @@
|
||||
<?php
|
||||
/**
|
||||
* CalDAV Server - handle MKTICKET method in line with defunct proposed RFC
|
||||
* from: http://tools.ietf.org/html/draft-ito-dav-ticket-00
|
||||
*
|
||||
* Why are we using a defunct RFC? Well, we want to support some kind of system
|
||||
* for providing a URI to people to give out for granting privileged access
|
||||
* without requiring logins. Using a defunct proposed spec seems better than
|
||||
* inventing our own. As well as Xythos, Cosmo follows this specification,
|
||||
* with some documented variations, which we will also follow. In particular
|
||||
* we use the xmlns="http://www.xythos.com/namespaces/StorageServer" rather
|
||||
* than the DAV: namespace.
|
||||
*
|
||||
* @package davical
|
||||
* @subpackage caldav
|
||||
* @author Andrew McMillan <andrew@mcmillan.net.nz>
|
||||
* @copyright Morphoss Ltd - http://www.morphoss.com/
|
||||
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2 or later
|
||||
*/
|
||||
dbg_error_log('MKTICKET', 'method handler');
|
||||
require_once('AwlQuery.php');
|
||||
|
||||
$request->NeedPrivilege('DAV::bind');
|
||||
|
||||
require_once('XMLDocument.php');
|
||||
$reply = new XMLDocument(array( 'DAV:' => '', 'T' => 'http://www.xythos.com/namespaces/StorageServer', 'DT' => 'http://xmlns.davical.org/ticket' ));
|
||||
|
||||
$target = new DAVResource( $request->path );
|
||||
if ( ! $target->Exists() ) {
|
||||
$request->XMLResponse( 404, $reply->Render( 'error', new XMLElement('not-found') ) );
|
||||
}
|
||||
|
||||
if ( ! isset($request->xml_tags) ) {
|
||||
$request->XMLResponse( 400, $reply->Render( 'error', new XMLElement('missing-xml-for-request') ) );
|
||||
}
|
||||
|
||||
$xmltree = BuildXMLTree( $request->xml_tags, $position);
|
||||
if ( $xmltree->GetTag() != 'http://www.xythos.com/namespaces/StorageServer:ticketinfo' ) {
|
||||
$request->XMLResponse( 400, $reply->Render( 'error', new XMLElement('invalid-xml-for-request') ) );
|
||||
}
|
||||
|
||||
$ticket_visits = 'infinity';
|
||||
$ticket_timeout = 'Seconds-3600';
|
||||
$ticket_public = 0;
|
||||
$ticket_privs_array = array('read-free-busy');
|
||||
$ticketinfo = $xmltree->GetContent();
|
||||
foreach( $ticketinfo AS $k => $v ) {
|
||||
// <!ELEMENT ticketinfo (id?, owner?, timeout, visits, privilege)>
|
||||
switch( $v->GetTag() ) {
|
||||
case 'DAV::timeout':
|
||||
case 'http://www.xythos.com/namespaces/StorageServer:timeout':
|
||||
$ticket_timeout = $v->GetContent();
|
||||
break;
|
||||
|
||||
case 'DAV::public':
|
||||
case 'http://xmlns.davical.org/ticket:public':
|
||||
$ticket_public = 1;
|
||||
break;
|
||||
|
||||
case 'DAV::visits':
|
||||
case 'http://www.xythos.com/namespaces/StorageServer:visits':
|
||||
$ticket_visits = $v->GetContent();
|
||||
break;
|
||||
|
||||
case 'DAV::privilege':
|
||||
case 'http://www.xythos.com/namespaces/StorageServer:privilege':
|
||||
$ticket_privs_array = $v->GetElements(); // Ensure we always get an array back
|
||||
$ticket_privileges = 0;
|
||||
foreach( $ticket_privs_array AS $k1 => $v1 ) {
|
||||
$ticket_privileges |= privilege_to_bits( $v1->GetTag() );
|
||||
}
|
||||
if ( $ticket_privileges & privilege_to_bits('write') ) $ticket_privileges |= privilege_to_bits( 'read' );
|
||||
if ( $ticket_privileges & privilege_to_bits('read') ) $ticket_privileges |= privilege_to_bits( array('read-free-busy', 'read-current-user-privilege-set') );
|
||||
if ( $ticket_privileges & privilege_to_bits('read-free-busy') ) $ticket_privileges |= privilege_to_bits( 'schedule-query-freebusy') );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( preg_match( '{^([a-z]+)-(\d+)$}', $ticket_timeout, $matches ) ) {
|
||||
/** It isn't specified, but timeout seems to be 'unit-number' like 'Seconds-3600', so we make it '3600 Seconds' which PostgreSQL understands */
|
||||
$sql_timeout = $matches[2] . ' ' . $matches[1];
|
||||
}
|
||||
else {
|
||||
$sql_timeout = $ticket_timeout;
|
||||
}
|
||||
|
||||
$sql_visits = ( $ticket_visits == 'infinity' ? -1: intval($ticket_visits) );
|
||||
|
||||
$collection_id = $target->GetProperty('collection_id');
|
||||
$resource_id = $target->GetProperty('dav_id');
|
||||
|
||||
$i = 0;
|
||||
do {
|
||||
$ticket_id = substr(sha1(date('r') .rand(2100000000) . microtime(true)), 7, 8);
|
||||
$qry = new AwlQuery(
|
||||
'INSERT INTO access_ticket ( ticket_id, dav_owner_id, is_public, privileges, target_collection_id, target_resource_id, expires, visits )
|
||||
VALUES( :ticket_id, :owner, :public, :privs, :collection, :resource, (current_timestamp + interval :expires), :visits )',
|
||||
array(
|
||||
':ticket_id' => $ticket_id,
|
||||
':owner' => $session->principal_id,
|
||||
':public' => $ticket_public,
|
||||
':privs' => $ticket_privileges,
|
||||
':collection' => $collection_id,
|
||||
':resource' => $resource_id,
|
||||
':expires' => $sql_timeout,
|
||||
':visits' => $sql_visits
|
||||
)
|
||||
)
|
||||
$result = $qry->Exec('MKTICKET', __LINE__, __FILE__);
|
||||
} while( !$result && $i++ < 2 );
|
||||
|
||||
|
||||
$ticketinfo = new XMLElement( 'T:ticketinfo', array(
|
||||
new XMLElement( 'T:id', $ticket_id),
|
||||
new XMLElement( 'owner', $reply->href( ConstructURL($session->dav_name) ) ),
|
||||
new XMLElement( 'privilege', privileges_to_XML(bits_to_privilege($ticket_privileges),$reply)),
|
||||
new XMLElement( 'T:timeout', $ticket_timeout),
|
||||
new XMLElement( 'T:visits', $ticket_visits)
|
||||
)
|
||||
);
|
||||
if ( $ticket_public ) $ticketinfo->NewElement( 'DT:public', $ticket_public);
|
||||
|
||||
$request->XMLResponse( 200, $reply->Render( 'prop', new XMLElement('T:ticketdiscovery', $ticketinfo) ) );
|
||||
Loading…
x
Reference in New Issue
Block a user