Projects
Kolab:16
chwala
Log In
Username
Password
We truncated the diff of some files because they were too big. If you want to see the full diff for every file,
click here
.
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 21
View file
chwala.spec
Changed
@@ -37,7 +37,7 @@ %global _ap_sysconfdir %{_sysconfdir}/%{httpd_name} Name: chwala -Version: 0.5.3 +Version: 0.5.4 Release: 1%{?dist} Summary: Glorified WebDAV, done right @@ -47,7 +47,7 @@ Source0: https://mirror.kolabenterprise.com/pub/releases/%{name}-%{version}.tar.gz Source2: chwala.logrotate -Patch1: chwala-0.5.3-suhosin.session.encrypt-php_flag.patch +Patch1: chwala-0.5.4-suhosin.session.encrypt-php_flag.patch BuildArch: noarch @@ -158,6 +158,9 @@ %attr(0750,%{httpd_user},%{httpd_group}) %{_localstatedir}/log/%{name} %changelog +* Fri Oct 26 2018 Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> - 0.5.4-1 +- Release 0.5.4 + * Fri Aug 10 2018 Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> - 0.5.3-1 - Release 0.5.3
View file
chwala-0.5.3-suhosin.session.encrypt-php_flag.patch
Deleted
@@ -1,8 +0,0 @@ -diff -ur chwala-0.5.3.orig/public_html/.htaccess chwala-0.5.3/public_html/.htaccess ---- chwala-0.5.3.orig/public_html/.htaccess 2018-06-27 09:07:38.000000000 +0200 -+++ chwala-0.5.3/public_html/.htaccess 2018-08-10 12:25:45.519638515 +0200 -@@ -3,3 +3,4 @@ - php_flag log_errors On - php_flag suhosin.session.encrypt Off - php_value error_log ../logs/errors -+php_flag session.auto_start Off
View file
chwala-0.5.4-suhosin.session.encrypt-php_flag.patch
Added
@@ -0,0 +1,9 @@ +diff -ur chwala-0.5.4.orig/public_html/.htaccess chwala-0.5.4/public_html/.htaccess +--- chwala-0.5.4.orig/public_html/.htaccess 2018-10-19 12:02:20.000000000 +0200 ++++ chwala-0.5.4/public_html/.htaccess 2018-10-26 09:59:43.987816518 +0200 +@@ -3,3 +3,4 @@ + php_flag log_errors On + php_flag suhosin.session.encrypt Off + php_value error_log ../logs/errors.log ++php_flag session.auto_start Off +Only in chwala-0.5.4/public_html: .htaccess.orig
View file
chwala-0.5.3.tar.gz/config/config.inc.php.dist -> chwala-0.5.4.tar.gz/config/config.inc.php.dist
Changed
@@ -52,6 +52,11 @@ ); */ +// Disables listing folders from the backend storage. +// This is useful when you configured an external source(s) and +// you want to use it exclusively, ignoring Kolab folders. +$config['fileapi_backend_storage_disabled'] = false; + // Manticore service URL. Enables use of WebODF collaborative editor. // Note: this URL should be accessible from Chwala host and Roundcube host as well. $config['fileapi_manticore'] = null; @@ -76,6 +81,26 @@ // possible units: s, m, h, d, w $config['fileapi_cache_ttl'] = '1d'; +// LDAP addressbook that would be searched for user names autocomplete. +// That should be an array refering to the Roundcube's $config['ldap_public'] +// array key or complete addressbook configuration array. +$config['fileapi_users_source'] = 'kolab_addressbook'; + +// The LDAP attribute which will be used as ACL user identifier +$config['fileapi_users_field'] = 'mail'; + +// The LDAP search filter will be combined with search queries +$config['fileapi_users_filter'] = ''; + +// Include groups in searching +$config['fileapi_groups'] = false; + +// Prefix added to the group name to build IMAP ACL identifier +$config['fileapi_group_prefix'] = 'group:'; + +// The LDAP attribute (or field name) which will be used as ACL group identifier +$config['fileapi_group_field'] = 'name'; + // ------------------------------------------------ // SeaFile driver settings // ------------------------------------------------
View file
chwala-0.5.4.tar.gz/lib/api/autocomplete.php
Added
@@ -0,0 +1,57 @@ +<?php +/* + +--------------------------------------------------------------------------+ + | This file is part of the Kolab File API | + | | + | Copyright (C) 2012-2018, Kolab Systems AG | + | | + | This program is free software: you can redistribute it and/or modify | + | it under the terms of the GNU Affero General Public License as published | + | by the Free Software Foundation, either version 3 of the License, or | + | (at your option) any later version. | + | | + | This program is distributed in the hope that it will be useful, | + | but WITHOUT ANY WARRANTY; without even the implied warranty of | + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | + | GNU Affero General Public License for more details. | + | | + | You should have received a copy of the GNU Affero General Public License | + | along with this program. If not, see <http://www.gnu.org/licenses/> | + +--------------------------------------------------------------------------+ + | Author: Aleksander Machniak <machniak@kolabsys.com> | + +--------------------------------------------------------------------------+ +*/ + +class file_api_autocomplete extends file_api_common +{ + /** + * Request handler + */ + public function handle() + { + parent::handle(); + + if (!isset($this->args['search']) || $this->args['search'] === '') { + throw new Exception("Missing search keyword", file_api_core::ERROR_CODE); + } + + if (isset($this->args['folder']) && $this->args['folder'] !== '') { + list($driver, $path) = $this->api->get_driver($this->args['folder']); + } + else { + $driver = $this->api->get_backend(); + } + + if (!empty($this->args['mode'])) { + $mode = 0; + $mode += stripos($this->args['mode'], 'user') !== false ? file_storage::SEARCH_USER : 0; + $mode += stripos($this->args['mode'], 'group') !== false ? file_storage::SEARCH_GROUP : 0; + } + + if (empty($mode)) { + $mode = file_storage::SEARCH_USER; + } + + return $driver->autocomplete($this->args['search'], $mode); + } +}
View file
chwala-0.5.3.tar.gz/lib/api/folder_list.php -> chwala-0.5.4.tar.gz/lib/api/folder_list.php
Changed
@@ -57,7 +57,7 @@ return $folders; } - $drivers = $this->api->get_drivers(true); + $drivers = $this->api->get_drivers(true, $admin_drivers); $has_more = false; $errors = array(); @@ -114,8 +114,13 @@ } catch (Exception $e) { if ($e->getCode() == file_storage::ERROR_NOAUTH) { - // inform UI about to ask user for credentials - $errors[$title] = $this->parse_metadata($driver->driver_metadata()); + if (!in_array($title, $admin_drivers)) { + // inform UI about to ask user for credentials + $errors[$title] = $this->parse_metadata($driver->driver_metadata()); + } + else { + $errors[$title] = array('error' => file_storage::ERROR_NOAUTH); + } } } }
View file
chwala-0.5.4.tar.gz/lib/api/sharing.php
Added
@@ -0,0 +1,84 @@ +<?php +/* + +--------------------------------------------------------------------------+ + | This file is part of the Kolab File API | + | | + | Copyright (C) 2012-2018, Kolab Systems AG | + | | + | This program is free software: you can redistribute it and/or modify | + | it under the terms of the GNU Affero General Public License as published | + | by the Free Software Foundation, either version 3 of the License, or | + | (at your option) any later version. | + | | + | This program is distributed in the hope that it will be useful, | + | but WITHOUT ANY WARRANTY; without even the implied warranty of | + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | + | GNU Affero General Public License for more details. | + | | + | You should have received a copy of the GNU Affero General Public License | + | along with this program. If not, see <http://www.gnu.org/licenses/> | + +--------------------------------------------------------------------------+ + | Author: Aleksander Machniak <machniak@kolabsys.com> | + +--------------------------------------------------------------------------+ +*/ + +class file_api_sharing extends file_api_common +{ + /** + * Request handler + */ + public function handle() + { + parent::handle(); + + if (!isset($this->args['folder']) || $this->args['folder'] === '') { + throw new Exception("Missing folder name", file_api_core::ERROR_CODE); + } + + list($driver, $path) = $this->api->get_driver($this->args['folder']); + + if ($_SERVER['REQUEST_METHOD'] == 'POST') { + // Required arguments: + // - action: 'submit', 'update', 'delete' + // - mode: depends on the storage driver + return $driver->sharing($path, file_storage::SHARING_MODE_UPDATE, $this->args); + } + + $form = $driver->sharing($path, file_storage::SHARING_MODE_FORM); + + if (empty($form)) { + throw new Exception("Sharing not supported", file_api_core::ERROR_UNSUPPORTED); + } + + $rights = $driver->sharing($path, file_storage::SHARING_MODE_RIGHTS); + + $this->localize_form_data($form); + + $result = array( + 'form' => $form, + 'rights' => (array) $rights, + ); + + return $result; + } + + /** + * Recurrent function to localize form data entries + */ + protected function localize_form_data(&$data, $key = null, $self = null) + { + if (!$self) { + $self = $this; + } + + if (in_array($key, array('title', 'placeholder', 'label', 'list_column_label'))) { + $data = $self->api->translate($data); + } + else if ($key == 'options') { + $data = array_map(array($self->api, 'translate'), $data); + } + else if (is_array($data)) { + array_walk($data, array($self, 'localize_form_data'), $self); + } + } +}
View file
chwala-0.5.4.tar.gz/lib/drivers/kolab/kolab_file_autocomplete.php
Added
@@ -0,0 +1,171 @@ +<?php +/* + +--------------------------------------------------------------------------+ + | This file is part of the Kolab File API | + | | + | Copyright (C) 2012-2018, Kolab Systems AG | + | | + | This program is free software: you can redistribute it and/or modify | + | it under the terms of the GNU Affero General Public License as published | + | by the Free Software Foundation, either version 3 of the License, or | + | (at your option) any later version. | + | | + | This program is distributed in the hope that it will be useful, | + | but WITHOUT ANY WARRANTY; without even the implied warranty of | + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | + | GNU Affero General Public License for more details. | + | | + | You should have received a copy of the GNU Affero General Public License | + | along with this program. If not, see <http://www.gnu.org/licenses/> | + +--------------------------------------------------------------------------+ + | Author: Aleksander Machniak <machniak@kolabsys.com> | + +--------------------------------------------------------------------------+ +*/ + +class kolab_file_autocomplete +{ + private $rc; + private $ldap; + + /** + * Class constructor + */ + public function __construct() + { + $this->rc = rcube::get_instance(); + } + + /** + * Search users/groups + */ + public function search($search, $with_groups = false) + { + if (!$this->init_ldap()) { + return false; + } + + $max = (int) $this->rc->config->get('autocomplete_max', 15); + $mode = (int) $this->rc->config->get('addressbook_search_mode'); + $me = $this->rc->get_user_name(); + + $this->ldap->set_pagesize($max); + + $result = $this->ldap->search('*', $search, $mode); + $users = array(); + $index = array(); + + foreach ($result->records as $record) { + $user = $record['uid']; + + if (is_array($user)) { + $user = array_filter($user); + $user = $user[0]; + } + + if (in_array($me, rcube_addressbook::get_col_values('email', $record, true))) { + continue; + } + + if ($user) { + $display = rcube_addressbook::compose_search_name($record); + $user = array('name' => $user, 'display' => $display); + $users[] = $user; + $index[] = $display ?: $user['name']; + } + } + + $group_support = $this->rc->config->get('fileapi_groups'); + $group_prefix = $this->rc->config->get('fileapi_group_prefix'); + $group_field = $this->rc->config->get('fileapi_group_field', 'name'); + + if ($with_groups && $group_support && $group_field) { + $result = $this->ldap->list_groups($search, $mode); + + foreach ($result as $record) { + $group = $record['name']; + $group_id = is_array($record[$group_field]) ? $record[$group_field][0] : $record[$group_field]; + + if ($group) { + $users[] = array('name' => ($group_prefix ? $group_prefix : '') . $group_id, 'display' => $group, 'type' => 'group'); + $index[] = $group; + } + } + } + + if (count($users)) { + array_multisort($index, SORT_ASC, SORT_LOCALE_STRING, $users); + } + + if (count($users) > $max) { + $users = array_slice($users, 0, $max); + } + + return $users; + } + + /** + * Initializes autocomplete LDAP backend + */ + private function init_ldap() + { + if ($this->ldap) { + return $this->ldap->ready; + } + + // get LDAP config + $config = $this->rc->config->get('fileapi_users_source'); + + if (empty($config)) { + return false; + } + + // not an array, use configured ldap_public source + if (!is_array($config)) { + $ldap_config = (array) $this->rc->config->get('ldap_public'); + $config = $ldap_config[$config]; + } + + $uid_field = $this->rc->config->get('fileapi_users_field', 'mail'); + $filter = $this->rc->config->get('fileapi_users_filter'); + $debug = $this->rc->config->get('ldap_debug'); + $domain = $this->rc->config->mail_domain($_SESSION['imap_host']); + + if (empty($uid_field) || empty($config)) { + return false; + } + + // get name attribute + if (!empty($config['fieldmap'])) { + $name_field = $config['fieldmap']['name']; + } + // ... no fieldmap, use the old method + if (empty($name_field)) { + $name_field = $config['name_field']; + } + + // add UID field to fieldmap, so it will be returned in a record with name + $config['fieldmap']['name'] = $name_field; + $config['fieldmap']['uid'] = $uid_field; + + // search in UID and name fields + // $name_field can be in a form of <field>:<modifier> (#1490591) + $name_field = preg_replace('/:.*$/', '', $name_field); + $search = array_unique(array($name_field, $uid_field)); + + $config['search_fields'] = $search; + $config['required_fields'] = array($uid_field); + + // set search filter + if ($filter) { + $config['filter'] = $filter; + } + + // disable vlv + $config['vlv'] = false; + + // Initialize LDAP connection + $this->ldap = new rcube_ldap($config, $debug, $domain); + + return $this->ldap->ready; + } +}
View file
chwala-0.5.3.tar.gz/lib/drivers/kolab/kolab_file_storage.php -> chwala-0.5.4.tar.gz/lib/drivers/kolab/kolab_file_storage.php
Changed
@@ -321,6 +321,7 @@ file_storage::CAPS_QUOTA => $quota, file_storage::CAPS_LOCKS => true, file_storage::CAPS_SUBSCRIPTIONS => true, + file_storage::CAPS_ACL => true, ); } @@ -1202,6 +1203,258 @@ } /** + * Sharing interface + * + * @param string $folder_name Name of a folder with full path + * @param int $mode Sharing action mode + * @param array $args POST/GET parameters + * + * @return mixed Sharing response + * @throws Exception + */ + public function sharing($folder, $mode, $args = array()) + { + $folder_name = rcube_charset::convert($folder, RCUBE_CHARSET, 'UTF7-IMAP'); + $storage = $this->rc->get_storage(); + $folder_info = $storage->folder_info($folder_name); + + if (!is_array($folder_info['rights'])) { + throw new Exception("Storage error. Failed to get folder permissions.", file_storage::ERROR); + } + + if (!in_array('a', $folder_info['rights'])) { + throw new Exception("No permissions to administer this folder.", file_storage::ERROR_FORBIDDEN); + } + + if ($mode == file_storage::SHARING_MODE_FORM) { + $form = array( + 'shares' => array( + 'title' => 'share.permissions', + 'form' => array( + 'user' => array( + 'title' => 'share.usergroup', + 'type' => 'input', + 'autocomplete' => 'user,group', + ), + 'right' => array( + 'title' => 'share.permission', + 'type' => 'select', + 'options' => array( + 'r' => 'share.readonly', + 'rw' => 'share.readwrite', + 'a' => 'share.admin', + ), + ), + ), + 'extra_fields' => array( + 'type' => 'user', + 'id' => '', + ), + ), + ); + + return $form; + } + + if ($mode == file_storage::SHARING_MODE_RIGHTS) { + $result = array(); + $acl_list = $storage->get_acl($folder_name); + + foreach ((array) $acl_list as $name => $acl) { + if ($name == $_SESSION['username']) { + continue; + } + + if (in_array('a', $acl)) { + $right = 'a'; + } + else if (in_array('i', $acl)) { + $right = 'rw'; + } + else if (in_array('r', $acl)) { + $right = 'r'; + } + else { + continue; + } + + $type = strpos($name, 'group:') === 0 ? 'group' : 'user'; + $id = $name; + + if ($type == 'group') { + $name = substr($name, 6); + } + + $result[] = array( + 'mode' => 'shares', + 'type' => $type, + 'right' => $right, + 'user' => $name, + 'id' => $id, + ); + } + + return $result; + } + + if ($mode == file_storage::SHARING_MODE_UPDATE) { + if ($args['mode'] == 'shares') { + $user = $args['id']; + if (!$user) { + $user = ($args['type'] == 'group' ? 'group:' : '') . preg_replace('/^group:/', '', $args['user']); + } + + switch ($args['right']) { + case 'r': $acl = 'lrs'; break; + case 'rw': $acl = 'lrswite'; break; + case 'a': $acl = 'lrswiteax'; break; + } + + if (empty($user) || (empty($acl) && $args['action'] != 'delete')) { + throw new Exception("Invalid input.", file_storage::ERROR); + } + + switch ($args['action']) { + case 'submit': + case 'update': + $result = $storage->set_acl($folder_name, $user, $acl); + break; + + case 'delete': + $result = $storage->delete_acl($folder_name, $user); + break; + } + } + else { + throw new Exception("Invalid input.", file_storage::ERROR); + } + + if (empty($result)) { + throw new Exception("Storage error. Failed to update share.", file_storage::ERROR); + } + + return true; + } + } + + /** + * User/group search (autocompletion) + * + * @param string $search Search string + * @param int $mode Search mode + * + * @return array Users/Groups list + * @throws Exception + */ + public function autocomplete($search, $mode) + { + $ac = new kolab_file_autocomplete($this); + + $result = $ac->search($search, $mode & file_storage::SEARCH_GROUP); + + if ($result === false) { + throw new Exception("Failed to search users", file_storage::ERROR); + } + + return $result; + } + + /** + * Convert file/folder path into a global URI. + * + * @param string $path File/folder path + * + * @return string URI + * @throws Exception + */ + public function path2uri($path) + { + $storage = $this->rc->get_storage(); + $namespace = $storage->get_namespace(); + $separator = $storage->get_hierarchy_delimiter(); + $_path = str_replace(file_storage::SEPARATOR, $separator, $path); + $owner = $this->rc->get_user_name(); + + // find the owner and remove namespace prefix + foreach (array_filter($namespace) as $type => $ns) { + foreach ($ns as $root) { + if (is_array($root) && $root[0] && strpos($_path, $root[0]) === 0) { + $path = substr($path, strlen($root[0])); + + switch ($type) { + case 'shared': + // in theory there can be more than one shared root + // we add it to dummy user name, so we can revert conversion + $owner = "shared({$root[0]})"; + break; + + case 'other': + list($user, $path) = explode(file_storage::SEPARATOR, $path, 2); +
View file
chwala-0.5.3.tar.gz/lib/drivers/seafile/seafile_api.php -> chwala-0.5.4.tar.gz/lib/drivers/seafile/seafile_api.php
Changed
@@ -142,15 +142,16 @@ /** * Send HTTP request * - * @param string $method Request method ('OPTIONS','GET','HEAD','POST','PUT','DELETE','TRACE','CONNECT') - * @param string $url Request API URL - * @param array $get GET parameters - * @param array $post POST parameters - * @param array $upload Uploaded files data + * @param string $method Request method ('OPTIONS','GET','HEAD','POST','PUT','DELETE','TRACE','CONNECT') + * @param string $url Request API URL + * @param array $get GET parameters + * @param array $post POST parameters + * @param array $upload Uploaded files data + * @param string $version API version (to replace "api2" with "api/v$version" in the URL * * @return string|array Server response */ - protected function request($method, $url, $get = null, $post = null, $upload = null) + protected function request($method, $url, $get = null, $post = null, $upload = null, $version = null) { if (!preg_match('/^https?:\/\//', $url)) { $url = $this->url . $url; @@ -161,6 +162,10 @@ $url = $this->mod_url($url); } + if ($version && $version != 2) { + $url = str_replace('/api2/', "/api/v$version/", $url); + } + if (!$this->request) { $this->config['store_body'] = true; // some methods respond with 301 redirect, we'll not follow them @@ -881,6 +886,459 @@ } /** + * Share a directory (or library) + * + * @param string $repo_id Library identifier + * @param string $dir Directory name (with path) + * @param string $right Permission ('r' or 'rw' or 'admin') + * @param string $mode Mode ('user' or 'group') + * @param string $who Username or Group ID + * @param bool $update Update an existing entry + * + * @return bool True on success, False on failure + */ + public function shared_item_add($repo_id, $dir, $right, $mode, $who, $update = false) + { + // sanity checks + if (!is_string($dir)) { + $this->status = self::BAD_REQUEST; + return false; + } + + if ($repo_id === '' || !is_string($repo_id)) { + $this->status = self::BAD_REQUEST; + return false; + } + + if ($mode != 'user' && $mode != 'group') { + $this->status = self::BAD_REQUEST; + return false; + } + + if ($right != 'r' && $right != 'rw' && $right != 'admin') { + $this->status = self::BAD_REQUEST; + return false; + } + + if ($dir === '') { + $dir = '/'; + } + + $post = array( + 'permission' => $right, + 'share_type' => $mode, + ); + + $post[$mode == 'group' ? 'group_id' : 'username'] = $who; + + $this->request($update ? 'POST' : 'PUT', "repos/$repo_id/dir/shared_items", array('p' => $dir), $post); + + return $this->is_error() === false; + } + + /** + * Update shared item permissions + * + * @param string $repo_id Library identifier + * @param string $dir Directory name (with path) + * @param string $right Permission ('r' or 'rw' or 'admin') + * @param string $mode Mode ('user' or 'group') + * @param string $who Username or Group ID + * + * @return bool True on success, False on failure + */ + public function shared_item_update($repo_id, $dir, $right, $mode, $who) + { + return $this->shared_item_add($repo_id, $dir, $right, $mode, $who, true); + } + + /** + * Un-Share a directory (or library) + * + * @param string $repo_id Library identifier + * @param string $dir Directory name (with path) + * @param string $mode Mode ('user' or 'group') + * @param string $who Username or Group ID + * + * @return bool True on success, False on failure + */ + public function shared_item_delete($repo_id, $dir, $mode, $who) + { + // sanity checks + if (!is_string($dir)) { + $this->status = self::BAD_REQUEST; + return false; + } + + if ($repo_id === '' || !is_string($repo_id)) { + $this->status = self::BAD_REQUEST; + return false; + } + + if ($mode != 'user' && $mode != 'group') { + $this->status = self::BAD_REQUEST; + return false; + } + + if ($dir === '') { + $dir = '/'; + } + + $get = array( + 'share_type' => $mode, + 'p' => $dir + ); + + $get[$mode == 'group' ? 'group_id' : 'username'] = $who; + + $this->request('DELETE', "repos/$repo_id/dir/shared_items", $get); + + return $this->is_error() === false; + } + + /** + * List directory permissions (shares) + * + * @param string $repo_id Library identifier + * @param string $dir Directory name (with path) + * + * @return bool|array List of user/group info on success, False on failure + */ + public function shared_item_list($repo_id, $dir) + { + // sanity checks + if (!is_string($dir)) { + $this->status = self::BAD_REQUEST; + return false; + } + + if ($repo_id === '' || !is_string($repo_id)) { + $this->status = self::BAD_REQUEST; + return false; + } + + if ($dir === '') { + $dir = '/'; + } + + // Example result: + // [ + // { + // "group_info": { "id": 17, "name": "Group Name" }, + // "is_admin": false, + // "share_type": "group", + // "permission": "rw" + // }, + // { + // "user_info": { "nickname": "user", "name": "user@domain.com" }, + // "share_type": "user", + // "permission": "r" + // } + // ] + + return $this->request('GET', "repos/$repo_id/dir/shared_items", array('p' => $dir)); + } + + /** + * List share (download) links + * + * @param string $repo_id Library identifier + * @param string $dir Directory name (with path) + * + * @return bool|array List of shared links on success, False on failure + */ + public function share_link_list($repo_id, $dir)
View file
chwala-0.5.3.tar.gz/lib/drivers/seafile/seafile_file_storage.php -> chwala-0.5.4.tar.gz/lib/drivers/seafile/seafile_file_storage.php
Changed
@@ -205,6 +205,7 @@ file_storage::CAPS_MAX_UPLOAD => $max_filesize, file_storage::CAPS_QUOTA => true, file_storage::CAPS_LOCKS => true, + file_storage::CAPS_ACL => true, ); } @@ -1106,6 +1107,312 @@ } /** + * Sharing interface + * + * @param string $folder_name Name of a folder with full path + * @param int $mode Sharing action mode + * @param array $args POST/GET parameters + * + * @return mixed Sharing response + * @throws Exception + */ + public function sharing($folder, $mode, $args = array()) + { + if ($mode == file_storage::SHARING_MODE_FORM) { + $form = array( + 'shares' => array( + 'title' => 'share.permissions', + 'form' => array( + 'user' => array( + 'title' => 'share.usergroup', + 'type' => 'input', + 'autocomplete' => 'user,group', + ), + 'right' => array( + 'title' => 'share.permission', + 'type' => 'select', + 'options' => array( + 'r' => 'share.readonly', + 'rw' => 'share.readwrite', + ), + ), + ), + 'extra_fields' => array( + 'type' => 'user', + 'id' => '', + ), + ), + 'download-link' => array( + 'title' => 'share.download-link', + 'label' => 'share.generate', + 'single' => true, + 'list_column' => 'link', + 'list_column_label' => 'share.link', + 'form' => array( + 'password' => array( + 'title' => 'share.password', + 'type' => 'password', + ), + 'expire' => array( + 'title' => 'share.expire', + 'placeholder' => 'share.expiredays', + 'type' => 'input', + ), + ), + 'extra_fields' => array( + 'id' => '', + ), + ), + 'upload-link' => array( + 'title' => 'share.upload-link', + 'label' => 'share.generate', + 'single' => true, + 'list_column' => 'link', + 'list_column_label' => 'share.link', + 'form' => array( + 'password' => array( + 'title' => 'share.password', + 'type' => 'password', + ), + ), + 'extra_fields' => array( + 'id' => '', + ), + ), + ); + + return $form; + } + + if ($mode == file_storage::SHARING_MODE_RIGHTS) { + if (!$this->init()) { + throw new Exception("Storage error. Unable to get shares of SeaFile folder/lib.", file_storage::ERROR); + } + + list($path, $repo_id) = $this->find_library($folder); + + $result = array(); + + if ($shares = $this->api->shared_item_list($repo_id, $path)) { + foreach ($shares as $share) { + if (!empty($share['group_info'])) { + $name = $share['group_info']['name']; + $name = $share['group_info']['id']; + } + else { + $name = $share['user_info']['name']; + $id = $share['user_info']['name']; + } + + $result[] = array( + 'mode' => 'shares', + 'type' => $share['share_type'], + 'right' => $share['permission'], + 'user' => $name, + 'id' => $id, + ); + } + } + + if ($links = $this->api->share_link_list($repo_id, $path)) { + foreach ($links as $link) { + $result[] = array( + 'mode' => 'download-link', + 'id' => $link['token'], + 'link' => $link['link'], + ); + } + } + + if ($links = $this->api->upload_link_list($repo_id, $path)) { + foreach ($links as $link) { + $result[] = array( + 'mode' => 'upload-link', + 'id' => $link['token'], + 'link' => $link['link'], + ); + } + } + + return $result; + } + + if ($mode == file_storage::SHARING_MODE_UPDATE) { + if (!$this->init()) { + throw new Exception("Storage error. Unable to update shares of SeaFile folder/lib.", file_storage::ERROR); + } + + list($path, $repo_id) = $this->find_library($folder); + + if ($args['mode'] == 'shares') { + switch ($args['action']) { + case 'submit': + $result = $this->api->shared_item_add($repo_id, $path, $args['right'], $args['type'], $args['user']); + break; + + case 'update': + $result = $this->api->shared_item_update($repo_id, $path, $args['right'], $args['type'], $args['id'] ?: $args['user']); + break; + + case 'delete': + $result = $this->api->shared_item_delete($repo_id, $path, $args['type'], $args['user']); + break; + } + } + else if ($args['mode'] == 'download-link') { + switch ($args['action']) { + case 'submit': + $result = $this->api->share_link_add($repo_id, $path, $args['password'], $args['expire']); + + if ($result) { + $result['id'] = $result['token']; + $result['mode'] = 'download-link'; + } + break; + + case 'delete': + $result = $this->api->share_link_delete($args['id']); + break; + } + } + else if ($args['mode'] == 'upload-link') { + switch ($args['action']) { + case 'submit': + $result = $this->api->upload_link_add($repo_id, $path, $args['password']); + + if ($result) { + $result['id'] = $result['token']; + $result['mode'] = 'upload-link'; + } + break; + + case 'delete': + $result = $this->api->upload_link_delete($args['id']); + break; + } + } + else { + throw new Exception("Invalid input.", file_storage::ERROR); + } +
View file
chwala-0.5.3.tar.gz/lib/drivers/webdav/webdav_file_storage.php -> chwala-0.5.4.tar.gz/lib/drivers/webdav/webdav_file_storage.php
Changed
@@ -917,6 +917,80 @@ } /** + * Sharing interface + * + * @param string $folder_name Name of a folder with full path + * @param int $mode Sharing action mode + * @param array $args POST/GET parameters + * + * @return mixed Sharing response + * @throws Exception + */ + public function sharing($folder, $mode, $args = array()) + { + // TODO + throw new Exception("Search not implemented", file_storage::ERROR_UNSUPPORTED); + } + + /** + * User/group search (autocompletion) + * + * @param string $search Search string + * @param int $mode Search mode + * + * @return array Users/Groups list + * @throws Exception + */ + public function autocomplete($search, $mode) + { + // TODO + throw new Exception("Search not implemented", file_storage::ERROR_UNSUPPORTED); + } + + /** + * Convert file/folder path into a global URI. + * + * @param string $path File/folder path + * + * @return string URI + * @throws Exception + */ + public function path2uri($path) + { + $base = preg_replace('|^[a-zA-Z]+://|', '', $this->config['baseuri']); + + return 'webdav://' . rawurlencode($this->config['username']) . '@' . $base + . '/' . file_utils::encode_path($path); + } + + /** + * Convert global URI into file/folder path. + * + * @param string $uri URI + * + * @return string File/folder path + * @throws Exception + */ + public function uri2path($uri) + { + if (!preg_match('|^webdav://([^@]+)@(.*)$|', $uri, $matches)) { + throw new Exception("Internal storage error. Unexpected data format.", file_storage::ERROR); + } + + $user = rawurldecode($matches[1]); + $base = preg_replace('|^[a-zA-Z]+://|', '', $this->config['baseuri']); + $uri = $matches[2]; + + if ($user != $this->config['username'] || strpos($uri, $base) !== 0) { + throw new Exception("Internal storage error. Unresolvable URI.", file_storage::ERROR); + } + + $uri = substr($matches[2], strlen($base) + 1); + + return file_utils::decode_path($uri); + } + + /** * Gets the relative URL of a resource * * @param string $url WebDAV URL @@ -976,49 +1050,6 @@ } /** - * Convert file/folder path into a global URI. - * - * @param string $path File/folder path - * - * @return string URI - * @throws Exception - */ - public function path2uri($path) - { - $base = preg_replace('|^[a-zA-Z]+://|', '', $this->config['baseuri']); - - return 'webdav://' . rawurlencode($this->config['username']) . '@' . $base - . '/' . file_utils::encode_path($path); - } - - /** - * Convert global URI into file/folder path. - * - * @param string $uri URI - * - * @return string File/folder path - * @throws Exception - */ - public function uri2path($uri) - { - if (!preg_match('|^webdav://([^@]+)@(.*)$|', $uri, $matches)) { - throw new Exception("Internal storage error. Unexpected data format.", file_storage::ERROR); - } - - $user = rawurldecode($matches[1]); - $base = preg_replace('|^[a-zA-Z]+://|', '', $this->config['baseuri']); - $uri = $matches[2]; - - if ($user != $this->config['username'] || strpos($uri, $base) !== 0) { - throw new Exception("Internal storage error. Unresolvable URI.", file_storage::ERROR); - } - - $uri = substr($matches[2], strlen($base) + 1); - - return file_utils::decode_path($uri); - } - - /** * Initializes file_locks object */ protected function init_lock_db()
View file
chwala-0.5.3.tar.gz/lib/file_api.php -> chwala-0.5.4.tar.gz/lib/file_api.php
Changed
@@ -188,9 +188,12 @@ $mem = memory_get_usage(); } - $request = ($this instanceof file_api_wopi ? 'wopi/' : '') - . $this->request - . (!empty($this->path) ? '/' . implode($this->path, '/') : ''); + $path = !empty($this->path) ? '/' . implode($this->path, '/') : ''; + $request = ($this instanceof file_api_wopi ? 'wopi/' : '') . $this->request; + + if ($path !== '' && substr_compare($this->request, $path, -1 * strlen($path), strlen($path), true) != 0) { + $request .= $path; + } $log = trim(sprintf('%s: %s %s', $this->method ?: $_SERVER['REQUEST_METHOD'],
View file
chwala-0.5.3.tar.gz/lib/file_api_core.php -> chwala-0.5.4.tar.gz/lib/file_api_core.php
Changed
@@ -24,7 +24,7 @@ class file_api_core extends file_locale { - const API_VERSION = 3; + const API_VERSION = 4; const ERROR_UNAUTHORIZED = 401; const ERROR_NOT_FOUND = 404; @@ -80,11 +80,12 @@ /** * Return supported/enabled external storage instances * - * @param bool $as_objects Return drivers as objects not config data + * @param bool $as_objects Return drivers as objects not config data + * @param array &$admin_drivers List of admin-configured drivers * * @return array List of storage drivers */ - public function get_drivers($as_objects = false) + public function get_drivers($as_objects = false, &$admin_drivers = null) { $rcube = rcube::get_instance(); $backend = $this->get_backend(); @@ -117,6 +118,8 @@ } } + $admin_drivers = array(); + if (empty($result) && !empty($preconf)) { foreach ((array) $preconf as $title => $item) { if (!in_array($title, $all)) { @@ -124,6 +127,8 @@ $item['admin'] = true; $result[] = $as_objects ? $this->get_driver_object($item) : $item; + + $admin_drivers[] = $title; } } } @@ -152,6 +157,11 @@ } if (empty($selected)) { + $rcube = rcube::get_instance(); + if ($rcube->config->get('fileapi_backend_storage_disabled')) { + throw new Exception("Failed to find a driver for specified folder/file.", self::ERROR_NOT_FOUND); + } + return array($this->get_backend(), $path); } @@ -218,7 +228,7 @@ { $rcube = rcube::get_instance(); $backend = $this->get_backend(); - $caps = array(); + $caps = array('VERSION' => self::API_VERSION); // check support for upload progress if (($progress_sec = $rcube->config->get('upload_progress')) @@ -246,6 +256,10 @@ $caps['WOPI'] = true; } + if ($rcube->config->get('fileapi_backend_storage_disabled')) { + $caps['NOROOT'] = true; + } + if (!$full) { return $caps; }
View file
chwala-0.5.3.tar.gz/lib/file_storage.php -> chwala-0.5.4.tar.gz/lib/file_storage.php
Changed
@@ -58,6 +58,16 @@ const ACL_READ = 1; const ACL_WRITE = 2; + // sharing interface modes + const SHARING_MODE_FORM = 1; + const SHARING_MODE_RIGHTS = 2; + const SHARING_MODE_UPDATE = 3; + + // search modes + const SEARCH_USER = 1; + const SEARCH_GROUP = 2; + + /** * Authenticates a user * @@ -349,7 +359,31 @@ public function quota($folder); /** + * Sharing interface + * + * @param string $folder_name Name of a folder with full path + * @param int $mode Sharing action mode + * @param array $args POST/GET parameters + * + * @return mixed Sharing response + * @throws Exception + */ + public function sharing($folder, $mode, $args = array()); + + /** + * User/group search (autocompletion) + * + * @param string $search Search string + * @param int $mode Search mode + * + * @return array Users/Groups list + * @throws Exception + */ + public function autocomplete($search, $mode); + + /** * Convert file/folder path into a global URI. + * Note: We're using self::SEPARATOR as a hierarchy delimiter * * @param string $path File/folder path * @@ -360,6 +394,7 @@ /** * Convert global URI into file/folder path. + * Note: We're using self::SEPARATOR as a hierarchy delimiter * * @param string $uri URI *
View file
chwala-0.5.3.tar.gz/lib/locale/en_US.php -> chwala-0.5.4.tar.gz/lib/locale/en_US.php
Changed
@@ -75,6 +75,20 @@ $LANG['search.in_all_folders'] = 'in all folders'; $LANG['search.in_current_folder'] = 'in current folder'; +$LANG['share.permissions'] = 'Permissions'; +$LANG['share.readonly'] = 'read-only'; +$LANG['share.readwrite'] = 'read-write'; +$LANG['share.admin'] = 'administrator'; +$LANG['share.usergroup'] = 'User or Group'; +$LANG['share.permission'] = 'Permission'; +$LANG['share.upload-link'] = 'Upload Link'; +$LANG['share.download-link'] = 'Download Link'; +$LANG['share.password'] = 'Password'; +$LANG['share.expire'] = 'Expiration'; +$LANG['share.expiredays'] = 'Expiration time in days'; +$LANG['share.generate'] = 'Generate'; +$LANG['share.link'] = 'Link'; + $LANG['size.B'] = 'B'; $LANG['size.KB'] = 'KB'; $LANG['size.MB'] = 'MB';
View file
chwala-0.5.3.tar.gz/lib/wopi/files.php -> chwala-0.5.4.tar.gz/lib/wopi/files.php
Changed
@@ -104,7 +104,7 @@ 'Version' => $info['modified'], 'OwnerId' => $info['owner'], 'UserId' => $info['user'], - 'UserFriendlyName' => $info['user_name'], + 'UserFriendlyName' => $info['user_name'] ?: preg_replace('/@.*$/', '', $info['user']), 'UserCanWrite' => empty($info['readonly']), 'PostMessageOrigin' => $info['origin'], // Tell the client we do not support PutRelativeFile yet @@ -114,9 +114,27 @@ 'HideExportOption' => true, 'HidePrintOption' => true, 'EnableOwnerTermination' => true, - // TODO: 'UserExtraInfo' => ['avatar' => 'http://url/to/user/avatar', 'mail' => 'user@server.com'] + 'WatermarkText' => '', // ?? + 'DisablePrint' => false, + 'DisableExport' => false, + 'DisableCopy' => false, + 'DisableInactiveMessages' => true, + 'DisableChangeTrackingRecord' => true, + 'DisableChangeTrackingShow' => true, + 'HideChangeTrackingControls' => true, + // TODO: 'UserExtraInfo' => ['avatar' => 'http://url/to/user/avatar', 'mail' => $info['user']] + 'UserExtraInfo' => array(), ); + if ($info['modified']) { + try { + $dt = new DateTime('@' . $info['modified'], new DateTimeZone('UTC')); + $result['LastModifiedTime'] = $dt->format('Y-m-dTH:i:s') . '.0000000Z'; + } + catch (Exception $e) { + } + } + return $result; }
View file
chwala-0.5.3.tar.gz/public_html/.htaccess -> chwala-0.5.4.tar.gz/public_html/.htaccess
Changed
@@ -2,4 +2,4 @@ php_flag display_errors Off php_flag log_errors On php_flag suhosin.session.encrypt Off -php_value error_log ../logs/errors +php_value error_log ../logs/errors.log
View file
chwala-0.5.3.tar.gz/public_html/api/.htaccess -> chwala-0.5.4.tar.gz/public_html/api/.htaccess
Changed
@@ -2,5 +2,5 @@ php_flag session.use_cookies Off php_flag display_errors Off php_flag log_errors On -php_value error_log ../../logs/errors +php_value error_log ../../logs/errors.log
View file
chwala-0.5.3.tar.gz/public_html/js/files_api.js -> chwala-0.5.4.tar.gz/public_html/js/files_api.js
Changed
@@ -72,7 +72,7 @@ /********************************************************/ // send a http POST request to the API service - this.post = function(action, data, func) + this.post = function(action, data, func, error_func) { var url = this.env.url + '?method=' + action; @@ -83,15 +83,15 @@ return $.ajax({ type: 'POST', url: url, data: JSON.stringify(data), dataType: 'json', contentType: 'application/json; charset=utf-8', - success: function(response) { if (typeof func == 'function') func(response); else ref[func](response); }, - error: function(o, status, err) { ref.http_error(o, status, err, data); }, + success: function(response) { if (typeof func == 'function') func(response, data); else ref[func](response, data); }, + error: function(o, status, err) { (error_func || ref.http_error)(o, status, err, data); }, cache: false, beforeSend: function(xmlhttp) { xmlhttp.setRequestHeader('X-Session-Token', ref.env.token); } }); }; // send a http GET request to the API service - this.get = function(action, data, func) + this.get = function(action, data, func, error_func) { var url = this.env.url; @@ -102,19 +102,19 @@ return $.ajax({ type: 'GET', url: url, data: data, dataType: 'json', - success: function(response) { if (typeof func == 'function') func(response); else ref[func](response); }, - error: function(o, status, err) { ref.http_error(o, status, err, data); }, + success: function(response) { if (typeof func == 'function') func(response, data); else ref[func](response, data); }, + error: function(o, status, err) { (error_func || ref.http_error)(o, status, err, data); }, cache: false, beforeSend: function(xmlhttp) { xmlhttp.setRequestHeader('X-Session-Token', ref.env.token); } }); }; // send request with auto-selection of POST/GET method - this.request = function(action, data, func) + this.request = function(action, data, func, error_func) { // Use POST for modification actions with probable big request size var method = /_(create|delete|move|copy|update|auth|subscribe|unsubscribe|invite|decline|request|accept|remove)$/.test(action) ? 'post' : 'get'; - return this[method](action, data, func); + return this[method](action, data, func, error_func); }; // handle HTTP request errors @@ -795,12 +795,9 @@ var color = value.Color; // make sure color is in css hex format - if (color) { - if ($.type(color) == 'string' && color.charAt(0) != '#') - color = '#' + color; - else if ($.type(color) == 'number') - color = ((color)>>>0).toString(16).slice(-6); - color = '#' + ("000000").substring(0, 6 - color.length) + color; + if (color && $.type(color) == 'number') { + color = ((color)>>>0).toString(16).slice(-6); + color = '#' + ("000000").substring(0, 6 - color.length) + color; } return { @@ -1186,6 +1183,24 @@ conf.invitationSaved(invitation); }; + this.domain_compare = function(origin, domain) + { + if (!origin && !domain) + return true; + + if (!origin || !domain) + return false; + + // Sometimes Collabora adds port to the URL + // We'll remove it for proper comparison + if (origin.match(/^https:\/\/(.*):443$/)) + origin = origin.replace(/:443$/, ''); + if (domain.match(/^https:\/\/(.*):443$/)) + domain = domain.replace(/:443$/, ''); + + return origin == domain; + }; + if (!conf) conf = {}; @@ -1204,7 +1219,7 @@ // Register 'message' event to receive messages from the editor iframe window.addEventListener('message', function(event) { - if (event.source == editor && event.origin == domain) { + if (event.source == editor && self.domain_compare(event.origin, domain)) { self.message_handler(event.data); } });
View file
chwala.dsc
Changed
@@ -2,7 +2,7 @@ Source: chwala Binary: chwala Architecture: all -Version: 0.5.3-0~kolab1 +Version: 0.5.4-0~kolab1 Maintainer: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> Uploaders: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com>, Paul Klos <kolab@klos2day.nl> Homepage: http://kolab.org/about/chwala/ @@ -11,5 +11,5 @@ Package-List: roundcubemail deb web extra Files: - 00000000000000000000000000000000 0 chwala-0.5.3.tar.gz + 00000000000000000000000000000000 0 chwala-0.5.4.tar.gz 00000000000000000000000000000000 0 debian.tar.gz
View file
debian.changelog
Changed
@@ -1,3 +1,9 @@ +chwala (0.5.4-0~kolab1) unsable; urgency=low + + * Release version 0.5.4 + + -- Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabys.com> Fri, 26 Oct 2018 12:12:12 +0100 + chwala (0.5.3-0~kolab1) unsable; urgency=low * Release version 0.5.3
View file
debian.series
Changed
@@ -1,2 +1,2 @@ -chwala-0.5.3-suhosin.session.encrypt-php_flag.patch -p1 +chwala-0.5.4-suhosin.session.encrypt-php_flag.patch -p1 fix-autoload-path-debian.patch -p1
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.