summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric P <eric@kastelo.net>2023-02-09 09:14:36 +0100
committerGitHub <noreply@github.com>2023-02-09 09:14:36 +0100
commit0530f0edbf57db8f8765be523bd1ad8f2f3deac8 (patch)
treea0ffb6e9d5ef29010e5fd7e3c01f221acc1e276b
parent784129e1cf89220dfceb2c3c2cbdc04c150a33b3 (diff)
gui: Add xattr filter editor (fixes #8660) (#8734)
-rw-r--r--gui/default/assets/css/overrides.css4
-rwxr-xr-xgui/default/syncthing/core/syncthingController.js79
-rw-r--r--gui/default/syncthing/folder/editFolderModalView.html56
3 files changed, 139 insertions, 0 deletions
diff --git a/gui/default/assets/css/overrides.css b/gui/default/assets/css/overrides.css
index 47147f3d2c..06f705629a 100644
--- a/gui/default/assets/css/overrides.css
+++ b/gui/default/assets/css/overrides.css
@@ -144,6 +144,10 @@ table.table-auto td {
max-width: 0px;
}
+td input[type="checkbox"] {
+ margin-top: 13px;
+}
+
/* Remote Devices connection-quality indicator */
.reception-0 {
background: url('../../vendor/bootstrap/fonts/reception-0.svg') no-repeat;
diff --git a/gui/default/syncthing/core/syncthingController.js b/gui/default/syncthing/core/syncthingController.js
index f61f0b0cf7..495e4e1b07 100755
--- a/gui/default/syncthing/core/syncthingController.js
+++ b/gui/default/syncthing/core/syncthingController.js
@@ -2301,6 +2301,7 @@ angular.module('syncthing.core')
return;
}
+ $scope.validateXattrFilter();
var folderCfg = angular.copy($scope.currentFolder);
$scope.currentSharing.selected[$scope.myID] = true;
var newDevices = [];
@@ -3330,6 +3331,84 @@ angular.module('syncthing.core')
$scope.showTemporaryTooltip(event, message);
};
+
+ $scope.newXattrEntry = function () {
+ var entries = $scope.currentFolder.xattrFilter.entries;
+ var newEntry = {match: '', permit: false};
+
+ if (entries.some(function (n) {
+ return n.match == '';
+ })) {
+ return;
+ }
+
+ if (entries.length > 0 && entries[entries.length -1].match === '*') {
+ if (newEntry.match !== '*') {
+ entries.splice(entries.length - 1, 0, newEntry);
+ }
+
+ return;
+ }
+
+ entries.push(newEntry);
+ };
+
+ $scope.removeXattrEntry = function (entry) {
+ $scope.currentFolder.xattrFilter.entries = $scope.currentFolder.xattrFilter.entries.filter(function (n) {
+ return n !== entry;
+ });
+ };
+
+ $scope.getXattrHint = function () {
+ var xattrFilter = $scope.currentFolder.xattrFilter;
+ if (xattrFilter == null || xattrFilter == {}) {
+ return '';
+ }
+ var filterEntries = xattrFilter.entries;
+ if (filterEntries.length === 0) {
+ return '';
+ }
+
+ // When the user explicitely added a wild-card, we don't show hints.
+ if (filterEntries.length === 1 && filterEntries[0].match === '*') {
+ return '';
+ }
+ // If all the filter entries are 'deny', we suggest adding a permit-any
+ // rule in the end since the default is already deny in that case.
+ if (filterEntries.every(function (entry) {
+ return entry.permit === false;
+ })) {
+ return $translate.instant('Hint: only deny-rules detected while the default is deny. Consider adding "permit any" as last rule.');
+ }
+
+ return '';
+ };
+
+ $scope.getXattrDefault = function () {
+ var xattrFilter = $scope.currentFolder.xattrFilter;
+ if (xattrFilter == null || xattrFilter == {}) {
+ return '';
+ }
+
+ var filterEntries = xattrFilter.entries;
+ // No entries present, default is thus 'allow'
+ if (filterEntries.length === 0) {
+ return $translate.instant('permit');
+ }
+ // If any rule is present and the last entry isn't a wild-card, the default is deny.
+ if (filterEntries[filterEntries.length -1].match !== '*') {
+ return $translate.instant('deny');
+ }
+
+ return '';
+ };
+
+ $scope.validateXattrFilter = function () {
+ // Fitlering out empty rules when saving the config
+ $scope.currentFolder.xattrFilter.entries = $scope.currentFolder.xattrFilter.entries.filter(function (n) {
+ return n.match !== "";
+ });
+ };
})
.directive('shareTemplate', function () {
return {
diff --git a/gui/default/syncthing/folder/editFolderModalView.html b/gui/default/syncthing/folder/editFolderModalView.html
index a21c45472c..6564479d0f 100644
--- a/gui/default/syncthing/folder/editFolderModalView.html
+++ b/gui/default/syncthing/folder/editFolderModalView.html
@@ -323,7 +323,63 @@
</p>
</div>
</div>
+
+ <div class="row" ng-if="currentFolder.syncXattrs">
+ <div class="col-md-12">
+ <p>
+ <label translate>Extended Attributes Filter</label>
+ &nbsp;<a href="{{docsURL('advanced/folder-xattr-filter')}}" target="_blank"><span class="fas fa-question-circle"></span>&nbsp;<span translate>Help</span></a>
+ </p>
+ </div>
+ <div class="col-md-6">
+ <p translate class="help-block">
+ To permit a rule, have the checkbox checked. To deny a rule, leave it unchecked.
+ </p>
+ <label translate>Active filter rules</label>
+ <table class="table table-condensed">
+ <colgroup>
+ <col class="col-xs-1 center"/>
+ <col class="col-xs-9"/>
+ <col class="col-xs-2"/>
+ </colgroup>
+ <tr ng-repeat="entry in currentFolder.xattrFilter.entries">
+ <td>
+ <input type="checkbox" ng-model="entry.permit">
+ </td>
+ <td><input class="form-control text-left" aria-required="true" ng-model="entry.match"/></td>
+ <td>
+ <button type="button" class="btn btn-default form-control" ng-click="removeXattrEntry(entry)">
+ <span class="fas fa-trash-alt"></span>
+ </button>
+ </td>
+ </tr>
+ </table>
+ <div class="form-group">
+ <button type="button" class="btn btn-default" ng-click="newXattrEntry()">
+ <span class="fas fa-plus"></span>&nbsp;<span translate>Add filter entry</span>
+ </button>
+ </div>
+ <p ng-if="currentFolder.xattrFilter.entries.length === 0">
+ <i translate>No rules set</i>
+ </p>
+ <p ng-if="getXattrDefault() !== ''">
+ <i><span translate>Default</span>: {{getXattrDefault()}}</i>
+ </p>
+ <p ng-if="getXattrHint() !== ''">
+ <i>{{getXattrHint()}}</i>
+ </p>
+ </div>
+ <div class="col-md-6 form-group">
+ <label for="xattrMaxSingleEntrySize" translate>Maximum single entry size</label>
+ <input name="xattrMaxSingleEntrySize" id="xattrMaxSingleEntrySize" class="form-control" type="number" ng-model="currentFolder.xattrFilter.maxSingleEntrySize" required="" aria-required="true" min="0" />
+ </div>
+ <div class="col-md-6 form-group">
+ <label for="xattrMaxTotalSize" translate>Maximum total size</label>
+ <input name="xattrMaxTotalSize" id="xattrMaxTotalSize" class="form-control" type="number" ng-model="currentFolder.xattrFilter.maxTotalSize" required="" aria-required="true" min="0" />
+ </div>
+ </div>
</div>
+
</div>
</form>
</div>