Menü schliessen
Created: November 3rd 2015
Last updated: May 1st 2020
Categories: ownCloud
Author: Marcus Fleuti

ownCloud : Prevent users from deleting a shared folder -- Löschen eines geteilten Ordners verhindern

Donation Section: Background
Monero Badge: QR-Code
Monero Badge: Logo Icon Donate with Monero Badge: Logo Text
82uymVXLkvVbB4c4JpTd1tYm1yj1cKPKR2wqmw3XF8YXKTmY7JrTriP4pVwp2EJYBnCFdXhLq4zfFA6ic7VAWCFX5wfQbCC

ownCloud version tested: 8.0.2 (03.11.2015)

ownCloud : How to prevent users from being able to remove shared folders?

What is the problem?

By default an ownCloud user can remove a shared folder (unshare a folder) by clicking the little trashcan icon on the right of each share. That is most probably unintended. When an ownCloud admin is sharing a folder he might not want the users to be able to remove (unshare) such a folder.

Community solution (added by PADDY in the comments on 06.10.2016)

PADDY submitted this very neat solution to address this problem:
Create a trigger in the database like this:

CREATE TRIGGER oc_share_before_delete
 BEFORE DELETE ON oc_share
 FOR EACH ROW
BEGIN
 IF oc_share.uid_initiator != 'admin' THEN
 SIGNAL SQLSTATE '45000';
 END IF;
END

His comments on this:
What the above does is check if the user is part of the group admin, if they are not then the produces an error and the delete is stopped in its tracks!
From the users perspective no matter what way the access the site, app browser etc.. they will not be able to delete, in the case of the desktop app they delete it and then they are asked if the want to confirm the delete in a cycle until the say the don’t want to delete the share/file and bingo the share is back, fool proof…
if its you own server you wont have any problems with adding a trigger but if your on a shared host they may need to enable you access to add triggers.
this method does not change the core db but if future db versions change the table names etc.. then a new trigger will be needed….. until then happy days!!

08.11.2016 - A new solution for MariaDB compatibility has just arrived:

DELIMITER //
CREATE TRIGGER oc_share_before_delete
 BEFORE DELETE ON oc_share
 FOR EACH ROW
BEGIN
 IF OLD.uid_initiator NOT LIKE 'admin' THEN
 SIGNAL SQLSTATE '45000';
 END IF;
END; //
DELIMITER ;

Our solution

We have found a way to simply hide the trashcan icon so that the user cannot issue any unshare action anymore.

Howto

1. Edit the file

/apps/files/js/fileactions.js

2. Find the following code

_renderDeleteAction: function(actionSpec, isDefault, context) {
                        var mountType = context.$file.attr('data-mounttype');
                        var deleteTitle = t('files', 'Delete');
                        if (mountType === 'external-root') {
                                deleteTitle = t('files', 'Disconnect storage');
                        } else if (mountType === 'shared-root') {
                                deleteTitle = t('files', 'Unshare');
                        }
                        var $actionLink = $('<a href="#" original-title="' +
                                escapeHTML(deleteTitle) +
                                '" class="action delete icon-delete">' +
                                '<span class="hidden-visually">' + escapeHTML(deleteTitle) + '</span>' +
                                '</a>'
                        );
                        var $container = context.$file.find('td:last');
                        $container.find('.delete').remove();
                        $container.append($actionLink);
                        return $actionLink;
                },

3. Replace it with

_renderDeleteAction: function(actionSpec, isDefault, context) {
                        var mountType = context.$file.attr('data-mounttype');
                        var deleteTitle = t('files', 'Delete');
                        if (mountType === 'external-root') {
                                deleteTitle = t('files', 'Disconnect storage');
                        var $actionLink = $('<a href="#" original-title="' +
                                escapeHTML(deleteTitle) +
                                '" class="action delete icon-delete">' +
                                '<span class="hidden-visually">' + escapeHTML(deleteTitle) + '</span>' +
                                '</a>'
                        );
                        } else if (mountType === 'shared-root') {
                                deleteTitle = t('files', 'Unshare');
                                var $actionLink = '';
                        }
                        var $container = context.$file.find('td:last');
                        $container.find('.delete').remove();
                        $container.append($actionLink);
                        return $actionLink;
                },

What does it do?

We simply tell the system that if the current folder is a shared folder return a link that is empty ($actionLink = ''). Normally the system returns a clickable link. Basically the user would be able to issue the unshare function manually by manipulating the HTML-Code in the DOM (Document Object Model) of the website. But most probably no user will do that. In other words: It's technically not completly safe but it will do the job for most situations.

What are the implications?

  • This rule applies to all users. It is not possible to enable it for some and disable it for others.
  • When updating ownCloud the file fileactions.js will most probably be overwritten => The code you apply will need to be reapplied.
  • The ownCloud client software (e.g. for Windows) will still allow shared folder removal

A bit more wisdom

As it seems it is planned for ownCloud to support this kind of behaviour in a future version. So we hope...

Allow the removal for users with change/write permissions

We found out that it might come in handy when a user with write/change permissions is allowed to remove folders. We extended the function to check the current users' file permissions and if he has change/write permission (we found out that this equals to the INT number 15) he shall be able to unshare a share or to delete files in it like this:

_renderDeleteAction: function(actionSpec, isDefault, context) {
                        var mountType = context.$file.attr('data-mounttype');
                        var deleteTitle = t('files', 'Delete');
                        if (mountType === 'external-root') {
                                deleteTitle = t('files', 'Disconnect storage');
                        } else if (mountType === 'shared-root') {
                                deleteTitle = t('files', 'Unshare');
                        }
                        if (this.getCurrentPermissions() == 15) {
                                var $actionLink = $('<a href="#" original-title="' +
                                        escapeHTML(deleteTitle) +
                                        '" class="action delete icon-delete">' +
                                        '<span class="hidden-visually">' + escapeHTML(deleteTitle) + '</span>' +
                                        '</a>'
                                );
                        } else $actionLink = '';
                        var $container = context.$file.find('td:last');
                        $container.find('.delete').remove();
                        $container.append($actionLink);
                        return $actionLink;
                },