Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@

## How it works
The administrator can create and manage a set of rule groups. Each of the rule groups consists of one or more rules. If all rules of a group hold true, the group matches the request and access is being denied or the upload is blocked. The rules criteria range from IP address, mimetype and request time to group membership, tags, user agent and more.

An example would be to deny access to MS Excel/XLSX files owned by the "Human Resources" group accessed from an IP not on the internal company network or to block uploads of files bigger than 512 mb by students in the "1st year" group.

Learn more about File Access Control on [https://nextcloud.com/workflow](https://nextcloud.com/workflow)</description>

<version>1.8.0</version>
Expand All @@ -36,9 +36,4 @@ Learn more about File Access Control on [https://nextcloud.com/workflow](https:/
<dependencies>
<nextcloud min-version="18" max-version="18" />
</dependencies>

<settings>
<admin>OCA\FilesAccessControl\Settings\Admin</admin>
<admin-section>OCA\FilesAccessControl\Settings\Section</admin-section>
</settings>
</info>
78 changes: 5 additions & 73 deletions js/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,77 +19,9 @@
*/

(function() {
OCA.FilesAccessControl = OCA.FilesAccessControl || {};

/**
* @class OCA.FilesAccessControl.Operation
*/
OCA.FilesAccessControl.Operation =
OCA.WorkflowEngine.Operation.extend({
defaults: {
'class': 'OCA\\FilesAccessControl\\Operation',
'name': '',
'checks': [],
'operation': 'deny'
}
});

/**
* @class OCA.FilesAccessControl.OperationsCollection
*
* collection for all configurated operations
*/
OCA.FilesAccessControl.OperationsCollection =
OCA.WorkflowEngine.OperationsCollection.extend({
model: OCA.FilesAccessControl.Operation
});

/**
* @class OCA.FilesAccessControl.OperationView
*
* this creates the view for a single operation
*/
OCA.FilesAccessControl.OperationView =
OCA.WorkflowEngine.OperationView.extend({
model: OCA.FilesAccessControl.Operation,
render: function() {
var $el = OCA.WorkflowEngine.OperationView.prototype.render.apply(this);
$el.find('input.operation-operation').addClass('hidden');
}
});

/**
* @class OCA.FilesAccessControl.OperationsView
*
* this creates the view for configured operations
*/
OCA.FilesAccessControl.OperationsView =
OCA.WorkflowEngine.OperationsView.extend({
initialize: function() {
OCA.WorkflowEngine.OperationsView.prototype.initialize.apply(this, [
'OCA\\FilesAccessControl\\Operation'
]);
},
renderOperation: function(operation) {
var subView = new OCA.FilesAccessControl.OperationView({
model: operation
});

OCA.WorkflowEngine.OperationsView.prototype.renderOperation.apply(this, [
subView
]);
}
});
OCA.WorkflowEngine.registerOperator({
id: 'OCA\\FilesAccessControl\\Operation',
color: '#ca2b2b',
operation: 'deny',
})
})();


$(document).ready(function() {
OC.SystemTags.collection.fetch({
success: function() {
new OCA.FilesAccessControl.OperationsView({
el: '#files_accesscontrol .rules',
collection: new OCA.FilesAccessControl.OperationsCollection()
});
}
});
});
11 changes: 11 additions & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,13 @@
namespace OCA\FilesAccessControl\AppInfo;

use OC\Files\Filesystem;
use OCA\FilesAccessControl\Operation;
use OCA\FilesAccessControl\StorageWrapper;
use OCA\WorkflowEngine\Manager;
use OCP\Files\Storage\IStorage;
use OCP\Util;
use OCP\WorkflowEngine\IManager;
use Symfony\Component\EventDispatcher\GenericEvent;

class Application extends \OCP\AppFramework\App {

Expand All @@ -36,7 +40,14 @@ public function __construct() {
* Register all hooks and listeners
*/
public function registerHooksAndListeners() {
$container = $this->getContainer();
Util::connectHook('OC_Filesystem', 'preSetup', $this, 'addStorageWrapper');
$container->getServer()->getEventDispatcher()->addListener(IManager::EVENT_NAME_REG_OPERATION, function (GenericEvent $event) use ($container){
$operation = $container->query(Operation::class);
$event->getSubject()->registerOperation($operation);
Util::addScript('files_accesscontrol', 'admin');
});

}

/**
Expand Down
104 changes: 98 additions & 6 deletions lib/Operation.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,29 +22,38 @@
namespace OCA\FilesAccessControl;


use OCA\WorkflowEngine\Entity\File;
use OCP\EventDispatcher\Event;
use OCP\Files\ForbiddenException;
use OCP\Files\Storage\IStorage;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\WorkflowEngine\IComplexOperation;
use OCP\WorkflowEngine\IManager;
use OCP\WorkflowEngine\IOperation;
use OCP\WorkflowEngine\IRuleMatcher;
use OCP\WorkflowEngine\ISpecificOperation;

class Operation implements IOperation{
class Operation implements IComplexOperation, ISpecificOperation {
/** @var IManager */
protected $manager;

/** @var IL10N */
protected $l;

/** @var IURLGenerator */
protected $urlGenerator;

/** @var int */
protected $nestingLevel = 0;

/**
* @param IManager $manager
* @param IL10N $l
*/
public function __construct(IManager $manager, IL10N $l) {
public function __construct(IManager $manager, IL10N $l, IURLGenerator $urlGenerator) {
$this->manager = $manager;
$this->l = $l;
$this->urlGenerator = $urlGenerator;
}

/**
Expand All @@ -63,8 +72,9 @@ public function checkFileAccess(IStorage $storage, $path) {
$this->nestingLevel++;

$filePath = $this->translatePath($storage, $path);
$this->manager->setFileInfo($storage, $filePath);
$match = $this->manager->getMatchingOperations('OCA\FilesAccessControl\Operation');
$ruleMatcher = $this->manager->getRuleMatcher();
$ruleMatcher->setFileInfo($storage, $filePath);
$match = $ruleMatcher->getMatchingOperations(self::class);

$this->nestingLevel--;

Expand Down Expand Up @@ -166,9 +176,91 @@ protected function isCreatingSkeletonFiles() {
* @param string $operation
* @throws \UnexpectedValueException
*/
public function validateOperation($name, array $checks, $operation) {
public function validateOperation(string $name, array $checks, string $operation): void {
if (empty($checks)) {
throw new \UnexpectedValueException($this->l->t('No rule given'));
}
}

/**
* returns a translated name to be presented in the web interface
*
* Example: "Automated tagging" (en), "Aŭtomata etikedado" (eo)
*
* @since 18.0.0
*/
public function getDisplayName(): string {
return $this->l->t('Block access to a file');
}

/**
* returns a translated, descriptive text to be presented in the web interface.
*
* It should be short and precise.
*
* Example: "Tag based automatic deletion of files after a given time." (en)
*
* @since 18.0.0
*/
public function getDescription(): string {
return '';
}

/**
* returns the URL to the icon of the operator for display in the web interface.
*
* Usually, the implementation would utilize the `imagePath()` method of the
* `\OCP\IURLGenerator` instance and simply return its result.
*
* Example implementation: return $this->urlGenerator->imagePath('myApp', 'cat.svg');
*
* @since 18.0.0
*/
public function getIcon(): string {
return $this->urlGenerator->imagePath('files_accesscontrol', 'app.svg');
}

/**
* returns whether the operation can be used in the requested scope.
*
* Scope IDs are defined as constants in OCP\WorkflowEngine\IManager. At
* time of writing these are SCOPE_ADMIN and SCOPE_USER.
*
* For possibly unknown future scopes the recommended behaviour is: if
* user scope is permitted, the default behaviour should return `true`,
* otherwise `false`.
*
* @since 18.0.0
*/
public function isAvailableForScope(int $scope): bool {
return $scope === IManager::SCOPE_ADMIN;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we plan to have it for users, I could totally see this too.
Maybe people want to prevent anyone from downloading files with anything but the sync client (I do this for my financial data, blocking web ui and mobile clients)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, we could think about that in a later step, but that will require more work to not lock out other users who should still have access (like the share owner of a file)

}

/**
* returns the id of the entity the operator is designed for
*
* Example: 'WorkflowEngine_Entity_File'
*
* @since 18.0.0
*/
public function getEntityId(): string {
return File::class;
}

/**
* As IComplexOperation chooses the triggering events itself, a hint has
* to be shown to the user so make clear when this operation is becoming
* active. This method returns such a translated string.
*
* Example: "When a file is accessed" (en)
*
* @since 18.0.0
*/
public function getTriggerHint(): string {
return $this->l->t('File is accessed');
}

public function onEvent(string $eventName, Event $event, IRuleMatcher $ruleMatcher): void {
// Noop
}
}
86 changes: 0 additions & 86 deletions lib/Settings/Admin.php

This file was deleted.

Loading