(core) Disallow the combination of Public Edit access and granular ACLs.

Summary:
- When Public Edit access is enabled, Access Rules page shows a warning and
  prevents saving rules.
- When any ACL rules are present, attempts to set Public access to Editor role
  get downgraded to Viewer role, with a warning notification.
- No checks are made on the server side, so the combination may be achieved via
  the API (but we may block it in the future).

Test Plan: Added a test case.

Reviewers: paulfitz

Reviewed By: paulfitz

Differential Revision: https://phab.getgrist.com/D2767
This commit is contained in:
Dmitry S
2021-03-25 19:15:34 -04:00
parent 8c2bea0f73
commit 1a5bacc807
6 changed files with 81 additions and 32 deletions

View File

@@ -96,7 +96,7 @@ export class Notification extends Expirable implements INotification {
constructor(_opts: INotifyOptions) {
super();
this.options = defaults({}, _opts, this.options)
this.options = defaults({}, _opts, this.options);
if (this.options.expireSec > 0) {
const expireTimer = setTimeout(() => this.expire(), 1000 * this.options.expireSec);

View File

@@ -1,3 +1,5 @@
import {DocPageModel} from 'app/client/models/DocPageModel';
import {reportError, UserError} from 'app/client/models/errors';
import {normalizeEmail} from 'app/common/emails';
import {GristLoadConfig} from 'app/common/gristUrls';
import * as roles from 'app/common/roles';
@@ -120,7 +122,8 @@ export class UserManagerModelImpl extends Disposable implements UserManagerModel
constructor(
public initData: PermissionData,
public resourceType: ResourceType,
private _activeUserEmail: string|null
private _activeUserEmail: string|null,
private _docPageModel?: DocPageModel,
) {
super();
}
@@ -194,13 +197,20 @@ export class UserManagerModelImpl extends Disposable implements UserManagerModel
delta.maxInheritedRole = maxInheritedRole;
}
}
// Looping through the members has the side effect of updating the delta.
const members = [...this.membersEdited.get()];
if (this.publicMember) {
members.push(this.publicMember);
}
members.forEach((m, i) => {
const access = m.access.get();
// Loop through the members and update the delta.
for (const m of members) {
let access = m.access.get();
if (m === this.publicMember && access === roles.EDITOR &&
this._docPageModel?.gristDoc.get()?.hasGranularAccessRules()) {
access = roles.VIEWER;
reportError(new UserError(
'Public "Editor" access is incompatible with Access Rules. Reduced to "Viewer".'
));
}
if (!roles.isValidRole(access)) {
throw new Error(`Cannot update user to invalid role ${access}`);
}
@@ -208,7 +218,7 @@ export class UserManagerModelImpl extends Disposable implements UserManagerModel
// Add users whose access changed.
delta.users![m.email] = m.isRemoved ? null : access as roles.NonGuestRole;
}
});
}
return delta;
}