(core) close a hole in bundle cleanup for granular access control

Summary:
A client hit a situation where a granular access control "bundle"
was not closed, leaving the document locked until reset.  I don't
yet have a replication.  This diff is a possible mitigation,
trusting various methods less.

Test Plan: existing tests pass

Reviewers: dsagal

Reviewed By: dsagal

Differential Revision: https://phab.getgrist.com/D2775
This commit is contained in:
Paul Fitzpatrick 2021-04-15 11:50:00 -04:00
parent 2b1b586ecd
commit bc0d6605a1

View File

@ -216,6 +216,8 @@ export class Sharing {
const {sandboxActionBundle, undo, accessControl} = const {sandboxActionBundle, undo, accessControl} =
await this._modificationLock.runExclusive(() => this._applyActionsToDataEngine(docSession, userActions)); await this._modificationLock.runExclusive(() => this._applyActionsToDataEngine(docSession, userActions));
try {
// A trivial action does not merit allocating an actionNum, // A trivial action does not merit allocating an actionNum,
// logging, and sharing. Since we currently don't store // logging, and sharing. Since we currently don't store
// calculated values in the database, it is best not to log the // calculated values in the database, it is best not to log the
@ -284,12 +286,8 @@ export class Sharing {
// date and other changes from external values may count as internal. // date and other changes from external values may count as internal.
internal: isCalculate, internal: isCalculate,
}); });
try {
await accessControl.appliedBundle(); await accessControl.appliedBundle();
await accessControl.sendDocUpdateForBundle(actionGroup); await accessControl.sendDocUpdateForBundle(actionGroup);
} finally {
await accessControl.finishedBundle();
}
if (docSession) { if (docSession) {
docSession.linkId = docSession.shouldBundleActions ? localActionBundle.actionNum : 0; docSession.linkId = docSession.shouldBundleActions ? localActionBundle.actionNum : 0;
} }
@ -298,6 +296,10 @@ export class Sharing {
retValues: sandboxActionBundle.retValues, retValues: sandboxActionBundle.retValues,
isModification: sandboxActionBundle.stored.length > 0 isModification: sandboxActionBundle.stored.length > 0
}; };
} finally {
// Make sure the bundle is marked as complete, even if some miscellaneous error occured.
await accessControl.finishedBundle();
}
} }
private _mergeAdjust(action: UserActionBundle): UserActionBundle { private _mergeAdjust(action: UserActionBundle): UserActionBundle {
@ -379,8 +381,11 @@ export class Sharing {
await accessControl.canApplyBundle(); await accessControl.canApplyBundle();
} catch (e) { } catch (e) {
// should not commit. Don't write to db. Remove changes from sandbox. // should not commit. Don't write to db. Remove changes from sandbox.
try {
await this._activeDoc.applyActionsToDataEngine([['ApplyUndoActions', undo]]); await this._activeDoc.applyActionsToDataEngine([['ApplyUndoActions', undo]]);
} finally {
await accessControl.finishedBundle(); await accessControl.finishedBundle();
}
throw e; throw e;
} }
return {sandboxActionBundle, undo, docActions, accessControl}; return {sandboxActionBundle, undo, docActions, accessControl};