(core) granular access control in the presence of schema changes

Summary:
 - Support schema changes in the presence of non-trivial ACL rules.
 - Fix update of `aclFormulaParsed` when updating formulas automatically after schema change.
 - Filter private metadata in broadcasts, not just fetches.  Censorship method is unchanged, just refactored.
 - Allow only owners to change ACL rules.
 - Force reloads if rules are changed.
 - Track rule changes within bundle, for clarity during schema changes - tableId and colId changes create a muddle otherwise.
 - Show or forbid pages dynamically depending on user's access to its sections. Logic unchanged, just no longer requires reload.
 - Fix calculation of pre-existing rows touched by a bundle, in the presence of schema changes.
 - Gray out acl page for non-owners.

Test Plan: added tests

Reviewers: dsagal

Reviewed By: dsagal

Differential Revision: https://phab.getgrist.com/D2734
This commit is contained in:
Paul Fitzpatrick
2021-03-01 11:51:30 -05:00
parent aae4a58300
commit 4ab096d179
18 changed files with 930 additions and 454 deletions

View File

@@ -213,7 +213,7 @@ export class Sharing {
info.linkId = docSession.linkId;
}
const {sandboxActionBundle, undo, docActions} =
const {sandboxActionBundle, undo, accessControl} =
await this._modificationLock.runExclusive(() => this._applyActionsToDataEngine(docSession, userActions));
// A trivial action does not merit allocating an actionNum,
@@ -285,13 +285,10 @@ export class Sharing {
internal: isCalculate,
});
try {
await this._activeDoc.appliedActions(docActions, undo);
await this._activeDoc.broadcastDocUpdate(client || null, 'docUserAction', {
actionGroup,
docActions,
});
await accessControl.appliedBundle();
await accessControl.sendDocUpdateForBundle(actionGroup);
} finally {
await this._activeDoc.finishedActions();
await accessControl.finishedBundle();
}
if (docSession) {
docSession.linkId = docSession.shouldBundleActions ? localActionBundle.actionNum : 0;
@@ -375,18 +372,18 @@ export class Sharing {
const docActions = getEnvContent(sandboxActionBundle.stored).concat(
getEnvContent(sandboxActionBundle.calc));
const accessControl = this._activeDoc.getGranularAccessForBundle(docSession || makeExceptionalDocSession('share'), docActions, undo, userActions);
try {
// TODO: see if any of the code paths that have no docSession are relevant outside
// of tests.
await this._activeDoc.canApplyDocActions(docSession || makeExceptionalDocSession('share'),
docActions, undo);
await accessControl.canApplyBundle();
} catch (e) {
// should not commit. Don't write to db. Remove changes from sandbox.
await this._activeDoc.applyActionsToDataEngine([['ApplyUndoActions', undo]]);
await this._activeDoc.finishedActions();
await accessControl.finishedBundle();
throw e;
}
return {sandboxActionBundle, undo, docActions};
return {sandboxActionBundle, undo, docActions, accessControl};
}
}