# Collection Sharing Static collection sharing without permissions filter using soft-links (Unix-only) is supported since storage type `multifilesystem` was implemented, see (Wiki: Sharing Collections)[https://github.com/Kozea/Radicale/wiki/Sharing-Collections] With 3.7.0 a major extension was implemented using internal mapping configuration stored in a database and a management API. ## Sharing Configuration Store Types of supported sharing configuration: * csv (_>= 3.7.0_) * files (_>= 3.7.0_) ### Sharing Configuration Entry Data * `ShareType`: type of share * `token`: token-based share (do not require user authentication) * `map`: map-based share (requires user authentication) * `PathOrToken`: token or "virtual" collection, has to be unique (PRIMARY KEY) * `PathMapped`: target collection * `Owner`: owner of the share * `User`: user of the share * `Permissions`: effective permission of the share * `EnabledByOwner`: control by owner * `EnabledByUser`: control by user * `HiddenByOwner`: control by owner * `HiddenByUser`: control by user * `TimestampCreated`: unixtime of creation * `TimestampUpdated`: unixtime of last update * `Properties`: overlay properties (limited set whitelisted) `Enabled*`: owner AND user have to enable a share to become usable `Hidden*`: owner AND user have to disable a share to become visible in PROPFIND ### Sharing Configuration Entry Storage #### CSV (_>= 3.7.0_) One CSV file containing one row per sharing config, separated by `,` and containing header with columns from above. #### Files (_>= 3.7.0_) File-based configuration store is using encoded `PathOrToken` as filename for each config. File contains the data stored as "dict" in binary Python "pickle" format (same is also used for item cache files). ## Sharing Access ### Sharing Access via Maps (_>= 3.7.0_) Map-based sharing can be accessed as usual after authentication and authorization. #### Workflow * create map as owner * enable map as owner (can be combined with "create") * enable map as user (explicit required to avoid sudden available share) In case share should be visible using PROPFIND * unhide map as owner (can be combined with "create") * unhide map as user (explicit required to avoid sudden visible share) ### Sharing Access via Tokens (_>= 3.7.0_) Token-based sharing can be accessed after retrieving the token via Token-URI: `/.token/` #### Workflow * create token as owner * enable token as owner (can be combined with "create") * handover URI with token to client ## Sharing Configuration Management API ### Sharing Configuration Management API version 1 (_>= 3.7.0_) Type: POST API Base-URI: `/.sharing/v1//` See also test cases in `radicale/tests/test_sharing.py` #### Data Format ##### Input Data Format Parsing be controlled by `CONTENT_TYPE` * application/x-www-form-urlencoded (_>= 3.7.0_) * application/json (_>= 3.7.0_) ##### Output Data Format Can be selected by `HTTP_ACCEPT` * text/plain (_>= 3.7.0_) * text/csv (_>= 3.7.0_) - only for "list" * application/json (_>= 3.7.0_) ##### Accepted Input Data Fields * `PathOrToken`: token or "virtual" collection * `PathMapped`: target collection * `Owner`: owner of the share * `User`: user of the share * `Permissions`: effective permission of the share * `Enabled`: owner/user selected by authentication * `Hidden`: owner/user selected by authentication #### API Hooks ##### API Hook "info" Shows what kind of ShareTypes are supported * Example: TEXT ``` curl -u user:pass -H "accept: text/plain" -d "" http://localhost:5232/.sharing/v1/all/info ApiVersion=1 Status=success FeatureEnabledCollectionByMap=True PermittedCreateCollectionByMap=True FeatureEnabledCollectionByToken=True PermittedCreateCollectionByToken=True ``` * Example: JSON ``` curl -u user:pass --silent -H "accept: application/json" -d "" http://localhost:5232/.sharing/v1/all/info | jq { "ApiVersion": 1, "Status": "success", "FeatureEnabledCollectionByMap": true, "PermittedCreateCollectionByMap": true, "FeatureEnabledCollectionByToken": true, "PermittedCreateCollectionByToken": true } ``` ##### API Hook "*/create" Create a share ###### API Hook "token/create" * Input | Parameter | Mandatory | Default | | - | - | - | | PathMapped | yes | | | Permissions | no | r * Output | Parameter | Value | | - | - | | PathOrToken | (autogenerated token) | * Example: TEXT ``` curl -u user:pass -d "PathMapped=/user/testcalendar1/" http://localhost:5232/.sharing/v1/token/create ApiVersion=1 Status=success PathOrToken=v1/VQR7AmsVRi2ZlFj_JwGpFx-ES5Goyku-gP_YkLh1zUw= ``` ###### API Hook "map/create" * Input | Parameter | Mandatory | Default | | - | - | - | | PathOrToken | yes | | | PathMapped | yes | | | Permissions | no | r | User | yes | | * Output: result status * Example: TEXT ``` curl -u owner:pass -d "PathOrToken=/user/cal1-from-owner/" -d "PathMapped=/owner/cal1/" -d "User=user" http://localhost:5232/.sharing/v1/map/create ApiVersion=1 Status=success ``` ##### API Hook "*/list" List shares (optional with filter) * Input | Parameter | Mandatory | Default | | - | - | - | | PathMapped | no | (all) | | Owner | no | (owned ones) | | User | no | (filtered) | * Output: plain/csv/json * Example: CSV ``` curl -H "accept: text/csv" -u owner:pass -d "" http://localhost:5232/.sharing/v1/map/list ShareType,PathOrToken,PathMapped,Owner,User,Permissions,EnabledByOwner,EnabledByUser,HiddenByOwner,HiddenByUser,TimestampCreated,TimestampUpdated map,/user/cal1-from-owner/,/owner/cal1/,owner,user,r,False,False,True,True,1771962120,1771962120 ``` ##### API Hook "*/delete" Delete a share selected by `PathOrToken` * Input | Parameter | Mandatory | Default | | - | - | - | | PathOrToken | yes | | * Output: result status ##### API Hook "*/update" Update a share selected by `PathOrToken` * Input | Parameter | Mandatory | Default | | - | - | - | | PathOrToken | yes | n/a | | PathMapped | no | | | OwnerOrUser | yes | n/a | | User | no | | | Properties | no | | * Output: result status ##### API Hooks "*/(enable|disable|hide|unhide)" Enable|disable|hide|unhide a share selected by `PathOrToken` * Input | Parameter | Mandatory | Default | | - | - | - | | PathOrToken | yes | n/a | * Output: result status * Example: TEXT (enable) ``` curl -u owner:pass -d "PathOrToken=/user/cal1-from-owner/" -d "PathMapped=/owner/cal1/" -d "User=user" http://localhost:5232/.sharing/v1/map/enable ApiVersion=1 Status=success ``` * Example: JSON (unhide) ``` curl -u owner:pass -d '{"PathOrToken": "/user/cal1-from-owner/", "PathMapped": "/owner/cal1/", "User": "user"} http://localhost:5232/.sharing/v1/map/unhide ApiVersion=1 Status=success ```